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_t* 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_t 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 verifytest_file("testdata/test_signatures.1", "20070818005004"); 500 #ifdef USE_DSA 501 verifytest_file("testdata/test_signatures.2", "20080414005004"); 502 verifytest_file("testdata/test_signatures.3", "20080416005004"); 503 verifytest_file("testdata/test_signatures.4", "20080416005004"); 504 verifytest_file("testdata/test_signatures.5", "20080416005004"); 505 verifytest_file("testdata/test_signatures.6", "20080416005004"); 506 verifytest_file("testdata/test_signatures.7", "20070829144150"); 507 #endif /* USE_DSA */ 508 verifytest_file("testdata/test_signatures.8", "20070829144150"); 509 #if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2) 510 verifytest_file("testdata/test_sigs.rsasha256", "20070829144150"); 511 verifytest_file("testdata/test_sigs.sha1_and_256", "20070829144150"); 512 verifytest_file("testdata/test_sigs.rsasha256_draft", "20090101000000"); 513 #endif 514 #if (defined(HAVE_EVP_SHA512) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2) 515 verifytest_file("testdata/test_sigs.rsasha512_draft", "20070829144150"); 516 #endif 517 verifytest_file("testdata/test_sigs.hinfo", "20090107100022"); 518 verifytest_file("testdata/test_sigs.revoked", "20080414005004"); 519 #ifdef USE_GOST 520 if(sldns_key_EVP_load_gost_id()) 521 verifytest_file("testdata/test_sigs.gost", "20090807060504"); 522 else printf("Warning: skipped GOST, openssl does not provide gost.\n"); 523 #endif 524 #ifdef USE_ECDSA 525 /* test for support in case we use libNSS and ECC is removed */ 526 if(dnskey_algo_id_is_supported(LDNS_ECDSAP256SHA256)) { 527 verifytest_file("testdata/test_sigs.ecdsa_p256", "20100908100439"); 528 verifytest_file("testdata/test_sigs.ecdsa_p384", "20100908100439"); 529 } 530 dstest_file("testdata/test_ds.sha384"); 531 #endif 532 dstest_file("testdata/test_ds.sha1"); 533 nsectest(); 534 nsec3_hash_test("testdata/test_nsec3_hash.1"); 535 } 536