From: Wouter Wijngaards Date: Thu, 1 Jul 2010 12:08:48 +0000 (+0000) Subject: Fix 4035 compliance for algorithms from the DS rrset that MUST sign the DNSKEY. X-Git-Tag: release-1.4.6rc1~27 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=518504ff5cf71e8f500bd4d2e1036194394eac25;p=thirdparty%2Funbound.git Fix 4035 compliance for algorithms from the DS rrset that MUST sign the DNSKEY. git-svn-id: file:///svn/unbound/trunk@2172 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 268fb31d6..20ef88701 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,8 @@ +1 July 2010: Wouter + - Fix RFC4035 compliance with 2.2 statement that the DNSKEY at apex + must be signed with all algorithms from the DS rrset at the parent. + This is now checked and becomes bogus if not. + 28 June 2010: Wouter - Fix jostle list bug found by Vince (luoce@cnnic), it caused the qps in overload situations to be about 5 qps for the class of shortly diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index 2a3e8a5ff..0b05bbfc3 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -452,41 +452,75 @@ int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset, dnskey_idx)); } -/** - * Fillup needed algorithm array for DNSKEY set - * @param dnskey: the key - * @param needs: array per algorithm. - * @return the number of algorithms that need valid signatures - */ -static size_t -dnskeyset_needs(struct ub_packed_rrset_key* dnskey, uint8_t needs[]) +void algo_needs_init_dnskey(struct algo_needs* n, + struct ub_packed_rrset_key* dnskey) { uint8_t algo; size_t i, total = 0; size_t num = rrset_get_count(dnskey); - memset(needs, 0, sizeof(uint8_t)*256); + memset(n->needs, 0, sizeof(uint8_t)*ALGO_NEEDS_MAX); for(i=0; ineeds[algo] == 0) { + n->needs[algo] = 1; total++; } } - return total; + n->num = total; +} + +void algo_needs_init_ds(struct algo_needs* n, struct ub_packed_rrset_key* ds, + int fav_ds_algo) +{ + uint8_t algo; + size_t i, total = 0; + size_t num = rrset_get_count(ds); + + memset(n->needs, 0, sizeof(uint8_t)*ALGO_NEEDS_MAX); + for(i=0; ineeds[algo] == 0) { + n->needs[algo] = 1; + total++; + } + } + n->num = total; +} + +int algo_needs_set_secure(struct algo_needs* n, uint8_t algo) +{ + if(n->needs[algo]) { + n->needs[algo] = 0; + n->num --; + if(n->num == 0) /* done! */ + return 1; + } + return 0; +} + +void algo_needs_set_bogus(struct algo_needs* n, uint8_t algo) +{ + if(n->needs[algo]) n->needs[algo] = 2; /* need it, but bogus */ } -/** see which algo needed */ -static int any_needed_bogus(uint8_t needs[]) +size_t algo_needs_num_missing(struct algo_needs* n) +{ + return n->num; +} + +int algo_needs_missing(struct algo_needs* n) { int i; /* first check if a needed algo was bogus - report that */ - for(i=0; i<256; i++) - if(needs[i] == 2) + for(i=0; ineeds[i] == 2) return 0; /* now check which algo is missing */ - for(i=0; i<256; i++) - if(needs[i] == 1) + for(i=0; ineeds[i] == 1) return i; return 0; } @@ -497,10 +531,10 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, char** reason) { enum sec_status sec; - size_t i, num, numneeds; + size_t i, num; rbtree_t* sortree = NULL; /* make sure that for all DNSKEY algorithms there are valid sigs */ - uint8_t needs[256]; /* 1 if need sig for that algorithm */ + struct algo_needs needs; int alg; num = rrset_get_sigcount(rrset); @@ -511,41 +545,41 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, return sec_status_bogus; } - numneeds = dnskeyset_needs(dnskey, needs); + algo_needs_init_dnskey(&needs, dnskey); for(i=0; inow, rrset, dnskey, i, &sortree, reason); /* see which algorithm has been fixed up */ if(sec == sec_status_secure) { - uint8_t a = (uint8_t)rrset_get_sig_algo(rrset, i); - if(needs[a]) { - needs[a] = 0; - numneeds --; - if(numneeds == 0) /* done! */ - return sec; - } + if(algo_needs_set_secure(&needs, + (uint8_t)rrset_get_sig_algo(rrset, i))) + return sec; /* done! */ } else if(sec == sec_status_bogus) { - uint8_t a = (uint8_t)rrset_get_sig_algo(rrset, i); - if(needs[a]) needs[a] = 2; /* need it, but bogus */ + algo_needs_set_bogus(&needs, + (uint8_t)rrset_get_sig_algo(rrset, i)); } } verbose(VERB_ALGO, "rrset failed to verify: no valid signatures for " - "%d algorithms", (int)numneeds); - if((alg=any_needed_bogus(needs)) != 0) { - char buf[256]; - ldns_lookup_table *t = ldns_lookup_by_id(ldns_algorithms, alg); - if(t&&t->name) - snprintf(buf, sizeof(buf), "no signatures with " - "algorithm %s", t->name); - else snprintf(buf, sizeof(buf), "no signatures with " - "algorithm ALG%u", (unsigned)alg); - *reason = regional_strdup(env->scratch, buf); - if(!*reason) - *reason = "no signatures for all algorithms"; + "%d algorithms", (int)algo_needs_num_missing(&needs)); + if((alg=algo_needs_missing(&needs)) != 0) { + algo_needs_reason(env, alg, reason, "no signatures"); } return sec_status_bogus; } +void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s) +{ + char buf[256]; + ldns_lookup_table *t = ldns_lookup_by_id(ldns_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 with all algorithms"; +} + enum sec_status dnskey_verify_rrset(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, diff --git a/validator/val_sigcrypt.h b/validator/val_sigcrypt.h index 95c702a09..3ced1e75a 100644 --- a/validator/val_sigcrypt.h +++ b/validator/val_sigcrypt.h @@ -50,6 +50,81 @@ struct ub_packed_rrset_key; struct rbtree_t; struct regional; +/** number of entries in algorithm needs array */ +#define ALGO_NEEDS_MAX 256 +/** + * Storage for algorithm needs. DNSKEY algorithms. + */ +struct algo_needs { + /** the algorithms (8-bit) with each a number. + * 0: not marked. + * 1: marked 'necessary but not yet fulfilled' + * 2: marked bogus. + * Indexed by algorithm number. + */ + uint8_t needs[ALGO_NEEDS_MAX]; + /** the number of entries in the array that are unfulfilled */ + size_t num; +}; + +/** + * Initialize algo needs structure, set algos from rrset as needed. + * @param n: struct with storage. + * @param dnskey: algos from this struct set as necessary. DNSKEY set. + */ +void algo_needs_init_dnskey(struct algo_needs* n, + struct ub_packed_rrset_key* dnskey); + +/** + * Initialize algo needs structure, set algos from rrset as needed. + * @param n: struct with storage. + * @param ds: algos from this struct set as necessary. DS set. + * @param fav_ds_algo: filter to use only this DS algo. + */ +void algo_needs_init_ds(struct algo_needs* n, struct ub_packed_rrset_key* ds, + int fav_ds_algo); + +/** + * Mark this algorithm as a success, sec_secure, and see if we are done. + * @param n: storage structure processed. + * @param algo: the algorithm processed to be secure. + * @return if true, processing has finished successfully, we are satisfied. + */ +int algo_needs_set_secure(struct algo_needs* n, uint8_t algo); + +/** + * Mark this algorithm a failure, sec_bogus. It can later be overridden + * by a success for this algorithm (with a different signature). + * @param n: storage structure processed. + * @param algo: the algorithm processed to be bogus. + */ +void algo_needs_set_bogus(struct algo_needs* n, uint8_t algo); + +/** + * See how many algorithms are missing (not bogus or secure, but not processed) + * @param n: storage structure processed. + * @return number of algorithms missing after processing. + */ +size_t algo_needs_num_missing(struct algo_needs* n); + +/** + * See which algo is missing. + * @param n: struct after processing. + * @return if 0 an algorithm was bogus, if a number, this algorithm was + * missing. So on 0, report why that was bogus, on number report a missing + * algorithm. There could be multiple missing, this reports the first one. + */ +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 ..'. + */ +void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s); + /** * Check if dnskey matches a DS digest * Does not check dnskey-keyid footprint, just the digest. diff --git a/validator/val_utils.c b/validator/val_utils.c index 298d39c11..c915e3dfd 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -424,7 +424,8 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, /* If it didn't validate with the DNSKEY, try the next one! */ } if(numchecked == 0) - *reason = "no keys have a DS"; + algo_needs_reason(env, ds_get_key_algo(ds_rrset, ds_idx), + reason, "no keys have a DS"); else if(numhashok == 0) *reason = "DS hash mismatches key"; else if(!*reason) @@ -456,7 +457,8 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, { /* as long as this is false, we can consider this DS rrset to be * equivalent to no DS rrset. */ - int has_useful_ds = 0, digest_algo; + int has_useful_ds = 0, digest_algo, alg; + struct algo_needs needs; size_t i, num; enum sec_status sec; @@ -470,6 +472,7 @@ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve, } digest_algo = val_favorite_ds_algo(ds_rrset); + algo_needs_init_ds(&needs, ds_rrset, digest_algo); num = rrset_get_count(ds_rrset); for(i=0; i