xref: /openbsd-src/sbin/unwind/libunbound/validator/val_utils.c (revision 7037e34cdfd270b3989fb1829c7cd3439048bd3a)
1ae8c6e27Sflorian /*
2ae8c6e27Sflorian  * validator/val_utils.c - validator utility functions.
3ae8c6e27Sflorian  *
4ae8c6e27Sflorian  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5ae8c6e27Sflorian  *
6ae8c6e27Sflorian  * This software is open source.
7ae8c6e27Sflorian  *
8ae8c6e27Sflorian  * Redistribution and use in source and binary forms, with or without
9ae8c6e27Sflorian  * modification, are permitted provided that the following conditions
10ae8c6e27Sflorian  * are met:
11ae8c6e27Sflorian  *
12ae8c6e27Sflorian  * Redistributions of source code must retain the above copyright notice,
13ae8c6e27Sflorian  * this list of conditions and the following disclaimer.
14ae8c6e27Sflorian  *
15ae8c6e27Sflorian  * Redistributions in binary form must reproduce the above copyright notice,
16ae8c6e27Sflorian  * this list of conditions and the following disclaimer in the documentation
17ae8c6e27Sflorian  * and/or other materials provided with the distribution.
18ae8c6e27Sflorian  *
19ae8c6e27Sflorian  * Neither the name of the NLNET LABS nor the names of its contributors may
20ae8c6e27Sflorian  * be used to endorse or promote products derived from this software without
21ae8c6e27Sflorian  * specific prior written permission.
22ae8c6e27Sflorian  *
23ae8c6e27Sflorian  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24ae8c6e27Sflorian  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25ae8c6e27Sflorian  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26ae8c6e27Sflorian  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27ae8c6e27Sflorian  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28ae8c6e27Sflorian  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29ae8c6e27Sflorian  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30ae8c6e27Sflorian  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31ae8c6e27Sflorian  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32ae8c6e27Sflorian  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33ae8c6e27Sflorian  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34ae8c6e27Sflorian  */
35ae8c6e27Sflorian 
36ae8c6e27Sflorian /**
37ae8c6e27Sflorian  * \file
38ae8c6e27Sflorian  *
39ae8c6e27Sflorian  * This file contains helper functions for the validator module.
40ae8c6e27Sflorian  */
41ae8c6e27Sflorian #include "config.h"
42ae8c6e27Sflorian #include "validator/val_utils.h"
43ae8c6e27Sflorian #include "validator/validator.h"
44ae8c6e27Sflorian #include "validator/val_kentry.h"
45ae8c6e27Sflorian #include "validator/val_sigcrypt.h"
46ae8c6e27Sflorian #include "validator/val_anchor.h"
47ae8c6e27Sflorian #include "validator/val_nsec.h"
48ae8c6e27Sflorian #include "validator/val_neg.h"
49ae8c6e27Sflorian #include "services/cache/rrset.h"
50ae8c6e27Sflorian #include "services/cache/dns.h"
51ae8c6e27Sflorian #include "util/data/msgreply.h"
52ae8c6e27Sflorian #include "util/data/packed_rrset.h"
53ae8c6e27Sflorian #include "util/data/dname.h"
54ae8c6e27Sflorian #include "util/net_help.h"
55ae8c6e27Sflorian #include "util/module.h"
56ae8c6e27Sflorian #include "util/regional.h"
57ae8c6e27Sflorian #include "util/config_file.h"
58ae8c6e27Sflorian #include "sldns/wire2str.h"
59ae8c6e27Sflorian #include "sldns/parseutil.h"
60ae8c6e27Sflorian 
61fed3efa7Sflorian /** Maximum allowed digest match failures per DS, for DNSKEYs with the same
62fed3efa7Sflorian  *  properties */
63fed3efa7Sflorian #define MAX_DS_MATCH_FAILURES 4
64fed3efa7Sflorian 
65ae8c6e27Sflorian enum val_classification
66ae8c6e27Sflorian val_classify_response(uint16_t query_flags, struct query_info* origqinf,
67ae8c6e27Sflorian 	struct query_info* qinf, struct reply_info* rep, size_t skip)
68ae8c6e27Sflorian {
69ae8c6e27Sflorian 	int rcode = (int)FLAGS_GET_RCODE(rep->flags);
70ae8c6e27Sflorian 	size_t i;
71ae8c6e27Sflorian 
72ae8c6e27Sflorian 	/* Normal Name Error's are easy to detect -- but don't mistake a CNAME
73ae8c6e27Sflorian 	 * chain ending in NXDOMAIN. */
74ae8c6e27Sflorian 	if(rcode == LDNS_RCODE_NXDOMAIN && rep->an_numrrsets == 0)
75ae8c6e27Sflorian 		return VAL_CLASS_NAMEERROR;
76ae8c6e27Sflorian 
77ae8c6e27Sflorian 	/* check for referral: nonRD query and it looks like a nodata */
78ae8c6e27Sflorian 	if(!(query_flags&BIT_RD) && rep->an_numrrsets == 0 &&
79ae8c6e27Sflorian 		rcode == LDNS_RCODE_NOERROR) {
80ae8c6e27Sflorian 		/* SOA record in auth indicates it is NODATA instead.
81ae8c6e27Sflorian 		 * All validation requiring NODATA messages have SOA in
82ae8c6e27Sflorian 		 * authority section. */
83ae8c6e27Sflorian 		/* uses fact that answer section is empty */
84ae8c6e27Sflorian 		int saw_ns = 0;
85ae8c6e27Sflorian 		for(i=0; i<rep->ns_numrrsets; i++) {
86ae8c6e27Sflorian 			if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_SOA)
87ae8c6e27Sflorian 				return VAL_CLASS_NODATA;
88ae8c6e27Sflorian 			if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_DS)
89ae8c6e27Sflorian 				return VAL_CLASS_REFERRAL;
90ae8c6e27Sflorian 			if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
91ae8c6e27Sflorian 				saw_ns = 1;
92ae8c6e27Sflorian 		}
93ae8c6e27Sflorian 		return saw_ns?VAL_CLASS_REFERRAL:VAL_CLASS_NODATA;
94ae8c6e27Sflorian 	}
95ae8c6e27Sflorian 	/* root referral where NS set is in the answer section */
96ae8c6e27Sflorian 	if(!(query_flags&BIT_RD) && rep->ns_numrrsets == 0 &&
97ae8c6e27Sflorian 		rep->an_numrrsets == 1 && rcode == LDNS_RCODE_NOERROR &&
98ae8c6e27Sflorian 		ntohs(rep->rrsets[0]->rk.type) == LDNS_RR_TYPE_NS &&
99ae8c6e27Sflorian 		query_dname_compare(rep->rrsets[0]->rk.dname,
100ae8c6e27Sflorian 			origqinf->qname) != 0)
101ae8c6e27Sflorian 		return VAL_CLASS_REFERRAL;
102ae8c6e27Sflorian 
103ae8c6e27Sflorian 	/* dump bad messages */
104ae8c6e27Sflorian 	if(rcode != LDNS_RCODE_NOERROR && rcode != LDNS_RCODE_NXDOMAIN)
105ae8c6e27Sflorian 		return VAL_CLASS_UNKNOWN;
106ae8c6e27Sflorian 	/* next check if the skip into the answer section shows no answer */
107ae8c6e27Sflorian 	if(skip>0 && rep->an_numrrsets <= skip)
108ae8c6e27Sflorian 		return VAL_CLASS_CNAMENOANSWER;
109ae8c6e27Sflorian 
110ae8c6e27Sflorian 	/* Next is NODATA */
111ae8c6e27Sflorian 	if(rcode == LDNS_RCODE_NOERROR && rep->an_numrrsets == 0)
112ae8c6e27Sflorian 		return VAL_CLASS_NODATA;
113ae8c6e27Sflorian 
114ae8c6e27Sflorian 	/* We distinguish between CNAME response and other positive/negative
115ae8c6e27Sflorian 	 * responses because CNAME answers require extra processing. */
116ae8c6e27Sflorian 
117ae8c6e27Sflorian 	/* We distinguish between ANY and CNAME or POSITIVE because
118ae8c6e27Sflorian 	 * ANY responses are validated differently. */
119ae8c6e27Sflorian 	if(rcode == LDNS_RCODE_NOERROR && qinf->qtype == LDNS_RR_TYPE_ANY)
120ae8c6e27Sflorian 		return VAL_CLASS_ANY;
121ae8c6e27Sflorian 
122096314feSflorian 	/* For the query type DNAME, the name matters. Equal name is the
123096314feSflorian 	 * answer looked for, but a subdomain redirects the query. */
124096314feSflorian 	if(qinf->qtype == LDNS_RR_TYPE_DNAME) {
125096314feSflorian 		for(i=skip; i<rep->an_numrrsets; i++) {
126096314feSflorian 			if(rcode == LDNS_RCODE_NOERROR &&
127096314feSflorian 				ntohs(rep->rrsets[i]->rk.type)
128096314feSflorian 				== LDNS_RR_TYPE_DNAME &&
129096314feSflorian 				query_dname_compare(qinf->qname,
130096314feSflorian 				rep->rrsets[i]->rk.dname) == 0) {
131096314feSflorian 				/* type is DNAME and name is equal, it is
132096314feSflorian 				 * the answer. For the query name a subdomain
133096314feSflorian 				 * of the rrset.dname it would redirect. */
134096314feSflorian 				return VAL_CLASS_POSITIVE;
135096314feSflorian 			}
136096314feSflorian 			if(ntohs(rep->rrsets[i]->rk.type)
137096314feSflorian 				== LDNS_RR_TYPE_CNAME)
138096314feSflorian 				return VAL_CLASS_CNAME;
139096314feSflorian 		}
140096314feSflorian 		log_dns_msg("validator: error. failed to classify response message: ",
141096314feSflorian 			qinf, rep);
142096314feSflorian 		return VAL_CLASS_UNKNOWN;
143096314feSflorian 	}
144096314feSflorian 
145ae8c6e27Sflorian 	/* Note that DNAMEs will be ignored here, unless qtype=DNAME. Unless
146ae8c6e27Sflorian 	 * qtype=CNAME, this will yield a CNAME response. */
147ae8c6e27Sflorian 	for(i=skip; i<rep->an_numrrsets; i++) {
148ae8c6e27Sflorian 		if(rcode == LDNS_RCODE_NOERROR &&
149ae8c6e27Sflorian 			ntohs(rep->rrsets[i]->rk.type) == qinf->qtype)
150ae8c6e27Sflorian 			return VAL_CLASS_POSITIVE;
151ae8c6e27Sflorian 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME)
152ae8c6e27Sflorian 			return VAL_CLASS_CNAME;
153ae8c6e27Sflorian 	}
154ae8c6e27Sflorian 	log_dns_msg("validator: error. failed to classify response message: ",
155ae8c6e27Sflorian 		qinf, rep);
156ae8c6e27Sflorian 	return VAL_CLASS_UNKNOWN;
157ae8c6e27Sflorian }
158ae8c6e27Sflorian 
159ae8c6e27Sflorian /** Get signer name from RRSIG */
160ae8c6e27Sflorian static void
161ae8c6e27Sflorian rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen)
162ae8c6e27Sflorian {
163ae8c6e27Sflorian 	/* RRSIG rdata is not allowed to be compressed, it is stored
164ae8c6e27Sflorian 	 * uncompressed in memory as well, so return a ptr to the name */
165ae8c6e27Sflorian 	if(len < 21) {
166ae8c6e27Sflorian 		/* too short RRSig:
167ae8c6e27Sflorian 		 * short, byte, byte, long, long, long, short, "." is
168ae8c6e27Sflorian 		 * 2	1	1	4	4  4	2	1 = 19
169ae8c6e27Sflorian 		 * 			and a skip of 18 bytes to the name.
170ae8c6e27Sflorian 		 * +2 for the rdatalen is 21 bytes len for root label */
171ae8c6e27Sflorian 		*sname = NULL;
172ae8c6e27Sflorian 		*slen = 0;
173ae8c6e27Sflorian 		return;
174ae8c6e27Sflorian 	}
175ae8c6e27Sflorian 	data += 20; /* skip the fixed size bits */
176ae8c6e27Sflorian 	len -= 20;
177ae8c6e27Sflorian 	*slen = dname_valid(data, len);
178ae8c6e27Sflorian 	if(!*slen) {
179ae8c6e27Sflorian 		/* bad dname in this rrsig. */
180ae8c6e27Sflorian 		*sname = NULL;
181ae8c6e27Sflorian 		return;
182ae8c6e27Sflorian 	}
183ae8c6e27Sflorian 	*sname = data;
184ae8c6e27Sflorian }
185ae8c6e27Sflorian 
186ae8c6e27Sflorian void
187ae8c6e27Sflorian val_find_rrset_signer(struct ub_packed_rrset_key* rrset, uint8_t** sname,
188ae8c6e27Sflorian 	size_t* slen)
189ae8c6e27Sflorian {
190ae8c6e27Sflorian 	struct packed_rrset_data* d = (struct packed_rrset_data*)
191ae8c6e27Sflorian 		rrset->entry.data;
192ae8c6e27Sflorian 	/* return signer for first signature, or NULL */
193ae8c6e27Sflorian 	if(d->rrsig_count == 0) {
194ae8c6e27Sflorian 		*sname = NULL;
195ae8c6e27Sflorian 		*slen = 0;
196ae8c6e27Sflorian 		return;
197ae8c6e27Sflorian 	}
198ae8c6e27Sflorian 	/* get rrsig signer name out of the signature */
199ae8c6e27Sflorian 	rrsig_get_signer(d->rr_data[d->count], d->rr_len[d->count],
200ae8c6e27Sflorian 		sname, slen);
201ae8c6e27Sflorian }
202ae8c6e27Sflorian 
203ae8c6e27Sflorian /**
204ae8c6e27Sflorian  * Find best signer name in this set of rrsigs.
205ae8c6e27Sflorian  * @param rrset: which rrsigs to look through.
206ae8c6e27Sflorian  * @param qinf: the query name that needs validation.
207ae8c6e27Sflorian  * @param signer_name: the best signer_name. Updated if a better one is found.
208ae8c6e27Sflorian  * @param signer_len: length of signer name.
209ae8c6e27Sflorian  * @param matchcount: count of current best name (starts at 0 for no match).
210ae8c6e27Sflorian  * 	Updated if match is improved.
211ae8c6e27Sflorian  */
212ae8c6e27Sflorian static void
213ae8c6e27Sflorian val_find_best_signer(struct ub_packed_rrset_key* rrset,
214ae8c6e27Sflorian 	struct query_info* qinf, uint8_t** signer_name, size_t* signer_len,
215ae8c6e27Sflorian 	int* matchcount)
216ae8c6e27Sflorian {
217ae8c6e27Sflorian 	struct packed_rrset_data* d = (struct packed_rrset_data*)
218ae8c6e27Sflorian 		rrset->entry.data;
219ae8c6e27Sflorian 	uint8_t* sign;
220ae8c6e27Sflorian 	size_t i;
221ae8c6e27Sflorian 	int m;
222ae8c6e27Sflorian 	for(i=d->count; i<d->count+d->rrsig_count; i++) {
223ae8c6e27Sflorian 		sign = d->rr_data[i]+2+18;
224ae8c6e27Sflorian 		/* look at signatures that are valid (long enough),
225ae8c6e27Sflorian 		 * and have a signer name that is a superdomain of qname,
226ae8c6e27Sflorian 		 * and then check the number of labels in the shared topdomain
227ae8c6e27Sflorian 		 * improve the match if possible */
228ae8c6e27Sflorian 		if(d->rr_len[i] > 2+19 && /* rdata, sig + root label*/
229ae8c6e27Sflorian 			dname_subdomain_c(qinf->qname, sign)) {
230ae8c6e27Sflorian 			(void)dname_lab_cmp(qinf->qname,
231ae8c6e27Sflorian 				dname_count_labels(qinf->qname),
232ae8c6e27Sflorian 				sign, dname_count_labels(sign), &m);
233ae8c6e27Sflorian 			if(m > *matchcount) {
234ae8c6e27Sflorian 				*matchcount = m;
235ae8c6e27Sflorian 				*signer_name = sign;
236ae8c6e27Sflorian 				(void)dname_count_size_labels(*signer_name,
237ae8c6e27Sflorian 					signer_len);
238ae8c6e27Sflorian 			}
239ae8c6e27Sflorian 		}
240ae8c6e27Sflorian 	}
241ae8c6e27Sflorian }
242ae8c6e27Sflorian 
243*7037e34cSflorian /** Detect if the, unsigned, CNAME is under a previous DNAME RR in the
244*7037e34cSflorian  * message, and thus it was generated from that previous DNAME.
245*7037e34cSflorian  */
246*7037e34cSflorian static int
247*7037e34cSflorian cname_under_previous_dname(struct reply_info* rep, size_t cname_idx,
248*7037e34cSflorian 	size_t* ret)
249*7037e34cSflorian {
250*7037e34cSflorian 	size_t i;
251*7037e34cSflorian 	for(i=0; i<cname_idx; i++) {
252*7037e34cSflorian 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_DNAME &&
253*7037e34cSflorian 			dname_strict_subdomain_c(rep->rrsets[cname_idx]->
254*7037e34cSflorian 			rk.dname, rep->rrsets[i]->rk.dname)) {
255*7037e34cSflorian 			*ret = i;
256*7037e34cSflorian 			return 1;
257*7037e34cSflorian 		}
258*7037e34cSflorian 	}
259*7037e34cSflorian 	*ret = 0;
260*7037e34cSflorian 	return 0;
261*7037e34cSflorian }
262*7037e34cSflorian 
263ae8c6e27Sflorian void
264ae8c6e27Sflorian val_find_signer(enum val_classification subtype, struct query_info* qinf,
265ae8c6e27Sflorian 	struct reply_info* rep, size_t skip, uint8_t** signer_name,
266ae8c6e27Sflorian 	size_t* signer_len)
267ae8c6e27Sflorian {
268ae8c6e27Sflorian 	size_t i;
269ae8c6e27Sflorian 
270ae8c6e27Sflorian 	if(subtype == VAL_CLASS_POSITIVE) {
271ae8c6e27Sflorian 		/* check for the answer rrset */
272ae8c6e27Sflorian 		for(i=skip; i<rep->an_numrrsets; i++) {
273ae8c6e27Sflorian 			if(query_dname_compare(qinf->qname,
274ae8c6e27Sflorian 				rep->rrsets[i]->rk.dname) == 0) {
275ae8c6e27Sflorian 				val_find_rrset_signer(rep->rrsets[i],
276ae8c6e27Sflorian 					signer_name, signer_len);
277096314feSflorian 				/* If there was no signer, and the query
278096314feSflorian 				 * was for type CNAME, and this is a CNAME,
279096314feSflorian 				 * and the previous is a DNAME, then this
280096314feSflorian 				 * is the synthesized CNAME, use the signer
281096314feSflorian 				 * of the DNAME record. */
282096314feSflorian 				if(*signer_name == NULL &&
283096314feSflorian 				   qinf->qtype == LDNS_RR_TYPE_CNAME &&
284096314feSflorian 				   ntohs(rep->rrsets[i]->rk.type) ==
285096314feSflorian 				   LDNS_RR_TYPE_CNAME && i > skip &&
286096314feSflorian 				   ntohs(rep->rrsets[i-1]->rk.type) ==
287096314feSflorian 				   LDNS_RR_TYPE_DNAME &&
288096314feSflorian 				   dname_strict_subdomain_c(rep->rrsets[i]->rk.dname, rep->rrsets[i-1]->rk.dname)) {
289096314feSflorian 					val_find_rrset_signer(rep->rrsets[i-1],
290096314feSflorian 						signer_name, signer_len);
291096314feSflorian 				}
292ae8c6e27Sflorian 				return;
293ae8c6e27Sflorian 			}
294ae8c6e27Sflorian 		}
295ae8c6e27Sflorian 		*signer_name = NULL;
296ae8c6e27Sflorian 		*signer_len = 0;
297ae8c6e27Sflorian 	} else if(subtype == VAL_CLASS_CNAME) {
298*7037e34cSflorian 		size_t j;
299ae8c6e27Sflorian 		/* check for the first signed cname/dname rrset */
300ae8c6e27Sflorian 		for(i=skip; i<rep->an_numrrsets; i++) {
301ae8c6e27Sflorian 			val_find_rrset_signer(rep->rrsets[i],
302ae8c6e27Sflorian 				signer_name, signer_len);
303ae8c6e27Sflorian 			if(*signer_name)
304ae8c6e27Sflorian 				return;
305*7037e34cSflorian 			if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME
306*7037e34cSflorian 				&& cname_under_previous_dname(rep, i, &j)) {
307*7037e34cSflorian 				val_find_rrset_signer(rep->rrsets[j],
308*7037e34cSflorian 					signer_name, signer_len);
309*7037e34cSflorian 				return;
310*7037e34cSflorian 			}
311ae8c6e27Sflorian 			if(ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_DNAME)
312ae8c6e27Sflorian 				break; /* only check CNAME after a DNAME */
313ae8c6e27Sflorian 		}
314ae8c6e27Sflorian 		*signer_name = NULL;
315ae8c6e27Sflorian 		*signer_len = 0;
316ae8c6e27Sflorian 	} else if(subtype == VAL_CLASS_NAMEERROR
317ae8c6e27Sflorian 		|| subtype == VAL_CLASS_NODATA) {
318ae8c6e27Sflorian 		/*Check to see if the AUTH section NSEC record(s) have rrsigs*/
319ae8c6e27Sflorian 		for(i=rep->an_numrrsets; i<
320ae8c6e27Sflorian 			rep->an_numrrsets+rep->ns_numrrsets; i++) {
321ae8c6e27Sflorian 			if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC
322ae8c6e27Sflorian 				|| ntohs(rep->rrsets[i]->rk.type) ==
323ae8c6e27Sflorian 				LDNS_RR_TYPE_NSEC3) {
324ae8c6e27Sflorian 				val_find_rrset_signer(rep->rrsets[i],
325ae8c6e27Sflorian 					signer_name, signer_len);
326ae8c6e27Sflorian 				return;
327ae8c6e27Sflorian 			}
328ae8c6e27Sflorian 		}
329ae8c6e27Sflorian 	} else if(subtype == VAL_CLASS_CNAMENOANSWER) {
330ae8c6e27Sflorian 		/* find closest superdomain signer name in authority section
331ae8c6e27Sflorian 		 * NSEC and NSEC3s */
332ae8c6e27Sflorian 		int matchcount = 0;
333ae8c6e27Sflorian 		*signer_name = NULL;
334ae8c6e27Sflorian 		*signer_len = 0;
335ae8c6e27Sflorian 		for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->
336ae8c6e27Sflorian 			ns_numrrsets; i++) {
337ae8c6e27Sflorian 			if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC
338ae8c6e27Sflorian 				|| ntohs(rep->rrsets[i]->rk.type) ==
339ae8c6e27Sflorian 				LDNS_RR_TYPE_NSEC3) {
340ae8c6e27Sflorian 				val_find_best_signer(rep->rrsets[i], qinf,
341ae8c6e27Sflorian 					signer_name, signer_len, &matchcount);
342ae8c6e27Sflorian 			}
343ae8c6e27Sflorian 		}
344ae8c6e27Sflorian 	} else if(subtype == VAL_CLASS_ANY) {
345ae8c6e27Sflorian 		/* check for one of the answer rrset that has signatures,
346ae8c6e27Sflorian 		 * or potentially a DNAME is in use with a different qname */
347ae8c6e27Sflorian 		for(i=skip; i<rep->an_numrrsets; i++) {
348ae8c6e27Sflorian 			if(query_dname_compare(qinf->qname,
349ae8c6e27Sflorian 				rep->rrsets[i]->rk.dname) == 0) {
350ae8c6e27Sflorian 				val_find_rrset_signer(rep->rrsets[i],
351ae8c6e27Sflorian 					signer_name, signer_len);
352ae8c6e27Sflorian 				if(*signer_name)
353ae8c6e27Sflorian 					return;
354ae8c6e27Sflorian 			}
355ae8c6e27Sflorian 		}
356ae8c6e27Sflorian 		/* no answer RRSIGs with qname, try a DNAME */
357ae8c6e27Sflorian 		if(skip < rep->an_numrrsets &&
358ae8c6e27Sflorian 			ntohs(rep->rrsets[skip]->rk.type) ==
359ae8c6e27Sflorian 			LDNS_RR_TYPE_DNAME) {
360ae8c6e27Sflorian 			val_find_rrset_signer(rep->rrsets[skip],
361ae8c6e27Sflorian 				signer_name, signer_len);
362ae8c6e27Sflorian 			if(*signer_name)
363ae8c6e27Sflorian 				return;
364ae8c6e27Sflorian 		}
365ae8c6e27Sflorian 		*signer_name = NULL;
366ae8c6e27Sflorian 		*signer_len = 0;
367ae8c6e27Sflorian 	} else if(subtype == VAL_CLASS_REFERRAL) {
368ae8c6e27Sflorian 		/* find keys for the item at skip */
369ae8c6e27Sflorian 		if(skip < rep->rrset_count) {
370ae8c6e27Sflorian 			val_find_rrset_signer(rep->rrsets[skip],
371ae8c6e27Sflorian 				signer_name, signer_len);
372ae8c6e27Sflorian 			return;
373ae8c6e27Sflorian 		}
374ae8c6e27Sflorian 		*signer_name = NULL;
375ae8c6e27Sflorian 		*signer_len = 0;
376ae8c6e27Sflorian 	} else {
377ae8c6e27Sflorian 		verbose(VERB_QUERY, "find_signer: could not find signer name"
378ae8c6e27Sflorian 			" for unknown type response");
379ae8c6e27Sflorian 		*signer_name = NULL;
380ae8c6e27Sflorian 		*signer_len = 0;
381ae8c6e27Sflorian 	}
382ae8c6e27Sflorian }
383ae8c6e27Sflorian 
384ae8c6e27Sflorian /** return number of rrs in an rrset */
385ae8c6e27Sflorian static size_t
386ae8c6e27Sflorian rrset_get_count(struct ub_packed_rrset_key* rrset)
387ae8c6e27Sflorian {
388ae8c6e27Sflorian 	struct packed_rrset_data* d = (struct packed_rrset_data*)
389ae8c6e27Sflorian 		rrset->entry.data;
390ae8c6e27Sflorian 	if(!d) return 0;
391ae8c6e27Sflorian 	return d->count;
392ae8c6e27Sflorian }
393ae8c6e27Sflorian 
394ae8c6e27Sflorian /** return TTL of rrset */
395ae8c6e27Sflorian static uint32_t
396ae8c6e27Sflorian rrset_get_ttl(struct ub_packed_rrset_key* rrset)
397ae8c6e27Sflorian {
398ae8c6e27Sflorian 	struct packed_rrset_data* d = (struct packed_rrset_data*)
399ae8c6e27Sflorian 		rrset->entry.data;
400ae8c6e27Sflorian 	if(!d) return 0;
401ae8c6e27Sflorian 	return d->ttl;
402ae8c6e27Sflorian }
403ae8c6e27Sflorian 
4047a05b9dfSflorian static enum sec_status
405ae8c6e27Sflorian val_verify_rrset(struct module_env* env, struct val_env* ve,
406ae8c6e27Sflorian         struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
4077a05b9dfSflorian 	uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus,
408fed3efa7Sflorian 	sldns_pkt_section section, struct module_qstate* qstate,
409*7037e34cSflorian 	int *verified, char* reasonbuf, size_t reasonlen)
410ae8c6e27Sflorian {
411ae8c6e27Sflorian 	enum sec_status sec;
412ae8c6e27Sflorian 	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
413ae8c6e27Sflorian 		entry.data;
414ae8c6e27Sflorian 	if(d->security == sec_status_secure) {
415ae8c6e27Sflorian 		/* re-verify all other statuses, because keyset may change*/
416ae8c6e27Sflorian 		log_nametypeclass(VERB_ALGO, "verify rrset cached",
417ae8c6e27Sflorian 			rrset->rk.dname, ntohs(rrset->rk.type),
418ae8c6e27Sflorian 			ntohs(rrset->rk.rrset_class));
419fed3efa7Sflorian 		*verified = 0;
420ae8c6e27Sflorian 		return d->security;
421ae8c6e27Sflorian 	}
422ae8c6e27Sflorian 	/* check in the cache if verification has already been done */
423ae8c6e27Sflorian 	rrset_check_sec_status(env->rrset_cache, rrset, *env->now);
424ae8c6e27Sflorian 	if(d->security == sec_status_secure) {
425ae8c6e27Sflorian 		log_nametypeclass(VERB_ALGO, "verify rrset from cache",
426ae8c6e27Sflorian 			rrset->rk.dname, ntohs(rrset->rk.type),
427ae8c6e27Sflorian 			ntohs(rrset->rk.rrset_class));
428fed3efa7Sflorian 		*verified = 0;
429ae8c6e27Sflorian 		return d->security;
430ae8c6e27Sflorian 	}
431ae8c6e27Sflorian 	log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
432ae8c6e27Sflorian 		ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
433ae8c6e27Sflorian 	sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason,
434*7037e34cSflorian 		reason_bogus, section, qstate, verified, reasonbuf, reasonlen);
435ae8c6e27Sflorian 	verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
436ae8c6e27Sflorian 	regional_free_all(env->scratch);
437ae8c6e27Sflorian 
438ae8c6e27Sflorian 	/* update rrset security status
439ae8c6e27Sflorian 	 * only improves security status
440ae8c6e27Sflorian 	 * and bogus is set only once, even if we rechecked the status */
441ae8c6e27Sflorian 	if(sec > d->security) {
442ae8c6e27Sflorian 		d->security = sec;
443ae8c6e27Sflorian 		if(sec == sec_status_secure)
444ae8c6e27Sflorian 			d->trust = rrset_trust_validated;
445ae8c6e27Sflorian 		else if(sec == sec_status_bogus) {
446ae8c6e27Sflorian 			size_t i;
447ae8c6e27Sflorian 			/* update ttl for rrset to fixed value. */
448ae8c6e27Sflorian 			d->ttl = ve->bogus_ttl;
449ae8c6e27Sflorian 			for(i=0; i<d->count+d->rrsig_count; i++)
450ae8c6e27Sflorian 				d->rr_ttl[i] = ve->bogus_ttl;
451ae8c6e27Sflorian 			/* leave RR specific TTL: not used for determine
452ae8c6e27Sflorian 			 * if RRset timed out and clients see proper value. */
453ae8c6e27Sflorian 			lock_basic_lock(&ve->bogus_lock);
454ae8c6e27Sflorian 			ve->num_rrset_bogus++;
455ae8c6e27Sflorian 			lock_basic_unlock(&ve->bogus_lock);
456ae8c6e27Sflorian 		}
457ae8c6e27Sflorian 		/* if status updated - store in cache for reuse */
458ae8c6e27Sflorian 		rrset_update_sec_status(env->rrset_cache, rrset, *env->now);
459ae8c6e27Sflorian 	}
460ae8c6e27Sflorian 
461ae8c6e27Sflorian 	return sec;
462ae8c6e27Sflorian }
463ae8c6e27Sflorian 
464ae8c6e27Sflorian enum sec_status
465ae8c6e27Sflorian val_verify_rrset_entry(struct module_env* env, struct val_env* ve,
466ae8c6e27Sflorian         struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey,
4677a05b9dfSflorian 	char** reason, sldns_ede_code *reason_bogus,
468fed3efa7Sflorian 	sldns_pkt_section section, struct module_qstate* qstate,
469*7037e34cSflorian 	int* verified, char* reasonbuf, size_t reasonlen)
470ae8c6e27Sflorian {
471ae8c6e27Sflorian 	/* temporary dnskey rrset-key */
472ae8c6e27Sflorian 	struct ub_packed_rrset_key dnskey;
473ae8c6e27Sflorian 	struct key_entry_data* kd = (struct key_entry_data*)kkey->entry.data;
474ae8c6e27Sflorian 	enum sec_status sec;
475ae8c6e27Sflorian 	dnskey.rk.type = htons(kd->rrset_type);
476ae8c6e27Sflorian 	dnskey.rk.rrset_class = htons(kkey->key_class);
477ae8c6e27Sflorian 	dnskey.rk.flags = 0;
478ae8c6e27Sflorian 	dnskey.rk.dname = kkey->name;
479ae8c6e27Sflorian 	dnskey.rk.dname_len = kkey->namelen;
480ae8c6e27Sflorian 	dnskey.entry.key = &dnskey;
481ae8c6e27Sflorian 	dnskey.entry.data = kd->rrset_data;
482ae8c6e27Sflorian 	sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason,
483*7037e34cSflorian 		reason_bogus, section, qstate, verified, reasonbuf, reasonlen);
484ae8c6e27Sflorian 	return sec;
485ae8c6e27Sflorian }
486ae8c6e27Sflorian 
487ae8c6e27Sflorian /** verify that a DS RR hashes to a key and that key signs the set */
488ae8c6e27Sflorian static enum sec_status
489ae8c6e27Sflorian verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
490ae8c6e27Sflorian 	struct ub_packed_rrset_key* dnskey_rrset,
491ae8c6e27Sflorian         struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason,
49254cc57acSflorian 	sldns_ede_code *reason_bogus, struct module_qstate* qstate,
493*7037e34cSflorian 	int *nonechecked, char* reasonbuf, size_t reasonlen)
494ae8c6e27Sflorian {
495ae8c6e27Sflorian 	enum sec_status sec = sec_status_bogus;
496411c5950Sflorian 	size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0;
497ae8c6e27Sflorian 	num = rrset_get_count(dnskey_rrset);
49854cc57acSflorian 	*nonechecked = 0;
499ae8c6e27Sflorian 	for(i=0; i<num; i++) {
500ae8c6e27Sflorian 		/* Skip DNSKEYs that don't match the basic criteria. */
501ae8c6e27Sflorian 		if(ds_get_key_algo(ds_rrset, ds_idx)
502ae8c6e27Sflorian 		   != dnskey_get_algo(dnskey_rrset, i)
503ae8c6e27Sflorian 		   || dnskey_calc_keytag(dnskey_rrset, i)
504ae8c6e27Sflorian 		   != ds_get_keytag(ds_rrset, ds_idx)) {
505ae8c6e27Sflorian 			continue;
506ae8c6e27Sflorian 		}
507ae8c6e27Sflorian 		numchecked++;
508ae8c6e27Sflorian 		verbose(VERB_ALGO, "attempt DS match algo %d keytag %d",
509ae8c6e27Sflorian 			ds_get_key_algo(ds_rrset, ds_idx),
510ae8c6e27Sflorian 			ds_get_keytag(ds_rrset, ds_idx));
511ae8c6e27Sflorian 
512ae8c6e27Sflorian 		/* Convert the candidate DNSKEY into a hash using the
513ae8c6e27Sflorian 		 * same DS hash algorithm. */
514ae8c6e27Sflorian 		if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset,
515ae8c6e27Sflorian 			ds_idx)) {
516ae8c6e27Sflorian 			verbose(VERB_ALGO, "DS match attempt failed");
517fed3efa7Sflorian 			if(numchecked > numhashok + MAX_DS_MATCH_FAILURES) {
518fed3efa7Sflorian 				verbose(VERB_ALGO, "DS match attempt reached "
519fed3efa7Sflorian 					"MAX_DS_MATCH_FAILURES (%d); bogus",
520fed3efa7Sflorian 					MAX_DS_MATCH_FAILURES);
521fed3efa7Sflorian 				return sec_status_bogus;
522fed3efa7Sflorian 			}
523ae8c6e27Sflorian 			continue;
524ae8c6e27Sflorian 		}
525ae8c6e27Sflorian 		numhashok++;
526411c5950Sflorian 		if(!dnskey_size_is_supported(dnskey_rrset, i)) {
527411c5950Sflorian 			verbose(VERB_ALGO, "DS okay but that DNSKEY size is not supported");
528411c5950Sflorian 			numsizesupp++;
529411c5950Sflorian 			continue;
530411c5950Sflorian 		}
531ae8c6e27Sflorian 		verbose(VERB_ALGO, "DS match digest ok, trying signature");
532ae8c6e27Sflorian 
533ae8c6e27Sflorian 		/* Otherwise, we have a match! Make sure that the DNSKEY
534ae8c6e27Sflorian 		 * verifies *with this key*  */
5357a05b9dfSflorian 		sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset,
5367a05b9dfSflorian 			i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate);
537ae8c6e27Sflorian 		if(sec == sec_status_secure) {
538ae8c6e27Sflorian 			return sec;
539ae8c6e27Sflorian 		}
540ae8c6e27Sflorian 		/* If it didn't validate with the DNSKEY, try the next one! */
541ae8c6e27Sflorian 	}
5426d08cb1bSflorian 	if(numsizesupp != 0 || sec == sec_status_indeterminate) {
543411c5950Sflorian 		/* there is a working DS, but that DNSKEY is not supported */
544411c5950Sflorian 		return sec_status_insecure;
545411c5950Sflorian 	}
54654cc57acSflorian 	if(numchecked == 0) {
547*7037e34cSflorian 		algo_needs_reason(ds_get_key_algo(ds_rrset, ds_idx),
548*7037e34cSflorian 			reason, "no keys have a DS", reasonbuf, reasonlen);
54954cc57acSflorian 		*nonechecked = 1;
55054cc57acSflorian 	} else if(numhashok == 0) {
551ae8c6e27Sflorian 		*reason = "DS hash mismatches key";
55254cc57acSflorian 	} else if(!*reason) {
553ae8c6e27Sflorian 		*reason = "keyset not secured by DNSKEY that matches DS";
55454cc57acSflorian 	}
555ae8c6e27Sflorian 	return sec_status_bogus;
556ae8c6e27Sflorian }
557ae8c6e27Sflorian 
558ae8c6e27Sflorian int val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset)
559ae8c6e27Sflorian {
560ae8c6e27Sflorian 	size_t i, num = rrset_get_count(ds_rrset);
561ae8c6e27Sflorian 	int d, digest_algo = 0; /* DS digest algo 0 is not used. */
562ae8c6e27Sflorian 	/* find favorite algo, for now, highest number supported */
563ae8c6e27Sflorian 	for(i=0; i<num; i++) {
564ae8c6e27Sflorian 		if(!ds_digest_algo_is_supported(ds_rrset, i) ||
565ae8c6e27Sflorian 			!ds_key_algo_is_supported(ds_rrset, i)) {
566ae8c6e27Sflorian 			continue;
567ae8c6e27Sflorian 		}
568ae8c6e27Sflorian 		d = ds_get_digest_algo(ds_rrset, i);
569ae8c6e27Sflorian 		if(d > digest_algo)
570ae8c6e27Sflorian 			digest_algo = d;
571ae8c6e27Sflorian 	}
572ae8c6e27Sflorian 	return digest_algo;
573ae8c6e27Sflorian }
574ae8c6e27Sflorian 
575ae8c6e27Sflorian enum sec_status
576ae8c6e27Sflorian val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
577ae8c6e27Sflorian 	struct ub_packed_rrset_key* dnskey_rrset,
578ae8c6e27Sflorian 	struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
579*7037e34cSflorian 	sldns_ede_code *reason_bogus, struct module_qstate* qstate,
580*7037e34cSflorian 	char* reasonbuf, size_t reasonlen)
581ae8c6e27Sflorian {
582ae8c6e27Sflorian 	/* as long as this is false, we can consider this DS rrset to be
583ae8c6e27Sflorian 	 * equivalent to no DS rrset. */
58454cc57acSflorian 	int has_useful_ds = 0, digest_algo, alg, has_algo_refusal = 0,
58554cc57acSflorian 		nonechecked, has_checked_ds = 0;
586ae8c6e27Sflorian 	struct algo_needs needs;
587ae8c6e27Sflorian 	size_t i, num;
588ae8c6e27Sflorian 	enum sec_status sec;
589ae8c6e27Sflorian 
590ae8c6e27Sflorian 	if(dnskey_rrset->rk.dname_len != ds_rrset->rk.dname_len ||
591ae8c6e27Sflorian 		query_dname_compare(dnskey_rrset->rk.dname, ds_rrset->rk.dname)
592ae8c6e27Sflorian 		!= 0) {
593ae8c6e27Sflorian 		verbose(VERB_QUERY, "DNSKEY RRset did not match DS RRset "
594ae8c6e27Sflorian 			"by name");
595ae8c6e27Sflorian 		*reason = "DNSKEY RRset did not match DS RRset by name";
596ae8c6e27Sflorian 		return sec_status_bogus;
597ae8c6e27Sflorian 	}
598ae8c6e27Sflorian 
599ae8c6e27Sflorian 	if(sigalg) {
600ae8c6e27Sflorian 		/* harden against algo downgrade is enabled */
601ae8c6e27Sflorian 		digest_algo = val_favorite_ds_algo(ds_rrset);
602ae8c6e27Sflorian 		algo_needs_init_ds(&needs, ds_rrset, digest_algo, sigalg);
603ae8c6e27Sflorian 	} else {
604ae8c6e27Sflorian 		/* accept any key algo, any digest algo */
605ae8c6e27Sflorian 		digest_algo = -1;
606ae8c6e27Sflorian 	}
607ae8c6e27Sflorian 	num = rrset_get_count(ds_rrset);
608ae8c6e27Sflorian 	for(i=0; i<num; i++) {
609ae8c6e27Sflorian 		/* Check to see if we can understand this DS.
610ae8c6e27Sflorian 		 * And check it is the strongest digest */
611ae8c6e27Sflorian 		if(!ds_digest_algo_is_supported(ds_rrset, i) ||
612ae8c6e27Sflorian 			!ds_key_algo_is_supported(ds_rrset, i) ||
613ae8c6e27Sflorian 			(sigalg && (ds_get_digest_algo(ds_rrset, i) != digest_algo))) {
614ae8c6e27Sflorian 			continue;
615ae8c6e27Sflorian 		}
616ae8c6e27Sflorian 
617411c5950Sflorian 		sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
61854cc57acSflorian 			ds_rrset, i, reason, reason_bogus, qstate,
619*7037e34cSflorian 			&nonechecked, reasonbuf, reasonlen);
62054cc57acSflorian 		if(sec == sec_status_insecure) {
62154cc57acSflorian 			/* DNSKEY too large unsupported or algo refused by
62254cc57acSflorian 			 * crypto lib. */
62354cc57acSflorian 			has_algo_refusal = 1;
624411c5950Sflorian 			continue;
62554cc57acSflorian 		}
62654cc57acSflorian 		if(!nonechecked)
62754cc57acSflorian 			has_checked_ds = 1;
628411c5950Sflorian 
629ae8c6e27Sflorian 		/* Once we see a single DS with a known digestID and
630ae8c6e27Sflorian 		 * algorithm, we cannot return INSECURE (with a
631ae8c6e27Sflorian 		 * "null" KeyEntry). */
632ae8c6e27Sflorian 		has_useful_ds = 1;
633ae8c6e27Sflorian 
634ae8c6e27Sflorian 		if(sec == sec_status_secure) {
635ae8c6e27Sflorian 			if(!sigalg || algo_needs_set_secure(&needs,
636ae8c6e27Sflorian 				(uint8_t)ds_get_key_algo(ds_rrset, i))) {
637ae8c6e27Sflorian 				verbose(VERB_ALGO, "DS matched DNSKEY.");
638411c5950Sflorian 				if(!dnskeyset_size_is_supported(dnskey_rrset)) {
639411c5950Sflorian 					verbose(VERB_ALGO, "DS works, but dnskeyset contain keys that are unsupported, treat as insecure");
640411c5950Sflorian 					return sec_status_insecure;
641411c5950Sflorian 				}
642ae8c6e27Sflorian 				return sec_status_secure;
643ae8c6e27Sflorian 			}
644ae8c6e27Sflorian 		} else if(sigalg && sec == sec_status_bogus) {
645ae8c6e27Sflorian 			algo_needs_set_bogus(&needs,
646ae8c6e27Sflorian 				(uint8_t)ds_get_key_algo(ds_rrset, i));
647ae8c6e27Sflorian 		}
648ae8c6e27Sflorian 	}
649ae8c6e27Sflorian 
650ae8c6e27Sflorian 	/* None of the DS's worked out. */
651ae8c6e27Sflorian 
65254cc57acSflorian 	/* If none of the DSes have been checked, eg. that means no matches
65354cc57acSflorian 	 * for keytags, and the other dses are all algo_refusal, it is an
65454cc57acSflorian 	 * insecure delegation point, since the only matched DS records
65554cc57acSflorian 	 * have an algo refusal, or are unsupported. */
65654cc57acSflorian 	if(has_algo_refusal && !has_checked_ds) {
65754cc57acSflorian 		verbose(VERB_ALGO, "No supported DS records were found -- "
65854cc57acSflorian 			"treating as insecure.");
65954cc57acSflorian 		return sec_status_insecure;
66054cc57acSflorian 	}
661ae8c6e27Sflorian 	/* If no DSs were understandable, then this is OK. */
662ae8c6e27Sflorian 	if(!has_useful_ds) {
663ae8c6e27Sflorian 		verbose(VERB_ALGO, "No usable DS records were found -- "
664ae8c6e27Sflorian 			"treating as insecure.");
665ae8c6e27Sflorian 		return sec_status_insecure;
666ae8c6e27Sflorian 	}
667ae8c6e27Sflorian 	/* If any were understandable, then it is bad. */
668ae8c6e27Sflorian 	verbose(VERB_QUERY, "Failed to match any usable DS to a DNSKEY.");
669ae8c6e27Sflorian 	if(sigalg && (alg=algo_needs_missing(&needs)) != 0) {
670*7037e34cSflorian 		algo_needs_reason(alg, reason, "missing verification of "
671*7037e34cSflorian 			"DNSKEY signature", reasonbuf, reasonlen);
672ae8c6e27Sflorian 	}
673ae8c6e27Sflorian 	return sec_status_bogus;
674ae8c6e27Sflorian }
675ae8c6e27Sflorian 
676ae8c6e27Sflorian struct key_entry_key*
677ae8c6e27Sflorian val_verify_new_DNSKEYs(struct regional* region, struct module_env* env,
678ae8c6e27Sflorian 	struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
679ae8c6e27Sflorian 	struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
680*7037e34cSflorian 	sldns_ede_code *reason_bogus, struct module_qstate* qstate,
681*7037e34cSflorian 	char* reasonbuf, size_t reasonlen)
682ae8c6e27Sflorian {
683ae8c6e27Sflorian 	uint8_t sigalg[ALGO_NEEDS_MAX+1];
684ae8c6e27Sflorian 	enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve,
6857a05b9dfSflorian 		dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason,
686*7037e34cSflorian 		reason_bogus, qstate, reasonbuf, reasonlen);
687ae8c6e27Sflorian 
688ae8c6e27Sflorian 	if(sec == sec_status_secure) {
689ae8c6e27Sflorian 		return key_entry_create_rrset(region,
690ae8c6e27Sflorian 			ds_rrset->rk.dname, ds_rrset->rk.dname_len,
691ae8c6e27Sflorian 			ntohs(ds_rrset->rk.rrset_class), dnskey_rrset,
692d500c338Sflorian 			downprot?sigalg:NULL, LDNS_EDE_NONE, NULL,
693d500c338Sflorian 			*env->now);
694ae8c6e27Sflorian 	} else if(sec == sec_status_insecure) {
695ae8c6e27Sflorian 		return key_entry_create_null(region, ds_rrset->rk.dname,
696ae8c6e27Sflorian 			ds_rrset->rk.dname_len,
697ae8c6e27Sflorian 			ntohs(ds_rrset->rk.rrset_class),
698d500c338Sflorian 			rrset_get_ttl(ds_rrset), *reason_bogus, *reason,
699d500c338Sflorian 			*env->now);
700ae8c6e27Sflorian 	}
701ae8c6e27Sflorian 	return key_entry_create_bad(region, ds_rrset->rk.dname,
702ae8c6e27Sflorian 		ds_rrset->rk.dname_len, ntohs(ds_rrset->rk.rrset_class),
703d500c338Sflorian 		BOGUS_KEY_TTL, *reason_bogus, *reason, *env->now);
704ae8c6e27Sflorian }
705ae8c6e27Sflorian 
706ae8c6e27Sflorian enum sec_status
707ae8c6e27Sflorian val_verify_DNSKEY_with_TA(struct module_env* env, struct val_env* ve,
708ae8c6e27Sflorian 	struct ub_packed_rrset_key* dnskey_rrset,
709ae8c6e27Sflorian 	struct ub_packed_rrset_key* ta_ds,
710ae8c6e27Sflorian 	struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
711*7037e34cSflorian 	sldns_ede_code *reason_bogus, struct module_qstate* qstate,
712*7037e34cSflorian 	char* reasonbuf, size_t reasonlen)
713ae8c6e27Sflorian {
714ae8c6e27Sflorian 	/* as long as this is false, we can consider this anchor to be
715ae8c6e27Sflorian 	 * equivalent to no anchor. */
71654cc57acSflorian 	int has_useful_ta = 0, digest_algo = 0, alg, has_algo_refusal = 0,
71754cc57acSflorian 		nonechecked, has_checked_ds = 0;
718ae8c6e27Sflorian 	struct algo_needs needs;
719ae8c6e27Sflorian 	size_t i, num;
720ae8c6e27Sflorian 	enum sec_status sec;
721ae8c6e27Sflorian 
722ae8c6e27Sflorian 	if(ta_ds && (dnskey_rrset->rk.dname_len != ta_ds->rk.dname_len ||
723ae8c6e27Sflorian 		query_dname_compare(dnskey_rrset->rk.dname, ta_ds->rk.dname)
724ae8c6e27Sflorian 		!= 0)) {
725ae8c6e27Sflorian 		verbose(VERB_QUERY, "DNSKEY RRset did not match DS RRset "
726ae8c6e27Sflorian 			"by name");
727ae8c6e27Sflorian 		*reason = "DNSKEY RRset did not match DS RRset by name";
7287a05b9dfSflorian 		if(reason_bogus)
7297a05b9dfSflorian 			*reason_bogus = LDNS_EDE_DNSKEY_MISSING;
730ae8c6e27Sflorian 		return sec_status_bogus;
731ae8c6e27Sflorian 	}
732ae8c6e27Sflorian 	if(ta_dnskey && (dnskey_rrset->rk.dname_len != ta_dnskey->rk.dname_len
733ae8c6e27Sflorian 	     || query_dname_compare(dnskey_rrset->rk.dname, ta_dnskey->rk.dname)
734ae8c6e27Sflorian 		!= 0)) {
735ae8c6e27Sflorian 		verbose(VERB_QUERY, "DNSKEY RRset did not match anchor RRset "
736ae8c6e27Sflorian 			"by name");
737ae8c6e27Sflorian 		*reason = "DNSKEY RRset did not match anchor RRset by name";
7387a05b9dfSflorian 		if(reason_bogus)
7397a05b9dfSflorian 			*reason_bogus = LDNS_EDE_DNSKEY_MISSING;
740ae8c6e27Sflorian 		return sec_status_bogus;
741ae8c6e27Sflorian 	}
742ae8c6e27Sflorian 
743ae8c6e27Sflorian 	if(ta_ds)
744ae8c6e27Sflorian 		digest_algo = val_favorite_ds_algo(ta_ds);
745ae8c6e27Sflorian 	if(sigalg) {
746ae8c6e27Sflorian 		if(ta_ds)
747ae8c6e27Sflorian 			algo_needs_init_ds(&needs, ta_ds, digest_algo, sigalg);
748ae8c6e27Sflorian 		else	memset(&needs, 0, sizeof(needs));
749ae8c6e27Sflorian 		if(ta_dnskey)
750ae8c6e27Sflorian 			algo_needs_init_dnskey_add(&needs, ta_dnskey, sigalg);
751ae8c6e27Sflorian 	}
752ae8c6e27Sflorian 	if(ta_ds) {
753ae8c6e27Sflorian 	    num = rrset_get_count(ta_ds);
754ae8c6e27Sflorian 	    for(i=0; i<num; i++) {
755ae8c6e27Sflorian 		/* Check to see if we can understand this DS.
756ae8c6e27Sflorian 		 * And check it is the strongest digest */
757ae8c6e27Sflorian 		if(!ds_digest_algo_is_supported(ta_ds, i) ||
758ae8c6e27Sflorian 			!ds_key_algo_is_supported(ta_ds, i) ||
759ae8c6e27Sflorian 			ds_get_digest_algo(ta_ds, i) != digest_algo)
760ae8c6e27Sflorian 			continue;
761ae8c6e27Sflorian 
762411c5950Sflorian 		sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
763*7037e34cSflorian 			ta_ds, i, reason, reason_bogus, qstate, &nonechecked,
764*7037e34cSflorian 			reasonbuf, reasonlen);
76554cc57acSflorian 		if(sec == sec_status_insecure) {
76654cc57acSflorian 			has_algo_refusal = 1;
767411c5950Sflorian 			continue;
76854cc57acSflorian 		}
76954cc57acSflorian 		if(!nonechecked)
77054cc57acSflorian 			has_checked_ds = 1;
771411c5950Sflorian 
772ae8c6e27Sflorian 		/* Once we see a single DS with a known digestID and
773ae8c6e27Sflorian 		 * algorithm, we cannot return INSECURE (with a
774ae8c6e27Sflorian 		 * "null" KeyEntry). */
775ae8c6e27Sflorian 		has_useful_ta = 1;
776ae8c6e27Sflorian 
777ae8c6e27Sflorian 		if(sec == sec_status_secure) {
778ae8c6e27Sflorian 			if(!sigalg || algo_needs_set_secure(&needs,
779ae8c6e27Sflorian 				(uint8_t)ds_get_key_algo(ta_ds, i))) {
780ae8c6e27Sflorian 				verbose(VERB_ALGO, "DS matched DNSKEY.");
781411c5950Sflorian 				if(!dnskeyset_size_is_supported(dnskey_rrset)) {
782411c5950Sflorian 					verbose(VERB_ALGO, "trustanchor works, but dnskeyset contain keys that are unsupported, treat as insecure");
783411c5950Sflorian 					return sec_status_insecure;
784411c5950Sflorian 				}
785ae8c6e27Sflorian 				return sec_status_secure;
786ae8c6e27Sflorian 			}
787ae8c6e27Sflorian 		} else if(sigalg && sec == sec_status_bogus) {
788ae8c6e27Sflorian 			algo_needs_set_bogus(&needs,
789ae8c6e27Sflorian 				(uint8_t)ds_get_key_algo(ta_ds, i));
790ae8c6e27Sflorian 		}
791ae8c6e27Sflorian 	    }
792ae8c6e27Sflorian 	}
793ae8c6e27Sflorian 
794ae8c6e27Sflorian 	/* None of the DS's worked out: check the DNSKEYs. */
795ae8c6e27Sflorian 	if(ta_dnskey) {
796ae8c6e27Sflorian 	    num = rrset_get_count(ta_dnskey);
797ae8c6e27Sflorian 	    for(i=0; i<num; i++) {
798ae8c6e27Sflorian 		/* Check to see if we can understand this DNSKEY */
799ae8c6e27Sflorian 		if(!dnskey_algo_is_supported(ta_dnskey, i))
800ae8c6e27Sflorian 			continue;
801411c5950Sflorian 		if(!dnskey_size_is_supported(ta_dnskey, i))
802411c5950Sflorian 			continue;
803ae8c6e27Sflorian 
804ae8c6e27Sflorian 		/* we saw a useful TA */
805ae8c6e27Sflorian 		has_useful_ta = 1;
806ae8c6e27Sflorian 
807ae8c6e27Sflorian 		sec = dnskey_verify_rrset(env, ve, dnskey_rrset,
808d500c338Sflorian 			ta_dnskey, i, reason, reason_bogus, LDNS_SECTION_ANSWER, qstate);
809ae8c6e27Sflorian 		if(sec == sec_status_secure) {
810ae8c6e27Sflorian 			if(!sigalg || algo_needs_set_secure(&needs,
811ae8c6e27Sflorian 				(uint8_t)dnskey_get_algo(ta_dnskey, i))) {
812ae8c6e27Sflorian 				verbose(VERB_ALGO, "anchor matched DNSKEY.");
813411c5950Sflorian 				if(!dnskeyset_size_is_supported(dnskey_rrset)) {
814411c5950Sflorian 					verbose(VERB_ALGO, "trustanchor works, but dnskeyset contain keys that are unsupported, treat as insecure");
815411c5950Sflorian 					return sec_status_insecure;
816411c5950Sflorian 				}
817ae8c6e27Sflorian 				return sec_status_secure;
818ae8c6e27Sflorian 			}
819ae8c6e27Sflorian 		} else if(sigalg && sec == sec_status_bogus) {
820ae8c6e27Sflorian 			algo_needs_set_bogus(&needs,
821ae8c6e27Sflorian 				(uint8_t)dnskey_get_algo(ta_dnskey, i));
822ae8c6e27Sflorian 		}
823ae8c6e27Sflorian 	    }
824ae8c6e27Sflorian 	}
825ae8c6e27Sflorian 
82654cc57acSflorian 	/* If none of the DSes have been checked, eg. that means no matches
82754cc57acSflorian 	 * for keytags, and the other dses are all algo_refusal, it is an
82854cc57acSflorian 	 * insecure delegation point, since the only matched DS records
82954cc57acSflorian 	 * have an algo refusal, or are unsupported. */
83054cc57acSflorian 	if(has_algo_refusal && !has_checked_ds) {
83154cc57acSflorian 		verbose(VERB_ALGO, "No supported trust anchors were found -- "
83254cc57acSflorian 			"treating as insecure.");
83354cc57acSflorian 		return sec_status_insecure;
83454cc57acSflorian 	}
835ae8c6e27Sflorian 	/* If no DSs were understandable, then this is OK. */
836ae8c6e27Sflorian 	if(!has_useful_ta) {
837ae8c6e27Sflorian 		verbose(VERB_ALGO, "No usable trust anchors were found -- "
838ae8c6e27Sflorian 			"treating as insecure.");
839ae8c6e27Sflorian 		return sec_status_insecure;
840ae8c6e27Sflorian 	}
841ae8c6e27Sflorian 	/* If any were understandable, then it is bad. */
842ae8c6e27Sflorian 	verbose(VERB_QUERY, "Failed to match any usable anchor to a DNSKEY.");
843ae8c6e27Sflorian 	if(sigalg && (alg=algo_needs_missing(&needs)) != 0) {
844*7037e34cSflorian 		algo_needs_reason(alg, reason, "missing verification of "
845*7037e34cSflorian 			"DNSKEY signature", reasonbuf, reasonlen);
846ae8c6e27Sflorian 	}
847ae8c6e27Sflorian 	return sec_status_bogus;
848ae8c6e27Sflorian }
849ae8c6e27Sflorian 
850ae8c6e27Sflorian struct key_entry_key*
851ae8c6e27Sflorian val_verify_new_DNSKEYs_with_ta(struct regional* region, struct module_env* env,
852ae8c6e27Sflorian 	struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
853ae8c6e27Sflorian 	struct ub_packed_rrset_key* ta_ds_rrset,
854ae8c6e27Sflorian 	struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
855*7037e34cSflorian 	char** reason, sldns_ede_code *reason_bogus,
856*7037e34cSflorian 	struct module_qstate* qstate, char* reasonbuf, size_t reasonlen)
857ae8c6e27Sflorian {
858ae8c6e27Sflorian 	uint8_t sigalg[ALGO_NEEDS_MAX+1];
859ae8c6e27Sflorian 	enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve,
860ae8c6e27Sflorian 		dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset,
861*7037e34cSflorian 		downprot?sigalg:NULL, reason, reason_bogus, qstate,
862*7037e34cSflorian 		reasonbuf, reasonlen);
863ae8c6e27Sflorian 
864ae8c6e27Sflorian 	if(sec == sec_status_secure) {
865ae8c6e27Sflorian 		return key_entry_create_rrset(region,
866ae8c6e27Sflorian 			dnskey_rrset->rk.dname, dnskey_rrset->rk.dname_len,
867ae8c6e27Sflorian 			ntohs(dnskey_rrset->rk.rrset_class), dnskey_rrset,
868d500c338Sflorian 			downprot?sigalg:NULL, LDNS_EDE_NONE, NULL, *env->now);
869ae8c6e27Sflorian 	} else if(sec == sec_status_insecure) {
870ae8c6e27Sflorian 		return key_entry_create_null(region, dnskey_rrset->rk.dname,
871ae8c6e27Sflorian 			dnskey_rrset->rk.dname_len,
872ae8c6e27Sflorian 			ntohs(dnskey_rrset->rk.rrset_class),
873d500c338Sflorian 			rrset_get_ttl(dnskey_rrset), *reason_bogus, *reason,
874d500c338Sflorian 			*env->now);
875ae8c6e27Sflorian 	}
876ae8c6e27Sflorian 	return key_entry_create_bad(region, dnskey_rrset->rk.dname,
877ae8c6e27Sflorian 		dnskey_rrset->rk.dname_len, ntohs(dnskey_rrset->rk.rrset_class),
878d500c338Sflorian 		BOGUS_KEY_TTL, *reason_bogus, *reason, *env->now);
879ae8c6e27Sflorian }
880ae8c6e27Sflorian 
881ae8c6e27Sflorian int
882ae8c6e27Sflorian val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset)
883ae8c6e27Sflorian {
884ae8c6e27Sflorian 	size_t i;
885ae8c6e27Sflorian 	for(i=0; i<rrset_get_count(ds_rrset); i++) {
886ae8c6e27Sflorian 		if(ds_digest_algo_is_supported(ds_rrset, i) &&
887ae8c6e27Sflorian 			ds_key_algo_is_supported(ds_rrset, i))
888ae8c6e27Sflorian 			return 1;
889ae8c6e27Sflorian 	}
890ae8c6e27Sflorian 	if(verbosity < VERB_ALGO)
891ae8c6e27Sflorian 		return 0;
892ae8c6e27Sflorian 	if(rrset_get_count(ds_rrset) == 0)
893ae8c6e27Sflorian 		verbose(VERB_ALGO, "DS is not usable");
894ae8c6e27Sflorian 	else {
895ae8c6e27Sflorian 		/* report usability for the first DS RR */
896ae8c6e27Sflorian 		sldns_lookup_table *lt;
897ae8c6e27Sflorian 		char herr[64], aerr[64];
898ae8c6e27Sflorian 		lt = sldns_lookup_by_id(sldns_hashes,
899a1a7ba80Sflorian 			(int)ds_get_digest_algo(ds_rrset, 0));
900ae8c6e27Sflorian 		if(lt) snprintf(herr, sizeof(herr), "%s", lt->name);
901ae8c6e27Sflorian 		else snprintf(herr, sizeof(herr), "%d",
902a1a7ba80Sflorian 			(int)ds_get_digest_algo(ds_rrset, 0));
903ae8c6e27Sflorian 		lt = sldns_lookup_by_id(sldns_algorithms,
904a1a7ba80Sflorian 			(int)ds_get_key_algo(ds_rrset, 0));
905ae8c6e27Sflorian 		if(lt) snprintf(aerr, sizeof(aerr), "%s", lt->name);
906ae8c6e27Sflorian 		else snprintf(aerr, sizeof(aerr), "%d",
907a1a7ba80Sflorian 			(int)ds_get_key_algo(ds_rrset, 0));
9087a05b9dfSflorian 
909ae8c6e27Sflorian 		verbose(VERB_ALGO, "DS unsupported, hash %s %s, "
910ae8c6e27Sflorian 			"key algorithm %s %s", herr,
911ae8c6e27Sflorian 			(ds_digest_algo_is_supported(ds_rrset, 0)?
912ae8c6e27Sflorian 			"(supported)":"(unsupported)"), aerr,
913ae8c6e27Sflorian 			(ds_key_algo_is_supported(ds_rrset, 0)?
914ae8c6e27Sflorian 			"(supported)":"(unsupported)"));
915ae8c6e27Sflorian 	}
916ae8c6e27Sflorian 	return 0;
917ae8c6e27Sflorian }
918ae8c6e27Sflorian 
919ae8c6e27Sflorian /** get label count for a signature */
920ae8c6e27Sflorian static uint8_t
921ae8c6e27Sflorian rrsig_get_labcount(struct packed_rrset_data* d, size_t sig)
922ae8c6e27Sflorian {
923ae8c6e27Sflorian 	if(d->rr_len[sig] < 2+4)
924ae8c6e27Sflorian 		return 0; /* bad sig length */
925ae8c6e27Sflorian 	return d->rr_data[sig][2+3];
926ae8c6e27Sflorian }
927ae8c6e27Sflorian 
928ae8c6e27Sflorian int
929ae8c6e27Sflorian val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc,
930ae8c6e27Sflorian 	size_t* wc_len)
931ae8c6e27Sflorian {
932ae8c6e27Sflorian 	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
933ae8c6e27Sflorian 		entry.data;
934ae8c6e27Sflorian 	uint8_t labcount;
935ae8c6e27Sflorian 	int labdiff;
936ae8c6e27Sflorian 	uint8_t* wn;
937ae8c6e27Sflorian 	size_t i, wl;
938ae8c6e27Sflorian 	if(d->rrsig_count == 0) {
939ae8c6e27Sflorian 		return 1;
940ae8c6e27Sflorian 	}
941ae8c6e27Sflorian 	labcount = rrsig_get_labcount(d, d->count + 0);
942ae8c6e27Sflorian 	/* check rest of signatures identical */
943ae8c6e27Sflorian 	for(i=1; i<d->rrsig_count; i++) {
944ae8c6e27Sflorian 		if(labcount != rrsig_get_labcount(d, d->count + i)) {
945ae8c6e27Sflorian 			return 0;
946ae8c6e27Sflorian 		}
947ae8c6e27Sflorian 	}
948ae8c6e27Sflorian 	/* OK the rrsigs check out */
949ae8c6e27Sflorian 	/* if the RRSIG label count is shorter than the number of actual
950ae8c6e27Sflorian 	 * labels, then this rrset was synthesized from a wildcard.
951ae8c6e27Sflorian 	 * Note that the RRSIG label count doesn't count the root label. */
952ae8c6e27Sflorian 	wn = rrset->rk.dname;
953ae8c6e27Sflorian 	wl = rrset->rk.dname_len;
954ae8c6e27Sflorian 	/* skip a leading wildcard label in the dname (RFC4035 2.2) */
955ae8c6e27Sflorian 	if(dname_is_wild(wn)) {
956ae8c6e27Sflorian 		wn += 2;
957ae8c6e27Sflorian 		wl -= 2;
958ae8c6e27Sflorian 	}
959ae8c6e27Sflorian 	labdiff = (dname_count_labels(wn) - 1) - (int)labcount;
960ae8c6e27Sflorian 	if(labdiff > 0) {
961ae8c6e27Sflorian 		*wc = wn;
962ae8c6e27Sflorian 		dname_remove_labels(wc, &wl, labdiff);
963ae8c6e27Sflorian 		*wc_len = wl;
964ae8c6e27Sflorian 		return 1;
965ae8c6e27Sflorian 	}
966ae8c6e27Sflorian 	return 1;
967ae8c6e27Sflorian }
968ae8c6e27Sflorian 
969ae8c6e27Sflorian int
970ae8c6e27Sflorian val_chase_cname(struct query_info* qchase, struct reply_info* rep,
971ae8c6e27Sflorian 	size_t* cname_skip) {
972ae8c6e27Sflorian 	size_t i;
973ae8c6e27Sflorian 	/* skip any DNAMEs, go to the CNAME for next part */
974ae8c6e27Sflorian 	for(i = *cname_skip; i < rep->an_numrrsets; i++) {
975ae8c6e27Sflorian 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME &&
976ae8c6e27Sflorian 			query_dname_compare(qchase->qname, rep->rrsets[i]->
977ae8c6e27Sflorian 				rk.dname) == 0) {
978ae8c6e27Sflorian 			qchase->qname = NULL;
979ae8c6e27Sflorian 			get_cname_target(rep->rrsets[i], &qchase->qname,
980ae8c6e27Sflorian 				&qchase->qname_len);
981ae8c6e27Sflorian 			if(!qchase->qname)
982ae8c6e27Sflorian 				return 0; /* bad CNAME rdata */
983ae8c6e27Sflorian 			(*cname_skip) = i+1;
984ae8c6e27Sflorian 			return 1;
985ae8c6e27Sflorian 		}
986ae8c6e27Sflorian 	}
987ae8c6e27Sflorian 	return 0; /* CNAME classified but no matching CNAME ?! */
988ae8c6e27Sflorian }
989ae8c6e27Sflorian 
990ae8c6e27Sflorian /** see if rrset has signer name as one of the rrsig signers */
991ae8c6e27Sflorian static int
992ae8c6e27Sflorian rrset_has_signer(struct ub_packed_rrset_key* rrset, uint8_t* name, size_t len)
993ae8c6e27Sflorian {
994ae8c6e27Sflorian 	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
995ae8c6e27Sflorian 		entry.data;
996ae8c6e27Sflorian 	size_t i;
997ae8c6e27Sflorian 	for(i = d->count; i< d->count+d->rrsig_count; i++) {
998ae8c6e27Sflorian 		if(d->rr_len[i] > 2+18+len) {
999ae8c6e27Sflorian 			/* at least rdatalen + signature + signame (+1 sig)*/
1000ae8c6e27Sflorian 			if(!dname_valid(d->rr_data[i]+2+18, d->rr_len[i]-2-18))
1001ae8c6e27Sflorian 				continue;
1002ae8c6e27Sflorian 			if(query_dname_compare(name, d->rr_data[i]+2+18) == 0)
1003ae8c6e27Sflorian 			{
1004ae8c6e27Sflorian 				return 1;
1005ae8c6e27Sflorian 			}
1006ae8c6e27Sflorian 		}
1007ae8c6e27Sflorian 	}
1008ae8c6e27Sflorian 	return 0;
1009ae8c6e27Sflorian }
1010ae8c6e27Sflorian 
1011ae8c6e27Sflorian void
1012ae8c6e27Sflorian val_fill_reply(struct reply_info* chase, struct reply_info* orig,
1013ae8c6e27Sflorian 	size_t skip, uint8_t* name, size_t len, uint8_t* signer)
1014ae8c6e27Sflorian {
1015*7037e34cSflorian 	size_t i, j;
1016ae8c6e27Sflorian 	int seen_dname = 0;
1017ae8c6e27Sflorian 	chase->rrset_count = 0;
1018ae8c6e27Sflorian 	chase->an_numrrsets = 0;
1019ae8c6e27Sflorian 	chase->ns_numrrsets = 0;
1020ae8c6e27Sflorian 	chase->ar_numrrsets = 0;
1021ae8c6e27Sflorian 	/* ANSWER section */
1022ae8c6e27Sflorian 	for(i=skip; i<orig->an_numrrsets; i++) {
1023ae8c6e27Sflorian 		if(!signer) {
1024ae8c6e27Sflorian 			if(query_dname_compare(name,
1025ae8c6e27Sflorian 				orig->rrsets[i]->rk.dname) == 0)
1026ae8c6e27Sflorian 				chase->rrsets[chase->an_numrrsets++] =
1027ae8c6e27Sflorian 					orig->rrsets[i];
1028ae8c6e27Sflorian 		} else if(seen_dname && ntohs(orig->rrsets[i]->rk.type) ==
1029ae8c6e27Sflorian 			LDNS_RR_TYPE_CNAME) {
1030ae8c6e27Sflorian 			chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i];
1031ae8c6e27Sflorian 			seen_dname = 0;
1032ae8c6e27Sflorian 		} else if(rrset_has_signer(orig->rrsets[i], name, len)) {
1033ae8c6e27Sflorian 			chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i];
1034ae8c6e27Sflorian 			if(ntohs(orig->rrsets[i]->rk.type) ==
1035ae8c6e27Sflorian 				LDNS_RR_TYPE_DNAME) {
1036ae8c6e27Sflorian 					seen_dname = 1;
1037ae8c6e27Sflorian 			}
1038*7037e34cSflorian 		} else if(ntohs(orig->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME
1039*7037e34cSflorian 			&& ((struct packed_rrset_data*)orig->rrsets[i]->
1040*7037e34cSflorian 			entry.data)->rrsig_count == 0 &&
1041*7037e34cSflorian 			cname_under_previous_dname(orig, i, &j) &&
1042*7037e34cSflorian 			rrset_has_signer(orig->rrsets[j], name, len)) {
1043*7037e34cSflorian 			chase->rrsets[chase->an_numrrsets++] = orig->rrsets[j];
1044*7037e34cSflorian 			chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i];
1045ae8c6e27Sflorian 		}
1046ae8c6e27Sflorian 	}
1047ae8c6e27Sflorian 	/* AUTHORITY section */
1048ae8c6e27Sflorian 	for(i = (skip > orig->an_numrrsets)?skip:orig->an_numrrsets;
1049ae8c6e27Sflorian 		i<orig->an_numrrsets+orig->ns_numrrsets;
1050ae8c6e27Sflorian 		i++) {
1051ae8c6e27Sflorian 		if(!signer) {
1052ae8c6e27Sflorian 			if(query_dname_compare(name,
1053ae8c6e27Sflorian 				orig->rrsets[i]->rk.dname) == 0)
1054ae8c6e27Sflorian 				chase->rrsets[chase->an_numrrsets+
1055ae8c6e27Sflorian 				    chase->ns_numrrsets++] = orig->rrsets[i];
1056ae8c6e27Sflorian 		} else if(rrset_has_signer(orig->rrsets[i], name, len)) {
1057ae8c6e27Sflorian 			chase->rrsets[chase->an_numrrsets+
1058ae8c6e27Sflorian 				chase->ns_numrrsets++] = orig->rrsets[i];
1059ae8c6e27Sflorian 		}
1060ae8c6e27Sflorian 	}
1061ae8c6e27Sflorian 	/* ADDITIONAL section */
1062ae8c6e27Sflorian 	for(i= (skip>orig->an_numrrsets+orig->ns_numrrsets)?
1063ae8c6e27Sflorian 		skip:orig->an_numrrsets+orig->ns_numrrsets;
1064ae8c6e27Sflorian 		i<orig->rrset_count; i++) {
1065ae8c6e27Sflorian 		if(!signer) {
1066ae8c6e27Sflorian 			if(query_dname_compare(name,
1067ae8c6e27Sflorian 				orig->rrsets[i]->rk.dname) == 0)
1068ae8c6e27Sflorian 			    chase->rrsets[chase->an_numrrsets
1069ae8c6e27Sflorian 				+orig->ns_numrrsets+chase->ar_numrrsets++]
1070ae8c6e27Sflorian 				= orig->rrsets[i];
1071ae8c6e27Sflorian 		} else if(rrset_has_signer(orig->rrsets[i], name, len)) {
1072ae8c6e27Sflorian 			chase->rrsets[chase->an_numrrsets+orig->ns_numrrsets+
1073ae8c6e27Sflorian 				chase->ar_numrrsets++] = orig->rrsets[i];
1074ae8c6e27Sflorian 		}
1075ae8c6e27Sflorian 	}
1076ae8c6e27Sflorian 	chase->rrset_count = chase->an_numrrsets + chase->ns_numrrsets +
1077ae8c6e27Sflorian 		chase->ar_numrrsets;
1078ae8c6e27Sflorian }
1079ae8c6e27Sflorian 
1080ae8c6e27Sflorian void val_reply_remove_auth(struct reply_info* rep, size_t index)
1081ae8c6e27Sflorian {
1082ae8c6e27Sflorian 	log_assert(index < rep->rrset_count);
1083ae8c6e27Sflorian 	log_assert(index >= rep->an_numrrsets);
1084ae8c6e27Sflorian 	log_assert(index < rep->an_numrrsets+rep->ns_numrrsets);
1085ae8c6e27Sflorian 	memmove(rep->rrsets+index, rep->rrsets+index+1,
1086ae8c6e27Sflorian 		sizeof(struct ub_packed_rrset_key*)*
1087ae8c6e27Sflorian 		(rep->rrset_count - index - 1));
1088ae8c6e27Sflorian 	rep->ns_numrrsets--;
1089ae8c6e27Sflorian 	rep->rrset_count--;
1090ae8c6e27Sflorian }
1091ae8c6e27Sflorian 
1092ae8c6e27Sflorian void
1093ae8c6e27Sflorian val_check_nonsecure(struct module_env* env, struct reply_info* rep)
1094ae8c6e27Sflorian {
1095ae8c6e27Sflorian 	size_t i;
1096ae8c6e27Sflorian 	/* authority */
1097ae8c6e27Sflorian 	for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
1098ae8c6e27Sflorian 		if(((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
1099ae8c6e27Sflorian 			->security != sec_status_secure) {
1100ae8c6e27Sflorian 			/* because we want to return the authentic original
1101ae8c6e27Sflorian 			 * message when presented with CD-flagged queries,
1102ae8c6e27Sflorian 			 * we need to preserve AUTHORITY section data.
1103ae8c6e27Sflorian 			 * However, this rrset is not signed or signed
1104ae8c6e27Sflorian 			 * with the wrong keys. Validation has tried to
1105ae8c6e27Sflorian 			 * verify this rrset with the keysets of import.
1106ae8c6e27Sflorian 			 * But this rrset did not verify.
1107ae8c6e27Sflorian 			 * Therefore the message is bogus.
1108ae8c6e27Sflorian 			 */
1109ae8c6e27Sflorian 
1110ae8c6e27Sflorian 			/* check if authority has an NS record
1111ae8c6e27Sflorian 			 * which is bad, and there is an answer section with
1112ae8c6e27Sflorian 			 * data.  In that case, delete NS and additional to
1113ae8c6e27Sflorian 			 * be lenient and make a minimal response */
1114ae8c6e27Sflorian 			if(rep->an_numrrsets != 0 &&
1115ae8c6e27Sflorian 				ntohs(rep->rrsets[i]->rk.type)
1116ae8c6e27Sflorian 				== LDNS_RR_TYPE_NS) {
1117ae8c6e27Sflorian 				verbose(VERB_ALGO, "truncate to minimal");
1118ae8c6e27Sflorian 				rep->ar_numrrsets = 0;
1119ae8c6e27Sflorian 				rep->rrset_count = rep->an_numrrsets +
1120ae8c6e27Sflorian 					rep->ns_numrrsets;
1121ae8c6e27Sflorian 				/* remove this unneeded authority rrset */
1122ae8c6e27Sflorian 				memmove(rep->rrsets+i, rep->rrsets+i+1,
1123ae8c6e27Sflorian 					sizeof(struct ub_packed_rrset_key*)*
1124ae8c6e27Sflorian 					(rep->rrset_count - i - 1));
1125ae8c6e27Sflorian 				rep->ns_numrrsets--;
1126ae8c6e27Sflorian 				rep->rrset_count--;
1127ae8c6e27Sflorian 				i--;
1128ae8c6e27Sflorian 				return;
1129ae8c6e27Sflorian 			}
1130ae8c6e27Sflorian 
1131ae8c6e27Sflorian 			log_nametypeclass(VERB_QUERY, "message is bogus, "
1132ae8c6e27Sflorian 				"non secure rrset",
1133ae8c6e27Sflorian 				rep->rrsets[i]->rk.dname,
1134ae8c6e27Sflorian 				ntohs(rep->rrsets[i]->rk.type),
1135ae8c6e27Sflorian 				ntohs(rep->rrsets[i]->rk.rrset_class));
1136ae8c6e27Sflorian 			rep->security = sec_status_bogus;
1137ae8c6e27Sflorian 			return;
1138ae8c6e27Sflorian 		}
1139ae8c6e27Sflorian 	}
1140ae8c6e27Sflorian 	/* additional */
1141ae8c6e27Sflorian 	if(!env->cfg->val_clean_additional)
1142ae8c6e27Sflorian 		return;
1143ae8c6e27Sflorian 	for(i=rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
1144ae8c6e27Sflorian 		if(((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
1145ae8c6e27Sflorian 			->security != sec_status_secure) {
1146ae8c6e27Sflorian 			/* This does not cause message invalidation. It was
1147ae8c6e27Sflorian 			 * simply unsigned data in the additional. The
1148ae8c6e27Sflorian 			 * RRSIG must have been truncated off the message.
1149ae8c6e27Sflorian 			 *
1150ae8c6e27Sflorian 			 * However, we do not want to return possible bogus
1151ae8c6e27Sflorian 			 * data to clients that rely on this service for
1152ae8c6e27Sflorian 			 * their authentication.
1153ae8c6e27Sflorian 			 */
1154ae8c6e27Sflorian 			/* remove this unneeded additional rrset */
1155ae8c6e27Sflorian 			memmove(rep->rrsets+i, rep->rrsets+i+1,
1156ae8c6e27Sflorian 				sizeof(struct ub_packed_rrset_key*)*
1157ae8c6e27Sflorian 				(rep->rrset_count - i - 1));
1158ae8c6e27Sflorian 			rep->ar_numrrsets--;
1159ae8c6e27Sflorian 			rep->rrset_count--;
1160ae8c6e27Sflorian 			i--;
1161ae8c6e27Sflorian 		}
1162ae8c6e27Sflorian 	}
1163ae8c6e27Sflorian }
1164ae8c6e27Sflorian 
1165ae8c6e27Sflorian /** check no anchor and unlock */
1166ae8c6e27Sflorian static int
1167ae8c6e27Sflorian check_no_anchor(struct val_anchors* anchors, uint8_t* nm, size_t l, uint16_t c)
1168ae8c6e27Sflorian {
1169ae8c6e27Sflorian 	struct trust_anchor* ta;
1170ae8c6e27Sflorian 	if((ta=anchors_lookup(anchors, nm, l, c))) {
1171ae8c6e27Sflorian 		lock_basic_unlock(&ta->lock);
1172ae8c6e27Sflorian 	}
1173ae8c6e27Sflorian 	return !ta;
1174ae8c6e27Sflorian }
1175ae8c6e27Sflorian 
1176ae8c6e27Sflorian void
1177ae8c6e27Sflorian val_mark_indeterminate(struct reply_info* rep, struct val_anchors* anchors,
1178ae8c6e27Sflorian 	struct rrset_cache* r, struct module_env* env)
1179ae8c6e27Sflorian {
1180ae8c6e27Sflorian 	size_t i;
1181ae8c6e27Sflorian 	struct packed_rrset_data* d;
1182ae8c6e27Sflorian 	for(i=0; i<rep->rrset_count; i++) {
1183ae8c6e27Sflorian 		d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
1184ae8c6e27Sflorian 		if(d->security == sec_status_unchecked &&
1185ae8c6e27Sflorian 		   check_no_anchor(anchors, rep->rrsets[i]->rk.dname,
1186ae8c6e27Sflorian 			rep->rrsets[i]->rk.dname_len,
1187ae8c6e27Sflorian 			ntohs(rep->rrsets[i]->rk.rrset_class)))
1188ae8c6e27Sflorian 		{
1189ae8c6e27Sflorian 			/* mark as indeterminate */
1190ae8c6e27Sflorian 			d->security = sec_status_indeterminate;
1191ae8c6e27Sflorian 			rrset_update_sec_status(r, rep->rrsets[i], *env->now);
1192ae8c6e27Sflorian 		}
1193ae8c6e27Sflorian 	}
1194ae8c6e27Sflorian }
1195ae8c6e27Sflorian 
1196ae8c6e27Sflorian void
1197ae8c6e27Sflorian val_mark_insecure(struct reply_info* rep, uint8_t* kname,
1198ae8c6e27Sflorian 	struct rrset_cache* r, struct module_env* env)
1199ae8c6e27Sflorian {
1200ae8c6e27Sflorian 	size_t i;
1201ae8c6e27Sflorian 	struct packed_rrset_data* d;
1202ae8c6e27Sflorian 	for(i=0; i<rep->rrset_count; i++) {
1203ae8c6e27Sflorian 		d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
1204ae8c6e27Sflorian 		if(d->security == sec_status_unchecked &&
1205ae8c6e27Sflorian 		   dname_subdomain_c(rep->rrsets[i]->rk.dname, kname)) {
1206ae8c6e27Sflorian 			/* mark as insecure */
1207ae8c6e27Sflorian 			d->security = sec_status_insecure;
1208ae8c6e27Sflorian 			rrset_update_sec_status(r, rep->rrsets[i], *env->now);
1209ae8c6e27Sflorian 		}
1210ae8c6e27Sflorian 	}
1211ae8c6e27Sflorian }
1212ae8c6e27Sflorian 
1213ae8c6e27Sflorian size_t
1214ae8c6e27Sflorian val_next_unchecked(struct reply_info* rep, size_t skip)
1215ae8c6e27Sflorian {
1216ae8c6e27Sflorian 	size_t i;
1217ae8c6e27Sflorian 	struct packed_rrset_data* d;
1218ae8c6e27Sflorian 	for(i=skip+1; i<rep->rrset_count; i++) {
1219ae8c6e27Sflorian 		d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
1220ae8c6e27Sflorian 		if(d->security == sec_status_unchecked) {
1221ae8c6e27Sflorian 			return i;
1222ae8c6e27Sflorian 		}
1223ae8c6e27Sflorian 	}
1224ae8c6e27Sflorian 	return rep->rrset_count;
1225ae8c6e27Sflorian }
1226ae8c6e27Sflorian 
1227ae8c6e27Sflorian const char*
1228ae8c6e27Sflorian val_classification_to_string(enum val_classification subtype)
1229ae8c6e27Sflorian {
1230ae8c6e27Sflorian 	switch(subtype) {
1231ae8c6e27Sflorian 		case VAL_CLASS_UNTYPED: 	return "untyped";
1232ae8c6e27Sflorian 		case VAL_CLASS_UNKNOWN: 	return "unknown";
1233ae8c6e27Sflorian 		case VAL_CLASS_POSITIVE: 	return "positive";
1234ae8c6e27Sflorian 		case VAL_CLASS_CNAME: 		return "cname";
1235ae8c6e27Sflorian 		case VAL_CLASS_NODATA: 		return "nodata";
1236ae8c6e27Sflorian 		case VAL_CLASS_NAMEERROR: 	return "nameerror";
1237ae8c6e27Sflorian 		case VAL_CLASS_CNAMENOANSWER: 	return "cnamenoanswer";
1238ae8c6e27Sflorian 		case VAL_CLASS_REFERRAL: 	return "referral";
1239ae8c6e27Sflorian 		case VAL_CLASS_ANY: 		return "qtype_any";
1240ae8c6e27Sflorian 		default:
1241ae8c6e27Sflorian 			return "bad_val_classification";
1242ae8c6e27Sflorian 	}
1243ae8c6e27Sflorian }
1244ae8c6e27Sflorian 
1245ae8c6e27Sflorian /** log a sock_list entry */
1246ae8c6e27Sflorian static void
1247ae8c6e27Sflorian sock_list_logentry(enum verbosity_value v, const char* s, struct sock_list* p)
1248ae8c6e27Sflorian {
1249ae8c6e27Sflorian 	if(p->len)
1250ae8c6e27Sflorian 		log_addr(v, s, &p->addr, p->len);
1251ae8c6e27Sflorian 	else	verbose(v, "%s cache", s);
1252ae8c6e27Sflorian }
1253ae8c6e27Sflorian 
1254ae8c6e27Sflorian void val_blacklist(struct sock_list** blacklist, struct regional* region,
1255ae8c6e27Sflorian 	struct sock_list* origin, int cross)
1256ae8c6e27Sflorian {
1257ae8c6e27Sflorian 	/* debug printout */
1258ae8c6e27Sflorian 	if(verbosity >= VERB_ALGO) {
1259ae8c6e27Sflorian 		struct sock_list* p;
1260ae8c6e27Sflorian 		for(p=*blacklist; p; p=p->next)
1261ae8c6e27Sflorian 			sock_list_logentry(VERB_ALGO, "blacklist", p);
1262ae8c6e27Sflorian 		if(!origin)
1263ae8c6e27Sflorian 			verbose(VERB_ALGO, "blacklist add: cache");
1264ae8c6e27Sflorian 		for(p=origin; p; p=p->next)
1265ae8c6e27Sflorian 			sock_list_logentry(VERB_ALGO, "blacklist add", p);
1266ae8c6e27Sflorian 	}
1267ae8c6e27Sflorian 	/* blacklist the IPs or the cache */
1268ae8c6e27Sflorian 	if(!origin) {
1269ae8c6e27Sflorian 		/* only add if nothing there. anything else also stops cache*/
1270ae8c6e27Sflorian 		if(!*blacklist)
1271ae8c6e27Sflorian 			sock_list_insert(blacklist, NULL, 0, region);
1272ae8c6e27Sflorian 	} else if(!cross)
1273ae8c6e27Sflorian 		sock_list_prepend(blacklist, origin);
1274ae8c6e27Sflorian 	else	sock_list_merge(blacklist, region, origin);
1275ae8c6e27Sflorian }
1276ae8c6e27Sflorian 
1277ae8c6e27Sflorian int val_has_signed_nsecs(struct reply_info* rep, char** reason)
1278ae8c6e27Sflorian {
1279ae8c6e27Sflorian 	size_t i, num_nsec = 0, num_nsec3 = 0;
1280ae8c6e27Sflorian 	struct packed_rrset_data* d;
1281ae8c6e27Sflorian 	for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
1282ae8c6e27Sflorian 		if(rep->rrsets[i]->rk.type == htons(LDNS_RR_TYPE_NSEC))
1283ae8c6e27Sflorian 			num_nsec++;
1284ae8c6e27Sflorian 		else if(rep->rrsets[i]->rk.type == htons(LDNS_RR_TYPE_NSEC3))
1285ae8c6e27Sflorian 			num_nsec3++;
1286ae8c6e27Sflorian 		else continue;
1287ae8c6e27Sflorian 		d = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
1288ae8c6e27Sflorian 		if(d && d->rrsig_count != 0) {
1289ae8c6e27Sflorian 			return 1;
1290ae8c6e27Sflorian 		}
1291ae8c6e27Sflorian 	}
1292ae8c6e27Sflorian 	if(num_nsec == 0 && num_nsec3 == 0)
1293ae8c6e27Sflorian 		*reason = "no DNSSEC records";
1294ae8c6e27Sflorian 	else if(num_nsec != 0)
1295ae8c6e27Sflorian 		*reason = "no signatures over NSECs";
1296ae8c6e27Sflorian 	else	*reason = "no signatures over NSEC3s";
1297ae8c6e27Sflorian 	return 0;
1298ae8c6e27Sflorian }
1299ae8c6e27Sflorian 
1300ae8c6e27Sflorian struct dns_msg*
1301ae8c6e27Sflorian val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t c,
1302ae8c6e27Sflorian 	struct regional* region, uint8_t* topname)
1303ae8c6e27Sflorian {
1304ae8c6e27Sflorian 	struct dns_msg* msg;
1305ae8c6e27Sflorian 	struct query_info qinfo;
1306ae8c6e27Sflorian 	struct ub_packed_rrset_key *rrset = rrset_cache_lookup(
1307ae8c6e27Sflorian 		env->rrset_cache, nm, nmlen, LDNS_RR_TYPE_DS, c, 0,
1308ae8c6e27Sflorian 		*env->now, 0);
1309ae8c6e27Sflorian 	if(rrset) {
1310ae8c6e27Sflorian 		/* DS rrset exists. Return it to the validator immediately*/
1311ae8c6e27Sflorian 		struct ub_packed_rrset_key* copy = packed_rrset_copy_region(
1312ae8c6e27Sflorian 			rrset, region, *env->now);
1313ae8c6e27Sflorian 		lock_rw_unlock(&rrset->entry.lock);
1314ae8c6e27Sflorian 		if(!copy)
1315ae8c6e27Sflorian 			return NULL;
1316ae8c6e27Sflorian 		msg = dns_msg_create(nm, nmlen, LDNS_RR_TYPE_DS, c, region, 1);
1317ae8c6e27Sflorian 		if(!msg)
1318ae8c6e27Sflorian 			return NULL;
1319ae8c6e27Sflorian 		msg->rep->rrsets[0] = copy;
1320ae8c6e27Sflorian 		msg->rep->rrset_count++;
1321ae8c6e27Sflorian 		msg->rep->an_numrrsets++;
1322ae8c6e27Sflorian 		return msg;
1323ae8c6e27Sflorian 	}
1324ae8c6e27Sflorian 	/* lookup in rrset and negative cache for NSEC/NSEC3 */
1325ae8c6e27Sflorian 	qinfo.qname = nm;
1326ae8c6e27Sflorian 	qinfo.qname_len = nmlen;
1327ae8c6e27Sflorian 	qinfo.qtype = LDNS_RR_TYPE_DS;
1328ae8c6e27Sflorian 	qinfo.qclass = c;
1329ae8c6e27Sflorian 	qinfo.local_alias = NULL;
1330ae8c6e27Sflorian 	/* do not add SOA to reply message, it is going to be used internal */
1331ae8c6e27Sflorian 	msg = val_neg_getmsg(env->neg_cache, &qinfo, region, env->rrset_cache,
1332ae8c6e27Sflorian 		env->scratch_buffer, *env->now, 0, topname, env->cfg);
1333ae8c6e27Sflorian 	return msg;
1334ae8c6e27Sflorian }
1335