1 /* $NetBSD: dnssec-keyfromlabel.c,v 1.11 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 <ctype.h> 19 #include <inttypes.h> 20 #include <stdbool.h> 21 #include <stdlib.h> 22 23 #include <isc/attributes.h> 24 #include <isc/buffer.h> 25 #include <isc/commandline.h> 26 #include <isc/mem.h> 27 #include <isc/region.h> 28 #include <isc/result.h> 29 #include <isc/string.h> 30 #include <isc/util.h> 31 32 #include <dns/dnssec.h> 33 #include <dns/fixedname.h> 34 #include <dns/keyvalues.h> 35 #include <dns/log.h> 36 #include <dns/name.h> 37 #include <dns/rdataclass.h> 38 #include <dns/secalg.h> 39 40 #include <dst/dst.h> 41 42 #include "dnssectool.h" 43 44 #define MAX_RSA 4096 /* should be long enough... */ 45 46 const char *program = "dnssec-keyfromlabel"; 47 48 static uint16_t tag_min = 0, tag_max = 0xffff; 49 50 noreturn static void 51 usage(void); 52 53 static void 54 usage(void) { 55 fprintf(stderr, "Usage:\n"); 56 fprintf(stderr, " %s -l label [options] name\n\n", program); 57 fprintf(stderr, "Version: %s\n", PACKAGE_VERSION); 58 fprintf(stderr, "Required options:\n"); 59 fprintf(stderr, " -l label: label of the key pair\n"); 60 fprintf(stderr, " name: owner of the key\n"); 61 fprintf(stderr, "Other options:\n"); 62 fprintf(stderr, " -a algorithm: \n" 63 " RSASHA1 |\n" 64 " NSEC3RSASHA1 |\n" 65 " RSASHA256 | RSASHA512 |\n" 66 " ECDSAP256SHA256 | ECDSAP384SHA384 |\n" 67 " ED25519 | ED448\n"); 68 fprintf(stderr, " -3: use NSEC3-capable algorithm\n"); 69 fprintf(stderr, " -c class (default: IN)\n"); 70 fprintf(stderr, " -E <engine>:\n"); 71 fprintf(stderr, " name of an OpenSSL engine to use\n"); 72 fprintf(stderr, " -f keyflag: KSK | REVOKE\n"); 73 fprintf(stderr, " -K directory: directory in which to place " 74 "key files\n"); 75 fprintf(stderr, " -k: generate a TYPE=KEY key\n"); 76 fprintf(stderr, " -L ttl: default key TTL\n"); 77 fprintf(stderr, " -M <min>:<max>: allowed Key ID range\n"); 78 fprintf(stderr, " -n nametype: ZONE | HOST | ENTITY | USER | " 79 "OTHER\n"); 80 fprintf(stderr, " (DNSKEY generation defaults to ZONE\n"); 81 fprintf(stderr, " -p protocol: default: 3 [dnssec]\n"); 82 fprintf(stderr, " -t type: " 83 "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " 84 "(default: AUTHCONF)\n"); 85 fprintf(stderr, " -y: permit keys that might collide\n"); 86 fprintf(stderr, " -v verbose level\n"); 87 fprintf(stderr, " -V: print version information\n"); 88 fprintf(stderr, "Date options:\n"); 89 fprintf(stderr, " -P date/[+-]offset: set key publication date\n"); 90 fprintf(stderr, " -P sync date/[+-]offset: set CDS and CDNSKEY " 91 "publication date\n"); 92 fprintf(stderr, " -A date/[+-]offset: set key activation date\n"); 93 fprintf(stderr, " -R date/[+-]offset: set key revocation date\n"); 94 fprintf(stderr, " -I date/[+-]offset: set key inactivation date\n"); 95 fprintf(stderr, " -D date/[+-]offset: set key deletion date\n"); 96 fprintf(stderr, " -D sync date/[+-]offset: set CDS and CDNSKEY " 97 "deletion date\n"); 98 fprintf(stderr, " -G: generate key only; do not set -P or -A\n"); 99 fprintf(stderr, " -C: generate a backward-compatible key, omitting" 100 " all dates\n"); 101 fprintf(stderr, " -S <key>: generate a successor to an existing " 102 "key\n"); 103 fprintf(stderr, " -i <interval>: prepublication interval for " 104 "successor key " 105 "(default: 30 days)\n"); 106 fprintf(stderr, "Output:\n"); 107 fprintf(stderr, " K<name>+<alg>+<id>.key, " 108 "K<name>+<alg>+<id>.private\n"); 109 110 exit(EXIT_FAILURE); 111 } 112 113 int 114 main(int argc, char **argv) { 115 char *algname = NULL, *freeit = NULL; 116 char *nametype = NULL, *type = NULL; 117 const char *directory = NULL; 118 const char *predecessor = NULL; 119 dst_key_t *prevkey = NULL; 120 const char *engine = NULL; 121 char *classname = NULL; 122 char *endp; 123 dst_key_t *key = NULL; 124 dns_fixedname_t fname; 125 dns_name_t *name; 126 uint16_t flags = 0, kskflag = 0, revflag = 0; 127 dns_secalg_t alg; 128 bool oldstyle = false; 129 isc_mem_t *mctx = NULL; 130 int ch; 131 int protocol = -1, signatory = 0; 132 isc_result_t ret; 133 isc_textregion_t r; 134 char filename[255]; 135 isc_buffer_t buf; 136 isc_log_t *log = NULL; 137 dns_rdataclass_t rdclass; 138 int options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC; 139 char *label = NULL; 140 dns_ttl_t ttl = 0; 141 isc_stdtime_t publish = 0, activate = 0, revoke = 0; 142 isc_stdtime_t inactive = 0, deltime = 0; 143 int prepub = -1; 144 bool setpub = false, setact = false; 145 bool setrev = false, setinact = false; 146 bool setdel = false, setttl = false; 147 bool unsetpub = false, unsetact = false; 148 bool unsetrev = false, unsetinact = false; 149 bool unsetdel = false; 150 bool genonly = false; 151 bool use_nsec3 = false; 152 bool avoid_collisions = true; 153 bool exact; 154 unsigned char c; 155 isc_stdtime_t syncadd = 0, syncdel = 0; 156 bool unsetsyncadd = false, setsyncadd = false; 157 bool unsetsyncdel = false, setsyncdel = false; 158 isc_stdtime_t now = isc_stdtime_now(); 159 160 if (argc == 1) { 161 usage(); 162 } 163 164 isc_mem_create(&mctx); 165 166 isc_commandline_errprint = false; 167 168 #define CMDLINE_FLAGS "3A:a:Cc:D:E:Ff:GhI:i:kK:L:l:M:n:P:p:R:S:t:v:Vy" 169 while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { 170 switch (ch) { 171 case '3': 172 use_nsec3 = true; 173 break; 174 case 'a': 175 algname = isc_commandline_argument; 176 break; 177 case 'C': 178 oldstyle = true; 179 break; 180 case 'c': 181 classname = isc_commandline_argument; 182 break; 183 case 'E': 184 engine = isc_commandline_argument; 185 break; 186 case 'f': 187 c = (unsigned char)(isc_commandline_argument[0]); 188 if (toupper(c) == 'K') { 189 kskflag = DNS_KEYFLAG_KSK; 190 } else if (toupper(c) == 'R') { 191 revflag = DNS_KEYFLAG_REVOKE; 192 } else { 193 fatal("unknown flag '%s'", 194 isc_commandline_argument); 195 } 196 break; 197 case 'K': 198 directory = isc_commandline_argument; 199 ret = try_dir(directory); 200 if (ret != ISC_R_SUCCESS) { 201 fatal("cannot open directory %s: %s", directory, 202 isc_result_totext(ret)); 203 } 204 break; 205 case 'k': 206 options |= DST_TYPE_KEY; 207 break; 208 case 'L': 209 ttl = strtottl(isc_commandline_argument); 210 setttl = true; 211 break; 212 case 'l': 213 label = isc_mem_strdup(mctx, isc_commandline_argument); 214 break; 215 case 'M': { 216 unsigned long ul; 217 tag_min = ul = strtoul(isc_commandline_argument, &endp, 218 10); 219 if (*endp != ':' || ul > 0xffff) { 220 fatal("-M range invalid"); 221 } 222 tag_max = ul = strtoul(endp + 1, &endp, 10); 223 if (*endp != '\0' || ul > 0xffff || tag_max <= tag_min) 224 { 225 fatal("-M range invalid"); 226 } 227 break; 228 } 229 case 'n': 230 nametype = isc_commandline_argument; 231 break; 232 case 'p': 233 protocol = strtol(isc_commandline_argument, &endp, 10); 234 if (*endp != '\0' || protocol < 0 || protocol > 255) { 235 fatal("-p must be followed by a number " 236 "[0..255]"); 237 } 238 break; 239 case 't': 240 type = isc_commandline_argument; 241 break; 242 case 'v': 243 verbose = strtol(isc_commandline_argument, &endp, 0); 244 if (*endp != '\0') { 245 fatal("-v must be followed by a number"); 246 } 247 break; 248 case 'y': 249 avoid_collisions = false; 250 break; 251 case 'G': 252 genonly = true; 253 break; 254 case 'P': 255 /* -Psync ? */ 256 if (isoptarg("sync", argv, usage)) { 257 if (unsetsyncadd || setsyncadd) { 258 fatal("-P sync specified more than " 259 "once"); 260 } 261 262 syncadd = strtotime(isc_commandline_argument, 263 now, now, &setsyncadd); 264 unsetsyncadd = !setsyncadd; 265 break; 266 } 267 /* -Pdnskey ? */ 268 (void)isoptarg("dnskey", argv, usage); 269 if (setpub || unsetpub) { 270 fatal("-P specified more than once"); 271 } 272 273 publish = strtotime(isc_commandline_argument, now, now, 274 &setpub); 275 unsetpub = !setpub; 276 break; 277 case 'A': 278 if (setact || unsetact) { 279 fatal("-A specified more than once"); 280 } 281 282 activate = strtotime(isc_commandline_argument, now, now, 283 &setact); 284 unsetact = !setact; 285 break; 286 case 'R': 287 if (setrev || unsetrev) { 288 fatal("-R specified more than once"); 289 } 290 291 revoke = strtotime(isc_commandline_argument, now, now, 292 &setrev); 293 unsetrev = !setrev; 294 break; 295 case 'I': 296 if (setinact || unsetinact) { 297 fatal("-I specified more than once"); 298 } 299 300 inactive = strtotime(isc_commandline_argument, now, now, 301 &setinact); 302 unsetinact = !setinact; 303 break; 304 case 'D': 305 /* -Dsync ? */ 306 if (isoptarg("sync", argv, usage)) { 307 if (unsetsyncdel || setsyncdel) { 308 fatal("-D sync specified more than " 309 "once"); 310 } 311 312 syncdel = strtotime(isc_commandline_argument, 313 now, now, &setsyncdel); 314 unsetsyncdel = !setsyncdel; 315 break; 316 } 317 /* -Ddnskey ? */ 318 (void)isoptarg("dnskey", argv, usage); 319 if (setdel || unsetdel) { 320 fatal("-D specified more than once"); 321 } 322 323 deltime = strtotime(isc_commandline_argument, now, now, 324 &setdel); 325 unsetdel = !setdel; 326 break; 327 case 'S': 328 predecessor = isc_commandline_argument; 329 break; 330 case 'i': 331 prepub = strtottl(isc_commandline_argument); 332 break; 333 case 'F': 334 /* Reserved for FIPS mode */ 335 FALLTHROUGH; 336 case '?': 337 if (isc_commandline_option != '?') { 338 fprintf(stderr, "%s: invalid argument -%c\n", 339 program, isc_commandline_option); 340 } 341 FALLTHROUGH; 342 case 'h': 343 /* Does not return. */ 344 usage(); 345 346 case 'V': 347 /* Does not return. */ 348 version(program); 349 350 default: 351 fprintf(stderr, "%s: unhandled option -%c\n", program, 352 isc_commandline_option); 353 exit(EXIT_FAILURE); 354 } 355 } 356 357 ret = dst_lib_init(mctx, engine); 358 if (ret != ISC_R_SUCCESS) { 359 fatal("could not initialize dst: %s", isc_result_totext(ret)); 360 } 361 362 setup_logging(mctx, &log); 363 364 if (predecessor == NULL) { 365 if (label == NULL) { 366 fatal("the key label was not specified"); 367 } 368 if (argc < isc_commandline_index + 1) { 369 fatal("the key name was not specified"); 370 } 371 if (argc > isc_commandline_index + 1) { 372 fatal("extraneous arguments"); 373 } 374 375 name = dns_fixedname_initname(&fname); 376 isc_buffer_init(&buf, argv[isc_commandline_index], 377 strlen(argv[isc_commandline_index])); 378 isc_buffer_add(&buf, strlen(argv[isc_commandline_index])); 379 ret = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL); 380 if (ret != ISC_R_SUCCESS) { 381 fatal("invalid key name %s: %s", 382 argv[isc_commandline_index], 383 isc_result_totext(ret)); 384 } 385 386 if (strchr(label, ':') == NULL) { 387 char *l; 388 int len; 389 390 len = strlen(label) + 8; 391 l = isc_mem_allocate(mctx, len); 392 snprintf(l, len, "pkcs11:%s", label); 393 isc_mem_free(mctx, label); 394 label = l; 395 } 396 397 if (algname == NULL) { 398 fatal("no algorithm specified"); 399 } 400 401 r.base = algname; 402 r.length = strlen(algname); 403 ret = dns_secalg_fromtext(&alg, &r); 404 if (ret != ISC_R_SUCCESS) { 405 fatal("unknown algorithm %s", algname); 406 } 407 408 if (use_nsec3) { 409 switch (alg) { 410 case DST_ALG_RSASHA1: 411 alg = DST_ALG_NSEC3RSASHA1; 412 break; 413 case DST_ALG_NSEC3RSASHA1: 414 case DST_ALG_RSASHA256: 415 case DST_ALG_RSASHA512: 416 case DST_ALG_ECDSA256: 417 case DST_ALG_ECDSA384: 418 case DST_ALG_ED25519: 419 case DST_ALG_ED448: 420 break; 421 default: 422 fatal("%s is incompatible with NSEC3; " 423 "do not use the -3 option", 424 algname); 425 } 426 } 427 428 if (type != NULL && (options & DST_TYPE_KEY) != 0) { 429 if (strcasecmp(type, "NOAUTH") == 0) { 430 flags |= DNS_KEYTYPE_NOAUTH; 431 } else if (strcasecmp(type, "NOCONF") == 0) { 432 flags |= DNS_KEYTYPE_NOCONF; 433 } else if (strcasecmp(type, "NOAUTHCONF") == 0) { 434 flags |= (DNS_KEYTYPE_NOAUTH | 435 DNS_KEYTYPE_NOCONF); 436 } else if (strcasecmp(type, "AUTHCONF") == 0) { 437 /* nothing */ 438 } else { 439 fatal("invalid type %s", type); 440 } 441 } 442 443 if (!oldstyle && prepub > 0) { 444 if (setpub && setact && (activate - prepub) < publish) { 445 fatal("Activation and publication dates " 446 "are closer together than the\n\t" 447 "prepublication interval."); 448 } 449 450 if (!setpub && !setact) { 451 setpub = setact = true; 452 publish = now; 453 activate = now + prepub; 454 } else if (setpub && !setact) { 455 setact = true; 456 activate = publish + prepub; 457 } else if (setact && !setpub) { 458 setpub = true; 459 publish = activate - prepub; 460 } 461 462 if ((activate - prepub) < now) { 463 fatal("Time until activation is shorter " 464 "than the\n\tprepublication interval."); 465 } 466 } 467 } else { 468 char keystr[DST_KEY_FORMATSIZE]; 469 isc_stdtime_t when; 470 int major, minor; 471 472 if (prepub == -1) { 473 prepub = (30 * 86400); 474 } 475 476 if (algname != NULL) { 477 fatal("-S and -a cannot be used together"); 478 } 479 if (nametype != NULL) { 480 fatal("-S and -n cannot be used together"); 481 } 482 if (type != NULL) { 483 fatal("-S and -t cannot be used together"); 484 } 485 if (setpub || unsetpub) { 486 fatal("-S and -P cannot be used together"); 487 } 488 if (setact || unsetact) { 489 fatal("-S and -A cannot be used together"); 490 } 491 if (use_nsec3) { 492 fatal("-S and -3 cannot be used together"); 493 } 494 if (oldstyle) { 495 fatal("-S and -C cannot be used together"); 496 } 497 if (genonly) { 498 fatal("-S and -G cannot be used together"); 499 } 500 501 ret = dst_key_fromnamedfile(predecessor, directory, 502 DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, 503 mctx, &prevkey); 504 if (ret != ISC_R_SUCCESS) { 505 fatal("Invalid keyfile %s: %s", predecessor, 506 isc_result_totext(ret)); 507 } 508 if (!dst_key_isprivate(prevkey)) { 509 fatal("%s is not a private key", predecessor); 510 } 511 512 name = dst_key_name(prevkey); 513 alg = dst_key_alg(prevkey); 514 flags = dst_key_flags(prevkey); 515 516 dst_key_format(prevkey, keystr, sizeof(keystr)); 517 dst_key_getprivateformat(prevkey, &major, &minor); 518 if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) { 519 fatal("Key %s has incompatible format version %d.%d\n\t" 520 "It is not possible to generate a successor key.", 521 keystr, major, minor); 522 } 523 524 ret = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &when); 525 if (ret != ISC_R_SUCCESS) { 526 fatal("Key %s has no activation date.\n\t" 527 "You must use dnssec-settime -A to set one " 528 "before generating a successor.", 529 keystr); 530 } 531 532 ret = dst_key_gettime(prevkey, DST_TIME_INACTIVE, &activate); 533 if (ret != ISC_R_SUCCESS) { 534 fatal("Key %s has no inactivation date.\n\t" 535 "You must use dnssec-settime -I to set one " 536 "before generating a successor.", 537 keystr); 538 } 539 540 publish = activate - prepub; 541 if (publish < now) { 542 fatal("Key %s becomes inactive\n\t" 543 "sooner than the prepublication period " 544 "for the new key ends.\n\t" 545 "Either change the inactivation date with " 546 "dnssec-settime -I,\n\t" 547 "or use the -i option to set a shorter " 548 "prepublication interval.", 549 keystr); 550 } 551 552 ret = dst_key_gettime(prevkey, DST_TIME_DELETE, &when); 553 if (ret != ISC_R_SUCCESS) { 554 fprintf(stderr, 555 "%s: WARNING: Key %s has no removal " 556 "date;\n\t it will remain in the zone " 557 "indefinitely after rollover.\n\t " 558 "You can use dnssec-settime -D to " 559 "change this.\n", 560 program, keystr); 561 } 562 563 setpub = setact = true; 564 } 565 566 if (nametype == NULL) { 567 if ((options & DST_TYPE_KEY) != 0) { /* KEY */ 568 fatal("no nametype specified"); 569 } 570 flags |= DNS_KEYOWNER_ZONE; /* DNSKEY */ 571 } else if (strcasecmp(nametype, "zone") == 0) { 572 flags |= DNS_KEYOWNER_ZONE; 573 } else if ((options & DST_TYPE_KEY) != 0) { /* KEY */ 574 if (strcasecmp(nametype, "host") == 0 || 575 strcasecmp(nametype, "entity") == 0) 576 { 577 flags |= DNS_KEYOWNER_ENTITY; 578 } else if (strcasecmp(nametype, "user") == 0) { 579 flags |= DNS_KEYOWNER_USER; 580 } else { 581 fatal("invalid KEY nametype %s", nametype); 582 } 583 } else if (strcasecmp(nametype, "other") != 0) { /* DNSKEY */ 584 fatal("invalid DNSKEY nametype %s", nametype); 585 } 586 587 rdclass = strtoclass(classname); 588 589 if (directory == NULL) { 590 directory = "."; 591 } 592 593 if ((options & DST_TYPE_KEY) != 0) { /* KEY */ 594 flags |= signatory; 595 } else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */ 596 flags |= kskflag; 597 flags |= revflag; 598 } 599 600 if (protocol == -1) { 601 protocol = DNS_KEYPROTO_DNSSEC; 602 } else if ((options & DST_TYPE_KEY) == 0 && 603 protocol != DNS_KEYPROTO_DNSSEC) 604 { 605 fatal("invalid DNSKEY protocol: %d", protocol); 606 } 607 608 if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { 609 if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0) { 610 fatal("specified null key with signing authority"); 611 } 612 } 613 614 isc_buffer_init(&buf, filename, sizeof(filename) - 1); 615 616 /* associate the key */ 617 ret = dst_key_fromlabel(name, alg, flags, protocol, rdclass, engine, 618 label, NULL, mctx, &key); 619 620 if (ret != ISC_R_SUCCESS) { 621 char namestr[DNS_NAME_FORMATSIZE]; 622 char algstr[DNS_SECALG_FORMATSIZE]; 623 dns_name_format(name, namestr, sizeof(namestr)); 624 dns_secalg_format(alg, algstr, sizeof(algstr)); 625 fatal("failed to get key %s/%s: %s", namestr, algstr, 626 isc_result_totext(ret)); 627 UNREACHABLE(); 628 exit(EXIT_FAILURE); 629 } 630 631 /* 632 * Set key timing metadata (unless using -C) 633 * 634 * Publish and activation dates are set to "now" by default, but 635 * can be overridden. Creation date is always set to "now". 636 */ 637 if (!oldstyle) { 638 dst_key_settime(key, DST_TIME_CREATED, now); 639 640 if (genonly && (setpub || setact)) { 641 fatal("cannot use -G together with -P or -A options"); 642 } 643 644 if (setpub) { 645 dst_key_settime(key, DST_TIME_PUBLISH, publish); 646 } else if (setact) { 647 dst_key_settime(key, DST_TIME_PUBLISH, activate); 648 } else if (!genonly && !unsetpub) { 649 dst_key_settime(key, DST_TIME_PUBLISH, now); 650 } 651 652 if (setact) { 653 dst_key_settime(key, DST_TIME_ACTIVATE, activate); 654 } else if (!genonly && !unsetact) { 655 dst_key_settime(key, DST_TIME_ACTIVATE, now); 656 } 657 658 if (setrev) { 659 if (kskflag == 0) { 660 fprintf(stderr, 661 "%s: warning: Key is " 662 "not flagged as a KSK, but -R " 663 "was used. Revoking a ZSK is " 664 "legal, but undefined.\n", 665 program); 666 } 667 dst_key_settime(key, DST_TIME_REVOKE, revoke); 668 } 669 670 if (setinact) { 671 dst_key_settime(key, DST_TIME_INACTIVE, inactive); 672 } 673 674 if (setdel) { 675 dst_key_settime(key, DST_TIME_DELETE, deltime); 676 } 677 if (setsyncadd) { 678 dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncadd); 679 } 680 if (setsyncdel) { 681 dst_key_settime(key, DST_TIME_SYNCDELETE, syncdel); 682 } 683 } else { 684 if (setpub || setact || setrev || setinact || setdel || 685 unsetpub || unsetact || unsetrev || unsetinact || 686 unsetdel || genonly || setsyncadd || setsyncdel) 687 { 688 fatal("cannot use -C together with " 689 "-P, -A, -R, -I, -D, or -G options"); 690 } 691 /* 692 * Compatibility mode: Private-key-format 693 * should be set to 1.2. 694 */ 695 dst_key_setprivateformat(key, 1, 2); 696 } 697 698 /* Set default key TTL */ 699 if (setttl) { 700 dst_key_setttl(key, ttl); 701 } 702 703 /* 704 * Do not overwrite an existing key. Warn LOUDLY if there 705 * is a risk of ID collision due to this key or another key 706 * being revoked. 707 */ 708 if (key_collision(key, name, directory, mctx, tag_min, tag_max, &exact)) 709 { 710 isc_buffer_clear(&buf); 711 ret = dst_key_buildfilename(key, 0, directory, &buf); 712 if (ret != ISC_R_SUCCESS) { 713 fatal("dst_key_buildfilename returned: %s\n", 714 isc_result_totext(ret)); 715 } 716 if (exact) { 717 fatal("%s: %s already exists\n", program, filename); 718 } 719 720 if (avoid_collisions) { 721 fatal("%s: %s could collide with another key upon " 722 "revokation\n", 723 program, filename); 724 } 725 726 fprintf(stderr, 727 "%s: WARNING: Key %s could collide with " 728 "another key upon revokation. If you plan " 729 "to revoke keys, destroy this key and " 730 "generate a different one.\n", 731 program, filename); 732 } 733 734 ret = dst_key_tofile(key, options, directory); 735 if (ret != ISC_R_SUCCESS) { 736 char keystr[DST_KEY_FORMATSIZE]; 737 dst_key_format(key, keystr, sizeof(keystr)); 738 fatal("failed to write key %s: %s\n", keystr, 739 isc_result_totext(ret)); 740 } 741 742 isc_buffer_clear(&buf); 743 ret = dst_key_buildfilename(key, 0, NULL, &buf); 744 if (ret != ISC_R_SUCCESS) { 745 fatal("dst_key_buildfilename returned: %s\n", 746 isc_result_totext(ret)); 747 } 748 printf("%s\n", filename); 749 dst_key_free(&key); 750 if (prevkey != NULL) { 751 dst_key_free(&prevkey); 752 } 753 754 cleanup_logging(&log); 755 dst_lib_destroy(); 756 if (verbose > 10) { 757 isc_mem_stats(mctx, stdout); 758 } 759 isc_mem_free(mctx, label); 760 isc_mem_destroy(&mctx); 761 762 if (freeit != NULL) { 763 free(freeit); 764 } 765 766 return 0; 767 } 768