Package: release.debian.org
Severity: normal
Tags: stretch
User: release.debian....@packages.debian.org
Usertags: pu

Hi,

I would like to fix a DNSSEC validation bug (CVE-2017-15105) in the
unbound package shipped in stretch. After discussion with the security
team, this bug was deemed minor enough that the fix could be shipped in
a point release:

https://security-tracker.debian.org/tracker/CVE-2017-15105

Please see attached a debdiff for unbound 1.6.0-3+deb9u2 containing the
backported fix from upstream version 1.6.8. I'd like to have this
considered for the upcoming stable point release.

Details on the bug and its impact are available in this upstream
advisory:

https://unbound.net/downloads/CVE-2017-15105.txt

I have cherry-picked two commits (svn r4441, r4528) from the upstream
repository containing the fix and a test case. Those upstream commits
are available here:

https://github.com/NLnetLabs/unbound/commit/2a6250e3fb3ccd6e9a0a16b6908c5cfb76d8d6f3

https://github.com/NLnetLabs/unbound/commit/eff62cecac1388214032906eb6944ceb9c0e6d41

(There was a minor conflict when merging the cherry-picked commit r4441
due to the renaming of some internal types in svn r3989.)

A very similar fix has already been shipped for wheezy-lts in
1.4.17-3+deb7u3.

Thanks!

-- 
Robert Edmonds
edmo...@debian.org
diff -Nru unbound-1.6.0/debian/changelog unbound-1.6.0/debian/changelog
--- unbound-1.6.0/debian/changelog      2017-08-27 00:43:42.000000000 -0400
+++ unbound-1.6.0/debian/changelog      2018-02-28 17:00:51.000000000 -0500
@@ -1,3 +1,12 @@
+unbound (1.6.0-3+deb9u2) stretch; urgency=high
+
+  * Cherry-pick upstream commit svn r4441, "patch for CVE-2017-15105:
+    vulnerability in the processing of wildcard synthesized NSEC records."
+  * Cherry-pick upstream commit svn r4528, "Added tests with wildcard
+    expanded NSEC records (CVE-2017-15105 test)".
+
+ -- Robert Edmonds <edmo...@debian.org>  Wed, 28 Feb 2018 17:00:51 -0500
+
 unbound (1.6.0-3+deb9u1) stretch; urgency=high
 
   * Cherry-pick upstream commit svn r4301, "Fix install of trust anchor
diff -Nru unbound-1.6.0/debian/patches/debian-changes 
unbound-1.6.0/debian/patches/debian-changes
--- unbound-1.6.0/debian/patches/debian-changes 2017-08-27 00:43:42.000000000 
-0400
+++ unbound-1.6.0/debian/patches/debian-changes 2018-02-28 17:00:51.000000000 
-0500
@@ -5,14 +5,12 @@
  information below has been extracted from the changelog. Adjust it or drop
  it.
  .
- unbound (1.6.0-3+deb9u1) stretch; urgency=high
+ unbound (1.6.0-3+deb9u2) stretch; urgency=high
  .
-   * Cherry-pick upstream commit svn r4301, "Fix install of trust anchor
-     when two anchors are present, makes both valid.  Checks hash of DS but
-     not signature of new key.  This fixes installs between sep11 and oct11
-     2017."
-   * debian/control: unbound: Add versioned dependency on dns-root-data (>=
-     2017072601~) for KSK-2017 in RFC 5011 state VALID.
+   * Cherry-pick upstream commit svn r4441, "patch for CVE-2017-15105:
+     vulnerability in the processing of wildcard synthesized NSEC records."
+   * Cherry-pick upstream commit svn r4528, "Added tests with wildcard
+     expanded NSEC records (CVE-2017-15105 test)".
 Author: Robert Edmonds <edmo...@debian.org>
 
 ---
@@ -26,7 +24,7 @@
 Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
 Forwarded: <no|not-needed|url proving that it has been forwarded>
 Reviewed-By: <name and email of someone who approved the patch>
-Last-Update: 2017-08-27
+Last-Update: 2018-02-28
 
 --- unbound-1.6.0.orig/acx_python.m4
 +++ unbound-1.6.0/acx_python.m4
@@ -79,6 +77,165 @@
 +echo "Setup success. Certificates created."
  
  exit 0
+--- unbound-1.6.0.orig/testcode/unitverify.c
++++ unbound-1.6.0/testcode/unitverify.c
+@@ -186,7 +186,9 @@ verifytest_rrset(struct module_env* env,
+                       ntohs(rrset->rk.rrset_class));
+       }
+       setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */
+-      sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason);
++      /* ok to give null as qstate here, won't be used for answer section. */
++      sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason,
++              LDNS_SECTION_ANSWER, NULL);
+       if(vsig) {
+               printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
+                       reason?reason:"");
+--- /dev/null
++++ unbound-1.6.0/testdata/val_nodata_failwc.rpl
+@@ -0,0 +1,71 @@
++; config options
++; The island of trust is at nsecwc.nlnetlabs.nl
++server:
++      trust-anchor: "nsecwc.nlnetlabs.nl.     10024   IN      DS      565 8 2 
0C15C04C022700C8713028F6F64CF2343DE627B8F83CDA1C421C65DB 52908A2E"
++      val-override-date: "20181202115531"
++      target-fetch-policy: "0 0 0 0 0"
++      fake-sha1: yes
++      trust-anchor-signaling: no
++stub-zone:
++      name: "nsecwc.nlnetlabs.nl"
++      stub-addr: "185.49.140.60"
++
++CONFIG_END
++
++SCENARIO_BEGIN Test validator with nodata response with wildcard expanded 
NSEC record, original NSEC owner does not provide proof for QNAME. 
CVE-2017-15105 test.
++
++ ; ns.example.com.                                                            
    
++RANGE_BEGIN 0 100                                                             
   
++      ADDRESS 185.49.140.60
++
++; response to DNSKEY priming query
++ENTRY_BEGIN
++MATCH opcode qtype qname
++ADJUST copy_id
++REPLY QR NOERROR
++SECTION QUESTION
++nsecwc.nlnetlabs.nl. IN DNSKEY
++SECTION ANSWER
++nsecwc.nlnetlabs.nl.  3600    IN      DNSKEY  257 3 8 
AwEAAbTluF4BfJ/FT7Ak5a3VvYG1AqhT8FXxOsVwGTyueyE/hW+fMFMd 
QlLMf2Lf/gmsnFgn/p7GDmJBLlPTATmLeP3isvAZbK3MDEP2O5UjTVmt 
LZriTv8xfxYW6emCM54EQjWii64BFWrOeLm9zQqzyaLl53CbIIXqiacV KPteh8GX
++nsecwc.nlnetlabs.nl.  3600    IN      RRSIG   DNSKEY 8 3 3600 20200101000000 
20171108114635 565 nsecwc.nlnetlabs.nl. 
q3bG4e8EtvXKDcNWcyYHeQxLF9l9aJKdmeSubyN6Qc3UVHugd6t3YSxD 
hlD+g43y7FcdnNHdAPh/jpgC4wtOb5J+5XAuESDHwesmIXOCTJjrb+A8 
r+xQK+vsY8FhNZ2r81JZ/KQ/+TcCS5tbYeNZQgENduWAxgGiw3fdrMOV xiU=
++ENTRY_END
++
++; response to query of interest
++ENTRY_BEGIN
++MATCH opcode qtype qname
++ADJUST copy_id
++REPLY QR NOERROR
++SECTION QUESTION
++_25._tcp.mail.nsecwc.nlnetlabs.nl. IN TLSA
++SECTION ANSWER
++SECTION AUTHORITY
++nsecwc.nlnetlabs.nl.  3600    IN      SOA     ns.nlnetlabs.nl. 
ralph.nlnetlabs.nl. 1 14400 3600 604800 3600
++nsecwc.nlnetlabs.nl.  3600    IN      RRSIG   SOA 8 3 3600 20200101000000 
20171108114635 565 nsecwc.nlnetlabs.nl. 
bYibpCDg1LgrnYJgVahgu94LBqLIcNs4iC0SW8LV7pTI1hhuFKbLkO2O 
ekPdkJAWmu/KTytf8D+cdcK6X/9VS8QCVIF5S0hraHtNezu0f1B5ztg3 
7Rqy+uJSucNKoykueAsz2z43GMgO0rGH3bqM7+3ii8p2E2rhzqEtG/D3 qyY=
++; NSEC has a label lenght of 3, indication that the original owner name is:
++; *.nsecwc.nlnetlabs.nl. The NSEC therefore does no prove the NODATA answer.
++_25._tcp.mail.nsecwc.nlnetlabs.nl. 3600       IN NSEC 
delegation.nsecwc.nlnetlabs.nl. TXT RRSIG NSEC
++_25._tcp.mail.nsecwc.nlnetlabs.nl. 3600       IN RRSIG NSEC 8 3 3600 
20200101000000 20171108114635 565 nsecwc.nlnetlabs.nl. 
ddy1MRbshFuFJswlouNGHsZUF/tYu8BOCztY2JuHeTMyWL7rhRKp73q/ 
1RAXMwywKsynT5ioY0bMtEQszeIEn29IYaPDHieLAobjF6BMu1kO7U2/ 
oEBrSHM/fx28BcaM5G4nfCIm3BlhQhWvk1NDHLn3Q26x4hF/dnmFOUet aXw=
++SECTION ADDITIONAL
++ENTRY_END
++RANGE_END
++
++STEP 1 QUERY
++ENTRY_BEGIN
++REPLY RD DO
++SECTION QUESTION
++_25._tcp.mail.nsecwc.nlnetlabs.nl. IN   TLSA
++ENTRY_END
++
++; recursion happens here.
++STEP 10 CHECK_ANSWER
++ENTRY_BEGIN
++MATCH all
++REPLY QR RD RA DO SERVFAIL
++SECTION QUESTION
++_25._tcp.mail.nsecwc.nlnetlabs.nl. IN   TLSA
++SECTION ANSWER
++SECTION AUTHORITY
++SECTION ADDITIONAL
++ENTRY_END
++
++SCENARIO_END
+--- /dev/null
++++ unbound-1.6.0/testdata/val_nx_failwc.rpl
+@@ -0,0 +1,69 @@
++; config options
++; The island of trust is at nsecwc.nlnetlabs.nl
++server:
++      trust-anchor: "nsecwc.nlnetlabs.nl.     10024   IN      DS      565 8 2 
0C15C04C022700C8713028F6F64CF2343DE627B8F83CDA1C421C65DB 52908A2E"
++      val-override-date: "20181202115531"
++      target-fetch-policy: "0 0 0 0 0"
++      fake-sha1: yes
++      trust-anchor-signaling: no
++stub-zone:
++      name: "nsecwc.nlnetlabs.nl"
++      stub-addr: "185.49.140.60"
++
++CONFIG_END
++
++SCENARIO_BEGIN Test validator with nxdomain response with wildcard expanded 
NSEC record, original NSEC owner does not provide proof for QNAME. 
CVE-2017-15105 test.
++
++ ; ns.example.com.                                                            
    
++RANGE_BEGIN 0 100                                                             
   
++      ADDRESS 185.49.140.60
++
++; response to DNSKEY priming query
++ENTRY_BEGIN
++MATCH opcode qtype qname
++ADJUST copy_id
++REPLY QR NOERROR
++SECTION QUESTION
++nsecwc.nlnetlabs.nl. IN DNSKEY
++SECTION ANSWER
++nsecwc.nlnetlabs.nl.  3600    IN      DNSKEY  257 3 8 
AwEAAbTluF4BfJ/FT7Ak5a3VvYG1AqhT8FXxOsVwGTyueyE/hW+fMFMd 
QlLMf2Lf/gmsnFgn/p7GDmJBLlPTATmLeP3isvAZbK3MDEP2O5UjTVmt 
LZriTv8xfxYW6emCM54EQjWii64BFWrOeLm9zQqzyaLl53CbIIXqiacV KPteh8GX
++nsecwc.nlnetlabs.nl.  3600    IN      RRSIG   DNSKEY 8 3 3600 20200101000000 
20171108114635 565 nsecwc.nlnetlabs.nl. 
q3bG4e8EtvXKDcNWcyYHeQxLF9l9aJKdmeSubyN6Qc3UVHugd6t3YSxD 
hlD+g43y7FcdnNHdAPh/jpgC4wtOb5J+5XAuESDHwesmIXOCTJjrb+A8 
r+xQK+vsY8FhNZ2r81JZ/KQ/+TcCS5tbYeNZQgENduWAxgGiw3fdrMOV xiU=
++ENTRY_END
++
++; response to query of interest
++ENTRY_BEGIN
++MATCH opcode qtype qname
++ADJUST copy_id
++REPLY QR NXDOMAIN
++SECTION QUESTION
++a.nsecwc.nlnetlabs.nl. IN     TXT
++SECTION ANSWER
++SECTION AUTHORITY
++!.nsecwc.nlnetlabs.nl.        3600    IN      NSEC    
delegation.nsecwc.nlnetlabs.nl. TXT RRSIG NSEC
++!.nsecwc.nlnetlabs.nl.        3600    IN      RRSIG   NSEC 8 3 3600 
20200101000000 20171108114635 565 nsecwc.nlnetlabs.nl. 
ddy1MRbshFuFJswlouNGHsZUF/tYu8BOCztY2JuHeTMyWL7rhRKp73q/ 
1RAXMwywKsynT5ioY0bMtEQszeIEn29IYaPDHieLAobjF6BMu1kO7U2/ 
oEBrSHM/fx28BcaM5G4nfCIm3BlhQhWvk1NDHLn3Q26x4hF/dnmFOUet aXw=
++nsecwc.nlnetlabs.nl.  3600    IN      SOA     ns.nlnetlabs.nl. 
ralph.nlnetlabs.nl. 1 14400 3600 604800 3600
++nsecwc.nlnetlabs.nl.  3600    IN      RRSIG   SOA 8 3 3600 20200101000000 
20171108114635 565 nsecwc.nlnetlabs.nl. 
bYibpCDg1LgrnYJgVahgu94LBqLIcNs4iC0SW8LV7pTI1hhuFKbLkO2O 
ekPdkJAWmu/KTytf8D+cdcK6X/9VS8QCVIF5S0hraHtNezu0f1B5ztg3 
7Rqy+uJSucNKoykueAsz2z43GMgO0rGH3bqM7+3ii8p2E2rhzqEtG/D3 qyY=
++SECTION ADDITIONAL
++ENTRY_END
++RANGE_END
++
++STEP 1 QUERY
++ENTRY_BEGIN
++REPLY RD DO
++SECTION QUESTION
++a.nsecwc.nlnetlabs.nl. IN   TXT
++ENTRY_END
++
++; recursion happens here.
++STEP 10 CHECK_ANSWER
++ENTRY_BEGIN
++MATCH all
++REPLY QR RD RA DO SERVFAIL
++SECTION QUESTION
++a.nsecwc.nlnetlabs.nl. IN   TXT
++SECTION ANSWER
++SECTION AUTHORITY
++SECTION ADDITIONAL
++ENTRY_END
++
++SCENARIO_END
 --- unbound-1.6.0.orig/util/config_file.c
 +++ unbound-1.6.0/util/config_file.c
 @@ -149,7 +149,7 @@ config_create(void)
@@ -123,7 +280,67 @@
        ;
 --- unbound-1.6.0.orig/validator/autotrust.c
 +++ unbound-1.6.0/validator/autotrust.c
-@@ -1571,6 +1571,11 @@ key_matches_a_ds(struct module_env* env,
+@@ -1227,17 +1227,20 @@ void autr_write_file(struct module_env*
+  * @param ve: validator environment (with options) for verification.
+  * @param tp: trust point to verify with
+  * @param rrset: DNSKEY rrset to verify.
++ * @param qstate: qstate with region.
+  * @return false on failure, true if verification successful.
+  */
+ static int
+ verify_dnskey(struct module_env* env, struct val_env* ve,
+-        struct trust_anchor* tp, struct ub_packed_rrset_key* rrset)
++        struct trust_anchor* tp, struct ub_packed_rrset_key* rrset,
++      struct module_qstate* qstate)
+ {
+       char* reason = NULL;
+       uint8_t sigalg[ALGO_NEEDS_MAX+1];
+       int downprot = env->cfg->harden_algo_downgrade;
+       enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
+-              tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason);
++              tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason,
++              qstate);
+       /* sigalg is ignored, it returns algorithms signalled to exist, but
+        * in 5011 there are no other rrsets to check.  if downprot is
+        * enabled, then it checks that the DNSKEY is signed with all
+@@ -1276,7 +1279,8 @@ min_expiry(struct module_env* env, struc
+ /** Is rr self-signed revoked key */
+ static int
+ rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
+-      struct ub_packed_rrset_key* dnskey_rrset, size_t i)
++      struct ub_packed_rrset_key* dnskey_rrset, size_t i,
++      struct module_qstate* qstate)
+ {
+       enum sec_status sec;
+       char* reason = NULL;
+@@ -1285,7 +1289,7 @@ rr_is_selfsigned_revoked(struct module_e
+       /* no algorithm downgrade protection necessary, if it is selfsigned
+        * revoked it can be removed. */
+       sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i, 
+-              &reason);
++              &reason, LDNS_SECTION_ANSWER, qstate);
+       return (sec == sec_status_secure);
+ }
+ 
+@@ -1501,7 +1505,7 @@ init_events(struct trust_anchor* tp)
+ static void
+ check_contains_revoked(struct module_env* env, struct val_env* ve,
+       struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
+-      int* changed)
++      int* changed, struct module_qstate* qstate)
+ {
+       struct packed_rrset_data* dd = (struct packed_rrset_data*)
+               dnskey_rrset->entry.data;
+@@ -1521,7 +1525,7 @@ check_contains_revoked(struct module_env
+               }
+               if(!ta)
+                       continue; /* key not found */
+-              if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i)) {
++              if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) {
+                       /* checked if there is an rrsig signed by this key. */
+                       /* same keytag, but stored can be revoked already, so 
+                        * compare keytags, with +0 or +128(REVOKE flag) */
+@@ -1571,6 +1575,11 @@ key_matches_a_ds(struct module_env* env,
                        verbose(VERB_ALGO, "DS match attempt failed");
                        continue;
                }
@@ -135,7 +352,7 @@
                if(dnskey_verify_rrset(env, ve, dnskey_rrset, 
                        dnskey_rrset, key_idx, &reason) == sec_status_secure) {
                        return 1;
-@@ -1578,6 +1583,7 @@ key_matches_a_ds(struct module_env* env,
+@@ -1578,6 +1587,7 @@ key_matches_a_ds(struct module_env* env,
                        verbose(VERB_ALGO, "DS match failed because the key "
                                "does not verify the keyset: %s", reason);
                }
@@ -143,3 +360,762 @@
        }
        return 0;
  }
+@@ -2112,7 +2122,8 @@ autr_tp_remove(struct module_env* env, s
+ }
+ 
+ int autr_process_prime(struct module_env* env, struct val_env* ve,
+-      struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset)
++      struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
++      struct module_qstate* qstate)
+ {
+       int changed = 0;
+       log_assert(tp && tp->autr);
+@@ -2153,7 +2164,7 @@ int autr_process_prime(struct module_env
+               return 1; /* trust point exists */
+       }
+       /* check for revoked keys to remove immediately */
+-      check_contains_revoked(env, ve, tp, dnskey_rrset, &changed);
++      check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate);
+       if(changed) {
+               verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble");
+               if(!autr_assemble(tp)) {
+@@ -2169,7 +2180,7 @@ int autr_process_prime(struct module_env
+               }
+       }
+       /* verify the dnskey rrset and see if it is valid. */
+-      if(!verify_dnskey(env, ve, tp, dnskey_rrset)) {
++      if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) {
+               verbose(VERB_ALGO, "autotrust: dnskey did not verify.");
+               /* only increase failure count if this is not the first prime,
+                * this means there was a previous successful probe */
+--- unbound-1.6.0.orig/validator/autotrust.h
++++ unbound-1.6.0/validator/autotrust.h
+@@ -47,6 +47,7 @@ struct val_anchors;
+ struct trust_anchor;
+ struct ub_packed_rrset_key;
+ struct module_env;
++struct module_qstate;
+ struct val_env;
+ struct sldns_buffer;
+ 
+@@ -188,12 +189,14 @@ void autr_point_delete(struct trust_anch
+  * @param tp: trust anchor to process.
+  * @param dnskey_rrset: DNSKEY rrset probed (can be NULL if bad prime result).
+  *    allocated in a region. Has not been validated yet.
++ * @param qstate: qstate with region.
+  * @return false if trust anchor was revoked completely.
+  *    Otherwise logs errors to log, does not change return value.
+  *    On errors, likely the trust point has been unchanged.
+  */
+ int autr_process_prime(struct module_env* env, struct val_env* ve,
+-      struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset);
++      struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
++      struct module_qstate* qstate);
+ 
+ /**
+  * Debug printout of rfc5011 tracked anchors
+--- unbound-1.6.0.orig/validator/val_nsec.c
++++ unbound-1.6.0/validator/val_nsec.c
+@@ -176,7 +176,7 @@ val_nsec_proves_no_ds(struct ub_packed_r
+ static int
+ nsec_verify_rrset(struct module_env* env, struct val_env* ve, 
+       struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey, 
+-      char** reason)
++      char** reason, struct module_qstate* qstate)
+ {
+       struct packed_rrset_data* d = (struct packed_rrset_data*)
+               nsec->entry.data;
+@@ -185,7 +185,8 @@ nsec_verify_rrset(struct module_env* env
+       rrset_check_sec_status(env->rrset_cache, nsec, *env->now);
+       if(d->security == sec_status_secure)
+               return 1;
+-      d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason);
++      d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason,
++              LDNS_SECTION_AUTHORITY, qstate);
+       if(d->security == sec_status_secure) {
+               rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
+               return 1;
+@@ -196,7 +197,8 @@ nsec_verify_rrset(struct module_env* env
+ enum sec_status 
+ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve, 
+       struct query_info* qinfo, struct reply_info* rep, 
+-      struct key_entry_key* kkey, time_t* proof_ttl, char** reason)
++      struct key_entry_key* kkey, time_t* proof_ttl, char** reason,
++      struct module_qstate* qstate)
+ {
+       struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns(
+               rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC, 
+@@ -213,7 +215,7 @@ val_nsec_prove_nodata_dsreply(struct mod
+        * 1) this is a delegation point and there is no DS
+        * 2) this is not a delegation point */
+       if(nsec) {
+-              if(!nsec_verify_rrset(env, ve, nsec, kkey, reason)) {
++              if(!nsec_verify_rrset(env, ve, nsec, kkey, reason, qstate)) {
+                       verbose(VERB_ALGO, "NSEC RRset for the "
+                               "referral did not verify.");
+                       return sec_status_bogus;
+@@ -242,7 +244,8 @@ val_nsec_prove_nodata_dsreply(struct mod
+               i++) {
+               if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC))
+                       continue;
+-              if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason)) {
++              if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason,
++                      qstate)) {
+                       verbose(VERB_ALGO, "NSEC for empty non-terminal "
+                               "did not verify.");
+                       return sec_status_bogus;
+--- unbound-1.6.0.orig/validator/val_nsec.h
++++ unbound-1.6.0/validator/val_nsec.h
+@@ -46,6 +46,7 @@
+ #include "util/data/packed_rrset.h"
+ struct val_env;
+ struct module_env;
++struct module_qstate;
+ struct ub_packed_rrset_key;
+ struct reply_info;
+ struct query_info;
+@@ -64,6 +65,7 @@ struct key_entry_key;
+  * @param kkey: key entry to use for verification of signatures.
+  * @param proof_ttl: if secure, the TTL of how long this proof lasts.
+  * @param reason: string explaining why bogus.
++ * @param qstate: qstate with region.
+  * @return security status.
+  *    SECURE: proved absence of DS.
+  *    INSECURE: proved that this was not a delegation point.
+@@ -73,7 +75,7 @@ struct key_entry_key;
+ enum sec_status val_nsec_prove_nodata_dsreply(struct module_env* env,
+       struct val_env* ve, struct query_info* qinfo, 
+       struct reply_info* rep, struct key_entry_key* kkey,
+-      time_t* proof_ttl, char** reason);
++      time_t* proof_ttl, char** reason, struct module_qstate* qstate);
+ 
+ /** 
+  * nsec typemap check, takes an NSEC-type bitmap as argument, checks for type.
+--- unbound-1.6.0.orig/validator/val_nsec3.c
++++ unbound-1.6.0/validator/val_nsec3.c
+@@ -1285,7 +1285,7 @@ nsec3_prove_wildcard(struct module_env*
+ static int
+ list_is_secure(struct module_env* env, struct val_env* ve, 
+       struct ub_packed_rrset_key** list, size_t num,
+-      struct key_entry_key* kkey, char** reason)
++      struct key_entry_key* kkey, char** reason, struct module_qstate* qstate)
+ {
+       struct packed_rrset_data* d;
+       size_t i;
+@@ -1299,7 +1299,7 @@ list_is_secure(struct module_env* env, s
+               if(d->security == sec_status_secure)
+                       continue;
+               d->security = val_verify_rrset_entry(env, ve, list[i], kkey,
+-                      reason);
++                      reason, LDNS_SECTION_AUTHORITY, qstate);
+               if(d->security != sec_status_secure) {
+                       verbose(VERB_ALGO, "NSEC3 did not verify");
+                       return 0;
+@@ -1312,7 +1312,8 @@ list_is_secure(struct module_env* env, s
+ enum sec_status
+ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
+       struct ub_packed_rrset_key** list, size_t num,
+-      struct query_info* qinfo, struct key_entry_key* kkey, char** reason)
++      struct query_info* qinfo, struct key_entry_key* kkey, char** reason,
++      struct module_qstate* qstate)
+ {
+       rbtree_t ct;
+       struct nsec3_filter flt;
+@@ -1325,7 +1326,7 @@ nsec3_prove_nods(struct module_env* env,
+               *reason = "no valid NSEC3s";
+               return sec_status_bogus; /* no valid NSEC3s, bogus */
+       }
+-      if(!list_is_secure(env, ve, list, num, kkey, reason))
++      if(!list_is_secure(env, ve, list, num, kkey, reason, qstate))
+               return sec_status_bogus; /* not all NSEC3 records secure */
+       rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
+       filter_init(&flt, list, num, qinfo); /* init RR iterator */
+--- unbound-1.6.0.orig/validator/val_nsec3.h
++++ unbound-1.6.0/validator/val_nsec3.h
+@@ -71,6 +71,7 @@
+ struct val_env;
+ struct regional;
+ struct module_env;
++struct module_qstate;
+ struct ub_packed_rrset_key;
+ struct reply_info;
+ struct query_info;
+@@ -185,6 +186,7 @@ nsec3_prove_wildcard(struct module_env*
+  * @param qinfo: query that is verified for.
+  * @param kkey: key entry that signed the NSEC3s.
+  * @param reason: string for bogus result.
++ * @param qstate: qstate with region.
+  * @return:
+  *    sec_status SECURE of the proposition is proven by the NSEC3 RRs, 
+  *    BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
+@@ -194,7 +196,8 @@ nsec3_prove_wildcard(struct module_env*
+ enum sec_status
+ nsec3_prove_nods(struct module_env* env, struct val_env* ve,
+       struct ub_packed_rrset_key** list, size_t num, 
+-      struct query_info* qinfo, struct key_entry_key* kkey, char** reason);
++      struct query_info* qinfo, struct key_entry_key* kkey, char** reason,
++      struct module_qstate* qstate);
+ 
+ /**
+  * Prove NXDOMAIN or NODATA.
+--- unbound-1.6.0.orig/validator/val_sigcrypt.c
++++ unbound-1.6.0/validator/val_sigcrypt.c
+@@ -479,7 +479,8 @@ int algo_needs_missing(struct algo_needs
+ enum sec_status 
+ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
+       struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
+-      uint8_t* sigalg, char** reason)
++      uint8_t* sigalg, char** reason, sldns_pkt_section section, 
++      struct module_qstate* qstate)
+ {
+       enum sec_status sec;
+       size_t i, num;
+@@ -506,7 +507,7 @@ dnskeyset_verify_rrset(struct module_env
+       }
+       for(i=0; i<num; i++) {
+               sec = dnskeyset_verify_rrset_sig(env, ve, *env->now, rrset, 
+-                      dnskey, i, &sortree, reason);
++                      dnskey, i, &sortree, reason, section, qstate);
+               /* see which algorithm has been fixed up */
+               if(sec == sec_status_secure) {
+                       if(!sigalg)
+@@ -547,7 +548,8 @@ void algo_needs_reason(struct module_env
+ enum sec_status 
+ dnskey_verify_rrset(struct module_env* env, struct val_env* ve,
+         struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
+-      size_t dnskey_idx, char** reason)
++      size_t dnskey_idx, char** reason, sldns_pkt_section section,
++      struct module_qstate* qstate)
+ {
+       enum sec_status sec;
+       size_t i, num, numchecked = 0;
+@@ -571,7 +573,8 @@ dnskey_verify_rrset(struct module_env* e
+               buf_canon = 0;
+               sec = dnskey_verify_rrset_sig(env->scratch, 
+                       env->scratch_buffer, ve, *env->now, rrset, 
+-                      dnskey, dnskey_idx, i, &sortree, &buf_canon, reason);
++                      dnskey, dnskey_idx, i, &sortree, &buf_canon, reason,
++                      section, qstate);
+               if(sec == sec_status_secure)
+                       return sec;
+               numchecked ++;
+@@ -585,7 +588,8 @@ enum sec_status
+ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, 
+       time_t now, struct ub_packed_rrset_key* rrset, 
+       struct ub_packed_rrset_key* dnskey, size_t sig_idx, 
+-      struct rbtree_t** sortree, char** reason)
++      struct rbtree_t** sortree, char** reason, sldns_pkt_section section,
++      struct module_qstate* qstate)
+ {
+       /* find matching keys and check them */
+       enum sec_status sec = sec_status_bogus;
+@@ -610,7 +614,7 @@ dnskeyset_verify_rrset_sig(struct module
+               /* see if key verifies */
+               sec = dnskey_verify_rrset_sig(env->scratch, 
+                       env->scratch_buffer, ve, now, rrset, dnskey, i, 
+-                      sig_idx, sortree, &buf_canon, reason);
++                      sig_idx, sortree, &buf_canon, reason, section, qstate);
+               if(sec == sec_status_secure)
+                       return sec;
+       }
+@@ -1115,12 +1119,15 @@ int rrset_canonical_equal(struct regiona
+  *    signer name length.
+  * @param sortree: if NULL is passed a new sorted rrset tree is built.
+  *    Otherwise it is reused.
++ * @param section: section of packet where this rrset comes from.
++ * @param qstate: qstate with region.
+  * @return false on alloc error.
+  */
+ static int
+ rrset_canonical(struct regional* region, sldns_buffer* buf, 
+       struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen,
+-      struct rbtree_t** sortree)
++      struct rbtree_t** sortree, sldns_pkt_section section,
++      struct module_qstate* qstate)
+ {
+       struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
+       uint8_t* can_owner = NULL;
+@@ -1169,6 +1176,20 @@ rrset_canonical(struct regional* region,
+               canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]);
+       }
+       sldns_buffer_flip(buf);
++
++      /* Replace RR owner with canonical owner for NSEC records in authority
++       * section, to prevent that a wildcard synthesized NSEC can be used in
++       * the non-existence proves. */
++      if(ntohs(k->rk.type) == LDNS_RR_TYPE_NSEC &&
++              section == LDNS_SECTION_AUTHORITY) {
++              k->rk.dname = regional_alloc_init(qstate->region, can_owner,
++                      can_owner_len);
++              if(!k->rk.dname)
++                      return 0;
++              k->rk.dname_len = can_owner_len;
++      }
++      
++
+       return 1;
+ }
+ 
+@@ -1312,7 +1333,8 @@ dnskey_verify_rrset_sig(struct regional*
+       struct val_env* ve, time_t now,
+         struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
+         size_t dnskey_idx, size_t sig_idx,
+-      struct rbtree_t** sortree, int* buf_canon, char** reason)
++      struct rbtree_t** sortree, int* buf_canon, char** reason,
++      sldns_pkt_section section, struct module_qstate* qstate)
+ {
+       enum sec_status sec;
+       uint8_t* sig;           /* RRSIG rdata */
+@@ -1411,7 +1433,7 @@ dnskey_verify_rrset_sig(struct regional*
+               /* create rrset canonical format in buffer, ready for 
+                * signature */
+               if(!rrset_canonical(region, buf, rrset, sig+2, 
+-                      18 + signer_len, sortree)) {
++                      18 + signer_len, sortree, section, qstate)) {
+                       log_err("verify: failed due to alloc error");
+                       return sec_status_unchecked;
+               }
+--- unbound-1.6.0.orig/validator/val_sigcrypt.h
++++ unbound-1.6.0/validator/val_sigcrypt.h
+@@ -44,8 +44,10 @@
+ #ifndef VALIDATOR_VAL_SIGCRYPT_H
+ #define VALIDATOR_VAL_SIGCRYPT_H
+ #include "util/data/packed_rrset.h"
++#include "sldns/pkthdr.h"
+ struct val_env;
+ struct module_env;
++struct module_qstate;
+ struct ub_packed_rrset_key;
+ struct rbtree_t;
+ struct regional;
+@@ -237,13 +239,16 @@ uint16_t dnskey_get_flags(struct ub_pack
+  * @param sigalg: if nonNULL provide downgrade protection otherwise one
+  *   algorithm is enough.
+  * @param reason: if bogus, a string returned, fixed or alloced in scratch.
++ * @param section: section of packet where this rrset comes from.
++ * @param qstate: qstate with region.
+  * @return SECURE if one key in the set verifies one rrsig.
+  *    UNCHECKED on allocation errors, unsupported algorithms, malformed data,
+  *    and BOGUS on verification failures (no keys match any signatures).
+  */
+ enum sec_status dnskeyset_verify_rrset(struct module_env* env, 
+       struct val_env* ve, struct ub_packed_rrset_key* rrset, 
+-      struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason);
++      struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason,
++      sldns_pkt_section section, struct module_qstate* qstate);
+ 
+ /** 
+  * verify rrset against one specific dnskey (from rrset) 
+@@ -253,12 +258,15 @@ enum sec_status dnskeyset_verify_rrset(s
+  * @param dnskey: DNSKEY rrset, keyset.
+  * @param dnskey_idx: which key from the rrset to try.
+  * @param reason: if bogus, a string returned, fixed or alloced in scratch.
++ * @param section: section of packet where this rrset comes from.
++ * @param qstate: qstate with region.
+  * @return secure if *this* key signs any of the signatures on rrset.
+  *    unchecked on error or and bogus on bad signature.
+  */
+ enum sec_status dnskey_verify_rrset(struct module_env* env, 
+       struct val_env* ve, struct ub_packed_rrset_key* rrset, 
+-      struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason);
++      struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason,
++      sldns_pkt_section section, struct module_qstate* qstate);
+ 
+ /** 
+  * verify rrset, with dnskey rrset, for a specific rrsig in rrset
+@@ -271,13 +279,16 @@ enum sec_status dnskey_verify_rrset(stru
+  * @param sortree: reused sorted order. Stored in region. Pass NULL at start,
+  *    and for a new rrset.
+  * @param reason: if bogus, a string returned, fixed or alloced in scratch.
++ * @param section: section of packet where this rrset comes from.
++ * @param qstate: qstate with region.
+  * @return secure if any key signs *this* signature. bogus if no key signs it,
+  *    or unchecked on error.
+  */
+ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, 
+       struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset, 
+       struct ub_packed_rrset_key* dnskey, size_t sig_idx, 
+-      struct rbtree_t** sortree, char** reason);
++      struct rbtree_t** sortree, char** reason, sldns_pkt_section section,
++      struct module_qstate* qstate);
+ 
+ /** 
+  * verify rrset, with specific dnskey(from set), for a specific rrsig 
+@@ -295,6 +306,8 @@ enum sec_status dnskeyset_verify_rrset_s
+  *    pass false at start. pass old value only for same rrset and same
+  *    signature (but perhaps different key) for reuse.
+  * @param reason: if bogus, a string returned, fixed or alloced in scratch.
++ * @param section: section of packet where this rrset comes from.
++ * @param qstate: qstate with region.
+  * @return secure if this key signs this signature. unchecked on error or 
+  *    bogus if it did not validate.
+  */
+@@ -302,7 +315,8 @@ enum sec_status dnskey_verify_rrset_sig(
+       struct sldns_buffer* buf, struct val_env* ve, time_t now,
+       struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, 
+       size_t dnskey_idx, size_t sig_idx,
+-      struct rbtree_t** sortree, int* buf_canon, char** reason);
++      struct rbtree_t** sortree, int* buf_canon, char** reason,
++      sldns_pkt_section section, struct module_qstate* qstate);
+ 
+ /**
+  * canonical compare for two tree entries
+--- unbound-1.6.0.orig/validator/val_utils.c
++++ unbound-1.6.0/validator/val_utils.c
+@@ -334,7 +334,8 @@ rrset_get_ttl(struct ub_packed_rrset_key
+ enum sec_status 
+ val_verify_rrset(struct module_env* env, struct val_env* ve,
+         struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
+-      uint8_t* sigalg, char** reason)
++      uint8_t* sigalg, char** reason, sldns_pkt_section section,
++      struct module_qstate* qstate)
+ {
+       enum sec_status sec;
+       struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
+@@ -356,7 +357,8 @@ val_verify_rrset(struct module_env* env,
+       }
+       log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
+               ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
+-      sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason);
++      sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason,
++              section, qstate);
+       verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
+       regional_free_all(env->scratch);
+ 
+@@ -389,7 +391,7 @@ val_verify_rrset(struct module_env* env,
+ enum sec_status 
+ val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
+         struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey,
+-      char** reason)
++      char** reason, sldns_pkt_section section, struct module_qstate* qstate)
+ {
+       /* temporary dnskey rrset-key */
+       struct ub_packed_rrset_key dnskey;
+@@ -402,7 +404,8 @@ val_verify_rrset_entry(struct module_env
+       dnskey.rk.dname_len = kkey->namelen;
+       dnskey.entry.key = &dnskey;
+       dnskey.entry.data = kd->rrset_data;
+-      sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason);
++      sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason,
++              section, qstate);
+       return sec;
+ }
+ 
+@@ -410,7 +413,8 @@ val_verify_rrset_entry(struct module_env
+ static enum sec_status
+ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve, 
+       struct ub_packed_rrset_key* dnskey_rrset, 
+-        struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason)
++        struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason,
++      struct module_qstate* qstate)
+ {
+       enum sec_status sec = sec_status_bogus;
+       size_t i, num, numchecked = 0, numhashok = 0;
+@@ -441,7 +445,7 @@ verify_dnskeys_with_ds_rr(struct module_
+               /* Otherwise, we have a match! Make sure that the DNSKEY 
+                * verifies *with this key*  */
+               sec = dnskey_verify_rrset(env, ve, dnskey_rrset, 
+-                      dnskey_rrset, i, reason);
++                      dnskey_rrset, i, reason, LDNS_SECTION_ANSWER, qstate);
+               if(sec == sec_status_secure) {
+                       return sec;
+               }
+@@ -477,7 +481,8 @@ int val_favorite_ds_algo(struct ub_packe
+ enum sec_status 
+ val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
+       struct ub_packed_rrset_key* dnskey_rrset,
+-      struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason)
++      struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
++      struct module_qstate* qstate)
+ {
+       /* as long as this is false, we can consider this DS rrset to be
+        * equivalent to no DS rrset. */
+@@ -514,7 +519,7 @@ val_verify_DNSKEY_with_DS(struct module_
+               has_useful_ds = 1;
+ 
+               sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, 
+-                      ds_rrset, i, reason);
++                      ds_rrset, i, reason, qstate);
+               if(sec == sec_status_secure) {
+                       if(!sigalg || algo_needs_set_secure(&needs,
+                               (uint8_t)ds_get_key_algo(ds_rrset, i))) {
+@@ -547,11 +552,12 @@ val_verify_DNSKEY_with_DS(struct module_
+ struct key_entry_key* 
+ val_verify_new_DNSKEYs(struct regional* region, struct module_env* env, 
+       struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, 
+-      struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason)
++      struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
++      struct module_qstate* qstate)
+ {
+       uint8_t sigalg[ALGO_NEEDS_MAX+1];
+       enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve, 
+-              dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason);
++              dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason, qstate);
+ 
+       if(sec == sec_status_secure) {
+               return key_entry_create_rrset(region, 
+@@ -573,7 +579,8 @@ enum sec_status
+ val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
+       struct ub_packed_rrset_key* dnskey_rrset,
+       struct ub_packed_rrset_key* ta_ds,
+-      struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason)
++      struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
++      struct module_qstate* qstate)
+ {
+       /* as long as this is false, we can consider this anchor to be
+        * equivalent to no anchor. */
+@@ -624,7 +631,7 @@ val_verify_DNSKEY_with_TA(struct module_
+               has_useful_ta = 1;
+ 
+               sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset, 
+-                      ta_ds, i, reason);
++                      ta_ds, i, reason, qstate);
+               if(sec == sec_status_secure) {
+                       if(!sigalg || algo_needs_set_secure(&needs,
+                               (uint8_t)ds_get_key_algo(ta_ds, i))) {
+@@ -650,7 +657,7 @@ val_verify_DNSKEY_with_TA(struct module_
+               has_useful_ta = 1;
+ 
+               sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
+-                      ta_dnskey, i, reason);
++                      ta_dnskey, i, reason, LDNS_SECTION_ANSWER, qstate);
+               if(sec == sec_status_secure) {
+                       if(!sigalg || algo_needs_set_secure(&needs,
+                               (uint8_t)dnskey_get_algo(ta_dnskey, i))) {
+@@ -684,12 +691,12 @@ val_verify_new_DNSKEYs_with_ta(struct re
+       struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, 
+       struct ub_packed_rrset_key* ta_ds_rrset,
+       struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
+-      char** reason)
++      char** reason, struct module_qstate* qstate)
+ {
+       uint8_t sigalg[ALGO_NEEDS_MAX+1];
+       enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, 
+               dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset,
+-              downprot?sigalg:NULL, reason);
++              downprot?sigalg:NULL, reason, qstate);
+ 
+       if(sec == sec_status_secure) {
+               return key_entry_create_rrset(region, 
+--- unbound-1.6.0.orig/validator/val_utils.h
++++ unbound-1.6.0/validator/val_utils.h
+@@ -42,10 +42,12 @@
+ #ifndef VALIDATOR_VAL_UTILS_H
+ #define VALIDATOR_VAL_UTILS_H
+ #include "util/data/packed_rrset.h"
++#include "sldns/pkthdr.h"
+ struct query_info;
+ struct reply_info;
+ struct val_env;
+ struct module_env;
++struct module_qstate;
+ struct ub_packed_rrset_key;
+ struct key_entry_key;
+ struct regional;
+@@ -120,11 +122,14 @@ void val_find_signer(enum val_classifica
+  * @param sigalg: if nonNULL provide downgrade protection otherwise one
+  *   algorithm is enough.  Algo list is constructed in here.
+  * @param reason: reason of failure. Fixed string or alloced in scratch.
++ * @param section: section of packet where this rrset comes from.
++ * @param qstate: qstate with region.
+  * @return security status of verification.
+  */
+ enum sec_status val_verify_rrset(struct module_env* env, struct val_env* ve,
+       struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
+-      uint8_t* sigalg, char** reason);
++      uint8_t* sigalg, char** reason, sldns_pkt_section section,
++      struct module_qstate* qstate);
+ 
+ /**
+  * Verify RRset with keys from a keyset.
+@@ -133,11 +138,14 @@ enum sec_status val_verify_rrset(struct
+  * @param rrset: what to verify
+  * @param kkey: key_entry to verify with.
+  * @param reason: reason of failure. Fixed string or alloced in scratch.
++ * @param section: section of packet where this rrset comes from.
++ * @param qstate: qstate with region.
+  * @return security status of verification.
+  */
+ enum sec_status val_verify_rrset_entry(struct module_env* env, 
+       struct val_env* ve, struct ub_packed_rrset_key* rrset, 
+-      struct key_entry_key* kkey, char** reason);
++      struct key_entry_key* kkey, char** reason, sldns_pkt_section section,
++      struct module_qstate* qstate);
+ 
+ /**
+  * Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
+@@ -150,13 +158,15 @@ enum sec_status val_verify_rrset_entry(s
+  *   algorithm is enough.  The list of signalled algorithms is returned,
+  *   must have enough space for ALGO_NEEDS_MAX+1.
+  * @param reason: reason of failure. Fixed string or alloced in scratch.
++ * @param qstate: qstate with region.
+  * @return: sec_status_secure if a DS matches.
+  *     sec_status_insecure if end of trust (i.e., unknown algorithms).
+  *     sec_status_bogus if it fails.
+  */
+ enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env, 
+       struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, 
+-      struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason);
++      struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
++      struct module_qstate* qstate);
+ 
+ /**
+  * Verify DNSKEYs with DS and DNSKEY rrset.  Like val_verify_DNSKEY_with_DS
+@@ -170,6 +180,7 @@ enum sec_status val_verify_DNSKEY_with_D
+  *   algorithm is enough.  The list of signalled algorithms is returned,
+  *   must have enough space for ALGO_NEEDS_MAX+1.
+  * @param reason: reason of failure. Fixed string or alloced in scratch.
++ * @param qstate: qstate with region.
+  * @return: sec_status_secure if a DS matches.
+  *     sec_status_insecure if end of trust (i.e., unknown algorithms).
+  *     sec_status_bogus if it fails.
+@@ -177,7 +188,8 @@ enum sec_status val_verify_DNSKEY_with_D
+ enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env, 
+       struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset, 
+       struct ub_packed_rrset_key* ta_ds,
+-      struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason);
++      struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
++      struct module_qstate* qstate);
+ 
+ /**
+  * Verify new DNSKEYs with DS rrset. The DS contains hash values that should
+@@ -192,6 +204,7 @@ enum sec_status val_verify_DNSKEY_with_T
+  * @param downprot: if true provide downgrade protection otherwise one
+  *   algorithm is enough.
+  * @param reason: reason of failure. Fixed string or alloced in scratch.
++ * @param qstate: qstate with region.
+  * @return a KeyEntry. This will either contain the now trusted
+  *         dnskey_rrset, a "null" key entry indicating that this DS
+  *         rrset/DNSKEY pair indicate an secure end to the island of trust
+@@ -205,7 +218,8 @@ enum sec_status val_verify_DNSKEY_with_T
+ struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region, 
+       struct module_env* env, struct val_env* ve, 
+       struct ub_packed_rrset_key* dnskey_rrset, 
+-      struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason);
++      struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
++      struct module_qstate* qstate);
+ 
+ 
+ /**
+@@ -220,6 +234,7 @@ struct key_entry_key* val_verify_new_DNS
+  * @param downprot: if true provide downgrade protection otherwise one
+  *   algorithm is enough.
+  * @param reason: reason of failure. Fixed string or alloced in scratch.
++ * @param qstate: qstate with region.
+  * @return a KeyEntry. This will either contain the now trusted
+  *         dnskey_rrset, a "null" key entry indicating that this DS
+  *         rrset/DNSKEY pair indicate an secure end to the island of trust
+@@ -235,7 +250,7 @@ struct key_entry_key* val_verify_new_DNS
+       struct ub_packed_rrset_key* dnskey_rrset, 
+       struct ub_packed_rrset_key* ta_ds_rrset, 
+       struct ub_packed_rrset_key* ta_dnskey_rrset,
+-      int downprot, char** reason);
++      int downprot, char** reason, struct module_qstate* qstate);
+ 
+ /**
+  * Determine if DS rrset is usable for validator or not.
+@@ -252,7 +267,7 @@ int val_dsset_isusable(struct ub_packed_
+  * the result of a wildcard expansion. If so, return the name of the
+  * generating wildcard.
+  * 
+- * @param rrset The rrset to chedck.
++ * @param rrset The rrset to check.
+  * @param wc: the wildcard name, if the rrset was synthesized from a wildcard.
+  *         unchanged if not.  The wildcard name, without "*." in front, is 
+  *         returned. This is a pointer into the rrset owner name.
+--- unbound-1.6.0.orig/validator/validator.c
++++ unbound-1.6.0/validator/validator.c
+@@ -490,7 +490,8 @@ validate_msg_signatures(struct module_qs
+               }
+ 
+               /* Verify the answer rrset */
+-              sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason);
++              sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
++                      LDNS_SECTION_ANSWER, qstate);
+               /* If the (answer) rrset failed to validate, then this 
+                * message is BAD. */
+               if(sec != sec_status_secure) {
+@@ -519,7 +520,8 @@ validate_msg_signatures(struct module_qs
+       for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
+               chase_reply->ns_numrrsets; i++) {
+               s = chase_reply->rrsets[i];
+-              sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason);
++              sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
++                      LDNS_SECTION_AUTHORITY, qstate);
+               /* If anything in the authority section fails to be secure, 
+                * we have a bad message. */
+               if(sec != sec_status_secure) {
+@@ -545,7 +547,7 @@ validate_msg_signatures(struct module_qs
+               val_find_rrset_signer(s, &sname, &slen);
+               if(sname && query_dname_compare(sname, key_entry->name)==0)
+                       (void)val_verify_rrset_entry(env, ve, s, key_entry,
+-                              &reason);
++                              &reason, LDNS_SECTION_ADDITIONAL, qstate);
+               /* the additional section can fail to be secure, 
+                * it is optional, check signature in case we need
+                * to clean the additional section later. */
+@@ -2389,7 +2391,7 @@ primeResponseToKE(struct ub_packed_rrset
+       /* attempt to verify with trust anchor DS and DNSKEY */
+       kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve, 
+               dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot,
+-              &reason);
++              &reason, qstate);
+       if(!kkey) {
+               log_err("out of memory: verifying prime TA");
+               return NULL;
+@@ -2479,7 +2481,7 @@ ds_response_to_ke(struct module_qstate*
+               /* Verify only returns BOGUS or SECURE. If the rrset is 
+                * bogus, then we are done. */
+               sec = val_verify_rrset_entry(qstate->env, ve, ds, 
+-                      vq->key_entry, &reason);
++                      vq->key_entry, &reason, LDNS_SECTION_ANSWER, qstate);
+               if(sec != sec_status_secure) {
+                       verbose(VERB_DETAIL, "DS rrset in DS response did "
+                               "not verify");
+@@ -2526,7 +2528,7 @@ ds_response_to_ke(struct module_qstate*
+               /* Try to prove absence of the DS with NSEC */
+               sec = val_nsec_prove_nodata_dsreply(
+                       qstate->env, ve, qinfo, msg->rep, vq->key_entry, 
+-                      &proof_ttl, &reason);
++                      &proof_ttl, &reason, qstate);
+               switch(sec) {
+                       case sec_status_secure:
+                               verbose(VERB_DETAIL, "NSEC RRset for the "
+@@ -2554,7 +2556,8 @@ ds_response_to_ke(struct module_qstate*
+ 
+               sec = nsec3_prove_nods(qstate->env, ve, 
+                       msg->rep->rrsets + msg->rep->an_numrrsets,
+-                      msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason);
++                      msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason,
++                      qstate);
+               switch(sec) {
+                       case sec_status_insecure:
+                               /* case insecure also continues to unsigned
+@@ -2615,7 +2618,7 @@ ds_response_to_ke(struct module_qstate*
+                       goto return_bogus;
+               }
+               sec = val_verify_rrset_entry(qstate->env, ve, cname, 
+-                      vq->key_entry, &reason);
++                      vq->key_entry, &reason, LDNS_SECTION_ANSWER, qstate);
+               if(sec == sec_status_secure) {
+                       verbose(VERB_ALGO, "CNAME validated, "
+                               "proof that DS does not exist");
+@@ -2781,7 +2784,7 @@ process_dnskey_response(struct module_qs
+       }
+       downprot = qstate->env->cfg->harden_algo_downgrade;
+       vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env,
+-              ve, dnskey, vq->ds_rrset, downprot, &reason);
++              ve, dnskey, vq->ds_rrset, downprot, &reason, qstate);
+ 
+       if(!vq->key_entry) {
+               log_err("out of memory in verify new DNSKEYs");
+@@ -2856,7 +2859,8 @@ process_prime_response(struct module_qst
+                       ta->dclass);
+       }
+       if(ta->autr) {
+-              if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset)) {
++              if(!autr_process_prime(qstate->env, ve, ta, dnskey_rrset,
++                      qstate)) {
+                       /* trust anchor revoked, restart with less anchors */
+                       vq->state = VAL_INIT_STATE;
+                       vq->trust_anchor_name = NULL;

Attachment: signature.asc
Description: PGP signature

Reply via email to