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