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. */ * to this head. For cleaning. */
getdns_rrset rrset; getdns_rrset rrset;
getdns_network_req *netreq; getdns_network_req *netreq;
int signer;
uint8_t name_spc[]; uint8_t name_spc[];
}; };
@ -376,9 +377,11 @@ struct chain_node {
getdns_rrset dnskey; getdns_rrset dnskey;
getdns_network_req *dnskey_req; getdns_network_req *dnskey_req;
int dnskey_signer;
getdns_rrset ds; getdns_rrset ds;
getdns_network_req *ds_req; getdns_network_req *ds_req;
int ds_signer;
getdns_network_req *soa_req; 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)) && priv_getdns_dname_equal(dnskey->name, signer))
return 1; return keytag;
} }
} }
return 0; return 0;
@ -586,7 +589,7 @@ static int dnskey_signed_rrset(
debug_sec_print_rr("key ", &dnskey->rr_i); debug_sec_print_rr("key ", &dnskey->rr_i);
debug_sec_print_rrset("signed ", rrset); debug_sec_print_rrset("signed ", rrset);
return 1; return 0x10000 | keytag; /* in case keytag == 0 */
} }
} }
return 0; return 0;
@ -599,31 +602,32 @@ static int a_key_signed_rrset(getdns_rrset *keyset, getdns_rrset *rrset)
{ {
rrtype_iter dnskey_spc, *dnskey; rrtype_iter dnskey_spc, *dnskey;
uint8_t *nc_name; uint8_t *nc_name;
int keytag;
assert(keyset->rr_type == GETDNS_RRTYPE_DNSKEY); assert(keyset->rr_type == GETDNS_RRTYPE_DNSKEY);
for ( dnskey = rrtype_iter_init(&dnskey_spc, keyset) for ( dnskey = rrtype_iter_init(&dnskey_spc, keyset)
; dnskey ; dnskey = rrtype_iter_next(dnskey) ) { ; dnskey ; dnskey = rrtype_iter_next(dnskey) ) {
if (!dnskey_signed_rrset(dnskey, rrset, &nc_name)) if (!(keytag = dnskey_signed_rrset(dnskey, rrset, &nc_name)))
continue; continue;
if (!nc_name) /* Not a wildcard, then success! */ if (!nc_name) /* Not a wildcard, then success! */
return 1; return keytag;
/* Wildcard RRSIG for a NSEC on the wildcard. /* Wildcard RRSIG for a NSEC on the wildcard.
* There is no more specific! * There is no more specific!
*/ */
if (rrset->rr_type == GETDNS_RRTYPE_NSEC && if (rrset->rr_type == GETDNS_RRTYPE_NSEC &&
rrset->name[0] == 1 && rrset->name[1] == '*') rrset->name[0] == 1 && rrset->name[1] == '*')
return 1; return keytag;
debug_sec_print_rrset("wildcard expanded to: ", rrset); debug_sec_print_rrset("wildcard expanded to: ", rrset);
debug_sec_print_dname("Find NSEC covering the more sepecific: " debug_sec_print_dname("Find NSEC covering the more sepecific: "
, nc_name); , nc_name);
if (find_nsec_covering_name(keyset, rrset, nc_name, NULL)) if (find_nsec_covering_name(keyset, rrset, nc_name, NULL))
return 1; return keytag;
} }
return 0; return 0;
} }
@ -680,7 +684,7 @@ static int ds_authenticates_keys(getdns_rrset *ds_set, getdns_rrset *dnskey_set)
debug_sec_print_rrset( debug_sec_print_rrset(
"keyset authenticated: ", dnskey_set); "keyset authenticated: ", dnskey_set);
return 1; return 0x10000 | keytag; /* In case keytag == 0 */
} }
debug_sec_print_rrset( debug_sec_print_rrset(
"keyset failed authentication: ", dnskey_set); "keyset failed authentication: ", dnskey_set);
@ -962,6 +966,7 @@ static int find_nsec_covering_name(
{ {
rrset_iter i_spc, *i; rrset_iter i_spc, *i;
getdns_rrset *n; getdns_rrset *n;
int keytag;
if (opt_out) if (opt_out)
*opt_out = 0; *opt_out = 0;
@ -971,21 +976,21 @@ static int find_nsec_covering_name(
if ((n = rrset_iter_value(i))->rr_type == GETDNS_RRTYPE_NSEC3 if ((n = rrset_iter_value(i))->rr_type == GETDNS_RRTYPE_NSEC3
&& nsec3_covers_name(n, name, opt_out) && 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_rrset("NSEC3: ", n);
debug_sec_print_dname("covered: ", name); debug_sec_print_dname("covered: ", name);
return 1; return keytag;
} }
if ((n = rrset_iter_value(i))->rr_type == GETDNS_RRTYPE_NSEC if ((n = rrset_iter_value(i))->rr_type == GETDNS_RRTYPE_NSEC
&& nsec_covers_name(n, name, NULL) && 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_rrset("NSEC: ", n);
debug_sec_print_dname("covered: ", name); debug_sec_print_dname("covered: ", name);
return 1; return keytag;
} }
} }
return 0; return 0;
@ -995,9 +1000,9 @@ static int nsec3_find_next_closer(
getdns_rrset *dnskey, getdns_rrset *rrset, uint8_t *nc_name) getdns_rrset *dnskey, getdns_rrset *rrset, uint8_t *nc_name)
{ {
uint8_t wc_name[256] = { 1, (uint8_t)'*' }; 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; return 0;
/* Wild card not needed on a "covering" NODATA response, /* Wild card not needed on a "covering" NODATA response,
@ -1009,7 +1014,7 @@ static int nsec3_find_next_closer(
* rcode is always NOERROR. * rcode is always NOERROR.
*/ */
if (opt_out) if (opt_out)
return 1; return keytag;
nc_name += *nc_name + 1; nc_name += *nc_name + 1;
(void) memcpy(wc_name + 2, nc_name, _dname_len(nc_name)); (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; rrset_iter i_spc, *i;
uint8_t *ce_name, *nc_name; uint8_t *ce_name, *nc_name;
uint8_t wc_name[256] = { 1, (uint8_t)'*' }; uint8_t wc_name[256] = { 1, (uint8_t)'*' };
int keytag;
assert(dnskey->rr_type == GETDNS_RRTYPE_DNSKEY); 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 = *rrset;
nsec_rrset.rr_type = GETDNS_RRTYPE_NSEC; nsec_rrset.rr_type = GETDNS_RRTYPE_NSEC;
if (nsec_bitmap_excludes_rrtype(&nsec_rrset, rrset->rr_type) && if (nsec_bitmap_excludes_rrtype(&nsec_rrset, rrset->rr_type)
a_key_signed_rrset(dnskey, &nsec_rrset)) { && (keytag = a_key_signed_rrset(dnskey, &nsec_rrset))) {
debug_sec_print_rrset("NSEC NODATA proof for: ", rrset); debug_sec_print_rrset("NSEC NODATA proof for: ", rrset);
return 1; return keytag;
} }
/* The NSEC Name error case /* 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, rrset->rr_type)
&& nsec_bitmap_excludes_rrtype(ce, GETDNS_RRTYPE_CNAME) && nsec_bitmap_excludes_rrtype(ce, GETDNS_RRTYPE_CNAME)
&& nsec3_matches_name(ce, rrset->name) && 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); debug_sec_print_rrset("NSEC3 No Data for: ", rrset);
return 1; return keytag;
} }
} }
/* The NSEC3 Name error case /* 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("Closest Encloser: ", ce_name);
debug_sec_print_dname(" Next closer: ", nc_name); debug_sec_print_dname(" Next closer: ", nc_name);
if (nsec3_find_next_closer(dnskey, rrset, nc_name)) if ((keytag = nsec3_find_next_closer(dnskey, rrset, nc_name)))
return 1; return keytag;
} }
} }
return 0; return 0;
@ -1107,7 +1113,7 @@ static int key_proves_nonexistance(getdns_rrset *dnskey, getdns_rrset *rrset)
static int chain_node_get_trusted_keys( static int chain_node_get_trusted_keys(
chain_node *node, getdns_rrset *ta, getdns_rrset **keys) chain_node *node, getdns_rrset *ta, getdns_rrset **keys)
{ {
int s; int s, keytag;
/* Descend down to the root */ /* Descend down to the root */
if (! node) if (! node)
@ -1115,25 +1121,31 @@ static int chain_node_get_trusted_keys(
else if (ta->rr_type == GETDNS_RRTYPE_DS) { 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; *keys = &node->dnskey;
node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE; return GETDNS_DNSSEC_SECURE;
} }
} else if (ta->rr_type == GETDNS_RRTYPE_DNSKEY) { } else if (ta->rr_type == GETDNS_RRTYPE_DNSKEY) {
/* ta is KSK */ /* ta is KSK */
if (a_key_signed_rrset(ta, &node->dnskey)) { if ((keytag = a_key_signed_rrset(ta, &node->dnskey))) {
*keys = &node->dnskey; *keys = &node->dnskey;
node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE; return GETDNS_DNSSEC_SECURE;
} }
/* ta is ZSK */ /* 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; return GETDNS_DNSSEC_INSECURE;
}
if (a_key_signed_rrset(ta, &node->ds)) { if ((keytag = a_key_signed_rrset(ta, &node->ds))) {
if (ds_authenticates_keys(&node->ds, &node->dnskey)) { node->ds_signer = keytag;
if ((keytag = ds_authenticates_keys(&node->ds, &node->dnskey))) {
*keys = &node->dnskey; *keys = &node->dnskey;
node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE; return GETDNS_DNSSEC_SECURE;
} }
return GETDNS_DNSSEC_BOGUS; 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) */ /* keys is an authenticated dnskey rrset always now (i.e. ZSK) */
ta = *keys; ta = *keys;
/* Back up to the head */ /* 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; 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) && 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; *keys = &node->dnskey;
node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE; return GETDNS_DNSSEC_SECURE;
} }
return GETDNS_DNSSEC_BOGUS; 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) static int chain_head_validate_with_ta(chain_head *head, getdns_rrset *ta)
{ {
getdns_rrset *keys; getdns_rrset *keys;
int s; int s, keytag;
if ((s = chain_node_get_trusted_keys(head->parent, ta, &keys)) if ((s = chain_node_get_trusted_keys(head->parent, ta, &keys))
!= GETDNS_DNSSEC_SECURE) != GETDNS_DNSSEC_SECURE)
return s; 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 (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; 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_SECURE;
}
return GETDNS_DNSSEC_BOGUS; 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, 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; rrset_iter *i, i_spc;
getdns_rrset *rrset; getdns_rrset *rrset;
@ -1347,8 +1360,17 @@ static void append_rrs2val_chain_list(getdns_context *ctxt,
for ( rrsig = rrsig_iter_init(&rrsig_spc, rrset) for ( rrsig = rrsig_iter_init(&rrsig_spc, rrset)
; rrsig; rrsig = rrsig_iter_next(rrsig)) { ; rrsig; rrsig = rrsig_iter_next(rrsig)) {
if (!(rr_dict = priv_getdns_rr_iter2rr_dict( if (/* No space for keytag & signer in rrsig rdata? */
&ctxt->mf, &rrsig->rr_i))) 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; continue;
(void)getdns_list_append_dict(val_chain_list, rr_dict); (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 ) { ; node_count--, node = node->parent ) {
if (node->dnskey_req) { if (node->dnskey_req) {
append_rrs2val_chain_list(context, append_rrs2val_chain_list(
val_chain_list, node->dnskey_req); context, val_chain_list,
node->dnskey_req, node->dnskey_signer);
dns_req_free(node->dnskey_req->owner); dns_req_free(node->dnskey_req->owner);
} }
if (node->ds_req) { if (node->ds_req) {
append_rrs2val_chain_list(context, append_rrs2val_chain_list(
val_chain_list, node->ds_req); context, val_chain_list,
node->ds_req, node->ds_signer);
dns_req_free(node->ds_req->owner); 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 = rrset->pkt;
head->rrset.pkt_len = rrset->pkt_len; head->rrset.pkt_len = rrset->pkt_len;
head->netreq = netreq; head->netreq = netreq;
head->signer = 0;
head->node_count = node_count; head->node_count = node_count;
if (!node_count) { if (!node_count) {
@ -1727,6 +1753,8 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
node->ds_req = NULL; node->ds_req = NULL;
node->dnskey_req = NULL; node->dnskey_req = NULL;
node->soa_req = NULL; node->soa_req = NULL;
node->ds_signer = 0;
node->dnskey_signer = 0;
node->chains = *chain_p; node->chains = *chain_p;
} }