untrusted comment: signature from openbsd 6.2 base secret key
RWRVWzAMgtyg7oA/zs/knuwVMt+8a7xAxWISqaCDdQT2ZiRVZRWYh7agLXPYBrRzHjvIjIafPj4u2Yf+dkJ94NFKa6i3X1oKxgk=

OpenBSD 6.2 errata 008, Feburary 8th, 2018:

A flaw was found in the way unbound validated wildcard-synthesized
NSEC records. An improperly validated wildcard NSEC record could be
used to prove the non-existence (NXDOMAIN answer) of an existing
wildcard record, or trick unbound into accepting a NODATA proof.
For details see https://unbound.net/downloads/CVE-2017-15105.txt.

Apply by doing:
   signify -Vep /etc/signify/openbsd-62-base.pub -x 008_unbound.patch.sig \
       -m - | (cd /usr/src && patch -p0)

And then rebuild and install unbound:
   cd /usr/src/usr.sbin/unbound
   make -f Makefile.bsd-wrapper obj
   make -f Makefile.bsd-wrapper
   make -f Makefile.bsd-wrapper install

Index: usr.sbin/unbound/validator/autotrust.c
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/autotrust.c,v
retrieving revision 1.7
diff -u -p -r1.7 autotrust.c
--- usr.sbin/unbound/validator/autotrust.c      23 Aug 2017 11:23:33 -0000      1.7
+++ usr.sbin/unbound/validator/autotrust.c      6 Feb 2018 00:41:14 -0000
@@ -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) */
@@ -2118,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);
@@ -2159,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)) {
@@ -2175,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 */
Index: usr.sbin/unbound/validator/autotrust.h
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/autotrust.h,v
retrieving revision 1.2
diff -u -p -r1.2 autotrust.h
--- usr.sbin/unbound/validator/autotrust.h      17 Feb 2017 18:53:32 -0000      1.2
+++ usr.sbin/unbound/validator/autotrust.h      6 Feb 2018 00:41:14 -0000
@@ -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
Index: usr.sbin/unbound/validator/val_nsec.c
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/val_nsec.c,v
retrieving revision 1.4
diff -u -p -r1.4 val_nsec.c
--- usr.sbin/unbound/validator/val_nsec.c       17 Feb 2017 18:53:32 -0000      1.4
+++ usr.sbin/unbound/validator/val_nsec.c       6 Feb 2018 00:41:14 -0000
@@ -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;
Index: usr.sbin/unbound/validator/val_nsec.h
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/val_nsec.h,v
retrieving revision 1.2
diff -u -p -r1.2 val_nsec.h
--- usr.sbin/unbound/validator/val_nsec.h       9 Dec 2015 00:59:02 -0000       1.2
+++ usr.sbin/unbound/validator/val_nsec.h       6 Feb 2018 00:41:14 -0000
@@ -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.
Index: usr.sbin/unbound/validator/val_nsec3.c
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/val_nsec3.c,v
retrieving revision 1.4
diff -u -p -r1.4 val_nsec3.c
--- usr.sbin/unbound/validator/val_nsec3.c      17 Feb 2017 18:53:32 -0000      1.4
+++ usr.sbin/unbound/validator/val_nsec3.c      6 Feb 2018 00:41:14 -0000
@@ -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_type 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 */
Index: usr.sbin/unbound/validator/val_nsec3.h
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/val_nsec3.h,v
retrieving revision 1.3
diff -u -p -r1.3 val_nsec3.h
--- usr.sbin/unbound/validator/val_nsec3.h      17 Feb 2017 18:53:32 -0000      1.3
+++ usr.sbin/unbound/validator/val_nsec3.h      6 Feb 2018 00:41:14 -0000
@@ -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.
Index: usr.sbin/unbound/validator/val_sigcrypt.c
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/val_sigcrypt.c,v
retrieving revision 1.5
diff -u -p -r1.5 val_sigcrypt.c
--- usr.sbin/unbound/validator/val_sigcrypt.c   12 Aug 2017 11:22:46 -0000      1.5
+++ usr.sbin/unbound/validator/val_sigcrypt.c   6 Feb 2018 00:41:14 -0000
@@ -485,7 +485,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;
@@ -512,7 +513,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)
@@ -553,7 +554,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;
@@ -577,7 +579,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 ++;
@@ -591,7 +594,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_type** sortree, char** reason)
+       struct rbtree_type** sortree, char** reason, sldns_pkt_section section,
+       struct module_qstate* qstate)
{
       /* find matching keys and check them */
       enum sec_status sec = sec_status_bogus;
@@ -616,7 +620,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;
       }
@@ -1121,12 +1125,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_type** sortree)
+       struct rbtree_type** 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;
@@ -1175,6 +1182,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;
}

@@ -1318,7 +1339,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_type** sortree, int* buf_canon, char** reason)
+       struct rbtree_type** sortree, int* buf_canon, char** reason,
+       sldns_pkt_section section, struct module_qstate* qstate)
{
       enum sec_status sec;
       uint8_t* sig;           /* RRSIG rdata */
@@ -1417,7 +1439,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;
               }
Index: usr.sbin/unbound/validator/val_sigcrypt.h
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/val_sigcrypt.h,v
retrieving revision 1.2
diff -u -p -r1.2 val_sigcrypt.h
--- usr.sbin/unbound/validator/val_sigcrypt.h   17 Feb 2017 18:53:32 -0000      1.2
+++ usr.sbin/unbound/validator/val_sigcrypt.h   6 Feb 2018 00:41:14 -0000
@@ -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_type;
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_type** sortree, char** reason);
+       struct rbtree_type** 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_type** sortree, int* buf_canon, char** reason);
+       struct rbtree_type** sortree, int* buf_canon, char** reason,
+       sldns_pkt_section section, struct module_qstate* qstate);

/**
 * canonical compare for two tree entries
Index: usr.sbin/unbound/validator/val_utils.c
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/val_utils.c,v
retrieving revision 1.6
diff -u -p -r1.6 val_utils.c
--- usr.sbin/unbound/validator/val_utils.c      29 Sep 2017 16:27:14 -0000      1.6
+++ usr.sbin/unbound/validator/val_utils.c      6 Feb 2018 00:41:14 -0000
@@ -335,7 +335,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->
@@ -357,7 +358,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);

@@ -390,7 +392,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;
@@ -403,7 +405,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;
}

@@ -411,7 +414,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;
@@ -442,7 +446,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;
               }
@@ -478,7 +482,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. */
@@ -520,7 +525,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))) {
@@ -553,11 +558,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,
@@ -579,7 +585,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. */
@@ -630,7 +637,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))) {
@@ -656,7 +663,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))) {
@@ -690,12 +697,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,
Index: usr.sbin/unbound/validator/val_utils.h
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/val_utils.h,v
retrieving revision 1.4
diff -u -p -r1.4 val_utils.h
--- usr.sbin/unbound/validator/val_utils.h      12 Aug 2017 11:22:46 -0000      1.4
+++ usr.sbin/unbound/validator/val_utils.h      6 Feb 2018 00:41:14 -0000
@@ -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.
Index: usr.sbin/unbound/validator/validator.c
===================================================================
RCS file: /cvs/src/usr.sbin/unbound/validator/validator.c,v
retrieving revision 1.8
diff -u -p -r1.8 validator.c
--- usr.sbin/unbound/validator/validator.c      12 Aug 2017 11:22:46 -0000      1.8
+++ usr.sbin/unbound/validator/validator.c      6 Feb 2018 00:41:14 -0000
@@ -572,7 +572,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) {
@@ -601,7 +602,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) {
@@ -629,7 +631,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. */
@@ -2484,7 +2486,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;
@@ -2574,7 +2576,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");
@@ -2621,7 +2623,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 "
@@ -2649,7 +2651,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
@@ -2710,7 +2713,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");
@@ -2876,7 +2879,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");
@@ -2952,7 +2955,8 @@ process_prime_response(struct module_qst
       }

       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;