From 649814f0e37a5bbc4f30f80e636fa38762dfa8df Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 7 Feb 2014 15:00:59 +0100 Subject: [PATCH] validate_dnssec does some chasing But not completely ... --- src/getdns/getdns.h | 6 +- src/test/tests_dnssec.c | 43 +++++++- src/validate_dnssec.c | 225 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 256 insertions(+), 18 deletions(-) diff --git a/src/getdns/getdns.h b/src/getdns/getdns.h index 3cdc1bec..68cc0695 100644 --- a/src/getdns/getdns.h +++ b/src/getdns/getdns.h @@ -779,9 +779,9 @@ char *getdns_convert_ulabel_to_alabel(const char *ulabel); char *getdns_convert_alabel_to_ulabel(const char *alabel); getdns_return_t -getdns_validate_dnssec(struct getdns_bindata *record_to_validate, - struct getdns_list *bundle_of_support_records, - struct getdns_list *trust_anchor_rdatas); +getdns_validate_dnssec(struct getdns_list *to_validate, + struct getdns_list *support_records, + struct getdns_list *trust_anchors); /** * creates a string that describes the dictionary in a human readable form diff --git a/src/test/tests_dnssec.c b/src/test/tests_dnssec.c index 38edf3c2..a58962aa 100644 --- a/src/test/tests_dnssec.c +++ b/src/test/tests_dnssec.c @@ -133,6 +133,10 @@ this_callbackfn(struct getdns_context *context, uint16_t callback_type, { struct getdns_list *validation_chain; struct getdns_list *trust_anchors; + struct getdns_list *replies_tree; + size_t replies_tree_length, i; + struct getdns_dict *reply; + struct getdns_list *answer; getdns_return_t r; do { @@ -155,6 +159,20 @@ this_callbackfn(struct getdns_context *context, uint16_t callback_type, " %d\n", r); break; } + r = getdns_dict_get_list(response, "replies_tree", &replies_tree); + if (r != GETDNS_RETURN_GOOD) { + fprintf(stderr, + "Could not get \"replies_tree\" from response:" + " %d\n", r); + break; + } + r = getdns_list_get_length(replies_tree, &replies_tree_length); + if (r != GETDNS_RETURN_GOOD) { + fprintf(stderr, + "Could not get length of the replies_tree:" + " %d\n", r); + break; + } r = create_root_trustanchor_list(&trust_anchors); if (r != GETDNS_RETURN_GOOD) { fprintf(stderr, @@ -162,11 +180,26 @@ this_callbackfn(struct getdns_context *context, uint16_t callback_type, " %d\n", r); break; } - r = getdns_validate_dnssec(NULL, - validation_chain, trust_anchors); - - printf("getdns_validate_dnssec returned: %d\n", r); - + for (i = 0; i < replies_tree_length; i++) { + r = getdns_list_get_dict(replies_tree, i, &reply); + if (r != GETDNS_RETURN_GOOD) { + fprintf(stderr, + "Could not get \"reply\" from replies_tree:" + " %d\n", r); + break; + } + r = getdns_dict_get_list(reply, "answer", &answer); + if (r != GETDNS_RETURN_GOOD) { + fprintf(stderr, + "Could not get \"answer\" from reply:" + " %d\n", r); + break; + } + r = getdns_validate_dnssec(answer, + validation_chain, trust_anchors); + printf("getdns_validate_dnssec returned: %d\n", r); + } + //printf("%s\n", getdns_pretty_print_dict(response)); getdns_list_destroy(trust_anchors); } while (0); getdns_dict_destroy(response); diff --git a/src/validate_dnssec.c b/src/validate_dnssec.c index 5358c506..b5dfb604 100644 --- a/src/validate_dnssec.c +++ b/src/validate_dnssec.c @@ -73,32 +73,237 @@ priv_getdns_rr_list_from_list(struct getdns_list *list, ldns_rr_list **rr_list) return r; } +static getdns_return_t +priv_getdns_dnssec_zone_from_list(struct getdns_list *list, + ldns_dnssec_zone **zone) +{ + getdns_return_t r; + size_t i, l; + struct getdns_dict *rr_dict; + ldns_rr *rr; + ldns_status s; + + if ((r = getdns_list_get_length(list, &l))) + return r; + + if (! (*zone = ldns_dnssec_zone_new())) + return GETDNS_RETURN_MEMORY_ERROR; + + for (i = 0; i < l; i++) { + if ((r = getdns_list_get_dict(list, i, &rr_dict))) + break; + + if ((r = priv_getdns_create_rr_from_dict(rr_dict, &rr))) + break; + + if ((s = ldns_dnssec_zone_add_rr(*zone, rr))) { + ldns_rr_free(rr); + r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + } + if (r) + ldns_dnssec_zone_free(*zone); + return r; +} + +typedef struct zone_iter { + ldns_dnssec_zone *zone; + ldns_rbnode_t *cur_node; + ldns_dnssec_rrsets *cur_rrset; +} zone_iter; + +static void +rrset_iter_init_zone(zone_iter *i, ldns_dnssec_zone *zone) +{ + assert(i); + + i->zone = zone; + i->cur_node = ldns_rbtree_first(zone->names); + i->cur_rrset = i->cur_node != LDNS_RBTREE_NULL + ? ((ldns_dnssec_name *)i->cur_node->data)->rrsets + : NULL; +} + +static ldns_dnssec_rrsets * +rrset_iter_value(zone_iter *i) +{ + assert(i); + + return i->cur_rrset; +} + +static void +rrset_iter_next(zone_iter *i) +{ + assert(i); + + if (! i->cur_rrset) + return; + + if (! (i->cur_rrset = i->cur_rrset->next)) { + i->cur_node = ldns_rbtree_next(i->cur_node); + i->cur_rrset = i->cur_node != LDNS_RBTREE_NULL + ? ((ldns_dnssec_name *)i->cur_node->data)->rrsets + : NULL; + } +} + +static ldns_rr_list * +rrs2rr_list(ldns_dnssec_rrs *rrs) +{ + ldns_rr_list *r = ldns_rr_list_new(); + if (r) + while (rrs) { + (void) ldns_rr_list_push_rr(r, rrs->rr); + rrs = rrs->next; + } + return r; +} + +static ldns_status +verify_rrset(ldns_dnssec_rrsets *rrset_and_sigs, + const ldns_rr_list *keys, ldns_rr_list *good_keys) +{ + ldns_status s; + ldns_rr_list *rrset = rrs2rr_list(rrset_and_sigs->rrs); + ldns_rr_list *sigs = rrs2rr_list(rrset_and_sigs->signatures); + s = ldns_verify(rrset, sigs, keys, good_keys); + ldns_rr_list_free(sigs); + ldns_rr_list_free(rrset); + return s; +} + +static ldns_status +chase(ldns_dnssec_rrsets *rrset, ldns_dnssec_zone *support, + ldns_rr_list *support_keys, ldns_rr_list *trusted) +{ + ldns_status s; + ldns_rr_list *verifying_keys; + size_t i; + ldns_rr *rr; + ldns_dnssec_rrsets *key_rrset; + + printf(";; RRSET to validate:\n"); + ldns_dnssec_rrsets_print(stdout, rrset, 0); + + printf(";;\n;; Validating with trust anchors:\n"); + verifying_keys = ldns_rr_list_new(); + s = verify_rrset(rrset, trusted, verifying_keys); + printf(";; status: %s\n", ldns_get_errorstr_by_id(s)); + if (ldns_rr_list_rr_count(verifying_keys)) { ldns_rr_list_print(stdout, verifying_keys); printf(";;\n"); } + ldns_rr_list_free(verifying_keys); + if (s == 0) + return s; + + printf(";; Validating with support keys:\n"); + verifying_keys = ldns_rr_list_new(); + s = verify_rrset(rrset, support_keys, verifying_keys); + printf(";; status: %s\n", ldns_get_errorstr_by_id(s)); + if (ldns_rr_list_rr_count(verifying_keys)) { ldns_rr_list_print(stdout, verifying_keys); printf(";;\n"); } + if (s != 0) + goto done_free_verifying_keys; + + printf(";; Looking up the verifying keys:\n"); + for (i = 0; i < ldns_rr_list_rr_count(verifying_keys); i++) { + rr = ldns_rr_list_rr(verifying_keys, i); + key_rrset = ldns_dnssec_zone_find_rrset( + support, ldns_rr_owner(rr), ldns_rr_get_type(rr)); + if (! key_rrset) { + printf(";; Key not found:\n;;\n"); + s = LDNS_STATUS_CRYPTO_NO_DNSKEY; + break; + } + if (rrset == key_rrset) { + printf(";; Key verifies itself, lookup DS:\n"); + key_rrset = ldns_dnssec_zone_find_rrset( + support, ldns_rr_owner(rr), LDNS_RR_TYPE_DS); + if (! key_rrset) { + printf(";; DS not found:\n;;\n"); + s = LDNS_STATUS_CRYPTO_NO_DNSKEY; + break; + } + /* Now check if DS matches the DNSKEY! */ + } + s = chase(key_rrset, support, support_keys, trusted); + if (s != 0) + break; + } + +done_free_verifying_keys: + ldns_rr_list_free(verifying_keys); + return s; +} + /* * getdns_validate_dnssec * */ getdns_return_t -getdns_validate_dnssec(struct getdns_bindata *to_validate, +getdns_validate_dnssec(struct getdns_list *records_to_validate, struct getdns_list *support_records, struct getdns_list *trust_anchors) { getdns_return_t r; - ldns_rr_list *tas; - ldns_rr_list *chain; + ldns_rr_list *trusted; + ldns_dnssec_zone *support; + ldns_rr_list *support_keys; + ldns_dnssec_zone *to_validate; + zone_iter i; + ldns_dnssec_rrsets *rrset; + ldns_dnssec_rrs *rrs; + ldns_status s; - if ((r = priv_getdns_rr_list_from_list(trust_anchors, &tas))) + if ((r = priv_getdns_rr_list_from_list(trust_anchors, &trusted))) return r; - printf(";; trust anchors:\n"); - ldns_rr_list_print(stdout, tas); + if ((r = priv_getdns_dnssec_zone_from_list( + support_records, &support))) + goto done_free_trusted; - if ((r = priv_getdns_rr_list_from_list(support_records, &chain))) - return r; + if ((r = priv_getdns_dnssec_zone_from_list( + records_to_validate, &to_validate))) + goto done_free_support; - printf(";; support records:\n"); - ldns_rr_list_print(stdout, chain); + if (! (support_keys = ldns_rr_list_new())) { + r = GETDNS_RETURN_MEMORY_ERROR; + goto done_free_to_validate; + } + /* Create a rr_list of all the keys in the support records */ + for (rrset_iter_init_zone(&i, support); + (rrset = rrset_iter_value(&i)); rrset_iter_next(&i)) + if (ldns_dnssec_rrsets_type(rrset) == LDNS_RR_TYPE_DS || + ldns_dnssec_rrsets_type(rrset) == LDNS_RR_TYPE_DNSKEY) + for (rrs = rrset->rrs; rrs; rrs = rrs->next) + (void) ldns_rr_list_push_rr( + support_keys, rrs->rr); + + /* Now walk through the rrsets to validate */ + for (rrset_iter_init_zone(&i, to_validate); + (rrset = rrset_iter_value(&i)); rrset_iter_next(&i)) { + + s |= chase(rrset, support, support_keys, trusted); + if (s != 0) + break; + } + + /* + for(zone_iter_init(&i, to_validate); + (rrset = zone_iter_rrset(&i)); zone_iter_next(&i)) { + + ldns_dnssec_rrsets_print(stdout, rrset, 0); + } + */ + + ldns_rr_list_free(support_keys); +done_free_to_validate: + ldns_dnssec_zone_free(to_validate); +done_free_support: + ldns_dnssec_zone_free(support); +done_free_trusted: + ldns_rr_list_deep_free(trusted); return r; } /* getdns_validate_dnssec */