validate_cname_response(struct module_env* env, struct val_env* ve,
	struct query_info* qchase, struct reply_info* chase_reply,
	struct key_entry_key* kkey)
{
	uint8_t* wc = NULL;
	size_t wl;
	int wc_NSEC_ok = 0;
	int nsec3s_seen = 0;
	size_t i;
	struct ub_packed_rrset_key* s;

	/* validate the ANSWER section - this will be the CNAME (+DNAME) */
	for(i=0; i<chase_reply->an_numrrsets; i++) {
		s = chase_reply->rrsets[i];

		/* Check to see if the rrset is the result of a wildcard 
		 * expansion. If so, an additional check will need to be 
		 * made in the authority section. */
		if(!val_rrset_wildcard(s, &wc, &wl)) {
			log_nametypeclass(VERB_QUERY, "Cname response has "
				"inconsistent wildcard sigs:", s->rk.dname,
				ntohs(s->rk.type), ntohs(s->rk.rrset_class));
			chase_reply->security = sec_status_bogus;
			update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
			return;
		}
		
		/* Refuse wildcarded DNAMEs rfc 4597. 
		 * Do not follow a wildcarded DNAME because 
		 * its synthesized CNAME expansion is underdefined */
		if(qchase->qtype != LDNS_RR_TYPE_DNAME && 
			ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME && wc) {
			log_nametypeclass(VERB_QUERY, "cannot validate a "
				"wildcarded DNAME:", s->rk.dname, 
				ntohs(s->rk.type), ntohs(s->rk.rrset_class));
			chase_reply->security = sec_status_bogus;
			update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
			return;
		}

		/* If we have found a CNAME, stop looking for one.
		 * The iterator has placed the CNAME chain in correct
		 * order. */
		if (ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) {
			break;
		}
	}

	/* AUTHORITY section */
	for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
		chase_reply->ns_numrrsets; i++) {
		s = chase_reply->rrsets[i];

		/* If this is a positive wildcard response, and we have a 
		 * (just verified) NSEC record, try to use it to 1) prove 
		 * that qname doesn't exist and 2) that the correct wildcard 
		 * was used. */
		if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
			if(val_nsec_proves_positive_wildcard(s, qchase, wc)) {
				wc_NSEC_ok = 1;
			}
			/* if not, continue looking for proof */
		}

		/* Otherwise, if this is a positive wildcard response and 
		 * we have NSEC3 records */
		if(wc != NULL && ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
			nsec3s_seen = 1;
		}
	}

	/* If this was a positive wildcard response that we haven't already
	 * proven, and we have NSEC3 records, try to prove it using the NSEC3
	 * records. */
	if(wc != NULL && !wc_NSEC_ok && nsec3s_seen) {
		enum sec_status sec = nsec3_prove_wildcard(env, ve, 
			chase_reply->rrsets+chase_reply->an_numrrsets,
			chase_reply->ns_numrrsets, qchase, kkey, wc);
		if(sec == sec_status_insecure) {
			verbose(VERB_ALGO, "wildcard CNAME response is "
				"insecure");
			chase_reply->security = sec_status_insecure;
			return;
		} else if(sec == sec_status_secure)
			wc_NSEC_ok = 1;
	}

	/* If after all this, we still haven't proven the positive wildcard
	 * response, fail. */
	if(wc != NULL && !wc_NSEC_ok) {
		verbose(VERB_QUERY, "CNAME response was wildcard "
			"expansion and did not prove original data "
			"did not exist");
		chase_reply->security = sec_status_bogus;
		update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
		return;
	}

	verbose(VERB_ALGO, "Successfully validated CNAME response");
	chase_reply->security = sec_status_secure;
}