xref: /openbsd-src/usr.sbin/unbound/testcode/unitverify.c (revision 98bc733b08604094f4138174a0ee0bb9faaca4bd)
1712b2f30Ssthen /*
2712b2f30Ssthen  * testcode/unitverify.c - unit test for signature verification routines.
3712b2f30Ssthen  *
4712b2f30Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5712b2f30Ssthen  *
6712b2f30Ssthen  * This software is open source.
7712b2f30Ssthen  *
8712b2f30Ssthen  * Redistribution and use in source and binary forms, with or without
9712b2f30Ssthen  * modification, are permitted provided that the following conditions
10712b2f30Ssthen  * are met:
11712b2f30Ssthen  *
12712b2f30Ssthen  * Redistributions of source code must retain the above copyright notice,
13712b2f30Ssthen  * this list of conditions and the following disclaimer.
14712b2f30Ssthen  *
15712b2f30Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16712b2f30Ssthen  * this list of conditions and the following disclaimer in the documentation
17712b2f30Ssthen  * and/or other materials provided with the distribution.
18712b2f30Ssthen  *
19712b2f30Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20712b2f30Ssthen  * be used to endorse or promote products derived from this software without
21712b2f30Ssthen  * specific prior written permission.
22712b2f30Ssthen  *
23712b2f30Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24712b2f30Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25712b2f30Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26712b2f30Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27712b2f30Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28712b2f30Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29712b2f30Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30712b2f30Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31712b2f30Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32712b2f30Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33712b2f30Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34712b2f30Ssthen  *
35712b2f30Ssthen  */
36712b2f30Ssthen /**
37712b2f30Ssthen  * \file
38712b2f30Ssthen  * Calls verification unit tests. Exits with code 1 on a failure.
39712b2f30Ssthen  */
40712b2f30Ssthen 
41712b2f30Ssthen #include "config.h"
42712b2f30Ssthen #include "util/log.h"
43712b2f30Ssthen #include "testcode/unitmain.h"
44712b2f30Ssthen #include "validator/val_sigcrypt.h"
45712b2f30Ssthen #include "validator/val_secalgo.h"
46712b2f30Ssthen #include "validator/val_nsec.h"
47712b2f30Ssthen #include "validator/val_nsec3.h"
48712b2f30Ssthen #include "validator/validator.h"
49712b2f30Ssthen #include "testcode/testpkts.h"
50712b2f30Ssthen #include "util/data/msgreply.h"
51712b2f30Ssthen #include "util/data/msgparse.h"
52712b2f30Ssthen #include "util/data/dname.h"
53712b2f30Ssthen #include "util/regional.h"
54712b2f30Ssthen #include "util/alloc.h"
55712b2f30Ssthen #include "util/rbtree.h"
56712b2f30Ssthen #include "util/net_help.h"
57712b2f30Ssthen #include "util/module.h"
58712b2f30Ssthen #include "util/config_file.h"
59712b2f30Ssthen #include "sldns/sbuffer.h"
60712b2f30Ssthen #include "sldns/keyraw.h"
61712b2f30Ssthen #include "sldns/str2wire.h"
62712b2f30Ssthen #include "sldns/wire2str.h"
63712b2f30Ssthen 
64712b2f30Ssthen /** verbose signature test */
65712b2f30Ssthen static int vsig = 0;
66712b2f30Ssthen 
67712b2f30Ssthen /** entry to packet buffer with wireformat */
68712b2f30Ssthen static void
69712b2f30Ssthen entry_to_buf(struct entry* e, sldns_buffer* pkt)
70712b2f30Ssthen {
71712b2f30Ssthen 	unit_assert(e->reply_list);
72712b2f30Ssthen 	if(e->reply_list->reply_from_hex) {
73712b2f30Ssthen 		sldns_buffer_copy(pkt, e->reply_list->reply_from_hex);
74712b2f30Ssthen 	} else {
75712b2f30Ssthen 		sldns_buffer_clear(pkt);
76712b2f30Ssthen 		sldns_buffer_write(pkt, e->reply_list->reply_pkt,
77712b2f30Ssthen 			e->reply_list->reply_len);
78712b2f30Ssthen 		sldns_buffer_flip(pkt);
79712b2f30Ssthen 	}
80712b2f30Ssthen }
81712b2f30Ssthen 
82712b2f30Ssthen /** entry to reply info conversion */
83712b2f30Ssthen static void
84712b2f30Ssthen entry_to_repinfo(struct entry* e, struct alloc_cache* alloc,
85712b2f30Ssthen 	struct regional* region, sldns_buffer* pkt, struct query_info* qi,
86712b2f30Ssthen 	struct reply_info** rep)
87712b2f30Ssthen {
88712b2f30Ssthen 	int ret;
89712b2f30Ssthen 	struct edns_data edns;
90712b2f30Ssthen 	entry_to_buf(e, pkt);
91712b2f30Ssthen 	/* lock alloc lock to please lock checking software.
92712b2f30Ssthen 	 * alloc_special_obtain assumes it is talking to a ub-alloc,
93712b2f30Ssthen 	 * and does not need to perform locking. Here the alloc is
94712b2f30Ssthen 	 * the only one, so we lock it here */
95712b2f30Ssthen 	lock_quick_lock(&alloc->lock);
96712b2f30Ssthen 	ret = reply_info_parse(pkt, alloc, qi, rep, region, &edns);
97712b2f30Ssthen 	lock_quick_unlock(&alloc->lock);
98712b2f30Ssthen 	if(ret != 0) {
99712b2f30Ssthen 		char rcode[16];
100712b2f30Ssthen 		sldns_wire2str_rcode_buf(ret, rcode, sizeof(rcode));
101712b2f30Ssthen 		printf("parse code %d: %s\n", ret, rcode);
102712b2f30Ssthen 		unit_assert(ret != 0);
103712b2f30Ssthen 	}
104712b2f30Ssthen }
105712b2f30Ssthen 
106712b2f30Ssthen /** extract DNSKEY rrset from answer and convert it */
107712b2f30Ssthen static struct ub_packed_rrset_key*
108712b2f30Ssthen extract_keys(struct entry* e, struct alloc_cache* alloc,
109712b2f30Ssthen 	struct regional* region, sldns_buffer* pkt)
110712b2f30Ssthen {
111712b2f30Ssthen 	struct ub_packed_rrset_key* dnskey = NULL;
112712b2f30Ssthen 	struct query_info qinfo;
113712b2f30Ssthen 	struct reply_info* rep = NULL;
114712b2f30Ssthen 	size_t i;
115712b2f30Ssthen 
116712b2f30Ssthen 	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
117712b2f30Ssthen 	for(i=0; i<rep->an_numrrsets; i++) {
118712b2f30Ssthen 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_DNSKEY) {
119712b2f30Ssthen 			dnskey = rep->rrsets[i];
120712b2f30Ssthen 			rep->rrsets[i] = NULL;
121712b2f30Ssthen 			break;
122712b2f30Ssthen 		}
123712b2f30Ssthen 	}
124712b2f30Ssthen 	unit_assert(dnskey);
125712b2f30Ssthen 
126712b2f30Ssthen 	reply_info_parsedelete(rep, alloc);
127712b2f30Ssthen 	query_info_clear(&qinfo);
128712b2f30Ssthen 	return dnskey;
129712b2f30Ssthen }
130712b2f30Ssthen 
131712b2f30Ssthen /** return true if answer should be bogus */
132712b2f30Ssthen static int
133712b2f30Ssthen should_be_bogus(struct ub_packed_rrset_key* rrset, struct query_info* qinfo)
134712b2f30Ssthen {
135712b2f30Ssthen 	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
136712b2f30Ssthen 		entry.data;
137712b2f30Ssthen 	if(d->rrsig_count == 0)
138712b2f30Ssthen 		return 1;
139712b2f30Ssthen 	/* name 'bogus' as first label signals bogus */
140712b2f30Ssthen 	if(rrset->rk.dname_len > 6 && memcmp(rrset->rk.dname+1, "bogus", 5)==0)
141712b2f30Ssthen 		return 1;
142712b2f30Ssthen 	if(qinfo->qname_len > 6 && memcmp(qinfo->qname+1, "bogus", 5)==0)
143712b2f30Ssthen 		return 1;
144712b2f30Ssthen 	return 0;
145712b2f30Ssthen }
146712b2f30Ssthen 
147712b2f30Ssthen /** return number of rrs in an rrset */
148712b2f30Ssthen static size_t
149712b2f30Ssthen rrset_get_count(struct ub_packed_rrset_key* rrset)
150712b2f30Ssthen {
151712b2f30Ssthen 	struct packed_rrset_data* d = (struct packed_rrset_data*)
152712b2f30Ssthen 	rrset->entry.data;
153712b2f30Ssthen 	if(!d) return 0;
154712b2f30Ssthen 	return d->count;
155712b2f30Ssthen }
156712b2f30Ssthen 
157712b2f30Ssthen /** setup sig alg list from dnskey */
158712b2f30Ssthen static void
159712b2f30Ssthen setup_sigalg(struct ub_packed_rrset_key* dnskey, uint8_t* sigalg)
160712b2f30Ssthen {
161712b2f30Ssthen 	uint8_t a[ALGO_NEEDS_MAX];
162712b2f30Ssthen 	size_t i, n = 0;
163712b2f30Ssthen 	memset(a, 0, sizeof(a));
164712b2f30Ssthen 	for(i=0; i<rrset_get_count(dnskey); i++) {
165712b2f30Ssthen 		uint8_t algo = (uint8_t)dnskey_get_algo(dnskey, i);
166712b2f30Ssthen 		if(a[algo] == 0) {
167712b2f30Ssthen 			a[algo] = 1;
168712b2f30Ssthen 			sigalg[n++] = algo;
169712b2f30Ssthen 		}
170712b2f30Ssthen 	}
171712b2f30Ssthen 	sigalg[n] = 0;
172712b2f30Ssthen }
173712b2f30Ssthen 
174712b2f30Ssthen /** verify and test one rrset against the key rrset */
175712b2f30Ssthen static void
176712b2f30Ssthen verifytest_rrset(struct module_env* env, struct val_env* ve,
177712b2f30Ssthen 	struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
178712b2f30Ssthen 	struct query_info* qinfo)
179712b2f30Ssthen {
180712b2f30Ssthen 	enum sec_status sec;
181*98bc733bSsthen 	char reasonbuf[256];
182712b2f30Ssthen 	char* reason = NULL;
183712b2f30Ssthen 	uint8_t sigalg[ALGO_NEEDS_MAX+1];
184817bdb8fSflorian 	int verified = 0;
185712b2f30Ssthen 	if(vsig) {
186712b2f30Ssthen 		log_nametypeclass(VERB_QUERY, "verify of rrset",
187712b2f30Ssthen 			rrset->rk.dname, ntohs(rrset->rk.type),
188712b2f30Ssthen 			ntohs(rrset->rk.rrset_class));
189712b2f30Ssthen 	}
190712b2f30Ssthen 	setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */
191712b2f30Ssthen 	/* ok to give null as qstate here, won't be used for answer section. */
192*98bc733bSsthen 	sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason,
193*98bc733bSsthen 		NULL, LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf,
194*98bc733bSsthen 		sizeof(reasonbuf));
195712b2f30Ssthen 	if(vsig) {
196712b2f30Ssthen 		printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
197712b2f30Ssthen 			reason?reason:"");
198712b2f30Ssthen 	}
199712b2f30Ssthen 	if(should_be_bogus(rrset, qinfo)) {
200712b2f30Ssthen 		unit_assert(sec == sec_status_bogus);
201712b2f30Ssthen 	} else {
202712b2f30Ssthen 		unit_assert(sec == sec_status_secure);
203712b2f30Ssthen 	}
204712b2f30Ssthen }
205712b2f30Ssthen 
206712b2f30Ssthen /** verify and test an entry - every rr in the message */
207712b2f30Ssthen static void
208712b2f30Ssthen verifytest_entry(struct entry* e, struct alloc_cache* alloc,
209712b2f30Ssthen 	struct regional* region, sldns_buffer* pkt,
210712b2f30Ssthen 	struct ub_packed_rrset_key* dnskey, struct module_env* env,
211712b2f30Ssthen 	struct val_env* ve)
212712b2f30Ssthen {
213712b2f30Ssthen 	struct query_info qinfo;
214712b2f30Ssthen 	struct reply_info* rep = NULL;
215712b2f30Ssthen 	size_t i;
216712b2f30Ssthen 
217712b2f30Ssthen 	regional_free_all(region);
218712b2f30Ssthen 	if(vsig) {
219712b2f30Ssthen 		char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt,
220712b2f30Ssthen 			e->reply_list->reply_len);
221712b2f30Ssthen 		printf("verifying pkt:\n%s\n", s?s:"outofmemory");
222712b2f30Ssthen 		free(s);
223712b2f30Ssthen 	}
224712b2f30Ssthen 	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
225712b2f30Ssthen 
226712b2f30Ssthen 	for(i=0; i<rep->rrset_count; i++) {
227712b2f30Ssthen 		verifytest_rrset(env, ve, rep->rrsets[i], dnskey, &qinfo);
228712b2f30Ssthen 	}
229712b2f30Ssthen 
230712b2f30Ssthen 	reply_info_parsedelete(rep, alloc);
231712b2f30Ssthen 	query_info_clear(&qinfo);
232712b2f30Ssthen }
233712b2f30Ssthen 
234712b2f30Ssthen /** find RRset in reply by type */
235712b2f30Ssthen static struct ub_packed_rrset_key*
236712b2f30Ssthen find_rrset_type(struct reply_info* rep, uint16_t type)
237712b2f30Ssthen {
238712b2f30Ssthen 	size_t i;
239712b2f30Ssthen 	for(i=0; i<rep->rrset_count; i++) {
240712b2f30Ssthen 		if(ntohs(rep->rrsets[i]->rk.type) == type)
241712b2f30Ssthen 			return rep->rrsets[i];
242712b2f30Ssthen 	}
243712b2f30Ssthen 	return NULL;
244712b2f30Ssthen }
245712b2f30Ssthen 
246712b2f30Ssthen /** DS sig test an entry - get DNSKEY and DS in entry and verify */
247712b2f30Ssthen static void
248712b2f30Ssthen dstest_entry(struct entry* e, struct alloc_cache* alloc,
249712b2f30Ssthen 	struct regional* region, sldns_buffer* pkt, struct module_env* env)
250712b2f30Ssthen {
251712b2f30Ssthen 	struct query_info qinfo;
252712b2f30Ssthen 	struct reply_info* rep = NULL;
253712b2f30Ssthen 	struct ub_packed_rrset_key* ds, *dnskey;
254712b2f30Ssthen 	int ret;
255712b2f30Ssthen 
256712b2f30Ssthen 	regional_free_all(region);
257712b2f30Ssthen 	if(vsig) {
258712b2f30Ssthen 		char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt,
259712b2f30Ssthen 			e->reply_list->reply_len);
260712b2f30Ssthen 		printf("verifying DS-DNSKEY match:\n%s\n", s?s:"outofmemory");
261712b2f30Ssthen 		free(s);
262712b2f30Ssthen 	}
263712b2f30Ssthen 	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
264712b2f30Ssthen 	ds = find_rrset_type(rep, LDNS_RR_TYPE_DS);
265712b2f30Ssthen 	dnskey = find_rrset_type(rep, LDNS_RR_TYPE_DNSKEY);
266712b2f30Ssthen 	/* check test is OK */
267712b2f30Ssthen 	unit_assert(ds && dnskey);
268712b2f30Ssthen 
269712b2f30Ssthen 	ret = ds_digest_match_dnskey(env, dnskey, 0, ds, 0);
270712b2f30Ssthen 	if(strncmp((char*)qinfo.qname, "\003yes", 4) == 0) {
271712b2f30Ssthen 		if(vsig) {
272712b2f30Ssthen 			printf("result(yes)= %s\n", ret?"yes":"no");
273712b2f30Ssthen 		}
274712b2f30Ssthen 		unit_assert(ret);
275712b2f30Ssthen 	} else if (strncmp((char*)qinfo.qname, "\002no", 3) == 0) {
276712b2f30Ssthen 		if(vsig) {
277712b2f30Ssthen 			printf("result(no)= %s\n", ret?"yes":"no");
278712b2f30Ssthen 		}
279712b2f30Ssthen 		unit_assert(!ret);
280712b2f30Ssthen 		verbose(VERB_QUERY, "DS fail: OK; matched unit test");
281712b2f30Ssthen 	} else {
282712b2f30Ssthen 		fatal_exit("Bad qname in DS unit test, yes or no");
283712b2f30Ssthen 	}
284712b2f30Ssthen 
285712b2f30Ssthen 	reply_info_parsedelete(rep, alloc);
286712b2f30Ssthen 	query_info_clear(&qinfo);
287712b2f30Ssthen }
288712b2f30Ssthen 
289712b2f30Ssthen /** verify from a file */
290712b2f30Ssthen static void
291712b2f30Ssthen verifytest_file(const char* fname, const char* at_date)
292712b2f30Ssthen {
293712b2f30Ssthen 	/*
294712b2f30Ssthen 	 * The file contains a list of ldns-testpkts entries.
295712b2f30Ssthen 	 * The first entry must be a query for DNSKEY.
296712b2f30Ssthen 	 * The answer rrset is the keyset that will be used for verification
297712b2f30Ssthen 	 */
298712b2f30Ssthen 	struct ub_packed_rrset_key* dnskey;
299712b2f30Ssthen 	struct regional* region = regional_create();
300712b2f30Ssthen 	struct alloc_cache alloc;
301712b2f30Ssthen 	sldns_buffer* buf = sldns_buffer_new(65535);
302712b2f30Ssthen 	struct entry* e;
303712b2f30Ssthen 	struct entry* list = read_datafile(fname, 1);
304712b2f30Ssthen 	struct module_env env;
305712b2f30Ssthen 	struct val_env ve;
306712b2f30Ssthen 	time_t now = time(NULL);
307712b2f30Ssthen 	unit_show_func("signature verify", fname);
308712b2f30Ssthen 
309712b2f30Ssthen 	if(!list)
310712b2f30Ssthen 		fatal_exit("could not read %s: %s", fname, strerror(errno));
311712b2f30Ssthen 	alloc_init(&alloc, NULL, 1);
312712b2f30Ssthen 	memset(&env, 0, sizeof(env));
313712b2f30Ssthen 	memset(&ve, 0, sizeof(ve));
314712b2f30Ssthen 	env.scratch = region;
315712b2f30Ssthen 	env.scratch_buffer = buf;
316712b2f30Ssthen 	env.now = &now;
317712b2f30Ssthen 	ve.date_override = cfg_convert_timeval(at_date);
318712b2f30Ssthen 	unit_assert(region && buf);
319712b2f30Ssthen 	dnskey = extract_keys(list, &alloc, region, buf);
320712b2f30Ssthen 	if(vsig) log_nametypeclass(VERB_QUERY, "test dnskey",
321712b2f30Ssthen 			dnskey->rk.dname, ntohs(dnskey->rk.type),
322712b2f30Ssthen 			ntohs(dnskey->rk.rrset_class));
323712b2f30Ssthen 	/* ready to go! */
324712b2f30Ssthen 	for(e = list->next; e; e = e->next) {
325712b2f30Ssthen 		verifytest_entry(e, &alloc, region, buf, dnskey, &env, &ve);
326712b2f30Ssthen 	}
327712b2f30Ssthen 
328712b2f30Ssthen 	ub_packed_rrset_parsedelete(dnskey, &alloc);
329712b2f30Ssthen 	delete_entry(list);
330712b2f30Ssthen 	regional_destroy(region);
331712b2f30Ssthen 	alloc_clear(&alloc);
332712b2f30Ssthen 	sldns_buffer_free(buf);
333712b2f30Ssthen }
334712b2f30Ssthen 
335712b2f30Ssthen /** verify DS matches DNSKEY from a file */
336712b2f30Ssthen static void
337712b2f30Ssthen dstest_file(const char* fname)
338712b2f30Ssthen {
339712b2f30Ssthen 	/*
340712b2f30Ssthen 	 * The file contains a list of ldns-testpkts entries.
341712b2f30Ssthen 	 * The first entry must be a query for DNSKEY.
342712b2f30Ssthen 	 * The answer rrset is the keyset that will be used for verification
343712b2f30Ssthen 	 */
344712b2f30Ssthen 	struct regional* region = regional_create();
345712b2f30Ssthen 	struct alloc_cache alloc;
346712b2f30Ssthen 	sldns_buffer* buf = sldns_buffer_new(65535);
347712b2f30Ssthen 	struct entry* e;
348712b2f30Ssthen 	struct entry* list = read_datafile(fname, 1);
349712b2f30Ssthen 	struct module_env env;
350712b2f30Ssthen 	unit_show_func("DS verify", fname);
351712b2f30Ssthen 
352712b2f30Ssthen 	if(!list)
353712b2f30Ssthen 		fatal_exit("could not read %s: %s", fname, strerror(errno));
354712b2f30Ssthen 	alloc_init(&alloc, NULL, 1);
355712b2f30Ssthen 	memset(&env, 0, sizeof(env));
356712b2f30Ssthen 	env.scratch = region;
357712b2f30Ssthen 	env.scratch_buffer = buf;
358712b2f30Ssthen 	unit_assert(region && buf);
359712b2f30Ssthen 
360712b2f30Ssthen 	/* ready to go! */
361712b2f30Ssthen 	for(e = list; e; e = e->next) {
362712b2f30Ssthen 		dstest_entry(e, &alloc, region, buf, &env);
363712b2f30Ssthen 	}
364712b2f30Ssthen 
365712b2f30Ssthen 	delete_entry(list);
366712b2f30Ssthen 	regional_destroy(region);
367712b2f30Ssthen 	alloc_clear(&alloc);
368712b2f30Ssthen 	sldns_buffer_free(buf);
369712b2f30Ssthen }
370712b2f30Ssthen 
371712b2f30Ssthen /** helper for unittest of NSEC routines */
372712b2f30Ssthen static int
373712b2f30Ssthen unitest_nsec_has_type_rdata(char* bitmap, size_t len, uint16_t type)
374712b2f30Ssthen {
375712b2f30Ssthen 	return nsecbitmap_has_type_rdata((uint8_t*)bitmap, len, type);
376712b2f30Ssthen }
377712b2f30Ssthen 
378712b2f30Ssthen /** Test NSEC type bitmap routine */
379712b2f30Ssthen static void
380712b2f30Ssthen nsectest(void)
381712b2f30Ssthen {
382712b2f30Ssthen 	/* bitmap starts at type bitmap rdata field */
383712b2f30Ssthen 	/* from rfc 4034 example */
384712b2f30Ssthen 	char* bitmap = "\000\006\100\001\000\000\000\003"
385712b2f30Ssthen 		"\004\033\000\000\000\000\000\000"
386712b2f30Ssthen 		"\000\000\000\000\000\000\000\000"
387712b2f30Ssthen 		"\000\000\000\000\000\000\000\000"
388712b2f30Ssthen 		"\000\000\000\000\040";
389712b2f30Ssthen 	size_t len = 37;
390712b2f30Ssthen 
391712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 0));
392712b2f30Ssthen 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_A));
393712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 2));
394712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 3));
395712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 4));
396712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 5));
397712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 6));
398712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 7));
399712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 8));
400712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 9));
401712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 10));
402712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 11));
403712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 12));
404712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 13));
405712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 14));
406712b2f30Ssthen 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_MX));
407712b2f30Ssthen 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_RRSIG));
408712b2f30Ssthen 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_NSEC));
409712b2f30Ssthen 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, 1234));
410712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1233));
411712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1235));
412712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1236));
413712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1237));
414712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1238));
415712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1239));
416712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1240));
417712b2f30Ssthen 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 2230));
418712b2f30Ssthen }
419712b2f30Ssthen 
420712b2f30Ssthen /** Test hash algo - NSEC3 hash it and compare result */
421712b2f30Ssthen static void
422712b2f30Ssthen nsec3_hash_test_entry(struct entry* e, rbtree_type* ct,
423712b2f30Ssthen 	struct alloc_cache* alloc, struct regional* region,
424712b2f30Ssthen 	sldns_buffer* buf)
425712b2f30Ssthen {
426712b2f30Ssthen 	struct query_info qinfo;
427712b2f30Ssthen 	struct reply_info* rep = NULL;
428712b2f30Ssthen 	struct ub_packed_rrset_key* answer, *nsec3;
429712b2f30Ssthen 	struct nsec3_cached_hash* hash = NULL;
430712b2f30Ssthen 	int ret;
431712b2f30Ssthen 	uint8_t* qname;
432712b2f30Ssthen 
433712b2f30Ssthen 	if(vsig) {
434712b2f30Ssthen 		char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt,
435712b2f30Ssthen 			e->reply_list->reply_len);
436712b2f30Ssthen 		printf("verifying NSEC3 hash:\n%s\n", s?s:"outofmemory");
437712b2f30Ssthen 		free(s);
438712b2f30Ssthen 	}
439712b2f30Ssthen 	entry_to_repinfo(e, alloc, region, buf, &qinfo, &rep);
440712b2f30Ssthen 	nsec3 = find_rrset_type(rep, LDNS_RR_TYPE_NSEC3);
441712b2f30Ssthen 	answer = find_rrset_type(rep, LDNS_RR_TYPE_AAAA);
442712b2f30Ssthen 	qname = regional_alloc_init(region, qinfo.qname, qinfo.qname_len);
443712b2f30Ssthen 	/* check test is OK */
444712b2f30Ssthen 	unit_assert(nsec3 && answer && qname);
445712b2f30Ssthen 
446712b2f30Ssthen 	ret = nsec3_hash_name(ct, region, buf, nsec3, 0, qname,
447712b2f30Ssthen 		qinfo.qname_len, &hash);
448817bdb8fSflorian 	if(ret < 1) {
449712b2f30Ssthen 		printf("Bad nsec3_hash_name retcode %d\n", ret);
450817bdb8fSflorian 		unit_assert(ret == 1 || ret == 2);
451712b2f30Ssthen 	}
452712b2f30Ssthen 	unit_assert(hash->dname && hash->hash && hash->hash_len &&
453712b2f30Ssthen 		hash->b32 && hash->b32_len);
454712b2f30Ssthen 	unit_assert(hash->b32_len == (size_t)answer->rk.dname[0]);
455712b2f30Ssthen 	/* does not do lowercasing. */
456712b2f30Ssthen 	unit_assert(memcmp(hash->b32, answer->rk.dname+1, hash->b32_len)
457712b2f30Ssthen 		== 0);
458712b2f30Ssthen 
459712b2f30Ssthen 	reply_info_parsedelete(rep, alloc);
460712b2f30Ssthen 	query_info_clear(&qinfo);
461712b2f30Ssthen }
462712b2f30Ssthen 
463712b2f30Ssthen 
464712b2f30Ssthen /** Read file to test NSEC3 hash algo */
465712b2f30Ssthen static void
466712b2f30Ssthen nsec3_hash_test(const char* fname)
467712b2f30Ssthen {
468712b2f30Ssthen 	/*
469712b2f30Ssthen 	 * The list contains a list of ldns-testpkts entries.
470712b2f30Ssthen 	 * Every entry is a test.
471712b2f30Ssthen 	 * 	The qname is hashed.
472712b2f30Ssthen 	 * 	The answer section AAAA RR name is the required result.
473712b2f30Ssthen 	 * 	The auth section NSEC3 is used to get hash parameters.
474712b2f30Ssthen 	 * The hash cache is maintained per file.
475712b2f30Ssthen 	 *
476712b2f30Ssthen 	 * The test does not perform canonicalization during the compare.
477712b2f30Ssthen 	 */
478712b2f30Ssthen 	rbtree_type ct;
479712b2f30Ssthen 	struct regional* region = regional_create();
480712b2f30Ssthen 	struct alloc_cache alloc;
481712b2f30Ssthen 	sldns_buffer* buf = sldns_buffer_new(65535);
482712b2f30Ssthen 	struct entry* e;
483712b2f30Ssthen 	struct entry* list = read_datafile(fname, 1);
484712b2f30Ssthen 	unit_show_func("NSEC3 hash", fname);
485712b2f30Ssthen 
486712b2f30Ssthen 	if(!list)
487712b2f30Ssthen 		fatal_exit("could not read %s: %s", fname, strerror(errno));
488712b2f30Ssthen 	rbtree_init(&ct, &nsec3_hash_cmp);
489712b2f30Ssthen 	alloc_init(&alloc, NULL, 1);
490712b2f30Ssthen 	unit_assert(region && buf);
491712b2f30Ssthen 
492712b2f30Ssthen 	/* ready to go! */
493712b2f30Ssthen 	for(e = list; e; e = e->next) {
494712b2f30Ssthen 		nsec3_hash_test_entry(e, &ct, &alloc, region, buf);
495712b2f30Ssthen 	}
496712b2f30Ssthen 
497712b2f30Ssthen 	delete_entry(list);
498712b2f30Ssthen 	regional_destroy(region);
499712b2f30Ssthen 	alloc_clear(&alloc);
500712b2f30Ssthen 	sldns_buffer_free(buf);
501712b2f30Ssthen }
502712b2f30Ssthen 
5037bc20e6dSsthen #define xstr(s) str(s)
5047bc20e6dSsthen #define str(s) #s
5057bc20e6dSsthen 
5067bc20e6dSsthen #define SRCDIRSTR xstr(SRCDIR)
5077bc20e6dSsthen 
508712b2f30Ssthen void
509712b2f30Ssthen verify_test(void)
510712b2f30Ssthen {
511712b2f30Ssthen 	unit_show_feature("signature verify");
512712b2f30Ssthen #ifdef USE_SHA1
5137bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.1", "20070818005004");
514712b2f30Ssthen #endif
515712b2f30Ssthen #if defined(USE_DSA) && defined(USE_SHA1)
5167bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.2", "20080414005004");
5177bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.3", "20080416005004");
5187bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.4", "20080416005004");
5197bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.5", "20080416005004");
5207bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.6", "20080416005004");
5217bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.7", "20070829144150");
522712b2f30Ssthen #endif /* USE_DSA */
523712b2f30Ssthen #ifdef USE_SHA1
5247bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.8", "20070829144150");
525712b2f30Ssthen #endif
526712b2f30Ssthen #if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2)
5277bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256", "20070829144150");
528712b2f30Ssthen #  ifdef USE_SHA1
5297bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.sha1_and_256", "20070829144150");
530712b2f30Ssthen #  endif
5317bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256_draft", "20090101000000");
532712b2f30Ssthen #endif
533712b2f30Ssthen #if (defined(HAVE_EVP_SHA512) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2)
5347bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha512_draft", "20070829144150");
5357bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.9", "20171215000000");
536712b2f30Ssthen #endif
537712b2f30Ssthen #ifdef USE_SHA1
5387bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.hinfo", "20090107100022");
5397bc20e6dSsthen 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.revoked", "20080414005004");
540712b2f30Ssthen #endif
541712b2f30Ssthen #ifdef USE_GOST
542712b2f30Ssthen 	if(sldns_key_EVP_load_gost_id())
5437bc20e6dSsthen 	  verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost", "20090807060504");
544712b2f30Ssthen 	else printf("Warning: skipped GOST, openssl does not provide gost.\n");
545712b2f30Ssthen #endif
546712b2f30Ssthen #ifdef USE_ECDSA
547712b2f30Ssthen 	/* test for support in case we use libNSS and ECC is removed */
548712b2f30Ssthen 	if(dnskey_algo_id_is_supported(LDNS_ECDSAP256SHA256)) {
5497bc20e6dSsthen 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ecdsa_p256", "20100908100439");
5507bc20e6dSsthen 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ecdsa_p384", "20100908100439");
551712b2f30Ssthen 	}
5527bc20e6dSsthen 	dstest_file(SRCDIRSTR "/testdata/test_ds.sha384");
553712b2f30Ssthen #endif
554712b2f30Ssthen #ifdef USE_ED25519
555712b2f30Ssthen 	if(dnskey_algo_id_is_supported(LDNS_ED25519)) {
5567bc20e6dSsthen 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ed25519", "20170530140439");
557712b2f30Ssthen 	}
558712b2f30Ssthen #endif
559712b2f30Ssthen #ifdef USE_ED448
560712b2f30Ssthen 	if(dnskey_algo_id_is_supported(LDNS_ED448)) {
5617bc20e6dSsthen 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ed448", "20180408143630");
562712b2f30Ssthen 	}
563712b2f30Ssthen #endif
564712b2f30Ssthen #ifdef USE_SHA1
5657bc20e6dSsthen 	dstest_file(SRCDIRSTR "/testdata/test_ds.sha1");
566712b2f30Ssthen #endif
567712b2f30Ssthen 	nsectest();
5687bc20e6dSsthen 	nsec3_hash_test(SRCDIRSTR "/testdata/test_nsec3_hash.1");
569712b2f30Ssthen }
570