Description: <short summary of the patch>
 TODO: Put a short summary on the line above and replace this paragraph
 with a longer explanation of this change. Complete the meta-information
 with other relevant fields (see below for details). To make it easier, the
 information below has been extracted from the changelog. Adjust it or drop
 it.
 .
 unbound (1.4.17-3+deb7u2) wheezy-security; urgency=medium
 .
    * Fix CVE-2014-8602: denial of service by making resolver chase endless
      series of delegations; closes: #772622.
Author: Robert Edmonds <edmonds@debian.org>
Bug-Debian: http://bugs.debian.org/772622

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: http://bugs.debian.org/<bugnumber>
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: <YYYY-MM-DD>

--- unbound-1.4.17.orig/acx_python.m4
+++ unbound-1.4.17/acx_python.m4
@@ -164,8 +164,11 @@ $ac_distutils_result])
         AC_MSG_CHECKING([consistency of all components of python development environment])
         AC_LANG_PUSH([C])
         # save current global flags
-        LIBS="$ac_save_LIBS $PYTHON_LDFLAGS"
-        CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
+        ac_save_LIBS="$LIBS"
+        ac_save_CPPFLAGS="$CPPFLAGS"
+
+        LIBS="$LIBS $PYTHON_LDFLAGS"
+        CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS"
         AC_TRY_LINK([
                 #include <Python.h>
         ],[
--- unbound-1.4.17.orig/configure.ac
+++ unbound-1.4.17/configure.ac
@@ -232,7 +232,11 @@ case "$debug_enabled" in
 		# nothing to do.
 		;;
 esac
-ACX_CHECK_FLTO
+case "`dpkg-architecture -qDEB_BUILD_ARCH 2>/dev/null`" in
+    amd64|i386)
+    ACX_CHECK_FLTO
+    ;;
+esac
 
 AC_C_INLINE
 ACX_CHECK_FORMAT_ATTRIBUTE
--- unbound-1.4.17.orig/daemon/daemon.c
+++ unbound-1.4.17/daemon/daemon.c
@@ -203,6 +203,10 @@ daemon_init(void)
 	comp_meth = (void*)SSL_COMP_get_compression_methods();
 #endif
 	(void)SSL_library_init();
+#  if defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
+	if(!ub_openssl_lock_init())
+		fatal_exit("could not init openssl locks");
+#  endif
 #ifdef HAVE_TZSET
 	/* init timezone info while we are not chrooted yet */
 	tzset();
@@ -555,6 +559,9 @@ daemon_delete(struct daemon* daemon)
 	ERR_remove_state(0);
 	ERR_free_strings();
 	RAND_cleanup();
+#  if defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
+	ub_openssl_lock_delete();
+#  endif
 	checklock_stop();
 #ifdef USE_WINSOCK
 	if(WSACleanup() != 0) {
--- unbound-1.4.17.orig/daemon/unbound.c
+++ unbound-1.4.17/daemon/unbound.c
@@ -266,8 +266,6 @@ checkrlimits(struct config_file* cfg)
 				"ports in config to remove this warning");
 			return;
 		}
-		log_warn("increased limit(open files) from %u to %u",
-			(unsigned)avail, (unsigned)total+10);
 	}
 #else	
 	(void)cfg;
--- unbound-1.4.17.orig/doc/unbound.conf.5.in
+++ unbound-1.4.17/doc/unbound.conf.5.in
@@ -916,7 +916,7 @@ section for options.  To setup the corre
 \fIunbound\-control\-setup\fR(8) utility.
 .TP 5
 .B control\-enable:     \fI<yes or no>
-The option is used to enable remote control, default is "no".
+The option is used to enable remote control, default is "yes".
 If turned off, the server does not listen for control commands.
 .TP 5
 .B control\-interface: <ip address>
--- unbound-1.4.17.orig/iterator/iter_hints.c
+++ unbound-1.4.17/iterator/iter_hints.c
@@ -129,7 +129,7 @@ compile_time_root_prime(int do_ip4, int
 	if(!ah(dp, "A.ROOT-SERVERS.NET.", "198.41.0.4"))	return 0;
 	if(!ah(dp, "B.ROOT-SERVERS.NET.", "192.228.79.201")) return 0;
 	if(!ah(dp, "C.ROOT-SERVERS.NET.", "192.33.4.12"))	return 0;
-	if(!ah(dp, "D.ROOT-SERVERS.NET.", "128.8.10.90"))	return 0;
+	if(!ah(dp, "D.ROOT-SERVERS.NET.", "199.7.91.13"))	return 0;
 	if(!ah(dp, "E.ROOT-SERVERS.NET.", "192.203.230.10")) return 0;
 	if(!ah(dp, "F.ROOT-SERVERS.NET.", "192.5.5.241"))	return 0;
 	if(!ah(dp, "G.ROOT-SERVERS.NET.", "192.112.36.4"))	return 0;
--- unbound-1.4.17.orig/iterator/iterator.c
+++ unbound-1.4.17/iterator/iterator.c
@@ -117,6 +117,7 @@ iter_new(struct module_qstate* qstate, i
 	iq->query_restart_count = 0;
 	iq->referral_count = 0;
 	iq->sent_count = 0;
+	iq->target_count = NULL;
 	iq->wait_priming_stub = 0;
 	iq->refetch_glue = 0;
 	iq->dnssec_expected = 0;
@@ -444,6 +445,26 @@ handle_cname_response(struct module_qsta
 	return 1;
 }
 
+/** create target count structure for this query */
+static void
+target_count_create(struct iter_qstate* iq)
+{
+	if(!iq->target_count) {
+		iq->target_count = (int*)calloc(2, sizeof(int));
+		/* if calloc fails we simply do not track this number */
+		if(iq->target_count)
+			iq->target_count[0] = 1;
+	}
+}
+
+static void
+target_count_increase(struct iter_qstate* iq, int num)
+{
+	target_count_create(iq);
+	if(iq->target_count)
+		iq->target_count[1] += num;
+}
+
 /**
  * Generate a subrequest.
  * Generate a local request event. Local events are tied to this module, and
@@ -515,6 +536,10 @@ generate_sub_request(uint8_t* qname, siz
 		subiq = (struct iter_qstate*)subq->minfo[id];
 		memset(subiq, 0, sizeof(*subiq));
 		subiq->num_target_queries = 0;
+		target_count_create(iq);
+		subiq->target_count = iq->target_count;
+		if(iq->target_count)
+			iq->target_count[0] ++; /* extra reference */
 		subiq->num_current_queries = 0;
 		subiq->depth = iq->depth+1;
 		outbound_list_init(&subiq->outlist);
@@ -1341,6 +1366,12 @@ query_for_targets(struct module_qstate*
 
 	if(iq->depth == ie->max_dependency_depth)
 		return 0;
+	if(iq->depth > 0 && iq->target_count &&
+		iq->target_count[1] > MAX_TARGET_COUNT) {
+		verbose(VERB_QUERY, "request has exceeded the maximum "
+			"number of glue fetches %d", iq->target_count[1]);
+		return 0;
+	}
 
 	iter_mark_cycle_targets(qstate, iq->dp);
 	missing = (int)delegpt_count_missing_targets(iq->dp);
@@ -1470,6 +1501,7 @@ processLastResort(struct module_qstate*
 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
 		}
 		iq->num_target_queries += qs;
+		target_count_increase(iq, qs);
 		if(qs != 0) {
 			qstate->ext_state[id] = module_wait_subquery;
 			return 0; /* and wait for them */
@@ -1479,6 +1511,12 @@ processLastResort(struct module_qstate*
 		verbose(VERB_QUERY, "maxdepth and need more nameservers, fail");
 		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
 	}
+	if(iq->depth > 0 && iq->target_count &&
+		iq->target_count[1] > MAX_TARGET_COUNT) {
+		verbose(VERB_QUERY, "request has exceeded the maximum "
+			"number of glue fetches %d", iq->target_count[1]);
+		return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
+	}
 	/* mark cycle targets for parent-side lookups */
 	iter_mark_pside_cycle_targets(qstate, iq->dp);
 	/* see if we can issue queries to get nameserver addresses */
@@ -1508,6 +1546,7 @@ processLastResort(struct module_qstate*
 		if(query_count != 0) { /* suspend to await results */
 			verbose(VERB_ALGO, "try parent-side glue lookup");
 			iq->num_target_queries += query_count;
+			target_count_increase(iq, query_count);
 			qstate->ext_state[id] = module_wait_subquery;
 			return 0;
 		}
@@ -1664,6 +1703,7 @@ processQueryTargets(struct module_qstate
 			return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
 		}
 		iq->num_target_queries += extra;
+		target_count_increase(iq, extra);
 		if(iq->num_target_queries > 0) {
 			/* wait to get all targets, we want to try em */
 			verbose(VERB_ALGO, "wait for all targets for fallback");
@@ -1704,6 +1744,7 @@ processQueryTargets(struct module_qstate
 		/* errors ignored, these targets are not strictly necessary for
 		 * this result, we do not have to reply with SERVFAIL */
 		iq->num_target_queries += extra;
+		target_count_increase(iq, extra);
 	}
 
 	/* Add the current set of unused targets to our queue. */
@@ -1749,6 +1790,7 @@ processQueryTargets(struct module_qstate
 					return 1;
 				}
 				iq->num_target_queries += qs;
+				target_count_increase(iq, qs);
 			}
 			/* Since a target query might have been made, we 
 			 * need to check again. */
@@ -2822,6 +2864,8 @@ iter_clear(struct module_qstate* qstate,
 	iq = (struct iter_qstate*)qstate->minfo[id];
 	if(iq) {
 		outbound_list_clear(&iq->outlist);
+		if(iq->target_count && --iq->target_count[0] == 0)
+			free(iq->target_count);
 		iq->num_current_queries = 0;
 	}
 	qstate->minfo[id] = NULL;
--- unbound-1.4.17.orig/iterator/iterator.h
+++ unbound-1.4.17/iterator/iterator.h
@@ -52,6 +52,8 @@ struct iter_donotq;
 struct iter_prep_list;
 struct iter_priv;
 
+/** max number of targets spawned for a query and its subqueries */
+#define MAX_TARGET_COUNT	32
 /** max number of query restarts. Determines max number of CNAME chain. */
 #define MAX_RESTART_COUNT       8
 /** max number of referrals. Makes sure resolver does not run away */
@@ -254,6 +256,10 @@ struct iter_qstate {
 
 	/** number of queries fired off */
 	int sent_count;
+	
+	/** number of target queries spawned in [1], for this query and its
+	 * subqueries, the malloced-array is shared, [0] refcount. */
+	int* target_count;
 
 	/**
 	 * The query must store NS records from referrals as parentside RRs
--- unbound-1.4.17.orig/smallapp/unbound-control-setup.sh
+++ unbound-1.4.17/smallapp/unbound-control-setup.sh
@@ -157,6 +157,6 @@ chmod o-rw $SVR_BASE.pem $SVR_BASE.key $
 rm -f request.cfg
 rm -f $CTL_BASE"_trust.pem" $SVR_BASE"_trust.pem" $SVR_BASE"_trust.srl"
 
-echo "Setup success. Certificates created. Enable in unbound.conf file to use"
+echo "Setup success. Certificates created."
 
 exit 0
--- unbound-1.4.17.orig/util/config_file.c
+++ unbound-1.4.17/util/config_file.c
@@ -133,7 +133,7 @@ config_create(void)
 	init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
 	if(!(cfg->username = strdup(UB_USERNAME))) goto error_exit;
 #ifdef HAVE_CHROOT
-	if(!(cfg->chrootdir = strdup(CHROOT_DIR))) goto error_exit;
+	if(!(cfg->chrootdir = strdup(""))) goto error_exit;
 #endif
 	if(!(cfg->directory = strdup(RUN_DIR))) goto error_exit;
 	if(!(cfg->logfile = strdup(""))) goto error_exit;
@@ -192,7 +192,7 @@ config_create(void)
 	cfg->local_zones_nodefault = NULL;
 	cfg->local_data = NULL;
 	cfg->python_script = NULL;
-	cfg->remote_control_enable = 0;
+	cfg->remote_control_enable = 1;
 	cfg->control_ifs = NULL;
 	cfg->control_port = UNBOUND_CONTROL_PORT;
 	cfg->minimal_responses = 0;
--- unbound-1.4.17.orig/util/net_help.c
+++ unbound-1.4.17/util/net_help.c
@@ -697,3 +697,54 @@ void* outgoing_ssl_fd(void* sslctx, int
 	}
 	return ssl;
 }
+
+/** global lock list for openssl locks */
+static lock_basic_t *ub_openssl_locks = NULL;
+
+/** callback that gets thread id for openssl */
+static unsigned long
+ub_crypto_id_cb(void)
+{
+	return (unsigned long)ub_thread_self();
+}
+
+static void
+ub_crypto_lock_cb(int mode, int type, const char *ATTR_UNUSED(file),
+	int ATTR_UNUSED(line))
+{
+	if((mode&CRYPTO_LOCK)) {
+		lock_basic_lock(&ub_openssl_locks[type]);
+	} else {
+		lock_basic_unlock(&ub_openssl_locks[type]);
+	}
+}
+
+int ub_openssl_lock_init(void)
+{
+#ifdef OPENSSL_THREADS
+	size_t i;
+	ub_openssl_locks = (lock_basic_t*)malloc(
+		sizeof(lock_basic_t)*CRYPTO_num_locks());
+	if(!ub_openssl_locks)
+		return 0;
+	for(i=0; i<CRYPTO_num_locks(); i++) {
+		lock_basic_init(&ub_openssl_locks[i]);
+	}
+	CRYPTO_set_id_callback(&ub_crypto_id_cb);
+	CRYPTO_set_locking_callback(&ub_crypto_lock_cb);
+#endif /* OPENSSL_THREADS */
+	return 1;
+}
+
+void ub_openssl_lock_delete(void)
+{
+#ifdef OPENSSL_THREADS
+	size_t i;
+	if(!ub_openssl_locks)
+		return;
+	for(i=0; i<CRYPTO_num_locks(); i++) {
+		lock_basic_destroy(&ub_openssl_locks[i]);
+	}
+#endif /* OPENSSL_THREADS */
+}
+
--- unbound-1.4.17.orig/util/net_help.h
+++ unbound-1.4.17/util/net_help.h
@@ -369,4 +369,15 @@ void* incoming_ssl_fd(void* sslctx, int
  */
 void* outgoing_ssl_fd(void* sslctx, int fd);
 
+/**
+ * Initialize openssl locking for thread safety
+ * @return false on failure (alloc failure).
+ */
+int ub_openssl_lock_init(void);
+
+/**
+ * De-init the allocated openssl locks
+ */
+void ub_openssl_lock_delete(void);
+
 #endif /* NET_HELP_H */
--- unbound-1.4.17.orig/testcode/unitverify.c
+++ unbound-1.4.17/testcode/unitverify.c
@@ -190,7 +190,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:"");
--- unbound-1.4.17.orig/validator/autotrust.c
+++ unbound-1.4.17/validator/autotrust.c
@@ -1010,17 +1010,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 = 1;
 	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
@@ -1053,7 +1056,8 @@ min_expiry(struct module_env* env, ldns_
 /** 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;
@@ -1062,7 +1066,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);
 }
 
@@ -1300,7 +1304,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)
 {
 	ldns_rr_list* r = packed_rrset_to_rr_list(dnskey_rrset, 
 		env->scratch_buffer);
@@ -1322,7 +1326,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. */
 			log_assert(dnskey_calc_keytag(dnskey_rrset, i) ==
 				ldns_calc_keytag(rr)); /* checks conversion*/
@@ -1363,6 +1367,7 @@ key_matches_a_ds(struct module_env* env,
 			verbose(VERB_ALGO, "DS match attempt failed");
 			continue;
 		}
+		/*no need to check RRSIG, DS hash already matched with source
 		if(dnskey_verify_rrset(env, ve, dnskey_rrset, 
 			dnskey_rrset, key_idx, &reason) == sec_status_secure) {
 			return 1;
@@ -1370,6 +1375,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);
 		}
+		*/
 	}
 	return 0;
 }
@@ -1895,7 +1901,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);
@@ -1936,7 +1943,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)) {
@@ -1952,7 +1959,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 succesful probe */
--- unbound-1.4.17.orig/validator/autotrust.h
+++ unbound-1.4.17/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;
 
 /** Autotrust anchor states */
@@ -185,12 +186,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.4.17.orig/validator/val_nsec.c
+++ unbound-1.4.17/validator/val_nsec.c
@@ -177,7 +177,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;
@@ -186,7 +186,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;
@@ -197,7 +198,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, uint32_t* proof_ttl, char** reason)
+	struct key_entry_key* kkey, uint32_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, 
@@ -214,7 +216,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;
@@ -243,7 +245,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.4.17.orig/validator/val_nsec.h
+++ unbound-1.4.17/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,
-	uint32_t* proof_ttl, char** reason);
+	uint32_t* proof_ttl, char** reason, struct module_qstate* qstate);
 
 /** 
  * nsec typemap check, takes an NSEC-type bitmap as argument, checks for type.
--- unbound-1.4.17.orig/validator/val_nsec3.c
+++ unbound-1.4.17/validator/val_nsec3.c
@@ -1297,7 +1297,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;
@@ -1311,7 +1311,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;
@@ -1324,7 +1324,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;
@@ -1337,7 +1338,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.4.17.orig/validator/val_nsec3.h
+++ unbound-1.4.17/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;
@@ -184,6 +185,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.
@@ -193,7 +195,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.4.17.orig/validator/val_sigcrypt.c
+++ unbound-1.4.17/validator/val_sigcrypt.c
@@ -566,7 +566,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, ldns_pkt_section section, 
+	struct module_qstate* qstate)
 {
 	enum sec_status sec;
 	size_t i, num;
@@ -593,7 +594,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)
@@ -630,7 +631,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, ldns_pkt_section section,
+	struct module_qstate* qstate)
 {
 	enum sec_status sec;
 	size_t i, num, numchecked = 0;
@@ -654,7 +656,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 ++;
@@ -668,7 +671,8 @@ enum sec_status
 dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, 
 	uint32_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, ldns_pkt_section section,
+	struct module_qstate* qstate)
 {
 	/* find matching keys and check them */
 	enum sec_status sec = sec_status_bogus;
@@ -693,7 +697,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;
 	}
@@ -1132,12 +1136,15 @@ canonicalize_rdata(ldns_buffer* buf, str
  * 	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, ldns_buffer* buf, 
 	struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen,
-	struct rbtree_t** sortree)
+	struct rbtree_t** sortree, ldns_pkt_section section,
+	struct module_qstate* qstate)
 {
 	struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
 	uint8_t* can_owner = NULL;
@@ -1184,6 +1191,19 @@ rrset_canonical(struct regional* region,
 		canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]);
 	}
 	ldns_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;
 }
 
@@ -1691,7 +1711,8 @@ dnskey_verify_rrset_sig(struct regional*
 	struct val_env* ve, uint32_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,
+	ldns_pkt_section section, struct module_qstate* qstate)
 {
 	enum sec_status sec;
 	uint8_t* sig;		/* RRSIG rdata */
@@ -1790,7 +1811,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.4.17.orig/validator/val_sigcrypt.h
+++ unbound-1.4.17/validator/val_sigcrypt.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 rbtree_t;
 struct regional;
@@ -236,13 +237,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,
+	ldns_pkt_section section, struct module_qstate* qstate);
 
 /** 
  * verify rrset against one specific dnskey (from rrset) 
@@ -252,12 +256,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,
+	ldns_pkt_section section, struct module_qstate* qstate);
 
 /** 
  * verify rrset, with dnskey rrset, for a specific rrsig in rrset
@@ -270,13 +277,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, uint32_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, ldns_pkt_section section,
+	struct module_qstate* qstate);
 
 /** 
  * verify rrset, with specific dnskey(from set), for a specific rrsig 
@@ -294,6 +304,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.
  */
@@ -301,7 +313,8 @@ enum sec_status dnskey_verify_rrset_sig(
 	ldns_buffer* buf, struct val_env* ve, uint32_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,
+	ldns_pkt_section section, struct module_qstate* qstate);
 
 /**
  * canonical compare for two tree entries
--- unbound-1.4.17.orig/validator/val_utils.c
+++ unbound-1.4.17/validator/val_utils.c
@@ -310,7 +310,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, ldns_pkt_section section,
+	struct module_qstate* qstate)
 {
 	enum sec_status sec;
 	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
@@ -332,7 +333,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);
 
@@ -365,7 +367,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, ldns_pkt_section section, struct module_qstate* qstate)
 {
 	/* temporary dnskey rrset-key */
 	struct ub_packed_rrset_key dnskey;
@@ -378,7 +380,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;
 }
 
@@ -386,7 +389,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;
@@ -417,7 +421,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;
 		}
@@ -453,7 +457,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. */
@@ -490,7 +495,7 @@ val_verify_DNSKEY_with_DS(struct module_
 		has_useful_ds = true;
 
 		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))) {
@@ -523,11 +528,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, 
@@ -549,7 +555,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. */
@@ -600,7 +607,7 @@ val_verify_DNSKEY_with_TA(struct module_
 		has_useful_ta = true;
 
 		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))) {
@@ -626,7 +633,7 @@ val_verify_DNSKEY_with_TA(struct module_
 		has_useful_ta = true;
 
 		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))) {
@@ -660,12 +667,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.4.17.orig/validator/val_utils.h
+++ unbound-1.4.17/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 <ldns/packet.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, ldns_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, ldns_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.4.17.orig/validator/validator.c
+++ unbound-1.4.17/validator/validator.c
@@ -457,7 +457,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) {
@@ -486,7 +487,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) {
@@ -512,7 +514,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. */
@@ -2272,7 +2274,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;
@@ -2361,7 +2363,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");
@@ -2408,7 +2410,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 "
@@ -2436,7 +2438,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
@@ -2497,7 +2500,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");
@@ -2662,7 +2665,7 @@ process_dnskey_response(struct module_qs
 	}
 	downprot = 1;
 	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");
@@ -2737,7 +2740,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;
