]>
git.saurik.com Git - apple/network_cmds.git/blob - unbound/testcode/unitverify.c
2 * testcode/unitverify.c - unit test for signature verification routines.
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
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.
38 * Calls verification unit tests. Exits with code 1 on a failure.
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 "ldns/sbuffer.h"
60 #include "ldns/keyraw.h"
61 #include "ldns/str2wire.h"
62 #include "ldns/wire2str.h"
64 /** verbose signature test */
67 /** entry to packet buffer with wireformat */
69 entry_to_buf(struct entry
* e
, sldns_buffer
* pkt
)
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
);
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
);
82 /** entry to reply info conversion */
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
)
89 struct edns_data edns
;
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
);
100 sldns_wire2str_rcode_buf(ret
, rcode
, sizeof(rcode
));
101 printf("parse code %d: %s\n", ret
, rcode
);
102 unit_assert(ret
!= 0);
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
)
111 struct ub_packed_rrset_key
* dnskey
= NULL
;
112 struct query_info qinfo
;
113 struct reply_info
* rep
= NULL
;
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
;
126 reply_info_parsedelete(rep
, alloc
);
127 query_info_clear(&qinfo
);
131 /** return true if answer should be bogus */
133 should_be_bogus(struct ub_packed_rrset_key
* rrset
, struct query_info
* qinfo
)
135 struct packed_rrset_data
* d
= (struct packed_rrset_data
*)rrset
->
137 if(d
->rrsig_count
== 0)
139 /* name 'bogus' as first label signals bogus */
140 if(rrset
->rk
.dname_len
> 6 && memcmp(rrset
->rk
.dname
+1, "bogus", 5)==0)
142 if(qinfo
->qname_len
> 6 && memcmp(qinfo
->qname
+1, "bogus", 5)==0)
147 /** return number of rrs in an rrset */
149 rrset_get_count(struct ub_packed_rrset_key
* rrset
)
151 struct packed_rrset_data
* d
= (struct packed_rrset_data
*)
157 /** setup sig alg list from dnskey */
159 setup_sigalg(struct ub_packed_rrset_key
* dnskey
, uint8_t* sigalg
)
161 uint8_t a
[ALGO_NEEDS_MAX
];
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
);
174 /** verify and test one rrset against the key rrset */
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
)
182 uint8_t sigalg
[ALGO_NEEDS_MAX
+1];
184 log_nametypeclass(VERB_QUERY
, "verify of rrset",
185 rrset
->rk
.dname
, ntohs(rrset
->rk
.type
),
186 ntohs(rrset
->rk
.rrset_class
));
188 setup_sigalg(dnskey
, sigalg
); /* check all algorithms in the dnskey */
189 sec
= dnskeyset_verify_rrset(env
, ve
, rrset
, dnskey
, sigalg
, &reason
);
191 printf("verify outcome is: %s %s\n", sec_status_to_string(sec
),
194 if(should_be_bogus(rrset
, qinfo
)) {
195 unit_assert(sec
== sec_status_bogus
);
197 unit_assert(sec
== sec_status_secure
);
201 /** verify and test an entry - every rr in the message */
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
,
208 struct query_info qinfo
;
209 struct reply_info
* rep
= NULL
;
212 regional_free_all(region
);
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");
219 entry_to_repinfo(e
, alloc
, region
, pkt
, &qinfo
, &rep
);
221 for(i
=0; i
<rep
->rrset_count
; i
++) {
222 verifytest_rrset(env
, ve
, rep
->rrsets
[i
], dnskey
, &qinfo
);
225 reply_info_parsedelete(rep
, alloc
);
226 query_info_clear(&qinfo
);
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
)
234 for(i
=0; i
<rep
->rrset_count
; i
++) {
235 if(ntohs(rep
->rrsets
[i
]->rk
.type
) == type
)
236 return rep
->rrsets
[i
];
241 /** DS sig test an entry - get DNSKEY and DS in entry and verify */
243 dstest_entry(struct entry
* e
, struct alloc_cache
* alloc
,
244 struct regional
* region
, sldns_buffer
* pkt
, struct module_env
* env
)
246 struct query_info qinfo
;
247 struct reply_info
* rep
= NULL
;
248 struct ub_packed_rrset_key
* ds
, *dnskey
;
251 regional_free_all(region
);
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");
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
);
264 ret
= ds_digest_match_dnskey(env
, dnskey
, 0, ds
, 0);
265 if(strncmp((char*)qinfo
.qname
, "\003yes", 4) == 0) {
267 printf("result(yes)= %s\n", ret
?"yes":"no");
270 } else if (strncmp((char*)qinfo
.qname
, "\002no", 3) == 0) {
272 printf("result(no)= %s\n", ret
?"yes":"no");
275 verbose(VERB_QUERY
, "DS fail: OK; matched unit test");
277 fatal_exit("Bad qname in DS unit test, yes or no");
280 reply_info_parsedelete(rep
, alloc
);
281 query_info_clear(&qinfo
);
284 /** verify from a file */
286 verifytest_file(const char* fname
, const char* at_date
)
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
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);
298 struct entry
* list
= read_datafile(fname
, 1);
299 struct module_env env
;
301 time_t now
= time(NULL
);
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
;
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
));
318 for(e
= list
->next
; e
; e
= e
->next
) {
319 verifytest_entry(e
, &alloc
, region
, buf
, dnskey
, &env
, &ve
);
322 ub_packed_rrset_parsedelete(dnskey
, &alloc
);
324 regional_destroy(region
);
326 sldns_buffer_free(buf
);
329 /** verify DS matches DNSKEY from a file */
331 dstest_file(const char* fname
)
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
338 struct regional
* region
= regional_create();
339 struct alloc_cache alloc
;
340 sldns_buffer
* buf
= sldns_buffer_new(65535);
342 struct entry
* list
= read_datafile(fname
, 1);
343 struct module_env env
;
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
);
354 for(e
= list
; e
; e
= e
->next
) {
355 dstest_entry(e
, &alloc
, region
, buf
, &env
);
359 regional_destroy(region
);
361 sldns_buffer_free(buf
);
364 /** helper for unittest of NSEC routines */
366 unitest_nsec_has_type_rdata(char* bitmap
, size_t len
, uint16_t type
)
368 return nsecbitmap_has_type_rdata((uint8_t*)bitmap
, len
, type
);
371 /** Test NSEC type bitmap routine */
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";
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));
413 /** Test hash algo - NSEC3 hash it and compare result */
415 nsec3_hash_test_entry(struct entry
* e
, rbtree_t
* ct
,
416 struct alloc_cache
* alloc
, struct regional
* region
,
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
;
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");
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
);
439 ret
= nsec3_hash_name(ct
, region
, buf
, nsec3
, 0, qname
,
440 qinfo
.qname_len
, &hash
);
442 printf("Bad nsec3_hash_name retcode %d\n", ret
);
443 unit_assert(ret
== 1);
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
)
452 reply_info_parsedelete(rep
, alloc
);
453 query_info_clear(&qinfo
);
457 /** Read file to test NSEC3 hash algo */
459 nsec3_hash_test(const char* fname
)
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.
469 * The test does not perform canonicalization during the compare.
472 struct regional
* region
= regional_create();
473 struct alloc_cache alloc
;
474 sldns_buffer
* buf
= sldns_buffer_new(65535);
476 struct entry
* list
= read_datafile(fname
, 1);
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
);
485 for(e
= list
; e
; e
= e
->next
) {
486 nsec3_hash_test_entry(e
, &ct
, &alloc
, region
, buf
);
490 regional_destroy(region
);
492 sldns_buffer_free(buf
);
498 unit_show_feature("signature verify");
499 verifytest_file("testdata/test_signatures.1", "20070818005004");
500 verifytest_file("testdata/test_signatures.2", "20080414005004");
501 verifytest_file("testdata/test_signatures.3", "20080416005004");
502 verifytest_file("testdata/test_signatures.4", "20080416005004");
503 verifytest_file("testdata/test_signatures.5", "20080416005004");
504 verifytest_file("testdata/test_signatures.6", "20080416005004");
505 verifytest_file("testdata/test_signatures.7", "20070829144150");
506 verifytest_file("testdata/test_signatures.8", "20070829144150");
507 #if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS)) && defined(USE_SHA2)
508 verifytest_file("testdata/test_sigs.rsasha256", "20070829144150");
509 verifytest_file("testdata/test_sigs.sha1_and_256", "20070829144150");
510 verifytest_file("testdata/test_sigs.rsasha256_draft", "20090101000000");
512 #if (defined(HAVE_EVP_SHA512) || defined(HAVE_NSS)) && defined(USE_SHA2)
513 verifytest_file("testdata/test_sigs.rsasha512_draft", "20070829144150");
515 verifytest_file("testdata/test_sigs.hinfo", "20090107100022");
516 verifytest_file("testdata/test_sigs.revoked", "20080414005004");
518 if(sldns_key_EVP_load_gost_id())
519 verifytest_file("testdata/test_sigs.gost", "20090807060504");
520 else printf("Warning: skipped GOST, openssl does not provide gost.\n");
523 /* test for support in case we use libNSS and ECC is removed */
524 if(dnskey_algo_id_is_supported(LDNS_ECDSAP256SHA256
)) {
525 verifytest_file("testdata/test_sigs.ecdsa_p256", "20100908100439");
526 verifytest_file("testdata/test_sigs.ecdsa_p384", "20100908100439");
528 dstest_file("testdata/test_ds.sha384");
530 dstest_file("testdata/test_ds.sha1");
532 nsec3_hash_test("testdata/test_nsec3_hash.1");