diff --git a/services/cache/rrset.c b/services/cache/rrset.c index ab4f4c8e0..404e11fbb 100644 --- a/services/cache/rrset.c +++ b/services/cache/rrset.c @@ -50,6 +50,7 @@ #include "util/regional.h" #include "util/alloc.h" #include "util/net_help.h" +#include "validator/val_utils.h" void rrset_markdel(void* key) @@ -255,12 +256,43 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, return 0; } +/** See if the name is a within signer authority */ +static int +dname_subdomain_rrsig_signers(uint8_t* dname, + struct ub_packed_rrset_key* rrset) +{ + struct packed_rrset_data* d = (struct packed_rrset_data*) + rrset->entry.data; + size_t i; + if(!d || !d->rrsig_count) + return 0; + for(i=0; irrsig_count; i++) { + uint8_t* sname = NULL; + size_t slen = 0; + rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i], + &sname, &slen); + if(!sname || !slen) + return 0; /* malformed */ + if(!dname_subdomain_c(dname, sname)) + return 0; /* not a subdomain */ + } + return 1; +} + void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache, struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len, struct alloc_cache* alloc, time_t timenow) { struct rrset_ref ref; uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3]; + + /* See if the RRSIG signer name allows this wildcard, + * the new rrset should fall within the zone of the RRSIG signer(s). */ + if(!dname_subdomain_rrsig_signers(ce, rrset)) { + verbose(VERB_ALGO, "wildcard canonical parent outside signer authority"); + return; + } + rrset = packed_rrset_copy_alloc(rrset, alloc, timenow); if(!rrset) { log_err("malloc failure in rrset_cache_update_wildcard"); diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index 9f27f9cc9..46e6ac16b 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -1666,6 +1666,13 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; return sec_status_bogus; } + if((int)sig[2+3] < dname_signame_label_count(signer)) { + verbose(VERB_QUERY, "verify: RRSIG label count too low for signer"); + *reason = "signature labelcount lower than signature signer"; + if(reason_bogus) + *reason_bogus = LDNS_EDE_DNSSEC_BOGUS; + return sec_status_bogus; + } /* original ttl, always ok */ diff --git a/validator/val_utils.c b/validator/val_utils.c index 8e4c91900..289078347 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -157,7 +157,7 @@ val_classify_response(uint16_t query_flags, struct query_info* origqinf, } /** Get signer name from RRSIG */ -static void +void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen) { /* RRSIG rdata is not allowed to be compressed, it is stored diff --git a/validator/val_utils.h b/validator/val_utils.h index e0c649902..f3750742b 100644 --- a/validator/val_utils.h +++ b/validator/val_utils.h @@ -438,4 +438,8 @@ struct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, int derive_cname_from_dname(struct ub_packed_rrset_key* cname, struct ub_packed_rrset_key* dname, uint8_t* out, size_t outlen); +/** Get signer name from RRSIG, sname is NULL if malformed. */ +void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, + size_t* slen); + #endif /* VALIDATOR_VAL_UTILS_H */ diff --git a/validator/validator.c b/validator/validator.c index e7992b6e3..a72aa9c6a 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -1043,6 +1043,10 @@ validate_positive_response(struct module_env* env, struct val_env* ve, uint8_t* wc = NULL; size_t wl; int wc_cached = 0; + int wc_to_cache = 0; + uint8_t* cache_wc = NULL; + size_t cache_wl = 0; + struct ub_packed_rrset_key* cache_s = NULL; int wc_NSEC_ok = 0; int nsec3s_seen = 0; size_t i; @@ -1065,8 +1069,11 @@ validate_positive_response(struct module_env* env, struct val_env* ve, return; } if(wc && !wc_cached && env->cfg->aggressive_nsec) { - rrset_cache_update_wildcard(env->rrset_cache, s, wc, wl, - env->alloc, *env->now); + /* Postpone cache adjust until proof has succeeded. */ + wc_to_cache = 1; + cache_wc = wc; + cache_wl = wl; + cache_s = s; wc_cached = 1; } @@ -1128,6 +1135,10 @@ validate_positive_response(struct module_env* env, struct val_env* ve, update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS); return; } + if(wc_to_cache) { + rrset_cache_update_wildcard(env->rrset_cache, cache_s, + cache_wc, cache_wl, env->alloc, *env->now); + } verbose(VERB_ALGO, "Successfully validated positive response"); chase_reply->security = sec_status_secure;