From 41e589b08b9a3c16ff12e9aa3a2756c64a0aabe3 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Wed, 18 Mar 2009 13:07:48 +0000 Subject: [PATCH] Fixup trust anchor algorithm check. git-svn-id: file:///svn/unbound/trunk@1532 be551aaa-1e26-0410-a405-d3ace91eadb9 --- doc/Changelog | 4 + testdata/val_unalgo_anchor.rpl | 150 +++++++++++++++++++++++++++++++++ validator/val_anchor.c | 52 +++++++----- validator/val_utils.c | 5 +- validator/val_utils.h | 5 +- validator/validator.c | 15 +++- 6 files changed, 204 insertions(+), 27 deletions(-) create mode 100644 testdata/val_unalgo_anchor.rpl diff --git a/doc/Changelog b/doc/Changelog index 16a41cc53..c06ffe06b 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,5 +1,9 @@ 18 March 2009: Wouter - Added tests, unknown algorithms become insecure. fallback works. + - Fix for and test for unknown algorithms in a trust anchor + definition. Trust anchors with no supported algos are ignored. + This means a (higher)DS or DLV entry for them could succeed, and + otherwise they are treated as insecure. 17 March 2009: Wouter - unit test for unsupported algorithm in anchor warning. diff --git a/testdata/val_unalgo_anchor.rpl b/testdata/val_unalgo_anchor.rpl new file mode 100644 index 000000000..e588b8a54 --- /dev/null +++ b/testdata/val_unalgo_anchor.rpl @@ -0,0 +1,150 @@ +; config options +; The island of trust is at example.com +server: + trust-anchor: "example.com. 3600 IN DS 2854 208 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b" + val-override-date: "20070916134226" + target-fetch-policy: "0 0 0 0 0" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test validator with unsupported algorithm trust anchor + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 100 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END +RANGE_END + +; a.gtld-servers.net. +RANGE_BEGIN 0 100 + ADDRESS 192.5.6.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION ANSWER +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION AUTHORITY +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.com. +RANGE_BEGIN 0 100 + ADDRESS 1.2.3.4 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION ANSWER +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} +ENTRY_END + +; response to DNSKEY priming query +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +example.com. IN DNSKEY +SECTION ANSWER +example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b} +example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854} +SECTION AUTHORITY +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} +ENTRY_END + +; response to query of interest +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854} +SECTION AUTHORITY +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} +SECTION AUTHORITY +example.com. IN NS ns.example.com. +example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854} +ENTRY_END + +SCENARIO_END diff --git a/validator/val_anchor.c b/validator/val_anchor.c index 1f4b68d38..9066078c5 100644 --- a/validator/val_anchor.c +++ b/validator/val_anchor.c @@ -823,35 +823,34 @@ anchors_assemble(struct val_anchors* anchors, struct trust_anchor* ta) /** * Check DS algos for support, warn if not. * @param ta: trust anchor - * @return true if all anchors are supported. + * @return number of DS anchors with unsupported algorithms. */ -static int -anchors_ds_is_supported(struct trust_anchor* ta) +static size_t +anchors_ds_unsupported(struct trust_anchor* ta) { - size_t i; + size_t i, num = 0; for(i=0; inumDS; i++) { - if(!ds_digest_algo_is_supported(ta->ds_rrset, i)) - return 0; - if(!ds_key_algo_is_supported(ta->ds_rrset, i)) - return 0; + if(!ds_digest_algo_is_supported(ta->ds_rrset, i) || + !ds_key_algo_is_supported(ta->ds_rrset, i)) + num++; } - return 1; + return num; } /** * Check DNSKEY algos for support, warn if not. * @param ta: trust anchor - * @return true if all anchors are supported. + * @return number of DNSKEY anchors with unsupported algorithms. */ -static int -anchors_dnskey_is_supported(struct trust_anchor* ta) +static size_t +anchors_dnskey_unsupported(struct trust_anchor* ta) { - size_t i; + size_t i, num = 0; for(i=0; inumDNSKEY; i++) { if(!dnskey_algo_is_supported(ta->dnskey_rrset, i)) - return 0; + num++; } - return 1; + return num; } /** @@ -863,21 +862,35 @@ static int anchors_assemble_rrsets(struct val_anchors* anchors) { struct trust_anchor* ta; - RBTREE_FOR(ta, struct trust_anchor*, anchors->tree) { + struct trust_anchor* next; + size_t nods, nokey; + ta=(struct trust_anchor*)rbtree_first(anchors->tree); + while((rbnode_t*)ta != RBTREE_NULL) { + next = (struct trust_anchor*)rbtree_next(&ta->node); if(!anchors_assemble(anchors, ta)) { log_err("out of memory"); return 0; } - if(!anchors_ds_is_supported(ta)) { + nods = anchors_ds_unsupported(ta); + nokey = anchors_dnskey_unsupported(ta); + if(nods) { log_nametypeclass(0, "warning: unsupported " "algorithm for trust anchor", ta->name, LDNS_RR_TYPE_DS, ta->dclass); } - if(!anchors_dnskey_is_supported(ta)) { + if(nokey) { log_nametypeclass(0, "warning: unsupported " "algorithm for trust anchor", ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass); } + if(nods == ta->numDS && nokey == ta->numDNSKEY) { + char b[257]; + dname_str(ta->name, b); + log_warn("trust anchor %s has no supported algorithms," + " the anchor is ignored", b); + (void)rbtree_delete(anchors->tree, &ta->node); + } + ta = next; } return 1; } @@ -946,8 +959,9 @@ anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg) return 0; } } - init_parents(anchors); + /* first assemble, since it may delete useless anchors */ anchors_assemble_rrsets(anchors); + init_parents(anchors); ldns_buffer_free(parsebuf); return 1; } diff --git a/validator/val_utils.c b/validator/val_utils.c index 9f7a44372..b10084b4c 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -718,16 +718,15 @@ val_mark_indeterminate(struct reply_info* rep, struct val_anchors* anchors, } void -val_mark_insecure(struct reply_info* rep, struct key_entry_key* kkey, +val_mark_insecure(struct reply_info* rep, uint8_t* kname, struct rrset_cache* r, struct module_env* env) { size_t i; struct packed_rrset_data* d; - log_assert(key_entry_isnull(kkey)); for(i=0; irrset_count; i++) { d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data; if(d->security == sec_status_unchecked && - dname_subdomain_c(rep->rrsets[i]->rk.dname, kkey->name)) { + dname_subdomain_c(rep->rrsets[i]->rk.dname, kname)) { /* mark as insecure */ d->security = sec_status_insecure; rrset_update_sec_status(r, rep->rrsets[i], *env->now); diff --git a/validator/val_utils.h b/validator/val_utils.h index c85f50392..027cb806a 100644 --- a/validator/val_utils.h +++ b/validator/val_utils.h @@ -240,12 +240,11 @@ void val_mark_indeterminate(struct reply_info* rep, * Mark all unchecked rrset entries below a NULL key entry as insecure. * Only security==unchecked rrsets are updated. * @param rep: the reply with rrsets. - * @param kkey: key entry, key_entry_isnull() for it. A key entry that marks - * the end of secure space into insecure space. + * @param kname: end of secure space name. * @param r: rrset cache to store updated security status into. * @param env: module environment */ -void val_mark_insecure(struct reply_info* rep, struct key_entry_key* kkey, +void val_mark_insecure(struct reply_info* rep, uint8_t* kname, struct rrset_cache* r, struct module_env* env); /** diff --git a/validator/validator.c b/validator/validator.c index a0e952786..299766358 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -1209,6 +1209,17 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, else if(vq->key_entry == NULL || (vq->trust_anchor && dname_strict_subdomain_c(vq->trust_anchor->name, vq->key_entry->name))) { + /* trust anchor is an 'unsigned' trust anchor */ + if(vq->trust_anchor && vq->trust_anchor->numDS == 0 && + vq->trust_anchor->numDNSKEY == 0) { + vq->chase_reply->security = sec_status_insecure; + val_mark_insecure(vq->chase_reply, + vq->trust_anchor->name, + qstate->env->rrset_cache, qstate->env); + /* go to finished state to cache this result */ + vq->state = VAL_FINISHED_STATE; + return 1; + } /* fire off a trust anchor priming query. */ verbose(VERB_DETAIL, "prime trust anchor"); if(!prime_trust_anchor(qstate, vq, id, vq->trust_anchor)) @@ -1222,7 +1233,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, * However, we do set the status to INSECURE, since it is * essentially proven insecure. */ vq->chase_reply->security = sec_status_insecure; - val_mark_insecure(vq->chase_reply, vq->key_entry, + val_mark_insecure(vq->chase_reply, vq->key_entry->name, qstate->env->rrset_cache, qstate->env); /* go to finished state to cache this result */ vq->state = VAL_FINISHED_STATE; @@ -1394,7 +1405,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, verbose(VERB_DETAIL, "Verified that %sresponse is INSECURE", vq->signer_name?"":"unsigned "); vq->chase_reply->security = sec_status_insecure; - val_mark_insecure(vq->chase_reply, vq->key_entry, + val_mark_insecure(vq->chase_reply, vq->key_entry->name, qstate->env->rrset_cache, qstate->env); return 1; }