1 /* $NetBSD: dnssec-settime.c,v 1.10 2025/01/26 16:24:32 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #include <errno.h> 19 #include <inttypes.h> 20 #include <stdbool.h> 21 #include <stdlib.h> 22 #include <time.h> 23 #include <unistd.h> 24 25 #include <isc/attributes.h> 26 #include <isc/buffer.h> 27 #include <isc/commandline.h> 28 #include <isc/file.h> 29 #include <isc/hash.h> 30 #include <isc/mem.h> 31 #include <isc/result.h> 32 #include <isc/string.h> 33 #include <isc/time.h> 34 #include <isc/util.h> 35 36 #include <dns/keyvalues.h> 37 #include <dns/log.h> 38 39 #include <dst/dst.h> 40 41 #include "dnssectool.h" 42 43 const char *program = "dnssec-settime"; 44 45 static isc_mem_t *mctx = NULL; 46 47 noreturn static void 48 usage(void); 49 50 static void 51 usage(void) { 52 fprintf(stderr, "Usage:\n"); 53 fprintf(stderr, " %s [options] keyfile\n\n", program); 54 fprintf(stderr, "Version: %s\n", PACKAGE_VERSION); 55 fprintf(stderr, "General options:\n"); 56 fprintf(stderr, " -E engine: specify OpenSSL engine\n"); 57 fprintf(stderr, " -f: force update of old-style " 58 "keys\n"); 59 fprintf(stderr, " -K directory: set key file location\n"); 60 fprintf(stderr, " -L ttl: set default key TTL\n"); 61 fprintf(stderr, " -v level: set level of verbosity\n"); 62 fprintf(stderr, " -V: print version information\n"); 63 fprintf(stderr, " -h: help\n"); 64 fprintf(stderr, "Timing options:\n"); 65 fprintf(stderr, " -P date/[+-]offset/none: set/unset key " 66 "publication date\n"); 67 fprintf(stderr, " -P ds date/[+-]offset/none: set/unset " 68 "DS publication date\n"); 69 fprintf(stderr, " -P sync date/[+-]offset/none: set/unset " 70 "CDS and CDNSKEY publication date\n"); 71 fprintf(stderr, " -A date/[+-]offset/none: set/unset key " 72 "activation date\n"); 73 fprintf(stderr, " -R date/[+-]offset/none: set/unset key " 74 "revocation date\n"); 75 fprintf(stderr, " -I date/[+-]offset/none: set/unset key " 76 "inactivation date\n"); 77 fprintf(stderr, " -D date/[+-]offset/none: set/unset key " 78 "deletion date\n"); 79 fprintf(stderr, " -D ds date/[+-]offset/none: set/unset " 80 "DS deletion date\n"); 81 fprintf(stderr, " -D sync date/[+-]offset/none: set/unset " 82 "CDS and CDNSKEY deletion date\n"); 83 fprintf(stderr, " -S <key>: generate a successor to an existing " 84 "key\n"); 85 fprintf(stderr, " -i <interval>: prepublication interval for " 86 "successor key " 87 "(default: 30 days)\n"); 88 fprintf(stderr, "Key state options:\n"); 89 fprintf(stderr, " -s: update key state file (default no)\n"); 90 fprintf(stderr, " -g state: set the goal state for this key\n"); 91 fprintf(stderr, " -d state date/[+-]offset: set the DS state\n"); 92 fprintf(stderr, " -k state date/[+-]offset: set the DNSKEY state\n"); 93 fprintf(stderr, " -r state date/[+-]offset: set the RRSIG (KSK) " 94 "state\n"); 95 fprintf(stderr, " -z state date/[+-]offset: set the RRSIG (ZSK) " 96 "state\n"); 97 fprintf(stderr, "Printing options:\n"); 98 fprintf(stderr, " -p C/P/Psync/A/R/I/D/Dsync/all: print a " 99 "particular time value or values\n"); 100 fprintf(stderr, " -u: print times in unix epoch " 101 "format\n"); 102 fprintf(stderr, "Output:\n"); 103 fprintf(stderr, " K<name>+<alg>+<new id>.key, " 104 "K<name>+<alg>+<new id>.private\n"); 105 106 exit(EXIT_FAILURE); 107 } 108 109 static void 110 printtime(dst_key_t *key, int type, const char *tag, bool epoch, FILE *stream) { 111 isc_result_t result; 112 isc_stdtime_t when; 113 114 if (tag != NULL) { 115 fprintf(stream, "%s: ", tag); 116 } 117 118 result = dst_key_gettime(key, type, &when); 119 if (result == ISC_R_NOTFOUND) { 120 fprintf(stream, "UNSET\n"); 121 } else if (epoch) { 122 fprintf(stream, "%d\n", (int)when); 123 } else { 124 time_t now = when; 125 struct tm t, *tm = localtime_r(&now, &t); 126 unsigned int flen; 127 char timebuf[80]; 128 129 if (tm == NULL) { 130 fprintf(stream, "INVALID\n"); 131 return; 132 } 133 134 flen = strftime(timebuf, sizeof(timebuf), 135 "%a %b %e %H:%M:%S %Y", tm); 136 INSIST(flen > 0U && flen < sizeof(timebuf)); 137 fprintf(stream, "%s\n", timebuf); 138 } 139 } 140 141 static void 142 writekey(dst_key_t *key, const char *directory, bool write_state) { 143 char newname[1024]; 144 char keystr[DST_KEY_FORMATSIZE]; 145 isc_buffer_t buf; 146 isc_result_t result; 147 int options = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE; 148 149 if (write_state) { 150 options |= DST_TYPE_STATE; 151 } 152 153 isc_buffer_init(&buf, newname, sizeof(newname)); 154 result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &buf); 155 if (result != ISC_R_SUCCESS) { 156 fatal("Failed to build public key filename: %s", 157 isc_result_totext(result)); 158 } 159 160 result = dst_key_tofile(key, options, directory); 161 if (result != ISC_R_SUCCESS) { 162 dst_key_format(key, keystr, sizeof(keystr)); 163 fatal("Failed to write key %s: %s", keystr, 164 isc_result_totext(result)); 165 } 166 printf("%s\n", newname); 167 168 isc_buffer_clear(&buf); 169 result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &buf); 170 if (result != ISC_R_SUCCESS) { 171 fatal("Failed to build private key filename: %s", 172 isc_result_totext(result)); 173 } 174 printf("%s\n", newname); 175 176 if (write_state) { 177 isc_buffer_clear(&buf); 178 result = dst_key_buildfilename(key, DST_TYPE_STATE, directory, 179 &buf); 180 if (result != ISC_R_SUCCESS) { 181 fatal("Failed to build key state filename: %s", 182 isc_result_totext(result)); 183 } 184 printf("%s\n", newname); 185 } 186 } 187 188 int 189 main(int argc, char **argv) { 190 isc_result_t result; 191 const char *engine = NULL; 192 const char *filename = NULL; 193 char *directory = NULL; 194 char keystr[DST_KEY_FORMATSIZE]; 195 char *endp, *p; 196 int ch; 197 const char *predecessor = NULL; 198 dst_key_t *prevkey = NULL; 199 dst_key_t *key = NULL; 200 dns_name_t *name = NULL; 201 dns_secalg_t alg = 0; 202 unsigned int size = 0; 203 uint16_t flags = 0; 204 int prepub = -1; 205 int options; 206 dns_ttl_t ttl = 0; 207 isc_stdtime_t dstime = 0, dnskeytime = 0; 208 isc_stdtime_t krrsigtime = 0, zrrsigtime = 0; 209 isc_stdtime_t pub = 0, act = 0, rev = 0, inact = 0, del = 0; 210 isc_stdtime_t prevact = 0, previnact = 0, prevdel = 0; 211 dst_key_state_t goal = DST_KEY_STATE_NA; 212 dst_key_state_t ds = DST_KEY_STATE_NA; 213 dst_key_state_t dnskey = DST_KEY_STATE_NA; 214 dst_key_state_t krrsig = DST_KEY_STATE_NA; 215 dst_key_state_t zrrsig = DST_KEY_STATE_NA; 216 bool setgoal = false, setds = false, setdnskey = false; 217 bool setkrrsig = false, setzrrsig = false; 218 bool setdstime = false, setdnskeytime = false; 219 bool setkrrsigtime = false, setzrrsigtime = false; 220 bool setpub = false, setact = false; 221 bool setrev = false, setinact = false; 222 bool setdel = false, setttl = false; 223 bool unsetpub = false, unsetact = false; 224 bool unsetrev = false, unsetinact = false; 225 bool unsetdel = false; 226 bool printcreate = false, printpub = false; 227 bool printact = false, printrev = false; 228 bool printinact = false, printdel = false; 229 bool force = false; 230 bool epoch = false; 231 bool changed = false; 232 bool write_state = false; 233 isc_log_t *log = NULL; 234 isc_stdtime_t syncadd = 0, syncdel = 0; 235 bool unsetsyncadd = false, setsyncadd = false; 236 bool unsetsyncdel = false, setsyncdel = false; 237 bool printsyncadd = false, printsyncdel = false; 238 isc_stdtime_t dsadd = 0, dsdel = 0; 239 bool unsetdsadd = false, setdsadd = false; 240 bool unsetdsdel = false, setdsdel = false; 241 bool printdsadd = false, printdsdel = false; 242 isc_stdtime_t now = isc_stdtime_now(); 243 244 options = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE; 245 246 if (argc == 1) { 247 usage(); 248 } 249 250 isc_mem_create(&mctx); 251 252 setup_logging(mctx, &log); 253 254 isc_commandline_errprint = false; 255 256 #define CMDLINE_FLAGS "A:D:d:E:fg:hI:i:K:k:L:P:p:R:r:S:suv:Vz:" 257 while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { 258 switch (ch) { 259 case 'A': 260 if (setact || unsetact) { 261 fatal("-A specified more than once"); 262 } 263 264 changed = true; 265 act = strtotime(isc_commandline_argument, now, now, 266 &setact); 267 unsetact = !setact; 268 break; 269 case 'D': 270 /* -Dsync ? */ 271 if (isoptarg("sync", argv, usage)) { 272 if (unsetsyncdel || setsyncdel) { 273 fatal("-D sync specified more than " 274 "once"); 275 } 276 277 changed = true; 278 syncdel = strtotime(isc_commandline_argument, 279 now, now, &setsyncdel); 280 unsetsyncdel = !setsyncdel; 281 break; 282 } 283 /* -Dds ? */ 284 if (isoptarg("ds", argv, usage)) { 285 if (unsetdsdel || setdsdel) { 286 fatal("-D ds specified more than once"); 287 } 288 289 changed = true; 290 dsdel = strtotime(isc_commandline_argument, now, 291 now, &setdsdel); 292 unsetdsdel = !setdsdel; 293 break; 294 } 295 /* -Ddnskey ? */ 296 (void)isoptarg("dnskey", argv, usage); 297 if (setdel || unsetdel) { 298 fatal("-D specified more than once"); 299 } 300 301 changed = true; 302 del = strtotime(isc_commandline_argument, now, now, 303 &setdel); 304 unsetdel = !setdel; 305 break; 306 case 'd': 307 if (setds) { 308 fatal("-d specified more than once"); 309 } 310 311 ds = strtokeystate(isc_commandline_argument); 312 setds = true; 313 /* time */ 314 (void)isoptarg(isc_commandline_argument, argv, usage); 315 dstime = strtotime(isc_commandline_argument, now, now, 316 &setdstime); 317 break; 318 case 'E': 319 engine = isc_commandline_argument; 320 break; 321 case 'f': 322 force = true; 323 break; 324 case 'g': 325 if (setgoal) { 326 fatal("-g specified more than once"); 327 } 328 329 goal = strtokeystate(isc_commandline_argument); 330 if (goal != DST_KEY_STATE_NA && 331 goal != DST_KEY_STATE_HIDDEN && 332 goal != DST_KEY_STATE_OMNIPRESENT) 333 { 334 fatal("-g must be either none, hidden, or " 335 "omnipresent"); 336 } 337 setgoal = true; 338 break; 339 case '?': 340 if (isc_commandline_option != '?') { 341 fprintf(stderr, "%s: invalid argument -%c\n", 342 program, isc_commandline_option); 343 } 344 FALLTHROUGH; 345 case 'h': 346 /* Does not return. */ 347 usage(); 348 case 'I': 349 if (setinact || unsetinact) { 350 fatal("-I specified more than once"); 351 } 352 353 changed = true; 354 inact = strtotime(isc_commandline_argument, now, now, 355 &setinact); 356 unsetinact = !setinact; 357 break; 358 case 'i': 359 prepub = strtottl(isc_commandline_argument); 360 break; 361 case 'K': 362 /* 363 * We don't have to copy it here, but do it to 364 * simplify cleanup later 365 */ 366 directory = isc_mem_strdup(mctx, 367 isc_commandline_argument); 368 break; 369 case 'k': 370 if (setdnskey) { 371 fatal("-k specified more than once"); 372 } 373 374 dnskey = strtokeystate(isc_commandline_argument); 375 setdnskey = true; 376 /* time */ 377 (void)isoptarg(isc_commandline_argument, argv, usage); 378 dnskeytime = strtotime(isc_commandline_argument, now, 379 now, &setdnskeytime); 380 break; 381 case 'L': 382 ttl = strtottl(isc_commandline_argument); 383 setttl = true; 384 break; 385 case 'P': 386 /* -Psync ? */ 387 if (isoptarg("sync", argv, usage)) { 388 if (unsetsyncadd || setsyncadd) { 389 fatal("-P sync specified more than " 390 "once"); 391 } 392 393 changed = true; 394 syncadd = strtotime(isc_commandline_argument, 395 now, now, &setsyncadd); 396 unsetsyncadd = !setsyncadd; 397 break; 398 } 399 /* -Pds ? */ 400 if (isoptarg("ds", argv, usage)) { 401 if (unsetdsadd || setdsadd) { 402 fatal("-P ds specified more than once"); 403 } 404 405 changed = true; 406 dsadd = strtotime(isc_commandline_argument, now, 407 now, &setdsadd); 408 unsetdsadd = !setdsadd; 409 break; 410 } 411 /* -Pdnskey ? */ 412 (void)isoptarg("dnskey", argv, usage); 413 if (setpub || unsetpub) { 414 fatal("-P specified more than once"); 415 } 416 417 changed = true; 418 pub = strtotime(isc_commandline_argument, now, now, 419 &setpub); 420 unsetpub = !setpub; 421 break; 422 case 'p': 423 p = isc_commandline_argument; 424 if (!strcasecmp(p, "all")) { 425 printcreate = true; 426 printpub = true; 427 printact = true; 428 printrev = true; 429 printinact = true; 430 printdel = true; 431 printsyncadd = true; 432 printsyncdel = true; 433 printdsadd = true; 434 printdsdel = true; 435 break; 436 } 437 438 do { 439 switch (*p++) { 440 case 'A': 441 printact = true; 442 break; 443 case 'C': 444 printcreate = true; 445 break; 446 case 'D': 447 if (!strncmp(p, "sync", 4)) { 448 p += 4; 449 printsyncdel = true; 450 break; 451 } 452 if (!strncmp(p, "ds", 2)) { 453 p += 2; 454 printdsdel = true; 455 break; 456 } 457 printdel = true; 458 break; 459 case 'I': 460 printinact = true; 461 break; 462 case 'P': 463 if (!strncmp(p, "sync", 4)) { 464 p += 4; 465 printsyncadd = true; 466 break; 467 } 468 if (!strncmp(p, "ds", 2)) { 469 p += 2; 470 printdsadd = true; 471 break; 472 } 473 printpub = true; 474 break; 475 case 'R': 476 printrev = true; 477 break; 478 case ' ': 479 break; 480 default: 481 usage(); 482 break; 483 } 484 } while (*p != '\0'); 485 break; 486 case 'R': 487 if (setrev || unsetrev) { 488 fatal("-R specified more than once"); 489 } 490 491 changed = true; 492 rev = strtotime(isc_commandline_argument, now, now, 493 &setrev); 494 unsetrev = !setrev; 495 break; 496 case 'r': 497 if (setkrrsig) { 498 fatal("-r specified more than once"); 499 } 500 501 krrsig = strtokeystate(isc_commandline_argument); 502 setkrrsig = true; 503 /* time */ 504 (void)isoptarg(isc_commandline_argument, argv, usage); 505 krrsigtime = strtotime(isc_commandline_argument, now, 506 now, &setkrrsigtime); 507 break; 508 case 'S': 509 predecessor = isc_commandline_argument; 510 break; 511 case 's': 512 write_state = true; 513 break; 514 case 'u': 515 epoch = true; 516 break; 517 case 'V': 518 /* Does not return. */ 519 version(program); 520 case 'v': 521 verbose = strtol(isc_commandline_argument, &endp, 0); 522 if (*endp != '\0') { 523 fatal("-v must be followed by a number"); 524 } 525 break; 526 case 'z': 527 if (setzrrsig) { 528 fatal("-z specified more than once"); 529 } 530 531 zrrsig = strtokeystate(isc_commandline_argument); 532 setzrrsig = true; 533 (void)isoptarg(isc_commandline_argument, argv, usage); 534 zrrsigtime = strtotime(isc_commandline_argument, now, 535 now, &setzrrsigtime); 536 break; 537 538 default: 539 fprintf(stderr, "%s: unhandled option -%c\n", program, 540 isc_commandline_option); 541 exit(EXIT_FAILURE); 542 } 543 } 544 545 if (argc < isc_commandline_index + 1 || 546 argv[isc_commandline_index] == NULL) 547 { 548 fatal("The key file name was not specified"); 549 } 550 if (argc > isc_commandline_index + 1) { 551 fatal("Extraneous arguments"); 552 } 553 554 if ((setgoal || setds || setdnskey || setkrrsig || setzrrsig) && 555 !write_state) 556 { 557 fatal("Options -g, -d, -k, -r and -z require -s to be set"); 558 } 559 560 result = dst_lib_init(mctx, engine); 561 if (result != ISC_R_SUCCESS) { 562 fatal("Could not initialize dst: %s", 563 isc_result_totext(result)); 564 } 565 566 if (predecessor != NULL) { 567 int major, minor; 568 569 if (prepub == -1) { 570 prepub = (30 * 86400); 571 } 572 573 if (setpub || unsetpub) { 574 fatal("-S and -P cannot be used together"); 575 } 576 if (setact || unsetact) { 577 fatal("-S and -A cannot be used together"); 578 } 579 580 result = dst_key_fromnamedfile(predecessor, directory, options, 581 mctx, &prevkey); 582 if (result != ISC_R_SUCCESS) { 583 fatal("Invalid keyfile %s: %s", filename, 584 isc_result_totext(result)); 585 } 586 if (!dst_key_isprivate(prevkey) && !dst_key_isexternal(prevkey)) 587 { 588 fatal("%s is not a private key", filename); 589 } 590 591 name = dst_key_name(prevkey); 592 alg = dst_key_alg(prevkey); 593 size = dst_key_size(prevkey); 594 flags = dst_key_flags(prevkey); 595 596 dst_key_format(prevkey, keystr, sizeof(keystr)); 597 dst_key_getprivateformat(prevkey, &major, &minor); 598 if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) { 599 fatal("Predecessor has incompatible format " 600 "version %d.%d\n\t", 601 major, minor); 602 } 603 604 result = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &prevact); 605 if (result != ISC_R_SUCCESS) { 606 fatal("Predecessor has no activation date. " 607 "You must set one before\n\t" 608 "generating a successor."); 609 } 610 611 result = dst_key_gettime(prevkey, DST_TIME_INACTIVE, 612 &previnact); 613 if (result != ISC_R_SUCCESS) { 614 fatal("Predecessor has no inactivation date. " 615 "You must set one before\n\t" 616 "generating a successor."); 617 } 618 619 pub = previnact - prepub; 620 act = previnact; 621 622 if ((previnact - prepub) < now && prepub != 0) { 623 fatal("Time until predecessor inactivation is\n\t" 624 "shorter than the prepublication interval. " 625 "Either change\n\t" 626 "predecessor inactivation date, or use the -i " 627 "option to set\n\t" 628 "a shorter prepublication interval."); 629 } 630 631 result = dst_key_gettime(prevkey, DST_TIME_DELETE, &prevdel); 632 if (result != ISC_R_SUCCESS) { 633 fprintf(stderr, 634 "%s: warning: Predecessor has no " 635 "removal date;\n\t" 636 "it will remain in the zone " 637 "indefinitely after rollover.\n", 638 program); 639 } else if (prevdel < previnact) { 640 fprintf(stderr, 641 "%s: warning: Predecessor is " 642 "scheduled to be deleted\n\t" 643 "before it is scheduled to be " 644 "inactive.\n", 645 program); 646 } 647 648 changed = setpub = setact = true; 649 } else { 650 if (prepub < 0) { 651 prepub = 0; 652 } 653 654 if (prepub > 0) { 655 if (setpub && setact && (act - prepub) < pub) { 656 fatal("Activation and publication dates " 657 "are closer together than the\n\t" 658 "prepublication interval."); 659 } 660 661 if (setpub && !setact) { 662 setact = true; 663 act = pub + prepub; 664 } else if (setact && !setpub) { 665 setpub = true; 666 pub = act - prepub; 667 } 668 669 if ((act - prepub) < now) { 670 fatal("Time until activation is shorter " 671 "than the\n\tprepublication interval."); 672 } 673 } 674 } 675 676 if (directory != NULL) { 677 filename = argv[isc_commandline_index]; 678 } else { 679 result = isc_file_splitpath(mctx, argv[isc_commandline_index], 680 &directory, &filename); 681 if (result != ISC_R_SUCCESS) { 682 fatal("cannot process filename %s: %s", 683 argv[isc_commandline_index], 684 isc_result_totext(result)); 685 } 686 } 687 688 result = dst_key_fromnamedfile(filename, directory, options, mctx, 689 &key); 690 if (result != ISC_R_SUCCESS) { 691 fatal("Invalid keyfile %s: %s", filename, 692 isc_result_totext(result)); 693 } 694 695 if (!dst_key_isprivate(key) && !dst_key_isexternal(key)) { 696 fatal("%s is not a private key", filename); 697 } 698 699 dst_key_format(key, keystr, sizeof(keystr)); 700 701 if (predecessor != NULL) { 702 if (!dns_name_equal(name, dst_key_name(key))) { 703 fatal("Key name mismatch"); 704 } 705 if (alg != dst_key_alg(key)) { 706 fatal("Key algorithm mismatch"); 707 } 708 if (size != dst_key_size(key)) { 709 fatal("Key size mismatch"); 710 } 711 if (flags != dst_key_flags(key)) { 712 fatal("Key flags mismatch"); 713 } 714 } 715 716 prevdel = previnact = 0; 717 if ((setdel && setinact && del < inact) || 718 (dst_key_gettime(key, DST_TIME_INACTIVE, &previnact) == 719 ISC_R_SUCCESS && 720 setdel && !setinact && !unsetinact && del < previnact) || 721 (dst_key_gettime(key, DST_TIME_DELETE, &prevdel) == ISC_R_SUCCESS && 722 setinact && !setdel && !unsetdel && prevdel < inact) || 723 (!setdel && !unsetdel && !setinact && !unsetinact && prevdel != 0 && 724 prevdel < previnact)) 725 { 726 fprintf(stderr, 727 "%s: warning: Key is scheduled to " 728 "be deleted before it is\n\t" 729 "scheduled to be inactive.\n", 730 program); 731 } 732 733 if (force) { 734 set_keyversion(key); 735 } else { 736 check_keyversion(key, keystr); 737 } 738 739 if (verbose > 2) { 740 fprintf(stderr, "%s: %s\n", program, keystr); 741 } 742 743 /* 744 * Set time values. 745 */ 746 if (setpub) { 747 dst_key_settime(key, DST_TIME_PUBLISH, pub); 748 } else if (unsetpub) { 749 dst_key_unsettime(key, DST_TIME_PUBLISH); 750 } 751 752 if (setact) { 753 dst_key_settime(key, DST_TIME_ACTIVATE, act); 754 } else if (unsetact) { 755 dst_key_unsettime(key, DST_TIME_ACTIVATE); 756 } 757 758 if (setrev) { 759 if ((dst_key_flags(key) & DNS_KEYFLAG_REVOKE) != 0) { 760 fprintf(stderr, 761 "%s: warning: Key %s is already " 762 "revoked; changing the revocation date " 763 "will not affect this.\n", 764 program, keystr); 765 } 766 if ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0) { 767 fprintf(stderr, 768 "%s: warning: Key %s is not flagged as " 769 "a KSK, but -R was used. Revoking a " 770 "ZSK is legal, but undefined.\n", 771 program, keystr); 772 } 773 dst_key_settime(key, DST_TIME_REVOKE, rev); 774 } else if (unsetrev) { 775 if ((dst_key_flags(key) & DNS_KEYFLAG_REVOKE) != 0) { 776 fprintf(stderr, 777 "%s: warning: Key %s is already " 778 "revoked; removing the revocation date " 779 "will not affect this.\n", 780 program, keystr); 781 } 782 dst_key_unsettime(key, DST_TIME_REVOKE); 783 } 784 785 if (setinact) { 786 dst_key_settime(key, DST_TIME_INACTIVE, inact); 787 } else if (unsetinact) { 788 dst_key_unsettime(key, DST_TIME_INACTIVE); 789 } 790 791 if (setdel) { 792 dst_key_settime(key, DST_TIME_DELETE, del); 793 } else if (unsetdel) { 794 dst_key_unsettime(key, DST_TIME_DELETE); 795 } 796 797 if (setsyncadd) { 798 dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncadd); 799 } else if (unsetsyncadd) { 800 dst_key_unsettime(key, DST_TIME_SYNCPUBLISH); 801 } 802 803 if (setsyncdel) { 804 dst_key_settime(key, DST_TIME_SYNCDELETE, syncdel); 805 } else if (unsetsyncdel) { 806 dst_key_unsettime(key, DST_TIME_SYNCDELETE); 807 } 808 809 if (setdsadd) { 810 dst_key_settime(key, DST_TIME_DSPUBLISH, dsadd); 811 } else if (unsetdsadd) { 812 dst_key_unsettime(key, DST_TIME_DSPUBLISH); 813 } 814 815 if (setdsdel) { 816 dst_key_settime(key, DST_TIME_DSDELETE, dsdel); 817 } else if (unsetdsdel) { 818 dst_key_unsettime(key, DST_TIME_DSDELETE); 819 } 820 821 if (setttl) { 822 dst_key_setttl(key, ttl); 823 } 824 825 if (predecessor != NULL && prevkey != NULL) { 826 dst_key_setnum(prevkey, DST_NUM_SUCCESSOR, dst_key_id(key)); 827 dst_key_setnum(key, DST_NUM_PREDECESSOR, dst_key_id(prevkey)); 828 } 829 830 /* 831 * No metadata changes were made but we're forcing an upgrade 832 * to the new format anyway: use "-P now -A now" as the default 833 */ 834 if (force && !changed) { 835 dst_key_settime(key, DST_TIME_PUBLISH, now); 836 dst_key_settime(key, DST_TIME_ACTIVATE, now); 837 changed = true; 838 } 839 840 /* 841 * Make sure the key state goals are written. 842 */ 843 if (write_state) { 844 if (setgoal) { 845 if (goal == DST_KEY_STATE_NA) { 846 dst_key_unsetstate(key, DST_KEY_GOAL); 847 } else { 848 dst_key_setstate(key, DST_KEY_GOAL, goal); 849 } 850 changed = true; 851 } 852 if (setds) { 853 if (ds == DST_KEY_STATE_NA) { 854 dst_key_unsetstate(key, DST_KEY_DS); 855 dst_key_unsettime(key, DST_TIME_DS); 856 } else { 857 dst_key_setstate(key, DST_KEY_DS, ds); 858 dst_key_settime(key, DST_TIME_DS, dstime); 859 } 860 changed = true; 861 } 862 if (setdnskey) { 863 if (dnskey == DST_KEY_STATE_NA) { 864 dst_key_unsetstate(key, DST_KEY_DNSKEY); 865 dst_key_unsettime(key, DST_TIME_DNSKEY); 866 } else { 867 dst_key_setstate(key, DST_KEY_DNSKEY, dnskey); 868 dst_key_settime(key, DST_TIME_DNSKEY, 869 dnskeytime); 870 } 871 changed = true; 872 } 873 if (setkrrsig) { 874 if (krrsig == DST_KEY_STATE_NA) { 875 dst_key_unsetstate(key, DST_KEY_KRRSIG); 876 dst_key_unsettime(key, DST_TIME_KRRSIG); 877 } else { 878 dst_key_setstate(key, DST_KEY_KRRSIG, krrsig); 879 dst_key_settime(key, DST_TIME_KRRSIG, 880 krrsigtime); 881 } 882 changed = true; 883 } 884 if (setzrrsig) { 885 if (zrrsig == DST_KEY_STATE_NA) { 886 dst_key_unsetstate(key, DST_KEY_ZRRSIG); 887 dst_key_unsettime(key, DST_TIME_ZRRSIG); 888 } else { 889 dst_key_setstate(key, DST_KEY_ZRRSIG, zrrsig); 890 dst_key_settime(key, DST_TIME_ZRRSIG, 891 zrrsigtime); 892 } 893 changed = true; 894 } 895 } 896 897 if (!changed && setttl) { 898 changed = true; 899 } 900 901 /* 902 * Print out time values, if -p was used. 903 */ 904 if (printcreate) { 905 printtime(key, DST_TIME_CREATED, "Created", epoch, stdout); 906 } 907 908 if (printpub) { 909 printtime(key, DST_TIME_PUBLISH, "Publish", epoch, stdout); 910 } 911 912 if (printact) { 913 printtime(key, DST_TIME_ACTIVATE, "Activate", epoch, stdout); 914 } 915 916 if (printrev) { 917 printtime(key, DST_TIME_REVOKE, "Revoke", epoch, stdout); 918 } 919 920 if (printinact) { 921 printtime(key, DST_TIME_INACTIVE, "Inactive", epoch, stdout); 922 } 923 924 if (printdel) { 925 printtime(key, DST_TIME_DELETE, "Delete", epoch, stdout); 926 } 927 928 if (printsyncadd) { 929 printtime(key, DST_TIME_SYNCPUBLISH, "SYNC Publish", epoch, 930 stdout); 931 } 932 933 if (printsyncdel) { 934 printtime(key, DST_TIME_SYNCDELETE, "SYNC Delete", epoch, 935 stdout); 936 } 937 938 if (printdsadd) { 939 printtime(key, DST_TIME_DSPUBLISH, "DS Publish", epoch, stdout); 940 } 941 942 if (printdsdel) { 943 printtime(key, DST_TIME_DSDELETE, "DS Delete", epoch, stdout); 944 } 945 946 if (changed) { 947 writekey(key, directory, write_state); 948 if (predecessor != NULL && prevkey != NULL) { 949 writekey(prevkey, directory, write_state); 950 } 951 } 952 953 if (prevkey != NULL) { 954 dst_key_free(&prevkey); 955 } 956 dst_key_free(&key); 957 dst_lib_destroy(); 958 if (verbose > 10) { 959 isc_mem_stats(mctx, stdout); 960 } 961 cleanup_logging(&log); 962 isc_mem_free(mctx, directory); 963 isc_mem_destroy(&mctx); 964 965 return 0; 966 } 967