From a664e8cec4b71a0b9e4aecc92fc96f668c0a16bb Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Tue, 14 Sep 2021 07:45:51 +0000 Subject: [PATCH] First step towards specific EDE DNSSEC errors --- validator/val_sigcrypt.c | 74 +++++++++++++++++++++++++++++++++++----- validator/val_sigcrypt.h | 9 +++++ validator/val_utils.c | 22 ++++++++---- validator/val_utils.h | 9 +++++ validator/validator.c | 21 ++++++++---- 5 files changed, 113 insertions(+), 22 deletions(-) diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index b15fba3f4..08a963058 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -530,6 +530,24 @@ 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_pkt_section section, struct module_qstate* qstate) +{ + return dnskeyset_verify_rrset_ede( + env, ve, rrset, dnskey, sigalg, reason, NULL, section, qstate); +} + +static enum sec_status +dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, + time_t now, struct ub_packed_rrset_key* rrset, + struct ub_packed_rrset_key* dnskey, size_t sig_idx, + struct rbtree_type** sortree, + char** reason, sldns_ede_code *reason_bogus, + sldns_pkt_section section, struct module_qstate* qstate); + +enum sec_status +dnskeyset_verify_rrset_ede(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) { enum sec_status sec; size_t i, num; @@ -543,6 +561,8 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, verbose(VERB_QUERY, "rrset failed to verify due to a lack of " "signatures"); *reason = "no signatures"; + if (reason_bogus) + *reason_bogus = LDNS_EDE_RRSIGS_MISSING; return sec_status_bogus; } @@ -551,12 +571,15 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, if(algo_needs_num_missing(&needs) == 0) { verbose(VERB_QUERY, "zone has no known algorithms"); *reason = "zone has no known algorithms"; + if (reason_bogus) + *reason_bogus = LDNS_EDE_UNSUPPORTED_DNSKEY_ALG; return sec_status_insecure; } } for(i=0; inow, rrset, - dnskey, i, &sortree, reason, section, qstate); + dnskey, i, &sortree, reason, reason_bogus, + section, qstate); /* see which algorithm has been fixed up */ if(sec == sec_status_secure) { if(!sigalg) @@ -633,12 +656,22 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve, return sec_status_bogus; } -enum sec_status +static enum sec_status +dnskey_verify_rrset_sig_ede(struct regional* region, sldns_buffer* buf, + struct val_env* ve, time_t now, + struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, + size_t dnskey_idx, size_t sig_idx, + struct rbtree_type** sortree, int* buf_canon, + char** reason, sldns_ede_code *reason_bogus, + sldns_pkt_section section, struct module_qstate* qstate); + +static enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t sig_idx, - struct rbtree_type** sortree, char** reason, sldns_pkt_section section, - struct module_qstate* qstate) + struct rbtree_type** sortree, + char** reason, sldns_ede_code *reason_bogus, + sldns_pkt_section section, struct module_qstate* qstate) { /* find matching keys and check them */ enum sec_status sec = sec_status_bogus; @@ -661,9 +694,10 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, numchecked ++; /* see if key verifies */ - sec = dnskey_verify_rrset_sig(env->scratch, + sec = dnskey_verify_rrset_sig_ede(env->scratch, env->scratch_buffer, ve, now, rrset, dnskey, i, - sig_idx, sortree, &buf_canon, reason, section, qstate); + sig_idx, sortree, &buf_canon, reason, reason_bogus, + section, qstate); if(sec == sec_status_secure) return sec; } @@ -1361,8 +1395,8 @@ subtract_1982(uint32_t a, uint32_t b) /** check rrsig dates */ static int -check_dates(struct val_env* ve, uint32_t unow, - uint8_t* expi_p, uint8_t* incep_p, char** reason) +check_dates(struct val_env* ve, uint32_t unow, uint8_t* expi_p, + uint8_t* incep_p, char** reason, sldns_ede_code *reason_bogus) { /* read out the dates */ uint32_t expi, incep, now; @@ -1386,6 +1420,7 @@ check_dates(struct val_env* ve, uint32_t unow, sigdate_error("verify: inception after expiration, " "signature bad", expi, incep, now); *reason = "signature inception after expiration"; + /* @TODO Tom, wat hier te doen? */ return 0; } if(compare_1982(incep, now) > 0) { @@ -1397,6 +1432,8 @@ check_dates(struct val_env* ve, uint32_t unow, sigdate_error("verify: signature bad, current time is" " before inception date", expi, incep, now); *reason = "signature before inception date"; + if (reason_bogus) + *reason_bogus = LDNS_EDE_SIGNATURE_NOT_YET_VALID; return 0; } sigdate_error("verify warning suspicious signature inception " @@ -1410,6 +1447,8 @@ check_dates(struct val_env* ve, uint32_t unow, sigdate_error("verify: signature expired", expi, incep, now); *reason = "signature expired"; + if (reason_bogus) + *reason_bogus = LDNS_EDE_SIGNATURE_EXPIRED; return 0; } sigdate_error("verify warning suspicious signature expiration " @@ -1475,6 +1514,20 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, size_t dnskey_idx, size_t sig_idx, struct rbtree_type** sortree, int* buf_canon, char** reason, sldns_pkt_section section, struct module_qstate* qstate) +{ + return dnskey_verify_rrset_sig_ede(region, buf, ve, now, rrset, dnskey, + dnskey_idx, sig_idx, sortree, buf_canon, reason, NULL, + section, qstate); +} + +static enum sec_status +dnskey_verify_rrset_sig_ede(struct regional* region, sldns_buffer* buf, + struct val_env* ve, time_t now, + struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, + size_t dnskey_idx, size_t sig_idx, + struct rbtree_type** sortree, int* buf_canon, + char** reason, sldns_ede_code *reason_bogus, + sldns_pkt_section section, struct module_qstate* qstate) { enum sec_status sec; uint8_t* sig; /* RRSIG rdata */ @@ -1498,6 +1551,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, if(!(dnskey_get_flags(dnskey, dnskey_idx) & DNSKEY_BIT_ZSK)) { verbose(VERB_QUERY, "verify: dnskey without ZSK flag"); *reason = "dnskey without ZSK flag"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_NO_ZONE_KEY_BIT_SET; return sec_status_bogus; } @@ -1598,7 +1653,8 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, /* verify inception, expiration dates * Do this last so that if you ignore expired-sigs the * rest is sure to be OK. */ - if(!check_dates(ve, now, sig+2+8, sig+2+12, reason)) { + if(!check_dates(ve, now, sig+2+8, sig+2+12, + reason, reason_bogus)) { return sec_status_bogus; } } diff --git a/validator/val_sigcrypt.h b/validator/val_sigcrypt.h index bbb95780d..af16c293c 100644 --- a/validator/val_sigcrypt.h +++ b/validator/val_sigcrypt.h @@ -45,6 +45,7 @@ #define VALIDATOR_VAL_SIGCRYPT_H #include "util/data/packed_rrset.h" #include "sldns/pkthdr.h" +#include "sldns/rrdef.h" struct val_env; struct module_env; struct module_qstate; @@ -266,6 +267,12 @@ 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_pkt_section section, struct module_qstate* qstate); +enum sec_status dnskeyset_verify_rrset_ede(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); + /** * verify rrset against one specific dnskey (from rrset) @@ -285,6 +292,7 @@ enum sec_status dnskey_verify_rrset(struct module_env* env, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason, sldns_pkt_section section, struct module_qstate* qstate); +#if 0 /** * verify rrset, with dnskey rrset, for a specific rrsig in rrset * @param env: module environment, scratch space is used. @@ -306,6 +314,7 @@ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, struct ub_packed_rrset_key* dnskey, size_t sig_idx, struct rbtree_type** sortree, char** reason, sldns_pkt_section section, struct module_qstate* qstate); +#endif /** * verify rrset, with specific dnskey(from set), for a specific rrsig diff --git a/validator/val_utils.c b/validator/val_utils.c index dd8d320e5..d0a59ef02 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -332,11 +332,11 @@ rrset_get_ttl(struct ub_packed_rrset_key* rrset) return d->ttl; } -enum sec_status +static enum sec_status 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_pkt_section section, - struct module_qstate* qstate) + uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus, + sldns_pkt_section section, struct module_qstate* qstate) { enum sec_status sec; struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> @@ -358,8 +358,8 @@ 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, - section, qstate); + sec = dnskeyset_verify_rrset_ede(env, ve, rrset, keys, sigalg, reason, + reason_bogus, section, qstate); verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec)); regional_free_all(env->scratch); @@ -393,6 +393,16 @@ 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_pkt_section section, struct module_qstate* qstate) +{ + return val_verify_rrset_entry_ede( + env, ve, rrset, kkey, reason, NULL, section, qstate); +} + +enum sec_status +val_verify_rrset_entry_ede(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) { /* temporary dnskey rrset-key */ struct ub_packed_rrset_key dnskey; @@ -406,7 +416,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, - section, qstate); + reason_bogus, section, qstate); return sec; } diff --git a/validator/val_utils.h b/validator/val_utils.h index 6e9867f6e..b7b0aea1b 100644 --- a/validator/val_utils.h +++ b/validator/val_utils.h @@ -43,6 +43,7 @@ #define VALIDATOR_VAL_UTILS_H #include "util/data/packed_rrset.h" #include "sldns/pkthdr.h" +#include "sldns/rrdef.h" struct query_info; struct reply_info; struct val_env; @@ -113,6 +114,7 @@ void val_find_signer(enum val_classification subtype, struct query_info* qinf, struct reply_info* rep, size_t cname_skip, uint8_t** signer_name, size_t* signer_len); +#if 0 /** * Verify RRset with keys * @param env: module environment (scratch buffer) @@ -130,6 +132,7 @@ enum sec_status 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_pkt_section section, struct module_qstate* qstate); +#endif /** * Verify RRset with keys from a keyset. @@ -147,6 +150,12 @@ enum sec_status val_verify_rrset_entry(struct module_env* env, struct key_entry_key* kkey, char** reason, sldns_pkt_section section, struct module_qstate* qstate); +enum sec_status val_verify_rrset_entry_ede(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); + + /** * Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but * returns a sec_status instead of a key_entry. diff --git a/validator/validator.c b/validator/validator.c index d4d48d956..f71c2191a 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -592,6 +592,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, enum sec_status sec; int dname_seen = 0; char* reason = NULL; + sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; /* validate the ANSWER section */ for(i=0; ian_numrrsets; i++) { @@ -612,8 +613,8 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, } /* Verify the answer rrset */ - sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, - LDNS_SECTION_ANSWER, qstate); + sec = val_verify_rrset_entry_ede(env, ve, s, key_entry, &reason, + &reason_bogus, LDNS_SECTION_ANSWER, qstate); /* If the (answer) rrset failed to validate, then this * message is BAD. */ if(sec != sec_status_secure) { @@ -627,6 +628,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, errinf(qstate, "for DNAME"); errinf_origin(qstate, qstate->reply_origin); chase_reply->security = sec_status_bogus; + chase_reply->reason_bogus = reason_bogus; return 0; } @@ -642,8 +644,8 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, for(i=chase_reply->an_numrrsets; ian_numrrsets+ chase_reply->ns_numrrsets; i++) { s = chase_reply->rrsets[i]; - sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason, - LDNS_SECTION_AUTHORITY, qstate); + sec = val_verify_rrset_entry_ede(env, ve, s, key_entry, &reason, + &reason_bogus, LDNS_SECTION_AUTHORITY, qstate); /* If anything in the authority section fails to be secure, * we have a bad message. */ if(sec != sec_status_secure) { @@ -654,6 +656,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct module_env* env, errinf_origin(qstate, qstate->reply_origin); errinf_rrset(qstate, s); chase_reply->security = sec_status_bogus; + chase_reply->reason_bogus = reason_bogus; return 0; } } @@ -2001,17 +2004,21 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, vq->orig_msg->rep, vq->rrset_skip); /* store overall validation result in orig_msg */ - if(vq->rrset_skip == 0) + if(vq->rrset_skip == 0) { vq->orig_msg->rep->security = vq->chase_reply->security; - else if(subtype != VAL_CLASS_REFERRAL || + vq->orig_msg->rep->reason_bogus = vq->chase_reply->reason_bogus; + } else if(subtype != VAL_CLASS_REFERRAL || vq->rrset_skip < vq->orig_msg->rep->an_numrrsets + vq->orig_msg->rep->ns_numrrsets) { /* ignore sec status of additional section if a referral * type message skips there and * use the lowest security status as end result. */ - if(vq->chase_reply->security < vq->orig_msg->rep->security) + if(vq->chase_reply->security < vq->orig_msg->rep->security) { vq->orig_msg->rep->security = vq->chase_reply->security; + vq->orig_msg->rep->reason_bogus = + vq->chase_reply->reason_bogus; + } } if(subtype == VAL_CLASS_REFERRAL) { -- 2.47.2