/** verify that a DS RR hashes to a key and that key signs the set */ static enum sec_status 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) { enum sec_status sec = sec_status_bogus; size_t i, num, numchecked = 0, numhashok = 0; num = rrset_get_count(dnskey_rrset); for(i=0; i<num; i++) { /* Skip DNSKEYs that don't match the basic criteria. */ if(ds_get_key_algo(ds_rrset, ds_idx) != dnskey_get_algo(dnskey_rrset, i) || dnskey_calc_keytag(dnskey_rrset, i) != ds_get_keytag(ds_rrset, ds_idx)) { continue; } numchecked++; verbose(VERB_ALGO, "attempt DS match algo %d keytag %d", ds_get_key_algo(ds_rrset, ds_idx), ds_get_keytag(ds_rrset, ds_idx)); /* Convert the candidate DNSKEY into a hash using the * same DS hash algorithm. */ if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset, ds_idx)) { verbose(VERB_ALGO, "DS match attempt failed"); continue; } numhashok++; verbose(VERB_ALGO, "DS match digest ok, trying signature"); /* Otherwise, we have a match! Make sure that the DNSKEY * verifies *with this key* */ sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i, reason); if(sec == sec_status_secure) { return sec; } /* If it didn't validate with the DNSKEY, try the next one! */ } if(numchecked == 0) 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) *reason = "keyset not secured by DNSKEY that matches DS"; return sec_status_bogus; }
/** DS sig test an entry - get DNSKEY and DS in entry and verify */ static void dstest_entry(struct entry* e, struct alloc_cache* alloc, struct regional* region, sldns_buffer* pkt, struct module_env* env) { struct query_info qinfo; struct reply_info* rep = NULL; struct ub_packed_rrset_key* ds, *dnskey; int ret; regional_free_all(region); if(vsig) { char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt, e->reply_list->reply_len); printf("verifying DS-DNSKEY match:\n%s\n", s?s:"outofmemory"); free(s); } entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep); ds = find_rrset_type(rep, LDNS_RR_TYPE_DS); dnskey = find_rrset_type(rep, LDNS_RR_TYPE_DNSKEY); /* check test is OK */ unit_assert(ds && dnskey); ret = ds_digest_match_dnskey(env, dnskey, 0, ds, 0); if(strncmp((char*)qinfo.qname, "\003yes", 4) == 0) { if(vsig) { printf("result(yes)= %s\n", ret?"yes":"no"); } unit_assert(ret); } else if (strncmp((char*)qinfo.qname, "\002no", 3) == 0) { if(vsig) { printf("result(no)= %s\n", ret?"yes":"no"); } unit_assert(!ret); verbose(VERB_QUERY, "DS fail: OK; matched unit test"); } else { fatal_exit("Bad qname in DS unit test, yes or no"); } reply_info_parsedelete(rep, alloc); query_info_clear(&qinfo); }