diff options
| author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-05-12 11:54:35 +0000 |
|---|---|---|
| committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-05-12 11:54:35 +0000 |
| commit | 15de2de8449b4f5063f93578ae68aa0bc79a205c (patch) | |
| tree | f0a7e3230212205e7ff88a2900de97026940f63c /validator | |
| parent | 689b65913bba5320ef50befddf4743c6dafde873 (diff) | |
Vendor import of Unbound 1.6.4.vendor/unbound/1.6.4
Diffstat (limited to 'validator')
| -rw-r--r-- | validator/val_secalgo.c | 51 | ||||
| -rw-r--r-- | validator/val_utils.c | 5 | ||||
| -rw-r--r-- | validator/val_utils.h | 4 | ||||
| -rw-r--r-- | validator/validator.c | 142 | ||||
| -rw-r--r-- | validator/validator.h | 13 |
5 files changed, 170 insertions, 45 deletions
diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c index be88ff438660..88d23472118f 100644 --- a/validator/val_secalgo.c +++ b/validator/val_secalgo.c @@ -228,6 +228,9 @@ dnskey_algo_id_is_supported(int id) case LDNS_ECDSAP256SHA256: case LDNS_ECDSAP384SHA384: #endif +#ifdef USE_ED25519 + case LDNS_ED25519: +#endif #if (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) || defined(USE_ECDSA) return 1; #endif @@ -555,6 +558,17 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, #endif break; #endif /* USE_ECDSA */ +#ifdef USE_ED25519 + case LDNS_ED25519: + *evp_key = sldns_ed255192pkey_raw(key, keylen); + if(!*evp_key) { + verbose(VERB_QUERY, "verify: " + "sldns_ed255192pkey_raw failed"); + return 0; + } + *digest_type = NULL; + break; +#endif /* USE_ED25519 */ default: verbose(VERB_QUERY, "verify: unknown algorithm %d", algo); @@ -644,18 +658,29 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, else if(docrypto_free) OPENSSL_free(sigblock); return sec_status_unchecked; } - if(EVP_VerifyInit(ctx, digest_type) == 0) { - verbose(VERB_QUERY, "verify: EVP_VerifyInit failed"); +#ifndef HAVE_EVP_DIGESTVERIFY + if(EVP_DigestInit(ctx, digest_type) == 0) { + verbose(VERB_QUERY, "verify: EVP_DigestInit failed"); +#ifdef HAVE_EVP_MD_CTX_NEW EVP_MD_CTX_destroy(ctx); +#else + EVP_MD_CTX_cleanup(ctx); + free(ctx); +#endif EVP_PKEY_free(evp_key); if(dofree) free(sigblock); else if(docrypto_free) OPENSSL_free(sigblock); return sec_status_unchecked; } - if(EVP_VerifyUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf), + if(EVP_DigestUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf), (unsigned int)sldns_buffer_limit(buf)) == 0) { - verbose(VERB_QUERY, "verify: EVP_VerifyUpdate failed"); + verbose(VERB_QUERY, "verify: EVP_DigestUpdate failed"); +#ifdef HAVE_EVP_MD_CTX_NEW EVP_MD_CTX_destroy(ctx); +#else + EVP_MD_CTX_cleanup(ctx); + free(ctx); +#endif EVP_PKEY_free(evp_key); if(dofree) free(sigblock); else if(docrypto_free) OPENSSL_free(sigblock); @@ -663,6 +688,24 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, } res = EVP_VerifyFinal(ctx, sigblock, sigblock_len, evp_key); +#else /* HAVE_EVP_DIGESTVERIFY */ + if(EVP_DigestVerifyInit(ctx, NULL, digest_type, NULL, evp_key) == 0) { + verbose(VERB_QUERY, "verify: EVP_DigestVerifyInit failed"); +#ifdef HAVE_EVP_MD_CTX_NEW + EVP_MD_CTX_destroy(ctx); +#else + EVP_MD_CTX_cleanup(ctx); + free(ctx); +#endif + EVP_PKEY_free(evp_key); + if(dofree) free(sigblock); + else if(docrypto_free) OPENSSL_free(sigblock); + return sec_status_unchecked; + } + res = EVP_DigestVerify(ctx, sigblock, sigblock_len, + (unsigned char*)sldns_buffer_begin(buf), + sldns_buffer_limit(buf)); +#endif #ifdef HAVE_EVP_MD_CTX_NEW EVP_MD_CTX_destroy(ctx); #else diff --git a/validator/val_utils.c b/validator/val_utils.c index e3677e1d9ceb..e4eff1b2523b 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -54,6 +54,7 @@ #include "util/net_help.h" #include "util/module.h" #include "util/regional.h" +#include "util/config_file.h" #include "sldns/wire2str.h" #include "sldns/parseutil.h" @@ -914,7 +915,7 @@ void val_reply_remove_auth(struct reply_info* rep, size_t index) } void -val_check_nonsecure(struct val_env* ve, struct reply_info* rep) +val_check_nonsecure(struct module_env* env, struct reply_info* rep) { size_t i; /* authority */ @@ -955,7 +956,7 @@ val_check_nonsecure(struct val_env* ve, struct reply_info* rep) } } /* additional */ - if(!ve->clean_additional) + if(!env->cfg->val_clean_additional) return; for(i=rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) { if(((struct packed_rrset_data*)rep->rrsets[i]->entry.data) diff --git a/validator/val_utils.h b/validator/val_utils.h index 051824abaf84..649adc2d6559 100644 --- a/validator/val_utils.h +++ b/validator/val_utils.h @@ -306,10 +306,10 @@ void val_reply_remove_auth(struct reply_info* rep, size_t index); * So that unsigned data does not get let through to clients, when we have * found the data to be secure. * - * @param ve: validator environment with cleaning options. + * @param env: environment with cleaning options. * @param rep: reply to dump all nonsecure stuff out of. */ -void val_check_nonsecure(struct val_env* ve, struct reply_info* rep); +void val_check_nonsecure(struct module_env* env, struct reply_info* rep); /** * Mark all unchecked rrset entries not below a trust anchor as indeterminate. diff --git a/validator/validator.c b/validator/validator.c index 81ba5fa17ba2..5f4a1eb4ebed 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -60,6 +60,7 @@ #include "util/fptr_wlist.h" #include "sldns/rrdef.h" #include "sldns/wire2str.h" +#include "sldns/str2wire.h" /* forward decl for cache response and normal super inform calls of a DS */ static void process_ds_response(struct module_qstate* qstate, @@ -112,8 +113,6 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env, { int c; val_env->bogus_ttl = (uint32_t)cfg->bogus_ttl; - val_env->clean_additional = cfg->val_clean_additional; - val_env->permissive_mode = cfg->val_permissive_mode; if(!env->anchors) env->anchors = anchors_create(); if(!env->anchors) { @@ -170,7 +169,6 @@ val_init(struct module_env* env, int id) } env->modinfo[id] = (void*)val_env; env->need_to_validate = 1; - val_env->permissive_mode = 0; lock_basic_init(&val_env->bogus_lock); lock_protect(&val_env->bogus_lock, &val_env->num_rrset_bogus, sizeof(val_env->num_rrset_bogus)); @@ -364,14 +362,17 @@ already_validated(struct dns_msg* ret_msg) * @param qtype: query type. * @param qclass: query class. * @param flags: additional flags, such as the CD bit (BIT_CD), or 0. + * @param newq: If the subquery is newly created, it is returned, + * otherwise NULL is returned + * @param detached: true if this qstate should not attach to the subquery * @return false on alloc failure. */ static int generate_request(struct module_qstate* qstate, int id, uint8_t* name, - size_t namelen, uint16_t qtype, uint16_t qclass, uint16_t flags) + size_t namelen, uint16_t qtype, uint16_t qclass, uint16_t flags, + struct module_qstate** newq, int detached) { struct val_qstate* vq = (struct val_qstate*)qstate->minfo[id]; - struct module_qstate* newq; struct query_info ask; int valrec; ask.qname = name; @@ -380,22 +381,35 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name, ask.qclass = qclass; ask.local_alias = NULL; log_query_info(VERB_ALGO, "generate request", &ask); - fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); /* enable valrec flag to avoid recursion to the same validation * routine, this lookup is simply a lookup. DLVs need validation */ if(qtype == LDNS_RR_TYPE_DLV) valrec = 0; else valrec = 1; - if(!(*qstate->env->attach_sub)(qstate, &ask, - (uint16_t)(BIT_RD|flags), 0, valrec, &newq)){ - log_err("Could not generate request: out of memory"); - return 0; + if(detached) { + struct mesh_state* sub = NULL; + fptr_ok(fptr_whitelist_modenv_add_sub( + qstate->env->add_sub)); + if(!(*qstate->env->add_sub)(qstate, &ask, + (uint16_t)(BIT_RD|flags), 0, valrec, newq, &sub)){ + log_err("Could not generate request: out of memory"); + return 0; + } + } + else { + fptr_ok(fptr_whitelist_modenv_attach_sub( + qstate->env->attach_sub)); + if(!(*qstate->env->attach_sub)(qstate, &ask, + (uint16_t)(BIT_RD|flags), 0, valrec, newq)){ + log_err("Could not generate request: out of memory"); + return 0; + } } /* newq; validator does not need state created for that * query, and its a 'normal' for iterator as well */ - if(newq) { + if(*newq) { /* add our blacklist to the query blacklist */ - sock_list_merge(&newq->blacklist, newq->region, + sock_list_merge(&(*newq)->blacklist, (*newq)->region, vq->chain_blacklist); } qstate->ext_state[id] = module_wait_subquery; @@ -403,6 +417,66 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name, } /** + * Generate, send and detach key tag signaling query. + * + * @param qstate: query state. + * @param id: module id. + * @param ta: trust anchor, locked. + * @return false on a processing error. + */ +static int +generate_keytag_query(struct module_qstate* qstate, int id, + struct trust_anchor* ta) +{ + /* 3 bytes for "_ta", 5 bytes per tag (4 bytes + "-") */ +#define MAX_LABEL_TAGS (LDNS_MAX_LABELLEN-3)/5 + size_t i, numtag; + uint16_t tags[MAX_LABEL_TAGS]; + char tagstr[LDNS_MAX_LABELLEN+1] = "_ta"; /* +1 for NULL byte */ + size_t tagstr_left = sizeof(tagstr) - strlen(tagstr); + char* tagstr_pos = tagstr + strlen(tagstr); + uint8_t dnamebuf[LDNS_MAX_DOMAINLEN+1]; /* +1 for label length byte */ + size_t dnamebuf_len = sizeof(dnamebuf); + uint8_t* keytagdname; + struct module_qstate* newq = NULL; + enum module_ext_state ext_state = qstate->ext_state[id]; + + numtag = anchor_list_keytags(ta, tags, MAX_LABEL_TAGS); + if(numtag == 0) + return 0; + + for(i=0; i<numtag; i++) { + /* Buffer can't overflow; numtag is limited to tags that fit in + * the buffer. */ + snprintf(tagstr_pos, tagstr_left, "-%04x", (unsigned)tags[i]); + tagstr_left -= strlen(tagstr_pos); + tagstr_pos += strlen(tagstr_pos); + } + + sldns_str2wire_dname_buf_origin(tagstr, dnamebuf, &dnamebuf_len, + ta->name, ta->namelen); + if(!(keytagdname = (uint8_t*)regional_alloc_init(qstate->region, + dnamebuf, dnamebuf_len))) { + log_err("could not generate key tag query: out of memory"); + return 0; + } + + log_nametypeclass(VERB_ALGO, "keytag query", keytagdname, + LDNS_RR_TYPE_NULL, ta->dclass); + if(!generate_request(qstate, id, keytagdname, dnamebuf_len, + LDNS_RR_TYPE_NULL, ta->dclass, 0, &newq, 1)) { + log_err("failed to generate key tag signaling request"); + return 0; + } + + /* Not interrested in subquery response. Restore the ext_state, + * that might be changed by generate_request() */ + qstate->ext_state[id] = ext_state; + + return 1; +} + +/** * Prime trust anchor for use. * Generate and dispatch a priming query for the given trust anchor. * The trust anchor can be DNSKEY or DS and does not have to be signed. @@ -417,8 +491,16 @@ static int prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq, int id, struct trust_anchor* toprime) { + struct module_qstate* newq = NULL; int ret = generate_request(qstate, id, toprime->name, toprime->namelen, - LDNS_RR_TYPE_DNSKEY, toprime->dclass, BIT_CD); + LDNS_RR_TYPE_DNSKEY, toprime->dclass, BIT_CD, &newq, 0); + + if(newq && qstate->env->cfg->trust_anchor_signaling && + !generate_keytag_query(qstate, id, toprime)) { + log_err("keytag signaling query failed"); + return 0; + } + if(!ret) { log_err("Could not prime trust anchor: out of memory"); return 0; @@ -534,9 +616,11 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, } } - /* attempt to validate the ADDITIONAL section rrsets */ - if(!ve->clean_additional) + /* If set, the validator should clean the additional section of + * secure messages. */ + if(!env->cfg->val_clean_additional) return 1; + /* attempt to validate the ADDITIONAL section rrsets */ for(i=chase_reply->an_numrrsets+chase_reply->ns_numrrsets; i<chase_reply->rrset_count; i++) { s = chase_reply->rrsets[i]; @@ -1510,6 +1594,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) uint8_t* target_key_name, *current_key_name; size_t target_key_len; int strip_lab; + struct module_qstate* newq = NULL; log_query_info(VERB_ALGO, "validator: FindKey", &vq->qchase); /* We know that state.key_entry is not 0 or bad key -- if it were, @@ -1522,7 +1607,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) if(key_entry_isnull(vq->key_entry)) { if(!generate_request(qstate, id, vq->ds_rrset->rk.dname, vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY, - vq->qchase.qclass, BIT_CD)) { + vq->qchase.qclass, BIT_CD, &newq, 0)) { log_err("mem error generating DNSKEY request"); return val_error(qstate, id); } @@ -1594,7 +1679,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) vq->key_entry->name) != 0) { if(!generate_request(qstate, id, vq->ds_rrset->rk.dname, vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY, - vq->qchase.qclass, BIT_CD)) { + vq->qchase.qclass, BIT_CD, &newq, 0)) { log_err("mem error generating DNSKEY request"); return val_error(qstate, id); } @@ -1623,7 +1708,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) } if(!generate_request(qstate, id, target_key_name, target_key_len, LDNS_RR_TYPE_DS, vq->qchase.qclass, - BIT_CD)) { + BIT_CD, &newq, 0)) { log_err("mem error generating DS request"); return val_error(qstate, id); } @@ -1633,7 +1718,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) /* Otherwise, it is time to query for the DNSKEY */ if(!generate_request(qstate, id, vq->ds_rrset->rk.dname, vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY, - vq->qchase.qclass, BIT_CD)) { + vq->qchase.qclass, BIT_CD, &newq, 0)) { log_err("mem error generating DNSKEY request"); return val_error(qstate, id); } @@ -1847,6 +1932,7 @@ val_dlv_init(struct module_qstate* qstate, struct val_qstate* vq, { uint8_t* nm; size_t nm_len; + struct module_qstate* newq = NULL; /* there must be a DLV configured */ log_assert(qstate->env->anchors->dlv_anchor); /* this bool is true to avoid looping in the DLV checks */ @@ -1948,7 +2034,7 @@ val_dlv_init(struct module_qstate* qstate, struct val_qstate* vq, vq->state = VAL_DLVLOOKUP_STATE; if(!generate_request(qstate, id, vq->dlv_lookup_name, vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV, - vq->qchase.qclass, 0)) { + vq->qchase.qclass, 0, &newq, 0)) { return val_error(qstate, id); } @@ -2042,7 +2128,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, * a different signer name). And drop additional rrsets * that are not secure (if clean-additional option is set) */ /* this may cause the msg to be marked bogus */ - val_check_nonsecure(ve, vq->orig_msg->rep); + val_check_nonsecure(qstate->env, vq->orig_msg->rep); if(vq->orig_msg->rep->security == sec_status_secure) { log_query_info(VERB_DETAIL, "validation success", &qstate->qinfo); @@ -2083,8 +2169,14 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, free(err); } } + /* + * If set, the validator will not make messages bogus, instead + * indeterminate is issued, so that no clients receive SERVFAIL. + * This allows an operator to run validation 'shadow' without + * hurting responses to clients. + */ /* If we are in permissive mode, bogus gets indeterminate */ - if(ve->permissive_mode) + if(qstate->env->cfg->val_permissive_mode) vq->orig_msg->rep->security = sec_status_indeterminate; } @@ -2128,6 +2220,7 @@ static int processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, struct val_env* ve, int id) { + struct module_qstate* newq = NULL; /* see if this we are ready to continue normal resolution */ /* we may need more DLV lookups */ if(vq->dlv_status==dlv_error) @@ -2176,7 +2269,7 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, if(!generate_request(qstate, id, vq->ds_rrset->rk.dname, vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY, - vq->qchase.qclass, BIT_CD)) { + vq->qchase.qclass, BIT_CD, &newq, 0)) { log_err("mem error generating DNSKEY request"); return val_error(qstate, id); } @@ -2218,7 +2311,7 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, if(!generate_request(qstate, id, vq->dlv_lookup_name, vq->dlv_lookup_name_len, LDNS_RR_TYPE_DLV, - vq->qchase.qclass, 0)) { + vq->qchase.qclass, 0, &newq, 0)) { return val_error(qstate, id); } @@ -2857,6 +2950,7 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq, ta->name, ta->namelen, LDNS_RR_TYPE_DNSKEY, ta->dclass); } + if(ta->autr) { if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset)) { /* trust anchor revoked, restart with less anchors */ diff --git a/validator/validator.h b/validator/validator.h index 23d3072427a2..9a591078f71c 100644 --- a/validator/validator.h +++ b/validator/validator.h @@ -93,19 +93,6 @@ struct val_env { * seconds. */ uint32_t bogus_ttl; - /** If set, the validator should clean the additional section of - * secure messages. - */ - int clean_additional; - - /** - * If set, the validator will not make messages bogus, instead - * indeterminate is issued, so that no clients receive SERVFAIL. - * This allows an operator to run validation 'shadow' without - * hurting responses to clients. - */ - int permissive_mode; - /** * Number of entries in the NSEC3 maximum iteration count table. * Keep this table short, and sorted by size |
