From: Wouter Wijngaards Date: Fri, 29 Oct 2010 13:10:26 +0000 (+0000) Subject: - Fix validation failure for parent and child on same server with an X-Git-Tag: release-1.4.7rc1~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=488aee467a413c5efd1d9e0005bb000d5162fd5f;p=thirdparty%2Funbound.git - Fix validation failure for parent and child on same server with an insecure childzone and a CNAME from parent to child. git-svn-id: file:///svn/unbound/trunk@2321 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 87a1f1ac2..32522a8eb 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,5 +1,7 @@ 27 October 2010: Wouter - Fix uninit value in dump_infra print. + - Fix validation failure for parent and child on same server with an + insecure childzone and a CNAME from parent to child. 26 October 2010: Wouter - dump_infra and flush_infra commands for unbound-control. diff --git a/testdata/val_cnametonsec.rpl b/testdata/val_cnametonsec.rpl new file mode 100644 index 000000000..9e5490938 --- /dev/null +++ b/testdata/val_cnametonsec.rpl @@ -0,0 +1,158 @@ +; config options +; The island of trust is at example.com +server: + trust-anchor: "example.com. 3600 IN DS 2854 3 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 CNAME to insecure NSEC delegation + +; 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 CNAME www.sub.example.com. +www.example.com. 3600 IN RRSIG CNAME 3 3 3600 20070926134802 20070829134802 2854 example.com. AKvv+5rFiCFiNRbdpna4rQtyARsLltUL9lXRWgpBVB5voJNJ9g/n/f4= ;{id = 2854} +SECTION AUTHORITY +sub.example.com. IN NSEC zzz.example.com. NS +sub.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926134802 20070829134802 2854 example.com. AJPvjSrqGbe3ZBOxV9J3XyFeOqrcPfIYPIWnlmj6G+PebJdAkvwIu9o= ;{id = 2854} +SECTION ADDITIONAL +ENTRY_END + +; this server also serves the zone sub.example.com. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.sub.example.com. IN A +SECTION AUTHORITY +sub.example.com. IN SOA a. b. 1 2 3 4 5 +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 CNAME www.sub.example.com. +www.example.com. 3600 IN RRSIG CNAME 3 3 3600 20070926134802 20070829134802 2854 example.com. AKvv+5rFiCFiNRbdpna4rQtyARsLltUL9lXRWgpBVB5voJNJ9g/n/f4= ;{id = 2854} +SECTION AUTHORITY +sub.example.com. IN NSEC zzz.example.com. NS +sub.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926134802 20070829134802 2854 example.com. AJPvjSrqGbe3ZBOxV9J3XyFeOqrcPfIYPIWnlmj6G+PebJdAkvwIu9o= ;{id = 2854} +sub.example.com. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +SCENARIO_END diff --git a/testdata/val_cnametooptin.rpl b/testdata/val_cnametooptin.rpl new file mode 100644 index 000000000..657dcd11e --- /dev/null +++ b/testdata/val_cnametooptin.rpl @@ -0,0 +1,162 @@ +; config options +; The island of trust is at example.com +server: + trust-anchor: "example.com. 3600 IN DS 2854 3 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 CNAME to insecure optin NSEC3 + +; 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 CNAME www.sub.example.com. +www.example.com. 3600 IN RRSIG CNAME 3 3 3600 20070926134802 20070829134802 2854 example.com. AKvv+5rFiCFiNRbdpna4rQtyARsLltUL9lXRWgpBVB5voJNJ9g/n/f4= ;{id = 2854} +SECTION AUTHORITY +; NSEC3PARAM 1 0 1 - +; example.com. -> 9vq38lj9qs6s1aruer131mbtsfnvek2p. +; sub.example.com. -> 7t1ect6t5vp0s7se8si9d07roqupr3gc. +; www.example.com. -> 0lverorlcjoa2lji5rik0otij3lgoj3l. +7t1ect6t5vp0s7se8si9d07roqupr3gc.example.com. IN NSEC3 1 0 1 - 7t1ect6t5vp0s7se8si9d07roqupr3gd NS +7t1ect6t5vp0s7se8si9d07roqupr3gc.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926134802 20070829134802 2854 example.com. AIiTSxI4hTDiDzo+bMaOKSvjIyoChgjY19y2NQG/Mtt80sNbDBY126I= ;{id = 2854} +SECTION ADDITIONAL +ENTRY_END + +; this server also serves the zone sub.example.com. +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.sub.example.com. IN A +SECTION AUTHORITY +sub.example.com. IN SOA a. b. 1 2 3 4 5 +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 CNAME www.sub.example.com. +www.example.com. 3600 IN RRSIG CNAME 3 3 3600 20070926134802 20070829134802 2854 example.com. AKvv+5rFiCFiNRbdpna4rQtyARsLltUL9lXRWgpBVB5voJNJ9g/n/f4= ;{id = 2854} +SECTION AUTHORITY +7t1ect6t5vp0s7se8si9d07roqupr3gc.example.com. IN NSEC3 1 0 1 - 7t1ect6t5vp0s7se8si9d07roqupr3gd NS +7t1ect6t5vp0s7se8si9d07roqupr3gc.example.com. 3600 IN RRSIG NSEC3 3 3 3600 20070926134802 20070829134802 2854 example.com. AIiTSxI4hTDiDzo+bMaOKSvjIyoChgjY19y2NQG/Mtt80sNbDBY126I= ;{id = 2854} +sub.example.com. IN SOA a. b. 1 2 3 4 5 +ENTRY_END + +SCENARIO_END diff --git a/testdata/val_nodata_zonecut.rpl b/testdata/val_nodata_zonecut.rpl index 49b52c0fd..e9e50a7ce 100644 --- a/testdata/val_nodata_zonecut.rpl +++ b/testdata/val_nodata_zonecut.rpl @@ -131,8 +131,8 @@ SECTION AUTHORITY ; SOA record is missing in reply. ; Denies A, note this is the end of the NSEC chain. ; from wrong side of zone-cut -www.example.com. IN NSEC example.com. NS RRSIG NSEC -www.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926135752 20070829135752 2854 example.com. MCwCFCQcnUp3juEjo72FpC82jFwZ2DStAhQpwpdMvEycW2elKfxpDdIHlT5ERg== ;{id = 2854} +www.example.com. 3600 IN NSEC example.com. NS DS RRSIG NSEC +www.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926135752 20070829135752 2854 example.com. AA+3mzAYPyQ8G9EKxeyNM+UZY+RtCiS5BOkS8h4wSxMT3lfVdadGpn8= ;{id = 2854} SECTION ADDITIONAL ENTRY_END RANGE_END diff --git a/validator/val_nsec.c b/validator/val_nsec.c index d6b2ed07c..75574ffb1 100644 --- a/validator/val_nsec.c +++ b/validator/val_nsec.c @@ -425,6 +425,27 @@ val_nsec_proves_name_error(struct ub_packed_rrset_key* nsec, uint8_t* qname) return 0; } +int val_nsec_proves_insecuredelegation(struct ub_packed_rrset_key* nsec, + struct query_info* qinfo) +{ + if(nsec_has_type(nsec, LDNS_RR_TYPE_NS) && + !nsec_has_type(nsec, LDNS_RR_TYPE_DS) && + !nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) { + /* see if nsec signals an insecure delegation */ + if(qinfo->qtype == LDNS_RR_TYPE_DS) { + /* if type is DS and qname is equal to nsec, then it + * is an exact match nsec, result not insecure */ + if(dname_strict_subdomain_c(qinfo->qname, + nsec->rk.dname)) + return 1; + } else { + if(dname_subdomain_c(qinfo->qname, nsec->rk.dname)) + return 1; + } + } + return 0; +} + uint8_t* nsec_closest_encloser(uint8_t* qname, struct ub_packed_rrset_key* nsec) { diff --git a/validator/val_nsec.h b/validator/val_nsec.h index 659edc2ff..34f7f63b4 100644 --- a/validator/val_nsec.h +++ b/validator/val_nsec.h @@ -169,4 +169,14 @@ int val_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname, int val_nsec_check_dlv(struct query_info* qinfo, struct reply_info* rep, uint8_t** nm, size_t* nm_len); +/** + * Determine if an nsec proves an insecure delegation towards the qname. + * @param nsec: nsec rrset. + * @param qinfo: what was queries for. + * @return 0 if not, 1 if an NSEC that signals an insecure delegation to + * the qname. + */ +int val_nsec_proves_insecuredelegation(struct ub_packed_rrset_key* nsec, + struct query_info* qinfo); + #endif /* VALIDATOR_VAL_NSEC_H */ diff --git a/validator/val_nsec3.c b/validator/val_nsec3.c index e966ca7bf..be99d9832 100644 --- a/validator/val_nsec3.c +++ b/validator/val_nsec3.c @@ -935,10 +935,12 @@ next_closer(uint8_t* qname, size_t qnamelen, uint8_t* ce, * If set true, and the return value is true, then you can be * certain that the ce.nc_rrset and ce.nc_rr are set properly. * @param ce: closest encloser information is returned in here. - * @return false if no closest encloser could be proven. - * true if a closest encloser could be proven, ce is set. + * @return bogus if no closest encloser could be proven. + * secure if a closest encloser could be proven, ce is set. + * insecure if the closest-encloser candidate turns out to prove + * that an insecure delegation exists above the qname. */ -static int +static enum sec_status nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, rbtree_t* ct, struct query_info* qinfo, int prove_does_not_exist, struct ce_response* ce) @@ -951,7 +953,7 @@ nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, if(!nsec3_find_closest_encloser(env, flt, ct, qinfo, ce)) { verbose(VERB_ALGO, "nsec3 proveClosestEncloser: could " "not find a candidate for the closest encloser."); - return 0; + return sec_status_bogus; } log_nametypeclass(VERB_ALGO, "ce candidate", ce->ce, 0, 0); @@ -959,11 +961,11 @@ nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, if(prove_does_not_exist) { verbose(VERB_ALGO, "nsec3 proveClosestEncloser: " "proved that qname existed, bad"); - return 0; + return sec_status_bogus; } /* otherwise, we need to nothing else to prove that qname * is its own closest encloser. */ - return 1; + return sec_status_secure; } /* If the closest encloser is actually a delegation, then the @@ -971,14 +973,19 @@ nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, * it should have been a DNAME response. */ if(nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_NS) && !nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_SOA)) { + if(!nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_DS)) { + verbose(VERB_ALGO, "nsec3 proveClosestEncloser: " + "closest encloser is insecure delegation"); + return sec_status_insecure; + } verbose(VERB_ALGO, "nsec3 proveClosestEncloser: closest " "encloser was a delegation, bad"); - return 0; + return sec_status_bogus; } if(nsec3_has_type(ce->ce_rrset, ce->ce_rr, LDNS_RR_TYPE_DNAME)) { verbose(VERB_ALGO, "nsec3 proveClosestEncloser: closest " "encloser was a DNAME, bad"); - return 0; + return sec_status_bogus; } /* Otherwise, we need to show that the next closer name is covered. */ @@ -987,9 +994,9 @@ nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, &ce->nc_rrset, &ce->nc_rr)) { verbose(VERB_ALGO, "nsec3: Could not find proof that the " "candidate encloser was the closest encloser"); - return 0; + return sec_status_bogus; } - return 1; + return sec_status_secure; } /** allocate a wildcard for the closest encloser */ @@ -1022,14 +1029,19 @@ nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, size_t wclen; struct ub_packed_rrset_key* wc_rrset; int wc_rr; + enum sec_status sec; /* First locate and prove the closest encloser to qname. We will * use the variant that fails if the closest encloser turns out * to be qname. */ - if(!nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce)) { - verbose(VERB_ALGO, "nsec3 nameerror proof: failed to prove " - "a closest encloser"); - return sec_status_bogus; + sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce); + if(sec != sec_status_secure) { + if(sec == sec_status_bogus) + verbose(VERB_ALGO, "nsec3 nameerror proof: failed " + "to prove a closest encloser"); + else verbose(VERB_ALGO, "nsec3 nameerror proof: closest " + "nsec3 is an insecure delegation"); + return sec; } log_nametypeclass(VERB_ALGO, "nsec3 namerror: proven ce=", ce.ce,0,0); @@ -1082,6 +1094,7 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, size_t wclen; struct ub_packed_rrset_key* rrset; int rr; + enum sec_status sec; if(find_matching_nsec3(env, flt, ct, qinfo->qname, qinfo->qname_len, &rrset, &rr)) { @@ -1126,10 +1139,15 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, /* For cases 3 - 5, we need the proven closest encloser, and it * can't match qname. Although, at this point, we know that it * won't since we just checked that. */ - if(!nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce)) { + sec = nsec3_prove_closest_encloser(env, flt, ct, qinfo, 1, &ce); + if(sec == sec_status_bogus) { verbose(VERB_ALGO, "proveNodata: did not match qname, " "nor found a proven closest encloser."); return sec_status_bogus; + } else if(sec==sec_status_insecure && qinfo->qtype!=LDNS_RR_TYPE_DS){ + verbose(VERB_ALGO, "proveNodata: closest nsec3 is insecure " + "delegation."); + return sec_status_insecure; } /* Case 3: removed */ @@ -1327,7 +1345,10 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, } /* Otherwise, we are probably in the opt-out case. */ - if(!nsec3_prove_closest_encloser(env, &flt, &ct, qinfo, 1, &ce)) { + if(nsec3_prove_closest_encloser(env, &flt, &ct, qinfo, 1, &ce) + != sec_status_secure) { + /* an insecure delegation *above* the qname does not prove + * anything about this qname exactly, and bogus is bogus */ verbose(VERB_ALGO, "nsec3 provenods: did not match qname, " "nor found a proven closest encloser."); *reason = "no NSEC3 closest encloser"; @@ -1372,7 +1393,8 @@ nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve, /* try nxdomain and nodata after another, while keeping the * hash cache intact */ - if(nsec3_do_prove_nameerror(env, &flt, &ct, qinfo)==sec_status_secure) + sec = nsec3_do_prove_nameerror(env, &flt, &ct, qinfo); + if(sec==sec_status_secure) return sec_status_secure; sec = nsec3_do_prove_nodata(env, &flt, &ct, qinfo); if(sec==sec_status_secure) { diff --git a/validator/validator.c b/validator/validator.c index 635058388..cfce63c8e 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -695,6 +695,11 @@ validate_nodata_response(struct module_env* env, struct val_env* ve, if(val_nsec_proves_name_error(s, qchase->qname)) { ce = nsec_closest_encloser(qchase->qname, s); } + if(val_nsec_proves_insecuredelegation(s, qchase)) { + verbose(VERB_ALGO, "delegation is insecure"); + chase_reply->security = sec_status_insecure; + return; + } } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) { nsec3s_seen = 1; } @@ -773,6 +778,11 @@ validate_nameerror_response(struct module_env* env, struct val_env* ve, if(val_nsec_proves_no_wc(s, qchase->qname, qchase->qname_len)) has_valid_wnsec = 1; + if(val_nsec_proves_insecuredelegation(s, qchase)) { + verbose(VERB_ALGO, "delegation is insecure"); + chase_reply->security = sec_status_insecure; + return; + } } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) nsec3s_seen = 1; } @@ -1116,6 +1126,11 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve, if(val_nsec_proves_no_wc(s, qchase->qname, qchase->qname_len)) nxdomain_valid_wnsec = 1; + if(val_nsec_proves_insecuredelegation(s, qchase)) { + verbose(VERB_ALGO, "delegation is insecure"); + chase_reply->security = sec_status_insecure; + return; + } } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) { nsec3s_seen = 1; }