1/* 2 * Copyright (C) 2004, 2005, 2007, 2009-2014 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: dnssectool.c,v 1.63 2011/10/21 03:55:33 marka Exp $ */ 19 20/*! \file */ 21 22/*% 23 * DNSSEC Support Routines. 24 */ 25 26#include <config.h> 27 28#include <stdlib.h> 29 30#include <isc/base32.h> 31#include <isc/buffer.h> 32#include <isc/dir.h> 33#include <isc/entropy.h> 34#include <isc/heap.h> 35#include <isc/list.h> 36#include <isc/mem.h> 37#include <isc/string.h> 38#include <isc/time.h> 39#include <isc/util.h> 40#include <isc/print.h> 41 42#include <dns/db.h> 43#include <dns/dbiterator.h> 44#include <dns/dnssec.h> 45#include <dns/fixedname.h> 46#include <dns/keyvalues.h> 47#include <dns/log.h> 48#include <dns/name.h> 49#include <dns/nsec.h> 50#include <dns/nsec3.h> 51#include <dns/rdatastruct.h> 52#include <dns/rdataclass.h> 53#include <dns/rdataset.h> 54#include <dns/rdatasetiter.h> 55#include <dns/rdatatype.h> 56#include <dns/result.h> 57#include <dns/secalg.h> 58#include <dns/time.h> 59 60#include "dnssectool.h" 61 62static isc_heap_t *expected_chains, *found_chains; 63 64struct nsec3_chain_fixed { 65 isc_uint8_t hash; 66 isc_uint8_t salt_length; 67 isc_uint8_t next_length; 68 isc_uint16_t iterations; 69 /* unsigned char salt[0]; */ 70 /* unsigned char owner[0]; */ 71 /* unsigned char next[0]; */ 72}; 73 74extern int verbose; 75extern const char *program; 76 77typedef struct entropysource entropysource_t; 78 79struct entropysource { 80 isc_entropysource_t *source; 81 isc_mem_t *mctx; 82 ISC_LINK(entropysource_t) link; 83}; 84 85static ISC_LIST(entropysource_t) sources; 86static fatalcallback_t *fatalcallback = NULL; 87 88void 89fatal(const char *format, ...) { 90 va_list args; 91 92 fprintf(stderr, "%s: fatal: ", program); 93 va_start(args, format); 94 vfprintf(stderr, format, args); 95 va_end(args); 96 fprintf(stderr, "\n"); 97 if (fatalcallback != NULL) 98 (*fatalcallback)(); 99 exit(1); 100} 101 102void 103setfatalcallback(fatalcallback_t *callback) { 104 fatalcallback = callback; 105} 106 107void 108check_result(isc_result_t result, const char *message) { 109 if (result != ISC_R_SUCCESS) 110 fatal("%s: %s", message, isc_result_totext(result)); 111} 112 113void 114vbprintf(int level, const char *fmt, ...) { 115 va_list ap; 116 if (level > verbose) 117 return; 118 va_start(ap, fmt); 119 fprintf(stderr, "%s: ", program); 120 vfprintf(stderr, fmt, ap); 121 va_end(ap); 122} 123 124void 125type_format(const dns_rdatatype_t type, char *cp, unsigned int size) { 126 isc_buffer_t b; 127 isc_region_t r; 128 isc_result_t result; 129 130 isc_buffer_init(&b, cp, size - 1); 131 result = dns_rdatatype_totext(type, &b); 132 check_result(result, "dns_rdatatype_totext()"); 133 isc_buffer_usedregion(&b, &r); 134 r.base[r.length] = 0; 135} 136 137void 138sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) { 139 char namestr[DNS_NAME_FORMATSIZE]; 140 char algstr[DNS_NAME_FORMATSIZE]; 141 142 dns_name_format(&sig->signer, namestr, sizeof(namestr)); 143 dns_secalg_format(sig->algorithm, algstr, sizeof(algstr)); 144 snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid); 145} 146 147void 148setup_logging(int verbose, isc_mem_t *mctx, isc_log_t **logp) { 149 isc_result_t result; 150 isc_logdestination_t destination; 151 isc_logconfig_t *logconfig = NULL; 152 isc_log_t *log = NULL; 153 int level; 154 155 if (verbose < 0) 156 verbose = 0; 157 switch (verbose) { 158 case 0: 159 /* 160 * We want to see warnings about things like out-of-zone 161 * data in the master file even when not verbose. 162 */ 163 level = ISC_LOG_WARNING; 164 break; 165 case 1: 166 level = ISC_LOG_INFO; 167 break; 168 default: 169 level = ISC_LOG_DEBUG(verbose - 2 + 1); 170 break; 171 } 172 173 RUNTIME_CHECK(isc_log_create(mctx, &log, &logconfig) == ISC_R_SUCCESS); 174 isc_log_setcontext(log); 175 dns_log_init(log); 176 dns_log_setcontext(log); 177 178 RUNTIME_CHECK(isc_log_settag(logconfig, program) == ISC_R_SUCCESS); 179 180 /* 181 * Set up a channel similar to default_stderr except: 182 * - the logging level is passed in 183 * - the program name and logging level are printed 184 * - no time stamp is printed 185 */ 186 destination.file.stream = stderr; 187 destination.file.name = NULL; 188 destination.file.versions = ISC_LOG_ROLLNEVER; 189 destination.file.maximum_size = 0; 190 result = isc_log_createchannel(logconfig, "stderr", 191 ISC_LOG_TOFILEDESC, 192 level, 193 &destination, 194 ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL); 195 check_result(result, "isc_log_createchannel()"); 196 197 RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", 198 NULL, NULL) == ISC_R_SUCCESS); 199 200 *logp = log; 201} 202 203void 204cleanup_logging(isc_log_t **logp) { 205 isc_log_t *log; 206 207 REQUIRE(logp != NULL); 208 209 log = *logp; 210 if (log == NULL) 211 return; 212 isc_log_destroy(&log); 213 isc_log_setcontext(NULL); 214 dns_log_setcontext(NULL); 215 logp = NULL; 216} 217 218void 219setup_entropy(isc_mem_t *mctx, const char *randomfile, isc_entropy_t **ectx) { 220 isc_result_t result; 221 isc_entropysource_t *source = NULL; 222 entropysource_t *elt; 223 int usekeyboard = ISC_ENTROPY_KEYBOARDMAYBE; 224 225 REQUIRE(ectx != NULL); 226 227 if (*ectx == NULL) { 228 result = isc_entropy_create(mctx, ectx); 229 if (result != ISC_R_SUCCESS) 230 fatal("could not create entropy object"); 231 ISC_LIST_INIT(sources); 232 } 233 234 if (randomfile != NULL && strcmp(randomfile, "keyboard") == 0) { 235 usekeyboard = ISC_ENTROPY_KEYBOARDYES; 236 randomfile = NULL; 237 } 238 239 result = isc_entropy_usebestsource(*ectx, &source, randomfile, 240 usekeyboard); 241 242 if (result != ISC_R_SUCCESS) 243 fatal("could not initialize entropy source: %s", 244 isc_result_totext(result)); 245 246 if (source != NULL) { 247 elt = isc_mem_get(mctx, sizeof(*elt)); 248 if (elt == NULL) 249 fatal("out of memory"); 250 elt->source = source; 251 elt->mctx = mctx; 252 ISC_LINK_INIT(elt, link); 253 ISC_LIST_APPEND(sources, elt, link); 254 } 255} 256 257void 258cleanup_entropy(isc_entropy_t **ectx) { 259 entropysource_t *source; 260 while (!ISC_LIST_EMPTY(sources)) { 261 source = ISC_LIST_HEAD(sources); 262 ISC_LIST_UNLINK(sources, source, link); 263 isc_entropy_destroysource(&source->source); 264 isc_mem_put(source->mctx, source, sizeof(*source)); 265 } 266 isc_entropy_detach(ectx); 267} 268 269static isc_stdtime_t 270time_units(isc_stdtime_t offset, char *suffix, const char *str) { 271 switch (suffix[0]) { 272 case 'Y': case 'y': 273 return (offset * (365 * 24 * 3600)); 274 case 'M': case 'm': 275 switch (suffix[1]) { 276 case 'O': case 'o': 277 return (offset * (30 * 24 * 3600)); 278 case 'I': case 'i': 279 return (offset * 60); 280 case '\0': 281 fatal("'%s' ambiguous: use 'mi' for minutes " 282 "or 'mo' for months", str); 283 default: 284 fatal("time value %s is invalid", str); 285 } 286 /* NOTREACHED */ 287 break; 288 case 'W': case 'w': 289 return (offset * (7 * 24 * 3600)); 290 case 'D': case 'd': 291 return (offset * (24 * 3600)); 292 case 'H': case 'h': 293 return (offset * 3600); 294 case 'S': case 's': case '\0': 295 return (offset); 296 default: 297 fatal("time value %s is invalid", str); 298 } 299 /* NOTREACHED */ 300 return(0); /* silence compiler warning */ 301} 302 303dns_ttl_t 304strtottl(const char *str) { 305 const char *orig = str; 306 dns_ttl_t ttl; 307 char *endp; 308 309 ttl = strtol(str, &endp, 0); 310 if (ttl == 0 && endp == str) 311 fatal("TTL must be numeric"); 312 ttl = time_units(ttl, endp, orig); 313 return (ttl); 314} 315 316isc_stdtime_t 317strtotime(const char *str, isc_int64_t now, isc_int64_t base) { 318 isc_int64_t val, offset; 319 isc_result_t result; 320 const char *orig = str; 321 char *endp; 322 int n; 323 324 if ((str[0] == '0' || str[0] == '-') && str[1] == '\0') 325 return ((isc_stdtime_t) 0); 326 327 /* 328 * We accept times in the following formats: 329 * now([+-]offset) 330 * YYYYMMDD([+-]offset) 331 * YYYYMMDDhhmmss([+-]offset) 332 * [+-]offset 333 */ 334 n = strspn(str, "0123456789"); 335 if ((n == 8 || n == 14) && 336 (str[n] == '\0' || str[n] == '-' || str[n] == '+')) 337 { 338 char timestr[15]; 339 340 strlcpy(timestr, str, sizeof(timestr)); 341 timestr[n] = 0; 342 if (n == 8) 343 strlcat(timestr, "000000", sizeof(timestr)); 344 result = dns_time64_fromtext(timestr, &val); 345 if (result != ISC_R_SUCCESS) 346 fatal("time value %s is invalid: %s", orig, 347 isc_result_totext(result)); 348 base = val; 349 str += n; 350 } else if (strncmp(str, "now", 3) == 0) { 351 base = now; 352 str += 3; 353 } 354 355 if (str[0] == '\0') 356 return ((isc_stdtime_t) base); 357 else if (str[0] == '+') { 358 offset = strtol(str + 1, &endp, 0); 359 offset = time_units((isc_stdtime_t) offset, endp, orig); 360 val = base + offset; 361 } else if (str[0] == '-') { 362 offset = strtol(str + 1, &endp, 0); 363 offset = time_units((isc_stdtime_t) offset, endp, orig); 364 val = base - offset; 365 } else 366 fatal("time value %s is invalid", orig); 367 368 return ((isc_stdtime_t) val); 369} 370 371dns_rdataclass_t 372strtoclass(const char *str) { 373 isc_textregion_t r; 374 dns_rdataclass_t rdclass; 375 isc_result_t ret; 376 377 if (str == NULL) 378 return dns_rdataclass_in; 379 DE_CONST(str, r.base); 380 r.length = strlen(str); 381 ret = dns_rdataclass_fromtext(&rdclass, &r); 382 if (ret != ISC_R_SUCCESS) 383 fatal("unknown class %s", str); 384 return (rdclass); 385} 386 387isc_result_t 388try_dir(const char *dirname) { 389 isc_result_t result; 390 isc_dir_t d; 391 392 isc_dir_init(&d); 393 result = isc_dir_open(&d, dirname); 394 if (result == ISC_R_SUCCESS) { 395 isc_dir_close(&d); 396 } 397 return (result); 398} 399 400/* 401 * Check private key version compatibility. 402 */ 403void 404check_keyversion(dst_key_t *key, char *keystr) { 405 int major, minor; 406 dst_key_getprivateformat(key, &major, &minor); 407 INSIST(major <= DST_MAJOR_VERSION); /* invalid private key */ 408 409 if (major < DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) 410 fatal("Key %s has incompatible format version %d.%d, " 411 "use -f to force upgrade to new version.", 412 keystr, major, minor); 413 if (minor > DST_MINOR_VERSION) 414 fatal("Key %s has incompatible format version %d.%d, " 415 "use -f to force downgrade to current version.", 416 keystr, major, minor); 417} 418 419void 420set_keyversion(dst_key_t *key) { 421 int major, minor; 422 dst_key_getprivateformat(key, &major, &minor); 423 INSIST(major <= DST_MAJOR_VERSION); 424 425 if (major != DST_MAJOR_VERSION || minor != DST_MINOR_VERSION) 426 dst_key_setprivateformat(key, DST_MAJOR_VERSION, 427 DST_MINOR_VERSION); 428 429 /* 430 * If the key is from a version older than 1.3, set 431 * set the creation date 432 */ 433 if (major < 1 || (major == 1 && minor <= 2)) { 434 isc_stdtime_t now; 435 isc_stdtime_get(&now); 436 dst_key_settime(key, DST_TIME_CREATED, now); 437 } 438} 439 440isc_boolean_t 441key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir, 442 isc_mem_t *mctx, isc_boolean_t *exact) 443{ 444 isc_result_t result; 445 isc_boolean_t conflict = ISC_FALSE; 446 dns_dnsseckeylist_t matchkeys; 447 dns_dnsseckey_t *key = NULL; 448 isc_uint16_t id, oldid; 449 isc_uint32_t rid, roldid; 450 dns_secalg_t alg; 451 452 if (exact != NULL) 453 *exact = ISC_FALSE; 454 455 id = dst_key_id(dstkey); 456 rid = dst_key_rid(dstkey); 457 alg = dst_key_alg(dstkey); 458 459 ISC_LIST_INIT(matchkeys); 460 result = dns_dnssec_findmatchingkeys(name, dir, mctx, &matchkeys); 461 if (result == ISC_R_NOTFOUND) 462 return (ISC_FALSE); 463 464 while (!ISC_LIST_EMPTY(matchkeys) && !conflict) { 465 key = ISC_LIST_HEAD(matchkeys); 466 if (dst_key_alg(key->key) != alg) 467 goto next; 468 469 oldid = dst_key_id(key->key); 470 roldid = dst_key_rid(key->key); 471 472 if (oldid == rid || roldid == id || id == oldid) { 473 conflict = ISC_TRUE; 474 if (id != oldid) { 475 if (verbose > 1) 476 fprintf(stderr, "Key ID %d could " 477 "collide with %d\n", 478 id, oldid); 479 } else { 480 if (exact != NULL) 481 *exact = ISC_TRUE; 482 if (verbose > 1) 483 fprintf(stderr, "Key ID %d exists\n", 484 id); 485 } 486 } 487 488 next: 489 ISC_LIST_UNLINK(matchkeys, key, link); 490 dns_dnsseckey_destroy(mctx, &key); 491 } 492 493 /* Finish freeing the list */ 494 while (!ISC_LIST_EMPTY(matchkeys)) { 495 key = ISC_LIST_HEAD(matchkeys); 496 ISC_LIST_UNLINK(matchkeys, key, link); 497 dns_dnsseckey_destroy(mctx, &key); 498 } 499 500 return (conflict); 501} 502 503isc_boolean_t 504is_delegation(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 505 dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp) 506{ 507 dns_rdataset_t nsset; 508 isc_result_t result; 509 510 if (dns_name_equal(name, origin)) 511 return (ISC_FALSE); 512 513 dns_rdataset_init(&nsset); 514 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_ns, 515 0, 0, &nsset, NULL); 516 if (dns_rdataset_isassociated(&nsset)) { 517 if (ttlp != NULL) 518 *ttlp = nsset.ttl; 519 dns_rdataset_disassociate(&nsset); 520 } 521 522 return (ISC_TF(result == ISC_R_SUCCESS)); 523} 524 525static isc_boolean_t 526goodsig(dns_name_t *origin, dns_rdata_t *sigrdata, dns_name_t *name, 527 dns_rdataset_t *keyrdataset, dns_rdataset_t *rdataset, isc_mem_t *mctx) 528{ 529 dns_rdata_dnskey_t key; 530 dns_rdata_rrsig_t sig; 531 dst_key_t *dstkey = NULL; 532 isc_result_t result; 533 534 result = dns_rdata_tostruct(sigrdata, &sig, NULL); 535 check_result(result, "dns_rdata_tostruct()"); 536 537 for (result = dns_rdataset_first(keyrdataset); 538 result == ISC_R_SUCCESS; 539 result = dns_rdataset_next(keyrdataset)) { 540 dns_rdata_t rdata = DNS_RDATA_INIT; 541 dns_rdataset_current(keyrdataset, &rdata); 542 result = dns_rdata_tostruct(&rdata, &key, NULL); 543 check_result(result, "dns_rdata_tostruct()"); 544 result = dns_dnssec_keyfromrdata(origin, &rdata, mctx, 545 &dstkey); 546 if (result != ISC_R_SUCCESS) 547 return (ISC_FALSE); 548 if (sig.algorithm != key.algorithm || 549 sig.keyid != dst_key_id(dstkey) || 550 !dns_name_equal(&sig.signer, origin)) { 551 dst_key_free(&dstkey); 552 continue; 553 } 554 result = dns_dnssec_verify(name, rdataset, dstkey, ISC_FALSE, 555 mctx, sigrdata); 556 dst_key_free(&dstkey); 557 if (result == ISC_R_SUCCESS) 558 return(ISC_TRUE); 559 } 560 return (ISC_FALSE); 561} 562 563static isc_result_t 564verifynsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 565 dns_dbnode_t *node, dns_name_t *nextname) 566{ 567 unsigned char buffer[DNS_NSEC_BUFFERSIZE]; 568 char namebuf[DNS_NAME_FORMATSIZE]; 569 char nextbuf[DNS_NAME_FORMATSIZE]; 570 char found[DNS_NAME_FORMATSIZE]; 571 dns_rdataset_t rdataset; 572 dns_rdata_t rdata = DNS_RDATA_INIT; 573 dns_rdata_t tmprdata = DNS_RDATA_INIT; 574 dns_rdata_nsec_t nsec; 575 isc_result_t result; 576 577 dns_rdataset_init(&rdataset); 578 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 579 0, 0, &rdataset, NULL); 580 if (result != ISC_R_SUCCESS) { 581 dns_name_format(name, namebuf, sizeof(namebuf)); 582 fprintf(stderr, "Missing NSEC record for %s\n", namebuf); 583 goto failure; 584 } 585 586 result = dns_rdataset_first(&rdataset); 587 check_result(result, "dns_rdataset_first()"); 588 589 dns_rdataset_current(&rdataset, &rdata); 590 result = dns_rdata_tostruct(&rdata, &nsec, NULL); 591 check_result(result, "dns_rdata_tostruct()"); 592 /* Check bit next name is consistent */ 593 if (!dns_name_equal(&nsec.next, nextname)) { 594 dns_name_format(name, namebuf, sizeof(namebuf)); 595 dns_name_format(nextname, nextbuf, sizeof(nextbuf)); 596 dns_name_format(&nsec.next, found, sizeof(found)); 597 fprintf(stderr, "Bad NSEC record for %s, next name " 598 "mismatch (expected:%s, found:%s)\n", namebuf, 599 nextbuf, found); 600 goto failure; 601 } 602 /* Check bit map is consistent */ 603 result = dns_nsec_buildrdata(db, ver, node, nextname, buffer, 604 &tmprdata); 605 check_result(result, "dns_nsec_buildrdata()"); 606 if (dns_rdata_compare(&rdata, &tmprdata) != 0) { 607 dns_name_format(name, namebuf, sizeof(namebuf)); 608 fprintf(stderr, "Bad NSEC record for %s, bit map " 609 "mismatch\n", namebuf); 610 goto failure; 611 } 612 result = dns_rdataset_next(&rdataset); 613 if (result != ISC_R_NOMORE) { 614 dns_name_format(name, namebuf, sizeof(namebuf)); 615 fprintf(stderr, "Multipe NSEC records for %s\n", namebuf); 616 goto failure; 617 618 } 619 dns_rdataset_disassociate(&rdataset); 620 return (ISC_R_SUCCESS); 621 failure: 622 if (dns_rdataset_isassociated(&rdataset)) 623 dns_rdataset_disassociate(&rdataset); 624 return (ISC_R_FAILURE); 625} 626 627static void 628check_no_rrsig(dns_db_t *db, dns_dbversion_t *ver, dns_rdataset_t *rdataset, 629 dns_name_t *name, dns_dbnode_t *node) 630{ 631 char namebuf[DNS_NAME_FORMATSIZE]; 632 char typebuf[80]; 633 dns_rdataset_t sigrdataset; 634 dns_rdatasetiter_t *rdsiter = NULL; 635 isc_result_t result; 636 637 dns_rdataset_init(&sigrdataset); 638 result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter); 639 check_result(result, "dns_db_allrdatasets()"); 640 for (result = dns_rdatasetiter_first(rdsiter); 641 result == ISC_R_SUCCESS; 642 result = dns_rdatasetiter_next(rdsiter)) { 643 dns_rdatasetiter_current(rdsiter, &sigrdataset); 644 if (sigrdataset.type == dns_rdatatype_rrsig && 645 sigrdataset.covers == rdataset->type) 646 break; 647 dns_rdataset_disassociate(&sigrdataset); 648 } 649 if (result == ISC_R_SUCCESS) { 650 dns_name_format(name, namebuf, sizeof(namebuf)); 651 type_format(rdataset->type, typebuf, sizeof(typebuf)); 652 fprintf(stderr, "Warning: Found unexpected signatures for " 653 "%s/%s\n", namebuf, typebuf); 654 } 655 if (dns_rdataset_isassociated(&sigrdataset)) 656 dns_rdataset_disassociate(&sigrdataset); 657 dns_rdatasetiter_destroy(&rdsiter); 658} 659 660static isc_boolean_t 661chain_compare(void *arg1, void *arg2) { 662 struct nsec3_chain_fixed *e1 = arg1, *e2 = arg2; 663 size_t len; 664 665 /* 666 * Do each element in turn to get a stable sort. 667 */ 668 if (e1->hash < e2->hash) 669 return (ISC_TRUE); 670 if (e1->hash > e2->hash) 671 return (ISC_FALSE); 672 if (e1->iterations < e2->iterations) 673 return (ISC_TRUE); 674 if (e1->iterations > e2->iterations) 675 return (ISC_FALSE); 676 if (e1->salt_length < e2->salt_length) 677 return (ISC_TRUE); 678 if (e1->salt_length > e2->salt_length) 679 return (ISC_FALSE); 680 if (e1->next_length < e2->next_length) 681 return (ISC_TRUE); 682 if (e1->next_length > e2->next_length) 683 return (ISC_FALSE); 684 len = e1->salt_length + 2 * e1->next_length; 685 if (memcmp(e1 + 1, e2 + 1, len) < 0) 686 return (ISC_TRUE); 687 return (ISC_FALSE); 688} 689 690static isc_boolean_t 691chain_equal(struct nsec3_chain_fixed *e1, struct nsec3_chain_fixed *e2) { 692 size_t len; 693 694 if (e1->hash != e2->hash) 695 return (ISC_FALSE); 696 if (e1->iterations != e2->iterations) 697 return (ISC_FALSE); 698 if (e1->salt_length != e2->salt_length) 699 return (ISC_FALSE); 700 if (e1->next_length != e2->next_length) 701 return (ISC_FALSE); 702 len = e1->salt_length + 2 * e1->next_length; 703 if (memcmp(e1 + 1, e2 + 1, len) != 0) 704 return (ISC_FALSE); 705 return (ISC_TRUE); 706} 707 708static isc_result_t 709record_nsec3(const unsigned char *rawhash, const dns_rdata_nsec3_t *nsec3, 710 isc_mem_t *mctx, isc_heap_t *chains) 711{ 712 struct nsec3_chain_fixed *element; 713 size_t len; 714 unsigned char *cp; 715 isc_result_t result; 716 717 len = sizeof(*element) + nsec3->next_length * 2 + nsec3->salt_length; 718 719 element = isc_mem_get(mctx, len); 720 if (element == NULL) 721 return (ISC_R_NOMEMORY); 722 memset(element, 0, len); 723 element->hash = nsec3->hash; 724 element->salt_length = nsec3->salt_length; 725 element->next_length = nsec3->next_length; 726 element->iterations = nsec3->iterations; 727 cp = (unsigned char *)(element + 1); 728 memmove(cp, nsec3->salt, nsec3->salt_length); 729 cp += nsec3->salt_length; 730 memmove(cp, rawhash, nsec3->next_length); 731 cp += nsec3->next_length; 732 memmove(cp, nsec3->next, nsec3->next_length); 733 result = isc_heap_insert(chains, element); 734 if (result != ISC_R_SUCCESS) { 735 fprintf(stderr, "isc_heap_insert failed: %s\n", 736 isc_result_totext(result)); 737 isc_mem_put(mctx, element, len); 738 } 739 return (result); 740} 741 742static isc_result_t 743match_nsec3(dns_name_t *name, isc_mem_t *mctx, 744 dns_rdata_nsec3param_t *nsec3param, dns_rdataset_t *rdataset, 745 unsigned char types[8192], unsigned int maxtype, 746 unsigned char *rawhash, size_t rhsize) 747{ 748 unsigned char cbm[8244]; 749 char namebuf[DNS_NAME_FORMATSIZE]; 750 dns_rdata_nsec3_t nsec3; 751 isc_result_t result; 752 unsigned int len; 753 754 /* 755 * Find matching NSEC3 record. 756 */ 757 for (result = dns_rdataset_first(rdataset); 758 result == ISC_R_SUCCESS; 759 result = dns_rdataset_next(rdataset)) { 760 dns_rdata_t rdata = DNS_RDATA_INIT; 761 dns_rdataset_current(rdataset, &rdata); 762 result = dns_rdata_tostruct(&rdata, &nsec3, NULL); 763 check_result(result, "dns_rdata_tostruct()"); 764 if (nsec3.hash == nsec3param->hash && 765 nsec3.next_length == rhsize && 766 nsec3.iterations == nsec3param->iterations && 767 nsec3.salt_length == nsec3param->salt_length && 768 memcmp(nsec3.salt, nsec3param->salt, 769 nsec3param->salt_length) == 0) 770 break; 771 } 772 if (result != ISC_R_SUCCESS) { 773 dns_name_format(name, namebuf, sizeof(namebuf)); 774 fprintf(stderr, "Missing NSEC3 record for %s\n", namebuf); 775 return (result); 776 } 777 778 /* 779 * Check the type list. 780 */ 781 len = dns_nsec_compressbitmap(cbm, types, maxtype); 782 if (nsec3.len != len || memcmp(cbm, nsec3.typebits, len) != 0) { 783 dns_name_format(name, namebuf, sizeof(namebuf)); 784 fprintf(stderr, "Bad NSEC3 record for %s, bit map " 785 "mismatch\n", namebuf); 786 return (ISC_R_FAILURE); 787 } 788 789 /* 790 * Record chain. 791 */ 792 result = record_nsec3(rawhash, &nsec3, mctx, expected_chains); 793 check_result(result, "record_nsec3()"); 794 795 /* 796 * Make sure there is only one NSEC3 record with this set of 797 * parameters. 798 */ 799 for (result = dns_rdataset_next(rdataset); 800 result == ISC_R_SUCCESS; 801 result = dns_rdataset_next(rdataset)) { 802 dns_rdata_t rdata = DNS_RDATA_INIT; 803 dns_rdataset_current(rdataset, &rdata); 804 result = dns_rdata_tostruct(&rdata, &nsec3, NULL); 805 check_result(result, "dns_rdata_tostruct()"); 806 if (nsec3.hash == nsec3param->hash && 807 nsec3.iterations == nsec3param->iterations && 808 nsec3.salt_length == nsec3param->salt_length && 809 memcmp(nsec3.salt, nsec3param->salt, 810 nsec3.salt_length) == 0) { 811 dns_name_format(name, namebuf, sizeof(namebuf)); 812 fprintf(stderr, "Multiple NSEC3 records with the " 813 "same parameter set for %s", namebuf); 814 result = DNS_R_DUPLICATE; 815 break; 816 } 817 } 818 if (result != ISC_R_NOMORE) 819 return (result); 820 821 result = ISC_R_SUCCESS; 822 return (result); 823} 824 825static isc_boolean_t 826innsec3params(dns_rdata_nsec3_t *nsec3, dns_rdataset_t *nsec3paramset) { 827 dns_rdata_nsec3param_t nsec3param; 828 isc_result_t result; 829 830 for (result = dns_rdataset_first(nsec3paramset); 831 result == ISC_R_SUCCESS; 832 result = dns_rdataset_next(nsec3paramset)) { 833 dns_rdata_t rdata = DNS_RDATA_INIT; 834 835 dns_rdataset_current(nsec3paramset, &rdata); 836 result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); 837 check_result(result, "dns_rdata_tostruct()"); 838 if (nsec3param.flags == 0 && 839 nsec3param.hash == nsec3->hash && 840 nsec3param.iterations == nsec3->iterations && 841 nsec3param.salt_length == nsec3->salt_length && 842 memcmp(nsec3param.salt, nsec3->salt, 843 nsec3->salt_length) == 0) 844 return (ISC_TRUE); 845 } 846 return (ISC_FALSE); 847} 848 849static isc_result_t 850record_found(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx, 851 dns_name_t *name, dns_dbnode_t *node, 852 dns_rdataset_t *nsec3paramset) 853{ 854 unsigned char owner[NSEC3_MAX_HASH_LENGTH]; 855 dns_rdata_nsec3_t nsec3; 856 dns_rdataset_t rdataset; 857 dns_label_t hashlabel; 858 isc_buffer_t b; 859 isc_result_t result; 860 861 if (nsec3paramset == NULL || !dns_rdataset_isassociated(nsec3paramset)) 862 return (ISC_R_SUCCESS); 863 864 dns_rdataset_init(&rdataset); 865 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3, 866 0, 0, &rdataset, NULL); 867 if (result != ISC_R_SUCCESS) 868 return (ISC_R_SUCCESS); 869 870 dns_name_getlabel(name, 0, &hashlabel); 871 isc_region_consume(&hashlabel, 1); 872 isc_buffer_init(&b, owner, sizeof(owner)); 873 result = isc_base32hex_decoderegion(&hashlabel, &b); 874 if (result != ISC_R_SUCCESS) 875 goto cleanup; 876 877 for (result = dns_rdataset_first(&rdataset); 878 result == ISC_R_SUCCESS; 879 result = dns_rdataset_next(&rdataset)) { 880 dns_rdata_t rdata = DNS_RDATA_INIT; 881 dns_rdataset_current(&rdataset, &rdata); 882 result = dns_rdata_tostruct(&rdata, &nsec3, NULL); 883 check_result(result, "dns_rdata_tostruct()"); 884 if (nsec3.next_length != isc_buffer_usedlength(&b)) 885 continue; 886 /* 887 * We only care about NSEC3 records that match a NSEC3PARAM 888 * record. 889 */ 890 if (!innsec3params(&nsec3, nsec3paramset)) 891 continue; 892 893 /* 894 * Record chain. 895 */ 896 result = record_nsec3(owner, &nsec3, mctx, found_chains); 897 check_result(result, "record_nsec3()"); 898 } 899 900 cleanup: 901 dns_rdataset_disassociate(&rdataset); 902 return (ISC_R_SUCCESS); 903} 904 905static isc_boolean_t 906isoptout(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 907 dns_rdata_t *nsec3rdata) 908{ 909 dns_rdataset_t rdataset; 910 dns_rdata_t rdata = DNS_RDATA_INIT; 911 dns_rdata_nsec3_t nsec3; 912 dns_rdata_nsec3param_t nsec3param; 913 dns_fixedname_t fixed; 914 dns_name_t *hashname; 915 isc_result_t result; 916 dns_dbnode_t *node = NULL; 917 unsigned char rawhash[NSEC3_MAX_HASH_LENGTH]; 918 size_t rhsize = sizeof(rawhash); 919 isc_boolean_t ret; 920 921 result = dns_rdata_tostruct(nsec3rdata, &nsec3param, NULL); 922 check_result(result, "dns_rdata_tostruct()"); 923 924 dns_fixedname_init(&fixed); 925 result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, origin, origin, 926 nsec3param.hash, nsec3param.iterations, 927 nsec3param.salt, nsec3param.salt_length); 928 check_result(result, "dns_nsec3_hashname()"); 929 930 dns_rdataset_init(&rdataset); 931 hashname = dns_fixedname_name(&fixed); 932 result = dns_db_findnsec3node(db, hashname, ISC_FALSE, &node); 933 if (result == ISC_R_SUCCESS) 934 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3, 935 0, 0, &rdataset, NULL); 936 if (result != ISC_R_SUCCESS) 937 return (ISC_FALSE); 938 939 result = dns_rdataset_first(&rdataset); 940 check_result(result, "dns_rdataset_first()"); 941 942 dns_rdataset_current(&rdataset, &rdata); 943 944 result = dns_rdata_tostruct(&rdata, &nsec3, NULL); 945 if (result != ISC_R_SUCCESS) 946 ret = ISC_FALSE; 947 else 948 ret = ISC_TF((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0); 949 950 if (dns_rdataset_isassociated(&rdataset)) 951 dns_rdataset_disassociate(&rdataset); 952 if (node != NULL) 953 dns_db_detachnode(db, &node); 954 955 return (ret); 956} 957 958static isc_result_t 959verifynsec3(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 960 isc_mem_t *mctx, dns_name_t *name, dns_rdata_t *rdata, 961 isc_boolean_t delegation, isc_boolean_t empty, 962 unsigned char types[8192], unsigned int maxtype) 963{ 964 char namebuf[DNS_NAME_FORMATSIZE]; 965 char hashbuf[DNS_NAME_FORMATSIZE]; 966 dns_rdataset_t rdataset; 967 dns_rdata_nsec3param_t nsec3param; 968 dns_fixedname_t fixed; 969 dns_name_t *hashname; 970 isc_result_t result; 971 dns_dbnode_t *node = NULL; 972 unsigned char rawhash[NSEC3_MAX_HASH_LENGTH]; 973 size_t rhsize = sizeof(rawhash); 974 isc_boolean_t optout; 975 976 result = dns_rdata_tostruct(rdata, &nsec3param, NULL); 977 check_result(result, "dns_rdata_tostruct()"); 978 979 if (nsec3param.flags != 0) 980 return (ISC_R_SUCCESS); 981 982 if (!dns_nsec3_supportedhash(nsec3param.hash)) 983 return (ISC_R_SUCCESS); 984 985 optout = isoptout(db, ver, origin, rdata); 986 987 dns_fixedname_init(&fixed); 988 result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, name, origin, 989 nsec3param.hash, nsec3param.iterations, 990 nsec3param.salt, nsec3param.salt_length); 991 check_result(result, "dns_nsec3_hashname()"); 992 993 /* 994 * We don't use dns_db_find() here as it works with the choosen 995 * nsec3 chain and we may also be called with uncommitted data 996 * from dnssec-signzone so the secure status of the zone may not 997 * be up to date. 998 */ 999 dns_rdataset_init(&rdataset); 1000 hashname = dns_fixedname_name(&fixed); 1001 result = dns_db_findnsec3node(db, hashname, ISC_FALSE, &node); 1002 if (result == ISC_R_SUCCESS) 1003 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3, 1004 0, 0, &rdataset, NULL); 1005 if (result != ISC_R_SUCCESS && 1006 (!delegation || (empty && !optout) || 1007 (!empty && dns_nsec_isset(types, dns_rdatatype_ds)))) 1008 { 1009 dns_name_format(name, namebuf, sizeof(namebuf)); 1010 dns_name_format(hashname, hashbuf, sizeof(hashbuf)); 1011 fprintf(stderr, "Missing NSEC3 record for %s (%s)\n", 1012 namebuf, hashbuf); 1013 } else if (result == ISC_R_NOTFOUND && 1014 delegation && (!empty || optout)) 1015 { 1016 result = ISC_R_SUCCESS; 1017 } else if (result == ISC_R_SUCCESS) { 1018 result = match_nsec3(name, mctx, &nsec3param, &rdataset, 1019 types, maxtype, rawhash, rhsize); 1020 } 1021 1022 if (dns_rdataset_isassociated(&rdataset)) 1023 dns_rdataset_disassociate(&rdataset); 1024 if (node != NULL) 1025 dns_db_detachnode(db, &node); 1026 1027 return (result); 1028} 1029 1030static isc_result_t 1031verifynsec3s(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 1032 isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *nsec3paramset, 1033 isc_boolean_t delegation, isc_boolean_t empty, 1034 unsigned char types[8192], unsigned int maxtype) 1035{ 1036 isc_result_t result; 1037 1038 for (result = dns_rdataset_first(nsec3paramset); 1039 result == ISC_R_SUCCESS; 1040 result = dns_rdataset_next(nsec3paramset)) { 1041 dns_rdata_t rdata = DNS_RDATA_INIT; 1042 1043 dns_rdataset_current(nsec3paramset, &rdata); 1044 result = verifynsec3(db, ver, origin, mctx, name, &rdata, 1045 delegation, empty, types, maxtype); 1046 if (result != ISC_R_SUCCESS) 1047 break; 1048 } 1049 if (result == ISC_R_NOMORE) 1050 result = ISC_R_SUCCESS; 1051 return (result); 1052} 1053 1054static void 1055verifyset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 1056 isc_mem_t *mctx, dns_rdataset_t *rdataset, dns_name_t *name, 1057 dns_dbnode_t *node, dns_rdataset_t *keyrdataset, 1058 unsigned char *act_algorithms, unsigned char *bad_algorithms) 1059{ 1060 unsigned char set_algorithms[256]; 1061 char namebuf[DNS_NAME_FORMATSIZE]; 1062 char algbuf[80]; 1063 char typebuf[80]; 1064 dns_rdataset_t sigrdataset; 1065 dns_rdatasetiter_t *rdsiter = NULL; 1066 isc_result_t result; 1067 int i; 1068 1069 dns_rdataset_init(&sigrdataset); 1070 result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter); 1071 check_result(result, "dns_db_allrdatasets()"); 1072 for (result = dns_rdatasetiter_first(rdsiter); 1073 result == ISC_R_SUCCESS; 1074 result = dns_rdatasetiter_next(rdsiter)) { 1075 dns_rdatasetiter_current(rdsiter, &sigrdataset); 1076 if (sigrdataset.type == dns_rdatatype_rrsig && 1077 sigrdataset.covers == rdataset->type) 1078 break; 1079 dns_rdataset_disassociate(&sigrdataset); 1080 } 1081 if (result != ISC_R_SUCCESS) { 1082 dns_name_format(name, namebuf, sizeof(namebuf)); 1083 type_format(rdataset->type, typebuf, sizeof(typebuf)); 1084 fprintf(stderr, "No signatures for %s/%s\n", namebuf, typebuf); 1085 for (i = 0; i < 256; i++) 1086 if (act_algorithms[i] != 0) 1087 bad_algorithms[i] = 1; 1088 dns_rdatasetiter_destroy(&rdsiter); 1089 return; 1090 } 1091 1092 memset(set_algorithms, 0, sizeof(set_algorithms)); 1093 for (result = dns_rdataset_first(&sigrdataset); 1094 result == ISC_R_SUCCESS; 1095 result = dns_rdataset_next(&sigrdataset)) { 1096 dns_rdata_t rdata = DNS_RDATA_INIT; 1097 dns_rdata_rrsig_t sig; 1098 1099 dns_rdataset_current(&sigrdataset, &rdata); 1100 result = dns_rdata_tostruct(&rdata, &sig, NULL); 1101 check_result(result, "dns_rdata_tostruct()"); 1102 if (rdataset->ttl != sig.originalttl) { 1103 dns_name_format(name, namebuf, sizeof(namebuf)); 1104 type_format(rdataset->type, typebuf, sizeof(typebuf)); 1105 fprintf(stderr, "TTL mismatch for %s %s keytag %u\n", 1106 namebuf, typebuf, sig.keyid); 1107 continue; 1108 } 1109 if ((set_algorithms[sig.algorithm] != 0) || 1110 (act_algorithms[sig.algorithm] == 0)) 1111 continue; 1112 if (goodsig(origin, &rdata, name, keyrdataset, rdataset, mctx)) 1113 set_algorithms[sig.algorithm] = 1; 1114 } 1115 dns_rdatasetiter_destroy(&rdsiter); 1116 if (memcmp(set_algorithms, act_algorithms, sizeof(set_algorithms))) { 1117 dns_name_format(name, namebuf, sizeof(namebuf)); 1118 type_format(rdataset->type, typebuf, sizeof(typebuf)); 1119 for (i = 0; i < 256; i++) 1120 if ((act_algorithms[i] != 0) && 1121 (set_algorithms[i] == 0)) { 1122 dns_secalg_format(i, algbuf, sizeof(algbuf)); 1123 fprintf(stderr, "No correct %s signature for " 1124 "%s %s\n", algbuf, namebuf, typebuf); 1125 bad_algorithms[i] = 1; 1126 } 1127 } 1128 dns_rdataset_disassociate(&sigrdataset); 1129} 1130 1131static isc_result_t 1132verifynode(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 1133 isc_mem_t *mctx, dns_name_t *name, dns_dbnode_t *node, 1134 isc_boolean_t delegation, dns_rdataset_t *keyrdataset, 1135 unsigned char *act_algorithms, unsigned char *bad_algorithms, 1136 dns_rdataset_t *nsecset, dns_rdataset_t *nsec3paramset, 1137 dns_name_t *nextname) 1138{ 1139 unsigned char types[8192]; 1140 unsigned int maxtype = 0; 1141 dns_rdataset_t rdataset; dns_rdatasetiter_t *rdsiter = NULL; 1142 isc_result_t result, tresult; 1143 1144 memset(types, 0, sizeof(types)); 1145 result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter); 1146 check_result(result, "dns_db_allrdatasets()"); 1147 result = dns_rdatasetiter_first(rdsiter); 1148 dns_rdataset_init(&rdataset); 1149 while (result == ISC_R_SUCCESS) { 1150 dns_rdatasetiter_current(rdsiter, &rdataset); 1151 /* 1152 * If we are not at a delegation then everything should be 1153 * signed. If we are at a delegation then only the DS set 1154 * is signed. The NS set is not signed at a delegation but 1155 * its existance is recorded in the bit map. Anything else 1156 * other than NSEC and DS is not signed at a delegation. 1157 */ 1158 if (rdataset.type != dns_rdatatype_rrsig && 1159 rdataset.type != dns_rdatatype_dnskey && 1160 (!delegation || rdataset.type == dns_rdatatype_ds || 1161 rdataset.type == dns_rdatatype_nsec)) { 1162 verifyset(db, ver, origin, mctx, &rdataset, 1163 name, node, keyrdataset, 1164 act_algorithms, bad_algorithms); 1165 dns_nsec_setbit(types, rdataset.type, 1); 1166 if (rdataset.type > maxtype) 1167 maxtype = rdataset.type; 1168 } else if (rdataset.type != dns_rdatatype_rrsig && 1169 rdataset.type != dns_rdatatype_dnskey) { 1170 if (rdataset.type == dns_rdatatype_ns) 1171 dns_nsec_setbit(types, rdataset.type, 1); 1172 check_no_rrsig(db, ver, &rdataset, name, node); 1173 } else 1174 dns_nsec_setbit(types, rdataset.type, 1); 1175 dns_rdataset_disassociate(&rdataset); 1176 result = dns_rdatasetiter_next(rdsiter); 1177 } 1178 if (result != ISC_R_NOMORE) 1179 fatal("rdataset iteration failed: %s", 1180 isc_result_totext(result)); 1181 dns_rdatasetiter_destroy(&rdsiter); 1182 1183 result = ISC_R_SUCCESS; 1184 1185 if (nsecset != NULL && dns_rdataset_isassociated(nsecset)) 1186 result = verifynsec(db, ver, name, node, nextname); 1187 1188 if (nsec3paramset != NULL && dns_rdataset_isassociated(nsec3paramset)) { 1189 tresult = verifynsec3s(db, ver, origin, mctx, name, 1190 nsec3paramset, delegation, ISC_FALSE, 1191 types, maxtype); 1192 if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) 1193 result = tresult; 1194 } 1195 return (result); 1196} 1197 1198static isc_boolean_t 1199is_empty(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node) { 1200 dns_rdatasetiter_t *rdsiter = NULL; 1201 isc_result_t result; 1202 1203 result = dns_db_allrdatasets(db, node, ver, 0, &rdsiter); 1204 check_result(result, "dns_db_allrdatasets()"); 1205 result = dns_rdatasetiter_first(rdsiter); 1206 dns_rdatasetiter_destroy(&rdsiter); 1207 if (result == ISC_R_NOMORE) 1208 return (ISC_TRUE); 1209 return (ISC_FALSE); 1210} 1211 1212static void 1213check_no_nsec(dns_name_t *name, dns_dbnode_t *node, dns_db_t *db, 1214 dns_dbversion_t *ver) 1215{ 1216 dns_rdataset_t rdataset; 1217 isc_result_t result; 1218 1219 dns_rdataset_init(&rdataset); 1220 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 1221 0, 0, &rdataset, NULL); 1222 if (result != ISC_R_NOTFOUND) { 1223 char namebuf[DNS_NAME_FORMATSIZE]; 1224 dns_name_format(name, namebuf, sizeof(namebuf)); 1225 fatal("unexpected NSEC RRset at %s\n", namebuf); 1226 } 1227 1228 if (dns_rdataset_isassociated(&rdataset)) 1229 dns_rdataset_disassociate(&rdataset); 1230} 1231 1232static isc_boolean_t 1233newchain(const struct nsec3_chain_fixed *first, 1234 const struct nsec3_chain_fixed *e) 1235{ 1236 if (first->hash != e->hash || 1237 first->iterations != e->iterations || 1238 first->salt_length != e->salt_length || 1239 first->next_length != e->next_length || 1240 memcmp(first + 1, e + 1, first->salt_length) != 0) 1241 return (ISC_TRUE); 1242 return (ISC_FALSE); 1243} 1244 1245static void 1246free_element(isc_mem_t *mctx, struct nsec3_chain_fixed *e) { 1247 size_t len; 1248 1249 len = sizeof(*e) + e->salt_length + 2 * e->next_length; 1250 isc_mem_put(mctx, e, len); 1251} 1252 1253static isc_boolean_t 1254checknext(const struct nsec3_chain_fixed *first, 1255 const struct nsec3_chain_fixed *e) 1256{ 1257 char buf[512]; 1258 const unsigned char *d1 = (const unsigned char *)(first + 1); 1259 const unsigned char *d2 = (const unsigned char *)(e + 1); 1260 isc_buffer_t b; 1261 isc_region_t sr; 1262 1263 d1 += first->salt_length + first->next_length; 1264 d2 += e->salt_length; 1265 1266 if (memcmp(d1, d2, first->next_length) == 0) 1267 return (ISC_TRUE); 1268 1269 DE_CONST(d1 - first->next_length, sr.base); 1270 sr.length = first->next_length; 1271 isc_buffer_init(&b, buf, sizeof(buf)); 1272 isc_base32hex_totext(&sr, 1, "", &b); 1273 fprintf(stderr, "Break in NSEC3 chain at: %.*s\n", 1274 (int) isc_buffer_usedlength(&b), buf); 1275 1276 DE_CONST(d1, sr.base); 1277 sr.length = first->next_length; 1278 isc_buffer_init(&b, buf, sizeof(buf)); 1279 isc_base32hex_totext(&sr, 1, "", &b); 1280 fprintf(stderr, "Expected: %.*s\n", (int) isc_buffer_usedlength(&b), 1281 buf); 1282 1283 DE_CONST(d2, sr.base); 1284 sr.length = first->next_length; 1285 isc_buffer_init(&b, buf, sizeof(buf)); 1286 isc_base32hex_totext(&sr, 1, "", &b); 1287 fprintf(stderr, "Found: %.*s\n", (int) isc_buffer_usedlength(&b), buf); 1288 1289 return (ISC_FALSE); 1290} 1291 1292#define EXPECTEDANDFOUND "Expected and found NSEC3 chains not equal\n" 1293 1294static isc_result_t 1295verify_nsec3_chains(isc_mem_t *mctx) { 1296 isc_result_t result = ISC_R_SUCCESS; 1297 struct nsec3_chain_fixed *e, *f = NULL; 1298 struct nsec3_chain_fixed *first = NULL, *prev = NULL; 1299 1300 while ((e = isc_heap_element(expected_chains, 1)) != NULL) { 1301 isc_heap_delete(expected_chains, 1); 1302 if (f == NULL) 1303 f = isc_heap_element(found_chains, 1); 1304 if (f != NULL) { 1305 isc_heap_delete(found_chains, 1); 1306 1307 /* 1308 * Check that they match. 1309 */ 1310 if (chain_equal(e, f)) { 1311 free_element(mctx, f); 1312 f = NULL; 1313 } else { 1314 if (result == ISC_R_SUCCESS) 1315 fprintf(stderr, EXPECTEDANDFOUND); 1316 result = ISC_R_FAILURE; 1317 /* 1318 * Attempt to resync found_chain. 1319 */ 1320 while (f != NULL && !chain_compare(e, f)) { 1321 free_element(mctx, f); 1322 f = isc_heap_element(found_chains, 1); 1323 if (f != NULL) 1324 isc_heap_delete(found_chains, 1); 1325 if (f != NULL && chain_equal(e, f)) { 1326 free_element(mctx, f); 1327 f = NULL; 1328 break; 1329 } 1330 } 1331 } 1332 } else if (result == ISC_R_SUCCESS) { 1333 fprintf(stderr, EXPECTEDANDFOUND); 1334 result = ISC_R_FAILURE; 1335 } 1336 if (first == NULL || newchain(first, e)) { 1337 if (prev != NULL) { 1338 if (!checknext(prev, first)) 1339 result = ISC_R_FAILURE; 1340 if (prev != first) 1341 free_element(mctx, prev); 1342 } 1343 if (first != NULL) 1344 free_element(mctx, first); 1345 prev = first = e; 1346 continue; 1347 } 1348 if (!checknext(prev, e)) 1349 result = ISC_R_FAILURE; 1350 if (prev != first) 1351 free_element(mctx, prev); 1352 prev = e; 1353 } 1354 if (prev != NULL) { 1355 if (!checknext(prev, first)) 1356 result = ISC_R_FAILURE; 1357 if (prev != first) 1358 free_element(mctx, prev); 1359 } 1360 if (first != NULL) 1361 free_element(mctx, first); 1362 do { 1363 if (f != NULL) { 1364 if (result == ISC_R_SUCCESS) { 1365 fprintf(stderr, EXPECTEDANDFOUND); 1366 result = ISC_R_FAILURE; 1367 } 1368 free_element(mctx, f); 1369 } 1370 f = isc_heap_element(found_chains, 1); 1371 if (f != NULL) 1372 isc_heap_delete(found_chains, 1); 1373 } while (f != NULL); 1374 1375 return (result); 1376} 1377 1378static isc_result_t 1379verifyemptynodes(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, 1380 isc_mem_t *mctx, dns_name_t *name, dns_name_t *prevname, 1381 isc_boolean_t isdelegation, dns_rdataset_t *nsec3paramset) 1382{ 1383 dns_namereln_t reln; 1384 int order; 1385 unsigned int labels, nlabels, i; 1386 dns_name_t suffix; 1387 isc_result_t result = ISC_R_SUCCESS, tresult; 1388 1389 reln = dns_name_fullcompare(prevname, name, &order, &labels); 1390 if (order >= 0) 1391 return (result); 1392 1393 nlabels = dns_name_countlabels(name); 1394 1395 if (reln == dns_namereln_commonancestor || 1396 reln == dns_namereln_contains) { 1397 dns_name_init(&suffix, NULL); 1398 for (i = labels + 1; i < nlabels; i++) { 1399 dns_name_getlabelsequence(name, nlabels - i, i, 1400 &suffix); 1401 if (nsec3paramset != NULL && 1402 dns_rdataset_isassociated(nsec3paramset)) { 1403 tresult = verifynsec3s(db, ver, origin, mctx, 1404 &suffix, nsec3paramset, 1405 isdelegation, ISC_TRUE, 1406 NULL, 0); 1407 if (result == ISC_R_SUCCESS && 1408 tresult != ISC_R_SUCCESS) 1409 result = tresult; 1410 } 1411 } 1412 } 1413 return (result); 1414} 1415 1416/*% 1417 * Verify that certain things are sane: 1418 * 1419 * The apex has a DNSKEY record with at least one KSK, and at least 1420 * one ZSK if the -x flag was not used. 1421 * 1422 * The DNSKEY record was signed with at least one of the KSKs in this 1423 * set. 1424 * 1425 * The rest of the zone was signed with at least one of the ZSKs 1426 * present in the DNSKEY RRSET. 1427 */ 1428void 1429verifyzone(dns_db_t *db, dns_dbversion_t *ver, 1430 dns_name_t *origin, isc_mem_t *mctx, 1431 isc_boolean_t ignore_kskflag, isc_boolean_t keyset_kskonly) 1432{ 1433 char algbuf[80]; 1434 dns_dbiterator_t *dbiter = NULL; 1435 dns_dbnode_t *node = NULL, *nextnode = NULL; 1436 dns_fixedname_t fname, fnextname, fprevname, fzonecut; 1437 dns_name_t *name, *nextname, *prevname, *zonecut; 1438 dns_rdata_dnskey_t dnskey; 1439 dns_rdata_t rdata = DNS_RDATA_INIT; 1440 dns_rdataset_t keyset, soaset; 1441 dns_rdataset_t keysigs, soasigs; 1442 dns_rdataset_t nsecset, nsecsigs; 1443 dns_rdataset_t nsec3paramset, nsec3paramsigs; 1444 int i; 1445 isc_boolean_t done = ISC_FALSE; 1446 isc_boolean_t first = ISC_TRUE; 1447 isc_boolean_t goodksk = ISC_FALSE; 1448 isc_boolean_t goodzsk = ISC_FALSE; 1449 isc_result_t result, vresult = ISC_R_UNSET; 1450 unsigned char revoked_ksk[256]; 1451 unsigned char revoked_zsk[256]; 1452 unsigned char standby_ksk[256]; 1453 unsigned char standby_zsk[256]; 1454 unsigned char ksk_algorithms[256]; 1455 unsigned char zsk_algorithms[256]; 1456 unsigned char bad_algorithms[256]; 1457 unsigned char act_algorithms[256]; 1458 1459 result = isc_heap_create(mctx, chain_compare, NULL, 1024, 1460 &expected_chains); 1461 check_result(result, "isc_heap_create()"); 1462 result = isc_heap_create(mctx, chain_compare, NULL, 1024, 1463 &found_chains); 1464 check_result(result, "isc_heap_create()"); 1465 1466 result = dns_db_findnode(db, origin, ISC_FALSE, &node); 1467 if (result != ISC_R_SUCCESS) 1468 fatal("failed to find the zone's origin: %s", 1469 isc_result_totext(result)); 1470 1471 dns_rdataset_init(&keyset); 1472 dns_rdataset_init(&keysigs); 1473 dns_rdataset_init(&soaset); 1474 dns_rdataset_init(&soasigs); 1475 dns_rdataset_init(&nsecset); 1476 dns_rdataset_init(&nsecsigs); 1477 dns_rdataset_init(&nsec3paramset); 1478 dns_rdataset_init(&nsec3paramsigs); 1479 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 1480 0, 0, &keyset, &keysigs); 1481 if (result != ISC_R_SUCCESS) 1482 fatal("Zone contains no DNSSEC keys\n"); 1483 1484 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 1485 0, 0, &soaset, &soasigs); 1486 if (result != ISC_R_SUCCESS) 1487 fatal("Zone contains no SOA record\n"); 1488 1489 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 1490 0, 0, &nsecset, &nsecsigs); 1491 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 1492 fatal("NSEC lookup failed\n"); 1493 1494 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 1495 0, 0, &nsec3paramset, &nsec3paramsigs); 1496 if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) 1497 fatal("NSEC3PARAM lookup failed\n"); 1498 1499 if (!dns_rdataset_isassociated(&keysigs)) 1500 fatal("DNSKEY is not signed (keys offline or inactive?)\n"); 1501 1502 if (!dns_rdataset_isassociated(&soasigs)) 1503 fatal("SOA is not signed (keys offline or inactive?)\n"); 1504 1505 if (dns_rdataset_isassociated(&nsecset) && 1506 !dns_rdataset_isassociated(&nsecsigs)) 1507 fatal("NSEC is not signed (keys offline or inactive?)\n"); 1508 1509 if (dns_rdataset_isassociated(&nsec3paramset) && 1510 !dns_rdataset_isassociated(&nsec3paramsigs)) 1511 fatal("NSEC3PARAM is not signed (keys offline or inactive?)\n"); 1512 1513 if (!dns_rdataset_isassociated(&nsecset) && 1514 !dns_rdataset_isassociated(&nsec3paramset)) 1515 fatal("No valid NSEC/NSEC3 chain for testing\n"); 1516 1517 dns_db_detachnode(db, &node); 1518 1519 memset(revoked_ksk, 0, sizeof(revoked_ksk)); 1520 memset(revoked_zsk, 0, sizeof(revoked_zsk)); 1521 memset(standby_ksk, 0, sizeof(standby_ksk)); 1522 memset(standby_zsk, 0, sizeof(standby_zsk)); 1523 memset(ksk_algorithms, 0, sizeof(ksk_algorithms)); 1524 memset(zsk_algorithms, 0, sizeof(zsk_algorithms)); 1525 memset(bad_algorithms, 0, sizeof(bad_algorithms)); 1526 memset(act_algorithms, 0, sizeof(act_algorithms)); 1527 1528 /* 1529 * Check that the DNSKEY RR has at least one self signing KSK 1530 * and one ZSK per algorithm in it (or, if -x was used, one 1531 * self-signing KSK). 1532 */ 1533 for (result = dns_rdataset_first(&keyset); 1534 result == ISC_R_SUCCESS; 1535 result = dns_rdataset_next(&keyset)) { 1536 dns_rdataset_current(&keyset, &rdata); 1537 result = dns_rdata_tostruct(&rdata, &dnskey, NULL); 1538 check_result(result, "dns_rdata_tostruct"); 1539 1540 if ((dnskey.flags & DNS_KEYOWNER_ZONE) == 0) 1541 ; 1542 else if ((dnskey.flags & DNS_KEYFLAG_REVOKE) != 0) { 1543 if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 && 1544 !dns_dnssec_selfsigns(&rdata, origin, &keyset, 1545 &keysigs, ISC_FALSE, 1546 mctx)) { 1547 char namebuf[DNS_NAME_FORMATSIZE]; 1548 char buffer[1024]; 1549 isc_buffer_t buf; 1550 1551 dns_name_format(origin, namebuf, 1552 sizeof(namebuf)); 1553 isc_buffer_init(&buf, buffer, sizeof(buffer)); 1554 result = dns_rdata_totext(&rdata, NULL, &buf); 1555 check_result(result, "dns_rdata_totext"); 1556 fatal("revoked KSK is not self signed:\n" 1557 "%s DNSKEY %.*s", namebuf, 1558 (int)isc_buffer_usedlength(&buf), buffer); 1559 } 1560 if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 && 1561 revoked_ksk[dnskey.algorithm] != 255) 1562 revoked_ksk[dnskey.algorithm]++; 1563 else if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 && 1564 revoked_zsk[dnskey.algorithm] != 255) 1565 revoked_zsk[dnskey.algorithm]++; 1566 } else if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0) { 1567 if (dns_dnssec_selfsigns(&rdata, origin, &keyset, 1568 &keysigs, ISC_FALSE, mctx)) { 1569 if (ksk_algorithms[dnskey.algorithm] != 255) 1570 ksk_algorithms[dnskey.algorithm]++; 1571 goodksk = ISC_TRUE; 1572 } else { 1573 if (standby_ksk[dnskey.algorithm] != 255) 1574 standby_ksk[dnskey.algorithm]++; 1575 } 1576 } else if (dns_dnssec_selfsigns(&rdata, origin, &keyset, 1577 &keysigs, ISC_FALSE, mctx)) { 1578 if (zsk_algorithms[dnskey.algorithm] != 255) 1579 zsk_algorithms[dnskey.algorithm]++; 1580 goodzsk = ISC_TRUE; 1581 } else if (dns_dnssec_signs(&rdata, origin, &soaset, 1582 &soasigs, ISC_FALSE, mctx)) { 1583 if (zsk_algorithms[dnskey.algorithm] != 255) 1584 zsk_algorithms[dnskey.algorithm]++; 1585 } else { 1586 if (standby_zsk[dnskey.algorithm] != 255) 1587 standby_zsk[dnskey.algorithm]++; 1588 } 1589 dns_rdata_freestruct(&dnskey); 1590 dns_rdata_reset(&rdata); 1591 } 1592 dns_rdataset_disassociate(&keysigs); 1593 dns_rdataset_disassociate(&soaset); 1594 dns_rdataset_disassociate(&soasigs); 1595 if (dns_rdataset_isassociated(&nsecsigs)) 1596 dns_rdataset_disassociate(&nsecsigs); 1597 if (dns_rdataset_isassociated(&nsec3paramsigs)) 1598 dns_rdataset_disassociate(&nsec3paramsigs); 1599 1600 if (ignore_kskflag ) { 1601 if (!goodksk && !goodzsk) 1602 fatal("No self-signed DNSKEY found."); 1603 } else if (!goodksk) 1604 fatal("No self-signed KSK DNSKEY found. Supply an active\n" 1605 "key with the KSK flag set, or use '-P'."); 1606 1607 fprintf(stderr, "Verifying the zone using the following algorithms:"); 1608 for (i = 0; i < 256; i++) { 1609 if (ignore_kskflag) 1610 act_algorithms[i] = (ksk_algorithms[i] != 0 || 1611 zsk_algorithms[i] != 0) ? 1 : 0; 1612 else 1613 act_algorithms[i] = ksk_algorithms[i] != 0 ? 1 : 0; 1614 if (act_algorithms[i] != 0) { 1615 dns_secalg_format(i, algbuf, sizeof(algbuf)); 1616 fprintf(stderr, " %s", algbuf); 1617 } 1618 } 1619 fprintf(stderr, ".\n"); 1620 1621 if (!ignore_kskflag && !keyset_kskonly) { 1622 for (i = 0; i < 256; i++) { 1623 /* 1624 * The counts should both be zero or both be non-zero. 1625 * Mark the algorithm as bad if this is not met. 1626 */ 1627 if ((ksk_algorithms[i] != 0) == 1628 (zsk_algorithms[i] != 0)) 1629 continue; 1630 dns_secalg_format(i, algbuf, sizeof(algbuf)); 1631 fprintf(stderr, "Missing %s for algorithm %s\n", 1632 (ksk_algorithms[i] != 0) 1633 ? "ZSK" 1634 : "self-signed KSK", 1635 algbuf); 1636 bad_algorithms[i] = 1; 1637 } 1638 } 1639 1640 /* 1641 * Check that all the other records were signed by keys that are 1642 * present in the DNSKEY RRSET. 1643 */ 1644 1645 dns_fixedname_init(&fname); 1646 name = dns_fixedname_name(&fname); 1647 dns_fixedname_init(&fnextname); 1648 nextname = dns_fixedname_name(&fnextname); 1649 dns_fixedname_init(&fprevname); 1650 prevname = NULL; 1651 dns_fixedname_init(&fzonecut); 1652 zonecut = NULL; 1653 1654 result = dns_db_createiterator(db, DNS_DB_NONSEC3, &dbiter); 1655 check_result(result, "dns_db_createiterator()"); 1656 1657 result = dns_dbiterator_first(dbiter); 1658 check_result(result, "dns_dbiterator_first()"); 1659 1660 while (!done) { 1661 isc_boolean_t isdelegation = ISC_FALSE; 1662 1663 result = dns_dbiterator_current(dbiter, &node, name); 1664 check_dns_dbiterator_current(result); 1665 if (!dns_name_issubdomain(name, origin)) { 1666 check_no_nsec(name, node, db, ver); 1667 dns_db_detachnode(db, &node); 1668 result = dns_dbiterator_next(dbiter); 1669 if (result == ISC_R_NOMORE) 1670 done = ISC_TRUE; 1671 else 1672 check_result(result, "dns_dbiterator_next()"); 1673 continue; 1674 } 1675 if (is_delegation(db, ver, origin, name, node, NULL)) { 1676 zonecut = dns_fixedname_name(&fzonecut); 1677 dns_name_copy(name, zonecut, NULL); 1678 isdelegation = ISC_TRUE; 1679 } 1680 nextnode = NULL; 1681 result = dns_dbiterator_next(dbiter); 1682 while (result == ISC_R_SUCCESS) { 1683 result = dns_dbiterator_current(dbiter, &nextnode, 1684 nextname); 1685 check_dns_dbiterator_current(result); 1686 if (!dns_name_issubdomain(nextname, origin) || 1687 (zonecut != NULL && 1688 dns_name_issubdomain(nextname, zonecut))) 1689 { 1690 check_no_nsec(nextname, nextnode, db, ver); 1691 dns_db_detachnode(db, &nextnode); 1692 result = dns_dbiterator_next(dbiter); 1693 continue; 1694 } 1695 if (is_empty(db, ver, nextnode)) { 1696 dns_db_detachnode(db, &nextnode); 1697 result = dns_dbiterator_next(dbiter); 1698 continue; 1699 } 1700 dns_db_detachnode(db, &nextnode); 1701 break; 1702 } 1703 if (result == ISC_R_NOMORE) { 1704 done = ISC_TRUE; 1705 nextname = origin; 1706 } else if (result != ISC_R_SUCCESS) 1707 fatal("iterating through the database failed: %s", 1708 isc_result_totext(result)); 1709 result = verifynode(db, ver, origin, mctx, name, node, 1710 isdelegation, &keyset, act_algorithms, 1711 bad_algorithms, &nsecset, &nsec3paramset, 1712 nextname); 1713 if (vresult == ISC_R_UNSET) 1714 vresult = ISC_R_SUCCESS; 1715 if (vresult == ISC_R_SUCCESS && result != ISC_R_SUCCESS) 1716 vresult = result; 1717 if (prevname != NULL) { 1718 result = verifyemptynodes(db, ver, origin, mctx, name, 1719 prevname, isdelegation, 1720 &nsec3paramset); 1721 } else 1722 prevname = dns_fixedname_name(&fprevname); 1723 dns_name_copy(name, prevname, NULL); 1724 if (vresult == ISC_R_SUCCESS && result != ISC_R_SUCCESS) 1725 vresult = result; 1726 dns_db_detachnode(db, &node); 1727 } 1728 1729 dns_dbiterator_destroy(&dbiter); 1730 1731 result = dns_db_createiterator(db, DNS_DB_NSEC3ONLY, &dbiter); 1732 check_result(result, "dns_db_createiterator()"); 1733 1734 for (result = dns_dbiterator_first(dbiter); 1735 result == ISC_R_SUCCESS; 1736 result = dns_dbiterator_next(dbiter) ) { 1737 result = dns_dbiterator_current(dbiter, &node, name); 1738 check_dns_dbiterator_current(result); 1739 result = verifynode(db, ver, origin, mctx, name, node, 1740 ISC_FALSE, &keyset, act_algorithms, 1741 bad_algorithms, NULL, NULL, NULL); 1742 check_result(result, "verifynode"); 1743 record_found(db, ver, mctx, name, node, &nsec3paramset); 1744 dns_db_detachnode(db, &node); 1745 } 1746 dns_dbiterator_destroy(&dbiter); 1747 1748 dns_rdataset_disassociate(&keyset); 1749 if (dns_rdataset_isassociated(&nsecset)) 1750 dns_rdataset_disassociate(&nsecset); 1751 if (dns_rdataset_isassociated(&nsec3paramset)) 1752 dns_rdataset_disassociate(&nsec3paramset); 1753 1754 result = verify_nsec3_chains(mctx); 1755 if (vresult == ISC_R_UNSET) 1756 vresult = ISC_R_SUCCESS; 1757 if (result != ISC_R_SUCCESS && vresult == ISC_R_SUCCESS) 1758 vresult = result; 1759 isc_heap_destroy(&expected_chains); 1760 isc_heap_destroy(&found_chains); 1761 1762 /* 1763 * If we made it this far, we have what we consider a properly signed 1764 * zone. Set the good flag. 1765 */ 1766 for (i = 0; i < 256; i++) { 1767 if (bad_algorithms[i] != 0) { 1768 if (first) 1769 fprintf(stderr, "The zone is not fully signed " 1770 "for the following algorithms:"); 1771 dns_secalg_format(i, algbuf, sizeof(algbuf)); 1772 fprintf(stderr, " %s", algbuf); 1773 first = ISC_FALSE; 1774 } 1775 } 1776 if (!first) { 1777 fprintf(stderr, ".\n"); 1778 fatal("DNSSEC completeness test failed."); 1779 } 1780 1781 if (vresult != ISC_R_SUCCESS) 1782 fatal("DNSSEC completeness test failed (%s).", 1783 dns_result_totext(vresult)); 1784 1785 if (goodksk || ignore_kskflag) { 1786 /* 1787 * Print the success summary. 1788 */ 1789 fprintf(stderr, "Zone fully signed:\n"); 1790 for (i = 0; i < 256; i++) { 1791 if ((ksk_algorithms[i] != 0) || 1792 (standby_ksk[i] != 0) || 1793 (revoked_zsk[i] != 0) || 1794 (zsk_algorithms[i] != 0) || 1795 (standby_zsk[i] != 0) || 1796 (revoked_zsk[i] != 0)) { 1797 dns_secalg_format(i, algbuf, sizeof(algbuf)); 1798 fprintf(stderr, "Algorithm: %s: KSKs: " 1799 "%u active, %u stand-by, %u revoked\n", 1800 algbuf, ksk_algorithms[i], 1801 standby_ksk[i], revoked_ksk[i]); 1802 fprintf(stderr, "%*sZSKs: " 1803 "%u active, %u %s, %u revoked\n", 1804 (int) strlen(algbuf) + 13, "", 1805 zsk_algorithms[i], 1806 standby_zsk[i], 1807 keyset_kskonly ? "present" : "stand-by", 1808 revoked_zsk[i]); 1809 } 1810 } 1811 } 1812} 1813