Update repub branch u/fanf2/patch to rebasing branch u/fanf2/rebasing revision v9_13_...
[ipreg/bind9.git] / bin / dnssec / dnssec-keygen.c
1 /*
2 * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 *
11 * Portions Copyright (C) Network Associates, Inc.
12 *
13 * Permission to use, copy, modify, and/or distribute this software for any
14 * purpose with or without fee is hereby granted, provided that the above
15 * copyright notice and this permission notice appear in all copies.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
18 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
20 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
23 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 */
25
26 /*! \file */
27
28 #include <ctype.h>
29 #include <inttypes.h>
30 #include <stdbool.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33
34 #include <isc/buffer.h>
35 #include <isc/commandline.h>
36 #include <isc/mem.h>
37 #include <isc/print.h>
38 #include <isc/region.h>
39 #include <isc/string.h>
40 #include <isc/util.h>
41
42 #include <pk11/site.h>
43
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/rdataclass.h>
50 #include <dns/result.h>
51 #include <dns/secalg.h>
52
53 #include <dst/dst.h>
54
55 #if USE_PKCS11
56 #include <pk11/result.h>
57 #endif
58
59 #include "dnssectool.h"
60
61 #define MAX_RSA 4096 /* should be long enough... */
62
63 const char *program = "dnssec-keygen";
64 int verbose;
65
66 ISC_PLATFORM_NORETURN_PRE static void
67 usage(void) ISC_PLATFORM_NORETURN_POST;
68
69 static void progress(int p);
70
71 static void
72 usage(void) {
73 fprintf(stderr, "Usage:\n");
74 fprintf(stderr, " %s [options] name\n\n", program);
75 fprintf(stderr, "Version: %s\n", VERSION);
76 fprintf(stderr, " name: owner of the key\n");
77 fprintf(stderr, "Options:\n");
78 fprintf(stderr, " -K <directory>: write keys into directory\n");
79 fprintf(stderr, " -a <algorithm>:\n");
80 fprintf(stderr, " RSASHA1 | NSEC3RSASHA1 |\n");
81 fprintf(stderr, " RSASHA256 | RSASHA512 |\n");
82 fprintf(stderr, " ECDSAP256SHA256 | ECDSAP384SHA384 |\n");
83 fprintf(stderr, " ED25519 | ED448 | DH\n");
84 fprintf(stderr, " -3: use NSEC3-capable algorithm\n");
85 fprintf(stderr, " -b <key size in bits>:\n");
86 fprintf(stderr, " RSASHA1:\t[1024..%d]\n", MAX_RSA);
87 fprintf(stderr, " NSEC3RSASHA1:\t[1024..%d]\n", MAX_RSA);
88 fprintf(stderr, " RSASHA256:\t[1024..%d]\n", MAX_RSA);
89 fprintf(stderr, " RSASHA512:\t[1024..%d]\n", MAX_RSA);
90 fprintf(stderr, " DH:\t\t[128..4096]\n");
91 fprintf(stderr, " ECDSAP256SHA256:\tignored\n");
92 fprintf(stderr, " ECDSAP384SHA384:\tignored\n");
93 fprintf(stderr, " ED25519:\tignored\n");
94 fprintf(stderr, " ED448:\tignored\n");
95 fprintf(stderr, " (key size defaults are set according to\n"
96 " algorithm and usage (ZSK or KSK)\n");
97 fprintf(stderr, " -n <nametype>: ZONE | HOST | ENTITY | "
98 "USER | OTHER\n");
99 fprintf(stderr, " (DNSKEY generation defaults to ZONE)\n");
100 fprintf(stderr, " -c <class>: (default: IN)\n");
101 fprintf(stderr, " -d <digest bits> (0 => max, default)\n");
102 fprintf(stderr, " -E <engine>:\n");
103 #if USE_PKCS11
104 fprintf(stderr, " path to PKCS#11 provider library "
105 "(default is %s)\n", PK11_LIB_LOCATION);
106 #else
107 fprintf(stderr, " name of an OpenSSL engine to use\n");
108 #endif
109 fprintf(stderr, " -f <keyflag>: KSK | REVOKE\n");
110 fprintf(stderr, " -g <generator>: use specified generator "
111 "(DH only)\n");
112 fprintf(stderr, " -L <ttl>: default key TTL\n");
113 fprintf(stderr, " -p <protocol>: (default: 3 [dnssec])\n");
114 fprintf(stderr, " -s <strength>: strength value this key signs DNS "
115 "records with (default: 0)\n");
116 fprintf(stderr, " -T <rrtype>: DNSKEY | KEY (default: DNSKEY; "
117 "use KEY for SIG(0))\n");
118 fprintf(stderr, " -t <type>: "
119 "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF "
120 "(default: AUTHCONF)\n");
121 fprintf(stderr, " -h: print usage and exit\n");
122 fprintf(stderr, " -m <memory debugging mode>:\n");
123 fprintf(stderr, " usage | trace | record | size | mctx\n");
124 fprintf(stderr, " -v <level>: set verbosity level (0 - 10)\n");
125 fprintf(stderr, " -V: print version information\n");
126 fprintf(stderr, "Timing options:\n");
127 fprintf(stderr, " -P date/[+-]offset/none: set key publication date "
128 "(default: now)\n");
129 fprintf(stderr, " -P sync date/[+-]offset/none: set CDS and CDNSKEY "
130 "publication date\n");
131 fprintf(stderr, " -A date/[+-]offset/none: set key activation date "
132 "(default: now)\n");
133 fprintf(stderr, " -R date/[+-]offset/none: set key "
134 "revocation date\n");
135 fprintf(stderr, " -I date/[+-]offset/none: set key "
136 "inactivation date\n");
137 fprintf(stderr, " -D date/[+-]offset/none: set key deletion date\n");
138 fprintf(stderr, " -D sync date/[+-]offset/none: set CDS and CDNSKEY "
139 "deletion date\n");
140
141 fprintf(stderr, " -G: generate key only; do not set -P or -A\n");
142 fprintf(stderr, " -C: generate a backward-compatible key, omitting "
143 "all dates\n");
144 fprintf(stderr, " -S <key>: generate a successor to an existing "
145 "key\n");
146 fprintf(stderr, " -i <interval>: prepublication interval for "
147 "successor key "
148 "(default: 30 days)\n");
149 fprintf(stderr, "Output:\n");
150 fprintf(stderr, " K<name>+<alg>+<id>.key, "
151 "K<name>+<alg>+<id>.private\n");
152
153 exit (-1);
154 }
155
156 static void
157 progress(int p)
158 {
159 char c = '*';
160
161 switch (p) {
162 case 0:
163 c = '.';
164 break;
165 case 1:
166 c = '+';
167 break;
168 case 2:
169 c = '*';
170 break;
171 case 3:
172 c = ' ';
173 break;
174 default:
175 break;
176 }
177 (void) putc(c, stderr);
178 (void) fflush(stderr);
179 }
180
181 int
182 main(int argc, char **argv) {
183 char *algname = NULL, *freeit = NULL;
184 char *nametype = NULL, *type = NULL;
185 char *classname = NULL;
186 char *endp;
187 dst_key_t *key = NULL;
188 dns_fixedname_t fname;
189 dns_name_t *name;
190 uint16_t flags = 0, kskflag = 0, revflag = 0;
191 dns_secalg_t alg;
192 bool conflict = false, null_key = false;
193 bool oldstyle = false;
194 isc_mem_t *mctx = NULL;
195 int ch, generator = 0, param = 0;
196 int protocol = -1, size = -1, signatory = 0;
197 isc_result_t ret;
198 isc_textregion_t r;
199 char filename[255];
200 const char *directory = NULL;
201 const char *predecessor = NULL;
202 dst_key_t *prevkey = NULL;
203 isc_buffer_t buf;
204 isc_log_t *log = NULL;
205 const char *engine = NULL;
206 dns_rdataclass_t rdclass;
207 int options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC;
208 int dbits = 0;
209 dns_ttl_t ttl = 0;
210 bool use_nsec3 = false;
211 isc_stdtime_t publish = 0, activate = 0, revokekey = 0;
212 isc_stdtime_t inactive = 0, deltime = 0;
213 isc_stdtime_t now;
214 int prepub = -1;
215 bool setpub = false, setact = false;
216 bool setrev = false, setinact = false;
217 bool setdel = false, setttl = false;
218 bool unsetpub = false, unsetact = false;
219 bool unsetrev = false, unsetinact = false;
220 bool unsetdel = false;
221 bool genonly = false;
222 bool quiet = false;
223 bool show_progress = false;
224 unsigned char c;
225 isc_stdtime_t syncadd = 0, syncdel = 0;
226 bool setsyncadd = false;
227 bool setsyncdel = false;
228
229 if (argc == 1)
230 usage();
231
232 #if USE_PKCS11
233 pk11_result_register();
234 #endif
235 dns_result_register();
236
237 isc_commandline_errprint = false;
238
239 /*
240 * Process memory debugging argument first.
241 */
242 #define CMDLINE_FLAGS "3A:a:b:Cc:D:d:E:eFf:Gg:hI:i:K:L:m:n:P:p:qR:r:S:s:T:t:" \
243 "v:V"
244 while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
245 switch (ch) {
246 case 'm':
247 if (strcasecmp(isc_commandline_argument, "record") == 0)
248 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
249 if (strcasecmp(isc_commandline_argument, "trace") == 0)
250 isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
251 if (strcasecmp(isc_commandline_argument, "usage") == 0)
252 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
253 if (strcasecmp(isc_commandline_argument, "size") == 0)
254 isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
255 if (strcasecmp(isc_commandline_argument, "mctx") == 0)
256 isc_mem_debugging |= ISC_MEM_DEBUGCTX;
257 break;
258 default:
259 break;
260 }
261 }
262 isc_commandline_reset = true;
263
264 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
265
266 isc_stdtime_get(&now);
267
268 while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
269 switch (ch) {
270 case '3':
271 use_nsec3 = true;
272 break;
273 case 'a':
274 algname = isc_commandline_argument;
275 break;
276 case 'b':
277 size = strtol(isc_commandline_argument, &endp, 10);
278 if (*endp != '\0' || size < 0)
279 fatal("-b requires a non-negative number");
280 break;
281 case 'C':
282 oldstyle = true;
283 break;
284 case 'c':
285 classname = isc_commandline_argument;
286 break;
287 case 'd':
288 dbits = strtol(isc_commandline_argument, &endp, 10);
289 if (*endp != '\0' || dbits < 0)
290 fatal("-d requires a non-negative number");
291 break;
292 case 'E':
293 engine = isc_commandline_argument;
294 break;
295 case 'e':
296 fprintf(stderr,
297 "phased-out option -e "
298 "(was 'use (RSA) large exponent')\n");
299 break;
300 case 'f':
301 c = (unsigned char)(isc_commandline_argument[0]);
302 if (toupper(c) == 'K')
303 kskflag = DNS_KEYFLAG_KSK;
304 else if (toupper(c) == 'R')
305 revflag = DNS_KEYFLAG_REVOKE;
306 else
307 fatal("unknown flag '%s'",
308 isc_commandline_argument);
309 break;
310 case 'g':
311 generator = strtol(isc_commandline_argument,
312 &endp, 10);
313 if (*endp != '\0' || generator <= 0)
314 fatal("-g requires a positive number");
315 break;
316 case 'K':
317 directory = isc_commandline_argument;
318 ret = try_dir(directory);
319 if (ret != ISC_R_SUCCESS)
320 fatal("cannot open directory %s: %s",
321 directory, isc_result_totext(ret));
322 break;
323 case 'L':
324 ttl = strtottl(isc_commandline_argument);
325 setttl = true;
326 break;
327 case 'n':
328 nametype = isc_commandline_argument;
329 break;
330 case 'm':
331 break;
332 case 'p':
333 protocol = strtol(isc_commandline_argument, &endp, 10);
334 if (*endp != '\0' || protocol < 0 || protocol > 255)
335 fatal("-p must be followed by a number "
336 "[0..255]");
337 break;
338 case 'q':
339 quiet = true;
340 break;
341 case 'r':
342 fatal("The -r option has been deprecated.\n"
343 "System random data is always used.\n");
344 break;
345 case 's':
346 signatory = strtol(isc_commandline_argument,
347 &endp, 10);
348 if (*endp != '\0' || signatory < 0 || signatory > 15)
349 fatal("-s must be followed by a number "
350 "[0..15]");
351 break;
352 case 'T':
353 if (strcasecmp(isc_commandline_argument, "KEY") == 0)
354 options |= DST_TYPE_KEY;
355 else if (strcasecmp(isc_commandline_argument,
356 "DNSKEY") == 0)
357 /* default behavior */
358 ;
359 else
360 fatal("unknown type '%s'",
361 isc_commandline_argument);
362 break;
363 case 't':
364 type = isc_commandline_argument;
365 break;
366 case 'v':
367 endp = NULL;
368 verbose = strtol(isc_commandline_argument, &endp, 0);
369 if (*endp != '\0')
370 fatal("-v must be followed by a number");
371 break;
372 case 'z':
373 /* already the default */
374 break;
375 case 'G':
376 genonly = true;
377 break;
378 case 'P':
379 /* -Psync ? */
380 if (isoptarg("sync", argv, usage)) {
381 if (setsyncadd)
382 fatal("-P sync specified more than "
383 "once");
384
385 syncadd = strtotime(isc_commandline_argument,
386 now, now, &setsyncadd);
387 break;
388 }
389 (void)isoptarg("dnskey", argv, usage);
390 if (setpub || unsetpub)
391 fatal("-P specified more than once");
392
393 publish = strtotime(isc_commandline_argument,
394 now, now, &setpub);
395 unsetpub = !setpub;
396 break;
397 case 'A':
398 if (setact || unsetact)
399 fatal("-A specified more than once");
400
401 activate = strtotime(isc_commandline_argument,
402 now, now, &setact);
403 unsetact = !setact;
404 break;
405 case 'R':
406 if (setrev || unsetrev)
407 fatal("-R specified more than once");
408
409 revokekey = strtotime(isc_commandline_argument,
410 now, now, &setrev);
411 unsetrev = !setrev;
412 break;
413 case 'I':
414 if (setinact || unsetinact)
415 fatal("-I specified more than once");
416
417 inactive = strtotime(isc_commandline_argument,
418 now, now, &setinact);
419 unsetinact = !setinact;
420 break;
421 case 'D':
422 /* -Dsync ? */
423 if (isoptarg("sync", argv, usage)) {
424 if (setsyncdel)
425 fatal("-D sync specified more than "
426 "once");
427
428 syncdel = strtotime(isc_commandline_argument,
429 now, now, &setsyncdel);
430 break;
431 }
432 (void)isoptarg("dnskey", argv, usage);
433 if (setdel || unsetdel)
434 fatal("-D specified more than once");
435
436 deltime = strtotime(isc_commandline_argument,
437 now, now, &setdel);
438 unsetdel = !setdel;
439 break;
440 case 'S':
441 predecessor = isc_commandline_argument;
442 break;
443 case 'i':
444 prepub = strtottl(isc_commandline_argument);
445 break;
446 case 'F':
447 /* Reserved for FIPS mode */
448 /* FALLTHROUGH */
449 case '?':
450 if (isc_commandline_option != '?')
451 fprintf(stderr, "%s: invalid argument -%c\n",
452 program, isc_commandline_option);
453 /* FALLTHROUGH */
454 case 'h':
455 /* Does not return. */
456 usage();
457
458 case 'V':
459 /* Does not return. */
460 version(program);
461
462 default:
463 fprintf(stderr, "%s: unhandled option -%c\n",
464 program, isc_commandline_option);
465 exit(1);
466 }
467 }
468
469 if (!isatty(0))
470 quiet = true;
471
472 ret = dst_lib_init(mctx, engine);
473 if (ret != ISC_R_SUCCESS)
474 fatal("could not initialize dst: %s",
475 isc_result_totext(ret));
476
477 setup_logging(mctx, &log);
478
479 if (predecessor == NULL) {
480 if (prepub == -1)
481 prepub = 0;
482
483 if (argc < isc_commandline_index + 1)
484 fatal("the key name was not specified");
485 if (argc > isc_commandline_index + 1)
486 fatal("extraneous arguments");
487
488 name = dns_fixedname_initname(&fname);
489 isc_buffer_init(&buf, argv[isc_commandline_index],
490 strlen(argv[isc_commandline_index]));
491 isc_buffer_add(&buf, strlen(argv[isc_commandline_index]));
492 ret = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
493 if (ret != ISC_R_SUCCESS)
494 fatal("invalid key name %s: %s",
495 argv[isc_commandline_index],
496 isc_result_totext(ret));
497
498 if (algname == NULL) {
499 fatal("no algorithm specified");
500 }
501
502 r.base = algname;
503 r.length = strlen(algname);
504 ret = dns_secalg_fromtext(&alg, &r);
505 if (ret != ISC_R_SUCCESS) {
506 fatal("unknown algorithm %s", algname);
507 }
508 if (alg == DST_ALG_DH) {
509 options |= DST_TYPE_KEY;
510 }
511
512 if (!dst_algorithm_supported(alg)) {
513 fatal("unsupported algorithm: %d", alg);
514 }
515
516 if (use_nsec3) {
517 switch (alg) {
518 case DST_ALG_RSASHA1:
519 alg = DST_ALG_NSEC3RSASHA1;
520 break;
521 case DST_ALG_NSEC3RSASHA1:
522 case DST_ALG_RSASHA256:
523 case DST_ALG_RSASHA512:
524 case DST_ALG_ECDSA256:
525 case DST_ALG_ECDSA384:
526 case DST_ALG_ED25519:
527 case DST_ALG_ED448:
528 break;
529 default:
530 fatal("%s is incompatible with NSEC3; "
531 "do not use the -3 option", algname);
532 }
533 }
534
535 if (type != NULL && (options & DST_TYPE_KEY) != 0) {
536 if (strcasecmp(type, "NOAUTH") == 0) {
537 flags |= DNS_KEYTYPE_NOAUTH;
538 } else if (strcasecmp(type, "NOCONF") == 0) {
539 flags |= DNS_KEYTYPE_NOCONF;
540 } else if (strcasecmp(type, "NOAUTHCONF") == 0) {
541 flags |= (DNS_KEYTYPE_NOAUTH |
542 DNS_KEYTYPE_NOCONF);
543 if (size < 0)
544 size = 0;
545 } else if (strcasecmp(type, "AUTHCONF") == 0) {
546 /* nothing */;
547 } else {
548 fatal("invalid type %s", type);
549 }
550 }
551
552 if (size < 0) {
553 switch (alg) {
554 case DST_ALG_RSASHA1:
555 case DST_ALG_NSEC3RSASHA1:
556 case DST_ALG_RSASHA256:
557 case DST_ALG_RSASHA512:
558 if ((kskflag & DNS_KEYFLAG_KSK) != 0) {
559 size = 2048;
560 } else {
561 size = 1024;
562 }
563 if (verbose > 0) {
564 fprintf(stderr, "key size not "
565 "specified; defaulting"
566 " to %d\n", size);
567 }
568 break;
569 case DST_ALG_ECDSA256:
570 case DST_ALG_ECDSA384:
571 case DST_ALG_ED25519:
572 case DST_ALG_ED448:
573 break;
574 default:
575 fatal("key size not specified (-b option)");
576 }
577 }
578
579 if (!oldstyle && prepub > 0) {
580 if (setpub && setact && (activate - prepub) < publish)
581 fatal("Activation and publication dates "
582 "are closer together than the\n\t"
583 "prepublication interval.");
584
585 if (!setpub && !setact) {
586 setpub = setact = true;
587 publish = now;
588 activate = now + prepub;
589 } else if (setpub && !setact) {
590 setact = true;
591 activate = publish + prepub;
592 } else if (setact && !setpub) {
593 setpub = true;
594 publish = activate - prepub;
595 }
596
597 if ((activate - prepub) < now)
598 fatal("Time until activation is shorter "
599 "than the\n\tprepublication interval.");
600 }
601 } else {
602 char keystr[DST_KEY_FORMATSIZE];
603 isc_stdtime_t when;
604 int major, minor;
605
606 if (prepub == -1)
607 prepub = (30 * 86400);
608
609 if (algname != NULL)
610 fatal("-S and -a cannot be used together");
611 if (size >= 0)
612 fatal("-S and -b cannot be used together");
613 if (nametype != NULL)
614 fatal("-S and -n cannot be used together");
615 if (type != NULL)
616 fatal("-S and -t cannot be used together");
617 if (setpub || unsetpub)
618 fatal("-S and -P cannot be used together");
619 if (setact || unsetact)
620 fatal("-S and -A cannot be used together");
621 if (use_nsec3)
622 fatal("-S and -3 cannot be used together");
623 if (oldstyle)
624 fatal("-S and -C cannot be used together");
625 if (genonly)
626 fatal("-S and -G cannot be used together");
627
628 ret = dst_key_fromnamedfile(predecessor, directory,
629 DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
630 mctx, &prevkey);
631 if (ret != ISC_R_SUCCESS)
632 fatal("Invalid keyfile %s: %s",
633 predecessor, isc_result_totext(ret));
634 if (!dst_key_isprivate(prevkey))
635 fatal("%s is not a private key", predecessor);
636
637 name = dst_key_name(prevkey);
638 alg = dst_key_alg(prevkey);
639 size = dst_key_size(prevkey);
640 flags = dst_key_flags(prevkey);
641
642 dst_key_format(prevkey, keystr, sizeof(keystr));
643 dst_key_getprivateformat(prevkey, &major, &minor);
644 if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION)
645 fatal("Key %s has incompatible format version %d.%d\n\t"
646 "It is not possible to generate a successor key.",
647 keystr, major, minor);
648
649 ret = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &when);
650 if (ret != ISC_R_SUCCESS)
651 fatal("Key %s has no activation date.\n\t"
652 "You must use dnssec-settime -A to set one "
653 "before generating a successor.", keystr);
654
655 ret = dst_key_gettime(prevkey, DST_TIME_INACTIVE, &activate);
656 if (ret != ISC_R_SUCCESS)
657 fatal("Key %s has no inactivation date.\n\t"
658 "You must use dnssec-settime -I to set one "
659 "before generating a successor.", keystr);
660
661 publish = activate - prepub;
662 if (publish < now)
663 fatal("Key %s becomes inactive\n\t"
664 "sooner than the prepublication period "
665 "for the new key ends.\n\t"
666 "Either change the inactivation date with "
667 "dnssec-settime -I,\n\t"
668 "or use the -i option to set a shorter "
669 "prepublication interval.", keystr);
670
671 ret = dst_key_gettime(prevkey, DST_TIME_DELETE, &when);
672 if (ret != ISC_R_SUCCESS)
673 fprintf(stderr, "%s: WARNING: Key %s has no removal "
674 "date;\n\t it will remain in the zone "
675 "indefinitely after rollover.\n\t "
676 "You can use dnssec-settime -D to "
677 "change this.\n", program, keystr);
678
679 setpub = setact = true;
680 }
681
682 switch (alg) {
683 case DNS_KEYALG_RSASHA1:
684 case DNS_KEYALG_NSEC3RSASHA1:
685 case DNS_KEYALG_RSASHA256:
686 if (size != 0 && (size < 1024 || size > MAX_RSA))
687 fatal("RSA key size %d out of range", size);
688 break;
689 case DNS_KEYALG_RSASHA512:
690 if (size != 0 && (size < 1024 || size > MAX_RSA))
691 fatal("RSA key size %d out of range", size);
692 break;
693 case DNS_KEYALG_DH:
694 if (size != 0 && (size < 128 || size > 4096))
695 fatal("DH key size %d out of range", size);
696 break;
697 case DST_ALG_ECDSA256:
698 size = 256;
699 break;
700 case DST_ALG_ECDSA384:
701 size = 384;
702 break;
703 case DST_ALG_ED25519:
704 size = 256;
705 break;
706 case DST_ALG_ED448:
707 size = 456;
708 break;
709 }
710
711 if (alg != DNS_KEYALG_DH && generator != 0)
712 fatal("specified DH generator for a non-DH key");
713
714 if (nametype == NULL) {
715 if ((options & DST_TYPE_KEY) != 0) /* KEY */
716 fatal("no nametype specified");
717 flags |= DNS_KEYOWNER_ZONE; /* DNSKEY */
718 } else if (strcasecmp(nametype, "zone") == 0)
719 flags |= DNS_KEYOWNER_ZONE;
720 else if ((options & DST_TYPE_KEY) != 0) { /* KEY */
721 if (strcasecmp(nametype, "host") == 0 ||
722 strcasecmp(nametype, "entity") == 0)
723 flags |= DNS_KEYOWNER_ENTITY;
724 else if (strcasecmp(nametype, "user") == 0)
725 flags |= DNS_KEYOWNER_USER;
726 else
727 fatal("invalid KEY nametype %s", nametype);
728 } else if (strcasecmp(nametype, "other") != 0) /* DNSKEY */
729 fatal("invalid DNSKEY nametype %s", nametype);
730
731 rdclass = strtoclass(classname);
732
733 if (directory == NULL)
734 directory = ".";
735
736 if ((options & DST_TYPE_KEY) != 0) /* KEY */
737 flags |= signatory;
738 else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */
739 flags |= kskflag;
740 flags |= revflag;
741 }
742
743 if (protocol == -1)
744 protocol = DNS_KEYPROTO_DNSSEC;
745 else if ((options & DST_TYPE_KEY) == 0 &&
746 protocol != DNS_KEYPROTO_DNSSEC)
747 fatal("invalid DNSKEY protocol: %d", protocol);
748
749 if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
750 if (size > 0)
751 fatal("specified null key with non-zero size");
752 if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0)
753 fatal("specified null key with signing authority");
754 }
755
756 if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE &&
757 alg == DNS_KEYALG_DH)
758 {
759 fatal("a key with algorithm '%s' cannot be a zone key",
760 algname);
761 }
762
763 switch(alg) {
764 case DNS_KEYALG_RSASHA1:
765 case DNS_KEYALG_NSEC3RSASHA1:
766 case DNS_KEYALG_RSASHA256:
767 case DNS_KEYALG_RSASHA512:
768 show_progress = true;
769 break;
770
771 case DNS_KEYALG_DH:
772 param = generator;
773 break;
774
775 case DST_ALG_ECDSA256:
776 case DST_ALG_ECDSA384:
777 case DST_ALG_ED25519:
778 case DST_ALG_ED448:
779 show_progress = true;
780 break;
781 }
782
783 if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY)
784 null_key = true;
785
786 isc_buffer_init(&buf, filename, sizeof(filename) - 1);
787
788 do {
789 conflict = false;
790
791 if (!quiet && show_progress) {
792 fprintf(stderr, "Generating key pair.");
793 ret = dst_key_generate(name, alg, size, param, flags,
794 protocol, rdclass, mctx, &key,
795 &progress);
796 putc('\n', stderr);
797 fflush(stderr);
798 } else {
799 ret = dst_key_generate(name, alg, size, param, flags,
800 protocol, rdclass, mctx, &key,
801 NULL);
802 }
803
804 if (ret != ISC_R_SUCCESS) {
805 char namestr[DNS_NAME_FORMATSIZE];
806 char algstr[DNS_SECALG_FORMATSIZE];
807 dns_name_format(name, namestr, sizeof(namestr));
808 dns_secalg_format(alg, algstr, sizeof(algstr));
809 fatal("failed to generate key %s/%s: %s\n",
810 namestr, algstr, isc_result_totext(ret));
811 /* NOTREACHED */
812 exit(-1);
813 }
814
815 dst_key_setbits(key, dbits);
816
817 /*
818 * Set key timing metadata (unless using -C)
819 *
820 * Creation date is always set to "now".
821 *
822 * For a new key without an explicit predecessor, publish
823 * and activation dates are set to "now" by default, but
824 * can both be overridden.
825 *
826 * For a successor key, activation is set to match the
827 * predecessor's inactivation date. Publish is set to 30
828 * days earlier than that (XXX: this should be configurable).
829 * If either of the resulting dates are in the past, that's
830 * an error; the inactivation date of the predecessor key
831 * must be updated before a successor key can be created.
832 */
833 if (!oldstyle) {
834 dst_key_settime(key, DST_TIME_CREATED, now);
835
836 if (genonly && (setpub || setact))
837 fatal("cannot use -G together with "
838 "-P or -A options");
839
840 if (setpub)
841 dst_key_settime(key, DST_TIME_PUBLISH, publish);
842 else if (setact && !unsetpub)
843 dst_key_settime(key, DST_TIME_PUBLISH,
844 activate - prepub);
845 else if (!genonly && !unsetpub)
846 dst_key_settime(key, DST_TIME_PUBLISH, now);
847
848 if (setact)
849 dst_key_settime(key, DST_TIME_ACTIVATE,
850 activate);
851 else if (!genonly && !unsetact)
852 dst_key_settime(key, DST_TIME_ACTIVATE, now);
853
854 if (setrev) {
855 if (kskflag == 0)
856 fprintf(stderr, "%s: warning: Key is "
857 "not flagged as a KSK, but -R "
858 "was used. Revoking a ZSK is "
859 "legal, but undefined.\n",
860 program);
861 dst_key_settime(key, DST_TIME_REVOKE, revokekey);
862 }
863
864 if (setinact)
865 dst_key_settime(key, DST_TIME_INACTIVE,
866 inactive);
867
868 if (setdel) {
869 if (setinact && deltime < inactive)
870 fprintf(stderr, "%s: warning: Key is "
871 "scheduled to be deleted "
872 "before it is scheduled to be "
873 "made inactive.\n",
874 program);
875 dst_key_settime(key, DST_TIME_DELETE, deltime);
876 }
877
878 if (setsyncadd)
879 dst_key_settime(key, DST_TIME_SYNCPUBLISH,
880 syncadd);
881
882 if (setsyncdel)
883 dst_key_settime(key, DST_TIME_SYNCDELETE,
884 syncdel);
885
886 } else {
887 if (setpub || setact || setrev || setinact ||
888 setdel || unsetpub || unsetact ||
889 unsetrev || unsetinact || unsetdel || genonly ||
890 setsyncadd || setsyncdel)
891 fatal("cannot use -C together with "
892 "-P, -A, -R, -I, -D, or -G options");
893 /*
894 * Compatibility mode: Private-key-format
895 * should be set to 1.2.
896 */
897 dst_key_setprivateformat(key, 1, 2);
898 }
899
900 /* Set the default key TTL */
901 if (setttl)
902 dst_key_setttl(key, ttl);
903
904 /*
905 * Do not overwrite an existing key, or create a key
906 * if there is a risk of ID collision due to this key
907 * or another key being revoked.
908 */
909 if (key_collision(key, name, directory, mctx, NULL)) {
910 conflict = true;
911 if (null_key) {
912 dst_key_free(&key);
913 break;
914 }
915
916 if (verbose > 0) {
917 isc_buffer_clear(&buf);
918 ret = dst_key_buildfilename(key, 0,
919 directory, &buf);
920 if (ret == ISC_R_SUCCESS)
921 fprintf(stderr,
922 "%s: %s already exists, or "
923 "might collide with another "
924 "key upon revokation. "
925 "Generating a new key\n",
926 program, filename);
927 }
928
929 dst_key_free(&key);
930 }
931 } while (conflict == true);
932
933 if (conflict)
934 fatal("cannot generate a null key due to possible key ID "
935 "collision");
936
937 ret = dst_key_tofile(key, options, directory);
938 if (ret != ISC_R_SUCCESS) {
939 char keystr[DST_KEY_FORMATSIZE];
940 dst_key_format(key, keystr, sizeof(keystr));
941 fatal("failed to write key %s: %s\n", keystr,
942 isc_result_totext(ret));
943 }
944
945 isc_buffer_clear(&buf);
946 ret = dst_key_buildfilename(key, 0, NULL, &buf);
947 if (ret != ISC_R_SUCCESS)
948 fatal("dst_key_buildfilename returned: %s\n",
949 isc_result_totext(ret));
950 printf("%s\n", filename);
951 dst_key_free(&key);
952 if (prevkey != NULL)
953 dst_key_free(&prevkey);
954
955 cleanup_logging(&log);
956 dst_lib_destroy();
957 dns_name_destroy();
958 if (verbose > 10)
959 isc_mem_stats(mctx, stdout);
960 isc_mem_destroy(&mctx);
961
962 if (freeit != NULL)
963 free(freeit);
964
965 return (0);
966 }