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