A single RRSIG per RRSET in validation_chain

This commit is contained in:
Willem Toorop 2015-07-02 17:30:37 +02:00
parent d47c533b64
commit af49184fd5
1 changed files with 75 additions and 47 deletions

View File

@ -367,6 +367,7 @@ struct chain_head {
* to this head. For cleaning. */
getdns_rrset rrset;
getdns_network_req *netreq;
int signer;
uint8_t name_spc[];
};
@ -376,9 +377,11 @@ struct chain_node {
getdns_rrset dnskey;
getdns_network_req *dnskey_req;
int dnskey_signer;
getdns_rrset ds;
getdns_network_req *ds_req;
int ds_signer;
getdns_network_req *soa_req;
@ -436,7 +439,7 @@ static int key_matches_signer(getdns_rrset *dnskey, getdns_rrset *rrset)
&& priv_getdns_dname_equal(dnskey->name, signer))
return 1;
return keytag;
}
}
return 0;
@ -586,7 +589,7 @@ static int dnskey_signed_rrset(
debug_sec_print_rr("key ", &dnskey->rr_i);
debug_sec_print_rrset("signed ", rrset);
return 1;
return 0x10000 | keytag; /* in case keytag == 0 */
}
}
return 0;
@ -599,31 +602,32 @@ static int a_key_signed_rrset(getdns_rrset *keyset, getdns_rrset *rrset)
{
rrtype_iter dnskey_spc, *dnskey;
uint8_t *nc_name;
int keytag;
assert(keyset->rr_type == GETDNS_RRTYPE_DNSKEY);
for ( dnskey = rrtype_iter_init(&dnskey_spc, keyset)
; dnskey ; dnskey = rrtype_iter_next(dnskey) ) {
if (!dnskey_signed_rrset(dnskey, rrset, &nc_name))
if (!(keytag = dnskey_signed_rrset(dnskey, rrset, &nc_name)))
continue;
if (!nc_name) /* Not a wildcard, then success! */
return 1;
return keytag;
/* Wildcard RRSIG for a NSEC on the wildcard.
* There is no more specific!
*/
if (rrset->rr_type == GETDNS_RRTYPE_NSEC &&
rrset->name[0] == 1 && rrset->name[1] == '*')
return 1;
return keytag;
debug_sec_print_rrset("wildcard expanded to: ", rrset);
debug_sec_print_dname("Find NSEC covering the more sepecific: "
, nc_name);
if (find_nsec_covering_name(keyset, rrset, nc_name, NULL))
return 1;
return keytag;
}
return 0;
}
@ -680,7 +684,7 @@ static int ds_authenticates_keys(getdns_rrset *ds_set, getdns_rrset *dnskey_set)
debug_sec_print_rrset(
"keyset authenticated: ", dnskey_set);
return 1;
return 0x10000 | keytag; /* In case keytag == 0 */
}
debug_sec_print_rrset(
"keyset failed authentication: ", dnskey_set);
@ -962,6 +966,7 @@ static int find_nsec_covering_name(
{
rrset_iter i_spc, *i;
getdns_rrset *n;
int keytag;
if (opt_out)
*opt_out = 0;
@ -971,21 +976,21 @@ static int find_nsec_covering_name(
if ((n = rrset_iter_value(i))->rr_type == GETDNS_RRTYPE_NSEC3
&& nsec3_covers_name(n, name, opt_out)
&& a_key_signed_rrset(dnskey, n)) {
&& (keytag = a_key_signed_rrset(dnskey, n))) {
debug_sec_print_rrset("NSEC3: ", n);
debug_sec_print_dname("covered: ", name);
return 1;
return keytag;
}
if ((n = rrset_iter_value(i))->rr_type == GETDNS_RRTYPE_NSEC
&& nsec_covers_name(n, name, NULL)
&& a_key_signed_rrset(dnskey, n)) {
&& (keytag = a_key_signed_rrset(dnskey, n))) {
debug_sec_print_rrset("NSEC: ", n);
debug_sec_print_dname("covered: ", name);
return 1;
return keytag;
}
}
return 0;
@ -995,9 +1000,9 @@ static int nsec3_find_next_closer(
getdns_rrset *dnskey, getdns_rrset *rrset, uint8_t *nc_name)
{
uint8_t wc_name[256] = { 1, (uint8_t)'*' };
int opt_out;
int opt_out, keytag;
if (!find_nsec_covering_name(dnskey, rrset, nc_name, &opt_out))
if (!(keytag = find_nsec_covering_name(dnskey, rrset, nc_name, &opt_out)))
return 0;
/* Wild card not needed on a "covering" NODATA response,
@ -1009,7 +1014,7 @@ static int nsec3_find_next_closer(
* rcode is always NOERROR.
*/
if (opt_out)
return 1;
return keytag;
nc_name += *nc_name + 1;
(void) memcpy(wc_name + 2, nc_name, _dname_len(nc_name));
@ -1023,6 +1028,7 @@ static int key_proves_nonexistance(getdns_rrset *dnskey, getdns_rrset *rrset)
rrset_iter i_spc, *i;
uint8_t *ce_name, *nc_name;
uint8_t wc_name[256] = { 1, (uint8_t)'*' };
int keytag;
assert(dnskey->rr_type == GETDNS_RRTYPE_DNSKEY);
@ -1033,11 +1039,11 @@ static int key_proves_nonexistance(getdns_rrset *dnskey, getdns_rrset *rrset)
*/
nsec_rrset = *rrset;
nsec_rrset.rr_type = GETDNS_RRTYPE_NSEC;
if (nsec_bitmap_excludes_rrtype(&nsec_rrset, rrset->rr_type) &&
a_key_signed_rrset(dnskey, &nsec_rrset)) {
if (nsec_bitmap_excludes_rrtype(&nsec_rrset, rrset->rr_type)
&& (keytag = a_key_signed_rrset(dnskey, &nsec_rrset))) {
debug_sec_print_rrset("NSEC NODATA proof for: ", rrset);
return 1;
return keytag;
}
/* The NSEC Name error case
@ -1071,10 +1077,10 @@ static int key_proves_nonexistance(getdns_rrset *dnskey, getdns_rrset *rrset)
&& nsec_bitmap_excludes_rrtype(ce, rrset->rr_type)
&& nsec_bitmap_excludes_rrtype(ce, GETDNS_RRTYPE_CNAME)
&& nsec3_matches_name(ce, rrset->name)
&& a_key_signed_rrset(dnskey, ce)) {
&& (keytag = a_key_signed_rrset(dnskey, ce))) {
debug_sec_print_rrset("NSEC3 No Data for: ", rrset);
return 1;
return keytag;
}
}
/* The NSEC3 Name error case
@ -1097,8 +1103,8 @@ static int key_proves_nonexistance(getdns_rrset *dnskey, getdns_rrset *rrset)
debug_sec_print_dname("Closest Encloser: ", ce_name);
debug_sec_print_dname(" Next closer: ", nc_name);
if (nsec3_find_next_closer(dnskey, rrset, nc_name))
return 1;
if ((keytag = nsec3_find_next_closer(dnskey, rrset, nc_name)))
return keytag;
}
}
return 0;
@ -1107,7 +1113,7 @@ static int key_proves_nonexistance(getdns_rrset *dnskey, getdns_rrset *rrset)
static int chain_node_get_trusted_keys(
chain_node *node, getdns_rrset *ta, getdns_rrset **keys)
{
int s;
int s, keytag;
/* Descend down to the root */
if (! node)
@ -1115,25 +1121,31 @@ static int chain_node_get_trusted_keys(
else if (ta->rr_type == GETDNS_RRTYPE_DS) {
if (ds_authenticates_keys(&node->ds, &node->dnskey)) {
if ((keytag = ds_authenticates_keys(&node->ds, &node->dnskey))) {
*keys = &node->dnskey;
node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE;
}
} else if (ta->rr_type == GETDNS_RRTYPE_DNSKEY) {
/* ta is KSK */
if (a_key_signed_rrset(ta, &node->dnskey)) {
if ((keytag = a_key_signed_rrset(ta, &node->dnskey))) {
*keys = &node->dnskey;
node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE;
}
/* ta is ZSK */
if (key_proves_nonexistance(ta, &node->ds))
if ((keytag = key_proves_nonexistance(ta, &node->ds))) {
node->ds_signer = keytag;
return GETDNS_DNSSEC_INSECURE;
}
if (a_key_signed_rrset(ta, &node->ds)) {
if (ds_authenticates_keys(&node->ds, &node->dnskey)) {
if ((keytag = a_key_signed_rrset(ta, &node->ds))) {
node->ds_signer = keytag;
if ((keytag = ds_authenticates_keys(&node->ds, &node->dnskey))) {
*keys = &node->dnskey;
node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE;
}
return GETDNS_DNSSEC_BOGUS;
@ -1148,14 +1160,17 @@ static int chain_node_get_trusted_keys(
/* keys is an authenticated dnskey rrset always now (i.e. ZSK) */
ta = *keys;
/* Back up to the head */
if (key_proves_nonexistance(ta, &node->ds))
if ((keytag = key_proves_nonexistance(ta, &node->ds))) {
node->ds_signer = keytag;
return GETDNS_DNSSEC_INSECURE;
if (key_matches_signer(ta, &node->ds)) {
}
if ((keytag = key_matches_signer(ta, &node->ds))) {
node->ds_signer = keytag;
if (a_key_signed_rrset(ta, &node->ds) &&
ds_authenticates_keys(&node->ds, &node->dnskey)) {
(keytag = ds_authenticates_keys(&node->ds, &node->dnskey))) {
*keys = &node->dnskey;
node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE;
}
return GETDNS_DNSSEC_BOGUS;
@ -1166,23 +1181,21 @@ static int chain_node_get_trusted_keys(
static int chain_head_validate_with_ta(chain_head *head, getdns_rrset *ta)
{
getdns_rrset *keys;
int s;
int s, keytag;
if ((s = chain_node_get_trusted_keys(head->parent, ta, &keys))
!= GETDNS_DNSSEC_SECURE)
return s;
debug_sec_print_rrset("Trusted keys to evaluate head: ", &head->rrset);
DEBUG_SEC("rrset_has_rrs(&head->rrset) -> %d\n", rrset_has_rrs(&head->rrset));
DEBUG_SEC("a_key_signed_rrset(keys, &head->rrset) -> %d\n", a_key_signed_rrset(keys, &head->rrset));
DEBUG_SEC("(key_proves_nonexistance(keys, &head->rrset) -> %d\n", key_proves_nonexistance(keys, &head->rrset));
if (rrset_has_rrs(&head->rrset)) {
if (a_key_signed_rrset(keys, &head->rrset))
if ((keytag = a_key_signed_rrset(keys, &head->rrset))) {
head->signer = keytag;
return GETDNS_DNSSEC_SECURE;
} else if (key_proves_nonexistance(keys, &head->rrset))
}
} else if ((keytag = key_proves_nonexistance(keys, &head->rrset))) {
head->signer = keytag;
return GETDNS_DNSSEC_SECURE;
}
return GETDNS_DNSSEC_BOGUS;
}
@ -1314,7 +1327,7 @@ static size_t count_outstanding_requests(chain_head *head)
}
static void append_rrs2val_chain_list(getdns_context *ctxt,
getdns_list *val_chain_list, getdns_network_req *netreq)
getdns_list *val_chain_list, getdns_network_req *netreq, int signer)
{
rrset_iter *i, i_spc;
getdns_rrset *rrset;
@ -1347,8 +1360,17 @@ static void append_rrs2val_chain_list(getdns_context *ctxt,
for ( rrsig = rrsig_iter_init(&rrsig_spc, rrset)
; rrsig; rrsig = rrsig_iter_next(rrsig)) {
if (!(rr_dict = priv_getdns_rr_iter2rr_dict(
&ctxt->mf, &rrsig->rr_i)))
if (/* No space for keytag & signer in rrsig rdata? */
rrsig->rr_i.nxt < rrsig->rr_i.rr_type + 28
/* We have a signer and it doesn't match? */
|| (signer &&
gldns_read_uint16(rrsig->rr_i.rr_type + 26)
!= (signer & 0xFFFF))
/* Could not convert to rr_dict */
|| !(rr_dict = priv_getdns_rr_iter2rr_dict(
&ctxt->mf, &rrsig->rr_i)))
continue;
(void)getdns_list_append_dict(val_chain_list, rr_dict);
@ -1400,13 +1422,16 @@ static void check_chain_complete(chain_head *chain)
; node_count--, node = node->parent ) {
if (node->dnskey_req) {
append_rrs2val_chain_list(context,
val_chain_list, node->dnskey_req);
append_rrs2val_chain_list(
context, val_chain_list,
node->dnskey_req, node->dnskey_signer);
dns_req_free(node->dnskey_req->owner);
}
if (node->ds_req) {
append_rrs2val_chain_list(context,
val_chain_list, node->ds_req);
append_rrs2val_chain_list(
context, val_chain_list,
node->ds_req, node->ds_signer);
dns_req_free(node->ds_req->owner);
}
}
@ -1698,6 +1723,7 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
head->rrset.pkt = rrset->pkt;
head->rrset.pkt_len = rrset->pkt_len;
head->netreq = netreq;
head->signer = 0;
head->node_count = node_count;
if (!node_count) {
@ -1727,6 +1753,8 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
node->ds_req = NULL;
node->dnskey_req = NULL;
node->soa_req = NULL;
node->ds_signer = 0;
node->dnskey_signer = 0;
node->chains = *chain_p;
}