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