Home | History | Annotate | Line # | Download | only in testcode
      1      1.1  christos /*
      2      1.1  christos  * testcode/unitverify.c - unit test for signature verification routines.
      3      1.1  christos  *
      4      1.1  christos  * Copyright (c) 2007, NLnet Labs. All rights reserved.
      5      1.1  christos  *
      6      1.1  christos  * This software is open source.
      7      1.1  christos  *
      8      1.1  christos  * Redistribution and use in source and binary forms, with or without
      9      1.1  christos  * modification, are permitted provided that the following conditions
     10      1.1  christos  * are met:
     11      1.1  christos  *
     12      1.1  christos  * Redistributions of source code must retain the above copyright notice,
     13      1.1  christos  * this list of conditions and the following disclaimer.
     14      1.1  christos  *
     15      1.1  christos  * Redistributions in binary form must reproduce the above copyright notice,
     16      1.1  christos  * this list of conditions and the following disclaimer in the documentation
     17      1.1  christos  * and/or other materials provided with the distribution.
     18      1.1  christos  *
     19      1.1  christos  * Neither the name of the NLNET LABS nor the names of its contributors may
     20      1.1  christos  * be used to endorse or promote products derived from this software without
     21      1.1  christos  * specific prior written permission.
     22      1.1  christos  *
     23      1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24      1.1  christos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25      1.1  christos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     26      1.1  christos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     27      1.1  christos  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     28      1.1  christos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
     29      1.1  christos  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     30      1.1  christos  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     31      1.1  christos  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     32      1.1  christos  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     33      1.1  christos  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34      1.1  christos  *
     35      1.1  christos  */
     36      1.1  christos /**
     37      1.1  christos  * \file
     38      1.1  christos  * Calls verification unit tests. Exits with code 1 on a failure.
     39      1.1  christos  */
     40      1.1  christos 
     41      1.1  christos #include "config.h"
     42      1.1  christos #include "util/log.h"
     43      1.1  christos #include "testcode/unitmain.h"
     44      1.1  christos #include "validator/val_sigcrypt.h"
     45      1.1  christos #include "validator/val_secalgo.h"
     46      1.1  christos #include "validator/val_nsec.h"
     47      1.1  christos #include "validator/val_nsec3.h"
     48      1.1  christos #include "validator/validator.h"
     49      1.1  christos #include "testcode/testpkts.h"
     50      1.1  christos #include "util/data/msgreply.h"
     51      1.1  christos #include "util/data/msgparse.h"
     52      1.1  christos #include "util/data/dname.h"
     53      1.1  christos #include "util/regional.h"
     54      1.1  christos #include "util/alloc.h"
     55      1.1  christos #include "util/rbtree.h"
     56      1.1  christos #include "util/net_help.h"
     57      1.1  christos #include "util/module.h"
     58      1.1  christos #include "util/config_file.h"
     59      1.1  christos #include "sldns/sbuffer.h"
     60      1.1  christos #include "sldns/keyraw.h"
     61      1.1  christos #include "sldns/str2wire.h"
     62      1.1  christos #include "sldns/wire2str.h"
     63      1.1  christos 
     64  1.1.1.8  christos #ifdef HAVE_SSL
     65  1.1.1.8  christos #ifdef HAVE_OPENSSL_ERR_H
     66  1.1.1.8  christos #include <openssl/err.h>
     67  1.1.1.8  christos #endif
     68  1.1.1.8  christos #endif
     69  1.1.1.8  christos 
     70      1.1  christos /** verbose signature test */
     71      1.1  christos static int vsig = 0;
     72      1.1  christos 
     73      1.1  christos /** entry to packet buffer with wireformat */
     74      1.1  christos static void
     75      1.1  christos entry_to_buf(struct entry* e, sldns_buffer* pkt)
     76      1.1  christos {
     77      1.1  christos 	unit_assert(e->reply_list);
     78      1.1  christos 	if(e->reply_list->reply_from_hex) {
     79      1.1  christos 		sldns_buffer_copy(pkt, e->reply_list->reply_from_hex);
     80      1.1  christos 	} else {
     81      1.1  christos 		sldns_buffer_clear(pkt);
     82      1.1  christos 		sldns_buffer_write(pkt, e->reply_list->reply_pkt,
     83      1.1  christos 			e->reply_list->reply_len);
     84      1.1  christos 		sldns_buffer_flip(pkt);
     85      1.1  christos 	}
     86      1.1  christos }
     87      1.1  christos 
     88      1.1  christos /** entry to reply info conversion */
     89      1.1  christos static void
     90      1.1  christos entry_to_repinfo(struct entry* e, struct alloc_cache* alloc,
     91      1.1  christos 	struct regional* region, sldns_buffer* pkt, struct query_info* qi,
     92      1.1  christos 	struct reply_info** rep)
     93      1.1  christos {
     94      1.1  christos 	int ret;
     95      1.1  christos 	struct edns_data edns;
     96      1.1  christos 	entry_to_buf(e, pkt);
     97      1.1  christos 	/* lock alloc lock to please lock checking software.
     98      1.1  christos 	 * alloc_special_obtain assumes it is talking to a ub-alloc,
     99      1.1  christos 	 * and does not need to perform locking. Here the alloc is
    100      1.1  christos 	 * the only one, so we lock it here */
    101      1.1  christos 	lock_quick_lock(&alloc->lock);
    102      1.1  christos 	ret = reply_info_parse(pkt, alloc, qi, rep, region, &edns);
    103      1.1  christos 	lock_quick_unlock(&alloc->lock);
    104      1.1  christos 	if(ret != 0) {
    105      1.1  christos 		char rcode[16];
    106      1.1  christos 		sldns_wire2str_rcode_buf(ret, rcode, sizeof(rcode));
    107      1.1  christos 		printf("parse code %d: %s\n", ret, rcode);
    108      1.1  christos 		unit_assert(ret != 0);
    109      1.1  christos 	}
    110      1.1  christos }
    111      1.1  christos 
    112      1.1  christos /** extract DNSKEY rrset from answer and convert it */
    113      1.1  christos static struct ub_packed_rrset_key*
    114      1.1  christos extract_keys(struct entry* e, struct alloc_cache* alloc,
    115      1.1  christos 	struct regional* region, sldns_buffer* pkt)
    116      1.1  christos {
    117      1.1  christos 	struct ub_packed_rrset_key* dnskey = NULL;
    118      1.1  christos 	struct query_info qinfo;
    119      1.1  christos 	struct reply_info* rep = NULL;
    120      1.1  christos 	size_t i;
    121      1.1  christos 
    122      1.1  christos 	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
    123      1.1  christos 	for(i=0; i<rep->an_numrrsets; i++) {
    124      1.1  christos 		if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_DNSKEY) {
    125      1.1  christos 			dnskey = rep->rrsets[i];
    126      1.1  christos 			rep->rrsets[i] = NULL;
    127      1.1  christos 			break;
    128      1.1  christos 		}
    129      1.1  christos 	}
    130      1.1  christos 	unit_assert(dnskey);
    131      1.1  christos 
    132      1.1  christos 	reply_info_parsedelete(rep, alloc);
    133      1.1  christos 	query_info_clear(&qinfo);
    134      1.1  christos 	return dnskey;
    135      1.1  christos }
    136      1.1  christos 
    137      1.1  christos /** return true if answer should be bogus */
    138      1.1  christos static int
    139      1.1  christos should_be_bogus(struct ub_packed_rrset_key* rrset, struct query_info* qinfo)
    140      1.1  christos {
    141      1.1  christos 	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
    142      1.1  christos 		entry.data;
    143      1.1  christos 	if(d->rrsig_count == 0)
    144      1.1  christos 		return 1;
    145      1.1  christos 	/* name 'bogus' as first label signals bogus */
    146      1.1  christos 	if(rrset->rk.dname_len > 6 && memcmp(rrset->rk.dname+1, "bogus", 5)==0)
    147      1.1  christos 		return 1;
    148      1.1  christos 	if(qinfo->qname_len > 6 && memcmp(qinfo->qname+1, "bogus", 5)==0)
    149      1.1  christos 		return 1;
    150      1.1  christos 	return 0;
    151      1.1  christos }
    152      1.1  christos 
    153      1.1  christos /** return number of rrs in an rrset */
    154      1.1  christos static size_t
    155      1.1  christos rrset_get_count(struct ub_packed_rrset_key* rrset)
    156      1.1  christos {
    157      1.1  christos 	struct packed_rrset_data* d = (struct packed_rrset_data*)
    158      1.1  christos 	rrset->entry.data;
    159      1.1  christos 	if(!d) return 0;
    160      1.1  christos 	return d->count;
    161      1.1  christos }
    162      1.1  christos 
    163      1.1  christos /** setup sig alg list from dnskey */
    164      1.1  christos static void
    165      1.1  christos setup_sigalg(struct ub_packed_rrset_key* dnskey, uint8_t* sigalg)
    166      1.1  christos {
    167      1.1  christos 	uint8_t a[ALGO_NEEDS_MAX];
    168      1.1  christos 	size_t i, n = 0;
    169      1.1  christos 	memset(a, 0, sizeof(a));
    170      1.1  christos 	for(i=0; i<rrset_get_count(dnskey); i++) {
    171      1.1  christos 		uint8_t algo = (uint8_t)dnskey_get_algo(dnskey, i);
    172      1.1  christos 		if(a[algo] == 0) {
    173      1.1  christos 			a[algo] = 1;
    174      1.1  christos 			sigalg[n++] = algo;
    175      1.1  christos 		}
    176      1.1  christos 	}
    177      1.1  christos 	sigalg[n] = 0;
    178      1.1  christos }
    179      1.1  christos 
    180      1.1  christos /** verify and test one rrset against the key rrset */
    181      1.1  christos static void
    182      1.1  christos verifytest_rrset(struct module_env* env, struct val_env* ve,
    183      1.1  christos 	struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
    184      1.1  christos 	struct query_info* qinfo)
    185      1.1  christos {
    186      1.1  christos 	enum sec_status sec;
    187  1.1.1.7  christos 	char reasonbuf[256];
    188      1.1  christos 	char* reason = NULL;
    189      1.1  christos 	uint8_t sigalg[ALGO_NEEDS_MAX+1];
    190  1.1.1.6  christos 	int verified = 0;
    191      1.1  christos 	if(vsig) {
    192      1.1  christos 		log_nametypeclass(VERB_QUERY, "verify of rrset",
    193      1.1  christos 			rrset->rk.dname, ntohs(rrset->rk.type),
    194      1.1  christos 			ntohs(rrset->rk.rrset_class));
    195      1.1  christos 	}
    196      1.1  christos 	setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */
    197  1.1.1.2  christos 	/* ok to give null as qstate here, won't be used for answer section. */
    198  1.1.1.7  christos 	sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason,
    199  1.1.1.7  christos 		NULL, LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf,
    200  1.1.1.7  christos 		sizeof(reasonbuf));
    201      1.1  christos 	if(vsig) {
    202      1.1  christos 		printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
    203      1.1  christos 			reason?reason:"");
    204      1.1  christos 	}
    205      1.1  christos 	if(should_be_bogus(rrset, qinfo)) {
    206      1.1  christos 		unit_assert(sec == sec_status_bogus);
    207      1.1  christos 	} else {
    208      1.1  christos 		unit_assert(sec == sec_status_secure);
    209      1.1  christos 	}
    210      1.1  christos }
    211      1.1  christos 
    212      1.1  christos /** verify and test an entry - every rr in the message */
    213      1.1  christos static void
    214      1.1  christos verifytest_entry(struct entry* e, struct alloc_cache* alloc,
    215      1.1  christos 	struct regional* region, sldns_buffer* pkt,
    216      1.1  christos 	struct ub_packed_rrset_key* dnskey, struct module_env* env,
    217      1.1  christos 	struct val_env* ve)
    218      1.1  christos {
    219      1.1  christos 	struct query_info qinfo;
    220      1.1  christos 	struct reply_info* rep = NULL;
    221      1.1  christos 	size_t i;
    222      1.1  christos 
    223      1.1  christos 	regional_free_all(region);
    224      1.1  christos 	if(vsig) {
    225      1.1  christos 		char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt,
    226      1.1  christos 			e->reply_list->reply_len);
    227      1.1  christos 		printf("verifying pkt:\n%s\n", s?s:"outofmemory");
    228      1.1  christos 		free(s);
    229      1.1  christos 	}
    230      1.1  christos 	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
    231      1.1  christos 
    232      1.1  christos 	for(i=0; i<rep->rrset_count; i++) {
    233      1.1  christos 		verifytest_rrset(env, ve, rep->rrsets[i], dnskey, &qinfo);
    234      1.1  christos 	}
    235      1.1  christos 
    236      1.1  christos 	reply_info_parsedelete(rep, alloc);
    237      1.1  christos 	query_info_clear(&qinfo);
    238      1.1  christos }
    239      1.1  christos 
    240      1.1  christos /** find RRset in reply by type */
    241      1.1  christos static struct ub_packed_rrset_key*
    242      1.1  christos find_rrset_type(struct reply_info* rep, uint16_t type)
    243      1.1  christos {
    244      1.1  christos 	size_t i;
    245      1.1  christos 	for(i=0; i<rep->rrset_count; i++) {
    246      1.1  christos 		if(ntohs(rep->rrsets[i]->rk.type) == type)
    247      1.1  christos 			return rep->rrsets[i];
    248      1.1  christos 	}
    249      1.1  christos 	return NULL;
    250      1.1  christos }
    251      1.1  christos 
    252      1.1  christos /** DS sig test an entry - get DNSKEY and DS in entry and verify */
    253      1.1  christos static void
    254      1.1  christos dstest_entry(struct entry* e, struct alloc_cache* alloc,
    255      1.1  christos 	struct regional* region, sldns_buffer* pkt, struct module_env* env)
    256      1.1  christos {
    257      1.1  christos 	struct query_info qinfo;
    258      1.1  christos 	struct reply_info* rep = NULL;
    259      1.1  christos 	struct ub_packed_rrset_key* ds, *dnskey;
    260      1.1  christos 	int ret;
    261      1.1  christos 
    262      1.1  christos 	regional_free_all(region);
    263      1.1  christos 	if(vsig) {
    264      1.1  christos 		char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt,
    265      1.1  christos 			e->reply_list->reply_len);
    266      1.1  christos 		printf("verifying DS-DNSKEY match:\n%s\n", s?s:"outofmemory");
    267      1.1  christos 		free(s);
    268      1.1  christos 	}
    269      1.1  christos 	entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep);
    270      1.1  christos 	ds = find_rrset_type(rep, LDNS_RR_TYPE_DS);
    271      1.1  christos 	dnskey = find_rrset_type(rep, LDNS_RR_TYPE_DNSKEY);
    272      1.1  christos 	/* check test is OK */
    273      1.1  christos 	unit_assert(ds && dnskey);
    274      1.1  christos 
    275      1.1  christos 	ret = ds_digest_match_dnskey(env, dnskey, 0, ds, 0);
    276      1.1  christos 	if(strncmp((char*)qinfo.qname, "\003yes", 4) == 0) {
    277      1.1  christos 		if(vsig) {
    278      1.1  christos 			printf("result(yes)= %s\n", ret?"yes":"no");
    279      1.1  christos 		}
    280      1.1  christos 		unit_assert(ret);
    281      1.1  christos 	} else if (strncmp((char*)qinfo.qname, "\002no", 3) == 0) {
    282      1.1  christos 		if(vsig) {
    283      1.1  christos 			printf("result(no)= %s\n", ret?"yes":"no");
    284      1.1  christos 		}
    285      1.1  christos 		unit_assert(!ret);
    286      1.1  christos 		verbose(VERB_QUERY, "DS fail: OK; matched unit test");
    287      1.1  christos 	} else {
    288      1.1  christos 		fatal_exit("Bad qname in DS unit test, yes or no");
    289      1.1  christos 	}
    290      1.1  christos 
    291      1.1  christos 	reply_info_parsedelete(rep, alloc);
    292      1.1  christos 	query_info_clear(&qinfo);
    293      1.1  christos }
    294      1.1  christos 
    295      1.1  christos /** verify from a file */
    296      1.1  christos static void
    297      1.1  christos verifytest_file(const char* fname, const char* at_date)
    298      1.1  christos {
    299      1.1  christos 	/*
    300      1.1  christos 	 * The file contains a list of ldns-testpkts entries.
    301      1.1  christos 	 * The first entry must be a query for DNSKEY.
    302      1.1  christos 	 * The answer rrset is the keyset that will be used for verification
    303      1.1  christos 	 */
    304      1.1  christos 	struct ub_packed_rrset_key* dnskey;
    305      1.1  christos 	struct regional* region = regional_create();
    306      1.1  christos 	struct alloc_cache alloc;
    307      1.1  christos 	sldns_buffer* buf = sldns_buffer_new(65535);
    308      1.1  christos 	struct entry* e;
    309      1.1  christos 	struct entry* list = read_datafile(fname, 1);
    310      1.1  christos 	struct module_env env;
    311      1.1  christos 	struct val_env ve;
    312      1.1  christos 	time_t now = time(NULL);
    313  1.1.1.2  christos 	unit_show_func("signature verify", fname);
    314      1.1  christos 
    315      1.1  christos 	if(!list)
    316      1.1  christos 		fatal_exit("could not read %s: %s", fname, strerror(errno));
    317      1.1  christos 	alloc_init(&alloc, NULL, 1);
    318      1.1  christos 	memset(&env, 0, sizeof(env));
    319      1.1  christos 	memset(&ve, 0, sizeof(ve));
    320      1.1  christos 	env.scratch = region;
    321      1.1  christos 	env.scratch_buffer = buf;
    322      1.1  christos 	env.now = &now;
    323      1.1  christos 	ve.date_override = cfg_convert_timeval(at_date);
    324      1.1  christos 	unit_assert(region && buf);
    325      1.1  christos 	dnskey = extract_keys(list, &alloc, region, buf);
    326      1.1  christos 	if(vsig) log_nametypeclass(VERB_QUERY, "test dnskey",
    327      1.1  christos 			dnskey->rk.dname, ntohs(dnskey->rk.type),
    328      1.1  christos 			ntohs(dnskey->rk.rrset_class));
    329      1.1  christos 	/* ready to go! */
    330      1.1  christos 	for(e = list->next; e; e = e->next) {
    331      1.1  christos 		verifytest_entry(e, &alloc, region, buf, dnskey, &env, &ve);
    332      1.1  christos 	}
    333      1.1  christos 
    334      1.1  christos 	ub_packed_rrset_parsedelete(dnskey, &alloc);
    335      1.1  christos 	delete_entry(list);
    336      1.1  christos 	regional_destroy(region);
    337      1.1  christos 	alloc_clear(&alloc);
    338      1.1  christos 	sldns_buffer_free(buf);
    339      1.1  christos }
    340      1.1  christos 
    341      1.1  christos /** verify DS matches DNSKEY from a file */
    342      1.1  christos static void
    343      1.1  christos dstest_file(const char* fname)
    344      1.1  christos {
    345      1.1  christos 	/*
    346      1.1  christos 	 * The file contains a list of ldns-testpkts entries.
    347      1.1  christos 	 * The first entry must be a query for DNSKEY.
    348      1.1  christos 	 * The answer rrset is the keyset that will be used for verification
    349      1.1  christos 	 */
    350      1.1  christos 	struct regional* region = regional_create();
    351      1.1  christos 	struct alloc_cache alloc;
    352      1.1  christos 	sldns_buffer* buf = sldns_buffer_new(65535);
    353      1.1  christos 	struct entry* e;
    354      1.1  christos 	struct entry* list = read_datafile(fname, 1);
    355      1.1  christos 	struct module_env env;
    356  1.1.1.2  christos 	unit_show_func("DS verify", fname);
    357      1.1  christos 
    358      1.1  christos 	if(!list)
    359      1.1  christos 		fatal_exit("could not read %s: %s", fname, strerror(errno));
    360      1.1  christos 	alloc_init(&alloc, NULL, 1);
    361      1.1  christos 	memset(&env, 0, sizeof(env));
    362      1.1  christos 	env.scratch = region;
    363      1.1  christos 	env.scratch_buffer = buf;
    364      1.1  christos 	unit_assert(region && buf);
    365      1.1  christos 
    366      1.1  christos 	/* ready to go! */
    367      1.1  christos 	for(e = list; e; e = e->next) {
    368      1.1  christos 		dstest_entry(e, &alloc, region, buf, &env);
    369      1.1  christos 	}
    370      1.1  christos 
    371      1.1  christos 	delete_entry(list);
    372      1.1  christos 	regional_destroy(region);
    373      1.1  christos 	alloc_clear(&alloc);
    374      1.1  christos 	sldns_buffer_free(buf);
    375      1.1  christos }
    376      1.1  christos 
    377      1.1  christos /** helper for unittest of NSEC routines */
    378      1.1  christos static int
    379      1.1  christos unitest_nsec_has_type_rdata(char* bitmap, size_t len, uint16_t type)
    380      1.1  christos {
    381      1.1  christos 	return nsecbitmap_has_type_rdata((uint8_t*)bitmap, len, type);
    382      1.1  christos }
    383      1.1  christos 
    384      1.1  christos /** Test NSEC type bitmap routine */
    385      1.1  christos static void
    386      1.1  christos nsectest(void)
    387      1.1  christos {
    388      1.1  christos 	/* bitmap starts at type bitmap rdata field */
    389      1.1  christos 	/* from rfc 4034 example */
    390      1.1  christos 	char* bitmap = "\000\006\100\001\000\000\000\003"
    391      1.1  christos 		"\004\033\000\000\000\000\000\000"
    392      1.1  christos 		"\000\000\000\000\000\000\000\000"
    393      1.1  christos 		"\000\000\000\000\000\000\000\000"
    394      1.1  christos 		"\000\000\000\000\040";
    395      1.1  christos 	size_t len = 37;
    396      1.1  christos 
    397      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 0));
    398      1.1  christos 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_A));
    399      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 2));
    400      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 3));
    401      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 4));
    402      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 5));
    403      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 6));
    404      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 7));
    405      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 8));
    406      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 9));
    407      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 10));
    408      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 11));
    409      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 12));
    410      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 13));
    411      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 14));
    412      1.1  christos 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_MX));
    413      1.1  christos 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_RRSIG));
    414      1.1  christos 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_NSEC));
    415      1.1  christos 	unit_assert(unitest_nsec_has_type_rdata(bitmap, len, 1234));
    416      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1233));
    417      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1235));
    418      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1236));
    419      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1237));
    420      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1238));
    421      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1239));
    422      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1240));
    423      1.1  christos 	unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 2230));
    424      1.1  christos }
    425      1.1  christos 
    426      1.1  christos /** Test hash algo - NSEC3 hash it and compare result */
    427      1.1  christos static void
    428  1.1.1.2  christos nsec3_hash_test_entry(struct entry* e, rbtree_type* ct,
    429      1.1  christos 	struct alloc_cache* alloc, struct regional* region,
    430      1.1  christos 	sldns_buffer* buf)
    431      1.1  christos {
    432      1.1  christos 	struct query_info qinfo;
    433      1.1  christos 	struct reply_info* rep = NULL;
    434  1.1.1.7  christos 	struct ub_packed_rrset_key* answer, *nsec3, *nsec3_region;
    435      1.1  christos 	struct nsec3_cached_hash* hash = NULL;
    436      1.1  christos 	int ret;
    437      1.1  christos 	uint8_t* qname;
    438      1.1  christos 
    439      1.1  christos 	if(vsig) {
    440      1.1  christos 		char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt,
    441      1.1  christos 			e->reply_list->reply_len);
    442      1.1  christos 		printf("verifying NSEC3 hash:\n%s\n", s?s:"outofmemory");
    443      1.1  christos 		free(s);
    444      1.1  christos 	}
    445      1.1  christos 	entry_to_repinfo(e, alloc, region, buf, &qinfo, &rep);
    446      1.1  christos 	nsec3 = find_rrset_type(rep, LDNS_RR_TYPE_NSEC3);
    447      1.1  christos 	answer = find_rrset_type(rep, LDNS_RR_TYPE_AAAA);
    448      1.1  christos 	qname = regional_alloc_init(region, qinfo.qname, qinfo.qname_len);
    449      1.1  christos 	/* check test is OK */
    450      1.1  christos 	unit_assert(nsec3 && answer && qname);
    451      1.1  christos 
    452  1.1.1.7  christos 	/* Copy the nsec3 to the region, so it can stay referenced by the
    453  1.1.1.7  christos 	 * ct tree entry. The region is freed when the file is done. */
    454  1.1.1.7  christos 	nsec3_region = packed_rrset_copy_region(nsec3, region, 0);
    455  1.1.1.7  christos 
    456  1.1.1.7  christos 	ret = nsec3_hash_name(ct, region, buf, nsec3_region, 0, qname,
    457      1.1  christos 		qinfo.qname_len, &hash);
    458  1.1.1.6  christos 	if(ret < 1) {
    459      1.1  christos 		printf("Bad nsec3_hash_name retcode %d\n", ret);
    460  1.1.1.6  christos 		unit_assert(ret == 1 || ret == 2);
    461      1.1  christos 	}
    462      1.1  christos 	unit_assert(hash->dname && hash->hash && hash->hash_len &&
    463      1.1  christos 		hash->b32 && hash->b32_len);
    464      1.1  christos 	unit_assert(hash->b32_len == (size_t)answer->rk.dname[0]);
    465      1.1  christos 	/* does not do lowercasing. */
    466      1.1  christos 	unit_assert(memcmp(hash->b32, answer->rk.dname+1, hash->b32_len)
    467      1.1  christos 		== 0);
    468      1.1  christos 
    469      1.1  christos 	reply_info_parsedelete(rep, alloc);
    470      1.1  christos 	query_info_clear(&qinfo);
    471      1.1  christos }
    472      1.1  christos 
    473      1.1  christos 
    474      1.1  christos /** Read file to test NSEC3 hash algo */
    475      1.1  christos static void
    476      1.1  christos nsec3_hash_test(const char* fname)
    477      1.1  christos {
    478      1.1  christos 	/*
    479      1.1  christos 	 * The list contains a list of ldns-testpkts entries.
    480      1.1  christos 	 * Every entry is a test.
    481      1.1  christos 	 * 	The qname is hashed.
    482      1.1  christos 	 * 	The answer section AAAA RR name is the required result.
    483      1.1  christos 	 * 	The auth section NSEC3 is used to get hash parameters.
    484      1.1  christos 	 * The hash cache is maintained per file.
    485      1.1  christos 	 *
    486      1.1  christos 	 * The test does not perform canonicalization during the compare.
    487      1.1  christos 	 */
    488  1.1.1.2  christos 	rbtree_type ct;
    489      1.1  christos 	struct regional* region = regional_create();
    490      1.1  christos 	struct alloc_cache alloc;
    491      1.1  christos 	sldns_buffer* buf = sldns_buffer_new(65535);
    492      1.1  christos 	struct entry* e;
    493      1.1  christos 	struct entry* list = read_datafile(fname, 1);
    494  1.1.1.2  christos 	unit_show_func("NSEC3 hash", fname);
    495      1.1  christos 
    496      1.1  christos 	if(!list)
    497      1.1  christos 		fatal_exit("could not read %s: %s", fname, strerror(errno));
    498      1.1  christos 	rbtree_init(&ct, &nsec3_hash_cmp);
    499      1.1  christos 	alloc_init(&alloc, NULL, 1);
    500      1.1  christos 	unit_assert(region && buf);
    501      1.1  christos 
    502      1.1  christos 	/* ready to go! */
    503      1.1  christos 	for(e = list; e; e = e->next) {
    504      1.1  christos 		nsec3_hash_test_entry(e, &ct, &alloc, region, buf);
    505      1.1  christos 	}
    506      1.1  christos 
    507      1.1  christos 	delete_entry(list);
    508      1.1  christos 	regional_destroy(region);
    509      1.1  christos 	alloc_clear(&alloc);
    510      1.1  christos 	sldns_buffer_free(buf);
    511      1.1  christos }
    512      1.1  christos 
    513  1.1.1.4  christos #define xstr(s) str(s)
    514  1.1.1.4  christos #define str(s) #s
    515  1.1.1.4  christos 
    516  1.1.1.4  christos #define SRCDIRSTR xstr(SRCDIR)
    517  1.1.1.4  christos 
    518  1.1.1.8  christos #if defined(HAVE_SSL) && defined(USE_SHA1)
    519  1.1.1.8  christos /* Detect if openssl is configured to disable RSASHA1 signatures,
    520  1.1.1.8  christos  * with the rh-allow-sha1-signatures disabled. */
    521  1.1.1.8  christos static int
    522  1.1.1.8  christos rh_allow_sha1_signatures_disabled(void)
    523  1.1.1.8  christos {
    524  1.1.1.8  christos 	EVP_MD_CTX* ctx;
    525  1.1.1.8  christos 	EVP_PKEY* evp_key;
    526  1.1.1.8  christos 	/* This key is rdata from nlnetlabs.nl DNSKEY from 20250424005001,
    527  1.1.1.8  christos 	 * with id=50602 (ksk), size=2048b.
    528  1.1.1.8  christos 	 * A 2048 bit key is taken to avoid key too small errors. */
    529  1.1.1.8  christos 	unsigned char key[] = {
    530  1.1.1.8  christos 		0x03, 0x01, 0x00, 0x01, 0xBC, 0x0B, 0xE8, 0xBB,
    531  1.1.1.8  christos 		0x97, 0x4C, 0xB5, 0xED, 0x6F, 0x6D, 0xC2, 0xB1,
    532  1.1.1.8  christos 		0x78, 0x69, 0x93, 0x1C, 0x72, 0x19, 0xB1, 0x05,
    533  1.1.1.8  christos 		0x51, 0x13, 0xA1, 0xFC, 0xBF, 0x01, 0x58, 0x0D,
    534  1.1.1.8  christos 		0x44, 0x10, 0x5F, 0x0B, 0x75, 0x0E, 0x11, 0x9A,
    535  1.1.1.8  christos 		0xC8, 0xF8, 0x0F, 0x90, 0xFC, 0xB8, 0x09, 0xD1,
    536  1.1.1.8  christos 		0x14, 0x39, 0x0D, 0x84, 0xCE, 0x97, 0x88, 0x82,
    537  1.1.1.8  christos 		0x3D, 0xC5, 0xCB, 0x1A, 0xBF, 0x00, 0x46, 0x37,
    538  1.1.1.8  christos 		0x01, 0xF1, 0xCD, 0x46, 0xA2, 0x8F, 0x83, 0x19,
    539  1.1.1.8  christos 		0x42, 0xED, 0x6F, 0xAF, 0x37, 0x1F, 0x18, 0x82,
    540  1.1.1.8  christos 		0x4B, 0x70, 0x2D, 0x50, 0xA5, 0xA6, 0x66, 0x48,
    541  1.1.1.8  christos 		0x7F, 0x56, 0xA8, 0x86, 0x05, 0x41, 0xC8, 0xBE,
    542  1.1.1.8  christos 		0x4F, 0x8B, 0x38, 0x51, 0xF0, 0xEB, 0xAD, 0x2F,
    543  1.1.1.8  christos 		0x7A, 0xC0, 0xEF, 0xC7, 0xD2, 0x72, 0x6F, 0x16,
    544  1.1.1.8  christos 		0x66, 0xAF, 0x59, 0x55, 0xFF, 0xEE, 0x9D, 0x50,
    545  1.1.1.8  christos 		0xE9, 0xDB, 0xF4, 0x02, 0xBC, 0x33, 0x5C, 0xC5,
    546  1.1.1.8  christos 		0xDA, 0x1C, 0x6A, 0xD1, 0x55, 0xD1, 0x20, 0x2B,
    547  1.1.1.8  christos 		0x63, 0x03, 0x4B, 0x77, 0x45, 0x46, 0x78, 0x31,
    548  1.1.1.8  christos 		0xE4, 0x90, 0xB9, 0x7F, 0x00, 0xFB, 0x62, 0x7C,
    549  1.1.1.8  christos 		0x07, 0xD3, 0xC1, 0x00, 0xA0, 0x54, 0x63, 0x74,
    550  1.1.1.8  christos 		0x0A, 0x17, 0x7B, 0xE7, 0xAD, 0x38, 0x07, 0x86,
    551  1.1.1.8  christos 		0x68, 0xE4, 0xFD, 0x20, 0x68, 0xD5, 0x33, 0x92,
    552  1.1.1.8  christos 		0xCA, 0x90, 0xDD, 0xA4, 0xE9, 0xF2, 0x11, 0xBD,
    553  1.1.1.8  christos 		0x9D, 0xA5, 0xF5, 0xEB, 0xB9, 0xFE, 0x8F, 0xA1,
    554  1.1.1.8  christos 		0xE4, 0xBF, 0xA4, 0xA4, 0x34, 0x5C, 0x6A, 0x95,
    555  1.1.1.8  christos 		0xB6, 0x42, 0x22, 0xF6, 0xD6, 0x10, 0x9C, 0x9B,
    556  1.1.1.8  christos 		0x0A, 0x56, 0xE7, 0x42, 0xE5, 0x7F, 0x1F, 0x4E,
    557  1.1.1.8  christos 		0xBE, 0x4F, 0x8C, 0xED, 0x30, 0x63, 0xA7, 0x88,
    558  1.1.1.8  christos 		0x93, 0xED, 0x37, 0x3C, 0x80, 0xBC, 0xD1, 0x66,
    559  1.1.1.8  christos 		0xBD, 0xB8, 0x2E, 0x65, 0xC4, 0xC8, 0x00, 0x5B,
    560  1.1.1.8  christos 		0xE7, 0x85, 0x96, 0xDD, 0xAA, 0x05, 0xE6, 0x4F,
    561  1.1.1.8  christos 		0x03, 0x64, 0xFA, 0x2D, 0xF6, 0x88, 0x14, 0x8F,
    562  1.1.1.8  christos 		0x15, 0x4D, 0xFD, 0xD3
    563  1.1.1.8  christos 	};
    564  1.1.1.8  christos 	size_t keylen = 260;
    565  1.1.1.8  christos 
    566  1.1.1.8  christos #ifdef HAVE_EVP_MD_CTX_NEW
    567  1.1.1.8  christos 	ctx = EVP_MD_CTX_new();
    568  1.1.1.8  christos #else
    569  1.1.1.8  christos 	ctx = (EVP_MD_CTX*)malloc(sizeof(*ctx));
    570  1.1.1.8  christos 	if(ctx) EVP_MD_CTX_init(ctx);
    571  1.1.1.8  christos #endif
    572  1.1.1.8  christos 	if(!ctx) return 0;
    573  1.1.1.8  christos 
    574  1.1.1.8  christos 	evp_key = sldns_key_rsa2pkey_raw(key, keylen);
    575  1.1.1.8  christos 	if(!evp_key) {
    576  1.1.1.8  christos #ifdef HAVE_EVP_MD_CTX_NEW
    577  1.1.1.8  christos 		EVP_MD_CTX_destroy(ctx);
    578  1.1.1.8  christos #else
    579  1.1.1.8  christos 		EVP_MD_CTX_cleanup(ctx);
    580  1.1.1.8  christos 		free(ctx);
    581  1.1.1.8  christos #endif
    582  1.1.1.8  christos 		return 0;
    583  1.1.1.8  christos 	}
    584  1.1.1.8  christos 
    585  1.1.1.8  christos #ifndef HAVE_EVP_DIGESTVERIFY
    586  1.1.1.8  christos 	(void)evp_key; /* not used */
    587  1.1.1.8  christos 	if(EVP_DigestInit(ctx, EVP_sha1()) == 0)
    588  1.1.1.8  christos #else
    589  1.1.1.8  christos 	if(EVP_DigestVerifyInit(ctx, NULL, EVP_sha1(), NULL, evp_key) == 0)
    590  1.1.1.8  christos #endif
    591  1.1.1.8  christos 	{
    592  1.1.1.8  christos 		unsigned long e = ERR_get_error();
    593  1.1.1.8  christos #ifdef EVP_R_INVALID_DIGEST
    594  1.1.1.8  christos 		if (ERR_GET_LIB(e) == ERR_LIB_EVP &&
    595  1.1.1.8  christos 			ERR_GET_REASON(e) == EVP_R_INVALID_DIGEST) {
    596  1.1.1.8  christos 			/* rh-allow-sha1-signatures makes use of sha1 invalid. */
    597  1.1.1.8  christos 			if(vsig)
    598  1.1.1.8  christos 				printf("Detected that rh-allow-sha1-signatures is off, and disables SHA1 signatures\n");
    599  1.1.1.8  christos #ifdef HAVE_EVP_MD_CTX_NEW
    600  1.1.1.8  christos 			EVP_MD_CTX_destroy(ctx);
    601  1.1.1.8  christos #else
    602  1.1.1.8  christos 			EVP_MD_CTX_cleanup(ctx);
    603  1.1.1.8  christos 			free(ctx);
    604  1.1.1.8  christos #endif
    605  1.1.1.8  christos 			EVP_PKEY_free(evp_key);
    606  1.1.1.8  christos 			return 1;
    607  1.1.1.8  christos 		}
    608  1.1.1.8  christos #endif /* EVP_R_INVALID_DIGEST */
    609  1.1.1.8  christos 		/* The signature verify failed for another reason. */
    610  1.1.1.8  christos 		log_crypto_err_code("EVP_DigestVerifyInit", e);
    611  1.1.1.8  christos #ifdef HAVE_EVP_MD_CTX_NEW
    612  1.1.1.8  christos 		EVP_MD_CTX_destroy(ctx);
    613  1.1.1.8  christos #else
    614  1.1.1.8  christos 		EVP_MD_CTX_cleanup(ctx);
    615  1.1.1.8  christos 		free(ctx);
    616  1.1.1.8  christos #endif
    617  1.1.1.8  christos 		EVP_PKEY_free(evp_key);
    618  1.1.1.8  christos 		return 0;
    619  1.1.1.8  christos 	}
    620  1.1.1.8  christos #ifdef HAVE_EVP_MD_CTX_NEW
    621  1.1.1.8  christos 	EVP_MD_CTX_destroy(ctx);
    622  1.1.1.8  christos #else
    623  1.1.1.8  christos 	EVP_MD_CTX_cleanup(ctx);
    624  1.1.1.8  christos 	free(ctx);
    625  1.1.1.8  christos #endif
    626  1.1.1.8  christos 	EVP_PKEY_free(evp_key);
    627  1.1.1.8  christos 	return 0;
    628  1.1.1.8  christos }
    629  1.1.1.8  christos #endif /* HAVE_SSL && USE_SHA1 */
    630  1.1.1.8  christos 
    631      1.1  christos void
    632      1.1  christos verify_test(void)
    633      1.1  christos {
    634      1.1  christos 	unit_show_feature("signature verify");
    635  1.1.1.8  christos 
    636  1.1.1.8  christos #if defined(HAVE_SSL) && defined(USE_SHA1)
    637  1.1.1.8  christos 	if(rh_allow_sha1_signatures_disabled()) {
    638  1.1.1.8  christos 		/* Allow the use of SHA1 signatures for the test,
    639  1.1.1.8  christos 		 * in case that OpenSSL disallows use of RSASHA1
    640  1.1.1.8  christos 		 * with rh-allow-sha1-signatures disabled. */
    641  1.1.1.8  christos #ifndef UB_ON_WINDOWS
    642  1.1.1.8  christos 		setenv("OPENSSL_ENABLE_SHA1_SIGNATURES", "1", 0);
    643  1.1.1.8  christos #else
    644  1.1.1.8  christos 		_putenv("OPENSSL_ENABLE_SHA1_SIGNATURES=1");
    645  1.1.1.8  christos #endif
    646  1.1.1.8  christos 	}
    647  1.1.1.8  christos #endif
    648  1.1.1.8  christos 
    649  1.1.1.2  christos #ifdef USE_SHA1
    650  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.1", "20070818005004");
    651  1.1.1.2  christos #endif
    652  1.1.1.2  christos #if defined(USE_DSA) && defined(USE_SHA1)
    653  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.2", "20080414005004");
    654  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.3", "20080416005004");
    655  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.4", "20080416005004");
    656  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.5", "20080416005004");
    657  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.6", "20080416005004");
    658  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.7", "20070829144150");
    659      1.1  christos #endif /* USE_DSA */
    660  1.1.1.2  christos #ifdef USE_SHA1
    661  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.8", "20070829144150");
    662  1.1.1.2  christos #endif
    663      1.1  christos #if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2)
    664  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256", "20070829144150");
    665  1.1.1.2  christos #  ifdef USE_SHA1
    666  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.sha1_and_256", "20070829144150");
    667  1.1.1.2  christos #  endif
    668  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256_draft", "20090101000000");
    669      1.1  christos #endif
    670      1.1  christos #if (defined(HAVE_EVP_SHA512) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2)
    671  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha512_draft", "20070829144150");
    672  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_signatures.9", "20171215000000");
    673      1.1  christos #endif
    674  1.1.1.2  christos #ifdef USE_SHA1
    675  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.hinfo", "20090107100022");
    676  1.1.1.4  christos 	verifytest_file(SRCDIRSTR "/testdata/test_sigs.revoked", "20080414005004");
    677  1.1.1.2  christos #endif
    678      1.1  christos #ifdef USE_GOST
    679      1.1  christos 	if(sldns_key_EVP_load_gost_id())
    680  1.1.1.4  christos 	  verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost", "20090807060504");
    681      1.1  christos 	else printf("Warning: skipped GOST, openssl does not provide gost.\n");
    682      1.1  christos #endif
    683      1.1  christos #ifdef USE_ECDSA
    684      1.1  christos 	/* test for support in case we use libNSS and ECC is removed */
    685      1.1  christos 	if(dnskey_algo_id_is_supported(LDNS_ECDSAP256SHA256)) {
    686  1.1.1.4  christos 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ecdsa_p256", "20100908100439");
    687  1.1.1.4  christos 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ecdsa_p384", "20100908100439");
    688      1.1  christos 	}
    689  1.1.1.4  christos 	dstest_file(SRCDIRSTR "/testdata/test_ds.sha384");
    690      1.1  christos #endif
    691  1.1.1.2  christos #ifdef USE_ED25519
    692  1.1.1.2  christos 	if(dnskey_algo_id_is_supported(LDNS_ED25519)) {
    693  1.1.1.4  christos 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ed25519", "20170530140439");
    694  1.1.1.2  christos 	}
    695  1.1.1.2  christos #endif
    696  1.1.1.3  christos #ifdef USE_ED448
    697  1.1.1.3  christos 	if(dnskey_algo_id_is_supported(LDNS_ED448)) {
    698  1.1.1.4  christos 		verifytest_file(SRCDIRSTR "/testdata/test_sigs.ed448", "20180408143630");
    699  1.1.1.3  christos 	}
    700  1.1.1.3  christos #endif
    701  1.1.1.2  christos #ifdef USE_SHA1
    702  1.1.1.4  christos 	dstest_file(SRCDIRSTR "/testdata/test_ds.sha1");
    703  1.1.1.2  christos #endif
    704      1.1  christos 	nsectest();
    705  1.1.1.4  christos 	nsec3_hash_test(SRCDIRSTR "/testdata/test_nsec3_hash.1");
    706      1.1  christos }
    707