/** * Check DS algos for support, warn if not. * @param ta: trust anchor * @return number of DS anchors with unsupported algorithms. */ static size_t anchors_ds_unsupported(struct trust_anchor* ta) { size_t i, num = 0; for(i=0; i<ta->numDS; i++) { if(!ds_digest_algo_is_supported(ta->ds_rrset, i) || !ds_key_algo_is_supported(ta->ds_rrset, i)) num++; } return num; }
int val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset) { size_t i; for(i=0; i<rrset_get_count(ds_rrset); i++) { if(ds_digest_algo_is_supported(ds_rrset, i) && ds_key_algo_is_supported(ds_rrset, i)) return 1; } return 0; }
int val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset) { size_t i, num = rrset_get_count(ds_rrset); int d, digest_algo = 0; /* DS digest algo 0 is not used. */ /* find favorite algo, for now, highest number supported */ for(i=0; i<num; i++) { if(!ds_digest_algo_is_supported(ds_rrset, i) || !ds_key_algo_is_supported(ds_rrset, i)) { continue; } d = ds_get_digest_algo(ds_rrset, i); if(d > digest_algo) digest_algo = d; } return digest_algo; }
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, char** reason) { /* 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, alg; struct algo_needs needs; size_t i, num; enum sec_status sec; if(dnskey_rrset->rk.dname_len != ds_rrset->rk.dname_len || query_dname_compare(dnskey_rrset->rk.dname, ds_rrset->rk.dname) != 0) { verbose(VERB_QUERY, "DNSKEY RRset did not match DS RRset " "by name"); *reason = "DNSKEY RRset did not match DS RRset by name"; return sec_status_bogus; } 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<num; i++) { /* Check to see if we can understand this DS. * And check it is the strongest digest */ if(!ds_digest_algo_is_supported(ds_rrset, i) || !ds_key_algo_is_supported(ds_rrset, i) || ds_get_digest_algo(ds_rrset, i) != digest_algo) { continue; } /* Once we see a single DS with a known digestID and * algorithm, we cannot return INSECURE (with a * "null" KeyEntry). */ has_useful_ds = true; sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, ds_rrset, i, reason); if(sec == sec_status_secure) { if(algo_needs_set_secure(&needs, (uint8_t)ds_get_key_algo(ds_rrset, i))) { verbose(VERB_ALGO, "DS matched DNSKEY."); return sec_status_secure; } } else if(sec == sec_status_bogus) { algo_needs_set_bogus(&needs, (uint8_t)ds_get_key_algo(ds_rrset, i)); } } /* None of the DS's worked out. */ /* If no DSs were understandable, then this is OK. */ if(!has_useful_ds) { verbose(VERB_ALGO, "No usable DS records were found -- " "treating as insecure."); return sec_status_insecure; } /* If any were understandable, then it is bad. */ verbose(VERB_QUERY, "Failed to match any usable DS to a DNSKEY."); if((alg=algo_needs_missing(&needs)) != 0) { algo_needs_reason(env, alg, reason, "missing verification of " "DNSKEY signature"); } return sec_status_bogus; }
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) { /* as long as this is false, we can consider this anchor to be * equivalent to no anchor. */ int has_useful_ta = 0, digest_algo = 0, alg; struct algo_needs needs; size_t i, num; enum sec_status sec; if(ta_ds && (dnskey_rrset->rk.dname_len != ta_ds->rk.dname_len || query_dname_compare(dnskey_rrset->rk.dname, ta_ds->rk.dname) != 0)) { verbose(VERB_QUERY, "DNSKEY RRset did not match DS RRset " "by name"); *reason = "DNSKEY RRset did not match DS RRset by name"; return sec_status_bogus; } if(ta_dnskey && (dnskey_rrset->rk.dname_len != ta_dnskey->rk.dname_len || query_dname_compare(dnskey_rrset->rk.dname, ta_dnskey->rk.dname) != 0)) { verbose(VERB_QUERY, "DNSKEY RRset did not match anchor RRset " "by name"); *reason = "DNSKEY RRset did not match anchor RRset by name"; return sec_status_bogus; } if(ta_ds) digest_algo = val_favorite_ds_algo(ta_ds); if(sigalg) { if(ta_ds) algo_needs_init_ds(&needs, ta_ds, digest_algo, sigalg); else memset(&needs, 0, sizeof(needs)); if(ta_dnskey) algo_needs_init_dnskey_add(&needs, ta_dnskey, sigalg); } if(ta_ds) { num = rrset_get_count(ta_ds); for(i=0; i<num; i++) { /* Check to see if we can understand this DS. * And check it is the strongest digest */ if(!ds_digest_algo_is_supported(ta_ds, i) || !ds_key_algo_is_supported(ta_ds, i) || ds_get_digest_algo(ta_ds, i) != digest_algo) continue; /* Once we see a single DS with a known digestID and * algorithm, we cannot return INSECURE (with a * "null" KeyEntry). */ has_useful_ta = 1; sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, ta_ds, i, reason); if(sec == sec_status_secure) { if(!sigalg || algo_needs_set_secure(&needs, (uint8_t)ds_get_key_algo(ta_ds, i))) { verbose(VERB_ALGO, "DS matched DNSKEY."); return sec_status_secure; } } else if(sigalg && sec == sec_status_bogus) { algo_needs_set_bogus(&needs, (uint8_t)ds_get_key_algo(ta_ds, i)); } } } /* None of the DS's worked out: check the DNSKEYs. */ if(ta_dnskey) { num = rrset_get_count(ta_dnskey); for(i=0; i<num; i++) { /* Check to see if we can understand this DNSKEY */ if(!dnskey_algo_is_supported(ta_dnskey, i)) continue; /* we saw a useful TA */ has_useful_ta = 1; sec = dnskey_verify_rrset(env, ve, dnskey_rrset, ta_dnskey, i, reason); if(sec == sec_status_secure) { if(!sigalg || algo_needs_set_secure(&needs, (uint8_t)dnskey_get_algo(ta_dnskey, i))) { verbose(VERB_ALGO, "anchor matched DNSKEY."); return sec_status_secure; } } else if(sigalg && sec == sec_status_bogus) { algo_needs_set_bogus(&needs, (uint8_t)dnskey_get_algo(ta_dnskey, i)); } } } /* If no DSs were understandable, then this is OK. */ if(!has_useful_ta) { verbose(VERB_ALGO, "No usable trust anchors were found -- " "treating as insecure."); return sec_status_insecure; } /* 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"); } return sec_status_bogus; }