static int cert_open_bincert(ProxyContext * const proxy_context, const SignedBincert * const signed_bincert, const size_t signed_bincert_len, Bincert ** const bincert_p) { Bincert *bincert; unsigned long long bincert_data_len_ul; size_t bincert_size; size_t signed_data_len; if (cert_parse_version(proxy_context, signed_bincert, signed_bincert_len) != 0) { DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION(); return -1; } bincert_size = signed_bincert_len; if ((bincert = malloc(bincert_size)) == NULL) { DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION(); return -1; } assert(signed_bincert_len >= (size_t) (signed_bincert->signed_data - signed_bincert->magic_cert)); signed_data_len = signed_bincert_len - (size_t) (signed_bincert->signed_data - signed_bincert->magic_cert); assert(bincert_size - (size_t) (bincert->server_publickey - bincert->magic_cert) == signed_data_len); if (crypto_sign_ed25519_open(bincert->server_publickey, &bincert_data_len_ul, signed_bincert->signed_data, signed_data_len, proxy_context->provider_publickey) != 0) { free(bincert); logger_noformat(proxy_context, LOG_ERR, "Suspicious certificate received"); DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_SECURITY(); return -1; } if (cert_parse_bincert(proxy_context, bincert, *bincert_p) != 0) { memset(bincert, 0, sizeof *bincert); free(bincert); return -1; } if (*bincert_p != NULL) { memset(*bincert_p, 0, sizeof **bincert_p); free(*bincert_p); } *bincert_p = bincert; return 0; }
static void cert_query_cb(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { Bincert *bincert = NULL; ProxyContext *proxy_context = arg; struct ares_txt_reply *txt_out; struct ares_txt_reply *txt_out_current; (void) timeouts; DNSCRYPT_PROXY_CERTS_UPDATE_RECEIVED(); if (status != ARES_SUCCESS || ares_parse_txt_reply(abuf, alen, &txt_out) != ARES_SUCCESS) { logger_noformat(proxy_context, LOG_ERR, "Unable to retrieve server certificates"); cert_reschedule_query_after_failure(proxy_context); DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION(); return; } txt_out_current = txt_out; while (txt_out_current != NULL) { cert_open_bincert(proxy_context, (const SignedBincert *) txt_out_current->txt, txt_out_current->length, &bincert); txt_out_current = txt_out_current->next; } ares_free_data(txt_out); if (bincert == NULL) { logger_noformat(proxy_context, LOG_ERR, "No useable certificates found"); cert_reschedule_query_after_failure(proxy_context); DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_NOCERTS(); return; } COMPILER_ASSERT(sizeof proxy_context->resolver_publickey == sizeof bincert->server_publickey); memcpy(proxy_context->resolver_publickey, bincert->server_publickey, sizeof proxy_context->resolver_publickey); COMPILER_ASSERT(sizeof proxy_context->dnscrypt_magic_query == sizeof bincert->magic_query); memcpy(proxy_context->dnscrypt_magic_query, bincert->magic_query, sizeof proxy_context->dnscrypt_magic_query); cert_print_server_key(proxy_context); dnscrypt_client_init_magic_query(&proxy_context->dnscrypt_client, bincert->magic_query); memset(bincert, 0, sizeof *bincert); free(bincert); dnscrypt_client_init_nmkey(&proxy_context->dnscrypt_client, proxy_context->resolver_publickey); dnscrypt_proxy_start_listeners(proxy_context); proxy_context->cert_updater.query_retry_step = 0U; cert_reschedule_query_after_success(proxy_context); DNSCRYPT_PROXY_CERTS_UPDATE_DONE((unsigned char *) proxy_context->resolver_publickey); }
static void cert_query_cb(int result, char type, int count, int ttl, void * const txt_records_, void * const arg) { Bincert *bincert = NULL; ProxyContext *proxy_context = arg; const struct txt_record *txt_records = txt_records_; int i = 0; (void) type; (void) ttl; DNSCRYPT_PROXY_CERTS_UPDATE_RECEIVED(); evdns_base_free(proxy_context->cert_updater.evdns_base, 0); proxy_context->cert_updater.evdns_base = NULL; if (result != DNS_ERR_NONE) { logger_noformat(proxy_context, LOG_ERR, "Unable to retrieve server certificates"); cert_reschedule_query_after_failure(proxy_context); DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION(); return; } assert(count >= 0); while (i < count) { cert_open_bincert(proxy_context, (const SignedBincert *) txt_records[i].txt, txt_records[i].len, &bincert); i++; } if (bincert == NULL) { logger_noformat(proxy_context, LOG_ERR, "No useable certificates found"); cert_reschedule_query_after_failure(proxy_context); DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_NOCERTS(); if (proxy_context->test_only) { exit(DNSCRYPT_EXIT_CERT_NOCERTS); } return; } if (proxy_context->test_only != 0) { const uint32_t now_u32 = (uint32_t) time(NULL); uint32_t ts_end; memcpy(&ts_end, bincert->ts_end, sizeof ts_end); ts_end = htonl(ts_end); if (ts_end < (uint32_t) proxy_context->test_cert_margin || now_u32 > ts_end - (uint32_t) proxy_context->test_cert_margin) { logger_noformat(proxy_context, LOG_WARNING, "The certificate is not valid for the given safety margin"); DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_NOCERTS(); exit(DNSCRYPT_EXIT_CERT_MARGIN); } } COMPILER_ASSERT(sizeof proxy_context->resolver_publickey == sizeof bincert->server_publickey); memcpy(proxy_context->resolver_publickey, bincert->server_publickey, sizeof proxy_context->resolver_publickey); COMPILER_ASSERT(sizeof proxy_context->dnscrypt_magic_query == sizeof bincert->magic_query); memcpy(proxy_context->dnscrypt_magic_query, bincert->magic_query, sizeof proxy_context->dnscrypt_magic_query); cert_print_bincert_info(proxy_context, bincert); cert_print_server_key(proxy_context); dnscrypt_client_init_magic_query(&proxy_context->dnscrypt_client, bincert->magic_query); memset(bincert, 0, sizeof *bincert); free(bincert); if (proxy_context->test_only) { DNSCRYPT_PROXY_CERTS_UPDATE_DONE((unsigned char *) proxy_context->resolver_publickey); exit(0); } dnscrypt_client_init_nmkey(&proxy_context->dnscrypt_client, proxy_context->resolver_publickey); dnscrypt_proxy_start_listeners(proxy_context); proxy_context->cert_updater.query_retry_step = 0U; cert_reschedule_query_after_success(proxy_context); DNSCRYPT_PROXY_CERTS_UPDATE_DONE((unsigned char *) proxy_context->resolver_publickey); }