diff --git a/doc/Changelog b/doc/Changelog index 150817308..8fbbf3c05 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +8 July 2024: Wouter + - Fix that validation reason failure that uses string print uses + separate buffer that is passed, from the scratch validation buffer. + 5 July 2024: Yorgos - Don't check for message TTL changes if the RRsets remain the same. diff --git a/services/authzone.c b/services/authzone.c index f01a6d9e0..0f79f42ea 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -7778,7 +7778,8 @@ static void auth_zone_log(uint8_t* name, enum verbosity_value level, static int zonemd_dnssec_verify_rrset(struct auth_zone* z, struct module_env* env, struct module_stack* mods, struct ub_packed_rrset_key* dnskey, struct auth_data* node, - struct auth_rrset* rrset, char** why_bogus, uint8_t* sigalg) + struct auth_rrset* rrset, char** why_bogus, uint8_t* sigalg, + char* reasonbuf, size_t reasonlen) { struct ub_packed_rrset_key pk; enum sec_status sec; @@ -7808,7 +7809,7 @@ static int zonemd_dnssec_verify_rrset(struct auth_zone* z, "zonemd: verify %s RRset with DNSKEY", typestr); } sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL, - LDNS_SECTION_ANSWER, NULL, &verified); + LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, reasonlen); if(sec == sec_status_secure) { return 1; } @@ -7851,7 +7852,8 @@ static int nsec3_of_param_has_type(struct auth_rrset* nsec3, int algo, static int zonemd_check_dnssec_absence(struct auth_zone* z, struct module_env* env, struct module_stack* mods, struct ub_packed_rrset_key* dnskey, struct auth_data* apex, - char** reason, char** why_bogus, uint8_t* sigalg) + char** reason, char** why_bogus, uint8_t* sigalg, char* reasonbuf, + size_t reasonlen) { struct auth_rrset* nsec = NULL; if(!apex) { @@ -7863,7 +7865,7 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z, struct ub_packed_rrset_key pk; /* dnssec verify the NSEC */ if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex, - nsec, why_bogus, sigalg)) { + nsec, why_bogus, sigalg, reasonbuf, reasonlen)) { *reason = "DNSSEC verify failed for NSEC RRset"; return 0; } @@ -7906,7 +7908,7 @@ static int zonemd_check_dnssec_absence(struct auth_zone* z, } /* dnssec verify the NSEC3 */ if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, match, - nsec3, why_bogus, sigalg)) { + nsec3, why_bogus, sigalg, reasonbuf, reasonlen)) { *reason = "DNSSEC verify failed for NSEC3 RRset"; return 0; } @@ -7928,7 +7930,7 @@ static int zonemd_check_dnssec_soazonemd(struct auth_zone* z, struct module_env* env, struct module_stack* mods, struct ub_packed_rrset_key* dnskey, struct auth_data* apex, struct auth_rrset* zonemd_rrset, char** reason, char** why_bogus, - uint8_t* sigalg) + uint8_t* sigalg, char* reasonbuf, size_t reasonlen) { struct auth_rrset* soa; if(!apex) { @@ -7941,12 +7943,12 @@ static int zonemd_check_dnssec_soazonemd(struct auth_zone* z, return 0; } if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex, soa, - why_bogus, sigalg)) { + why_bogus, sigalg, reasonbuf, reasonlen)) { *reason = "DNSSEC verify failed for SOA RRset"; return 0; } if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex, - zonemd_rrset, why_bogus, sigalg)) { + zonemd_rrset, why_bogus, sigalg, reasonbuf, reasonlen)) { *reason = "DNSSEC verify failed for ZONEMD RRset"; return 0; } @@ -8014,6 +8016,7 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env, struct module_stack* mods, struct ub_packed_rrset_key* dnskey, int is_insecure, char** result, uint8_t* sigalg) { + char reasonbuf[256]; char* reason = NULL, *why_bogus = NULL; struct auth_data* apex = NULL; struct auth_rrset* zonemd_rrset = NULL; @@ -8042,7 +8045,8 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env, } else if(!zonemd_rrset && dnskey && !is_insecure) { /* fetch, DNSSEC verify, and check NSEC/NSEC3 */ if(!zonemd_check_dnssec_absence(z, env, mods, dnskey, apex, - &reason, &why_bogus, sigalg)) { + &reason, &why_bogus, sigalg, reasonbuf, + sizeof(reasonbuf))) { auth_zone_zonemd_fail(z, env, reason, why_bogus, result); return; } @@ -8050,7 +8054,8 @@ auth_zone_verify_zonemd_with_key(struct auth_zone* z, struct module_env* env, } else if(zonemd_rrset && dnskey && !is_insecure) { /* check DNSSEC verify of SOA and ZONEMD */ if(!zonemd_check_dnssec_soazonemd(z, env, mods, dnskey, apex, - zonemd_rrset, &reason, &why_bogus, sigalg)) { + zonemd_rrset, &reason, &why_bogus, sigalg, reasonbuf, + sizeof(reasonbuf))) { auth_zone_zonemd_fail(z, env, reason, why_bogus, result); return; } @@ -8114,7 +8119,8 @@ static struct ub_packed_rrset_key* zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env, struct module_stack* mods, struct trust_anchor* anchor, int* is_insecure, char** why_bogus, - struct ub_packed_rrset_key* keystorage) + struct ub_packed_rrset_key* keystorage, char* reasonbuf, + size_t reasonlen) { struct auth_data* apex; struct auth_rrset* dnskey_rrset; @@ -8150,7 +8156,8 @@ zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env, auth_zone_log(z->name, VERB_QUERY, "zonemd: verify DNSKEY RRset with trust anchor"); sec = val_verify_DNSKEY_with_TA(env, ve, keystorage, anchor->ds_rrset, - anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL); + anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, reasonbuf, + reasonlen); regional_free_all(env->scratch); if(sec == sec_status_secure) { /* success */ @@ -8173,7 +8180,8 @@ static struct ub_packed_rrset_key* auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z, struct module_env* env, struct module_stack* mods, struct ub_packed_rrset_key* ds, int* is_insecure, char** why_bogus, - struct ub_packed_rrset_key* keystorage, uint8_t* sigalg) + struct ub_packed_rrset_key* keystorage, uint8_t* sigalg, + char* reasonbuf, size_t reasonlen) { struct auth_data* apex; struct auth_rrset* dnskey_rrset; @@ -8209,7 +8217,7 @@ auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z, keystorage->rk.rrset_class = htons(z->dclass); auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS"); sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg, - why_bogus, NULL, NULL); + why_bogus, NULL, NULL, reasonbuf, reasonlen); regional_free_all(env->scratch); if(sec == sec_status_secure) { /* success */ @@ -8235,6 +8243,7 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf, { struct auth_zone* z = (struct auth_zone*)arg; struct module_env* env; + char reasonbuf[256]; char* reason = NULL, *ds_bogus = NULL, *typestr="DNSKEY"; struct ub_packed_rrset_key* dnskey = NULL, *ds = NULL; int is_insecure = 0, downprot; @@ -8346,7 +8355,8 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf, if(!reason && !is_insecure && !dnskey && ds) { dnskey = auth_zone_verify_zonemd_key_with_ds(z, env, &env->mesh->mods, ds, &is_insecure, &ds_bogus, - &keystorage, downprot?sigalg:NULL); + &keystorage, downprot?sigalg:NULL, reasonbuf, + sizeof(reasonbuf)); if(!dnskey && !is_insecure && !reason) reason = "DNSKEY verify with DS failed"; } @@ -8354,6 +8364,7 @@ void auth_zonemd_dnskey_lookup_callback(void* arg, int rcode, sldns_buffer* buf, if(reason) { auth_zone_zonemd_fail(z, env, reason, ds_bogus, NULL); lock_rw_unlock(&z->lock); + regional_free_all(env->scratch); return; } @@ -8438,6 +8449,7 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env) void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env, struct module_stack* mods, char** result, int offline, int only_online) { + char reasonbuf[256]; char* reason = NULL, *why_bogus = NULL; struct trust_anchor* anchor = NULL; struct ub_packed_rrset_key* dnskey = NULL; @@ -8472,7 +8484,8 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env, } /* equal to trustanchor, no need for online lookups */ dnskey = zonemd_get_dnskey_from_anchor(z, env, mods, anchor, - &is_insecure, &why_bogus, &keystorage); + &is_insecure, &why_bogus, &keystorage, reasonbuf, + sizeof(reasonbuf)); lock_basic_unlock(&anchor->lock); if(!dnskey && !reason && !is_insecure) { reason = "verify DNSKEY RRset with trust anchor failed"; @@ -8498,6 +8511,7 @@ void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env, if(reason) { auth_zone_zonemd_fail(z, env, reason, why_bogus, result); + regional_free_all(env->scratch); return; } diff --git a/testcode/unitverify.c b/testcode/unitverify.c index 395b4c257..275435c73 100644 --- a/testcode/unitverify.c +++ b/testcode/unitverify.c @@ -178,6 +178,7 @@ verifytest_rrset(struct module_env* env, struct val_env* ve, struct query_info* qinfo) { enum sec_status sec; + char reasonbuf[256]; char* reason = NULL; uint8_t sigalg[ALGO_NEEDS_MAX+1]; int verified = 0; @@ -188,8 +189,9 @@ verifytest_rrset(struct module_env* env, struct val_env* ve, } setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */ /* ok to give null as qstate here, won't be used for answer section. */ - sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason, NULL, - LDNS_SECTION_ANSWER, NULL, &verified); + sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason, + NULL, LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, + sizeof(reasonbuf)); if(vsig) { printf("verify outcome is: %s %s\n", sec_status_to_string(sec), reason?reason:""); diff --git a/validator/autotrust.c b/validator/autotrust.c index 3eb13b35c..36cdf3e0a 100644 --- a/validator/autotrust.c +++ b/validator/autotrust.c @@ -1262,12 +1262,13 @@ verify_dnskey(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* rrset, struct module_qstate* qstate) { + char reasonbuf[256]; char* reason = NULL; uint8_t sigalg[ALGO_NEEDS_MAX+1]; int downprot = env->cfg->harden_algo_downgrade; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason, - NULL, qstate); + NULL, qstate, reasonbuf, sizeof(reasonbuf)); /* sigalg is ignored, it returns algorithms signalled to exist, but * in 5011 there are no other rrsets to check. if downprot is * enabled, then it checks that the DNSKEY is signed with all diff --git a/validator/val_nsec.c b/validator/val_nsec.c index d0cc67ff5..ad0cba1c4 100644 --- a/validator/val_nsec.c +++ b/validator/val_nsec.c @@ -177,7 +177,7 @@ static int nsec_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, - struct module_qstate* qstate) + struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) { struct packed_rrset_data* d = (struct packed_rrset_data*) nsec->entry.data; @@ -189,7 +189,8 @@ nsec_verify_rrset(struct module_env* env, struct val_env* ve, if(d->security == sec_status_secure) return 1; d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason, - reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified); + reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified, + reasonbuf, reasonlen); if(d->security == sec_status_secure) { rrset_update_sec_status(env->rrset_cache, nsec, *env->now); return 1; @@ -201,7 +202,8 @@ enum sec_status val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, struct query_info* qinfo, struct reply_info* rep, struct key_entry_key* kkey, time_t* proof_ttl, char** reason, - sldns_ede_code* reason_bogus, struct module_qstate* qstate) + sldns_ede_code* reason_bogus, struct module_qstate* qstate, + char* reasonbuf, size_t reasonlen) { struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns( rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC, @@ -219,7 +221,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, * 2) this is not a delegation point */ if(nsec) { if(!nsec_verify_rrset(env, ve, nsec, kkey, reason, - reason_bogus, qstate)) { + reason_bogus, qstate, reasonbuf, reasonlen)) { verbose(VERB_ALGO, "NSEC RRset for the " "referral did not verify."); return sec_status_bogus; @@ -250,7 +252,7 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC)) continue; if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason, - reason_bogus, qstate)) { + reason_bogus, qstate, reasonbuf, reasonlen)) { verbose(VERB_ALGO, "NSEC for empty non-terminal " "did not verify."); *reason = "NSEC for empty non-terminal " diff --git a/validator/val_nsec.h b/validator/val_nsec.h index 81844c908..c1d45314a 100644 --- a/validator/val_nsec.h +++ b/validator/val_nsec.h @@ -68,6 +68,8 @@ struct key_entry_key; * @param reason: string explaining why bogus. * @param reason_bogus: relevant EDE code for validation failure. * @param qstate: qstate with region. + * @param reasonbuf: buffer to use for fail reason string print. + * @param reasonlen: length of reasonbuf. * @return security status. * SECURE: proved absence of DS. * INSECURE: proved that this was not a delegation point. @@ -78,7 +80,7 @@ enum sec_status val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, struct query_info* qinfo, struct reply_info* rep, struct key_entry_key* kkey, time_t* proof_ttl, char** reason, sldns_ede_code* reason_bogus, - struct module_qstate* qstate); + struct module_qstate* qstate, char* reasonbuf, size_t reasonlen); /** * nsec typemap check, takes an NSEC-type bitmap as argument, checks for type. diff --git a/validator/val_nsec3.c b/validator/val_nsec3.c index 95d1e4d7e..e790e9982 100644 --- a/validator/val_nsec3.c +++ b/validator/val_nsec3.c @@ -1445,7 +1445,7 @@ static int list_is_secure(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, - struct module_qstate* qstate) + struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) { struct packed_rrset_data* d; size_t i; @@ -1461,7 +1461,7 @@ list_is_secure(struct module_env* env, struct val_env* ve, continue; d->security = val_verify_rrset_entry(env, ve, list[i], kkey, reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate, - &verified); + &verified, reasonbuf, reasonlen); if(d->security != sec_status_secure) { verbose(VERB_ALGO, "NSEC3 did not verify"); return 0; @@ -1476,7 +1476,7 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - struct nsec3_cache_table* ct) + struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen) { struct nsec3_filter flt; struct ce_response ce; @@ -1491,7 +1491,8 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, *reason = "no valid NSEC3s"; return sec_status_bogus; /* no valid NSEC3s, bogus */ } - if(!list_is_secure(env, ve, list, num, kkey, reason, reason_bogus, qstate)) { + if(!list_is_secure(env, ve, list, num, kkey, reason, reason_bogus, + qstate, reasonbuf, reasonlen)) { *reason = "not all NSEC3 records secure"; return sec_status_bogus; /* not all NSEC3 records secure */ } diff --git a/validator/val_nsec3.h b/validator/val_nsec3.h index 8ca912934..f668a270f 100644 --- a/validator/val_nsec3.h +++ b/validator/val_nsec3.h @@ -210,6 +210,8 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. * @param ct: cached hashes table. + * @param reasonbuf: buffer to use for fail reason string print. + * @param reasonlen: length of reasonbuf. * @return: * sec_status SECURE of the proposition is proven by the NSEC3 RRs, * BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored. @@ -222,7 +224,7 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, char** reason, sldns_ede_code* reason_bogus, struct module_qstate* qstate, - struct nsec3_cache_table* ct); + struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen); /** * Prove NXDOMAIN or NODATA. diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index 7c2b9d7e6..3e90eeb84 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -623,7 +623,8 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate, int* verified) + sldns_pkt_section section, struct module_qstate* qstate, int* verified, + char* reasonbuf, size_t reasonlen) { enum sec_status sec; size_t i, num; @@ -680,7 +681,8 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, verbose(VERB_ALGO, "rrset failed to verify: " "no valid signatures for %d algorithms", (int)algo_needs_num_missing(&needs)); - algo_needs_reason(env, alg, reason, "no signatures"); + algo_needs_reason(alg, reason, "no signatures", reasonbuf, + reasonlen); } else { verbose(VERB_ALGO, "rrset failed to verify: " "no valid signatures"); @@ -688,17 +690,16 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, return sec_status_bogus; } -void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s) +void algo_needs_reason(int alg, char** reason, char* s, char* reasonbuf, + size_t reasonlen) { - char buf[256]; sldns_lookup_table *t = sldns_lookup_by_id(sldns_algorithms, alg); if(t&&t->name) - snprintf(buf, sizeof(buf), "%s with algorithm %s", s, t->name); - else snprintf(buf, sizeof(buf), "%s with algorithm ALG%u", s, - (unsigned)alg); - *reason = regional_strdup(env->scratch, buf); - if(!*reason) - *reason = s; + snprintf(reasonbuf, sizeof(reasonlen), "%s with algorithm %s", + s, t->name); + else snprintf(reasonbuf, sizeof(reasonlen), "%s with algorithm " + "ALG%u", s, (unsigned)alg); + *reason = reasonbuf; } enum sec_status diff --git a/validator/val_sigcrypt.h b/validator/val_sigcrypt.h index 1a3d8fcb2..1fac8bde0 100644 --- a/validator/val_sigcrypt.h +++ b/validator/val_sigcrypt.h @@ -134,12 +134,14 @@ int algo_needs_missing(struct algo_needs* n); /** * Format error reason for algorithm missing. - * @param env: module env with scratch for temp storage of string. * @param alg: DNSKEY-algorithm missing. * @param reason: destination. * @param s: string, appended with 'with algorithm ..'. + * @param reasonbuf: buffer to use for fail reason string print. + * @param reasonlen: length of reasonbuf. */ -void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s); +void algo_needs_reason(int alg, char** reason, char* s, char* reasonbuf, + size_t reasonlen); /** * Check if dnskey matches a DS digest @@ -261,6 +263,8 @@ uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx); * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. * @param verified: if not NULL the number of RRSIG validations is returned. + * @param reasonbuf: buffer to use for fail reason string print. + * @param reasonlen: length of reasonbuf. * @return SECURE if one key in the set verifies one rrsig. * UNCHECKED on allocation errors, unsupported algorithms, malformed data, * and BOGUS on verification failures (no keys match any signatures). @@ -269,8 +273,8 @@ enum sec_status dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, - sldns_pkt_section section, struct module_qstate* qstate, int* verified); - + sldns_pkt_section section, struct module_qstate* qstate, int* verified, + char* reasonbuf, size_t reasonlen); /** * verify rrset against one specific dnskey (from rrset) diff --git a/validator/val_utils.c b/validator/val_utils.c index add6d9bba..549264d76 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -406,7 +406,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys, uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int *verified) + int *verified, char* reasonbuf, size_t reasonlen) { enum sec_status sec; struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> @@ -431,7 +431,7 @@ val_verify_rrset(struct module_env* env, struct val_env* ve, log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname, ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class)); sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason, - reason_bogus, section, qstate, verified); + reason_bogus, section, qstate, verified, reasonbuf, reasonlen); verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec)); regional_free_all(env->scratch); @@ -466,7 +466,7 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* verified) + int* verified, char* reasonbuf, size_t reasonlen) { /* temporary dnskey rrset-key */ struct ub_packed_rrset_key dnskey; @@ -480,7 +480,7 @@ val_verify_rrset_entry(struct module_env* env, struct val_env* ve, dnskey.entry.key = &dnskey; dnskey.entry.data = kd->rrset_data; sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason, - reason_bogus, section, qstate, verified); + reason_bogus, section, qstate, verified, reasonbuf, reasonlen); return sec; } @@ -490,7 +490,7 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, - int *nonechecked) + int *nonechecked, char* reasonbuf, size_t reasonlen) { enum sec_status sec = sec_status_bogus; size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0; @@ -544,8 +544,8 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, return sec_status_insecure; } if(numchecked == 0) { - algo_needs_reason(env, ds_get_key_algo(ds_rrset, ds_idx), - reason, "no keys have a DS"); + algo_needs_reason(ds_get_key_algo(ds_rrset, ds_idx), + reason, "no keys have a DS", reasonbuf, reasonlen); *nonechecked = 1; } else if(numhashok == 0) { *reason = "DS hash mismatches key"; @@ -576,7 +576,8 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason, - sldns_ede_code *reason_bogus, struct module_qstate* qstate) + sldns_ede_code *reason_bogus, struct module_qstate* qstate, + char* reasonbuf, size_t reasonlen) { /* as long as this is false, we can consider this DS rrset to be * equivalent to no DS rrset. */ @@ -615,7 +616,7 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, ds_rrset, i, reason, reason_bogus, qstate, - &nonechecked); + &nonechecked, reasonbuf, reasonlen); if(sec == sec_status_insecure) { /* DNSKEY too large unsupported or algo refused by * crypto lib. */ @@ -666,8 +667,8 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, /* If any were understandable, then it is bad. */ verbose(VERB_QUERY, "Failed to match any usable DS to a DNSKEY."); if(sigalg && (alg=algo_needs_missing(&needs)) != 0) { - algo_needs_reason(env, alg, reason, "missing verification of " - "DNSKEY signature"); + algo_needs_reason(alg, reason, "missing verification of " + "DNSKEY signature", reasonbuf, reasonlen); } return sec_status_bogus; } @@ -676,12 +677,13 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region, struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason, - sldns_ede_code *reason_bogus, struct module_qstate* qstate) + sldns_ede_code *reason_bogus, struct module_qstate* qstate, + char* reasonbuf, size_t reasonlen) { uint8_t sigalg[ALGO_NEEDS_MAX+1]; enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve, dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason, - reason_bogus, qstate); + reason_bogus, qstate, reasonbuf, reasonlen); if(sec == sec_status_secure) { return key_entry_create_rrset(region, @@ -706,7 +708,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ta_ds, struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason, - sldns_ede_code *reason_bogus, struct module_qstate* qstate) + sldns_ede_code *reason_bogus, struct module_qstate* qstate, + char* reasonbuf, size_t reasonlen) { /* as long as this is false, we can consider this anchor to be * equivalent to no anchor. */ @@ -757,7 +760,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, continue; sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, - ta_ds, i, reason, reason_bogus, qstate, &nonechecked); + ta_ds, i, reason, reason_bogus, qstate, &nonechecked, + reasonbuf, reasonlen); if(sec == sec_status_insecure) { has_algo_refusal = 1; continue; @@ -837,8 +841,8 @@ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, /* If any were understandable, then it is bad. */ verbose(VERB_QUERY, "Failed to match any usable anchor to a DNSKEY."); if(sigalg && (alg=algo_needs_missing(&needs)) != 0) { - algo_needs_reason(env, alg, reason, "missing verification of " - "DNSKEY signature"); + algo_needs_reason(alg, reason, "missing verification of " + "DNSKEY signature", reasonbuf, reasonlen); } return sec_status_bogus; } @@ -848,12 +852,14 @@ val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ta_ds_rrset, struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot, - char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate) + char** reason, sldns_ede_code *reason_bogus, + struct module_qstate* qstate, char* reasonbuf, size_t reasonlen) { uint8_t sigalg[ALGO_NEEDS_MAX+1]; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset, - downprot?sigalg:NULL, reason, reason_bogus, qstate); + downprot?sigalg:NULL, reason, reason_bogus, qstate, + reasonbuf, reasonlen); if(sec == sec_status_secure) { return key_entry_create_rrset(region, diff --git a/validator/val_utils.h b/validator/val_utils.h index e8cdcefa6..4fe38c1bb 100644 --- a/validator/val_utils.h +++ b/validator/val_utils.h @@ -125,13 +125,15 @@ void val_find_signer(enum val_classification subtype, * @param section: section of packet where this rrset comes from. * @param qstate: qstate with region. * @param verified: if not NULL, the number of RRSIG validations is returned. + * @param reasonbuf: buffer to use for fail reason string print. + * @param reasonlen: length of reasonbuf. * @return security status of verification. */ enum sec_status val_verify_rrset_entry(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus, sldns_pkt_section section, struct module_qstate* qstate, - int* verified); + int* verified, char* reasonbuf, size_t reasonlen); /** * Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but @@ -146,6 +148,8 @@ enum sec_status val_verify_rrset_entry(struct module_env* env, * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param reasonbuf: buffer to use for fail reason string print. + * @param reasonlen: length of reasonbuf. * @return: sec_status_secure if a DS matches. * sec_status_insecure if end of trust (i.e., unknown algorithms). * sec_status_bogus if it fails. @@ -153,7 +157,8 @@ enum sec_status val_verify_rrset_entry(struct module_env* env, enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason, - sldns_ede_code *reason_bogus, struct module_qstate* qstate); + sldns_ede_code *reason_bogus, struct module_qstate* qstate, + char* reasonbuf, size_t reasonlen); /** * Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS @@ -167,8 +172,10 @@ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env, * algorithm is enough. The list of signalled algorithms is returned, * must have enough space for ALGO_NEEDS_MAX+1. * @param reason: reason of failure. Fixed string or alloced in scratch. -* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. + * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param reasonbuf: buffer to use for fail reason string print. + * @param reasonlen: length of reasonbuf. * @return: sec_status_secure if a DS matches. * sec_status_insecure if end of trust (i.e., unknown algorithms). * sec_status_bogus if it fails. @@ -177,7 +184,8 @@ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ta_ds, struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason, - sldns_ede_code *reason_bogus, struct module_qstate* qstate); + sldns_ede_code *reason_bogus, struct module_qstate* qstate, + char* reasonbuf, size_t reasonlen); /** * Verify new DNSKEYs with DS rrset. The DS contains hash values that should @@ -194,6 +202,8 @@ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env, * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param reasonbuf: buffer to use for fail reason string print. + * @param reasonlen: length of reasonbuf. * @return a KeyEntry. This will either contain the now trusted * dnskey_rrset, a "null" key entry indicating that this DS * rrset/DNSKEY pair indicate an secure end to the island of trust @@ -208,7 +218,8 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region, struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason, - sldns_ede_code *reason_bogus, struct module_qstate* qstate); + sldns_ede_code *reason_bogus, struct module_qstate* qstate, + char* reasonbuf, size_t reasonlen); /** * Verify rrset with trust anchor: DS and DNSKEY rrset. @@ -224,6 +235,8 @@ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region, * @param reason: reason of failure. Fixed string or alloced in scratch. * @param reason_bogus: EDE (RFC8914) code paired with the reason of failure. * @param qstate: qstate with region. + * @param reasonbuf: buffer to use for fail reason string print. + * @param reasonlen: length of reasonbuf. * @return a KeyEntry. This will either contain the now trusted * dnskey_rrset, a "null" key entry indicating that this DS * rrset/DNSKEY pair indicate an secure end to the island of trust @@ -239,7 +252,8 @@ struct key_entry_key* val_verify_new_DNSKEYs_with_ta(struct regional* region, struct ub_packed_rrset_key* dnskey_rrset, struct ub_packed_rrset_key* ta_ds_rrset, struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot, - char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate); + char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate, + char* reasonbuf, size_t reasonlen); /** * Determine if DS rrset is usable for validator or not. diff --git a/validator/validator.c b/validator/validator.c index f5894e30c..77718cbfd 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -647,6 +647,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq, struct ub_packed_rrset_key* s; enum sec_status sec; int num_verifies = 0, verified, have_state = 0; + char reasonbuf[256]; char* reason = NULL; sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; *suspend = 0; @@ -682,7 +683,8 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq, /* Verify the answer rrset */ sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, - &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified); + &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified, + reasonbuf, sizeof(reasonbuf)); /* If the (answer) rrset failed to validate, then this * message is BAD. */ if(sec != sec_status_secure) { @@ -727,7 +729,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq, s = chase_reply->rrsets[i]; sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, &reason_bogus, LDNS_SECTION_AUTHORITY, qstate, - &verified); + &verified, reasonbuf, sizeof(reasonbuf)); /* If anything in the authority section fails to be secure, * we have a bad message. */ if(sec != sec_status_secure) { @@ -773,7 +775,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq, if(sname && query_dname_compare(sname, key_entry->name)==0) (void)val_verify_rrset_entry(env, ve, s, key_entry, &reason, NULL, LDNS_SECTION_ADDITIONAL, qstate, - &verified); + &verified, reasonbuf, sizeof(reasonbuf)); /* the additional section can fail to be secure, * it is optional, check signature in case we need * to clean the additional section later. */ @@ -2680,6 +2682,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; struct key_entry_key* kkey = NULL; enum sec_status sec = sec_status_unchecked; + char reasonbuf[256]; char* reason = NULL; sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; int downprot = qstate->env->cfg->harden_algo_downgrade; @@ -2716,7 +2719,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, /* attempt to verify with trust anchor DS and DNSKEY */ kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve, dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot, - &reason, &reason_bogus, qstate); + &reason, &reason_bogus, qstate, reasonbuf, sizeof(reasonbuf)); if(!kkey) { log_err("out of memory: verifying prime TA"); return NULL; @@ -2785,6 +2788,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, struct key_entry_key** ke, struct module_qstate* sub_qstate) { struct val_env* ve = (struct val_env*)qstate->env->modinfo[id]; + char reasonbuf[256]; char* reason = NULL; sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; enum val_classification subtype; @@ -2827,7 +2831,9 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, /* Verify only returns BOGUS or SECURE. If the rrset is * bogus, then we are done. */ sec = val_verify_rrset_entry(qstate->env, ve, ds, - vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified); + vq->key_entry, &reason, &reason_bogus, + LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf, + sizeof(reasonbuf)); if(sec != sec_status_secure) { verbose(VERB_DETAIL, "DS rrset in DS response did " "not verify"); @@ -2877,7 +2883,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, /* Try to prove absence of the DS with NSEC */ sec = val_nsec_prove_nodata_dsreply( qstate->env, ve, qinfo, msg->rep, vq->key_entry, - &proof_ttl, &reason, &reason_bogus, qstate); + &proof_ttl, &reason, &reason_bogus, qstate, + reasonbuf, sizeof(reasonbuf)); switch(sec) { case sec_status_secure: verbose(VERB_DETAIL, "NSEC RRset for the " @@ -2914,7 +2921,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, sec = nsec3_prove_nods(qstate->env, ve, msg->rep->rrsets + msg->rep->an_numrrsets, msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason, - &reason_bogus, qstate, &vq->nsec3_cache_table); + &reason_bogus, qstate, &vq->nsec3_cache_table, + reasonbuf, sizeof(reasonbuf)); switch(sec) { case sec_status_insecure: /* case insecure also continues to unsigned @@ -2981,7 +2989,8 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, } sec = val_verify_rrset_entry(qstate->env, ve, cname, vq->key_entry, &reason, &reason_bogus, - LDNS_SECTION_ANSWER, qstate, &verified); + LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf, + sizeof(reasonbuf)); if(sec == sec_status_secure) { verbose(VERB_ALGO, "CNAME validated, " "proof that DS does not exist"); @@ -3135,6 +3144,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, struct key_entry_key* old = vq->key_entry; struct ub_packed_rrset_key* dnskey = NULL; int downprot; + char reasonbuf[256]; char* reason = NULL; sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; @@ -3185,7 +3195,8 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, } downprot = qstate->env->cfg->harden_algo_downgrade; vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env, - ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, qstate); + ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, + qstate, reasonbuf, sizeof(reasonbuf)); if(!vq->key_entry) { log_err("out of memory in verify new DNSKEYs");