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