xref: /freebsd/contrib/unbound/testcode/unitverify.c (revision be771a7b7f4580a30d99e41a5bb1b93a385a119d)
1*be771a7bSCy Schubert /*
2*be771a7bSCy Schubert  * testcode/unitverify.c - unit test for signature verification routines.
3*be771a7bSCy Schubert  *
4*be771a7bSCy Schubert  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5*be771a7bSCy Schubert  *
6*be771a7bSCy Schubert  * This software is open source.
7*be771a7bSCy Schubert  *
8*be771a7bSCy Schubert  * Redistribution and use in source and binary forms, with or without
9*be771a7bSCy Schubert  * modification, are permitted provided that the following conditions
10*be771a7bSCy Schubert  * are met:
11*be771a7bSCy Schubert  *
12*be771a7bSCy Schubert  * Redistributions of source code must retain the above copyright notice,
13*be771a7bSCy Schubert  * this list of conditions and the following disclaimer.
14*be771a7bSCy Schubert  *
15*be771a7bSCy Schubert  * Redistributions in binary form must reproduce the above copyright notice,
16*be771a7bSCy Schubert  * this list of conditions and the following disclaimer in the documentation
17*be771a7bSCy Schubert  * and/or other materials provided with the distribution.
18*be771a7bSCy Schubert  *
19*be771a7bSCy Schubert  * Neither the name of the NLNET LABS nor the names of its contributors may
20*be771a7bSCy Schubert  * be used to endorse or promote products derived from this software without
21*be771a7bSCy Schubert  * specific prior written permission.
22*be771a7bSCy Schubert  *
23*be771a7bSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*be771a7bSCy Schubert  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25*be771a7bSCy Schubert  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26*be771a7bSCy Schubert  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27*be771a7bSCy Schubert  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28*be771a7bSCy Schubert  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29*be771a7bSCy Schubert  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30*be771a7bSCy Schubert  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31*be771a7bSCy Schubert  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32*be771a7bSCy Schubert  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*be771a7bSCy Schubert  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*be771a7bSCy Schubert  *
35*be771a7bSCy Schubert  */
36*be771a7bSCy Schubert /**
37*be771a7bSCy Schubert  * \file
38*be771a7bSCy Schubert  * Calls verification unit tests. Exits with code 1 on a failure.
39*be771a7bSCy Schubert  */
40*be771a7bSCy Schubert 
41*be771a7bSCy Schubert #include "config.h"
42*be771a7bSCy Schubert #include "util/log.h"
43*be771a7bSCy Schubert #include "testcode/unitmain.h"
44*be771a7bSCy Schubert #include "validator/val_sigcrypt.h"
45*be771a7bSCy Schubert #include "validator/val_secalgo.h"
46*be771a7bSCy Schubert #include "validator/val_nsec.h"
47*be771a7bSCy Schubert #include "validator/val_nsec3.h"
48*be771a7bSCy Schubert #include "validator/validator.h"
49*be771a7bSCy Schubert #include "testcode/testpkts.h"
50*be771a7bSCy Schubert #include "util/data/msgreply.h"
51*be771a7bSCy Schubert #include "util/data/msgparse.h"
52*be771a7bSCy Schubert #include "util/data/dname.h"
53*be771a7bSCy Schubert #include "util/regional.h"
54*be771a7bSCy Schubert #include "util/alloc.h"
55*be771a7bSCy Schubert #include "util/rbtree.h"
56*be771a7bSCy Schubert #include "util/net_help.h"
57*be771a7bSCy Schubert #include "util/module.h"
58*be771a7bSCy Schubert #include "util/config_file.h"
59*be771a7bSCy Schubert #include "sldns/sbuffer.h"
60*be771a7bSCy Schubert #include "sldns/keyraw.h"
61*be771a7bSCy Schubert #include "sldns/str2wire.h"
62*be771a7bSCy Schubert #include "sldns/wire2str.h"
63*be771a7bSCy Schubert 
64*be771a7bSCy Schubert /** verbose signature test */
65*be771a7bSCy Schubert static int vsig = 0;
66*be771a7bSCy Schubert 
67*be771a7bSCy Schubert /** entry to packet buffer with wireformat */
68*be771a7bSCy Schubert static void
69*be771a7bSCy Schubert entry_to_buf(struct entry* e, sldns_buffer* pkt)
70*be771a7bSCy Schubert {
71*be771a7bSCy Schubert 	unit_assert(e->reply_list);
72*be771a7bSCy Schubert 	if(e->reply_list->reply_from_hex) {
73*be771a7bSCy Schubert 		sldns_buffer_copy(pkt, e->reply_list->reply_from_hex);
74*be771a7bSCy Schubert 	} else {
75*be771a7bSCy Schubert 		sldns_buffer_clear(pkt);
76*be771a7bSCy Schubert 		sldns_buffer_write(pkt, e->reply_list->reply_pkt,
77*be771a7bSCy Schubert 			e->reply_list->reply_len);
78*be771a7bSCy Schubert 		sldns_buffer_flip(pkt);
79*be771a7bSCy Schubert 	}
80*be771a7bSCy Schubert }
81*be771a7bSCy Schubert 
82*be771a7bSCy Schubert /** entry to reply info conversion */
83*be771a7bSCy Schubert static void
84*be771a7bSCy Schubert entry_to_repinfo(struct entry* e, struct alloc_cache* alloc,
85*be771a7bSCy Schubert 	struct regional* region, sldns_buffer* pkt, struct query_info* qi,
86*be771a7bSCy Schubert 	struct reply_info** rep)
87*be771a7bSCy Schubert {
88*be771a7bSCy Schubert 	int ret;
89*be771a7bSCy Schubert 	struct edns_data edns;
90*be771a7bSCy Schubert 	entry_to_buf(e, pkt);
91*be771a7bSCy Schubert 	/* lock alloc lock to please lock checking software.
92*be771a7bSCy Schubert 	 * alloc_special_obtain assumes it is talking to a ub-alloc,
93*be771a7bSCy Schubert 	 * and does not need to perform locking. Here the alloc is
94*be771a7bSCy Schubert 	 * the only one, so we lock it here */
95*be771a7bSCy Schubert 	lock_quick_lock(&alloc->lock);
96*be771a7bSCy Schubert 	ret = reply_info_parse(pkt, alloc, qi, rep, region, &edns);
97*be771a7bSCy Schubert 	lock_quick_unlock(&alloc->lock);
98*be771a7bSCy Schubert 	if(ret != 0) {
99*be771a7bSCy Schubert 		char rcode[16];
100*be771a7bSCy Schubert 		sldns_wire2str_rcode_buf(ret, rcode, sizeof(rcode));
101*be771a7bSCy Schubert 		printf("parse code %d: %s\n", ret, rcode);
102*be771a7bSCy Schubert 		unit_assert(ret != 0);
103*be771a7bSCy Schubert 	}
104*be771a7bSCy Schubert }
105*be771a7bSCy Schubert 
106*be771a7bSCy Schubert /** extract DNSKEY rrset from answer and convert it */
107*be771a7bSCy Schubert static struct ub_packed_rrset_key*
108*be771a7bSCy Schubert extract_keys(struct entry* e, struct alloc_cache* alloc,
109*be771a7bSCy Schubert 	struct regional* region, sldns_buffer* pkt)
110*be771a7bSCy Schubert {
111*be771a7bSCy Schubert 	struct ub_packed_rrset_key* dnskey = NULL;
112*be771a7bSCy Schubert 	struct query_info qinfo;
113*be771a7bSCy Schubert 	struct reply_info* rep = NULL;
114*be771a7bSCy Schubert 	size_t i;
115*be771a7bSCy Schubert 
116*be771a7bSCy Schubert 	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
117*be771a7bSCy Schubert 	for(i=0; i<rep->an_numrrsets; i++) {
118*be771a7bSCy Schubert 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_DNSKEY) {
119*be771a7bSCy Schubert 			dnskey = rep->rrsets[i];
120*be771a7bSCy Schubert 			rep->rrsets[i] = NULL;
121*be771a7bSCy Schubert 			break;
122*be771a7bSCy Schubert 		}
123*be771a7bSCy Schubert 	}
124*be771a7bSCy Schubert 	unit_assert(dnskey);
125*be771a7bSCy Schubert 
126*be771a7bSCy Schubert 	reply_info_parsedelete(rep, alloc);
127*be771a7bSCy Schubert 	query_info_clear(&qinfo);
128*be771a7bSCy Schubert 	return dnskey;
129*be771a7bSCy Schubert }
130*be771a7bSCy Schubert 
131*be771a7bSCy Schubert /** return true if answer should be bogus */
132*be771a7bSCy Schubert static int
133*be771a7bSCy Schubert should_be_bogus(struct ub_packed_rrset_key* rrset, struct query_info* qinfo)
134*be771a7bSCy Schubert {
135*be771a7bSCy Schubert 	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
136*be771a7bSCy Schubert 		entry.data;
137*be771a7bSCy Schubert 	if(d->rrsig_count == 0)
138*be771a7bSCy Schubert 		return 1;
139*be771a7bSCy Schubert 	/* name 'bogus' as first label signals bogus */
140*be771a7bSCy Schubert 	if(rrset->rk.dname_len > 6 && memcmp(rrset->rk.dname+1, "bogus", 5)==0)
141*be771a7bSCy Schubert 		return 1;
142*be771a7bSCy Schubert 	if(qinfo->qname_len > 6 && memcmp(qinfo->qname+1, "bogus", 5)==0)
143*be771a7bSCy Schubert 		return 1;
144*be771a7bSCy Schubert 	return 0;
145*be771a7bSCy Schubert }
146*be771a7bSCy Schubert 
147*be771a7bSCy Schubert /** return number of rrs in an rrset */
148*be771a7bSCy Schubert static size_t
149*be771a7bSCy Schubert rrset_get_count(struct ub_packed_rrset_key* rrset)
150*be771a7bSCy Schubert {
151*be771a7bSCy Schubert 	struct packed_rrset_data* d = (struct packed_rrset_data*)
152*be771a7bSCy Schubert 	rrset->entry.data;
153*be771a7bSCy Schubert 	if(!d) return 0;
154*be771a7bSCy Schubert 	return d->count;
155*be771a7bSCy Schubert }
156*be771a7bSCy Schubert 
157*be771a7bSCy Schubert /** setup sig alg list from dnskey */
158*be771a7bSCy Schubert static void
159*be771a7bSCy Schubert setup_sigalg(struct ub_packed_rrset_key* dnskey, uint8_t* sigalg)
160*be771a7bSCy Schubert {
161*be771a7bSCy Schubert 	uint8_t a[ALGO_NEEDS_MAX];
162*be771a7bSCy Schubert 	size_t i, n = 0;
163*be771a7bSCy Schubert 	memset(a, 0, sizeof(a));
164*be771a7bSCy Schubert 	for(i=0; i<rrset_get_count(dnskey); i++) {
165*be771a7bSCy Schubert 		uint8_t algo = (uint8_t)dnskey_get_algo(dnskey, i);
166*be771a7bSCy Schubert 		if(a[algo] == 0) {
167*be771a7bSCy Schubert 			a[algo] = 1;
168*be771a7bSCy Schubert 			sigalg[n++] = algo;
169*be771a7bSCy Schubert 		}
170*be771a7bSCy Schubert 	}
171*be771a7bSCy Schubert 	sigalg[n] = 0;
172*be771a7bSCy Schubert }
173*be771a7bSCy Schubert 
174*be771a7bSCy Schubert /** verify and test one rrset against the key rrset */
175*be771a7bSCy Schubert static void
176*be771a7bSCy Schubert verifytest_rrset(struct module_env* env, struct val_env* ve,
177*be771a7bSCy Schubert 	struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
178*be771a7bSCy Schubert 	struct query_info* qinfo)
179*be771a7bSCy Schubert {
180*be771a7bSCy Schubert 	enum sec_status sec;
181*be771a7bSCy Schubert 	char reasonbuf[256];
182*be771a7bSCy Schubert 	char* reason = NULL;
183*be771a7bSCy Schubert 	uint8_t sigalg[ALGO_NEEDS_MAX+1];
184*be771a7bSCy Schubert 	int verified = 0;
185*be771a7bSCy Schubert 	if(vsig) {
186*be771a7bSCy Schubert 		log_nametypeclass(VERB_QUERY, "verify of rrset",
187*be771a7bSCy Schubert 			rrset->rk.dname, ntohs(rrset->rk.type),
188*be771a7bSCy Schubert 			ntohs(rrset->rk.rrset_class));
189*be771a7bSCy Schubert 	}
190*be771a7bSCy Schubert 	setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */
191*be771a7bSCy Schubert 	/* ok to give null as qstate here, won't be used for answer section. */
192*be771a7bSCy Schubert 	sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason,
193*be771a7bSCy Schubert 		NULL, LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf,
194*be771a7bSCy Schubert 		sizeof(reasonbuf));
195*be771a7bSCy Schubert 	if(vsig) {
196*be771a7bSCy Schubert 		printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
197*be771a7bSCy Schubert 			reason?reason:"");
198*be771a7bSCy Schubert 	}
199*be771a7bSCy Schubert 	if(should_be_bogus(rrset, qinfo)) {
200*be771a7bSCy Schubert 		unit_assert(sec == sec_status_bogus);
201*be771a7bSCy Schubert 	} else {
202*be771a7bSCy Schubert 		unit_assert(sec == sec_status_secure);
203*be771a7bSCy Schubert 	}
204*be771a7bSCy Schubert }
205*be771a7bSCy Schubert 
206*be771a7bSCy Schubert /** verify and test an entry - every rr in the message */
207*be771a7bSCy Schubert static void
208*be771a7bSCy Schubert verifytest_entry(struct entry* e, struct alloc_cache* alloc,
209*be771a7bSCy Schubert 	struct regional* region, sldns_buffer* pkt,
210*be771a7bSCy Schubert 	struct ub_packed_rrset_key* dnskey, struct module_env* env,
211*be771a7bSCy Schubert 	struct val_env* ve)
212*be771a7bSCy Schubert {
213*be771a7bSCy Schubert 	struct query_info qinfo;
214*be771a7bSCy Schubert 	struct reply_info* rep = NULL;
215*be771a7bSCy Schubert 	size_t i;
216*be771a7bSCy Schubert 
217*be771a7bSCy Schubert 	regional_free_all(region);
218*be771a7bSCy Schubert 	if(vsig) {
219*be771a7bSCy Schubert 		char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt,
220*be771a7bSCy Schubert 			e->reply_list->reply_len);
221*be771a7bSCy Schubert 		printf("verifying pkt:\n%s\n", s?s:"outofmemory");
222*be771a7bSCy Schubert 		free(s);
223*be771a7bSCy Schubert 	}
224*be771a7bSCy Schubert 	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
225*be771a7bSCy Schubert 
226*be771a7bSCy Schubert 	for(i=0; i<rep->rrset_count; i++) {
227*be771a7bSCy Schubert 		verifytest_rrset(env, ve, rep->rrsets[i], dnskey, &qinfo);
228*be771a7bSCy Schubert 	}
229*be771a7bSCy Schubert 
230*be771a7bSCy Schubert 	reply_info_parsedelete(rep, alloc);
231*be771a7bSCy Schubert 	query_info_clear(&qinfo);
232*be771a7bSCy Schubert }
233*be771a7bSCy Schubert 
234*be771a7bSCy Schubert /** find RRset in reply by type */
235*be771a7bSCy Schubert static struct ub_packed_rrset_key*
236*be771a7bSCy Schubert find_rrset_type(struct reply_info* rep, uint16_t type)
237*be771a7bSCy Schubert {
238*be771a7bSCy Schubert 	size_t i;
239*be771a7bSCy Schubert 	for(i=0; i<rep->rrset_count; i++) {
240*be771a7bSCy Schubert 		if(ntohs(rep->rrsets[i]->rk.type) == type)
241*be771a7bSCy Schubert 			return rep->rrsets[i];
242*be771a7bSCy Schubert 	}
243*be771a7bSCy Schubert 	return NULL;
244*be771a7bSCy Schubert }
245*be771a7bSCy Schubert 
246*be771a7bSCy Schubert /** DS sig test an entry - get DNSKEY and DS in entry and verify */
247*be771a7bSCy Schubert static void
248*be771a7bSCy Schubert dstest_entry(struct entry* e, struct alloc_cache* alloc,
249*be771a7bSCy Schubert 	struct regional* region, sldns_buffer* pkt, struct module_env* env)
250*be771a7bSCy Schubert {
251*be771a7bSCy Schubert 	struct query_info qinfo;
252*be771a7bSCy Schubert 	struct reply_info* rep = NULL;
253*be771a7bSCy Schubert 	struct ub_packed_rrset_key* ds, *dnskey;
254*be771a7bSCy Schubert 	int ret;
255*be771a7bSCy Schubert 
256*be771a7bSCy Schubert 	regional_free_all(region);
257*be771a7bSCy Schubert 	if(vsig) {
258*be771a7bSCy Schubert 		char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt,
259*be771a7bSCy Schubert 			e->reply_list->reply_len);
260*be771a7bSCy Schubert 		printf("verifying DS-DNSKEY match:\n%s\n", s?s:"outofmemory");
261*be771a7bSCy Schubert 		free(s);
262*be771a7bSCy Schubert 	}
263*be771a7bSCy Schubert 	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
264*be771a7bSCy Schubert 	ds = find_rrset_type(rep, LDNS_RR_TYPE_DS);
265*be771a7bSCy Schubert 	dnskey = find_rrset_type(rep, LDNS_RR_TYPE_DNSKEY);
266*be771a7bSCy Schubert 	/* check test is OK */
267*be771a7bSCy Schubert 	unit_assert(ds && dnskey);
268*be771a7bSCy Schubert 
269*be771a7bSCy Schubert 	ret = ds_digest_match_dnskey(env, dnskey, 0, ds, 0);
270*be771a7bSCy Schubert 	if(strncmp((char*)qinfo.qname, "\003yes", 4) == 0) {
271*be771a7bSCy Schubert 		if(vsig) {
272*be771a7bSCy Schubert 			printf("result(yes)= %s\n", ret?"yes":"no");
273*be771a7bSCy Schubert 		}
274*be771a7bSCy Schubert 		unit_assert(ret);
275*be771a7bSCy Schubert 	} else if (strncmp((char*)qinfo.qname, "\002no", 3) == 0) {
276*be771a7bSCy Schubert 		if(vsig) {
277*be771a7bSCy Schubert 			printf("result(no)= %s\n", ret?"yes":"no");
278*be771a7bSCy Schubert 		}
279*be771a7bSCy Schubert 		unit_assert(!ret);
280*be771a7bSCy Schubert 		verbose(VERB_QUERY, "DS fail: OK; matched unit test");
281*be771a7bSCy Schubert 	} else {
282*be771a7bSCy Schubert 		fatal_exit("Bad qname in DS unit test, yes or no");
283*be771a7bSCy Schubert 	}
284*be771a7bSCy Schubert 
285*be771a7bSCy Schubert 	reply_info_parsedelete(rep, alloc);
286*be771a7bSCy Schubert 	query_info_clear(&qinfo);
287*be771a7bSCy Schubert }
288*be771a7bSCy Schubert 
289*be771a7bSCy Schubert /** verify from a file */
290*be771a7bSCy Schubert static void
291*be771a7bSCy Schubert verifytest_file(const char* fname, const char* at_date)
292*be771a7bSCy Schubert {
293*be771a7bSCy Schubert 	/*
294*be771a7bSCy Schubert 	 * The file contains a list of ldns-testpkts entries.
295*be771a7bSCy Schubert 	 * The first entry must be a query for DNSKEY.
296*be771a7bSCy Schubert 	 * The answer rrset is the keyset that will be used for verification
297*be771a7bSCy Schubert 	 */
298*be771a7bSCy Schubert 	struct ub_packed_rrset_key* dnskey;
299*be771a7bSCy Schubert 	struct regional* region = regional_create();
300*be771a7bSCy Schubert 	struct alloc_cache alloc;
301*be771a7bSCy Schubert 	sldns_buffer* buf = sldns_buffer_new(65535);
302*be771a7bSCy Schubert 	struct entry* e;
303*be771a7bSCy Schubert 	struct entry* list = read_datafile(fname, 1);
304*be771a7bSCy Schubert 	struct module_env env;
305*be771a7bSCy Schubert 	struct val_env ve;
306*be771a7bSCy Schubert 	time_t now = time(NULL);
307*be771a7bSCy Schubert 	unit_show_func("signature verify", fname);
308*be771a7bSCy Schubert 
309*be771a7bSCy Schubert 	if(!list)
310*be771a7bSCy Schubert 		fatal_exit("could not read %s: %s", fname, strerror(errno));
311*be771a7bSCy Schubert 	alloc_init(&alloc, NULL, 1);
312*be771a7bSCy Schubert 	memset(&env, 0, sizeof(env));
313*be771a7bSCy Schubert 	memset(&ve, 0, sizeof(ve));
314*be771a7bSCy Schubert 	env.scratch = region;
315*be771a7bSCy Schubert 	env.scratch_buffer = buf;
316*be771a7bSCy Schubert 	env.now = &now;
317*be771a7bSCy Schubert 	ve.date_override = cfg_convert_timeval(at_date);
318*be771a7bSCy Schubert 	unit_assert(region && buf);
319*be771a7bSCy Schubert 	dnskey = extract_keys(list, &alloc, region, buf);
320*be771a7bSCy Schubert 	if(vsig) log_nametypeclass(VERB_QUERY, "test dnskey",
321*be771a7bSCy Schubert 			dnskey->rk.dname, ntohs(dnskey->rk.type),
322*be771a7bSCy Schubert 			ntohs(dnskey->rk.rrset_class));
323*be771a7bSCy Schubert 	/* ready to go! */
324*be771a7bSCy Schubert 	for(e = list->next; e; e = e->next) {
325*be771a7bSCy Schubert 		verifytest_entry(e, &alloc, region, buf, dnskey, &env, &ve);
326*be771a7bSCy Schubert 	}
327*be771a7bSCy Schubert 
328*be771a7bSCy Schubert 	ub_packed_rrset_parsedelete(dnskey, &alloc);
329*be771a7bSCy Schubert 	delete_entry(list);
330*be771a7bSCy Schubert 	regional_destroy(region);
331*be771a7bSCy Schubert 	alloc_clear(&alloc);
332*be771a7bSCy Schubert 	sldns_buffer_free(buf);
333*be771a7bSCy Schubert }
334*be771a7bSCy Schubert 
335*be771a7bSCy Schubert /** verify DS matches DNSKEY from a file */
336*be771a7bSCy Schubert static void
337*be771a7bSCy Schubert dstest_file(const char* fname)
338*be771a7bSCy Schubert {
339*be771a7bSCy Schubert 	/*
340*be771a7bSCy Schubert 	 * The file contains a list of ldns-testpkts entries.
341*be771a7bSCy Schubert 	 * The first entry must be a query for DNSKEY.
342*be771a7bSCy Schubert 	 * The answer rrset is the keyset that will be used for verification
343*be771a7bSCy Schubert 	 */
344*be771a7bSCy Schubert 	struct regional* region = regional_create();
345*be771a7bSCy Schubert 	struct alloc_cache alloc;
346*be771a7bSCy Schubert 	sldns_buffer* buf = sldns_buffer_new(65535);
347*be771a7bSCy Schubert 	struct entry* e;
348*be771a7bSCy Schubert 	struct entry* list = read_datafile(fname, 1);
349*be771a7bSCy Schubert 	struct module_env env;
350*be771a7bSCy Schubert 	unit_show_func("DS verify", fname);
351*be771a7bSCy Schubert 
352*be771a7bSCy Schubert 	if(!list)
353*be771a7bSCy Schubert 		fatal_exit("could not read %s: %s", fname, strerror(errno));
354*be771a7bSCy Schubert 	alloc_init(&alloc, NULL, 1);
355*be771a7bSCy Schubert 	memset(&env, 0, sizeof(env));
356*be771a7bSCy Schubert 	env.scratch = region;
357*be771a7bSCy Schubert 	env.scratch_buffer = buf;
358*be771a7bSCy Schubert 	unit_assert(region && buf);
359*be771a7bSCy Schubert 
360*be771a7bSCy Schubert 	/* ready to go! */
361*be771a7bSCy Schubert 	for(e = list; e; e = e->next) {
362*be771a7bSCy Schubert 		dstest_entry(e, &alloc, region, buf, &env);
363*be771a7bSCy Schubert 	}
364*be771a7bSCy Schubert 
365*be771a7bSCy Schubert 	delete_entry(list);
366*be771a7bSCy Schubert 	regional_destroy(region);
367*be771a7bSCy Schubert 	alloc_clear(&alloc);
368*be771a7bSCy Schubert 	sldns_buffer_free(buf);
369*be771a7bSCy Schubert }
370*be771a7bSCy Schubert 
371*be771a7bSCy Schubert /** helper for unittest of NSEC routines */
372*be771a7bSCy Schubert static int
373*be771a7bSCy Schubert unitest_nsec_has_type_rdata(char* bitmap, size_t len, uint16_t type)
374*be771a7bSCy Schubert {
375*be771a7bSCy Schubert 	return nsecbitmap_has_type_rdata((uint8_t*)bitmap, len, type);
376*be771a7bSCy Schubert }
377*be771a7bSCy Schubert 
378*be771a7bSCy Schubert /** Test NSEC type bitmap routine */
379*be771a7bSCy Schubert static void
380*be771a7bSCy Schubert nsectest(void)
381*be771a7bSCy Schubert {
382*be771a7bSCy Schubert 	/* bitmap starts at type bitmap rdata field */
383*be771a7bSCy Schubert 	/* from rfc 4034 example */
384*be771a7bSCy Schubert 	char* bitmap = "\000\006\100\001\000\000\000\003"
385*be771a7bSCy Schubert 		"\004\033\000\000\000\000\000\000"
386*be771a7bSCy Schubert 		"\000\000\000\000\000\000\000\000"
387*be771a7bSCy Schubert 		"\000\000\000\000\000\000\000\000"
388*be771a7bSCy Schubert 		"\000\000\000\000\040";
389*be771a7bSCy Schubert 	size_t len = 37;
390*be771a7bSCy Schubert 
391*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 0));
392*be771a7bSCy Schubert 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_A));
393*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 2));
394*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 3));
395*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 4));
396*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 5));
397*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 6));
398*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 7));
399*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 8));
400*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 9));
401*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 10));
402*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 11));
403*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 12));
404*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 13));
405*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 14));
406*be771a7bSCy Schubert 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_MX));
407*be771a7bSCy Schubert 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_RRSIG));
408*be771a7bSCy Schubert 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_NSEC));
409*be771a7bSCy Schubert 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, 1234));
410*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1233));
411*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1235));
412*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1236));
413*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1237));
414*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1238));
415*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1239));
416*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1240));
417*be771a7bSCy Schubert 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 2230));
418*be771a7bSCy Schubert }
419*be771a7bSCy Schubert 
420*be771a7bSCy Schubert /** Test hash algo - NSEC3 hash it and compare result */
421*be771a7bSCy Schubert static void
422*be771a7bSCy Schubert nsec3_hash_test_entry(struct entry* e, rbtree_type* ct,
423*be771a7bSCy Schubert 	struct alloc_cache* alloc, struct regional* region,
424*be771a7bSCy Schubert 	sldns_buffer* buf)
425*be771a7bSCy Schubert {
426*be771a7bSCy Schubert 	struct query_info qinfo;
427*be771a7bSCy Schubert 	struct reply_info* rep = NULL;
428*be771a7bSCy Schubert 	struct ub_packed_rrset_key* answer, *nsec3, *nsec3_region;
429*be771a7bSCy Schubert 	struct nsec3_cached_hash* hash = NULL;
430*be771a7bSCy Schubert 	int ret;
431*be771a7bSCy Schubert 	uint8_t* qname;
432*be771a7bSCy Schubert 
433*be771a7bSCy Schubert 	if(vsig) {
434*be771a7bSCy Schubert 		char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt,
435*be771a7bSCy Schubert 			e->reply_list->reply_len);
436*be771a7bSCy Schubert 		printf("verifying NSEC3 hash:\n%s\n", s?s:"outofmemory");
437*be771a7bSCy Schubert 		free(s);
438*be771a7bSCy Schubert 	}
439*be771a7bSCy Schubert 	entry_to_repinfo(e, alloc, region, buf, &qinfo, &rep);
440*be771a7bSCy Schubert 	nsec3 = find_rrset_type(rep, LDNS_RR_TYPE_NSEC3);
441*be771a7bSCy Schubert 	answer = find_rrset_type(rep, LDNS_RR_TYPE_AAAA);
442*be771a7bSCy Schubert 	qname = regional_alloc_init(region, qinfo.qname, qinfo.qname_len);
443*be771a7bSCy Schubert 	/* check test is OK */
444*be771a7bSCy Schubert 	unit_assert(nsec3 && answer && qname);
445*be771a7bSCy Schubert 
446*be771a7bSCy Schubert 	/* Copy the nsec3 to the region, so it can stay referenced by the
447*be771a7bSCy Schubert 	 * ct tree entry. The region is freed when the file is done. */
448*be771a7bSCy Schubert 	nsec3_region = packed_rrset_copy_region(nsec3, region, 0);
449*be771a7bSCy Schubert 
450*be771a7bSCy Schubert 	ret = nsec3_hash_name(ct, region, buf, nsec3_region, 0, qname,
451*be771a7bSCy Schubert 		qinfo.qname_len, &hash);
452*be771a7bSCy Schubert 	if(ret < 1) {
453*be771a7bSCy Schubert 		printf("Bad nsec3_hash_name retcode %d\n", ret);
454*be771a7bSCy Schubert 		unit_assert(ret == 1 || ret == 2);
455*be771a7bSCy Schubert 	}
456*be771a7bSCy Schubert 	unit_assert(hash->dname && hash->hash && hash->hash_len &&
457*be771a7bSCy Schubert 		hash->b32 && hash->b32_len);
458*be771a7bSCy Schubert 	unit_assert(hash->b32_len == (size_t)answer->rk.dname[0]);
459*be771a7bSCy Schubert 	/* does not do lowercasing. */
460*be771a7bSCy Schubert 	unit_assert(memcmp(hash->b32, answer->rk.dname+1, hash->b32_len)
461*be771a7bSCy Schubert 		== 0);
462*be771a7bSCy Schubert 
463*be771a7bSCy Schubert 	reply_info_parsedelete(rep, alloc);
464*be771a7bSCy Schubert 	query_info_clear(&qinfo);
465*be771a7bSCy Schubert }
466*be771a7bSCy Schubert 
467*be771a7bSCy Schubert 
468*be771a7bSCy Schubert /** Read file to test NSEC3 hash algo */
469*be771a7bSCy Schubert static void
470*be771a7bSCy Schubert nsec3_hash_test(const char* fname)
471*be771a7bSCy Schubert {
472*be771a7bSCy Schubert 	/*
473*be771a7bSCy Schubert 	 * The list contains a list of ldns-testpkts entries.
474*be771a7bSCy Schubert 	 * Every entry is a test.
475*be771a7bSCy Schubert 	 * 	The qname is hashed.
476*be771a7bSCy Schubert 	 * 	The answer section AAAA RR name is the required result.
477*be771a7bSCy Schubert 	 * 	The auth section NSEC3 is used to get hash parameters.
478*be771a7bSCy Schubert 	 * The hash cache is maintained per file.
479*be771a7bSCy Schubert 	 *
480*be771a7bSCy Schubert 	 * The test does not perform canonicalization during the compare.
481*be771a7bSCy Schubert 	 */
482*be771a7bSCy Schubert 	rbtree_type ct;
483*be771a7bSCy Schubert 	struct regional* region = regional_create();
484*be771a7bSCy Schubert 	struct alloc_cache alloc;
485*be771a7bSCy Schubert 	sldns_buffer* buf = sldns_buffer_new(65535);
486*be771a7bSCy Schubert 	struct entry* e;
487*be771a7bSCy Schubert 	struct entry* list = read_datafile(fname, 1);
488*be771a7bSCy Schubert 	unit_show_func("NSEC3 hash", fname);
489*be771a7bSCy Schubert 
490*be771a7bSCy Schubert 	if(!list)
491*be771a7bSCy Schubert 		fatal_exit("could not read %s: %s", fname, strerror(errno));
492*be771a7bSCy Schubert 	rbtree_init(&ct, &nsec3_hash_cmp);
493*be771a7bSCy Schubert 	alloc_init(&alloc, NULL, 1);
494*be771a7bSCy Schubert 	unit_assert(region && buf);
495*be771a7bSCy Schubert 
496*be771a7bSCy Schubert 	/* ready to go! */
497*be771a7bSCy Schubert 	for(e = list; e; e = e->next) {
498*be771a7bSCy Schubert 		nsec3_hash_test_entry(e, &ct, &alloc, region, buf);
499*be771a7bSCy Schubert 	}
500*be771a7bSCy Schubert 
501*be771a7bSCy Schubert 	delete_entry(list);
502*be771a7bSCy Schubert 	regional_destroy(region);
503*be771a7bSCy Schubert 	alloc_clear(&alloc);
504*be771a7bSCy Schubert 	sldns_buffer_free(buf);
505*be771a7bSCy Schubert }
506*be771a7bSCy Schubert 
507*be771a7bSCy Schubert #define xstr(s) str(s)
508*be771a7bSCy Schubert #define str(s) #s
509*be771a7bSCy Schubert 
510*be771a7bSCy Schubert #define SRCDIRSTR xstr(SRCDIR)
511*be771a7bSCy Schubert 
512*be771a7bSCy Schubert void
513*be771a7bSCy Schubert verify_test(void)
514*be771a7bSCy Schubert {
515*be771a7bSCy Schubert 	unit_show_feature("signature verify");
516*be771a7bSCy Schubert #ifdef USE_SHA1
517*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.1", "20070818005004");
518*be771a7bSCy Schubert #endif
519*be771a7bSCy Schubert #if defined(USE_DSA) && defined(USE_SHA1)
520*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.2", "20080414005004");
521*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.3", "20080416005004");
522*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.4", "20080416005004");
523*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.5", "20080416005004");
524*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.6", "20080416005004");
525*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.7", "20070829144150");
526*be771a7bSCy Schubert #endif /* USE_DSA */
527*be771a7bSCy Schubert #ifdef USE_SHA1
528*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.8", "20070829144150");
529*be771a7bSCy Schubert #endif
530*be771a7bSCy Schubert #if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2)
531*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256", "20070829144150");
532*be771a7bSCy Schubert #  ifdef USE_SHA1
533*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.sha1_and_256", "20070829144150");
534*be771a7bSCy Schubert #  endif
535*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256_draft", "20090101000000");
536*be771a7bSCy Schubert #endif
537*be771a7bSCy Schubert #if (defined(HAVE_EVP_SHA512) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2)
538*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha512_draft", "20070829144150");
539*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.9", "20171215000000");
540*be771a7bSCy Schubert #endif
541*be771a7bSCy Schubert #ifdef USE_SHA1
542*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.hinfo", "20090107100022");
543*be771a7bSCy Schubert 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.revoked", "20080414005004");
544*be771a7bSCy Schubert #endif
545*be771a7bSCy Schubert #ifdef USE_GOST
546*be771a7bSCy Schubert 	if(sldns_key_EVP_load_gost_id())
547*be771a7bSCy Schubert 	  verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost", "20090807060504");
548*be771a7bSCy Schubert 	else printf("Warning: skipped GOST, openssl does not provide gost.\n");
549*be771a7bSCy Schubert #endif
550*be771a7bSCy Schubert #ifdef USE_ECDSA
551*be771a7bSCy Schubert 	/* test for support in case we use libNSS and ECC is removed */
552*be771a7bSCy Schubert 	if(dnskey_algo_id_is_supported(LDNS_ECDSAP256SHA256)) {
553*be771a7bSCy Schubert 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ecdsa_p256", "20100908100439");
554*be771a7bSCy Schubert 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ecdsa_p384", "20100908100439");
555*be771a7bSCy Schubert 	}
556*be771a7bSCy Schubert 	dstest_file(SRCDIRSTR "/testdata/test_ds.sha384");
557*be771a7bSCy Schubert #endif
558*be771a7bSCy Schubert #ifdef USE_ED25519
559*be771a7bSCy Schubert 	if(dnskey_algo_id_is_supported(LDNS_ED25519)) {
560*be771a7bSCy Schubert 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ed25519", "20170530140439");
561*be771a7bSCy Schubert 	}
562*be771a7bSCy Schubert #endif
563*be771a7bSCy Schubert #ifdef USE_ED448
564*be771a7bSCy Schubert 	if(dnskey_algo_id_is_supported(LDNS_ED448)) {
565*be771a7bSCy Schubert 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ed448", "20180408143630");
566*be771a7bSCy Schubert 	}
567*be771a7bSCy Schubert #endif
568*be771a7bSCy Schubert #ifdef USE_SHA1
569*be771a7bSCy Schubert 	dstest_file(SRCDIRSTR "/testdata/test_ds.sha1");
570*be771a7bSCy Schubert #endif
571*be771a7bSCy Schubert 	nsectest();
572*be771a7bSCy Schubert 	nsec3_hash_test(SRCDIRSTR "/testdata/test_nsec3_hash.1");
573*be771a7bSCy Schubert }
574