dnscrypto-proxy: Update to release 1.3.0
[tomato.git] / release / src / router / dnscrypt / src / proxy / cert.c
blob65d0a71380779a8b12071cee978374b5fec950d6
2 #include <config.h>
3 #include <sys/types.h>
4 #ifdef _WIN32
5 # include <winsock2.h>
6 #else
7 # include <sys/socket.h>
8 # include <arpa/inet.h>
9 #endif
11 #include <assert.h>
12 #include <inttypes.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
18 #include <event2/dns.h>
19 #include <event2/event.h>
21 #include "cert.h"
22 #include "cert_p.h"
23 #include "dnscrypt_proxy.h"
24 #include "logger.h"
25 #include "probes.h"
26 #include "sodium.h"
27 #include "utils.h"
29 static int cert_updater_update(ProxyContext * const proxy_context);
31 static int
32 cert_parse_version(ProxyContext * const proxy_context,
33 const SignedBincert * const signed_bincert,
34 const size_t signed_bincert_len)
36 if (signed_bincert_len <= (size_t) (signed_bincert->signed_data -
37 signed_bincert->magic_cert) ||
38 memcmp(signed_bincert->magic_cert, CERT_MAGIC_CERT,
39 sizeof signed_bincert->magic_cert) != 0) {
40 logger_noformat(proxy_context, LOG_DEBUG,
41 "TXT record with no certificates received");
42 return -1;
44 if (signed_bincert->version_major[0] != 0U ||
45 signed_bincert->version_major[1] != 1U) {
46 logger_noformat(proxy_context, LOG_WARNING,
47 "Unsupported certificate version");
48 return -1;
50 return 0;
53 static int
54 cert_parse_bincert(ProxyContext * const proxy_context,
55 const Bincert * const bincert,
56 const Bincert * const previous_bincert)
58 uint32_t serial;
59 memcpy(&serial, bincert->serial, sizeof serial);
60 serial = htonl(serial);
61 logger(proxy_context, LOG_INFO,
62 "Server certificate #%" PRIu32 " received", serial);
64 uint32_t ts_begin;
65 memcpy(&ts_begin, bincert->ts_begin, sizeof ts_begin);
66 ts_begin = htonl(ts_begin);
68 uint32_t ts_end;
69 memcpy(&ts_end, bincert->ts_end, sizeof ts_end);
70 ts_end = htonl(ts_end);
72 uint32_t now_u32 = (uint32_t) time(NULL);
74 if (now_u32 < ts_begin) {
75 logger_noformat(proxy_context, LOG_INFO,
76 "This certificate has not been activated yet");
77 return -1;
79 if (now_u32 > ts_end) {
80 logger_noformat(proxy_context, LOG_INFO,
81 "This certificate has expired");
82 return -1;
84 logger_noformat(proxy_context, LOG_INFO, "This certificate looks valid");
85 if (previous_bincert == NULL) {
86 return 0;
89 uint32_t previous_serial;
90 memcpy(&previous_serial, previous_bincert->serial, sizeof previous_serial);
91 previous_serial = htonl(previous_serial);
92 if (previous_serial > serial) {
93 logger(proxy_context, LOG_INFO, "Certificate #%" PRIu32 " "
94 "has been superseded by certificate #%" PRIu32,
95 previous_serial, serial);
96 return -1;
98 logger(proxy_context, LOG_INFO,
99 "This certificate supersedes certificate #%" PRIu32,
100 previous_serial);
102 return 0;
105 static int
106 cert_open_bincert(ProxyContext * const proxy_context,
107 const SignedBincert * const signed_bincert,
108 const size_t signed_bincert_len,
109 Bincert ** const bincert_p)
111 Bincert *bincert;
112 unsigned long long bincert_data_len_ul;
113 size_t bincert_size;
114 size_t signed_data_len;
116 if (cert_parse_version(proxy_context,
117 signed_bincert, signed_bincert_len) != 0) {
118 DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION();
119 return -1;
121 bincert_size = signed_bincert_len;
122 if ((bincert = malloc(bincert_size)) == NULL) {
123 DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION();
124 return -1;
126 assert(signed_bincert_len >= (size_t) (signed_bincert->signed_data -
127 signed_bincert->magic_cert));
128 signed_data_len = signed_bincert_len -
129 (size_t) (signed_bincert->signed_data - signed_bincert->magic_cert);
130 assert(bincert_size - (size_t) (bincert->server_publickey -
131 bincert->magic_cert) == signed_data_len);
132 if (crypto_sign_ed25519_open(bincert->server_publickey, &bincert_data_len_ul,
133 signed_bincert->signed_data, signed_data_len,
134 proxy_context->provider_publickey) != 0) {
135 free(bincert);
136 logger_noformat(proxy_context, LOG_ERR,
137 "Suspicious certificate received");
138 DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_SECURITY();
139 return -1;
141 if (cert_parse_bincert(proxy_context, bincert, *bincert_p) != 0) {
142 memset(bincert, 0, sizeof *bincert);
143 free(bincert);
144 return -1;
146 if (*bincert_p != NULL) {
147 memset(*bincert_p, 0, sizeof **bincert_p);
148 free(*bincert_p);
150 *bincert_p = bincert;
152 return 0;
155 static void
156 cert_print_server_key(ProxyContext * const proxy_context)
158 char fingerprint[80U];
160 dnscrypt_key_to_fingerprint(fingerprint,
161 proxy_context->resolver_publickey);
162 logger(proxy_context, LOG_INFO,
163 "Server key fingerprint is %s", fingerprint);
166 static void
167 cert_timer_cb(evutil_socket_t handle, const short event,
168 void * const proxy_context_)
170 ProxyContext * const proxy_context = proxy_context_;
172 (void) handle;
173 (void) event;
174 logger_noformat(proxy_context, LOG_INFO,
175 "Refetching server certificates");
176 cert_updater_update(proxy_context);
179 static void
180 cert_reschedule_query(ProxyContext * const proxy_context,
181 const time_t query_retry_delay)
183 CertUpdater *cert_updater = &proxy_context->cert_updater;
185 if (evtimer_pending(cert_updater->cert_timer, NULL)) {
186 return;
188 const struct timeval tv = { .tv_sec = query_retry_delay, .tv_usec = 0 };
189 evtimer_add(cert_updater->cert_timer, &tv);
192 static void
193 cert_reschedule_query_after_failure(ProxyContext * const proxy_context)
195 CertUpdater *cert_updater = &proxy_context->cert_updater;
196 time_t query_retry_delay;
198 if (evtimer_pending(cert_updater->cert_timer, NULL)) {
199 return;
201 query_retry_delay = (time_t)
202 (CERT_QUERY_RETRY_MIN_DELAY +
203 (time_t) cert_updater->query_retry_step *
204 (CERT_QUERY_RETRY_MAX_DELAY - CERT_QUERY_RETRY_MIN_DELAY) /
205 CERT_QUERY_RETRY_STEPS);
206 if (cert_updater->query_retry_step < CERT_QUERY_RETRY_STEPS) {
207 cert_updater->query_retry_step++;
209 cert_reschedule_query(proxy_context, query_retry_delay);
210 DNSCRYPT_PROXY_CERTS_UPDATE_RETRY();
213 static void
214 cert_reschedule_query_after_success(ProxyContext * const proxy_context)
216 if (evtimer_pending(proxy_context->cert_updater.cert_timer, NULL)) {
217 return;
219 cert_reschedule_query(proxy_context, (time_t)
220 CERT_QUERY_RETRY_DELAY_AFTER_SUCCESS_MIN_DELAY
221 + (time_t) randombytes_uniform
222 (CERT_QUERY_RETRY_DELAY_AFTER_SUCCESS_JITTER));
225 static void
226 cert_query_cb(int result, char type, int count, int ttl,
227 void * const txt_records_, void * const arg)
229 Bincert *bincert = NULL;
230 ProxyContext *proxy_context = arg;
231 const struct txt_record *txt_records = txt_records_;
232 int i = 0;
234 (void) type;
235 (void) ttl;
236 DNSCRYPT_PROXY_CERTS_UPDATE_RECEIVED();
237 evdns_base_free(proxy_context->cert_updater.evdns_base, 0);
238 proxy_context->cert_updater.evdns_base = NULL;
239 if (result != DNS_ERR_NONE) {
240 logger_noformat(proxy_context, LOG_ERR,
241 "Unable to retrieve server certificates");
242 cert_reschedule_query_after_failure(proxy_context);
243 DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION();
244 return;
246 assert(count >= 0);
247 while (i < count) {
248 cert_open_bincert(proxy_context,
249 (const SignedBincert *) txt_records[i].txt,
250 txt_records[i].len, &bincert);
251 i++;
253 if (bincert == NULL) {
254 logger_noformat(proxy_context, LOG_ERR,
255 "No useable certificates found");
256 cert_reschedule_query_after_failure(proxy_context);
257 DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_NOCERTS();
258 return;
260 COMPILER_ASSERT(sizeof proxy_context->resolver_publickey ==
261 sizeof bincert->server_publickey);
262 memcpy(proxy_context->resolver_publickey, bincert->server_publickey,
263 sizeof proxy_context->resolver_publickey);
264 COMPILER_ASSERT(sizeof proxy_context->dnscrypt_magic_query ==
265 sizeof bincert->magic_query);
266 memcpy(proxy_context->dnscrypt_magic_query, bincert->magic_query,
267 sizeof proxy_context->dnscrypt_magic_query);
268 cert_print_server_key(proxy_context);
269 dnscrypt_client_init_magic_query(&proxy_context->dnscrypt_client,
270 bincert->magic_query);
271 memset(bincert, 0, sizeof *bincert);
272 free(bincert);
273 dnscrypt_client_init_nmkey(&proxy_context->dnscrypt_client,
274 proxy_context->resolver_publickey);
275 dnscrypt_proxy_start_listeners(proxy_context);
276 proxy_context->cert_updater.query_retry_step = 0U;
277 cert_reschedule_query_after_success(proxy_context);
278 DNSCRYPT_PROXY_CERTS_UPDATE_DONE((unsigned char *)
279 proxy_context->resolver_publickey);
283 cert_updater_init(ProxyContext * const proxy_context)
285 CertUpdater *cert_updater = &proxy_context->cert_updater;
287 memset(cert_updater, 0, sizeof *cert_updater);
288 assert(proxy_context->event_loop != NULL);
289 assert(cert_updater->cert_timer == NULL);
290 if ((cert_updater->cert_timer =
291 evtimer_new(proxy_context->event_loop,
292 cert_timer_cb, proxy_context)) == NULL) {
293 return -1;
295 cert_updater->query_retry_step = 0U;
296 cert_updater->evdns_base = NULL;
298 return 0;
301 static int
302 cert_updater_update(ProxyContext * const proxy_context)
304 CertUpdater *cert_updater = &proxy_context->cert_updater;
306 DNSCRYPT_PROXY_CERTS_UPDATE_START();
307 if (cert_updater->evdns_base != NULL) {
308 evdns_base_free(cert_updater->evdns_base, 0);
310 if ((cert_updater->evdns_base =
311 evdns_base_new(proxy_context->event_loop, 0)) == NULL) {
312 return -1;
314 if (evdns_base_nameserver_sockaddr_add(cert_updater->evdns_base,
315 (struct sockaddr *)
316 &proxy_context->resolver_sockaddr,
317 proxy_context->resolver_sockaddr_len,
318 DNS_QUERY_NO_SEARCH) != 0) {
319 return -1;
321 if (proxy_context->tcp_only != 0) {
322 (void) evdns_base_nameserver_ip_add(cert_updater->evdns_base,
323 proxy_context->resolver_ip);
325 if (evdns_base_resolve_txt(cert_updater->evdns_base,
326 proxy_context->provider_name,
327 DNS_QUERY_NO_SEARCH,
328 cert_query_cb,
329 proxy_context) == NULL) {
330 return -1;
332 return 0;
336 cert_updater_start(ProxyContext * const proxy_context)
338 evdns_set_random_init_fn(NULL);
339 evdns_set_random_bytes_fn(randombytes_buf);
340 cert_updater_update(proxy_context);
342 return 0;
345 void
346 cert_updater_stop(ProxyContext * const proxy_context)
348 CertUpdater * const cert_updater = &proxy_context->cert_updater;
350 assert(cert_updater->cert_timer != NULL);
351 evtimer_del(cert_updater->cert_timer);
354 void
355 cert_updater_free(ProxyContext * const proxy_context)
357 CertUpdater * const cert_updater = &proxy_context->cert_updater;
359 event_free(cert_updater->cert_timer);
360 cert_updater->cert_timer = NULL;
361 if (cert_updater->evdns_base != NULL) {
362 evdns_base_free(cert_updater->evdns_base, 0);
363 cert_updater->evdns_base = NULL;