1*4ac1c27eSchristos /*	$NetBSD: dnssec-keygen.c,v 1.10 2023/01/25 21:43:23 christos Exp $	*/
2e2b1b9c0Schristos 
3e2b1b9c0Schristos /*
4e2b1b9c0Schristos  * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5e2b1b9c0Schristos  *
6c0b5d9fbSchristos  * SPDX-License-Identifier: MPL-2.0
7c0b5d9fbSchristos  *
8e2b1b9c0Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
9e2b1b9c0Schristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
1073584a28Schristos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11e2b1b9c0Schristos  *
12e2b1b9c0Schristos  * See the COPYRIGHT file distributed with this work for additional
13e2b1b9c0Schristos  * information regarding copyright ownership.
14e2b1b9c0Schristos  *
15e2b1b9c0Schristos  * Portions Copyright (C) Network Associates, Inc.
16e2b1b9c0Schristos  *
17e2b1b9c0Schristos  * Permission to use, copy, modify, and/or distribute this software for any
18e2b1b9c0Schristos  * purpose with or without fee is hereby granted, provided that the above
19e2b1b9c0Schristos  * copyright notice and this permission notice appear in all copies.
20e2b1b9c0Schristos  *
21e2b1b9c0Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
22e2b1b9c0Schristos  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
23e2b1b9c0Schristos  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
24e2b1b9c0Schristos  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
25e2b1b9c0Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
26e2b1b9c0Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
27e2b1b9c0Schristos  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28e2b1b9c0Schristos  */
29e2b1b9c0Schristos 
30e2b1b9c0Schristos /*! \file */
31e2b1b9c0Schristos 
32e2b1b9c0Schristos #include <ctype.h>
33f2e20987Schristos #include <inttypes.h>
34f2e20987Schristos #include <stdbool.h>
35e2b1b9c0Schristos #include <stdlib.h>
36e2b1b9c0Schristos #include <unistd.h>
37e2b1b9c0Schristos 
38e2b1b9c0Schristos #include <isc/buffer.h>
39e2b1b9c0Schristos #include <isc/commandline.h>
40e2b1b9c0Schristos #include <isc/mem.h>
41e2b1b9c0Schristos #include <isc/print.h>
42e2b1b9c0Schristos #include <isc/region.h>
43e2b1b9c0Schristos #include <isc/string.h>
44e2b1b9c0Schristos #include <isc/util.h>
45e2b1b9c0Schristos 
46e2b1b9c0Schristos #include <pk11/site.h>
47e2b1b9c0Schristos 
48e2b1b9c0Schristos #include <dns/dnssec.h>
49e2b1b9c0Schristos #include <dns/fixedname.h>
509742fdb4Schristos #include <dns/kasp.h>
51e2b1b9c0Schristos #include <dns/keyvalues.h>
52e2b1b9c0Schristos #include <dns/log.h>
53e2b1b9c0Schristos #include <dns/name.h>
54e2b1b9c0Schristos #include <dns/rdataclass.h>
55e2b1b9c0Schristos #include <dns/result.h>
56e2b1b9c0Schristos #include <dns/secalg.h>
57e2b1b9c0Schristos 
58e2b1b9c0Schristos #include <dst/dst.h>
59e2b1b9c0Schristos 
609742fdb4Schristos #include <isccfg/cfg.h>
619742fdb4Schristos #include <isccfg/grammar.h>
629742fdb4Schristos #include <isccfg/kaspconf.h>
639742fdb4Schristos #include <isccfg/namedconf.h>
649742fdb4Schristos 
65f2e20987Schristos #if USE_PKCS11
66e2b1b9c0Schristos #include <pk11/result.h>
679742fdb4Schristos #endif /* if USE_PKCS11 */
68e2b1b9c0Schristos 
69e2b1b9c0Schristos #include "dnssectool.h"
70e2b1b9c0Schristos 
71e2b1b9c0Schristos #define MAX_RSA 4096 /* should be long enough... */
72e2b1b9c0Schristos 
73e2b1b9c0Schristos const char *program = "dnssec-keygen";
749742fdb4Schristos 
759742fdb4Schristos isc_log_t *lctx = NULL;
76e2b1b9c0Schristos 
77e2b1b9c0Schristos ISC_PLATFORM_NORETURN_PRE static void
78e2b1b9c0Schristos usage(void) ISC_PLATFORM_NORETURN_POST;
79e2b1b9c0Schristos 
809742fdb4Schristos static void
819742fdb4Schristos progress(int p);
829742fdb4Schristos 
839742fdb4Schristos struct keygen_ctx {
849742fdb4Schristos 	const char *predecessor;
859742fdb4Schristos 	const char *policy;
869742fdb4Schristos 	const char *configfile;
879742fdb4Schristos 	const char *directory;
889742fdb4Schristos 	char *algname;
899742fdb4Schristos 	char *nametype;
909742fdb4Schristos 	char *type;
919742fdb4Schristos 	int generator;
929742fdb4Schristos 	int protocol;
939742fdb4Schristos 	int size;
949742fdb4Schristos 	int signatory;
959742fdb4Schristos 	dns_rdataclass_t rdclass;
969742fdb4Schristos 	int options;
979742fdb4Schristos 	int dbits;
989742fdb4Schristos 	dns_ttl_t ttl;
999742fdb4Schristos 	uint16_t kskflag;
1009742fdb4Schristos 	uint16_t revflag;
1019742fdb4Schristos 	dns_secalg_t alg;
1029742fdb4Schristos 	/* timing data */
1039742fdb4Schristos 	int prepub;
1049742fdb4Schristos 	isc_stdtime_t now;
1059742fdb4Schristos 	isc_stdtime_t publish;
1069742fdb4Schristos 	isc_stdtime_t activate;
1079742fdb4Schristos 	isc_stdtime_t inactive;
1089742fdb4Schristos 	isc_stdtime_t revokekey;
1099742fdb4Schristos 	isc_stdtime_t deltime;
1109742fdb4Schristos 	isc_stdtime_t syncadd;
1119742fdb4Schristos 	isc_stdtime_t syncdel;
1129742fdb4Schristos 	bool setpub;
1139742fdb4Schristos 	bool setact;
1149742fdb4Schristos 	bool setinact;
1159742fdb4Schristos 	bool setrev;
1169742fdb4Schristos 	bool setdel;
1179742fdb4Schristos 	bool setsyncadd;
1189742fdb4Schristos 	bool setsyncdel;
1199742fdb4Schristos 	bool unsetpub;
1209742fdb4Schristos 	bool unsetact;
1219742fdb4Schristos 	bool unsetinact;
1229742fdb4Schristos 	bool unsetrev;
1239742fdb4Schristos 	bool unsetdel;
1249742fdb4Schristos 	/* how to generate the key */
1259742fdb4Schristos 	bool setttl;
1269742fdb4Schristos 	bool use_nsec3;
1279742fdb4Schristos 	bool genonly;
1289742fdb4Schristos 	bool showprogress;
1299742fdb4Schristos 	bool quiet;
1309742fdb4Schristos 	bool oldstyle;
1319742fdb4Schristos 	/* state */
1329742fdb4Schristos 	time_t lifetime;
1339742fdb4Schristos 	bool ksk;
1349742fdb4Schristos 	bool zsk;
1359742fdb4Schristos };
1369742fdb4Schristos 
1379742fdb4Schristos typedef struct keygen_ctx keygen_ctx_t;
138e2b1b9c0Schristos 
139e2b1b9c0Schristos static void
usage(void)140e2b1b9c0Schristos usage(void) {
141e2b1b9c0Schristos 	fprintf(stderr, "Usage:\n");
142e2b1b9c0Schristos 	fprintf(stderr, "    %s [options] name\n\n", program);
143e2b1b9c0Schristos 	fprintf(stderr, "Version: %s\n", VERSION);
144e2b1b9c0Schristos 	fprintf(stderr, "    name: owner of the key\n");
145e2b1b9c0Schristos 	fprintf(stderr, "Options:\n");
146e2b1b9c0Schristos 	fprintf(stderr, "    -K <directory>: write keys into directory\n");
1479742fdb4Schristos 	fprintf(stderr, "    -k <policy>: generate keys for dnssec-policy\n");
1489742fdb4Schristos 	fprintf(stderr, "    -l <file>: configuration file with dnssec-policy "
1499742fdb4Schristos 			"statement\n");
150e2b1b9c0Schristos 	fprintf(stderr, "    -a <algorithm>:\n");
151cc2e102bSchristos 	fprintf(stderr, "        RSASHA1 | NSEC3RSASHA1 |\n");
152f2e20987Schristos 	fprintf(stderr, "        RSASHA256 | RSASHA512 |\n");
153e2b1b9c0Schristos 	fprintf(stderr, "        ECDSAP256SHA256 | ECDSAP384SHA384 |\n");
154f2e20987Schristos 	fprintf(stderr, "        ED25519 | ED448 | DH\n");
155e2b1b9c0Schristos 	fprintf(stderr, "    -3: use NSEC3-capable algorithm\n");
156e2b1b9c0Schristos 	fprintf(stderr, "    -b <key size in bits>:\n");
157e2b1b9c0Schristos 	fprintf(stderr, "        RSASHA1:\t[1024..%d]\n", MAX_RSA);
158e2b1b9c0Schristos 	fprintf(stderr, "        NSEC3RSASHA1:\t[1024..%d]\n", MAX_RSA);
159e2b1b9c0Schristos 	fprintf(stderr, "        RSASHA256:\t[1024..%d]\n", MAX_RSA);
160e2b1b9c0Schristos 	fprintf(stderr, "        RSASHA512:\t[1024..%d]\n", MAX_RSA);
161e2b1b9c0Schristos 	fprintf(stderr, "        DH:\t\t[128..4096]\n");
162e2b1b9c0Schristos 	fprintf(stderr, "        ECDSAP256SHA256:\tignored\n");
163e2b1b9c0Schristos 	fprintf(stderr, "        ECDSAP384SHA384:\tignored\n");
164e2b1b9c0Schristos 	fprintf(stderr, "        ED25519:\tignored\n");
165e2b1b9c0Schristos 	fprintf(stderr, "        ED448:\tignored\n");
166e2b1b9c0Schristos 	fprintf(stderr, "        (key size defaults are set according to\n"
167e2b1b9c0Schristos 			"        algorithm and usage (ZSK or KSK)\n");
168e2b1b9c0Schristos 	fprintf(stderr, "    -n <nametype>: ZONE | HOST | ENTITY | "
169e2b1b9c0Schristos 			"USER | OTHER\n");
170e2b1b9c0Schristos 	fprintf(stderr, "        (DNSKEY generation defaults to ZONE)\n");
171e2b1b9c0Schristos 	fprintf(stderr, "    -c <class>: (default: IN)\n");
172e2b1b9c0Schristos 	fprintf(stderr, "    -d <digest bits> (0 => max, default)\n");
173e2b1b9c0Schristos 	fprintf(stderr, "    -E <engine>:\n");
174f2e20987Schristos #if USE_PKCS11
1759742fdb4Schristos 	fprintf(stderr,
1769742fdb4Schristos 		"        path to PKCS#11 provider library "
1779742fdb4Schristos 		"(default is %s)\n",
1789742fdb4Schristos 		PK11_LIB_LOCATION);
1799742fdb4Schristos #else  /* if USE_PKCS11 */
180e2b1b9c0Schristos 	fprintf(stderr, "        name of an OpenSSL engine to use\n");
1819742fdb4Schristos #endif /* if USE_PKCS11 */
182e2b1b9c0Schristos 	fprintf(stderr, "    -f <keyflag>: KSK | REVOKE\n");
183e2b1b9c0Schristos 	fprintf(stderr, "    -g <generator>: use specified generator "
184e2b1b9c0Schristos 			"(DH only)\n");
185e2b1b9c0Schristos 	fprintf(stderr, "    -L <ttl>: default key TTL\n");
186e2b1b9c0Schristos 	fprintf(stderr, "    -p <protocol>: (default: 3 [dnssec])\n");
187e2b1b9c0Schristos 	fprintf(stderr, "    -s <strength>: strength value this key signs DNS "
188e2b1b9c0Schristos 			"records with (default: 0)\n");
189e2b1b9c0Schristos 	fprintf(stderr, "    -T <rrtype>: DNSKEY | KEY (default: DNSKEY; "
190e2b1b9c0Schristos 			"use KEY for SIG(0))\n");
191e2b1b9c0Schristos 	fprintf(stderr, "    -t <type>: "
192e2b1b9c0Schristos 			"AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF "
193e2b1b9c0Schristos 			"(default: AUTHCONF)\n");
194e2b1b9c0Schristos 	fprintf(stderr, "    -h: print usage and exit\n");
195e2b1b9c0Schristos 	fprintf(stderr, "    -m <memory debugging mode>:\n");
196e2b1b9c0Schristos 	fprintf(stderr, "       usage | trace | record | size | mctx\n");
197e2b1b9c0Schristos 	fprintf(stderr, "    -v <level>: set verbosity level (0 - 10)\n");
198e2b1b9c0Schristos 	fprintf(stderr, "    -V: print version information\n");
199e2b1b9c0Schristos 	fprintf(stderr, "Timing options:\n");
200e2b1b9c0Schristos 	fprintf(stderr, "    -P date/[+-]offset/none: set key publication date "
201e2b1b9c0Schristos 			"(default: now)\n");
202e2b1b9c0Schristos 	fprintf(stderr, "    -P sync date/[+-]offset/none: set CDS and CDNSKEY "
203e2b1b9c0Schristos 			"publication date\n");
204e2b1b9c0Schristos 	fprintf(stderr, "    -A date/[+-]offset/none: set key activation date "
205e2b1b9c0Schristos 			"(default: now)\n");
206e2b1b9c0Schristos 	fprintf(stderr, "    -R date/[+-]offset/none: set key "
207e2b1b9c0Schristos 			"revocation date\n");
208e2b1b9c0Schristos 	fprintf(stderr, "    -I date/[+-]offset/none: set key "
209e2b1b9c0Schristos 			"inactivation date\n");
210e2b1b9c0Schristos 	fprintf(stderr, "    -D date/[+-]offset/none: set key deletion date\n");
211e2b1b9c0Schristos 	fprintf(stderr, "    -D sync date/[+-]offset/none: set CDS and CDNSKEY "
212e2b1b9c0Schristos 			"deletion date\n");
213e2b1b9c0Schristos 
214e2b1b9c0Schristos 	fprintf(stderr, "    -G: generate key only; do not set -P or -A\n");
215e2b1b9c0Schristos 	fprintf(stderr, "    -C: generate a backward-compatible key, omitting "
216e2b1b9c0Schristos 			"all dates\n");
217e2b1b9c0Schristos 	fprintf(stderr, "    -S <key>: generate a successor to an existing "
218e2b1b9c0Schristos 			"key\n");
219e2b1b9c0Schristos 	fprintf(stderr, "    -i <interval>: prepublication interval for "
220e2b1b9c0Schristos 			"successor key "
221e2b1b9c0Schristos 			"(default: 30 days)\n");
222e2b1b9c0Schristos 	fprintf(stderr, "Output:\n");
223e2b1b9c0Schristos 	fprintf(stderr, "     K<name>+<alg>+<id>.key, "
224e2b1b9c0Schristos 			"K<name>+<alg>+<id>.private\n");
225e2b1b9c0Schristos 
226e2b1b9c0Schristos 	exit(-1);
227e2b1b9c0Schristos }
228e2b1b9c0Schristos 
229e2b1b9c0Schristos static void
progress(int p)2309742fdb4Schristos progress(int p) {
231e2b1b9c0Schristos 	char c = '*';
232e2b1b9c0Schristos 
233e2b1b9c0Schristos 	switch (p) {
234e2b1b9c0Schristos 	case 0:
235e2b1b9c0Schristos 		c = '.';
236e2b1b9c0Schristos 		break;
237e2b1b9c0Schristos 	case 1:
238e2b1b9c0Schristos 		c = '+';
239e2b1b9c0Schristos 		break;
240e2b1b9c0Schristos 	case 2:
241e2b1b9c0Schristos 		c = '*';
242e2b1b9c0Schristos 		break;
243e2b1b9c0Schristos 	case 3:
244e2b1b9c0Schristos 		c = ' ';
245e2b1b9c0Schristos 		break;
246e2b1b9c0Schristos 	default:
247e2b1b9c0Schristos 		break;
248e2b1b9c0Schristos 	}
249e2b1b9c0Schristos 	(void)putc(c, stderr);
250e2b1b9c0Schristos 	(void)fflush(stderr);
251e2b1b9c0Schristos }
252e2b1b9c0Schristos 
2539742fdb4Schristos static void
kasp_from_conf(cfg_obj_t * config,isc_mem_t * mctx,const char * name,dns_kasp_t ** kaspp)2549742fdb4Schristos kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, const char *name,
2559742fdb4Schristos 	       dns_kasp_t **kaspp) {
2569742fdb4Schristos 	const cfg_listelt_t *element;
2579742fdb4Schristos 	const cfg_obj_t *kasps = NULL;
2589742fdb4Schristos 	dns_kasp_t *kasp = NULL, *kasp_next;
2599742fdb4Schristos 	isc_result_t result = ISC_R_NOTFOUND;
2609742fdb4Schristos 	dns_kasplist_t kasplist;
261e2b1b9c0Schristos 
2629742fdb4Schristos 	ISC_LIST_INIT(kasplist);
263e2b1b9c0Schristos 
2649742fdb4Schristos 	(void)cfg_map_get(config, "dnssec-policy", &kasps);
2659742fdb4Schristos 	for (element = cfg_list_first(kasps); element != NULL;
2669742fdb4Schristos 	     element = cfg_list_next(element))
2679742fdb4Schristos 	{
2689742fdb4Schristos 		cfg_obj_t *kconfig = cfg_listelt_value(element);
2699742fdb4Schristos 		kasp = NULL;
2709742fdb4Schristos 		if (strcmp(cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
271*4ac1c27eSchristos 			   name) != 0)
272*4ac1c27eSchristos 		{
2739742fdb4Schristos 			continue;
2749742fdb4Schristos 		}
275e2b1b9c0Schristos 
27673584a28Schristos 		result = cfg_kasp_fromconfig(kconfig, NULL, mctx, lctx,
27773584a28Schristos 					     &kasplist, &kasp);
2789742fdb4Schristos 		if (result != ISC_R_SUCCESS) {
2799742fdb4Schristos 			fatal("failed to configure dnssec-policy '%s': %s",
2809742fdb4Schristos 			      cfg_obj_asstring(cfg_tuple_get(kconfig, "name")),
2819742fdb4Schristos 			      isc_result_totext(result));
2829742fdb4Schristos 		}
2839742fdb4Schristos 		INSIST(kasp != NULL);
2849742fdb4Schristos 		dns_kasp_freeze(kasp);
2859742fdb4Schristos 		break;
2869742fdb4Schristos 	}
2879742fdb4Schristos 
2889742fdb4Schristos 	*kaspp = kasp;
289e2b1b9c0Schristos 
290e2b1b9c0Schristos 	/*
29173584a28Schristos 	 * Cleanup kasp list.
292e2b1b9c0Schristos 	 */
2939742fdb4Schristos 	for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
2949742fdb4Schristos 		kasp_next = ISC_LIST_NEXT(kasp, link);
2959742fdb4Schristos 		ISC_LIST_UNLINK(kasplist, kasp, link);
2969742fdb4Schristos 		dns_kasp_detach(&kasp);
297e2b1b9c0Schristos 	}
298e2b1b9c0Schristos }
299e2b1b9c0Schristos 
3009742fdb4Schristos static void
keygen(keygen_ctx_t * ctx,isc_mem_t * mctx,int argc,char ** argv)3019742fdb4Schristos keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
3029742fdb4Schristos 	char filename[255];
3039742fdb4Schristos 	char algstr[DNS_SECALG_FORMATSIZE];
3049742fdb4Schristos 	uint16_t flags = 0;
3059742fdb4Schristos 	int param = 0;
3069742fdb4Schristos 	bool null_key = false;
3079742fdb4Schristos 	bool conflict = false;
3089742fdb4Schristos 	bool show_progress = false;
3099742fdb4Schristos 	isc_buffer_t buf;
3109742fdb4Schristos 	dns_name_t *name;
3119742fdb4Schristos 	dns_fixedname_t fname;
3129742fdb4Schristos 	isc_result_t ret;
3139742fdb4Schristos 	dst_key_t *key = NULL;
3149742fdb4Schristos 	dst_key_t *prevkey = NULL;
315e2b1b9c0Schristos 
3169742fdb4Schristos 	UNUSED(argc);
317e2b1b9c0Schristos 
3189742fdb4Schristos 	dns_secalg_format(ctx->alg, algstr, sizeof(algstr));
319e2b1b9c0Schristos 
3209742fdb4Schristos 	if (ctx->predecessor == NULL) {
3219742fdb4Schristos 		if (ctx->prepub == -1) {
3229742fdb4Schristos 			ctx->prepub = 0;
3239742fdb4Schristos 		}
324e2b1b9c0Schristos 
325e2b1b9c0Schristos 		name = dns_fixedname_initname(&fname);
326e2b1b9c0Schristos 		isc_buffer_init(&buf, argv[isc_commandline_index],
327e2b1b9c0Schristos 				strlen(argv[isc_commandline_index]));
328e2b1b9c0Schristos 		isc_buffer_add(&buf, strlen(argv[isc_commandline_index]));
329e2b1b9c0Schristos 		ret = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
3309742fdb4Schristos 		if (ret != ISC_R_SUCCESS) {
331e2b1b9c0Schristos 			fatal("invalid key name %s: %s",
332e2b1b9c0Schristos 			      argv[isc_commandline_index],
333e2b1b9c0Schristos 			      isc_result_totext(ret));
334e2b1b9c0Schristos 		}
335e2b1b9c0Schristos 
3369742fdb4Schristos 		if (!dst_algorithm_supported(ctx->alg)) {
3379742fdb4Schristos 			fatal("unsupported algorithm: %s", algstr);
338e2b1b9c0Schristos 		}
339e2b1b9c0Schristos 
3409742fdb4Schristos 		if (ctx->alg == DST_ALG_DH) {
3419742fdb4Schristos 			ctx->options |= DST_TYPE_KEY;
342f2e20987Schristos 		}
343e2b1b9c0Schristos 
3449742fdb4Schristos 		if (ctx->use_nsec3) {
3459742fdb4Schristos 			switch (ctx->alg) {
346e2b1b9c0Schristos 			case DST_ALG_RSASHA1:
3479742fdb4Schristos 				ctx->alg = DST_ALG_NSEC3RSASHA1;
348e2b1b9c0Schristos 				break;
349e2b1b9c0Schristos 			case DST_ALG_NSEC3RSASHA1:
350e2b1b9c0Schristos 			case DST_ALG_RSASHA256:
351e2b1b9c0Schristos 			case DST_ALG_RSASHA512:
352e2b1b9c0Schristos 			case DST_ALG_ECDSA256:
353e2b1b9c0Schristos 			case DST_ALG_ECDSA384:
354e2b1b9c0Schristos 			case DST_ALG_ED25519:
355e2b1b9c0Schristos 			case DST_ALG_ED448:
356e2b1b9c0Schristos 				break;
357e2b1b9c0Schristos 			default:
3589742fdb4Schristos 				fatal("algorithm %s is incompatible with NSEC3"
3599742fdb4Schristos 				      ", do not use the -3 option",
3609742fdb4Schristos 				      algstr);
361e2b1b9c0Schristos 			}
362e2b1b9c0Schristos 		}
363e2b1b9c0Schristos 
3649742fdb4Schristos 		if (ctx->type != NULL && (ctx->options & DST_TYPE_KEY) != 0) {
3659742fdb4Schristos 			if (strcasecmp(ctx->type, "NOAUTH") == 0) {
366e2b1b9c0Schristos 				flags |= DNS_KEYTYPE_NOAUTH;
3679742fdb4Schristos 			} else if (strcasecmp(ctx->type, "NOCONF") == 0) {
368e2b1b9c0Schristos 				flags |= DNS_KEYTYPE_NOCONF;
3699742fdb4Schristos 			} else if (strcasecmp(ctx->type, "NOAUTHCONF") == 0) {
370e2b1b9c0Schristos 				flags |= (DNS_KEYTYPE_NOAUTH |
371e2b1b9c0Schristos 					  DNS_KEYTYPE_NOCONF);
3729742fdb4Schristos 				if (ctx->size < 0) {
3739742fdb4Schristos 					ctx->size = 0;
3749742fdb4Schristos 				}
3759742fdb4Schristos 			} else if (strcasecmp(ctx->type, "AUTHCONF") == 0) {
3769742fdb4Schristos 				/* nothing */
377f2e20987Schristos 			} else {
3789742fdb4Schristos 				fatal("invalid type %s", ctx->type);
379e2b1b9c0Schristos 			}
380f2e20987Schristos 		}
381e2b1b9c0Schristos 
3829742fdb4Schristos 		if (ctx->size < 0) {
3839742fdb4Schristos 			switch (ctx->alg) {
384e2b1b9c0Schristos 			case DST_ALG_RSASHA1:
385e2b1b9c0Schristos 			case DST_ALG_NSEC3RSASHA1:
386e2b1b9c0Schristos 			case DST_ALG_RSASHA256:
387e2b1b9c0Schristos 			case DST_ALG_RSASHA512:
3889742fdb4Schristos 				ctx->size = 2048;
389e2b1b9c0Schristos 				if (verbose > 0) {
3909742fdb4Schristos 					fprintf(stderr,
3919742fdb4Schristos 						"key size not "
392e2b1b9c0Schristos 						"specified; defaulting"
3939742fdb4Schristos 						" to %d\n",
3949742fdb4Schristos 						ctx->size);
395e2b1b9c0Schristos 				}
396e2b1b9c0Schristos 				break;
397e2b1b9c0Schristos 			case DST_ALG_ECDSA256:
398e2b1b9c0Schristos 			case DST_ALG_ECDSA384:
399e2b1b9c0Schristos 			case DST_ALG_ED25519:
400e2b1b9c0Schristos 			case DST_ALG_ED448:
401e2b1b9c0Schristos 				break;
402e2b1b9c0Schristos 			default:
403e2b1b9c0Schristos 				fatal("key size not specified (-b option)");
404e2b1b9c0Schristos 			}
405e2b1b9c0Schristos 		}
406e2b1b9c0Schristos 
4079742fdb4Schristos 		if (!ctx->oldstyle && ctx->prepub > 0) {
4089742fdb4Schristos 			if (ctx->setpub && ctx->setact &&
409*4ac1c27eSchristos 			    (ctx->activate - ctx->prepub) < ctx->publish)
410*4ac1c27eSchristos 			{
411e2b1b9c0Schristos 				fatal("Activation and publication dates "
412e2b1b9c0Schristos 				      "are closer together than the\n\t"
413e2b1b9c0Schristos 				      "prepublication interval.");
414e2b1b9c0Schristos 			}
415e2b1b9c0Schristos 
4169742fdb4Schristos 			if (!ctx->setpub && !ctx->setact) {
4179742fdb4Schristos 				ctx->setpub = ctx->setact = true;
4189742fdb4Schristos 				ctx->publish = ctx->now;
4199742fdb4Schristos 				ctx->activate = ctx->now + ctx->prepub;
4209742fdb4Schristos 			} else if (ctx->setpub && !ctx->setact) {
4219742fdb4Schristos 				ctx->setact = true;
4229742fdb4Schristos 				ctx->activate = ctx->publish + ctx->prepub;
4239742fdb4Schristos 			} else if (ctx->setact && !ctx->setpub) {
4249742fdb4Schristos 				ctx->setpub = true;
4259742fdb4Schristos 				ctx->publish = ctx->activate - ctx->prepub;
4269742fdb4Schristos 			}
4279742fdb4Schristos 
4289742fdb4Schristos 			if ((ctx->activate - ctx->prepub) < ctx->now) {
429e2b1b9c0Schristos 				fatal("Time until activation is shorter "
430e2b1b9c0Schristos 				      "than the\n\tprepublication interval.");
431e2b1b9c0Schristos 			}
4329742fdb4Schristos 		}
433e2b1b9c0Schristos 	} else {
434e2b1b9c0Schristos 		char keystr[DST_KEY_FORMATSIZE];
435e2b1b9c0Schristos 		isc_stdtime_t when;
436e2b1b9c0Schristos 		int major, minor;
437e2b1b9c0Schristos 
4389742fdb4Schristos 		if (ctx->prepub == -1) {
4399742fdb4Schristos 			ctx->prepub = (30 * 86400);
4409742fdb4Schristos 		}
441e2b1b9c0Schristos 
4429742fdb4Schristos 		if (ctx->alg != 0) {
443e2b1b9c0Schristos 			fatal("-S and -a cannot be used together");
4449742fdb4Schristos 		}
4459742fdb4Schristos 		if (ctx->size >= 0) {
446e2b1b9c0Schristos 			fatal("-S and -b cannot be used together");
4479742fdb4Schristos 		}
4489742fdb4Schristos 		if (ctx->nametype != NULL) {
449e2b1b9c0Schristos 			fatal("-S and -n cannot be used together");
4509742fdb4Schristos 		}
4519742fdb4Schristos 		if (ctx->type != NULL) {
452e2b1b9c0Schristos 			fatal("-S and -t cannot be used together");
4539742fdb4Schristos 		}
4549742fdb4Schristos 		if (ctx->setpub || ctx->unsetpub) {
455e2b1b9c0Schristos 			fatal("-S and -P cannot be used together");
4569742fdb4Schristos 		}
4579742fdb4Schristos 		if (ctx->setact || ctx->unsetact) {
458e2b1b9c0Schristos 			fatal("-S and -A cannot be used together");
4599742fdb4Schristos 		}
4609742fdb4Schristos 		if (ctx->use_nsec3) {
461e2b1b9c0Schristos 			fatal("-S and -3 cannot be used together");
4629742fdb4Schristos 		}
4639742fdb4Schristos 		if (ctx->oldstyle) {
464e2b1b9c0Schristos 			fatal("-S and -C cannot be used together");
4659742fdb4Schristos 		}
4669742fdb4Schristos 		if (ctx->genonly) {
467e2b1b9c0Schristos 			fatal("-S and -G cannot be used together");
4689742fdb4Schristos 		}
469e2b1b9c0Schristos 
4709742fdb4Schristos 		ret = dst_key_fromnamedfile(
4719742fdb4Schristos 			ctx->predecessor, ctx->directory,
4729742fdb4Schristos 			(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE),
473e2b1b9c0Schristos 			mctx, &prevkey);
4749742fdb4Schristos 		if (ret != ISC_R_SUCCESS) {
4759742fdb4Schristos 			fatal("Invalid keyfile %s: %s", ctx->predecessor,
4769742fdb4Schristos 			      isc_result_totext(ret));
4779742fdb4Schristos 		}
4789742fdb4Schristos 		if (!dst_key_isprivate(prevkey)) {
4799742fdb4Schristos 			fatal("%s is not a private key", ctx->predecessor);
4809742fdb4Schristos 		}
481e2b1b9c0Schristos 
482e2b1b9c0Schristos 		name = dst_key_name(prevkey);
4839742fdb4Schristos 		ctx->alg = dst_key_alg(prevkey);
4849742fdb4Schristos 		ctx->size = dst_key_size(prevkey);
485e2b1b9c0Schristos 		flags = dst_key_flags(prevkey);
486e2b1b9c0Schristos 
487e2b1b9c0Schristos 		dst_key_format(prevkey, keystr, sizeof(keystr));
488e2b1b9c0Schristos 		dst_key_getprivateformat(prevkey, &major, &minor);
4899742fdb4Schristos 		if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) {
490e2b1b9c0Schristos 			fatal("Key %s has incompatible format version %d.%d\n\t"
491e2b1b9c0Schristos 			      "It is not possible to generate a successor key.",
492e2b1b9c0Schristos 			      keystr, major, minor);
4939742fdb4Schristos 		}
494e2b1b9c0Schristos 
495e2b1b9c0Schristos 		ret = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &when);
4969742fdb4Schristos 		if (ret != ISC_R_SUCCESS) {
497e2b1b9c0Schristos 			fatal("Key %s has no activation date.\n\t"
498e2b1b9c0Schristos 			      "You must use dnssec-settime -A to set one "
4999742fdb4Schristos 			      "before generating a successor.",
5009742fdb4Schristos 			      keystr);
5019742fdb4Schristos 		}
502e2b1b9c0Schristos 
5039742fdb4Schristos 		ret = dst_key_gettime(prevkey, DST_TIME_INACTIVE,
5049742fdb4Schristos 				      &ctx->activate);
5059742fdb4Schristos 		if (ret != ISC_R_SUCCESS) {
506e2b1b9c0Schristos 			fatal("Key %s has no inactivation date.\n\t"
507e2b1b9c0Schristos 			      "You must use dnssec-settime -I to set one "
5089742fdb4Schristos 			      "before generating a successor.",
5099742fdb4Schristos 			      keystr);
5109742fdb4Schristos 		}
511e2b1b9c0Schristos 
5129742fdb4Schristos 		ctx->publish = ctx->activate - ctx->prepub;
5139742fdb4Schristos 		if (ctx->publish < ctx->now) {
514e2b1b9c0Schristos 			fatal("Key %s becomes inactive\n\t"
515e2b1b9c0Schristos 			      "sooner than the prepublication period "
516e2b1b9c0Schristos 			      "for the new key ends.\n\t"
517e2b1b9c0Schristos 			      "Either change the inactivation date with "
518e2b1b9c0Schristos 			      "dnssec-settime -I,\n\t"
519e2b1b9c0Schristos 			      "or use the -i option to set a shorter "
5209742fdb4Schristos 			      "prepublication interval.",
5219742fdb4Schristos 			      keystr);
5229742fdb4Schristos 		}
523e2b1b9c0Schristos 
524e2b1b9c0Schristos 		ret = dst_key_gettime(prevkey, DST_TIME_DELETE, &when);
5259742fdb4Schristos 		if (ret != ISC_R_SUCCESS) {
5269742fdb4Schristos 			fprintf(stderr,
5279742fdb4Schristos 				"%s: WARNING: Key %s has no removal "
528e2b1b9c0Schristos 				"date;\n\t it will remain in the zone "
529e2b1b9c0Schristos 				"indefinitely after rollover.\n\t "
530e2b1b9c0Schristos 				"You can use dnssec-settime -D to "
5319742fdb4Schristos 				"change this.\n",
5329742fdb4Schristos 				program, keystr);
533e2b1b9c0Schristos 		}
534e2b1b9c0Schristos 
5359742fdb4Schristos 		ctx->setpub = ctx->setact = true;
5369742fdb4Schristos 	}
5379742fdb4Schristos 
5389742fdb4Schristos 	switch (ctx->alg) {
539e2b1b9c0Schristos 	case DNS_KEYALG_RSASHA1:
540e2b1b9c0Schristos 	case DNS_KEYALG_NSEC3RSASHA1:
541e2b1b9c0Schristos 	case DNS_KEYALG_RSASHA256:
5429742fdb4Schristos 		if (ctx->size != 0 && (ctx->size < 1024 || ctx->size > MAX_RSA))
5439742fdb4Schristos 		{
5449742fdb4Schristos 			fatal("RSA key size %d out of range", ctx->size);
5459742fdb4Schristos 		}
546e2b1b9c0Schristos 		break;
547e2b1b9c0Schristos 	case DNS_KEYALG_RSASHA512:
5489742fdb4Schristos 		if (ctx->size != 0 && (ctx->size < 1024 || ctx->size > MAX_RSA))
5499742fdb4Schristos 		{
5509742fdb4Schristos 			fatal("RSA key size %d out of range", ctx->size);
5519742fdb4Schristos 		}
552e2b1b9c0Schristos 		break;
553e2b1b9c0Schristos 	case DNS_KEYALG_DH:
5549742fdb4Schristos 		if (ctx->size != 0 && (ctx->size < 128 || ctx->size > 4096)) {
5559742fdb4Schristos 			fatal("DH key size %d out of range", ctx->size);
5569742fdb4Schristos 		}
557e2b1b9c0Schristos 		break;
558e2b1b9c0Schristos 	case DST_ALG_ECDSA256:
5599742fdb4Schristos 		ctx->size = 256;
560e2b1b9c0Schristos 		break;
561e2b1b9c0Schristos 	case DST_ALG_ECDSA384:
5629742fdb4Schristos 		ctx->size = 384;
563e2b1b9c0Schristos 		break;
564e2b1b9c0Schristos 	case DST_ALG_ED25519:
5659742fdb4Schristos 		ctx->size = 256;
566e2b1b9c0Schristos 		break;
567e2b1b9c0Schristos 	case DST_ALG_ED448:
5689742fdb4Schristos 		ctx->size = 456;
569e2b1b9c0Schristos 		break;
570e2b1b9c0Schristos 	}
571e2b1b9c0Schristos 
5729742fdb4Schristos 	if (ctx->alg != DNS_KEYALG_DH && ctx->generator != 0) {
573e2b1b9c0Schristos 		fatal("specified DH generator for a non-DH key");
574e2b1b9c0Schristos 	}
575e2b1b9c0Schristos 
5769742fdb4Schristos 	if (ctx->nametype == NULL) {
5779742fdb4Schristos 		if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */
5789742fdb4Schristos 			fatal("no nametype specified");
5799742fdb4Schristos 		}
5809742fdb4Schristos 		flags |= DNS_KEYOWNER_ZONE; /* DNSKEY */
5819742fdb4Schristos 	} else if (strcasecmp(ctx->nametype, "zone") == 0) {
5829742fdb4Schristos 		flags |= DNS_KEYOWNER_ZONE;
5839742fdb4Schristos 	} else if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */
5849742fdb4Schristos 		if (strcasecmp(ctx->nametype, "host") == 0 ||
5859742fdb4Schristos 		    strcasecmp(ctx->nametype, "entity") == 0)
5869742fdb4Schristos 		{
5879742fdb4Schristos 			flags |= DNS_KEYOWNER_ENTITY;
5889742fdb4Schristos 		} else if (strcasecmp(ctx->nametype, "user") == 0) {
5899742fdb4Schristos 			flags |= DNS_KEYOWNER_USER;
5909742fdb4Schristos 		} else {
5919742fdb4Schristos 			fatal("invalid KEY nametype %s", ctx->nametype);
5929742fdb4Schristos 		}
5939742fdb4Schristos 	} else if (strcasecmp(ctx->nametype, "other") != 0) { /* DNSKEY */
5949742fdb4Schristos 		fatal("invalid DNSKEY nametype %s", ctx->nametype);
5959742fdb4Schristos 	}
5969742fdb4Schristos 
5979742fdb4Schristos 	if (ctx->directory == NULL) {
5989742fdb4Schristos 		ctx->directory = ".";
5999742fdb4Schristos 	}
6009742fdb4Schristos 
6019742fdb4Schristos 	if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */
6029742fdb4Schristos 		flags |= ctx->signatory;
6039742fdb4Schristos 	} else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */
6049742fdb4Schristos 		flags |= ctx->kskflag;
6059742fdb4Schristos 		flags |= ctx->revflag;
6069742fdb4Schristos 	}
6079742fdb4Schristos 
6089742fdb4Schristos 	if (ctx->protocol == -1) {
6099742fdb4Schristos 		ctx->protocol = DNS_KEYPROTO_DNSSEC;
6109742fdb4Schristos 	} else if ((ctx->options & DST_TYPE_KEY) == 0 &&
6119742fdb4Schristos 		   ctx->protocol != DNS_KEYPROTO_DNSSEC)
6129742fdb4Schristos 	{
6139742fdb4Schristos 		fatal("invalid DNSKEY protocol: %d", ctx->protocol);
6149742fdb4Schristos 	}
615e2b1b9c0Schristos 
616e2b1b9c0Schristos 	if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
6179742fdb4Schristos 		if (ctx->size > 0) {
618e2b1b9c0Schristos 			fatal("specified null key with non-zero size");
6199742fdb4Schristos 		}
6209742fdb4Schristos 		if ((flags & DNS_KEYFLAG_SIGNATORYMASK) != 0) {
621e2b1b9c0Schristos 			fatal("specified null key with signing authority");
622e2b1b9c0Schristos 		}
6239742fdb4Schristos 	}
624e2b1b9c0Schristos 
625e2b1b9c0Schristos 	if ((flags & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE &&
6269742fdb4Schristos 	    ctx->alg == DNS_KEYALG_DH)
627f2e20987Schristos 	{
6289742fdb4Schristos 		fatal("a key with algorithm %s cannot be a zone key", algstr);
629f2e20987Schristos 	}
630e2b1b9c0Schristos 
6319742fdb4Schristos 	switch (ctx->alg) {
632e2b1b9c0Schristos 	case DNS_KEYALG_RSASHA1:
633e2b1b9c0Schristos 	case DNS_KEYALG_NSEC3RSASHA1:
634e2b1b9c0Schristos 	case DNS_KEYALG_RSASHA256:
635e2b1b9c0Schristos 	case DNS_KEYALG_RSASHA512:
636f2e20987Schristos 		show_progress = true;
637e2b1b9c0Schristos 		break;
638e2b1b9c0Schristos 
639e2b1b9c0Schristos 	case DNS_KEYALG_DH:
6409742fdb4Schristos 		param = ctx->generator;
641e2b1b9c0Schristos 		break;
642e2b1b9c0Schristos 
643e2b1b9c0Schristos 	case DST_ALG_ECDSA256:
644e2b1b9c0Schristos 	case DST_ALG_ECDSA384:
645e2b1b9c0Schristos 	case DST_ALG_ED25519:
646e2b1b9c0Schristos 	case DST_ALG_ED448:
647f2e20987Schristos 		show_progress = true;
648e2b1b9c0Schristos 		break;
649e2b1b9c0Schristos 	}
650e2b1b9c0Schristos 
6519742fdb4Schristos 	if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
652f2e20987Schristos 		null_key = true;
6539742fdb4Schristos 	}
654e2b1b9c0Schristos 
655e2b1b9c0Schristos 	isc_buffer_init(&buf, filename, sizeof(filename) - 1);
656e2b1b9c0Schristos 
657e2b1b9c0Schristos 	do {
658f2e20987Schristos 		conflict = false;
659e2b1b9c0Schristos 
6609742fdb4Schristos 		if (!ctx->quiet && show_progress) {
661e2b1b9c0Schristos 			fprintf(stderr, "Generating key pair.");
6629742fdb4Schristos 			ret = dst_key_generate(name, ctx->alg, ctx->size, param,
6639742fdb4Schristos 					       flags, ctx->protocol,
6649742fdb4Schristos 					       ctx->rdclass, mctx, &key,
665e2b1b9c0Schristos 					       &progress);
666e2b1b9c0Schristos 			putc('\n', stderr);
667e2b1b9c0Schristos 			fflush(stderr);
668e2b1b9c0Schristos 		} else {
6699742fdb4Schristos 			ret = dst_key_generate(name, ctx->alg, ctx->size, param,
6709742fdb4Schristos 					       flags, ctx->protocol,
6719742fdb4Schristos 					       ctx->rdclass, mctx, &key, NULL);
672e2b1b9c0Schristos 		}
673e2b1b9c0Schristos 
674e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS) {
675e2b1b9c0Schristos 			char namestr[DNS_NAME_FORMATSIZE];
676e2b1b9c0Schristos 			dns_name_format(name, namestr, sizeof(namestr));
6779742fdb4Schristos 			fatal("failed to generate key %s/%s: %s\n", namestr,
6789742fdb4Schristos 			      algstr, isc_result_totext(ret));
679e2b1b9c0Schristos 		}
680e2b1b9c0Schristos 
6819742fdb4Schristos 		dst_key_setbits(key, ctx->dbits);
682e2b1b9c0Schristos 
683e2b1b9c0Schristos 		/*
684e2b1b9c0Schristos 		 * Set key timing metadata (unless using -C)
685e2b1b9c0Schristos 		 *
686e2b1b9c0Schristos 		 * Creation date is always set to "now".
687e2b1b9c0Schristos 		 *
688e2b1b9c0Schristos 		 * For a new key without an explicit predecessor, publish
689e2b1b9c0Schristos 		 * and activation dates are set to "now" by default, but
690e2b1b9c0Schristos 		 * can both be overridden.
691e2b1b9c0Schristos 		 *
692e2b1b9c0Schristos 		 * For a successor key, activation is set to match the
693e2b1b9c0Schristos 		 * predecessor's inactivation date.  Publish is set to 30
694e2b1b9c0Schristos 		 * days earlier than that (XXX: this should be configurable).
695e2b1b9c0Schristos 		 * If either of the resulting dates are in the past, that's
696e2b1b9c0Schristos 		 * an error; the inactivation date of the predecessor key
697e2b1b9c0Schristos 		 * must be updated before a successor key can be created.
698e2b1b9c0Schristos 		 */
6999742fdb4Schristos 		if (!ctx->oldstyle) {
7009742fdb4Schristos 			dst_key_settime(key, DST_TIME_CREATED, ctx->now);
701e2b1b9c0Schristos 
7029742fdb4Schristos 			if (ctx->genonly && (ctx->setpub || ctx->setact)) {
703e2b1b9c0Schristos 				fatal("cannot use -G together with "
704e2b1b9c0Schristos 				      "-P or -A options");
7059742fdb4Schristos 			}
706e2b1b9c0Schristos 
7079742fdb4Schristos 			if (ctx->setpub) {
708e2b1b9c0Schristos 				dst_key_settime(key, DST_TIME_PUBLISH,
7099742fdb4Schristos 						ctx->publish);
7109742fdb4Schristos 			} else if (ctx->setact && !ctx->unsetpub) {
7119742fdb4Schristos 				dst_key_settime(key, DST_TIME_PUBLISH,
7129742fdb4Schristos 						ctx->activate - ctx->prepub);
7139742fdb4Schristos 			} else if (!ctx->genonly && !ctx->unsetpub) {
7149742fdb4Schristos 				dst_key_settime(key, DST_TIME_PUBLISH,
7159742fdb4Schristos 						ctx->now);
7169742fdb4Schristos 			}
717e2b1b9c0Schristos 
7189742fdb4Schristos 			if (ctx->setact) {
719e2b1b9c0Schristos 				dst_key_settime(key, DST_TIME_ACTIVATE,
7209742fdb4Schristos 						ctx->activate);
7219742fdb4Schristos 			} else if (!ctx->genonly && !ctx->unsetact) {
7229742fdb4Schristos 				dst_key_settime(key, DST_TIME_ACTIVATE,
7239742fdb4Schristos 						ctx->now);
7249742fdb4Schristos 			}
725e2b1b9c0Schristos 
7269742fdb4Schristos 			if (ctx->setrev) {
7279742fdb4Schristos 				if (ctx->kskflag == 0) {
7289742fdb4Schristos 					fprintf(stderr,
7299742fdb4Schristos 						"%s: warning: Key is "
730e2b1b9c0Schristos 						"not flagged as a KSK, but -R "
731e2b1b9c0Schristos 						"was used. Revoking a ZSK is "
732e2b1b9c0Schristos 						"legal, but undefined.\n",
733e2b1b9c0Schristos 						program);
7349742fdb4Schristos 				}
7359742fdb4Schristos 				dst_key_settime(key, DST_TIME_REVOKE,
7369742fdb4Schristos 						ctx->revokekey);
737e2b1b9c0Schristos 			}
738e2b1b9c0Schristos 
7399742fdb4Schristos 			if (ctx->setinact) {
740e2b1b9c0Schristos 				dst_key_settime(key, DST_TIME_INACTIVE,
7419742fdb4Schristos 						ctx->inactive);
7429742fdb4Schristos 			}
743e2b1b9c0Schristos 
7449742fdb4Schristos 			if (ctx->setdel) {
7459742fdb4Schristos 				if (ctx->setinact &&
746*4ac1c27eSchristos 				    ctx->deltime < ctx->inactive)
747*4ac1c27eSchristos 				{
7489742fdb4Schristos 					fprintf(stderr,
7499742fdb4Schristos 						"%s: warning: Key is "
750e2b1b9c0Schristos 						"scheduled to be deleted "
751e2b1b9c0Schristos 						"before it is scheduled to be "
752e2b1b9c0Schristos 						"made inactive.\n",
753e2b1b9c0Schristos 						program);
7549742fdb4Schristos 				}
7559742fdb4Schristos 				dst_key_settime(key, DST_TIME_DELETE,
7569742fdb4Schristos 						ctx->deltime);
757e2b1b9c0Schristos 			}
758e2b1b9c0Schristos 
7599742fdb4Schristos 			if (ctx->setsyncadd) {
760e2b1b9c0Schristos 				dst_key_settime(key, DST_TIME_SYNCPUBLISH,
7619742fdb4Schristos 						ctx->syncadd);
7629742fdb4Schristos 			}
763e2b1b9c0Schristos 
7649742fdb4Schristos 			if (ctx->setsyncdel) {
765e2b1b9c0Schristos 				dst_key_settime(key, DST_TIME_SYNCDELETE,
7669742fdb4Schristos 						ctx->syncdel);
7679742fdb4Schristos 			}
768e2b1b9c0Schristos 		} else {
7699742fdb4Schristos 			if (ctx->setpub || ctx->setact || ctx->setrev ||
7709742fdb4Schristos 			    ctx->setinact || ctx->setdel || ctx->unsetpub ||
7719742fdb4Schristos 			    ctx->unsetact || ctx->unsetrev || ctx->unsetinact ||
7729742fdb4Schristos 			    ctx->unsetdel || ctx->genonly || ctx->setsyncadd ||
7739742fdb4Schristos 			    ctx->setsyncdel)
7749742fdb4Schristos 			{
775e2b1b9c0Schristos 				fatal("cannot use -C together with "
776e2b1b9c0Schristos 				      "-P, -A, -R, -I, -D, or -G options");
7779742fdb4Schristos 			}
778e2b1b9c0Schristos 			/*
779e2b1b9c0Schristos 			 * Compatibility mode: Private-key-format
780e2b1b9c0Schristos 			 * should be set to 1.2.
781e2b1b9c0Schristos 			 */
782e2b1b9c0Schristos 			dst_key_setprivateformat(key, 1, 2);
783e2b1b9c0Schristos 		}
784e2b1b9c0Schristos 
785e2b1b9c0Schristos 		/* Set the default key TTL */
7869742fdb4Schristos 		if (ctx->setttl) {
7879742fdb4Schristos 			dst_key_setttl(key, ctx->ttl);
7889742fdb4Schristos 		}
7899742fdb4Schristos 
7909742fdb4Schristos 		/* Set dnssec-policy related metadata */
79173584a28Schristos 		if (ctx->policy != NULL) {
7929742fdb4Schristos 			dst_key_setnum(key, DST_NUM_LIFETIME, ctx->lifetime);
7939742fdb4Schristos 			dst_key_setbool(key, DST_BOOL_KSK, ctx->ksk);
7949742fdb4Schristos 			dst_key_setbool(key, DST_BOOL_ZSK, ctx->zsk);
7959742fdb4Schristos 		}
796e2b1b9c0Schristos 
797e2b1b9c0Schristos 		/*
798e2b1b9c0Schristos 		 * Do not overwrite an existing key, or create a key
799e2b1b9c0Schristos 		 * if there is a risk of ID collision due to this key
800e2b1b9c0Schristos 		 * or another key being revoked.
801e2b1b9c0Schristos 		 */
8029742fdb4Schristos 		if (key_collision(key, name, ctx->directory, mctx, NULL)) {
803f2e20987Schristos 			conflict = true;
804e2b1b9c0Schristos 			if (null_key) {
805e2b1b9c0Schristos 				dst_key_free(&key);
806e2b1b9c0Schristos 				break;
807e2b1b9c0Schristos 			}
808e2b1b9c0Schristos 
809e2b1b9c0Schristos 			if (verbose > 0) {
810e2b1b9c0Schristos 				isc_buffer_clear(&buf);
8119742fdb4Schristos 				ret = dst_key_buildfilename(
8129742fdb4Schristos 					key, 0, ctx->directory, &buf);
8139742fdb4Schristos 				if (ret == ISC_R_SUCCESS) {
814e2b1b9c0Schristos 					fprintf(stderr,
815e2b1b9c0Schristos 						"%s: %s already exists, or "
816e2b1b9c0Schristos 						"might collide with another "
817e2b1b9c0Schristos 						"key upon revokation.  "
818e2b1b9c0Schristos 						"Generating a new key\n",
819e2b1b9c0Schristos 						program, filename);
820e2b1b9c0Schristos 				}
8219742fdb4Schristos 			}
822e2b1b9c0Schristos 
823e2b1b9c0Schristos 			dst_key_free(&key);
824e2b1b9c0Schristos 		}
825803e9293Schristos 	} while (conflict);
826e2b1b9c0Schristos 
8279742fdb4Schristos 	if (conflict) {
828e2b1b9c0Schristos 		fatal("cannot generate a null key due to possible key ID "
829e2b1b9c0Schristos 		      "collision");
8309742fdb4Schristos 	}
831e2b1b9c0Schristos 
8329742fdb4Schristos 	if (ctx->predecessor != NULL && prevkey != NULL) {
8339742fdb4Schristos 		dst_key_setnum(prevkey, DST_NUM_SUCCESSOR, dst_key_id(key));
8349742fdb4Schristos 		dst_key_setnum(key, DST_NUM_PREDECESSOR, dst_key_id(prevkey));
8359742fdb4Schristos 
8369742fdb4Schristos 		ret = dst_key_tofile(prevkey, ctx->options, ctx->directory);
8379742fdb4Schristos 		if (ret != ISC_R_SUCCESS) {
8389742fdb4Schristos 			char keystr[DST_KEY_FORMATSIZE];
8399742fdb4Schristos 			dst_key_format(prevkey, keystr, sizeof(keystr));
8409742fdb4Schristos 			fatal("failed to update predecessor %s: %s\n", keystr,
8419742fdb4Schristos 			      isc_result_totext(ret));
8429742fdb4Schristos 		}
8439742fdb4Schristos 	}
8449742fdb4Schristos 
8459742fdb4Schristos 	ret = dst_key_tofile(key, ctx->options, ctx->directory);
846e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS) {
847e2b1b9c0Schristos 		char keystr[DST_KEY_FORMATSIZE];
848e2b1b9c0Schristos 		dst_key_format(key, keystr, sizeof(keystr));
849e2b1b9c0Schristos 		fatal("failed to write key %s: %s\n", keystr,
850e2b1b9c0Schristos 		      isc_result_totext(ret));
851e2b1b9c0Schristos 	}
852e2b1b9c0Schristos 
853e2b1b9c0Schristos 	isc_buffer_clear(&buf);
854e2b1b9c0Schristos 	ret = dst_key_buildfilename(key, 0, NULL, &buf);
8559742fdb4Schristos 	if (ret != ISC_R_SUCCESS) {
856e2b1b9c0Schristos 		fatal("dst_key_buildfilename returned: %s\n",
857e2b1b9c0Schristos 		      isc_result_totext(ret));
8589742fdb4Schristos 	}
859e2b1b9c0Schristos 	printf("%s\n", filename);
860e2b1b9c0Schristos 
8619742fdb4Schristos 	dst_key_free(&key);
8629742fdb4Schristos 	if (prevkey != NULL) {
8639742fdb4Schristos 		dst_key_free(&prevkey);
8649742fdb4Schristos 	}
8659742fdb4Schristos }
8669742fdb4Schristos 
8679742fdb4Schristos int
main(int argc,char ** argv)8689742fdb4Schristos main(int argc, char **argv) {
8699742fdb4Schristos 	char *algname = NULL, *freeit = NULL;
8709742fdb4Schristos 	char *classname = NULL;
8719742fdb4Schristos 	char *endp;
8729742fdb4Schristos 	isc_mem_t *mctx = NULL;
8739742fdb4Schristos 	isc_result_t ret;
8749742fdb4Schristos 	isc_textregion_t r;
8759742fdb4Schristos 	const char *engine = NULL;
8769742fdb4Schristos 	unsigned char c;
8779742fdb4Schristos 	int ch;
8789742fdb4Schristos 
8799742fdb4Schristos 	keygen_ctx_t ctx = {
8809742fdb4Schristos 		.options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC,
8819742fdb4Schristos 		.prepub = -1,
8829742fdb4Schristos 		.protocol = -1,
8839742fdb4Schristos 		.size = -1,
8849742fdb4Schristos 	};
8859742fdb4Schristos 
8869742fdb4Schristos 	if (argc == 1) {
8879742fdb4Schristos 		usage();
8889742fdb4Schristos 	}
8899742fdb4Schristos 
8909742fdb4Schristos #if USE_PKCS11
8919742fdb4Schristos 	pk11_result_register();
8929742fdb4Schristos #endif /* if USE_PKCS11 */
8939742fdb4Schristos 	dns_result_register();
8949742fdb4Schristos 
8959742fdb4Schristos 	isc_commandline_errprint = false;
8969742fdb4Schristos 
8979742fdb4Schristos 	/*
8989742fdb4Schristos 	 * Process memory debugging argument first.
8999742fdb4Schristos 	 */
9009742fdb4Schristos #define CMDLINE_FLAGS                                           \
9019742fdb4Schristos 	"3A:a:b:Cc:D:d:E:eFf:Gg:hI:i:K:k:L:l:m:n:P:p:qR:r:S:s:" \
9029742fdb4Schristos 	"T:t:v:V"
9039742fdb4Schristos 	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
9049742fdb4Schristos 		switch (ch) {
9059742fdb4Schristos 		case 'm':
9069742fdb4Schristos 			if (strcasecmp(isc_commandline_argument, "record") == 0)
9079742fdb4Schristos 			{
9089742fdb4Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
9099742fdb4Schristos 			}
9109742fdb4Schristos 			if (strcasecmp(isc_commandline_argument, "trace") == 0)
9119742fdb4Schristos 			{
9129742fdb4Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
9139742fdb4Schristos 			}
9149742fdb4Schristos 			if (strcasecmp(isc_commandline_argument, "usage") == 0)
9159742fdb4Schristos 			{
9169742fdb4Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
9179742fdb4Schristos 			}
9189742fdb4Schristos 			if (strcasecmp(isc_commandline_argument, "size") == 0) {
9199742fdb4Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGSIZE;
9209742fdb4Schristos 			}
9219742fdb4Schristos 			if (strcasecmp(isc_commandline_argument, "mctx") == 0) {
9229742fdb4Schristos 				isc_mem_debugging |= ISC_MEM_DEBUGCTX;
9239742fdb4Schristos 			}
9249742fdb4Schristos 			break;
9259742fdb4Schristos 		default:
9269742fdb4Schristos 			break;
9279742fdb4Schristos 		}
9289742fdb4Schristos 	}
9299742fdb4Schristos 	isc_commandline_reset = true;
9309742fdb4Schristos 
9319742fdb4Schristos 	isc_mem_create(&mctx);
9329742fdb4Schristos 	isc_stdtime_get(&ctx.now);
9339742fdb4Schristos 
9349742fdb4Schristos 	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
9359742fdb4Schristos 		switch (ch) {
9369742fdb4Schristos 		case '3':
9379742fdb4Schristos 			ctx.use_nsec3 = true;
9389742fdb4Schristos 			break;
9399742fdb4Schristos 		case 'a':
9409742fdb4Schristos 			algname = isc_commandline_argument;
9419742fdb4Schristos 			break;
9429742fdb4Schristos 		case 'b':
9439742fdb4Schristos 			ctx.size = strtol(isc_commandline_argument, &endp, 10);
9449742fdb4Schristos 			if (*endp != '\0' || ctx.size < 0) {
9459742fdb4Schristos 				fatal("-b requires a non-negative number");
9469742fdb4Schristos 			}
9479742fdb4Schristos 			break;
9489742fdb4Schristos 		case 'C':
9499742fdb4Schristos 			ctx.oldstyle = true;
9509742fdb4Schristos 			break;
9519742fdb4Schristos 		case 'c':
9529742fdb4Schristos 			classname = isc_commandline_argument;
9539742fdb4Schristos 			break;
9549742fdb4Schristos 		case 'd':
9559742fdb4Schristos 			ctx.dbits = strtol(isc_commandline_argument, &endp, 10);
9569742fdb4Schristos 			if (*endp != '\0' || ctx.dbits < 0) {
9579742fdb4Schristos 				fatal("-d requires a non-negative number");
9589742fdb4Schristos 			}
9599742fdb4Schristos 			break;
9609742fdb4Schristos 		case 'E':
9619742fdb4Schristos 			engine = isc_commandline_argument;
9629742fdb4Schristos 			break;
9639742fdb4Schristos 		case 'e':
9649742fdb4Schristos 			fprintf(stderr, "phased-out option -e "
9659742fdb4Schristos 					"(was 'use (RSA) large exponent')\n");
9669742fdb4Schristos 			break;
9679742fdb4Schristos 		case 'f':
9689742fdb4Schristos 			c = (unsigned char)(isc_commandline_argument[0]);
9699742fdb4Schristos 			if (toupper(c) == 'K') {
9709742fdb4Schristos 				ctx.kskflag = DNS_KEYFLAG_KSK;
9719742fdb4Schristos 			} else if (toupper(c) == 'R') {
9729742fdb4Schristos 				ctx.revflag = DNS_KEYFLAG_REVOKE;
9739742fdb4Schristos 			} else {
9749742fdb4Schristos 				fatal("unknown flag '%s'",
9759742fdb4Schristos 				      isc_commandline_argument);
9769742fdb4Schristos 			}
9779742fdb4Schristos 			break;
9789742fdb4Schristos 		case 'g':
9799742fdb4Schristos 			ctx.generator = strtol(isc_commandline_argument, &endp,
9809742fdb4Schristos 					       10);
9819742fdb4Schristos 			if (*endp != '\0' || ctx.generator <= 0) {
9829742fdb4Schristos 				fatal("-g requires a positive number");
9839742fdb4Schristos 			}
9849742fdb4Schristos 			break;
9859742fdb4Schristos 		case 'K':
9869742fdb4Schristos 			ctx.directory = isc_commandline_argument;
9879742fdb4Schristos 			ret = try_dir(ctx.directory);
9889742fdb4Schristos 			if (ret != ISC_R_SUCCESS) {
9899742fdb4Schristos 				fatal("cannot open directory %s: %s",
9909742fdb4Schristos 				      ctx.directory, isc_result_totext(ret));
9919742fdb4Schristos 			}
9929742fdb4Schristos 			break;
9939742fdb4Schristos 		case 'k':
9949742fdb4Schristos 			ctx.policy = isc_commandline_argument;
9959742fdb4Schristos 			break;
9969742fdb4Schristos 		case 'L':
9979742fdb4Schristos 			ctx.ttl = strtottl(isc_commandline_argument);
9989742fdb4Schristos 			ctx.setttl = true;
9999742fdb4Schristos 			break;
10009742fdb4Schristos 		case 'l':
10019742fdb4Schristos 			ctx.configfile = isc_commandline_argument;
10029742fdb4Schristos 			break;
10039742fdb4Schristos 		case 'n':
10049742fdb4Schristos 			ctx.nametype = isc_commandline_argument;
10059742fdb4Schristos 			break;
10069742fdb4Schristos 		case 'm':
10079742fdb4Schristos 			break;
10089742fdb4Schristos 		case 'p':
10099742fdb4Schristos 			ctx.protocol = strtol(isc_commandline_argument, &endp,
10109742fdb4Schristos 					      10);
10119742fdb4Schristos 			if (*endp != '\0' || ctx.protocol < 0 ||
1012*4ac1c27eSchristos 			    ctx.protocol > 255)
1013*4ac1c27eSchristos 			{
10149742fdb4Schristos 				fatal("-p must be followed by a number "
10159742fdb4Schristos 				      "[0..255]");
10169742fdb4Schristos 			}
10179742fdb4Schristos 			break;
10189742fdb4Schristos 		case 'q':
10199742fdb4Schristos 			ctx.quiet = true;
10209742fdb4Schristos 			break;
10219742fdb4Schristos 		case 'r':
10229742fdb4Schristos 			fatal("The -r option has been deprecated.\n"
10239742fdb4Schristos 			      "System random data is always used.\n");
10249742fdb4Schristos 			break;
10259742fdb4Schristos 		case 's':
10269742fdb4Schristos 			ctx.signatory = strtol(isc_commandline_argument, &endp,
10279742fdb4Schristos 					       10);
10289742fdb4Schristos 			if (*endp != '\0' || ctx.signatory < 0 ||
1029*4ac1c27eSchristos 			    ctx.signatory > 15)
1030*4ac1c27eSchristos 			{
10319742fdb4Schristos 				fatal("-s must be followed by a number "
10329742fdb4Schristos 				      "[0..15]");
10339742fdb4Schristos 			}
10349742fdb4Schristos 			break;
10359742fdb4Schristos 		case 'T':
10369742fdb4Schristos 			if (strcasecmp(isc_commandline_argument, "KEY") == 0) {
10379742fdb4Schristos 				ctx.options |= DST_TYPE_KEY;
10389742fdb4Schristos 			} else if (strcasecmp(isc_commandline_argument,
10399742fdb4Schristos 					      "DNSKE"
10409742fdb4Schristos 					      "Y") == 0)
10419742fdb4Schristos 			{
10429742fdb4Schristos 				/* default behavior */
10439742fdb4Schristos 			} else {
10449742fdb4Schristos 				fatal("unknown type '%s'",
10459742fdb4Schristos 				      isc_commandline_argument);
10469742fdb4Schristos 			}
10479742fdb4Schristos 			break;
10489742fdb4Schristos 		case 't':
10499742fdb4Schristos 			ctx.type = isc_commandline_argument;
10509742fdb4Schristos 			break;
10519742fdb4Schristos 		case 'v':
10529742fdb4Schristos 			endp = NULL;
10539742fdb4Schristos 			verbose = strtol(isc_commandline_argument, &endp, 0);
10549742fdb4Schristos 			if (*endp != '\0') {
10559742fdb4Schristos 				fatal("-v must be followed by a number");
10569742fdb4Schristos 			}
10579742fdb4Schristos 			break;
10589742fdb4Schristos 		case 'G':
10599742fdb4Schristos 			ctx.genonly = true;
10609742fdb4Schristos 			break;
10619742fdb4Schristos 		case 'P':
10629742fdb4Schristos 			/* -Psync ? */
10639742fdb4Schristos 			if (isoptarg("sync", argv, usage)) {
10649742fdb4Schristos 				if (ctx.setsyncadd) {
10659742fdb4Schristos 					fatal("-P sync specified more than "
10669742fdb4Schristos 					      "once");
10679742fdb4Schristos 				}
10689742fdb4Schristos 
10699742fdb4Schristos 				ctx.syncadd = strtotime(
10709742fdb4Schristos 					isc_commandline_argument, ctx.now,
10719742fdb4Schristos 					ctx.now, &ctx.setsyncadd);
10729742fdb4Schristos 				break;
10739742fdb4Schristos 			}
10749742fdb4Schristos 			(void)isoptarg("dnskey", argv, usage);
10759742fdb4Schristos 			if (ctx.setpub || ctx.unsetpub) {
10769742fdb4Schristos 				fatal("-P specified more than once");
10779742fdb4Schristos 			}
10789742fdb4Schristos 
10799742fdb4Schristos 			ctx.publish = strtotime(isc_commandline_argument,
10809742fdb4Schristos 						ctx.now, ctx.now, &ctx.setpub);
10819742fdb4Schristos 			ctx.unsetpub = !ctx.setpub;
10829742fdb4Schristos 			break;
10839742fdb4Schristos 		case 'A':
10849742fdb4Schristos 			if (ctx.setact || ctx.unsetact) {
10859742fdb4Schristos 				fatal("-A specified more than once");
10869742fdb4Schristos 			}
10879742fdb4Schristos 
10889742fdb4Schristos 			ctx.activate = strtotime(isc_commandline_argument,
10899742fdb4Schristos 						 ctx.now, ctx.now, &ctx.setact);
10909742fdb4Schristos 			ctx.unsetact = !ctx.setact;
10919742fdb4Schristos 			break;
10929742fdb4Schristos 		case 'R':
10939742fdb4Schristos 			if (ctx.setrev || ctx.unsetrev) {
10949742fdb4Schristos 				fatal("-R specified more than once");
10959742fdb4Schristos 			}
10969742fdb4Schristos 
10979742fdb4Schristos 			ctx.revokekey = strtotime(isc_commandline_argument,
10989742fdb4Schristos 						  ctx.now, ctx.now,
10999742fdb4Schristos 						  &ctx.setrev);
11009742fdb4Schristos 			ctx.unsetrev = !ctx.setrev;
11019742fdb4Schristos 			break;
11029742fdb4Schristos 		case 'I':
11039742fdb4Schristos 			if (ctx.setinact || ctx.unsetinact) {
11049742fdb4Schristos 				fatal("-I specified more than once");
11059742fdb4Schristos 			}
11069742fdb4Schristos 
11079742fdb4Schristos 			ctx.inactive = strtotime(isc_commandline_argument,
11089742fdb4Schristos 						 ctx.now, ctx.now,
11099742fdb4Schristos 						 &ctx.setinact);
11109742fdb4Schristos 			ctx.unsetinact = !ctx.setinact;
11119742fdb4Schristos 			break;
11129742fdb4Schristos 		case 'D':
11139742fdb4Schristos 			/* -Dsync ? */
11149742fdb4Schristos 			if (isoptarg("sync", argv, usage)) {
11159742fdb4Schristos 				if (ctx.setsyncdel) {
11169742fdb4Schristos 					fatal("-D sync specified more than "
11179742fdb4Schristos 					      "once");
11189742fdb4Schristos 				}
11199742fdb4Schristos 
11209742fdb4Schristos 				ctx.syncdel = strtotime(
11219742fdb4Schristos 					isc_commandline_argument, ctx.now,
11229742fdb4Schristos 					ctx.now, &ctx.setsyncdel);
11239742fdb4Schristos 				break;
11249742fdb4Schristos 			}
11259742fdb4Schristos 			(void)isoptarg("dnskey", argv, usage);
11269742fdb4Schristos 			if (ctx.setdel || ctx.unsetdel) {
11279742fdb4Schristos 				fatal("-D specified more than once");
11289742fdb4Schristos 			}
11299742fdb4Schristos 
11309742fdb4Schristos 			ctx.deltime = strtotime(isc_commandline_argument,
11319742fdb4Schristos 						ctx.now, ctx.now, &ctx.setdel);
11329742fdb4Schristos 			ctx.unsetdel = !ctx.setdel;
11339742fdb4Schristos 			break;
11349742fdb4Schristos 		case 'S':
11359742fdb4Schristos 			ctx.predecessor = isc_commandline_argument;
11369742fdb4Schristos 			break;
11379742fdb4Schristos 		case 'i':
11389742fdb4Schristos 			ctx.prepub = strtottl(isc_commandline_argument);
11399742fdb4Schristos 			break;
11409742fdb4Schristos 		case 'F':
11419742fdb4Schristos 			/* Reserved for FIPS mode */
1142c0b5d9fbSchristos 			FALLTHROUGH;
11439742fdb4Schristos 		case '?':
11449742fdb4Schristos 			if (isc_commandline_option != '?') {
11459742fdb4Schristos 				fprintf(stderr, "%s: invalid argument -%c\n",
11469742fdb4Schristos 					program, isc_commandline_option);
11479742fdb4Schristos 			}
1148c0b5d9fbSchristos 			FALLTHROUGH;
11499742fdb4Schristos 		case 'h':
11509742fdb4Schristos 			/* Does not return. */
11519742fdb4Schristos 			usage();
11529742fdb4Schristos 
11539742fdb4Schristos 		case 'V':
11549742fdb4Schristos 			/* Does not return. */
11559742fdb4Schristos 			version(program);
11569742fdb4Schristos 
11579742fdb4Schristos 		default:
11589742fdb4Schristos 			fprintf(stderr, "%s: unhandled option -%c\n", program,
11599742fdb4Schristos 				isc_commandline_option);
11609742fdb4Schristos 			exit(1);
11619742fdb4Schristos 		}
11629742fdb4Schristos 	}
11639742fdb4Schristos 
11649742fdb4Schristos 	if (!isatty(0)) {
11659742fdb4Schristos 		ctx.quiet = true;
11669742fdb4Schristos 	}
11679742fdb4Schristos 
11689742fdb4Schristos 	ret = dst_lib_init(mctx, engine);
11699742fdb4Schristos 	if (ret != ISC_R_SUCCESS) {
11709742fdb4Schristos 		fatal("could not initialize dst: %s", isc_result_totext(ret));
11719742fdb4Schristos 	}
11729742fdb4Schristos 
11739742fdb4Schristos 	setup_logging(mctx, &lctx);
11749742fdb4Schristos 
11759742fdb4Schristos 	ctx.rdclass = strtoclass(classname);
11769742fdb4Schristos 
11779742fdb4Schristos 	if (ctx.configfile == NULL || ctx.configfile[0] == '\0') {
11789742fdb4Schristos 		ctx.configfile = NAMED_CONFFILE;
11799742fdb4Schristos 	}
11809742fdb4Schristos 
11819742fdb4Schristos 	if (ctx.predecessor == NULL) {
11829742fdb4Schristos 		if (argc < isc_commandline_index + 1) {
11839742fdb4Schristos 			fatal("the key name was not specified");
11849742fdb4Schristos 		}
11859742fdb4Schristos 		if (argc > isc_commandline_index + 1) {
11869742fdb4Schristos 			fatal("extraneous arguments");
11879742fdb4Schristos 		}
11889742fdb4Schristos 	}
11899742fdb4Schristos 
11909742fdb4Schristos 	if (ctx.predecessor == NULL && ctx.policy == NULL) {
11919742fdb4Schristos 		if (algname == NULL) {
11929742fdb4Schristos 			fatal("no algorithm specified");
11939742fdb4Schristos 		}
11949742fdb4Schristos 		r.base = algname;
11959742fdb4Schristos 		r.length = strlen(algname);
11969742fdb4Schristos 		ret = dns_secalg_fromtext(&ctx.alg, &r);
11979742fdb4Schristos 		if (ret != ISC_R_SUCCESS) {
11989742fdb4Schristos 			fatal("unknown algorithm %s", algname);
11999742fdb4Schristos 		}
12009742fdb4Schristos 		if (!dst_algorithm_supported(ctx.alg)) {
12019742fdb4Schristos 			fatal("unsupported algorithm: %s", algname);
12029742fdb4Schristos 		}
12039742fdb4Schristos 	}
12049742fdb4Schristos 
12059742fdb4Schristos 	if (ctx.policy != NULL) {
12069742fdb4Schristos 		if (ctx.nametype != NULL) {
12079742fdb4Schristos 			fatal("-k and -n cannot be used together");
12089742fdb4Schristos 		}
12099742fdb4Schristos 		if (ctx.predecessor != NULL) {
12109742fdb4Schristos 			fatal("-k and -S cannot be used together");
12119742fdb4Schristos 		}
12129742fdb4Schristos 		if (ctx.oldstyle) {
12139742fdb4Schristos 			fatal("-k and -C cannot be used together");
12149742fdb4Schristos 		}
12159742fdb4Schristos 		if (ctx.setttl) {
12169742fdb4Schristos 			fatal("-k and -L cannot be used together");
12179742fdb4Schristos 		}
12189742fdb4Schristos 		if (ctx.prepub > 0) {
12199742fdb4Schristos 			fatal("-k and -i cannot be used together");
12209742fdb4Schristos 		}
12219742fdb4Schristos 		if (ctx.size != -1) {
12229742fdb4Schristos 			fatal("-k and -b cannot be used together");
12239742fdb4Schristos 		}
12249742fdb4Schristos 		if (ctx.kskflag || ctx.revflag) {
12259742fdb4Schristos 			fatal("-k and -f cannot be used together");
12269742fdb4Schristos 		}
12279742fdb4Schristos 		if (ctx.options & DST_TYPE_KEY) {
12289742fdb4Schristos 			fatal("-k and -T KEY cannot be used together");
12299742fdb4Schristos 		}
12309742fdb4Schristos 		if (ctx.use_nsec3) {
12319742fdb4Schristos 			fatal("-k and -3 cannot be used together");
12329742fdb4Schristos 		}
12339742fdb4Schristos 
12349742fdb4Schristos 		ctx.options |= DST_TYPE_STATE;
12359742fdb4Schristos 
12369742fdb4Schristos 		if (strcmp(ctx.policy, "default") == 0) {
12379742fdb4Schristos 			ctx.use_nsec3 = false;
12389742fdb4Schristos 			ctx.alg = DST_ALG_ECDSA256;
12399742fdb4Schristos 			ctx.size = 0;
12409742fdb4Schristos 			ctx.kskflag = DNS_KEYFLAG_KSK;
12419742fdb4Schristos 			ctx.ttl = 3600;
12429742fdb4Schristos 			ctx.setttl = true;
12439742fdb4Schristos 			ctx.ksk = true;
12449742fdb4Schristos 			ctx.zsk = true;
12459742fdb4Schristos 			ctx.lifetime = 0;
12469742fdb4Schristos 
12479742fdb4Schristos 			keygen(&ctx, mctx, argc, argv);
12489742fdb4Schristos 		} else {
12499742fdb4Schristos 			cfg_parser_t *parser = NULL;
12509742fdb4Schristos 			cfg_obj_t *config = NULL;
12519742fdb4Schristos 			dns_kasp_t *kasp = NULL;
12529742fdb4Schristos 			dns_kasp_key_t *kaspkey = NULL;
12539742fdb4Schristos 
12549742fdb4Schristos 			RUNTIME_CHECK(cfg_parser_create(mctx, lctx, &parser) ==
12559742fdb4Schristos 				      ISC_R_SUCCESS);
12569742fdb4Schristos 			if (cfg_parse_file(parser, ctx.configfile,
12579742fdb4Schristos 					   &cfg_type_namedconf,
12589742fdb4Schristos 					   &config) != ISC_R_SUCCESS)
12599742fdb4Schristos 			{
12609742fdb4Schristos 				fatal("unable to load dnssec-policy '%s' from "
12619742fdb4Schristos 				      "'%s'",
12629742fdb4Schristos 				      ctx.policy, ctx.configfile);
12639742fdb4Schristos 			}
12649742fdb4Schristos 
12659742fdb4Schristos 			kasp_from_conf(config, mctx, ctx.policy, &kasp);
12669742fdb4Schristos 			if (kasp == NULL) {
12679742fdb4Schristos 				fatal("failed to load dnssec-policy '%s'",
12689742fdb4Schristos 				      ctx.policy);
12699742fdb4Schristos 			}
12709742fdb4Schristos 			if (ISC_LIST_EMPTY(dns_kasp_keys(kasp))) {
12719742fdb4Schristos 				fatal("dnssec-policy '%s' has no keys "
12729742fdb4Schristos 				      "configured",
12739742fdb4Schristos 				      ctx.policy);
12749742fdb4Schristos 			}
12759742fdb4Schristos 
12769742fdb4Schristos 			ctx.ttl = dns_kasp_dnskeyttl(kasp);
12779742fdb4Schristos 			ctx.setttl = true;
12789742fdb4Schristos 
12799742fdb4Schristos 			kaspkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
12809742fdb4Schristos 
12819742fdb4Schristos 			while (kaspkey != NULL) {
12829742fdb4Schristos 				ctx.use_nsec3 = false;
12839742fdb4Schristos 				ctx.alg = dns_kasp_key_algorithm(kaspkey);
12849742fdb4Schristos 				ctx.size = dns_kasp_key_size(kaspkey);
12859742fdb4Schristos 				ctx.kskflag = dns_kasp_key_ksk(kaspkey)
12869742fdb4Schristos 						      ? DNS_KEYFLAG_KSK
12879742fdb4Schristos 						      : 0;
12889742fdb4Schristos 				ctx.ksk = dns_kasp_key_ksk(kaspkey);
12899742fdb4Schristos 				ctx.zsk = dns_kasp_key_zsk(kaspkey);
12909742fdb4Schristos 				ctx.lifetime = dns_kasp_key_lifetime(kaspkey);
12919742fdb4Schristos 
12929742fdb4Schristos 				keygen(&ctx, mctx, argc, argv);
12939742fdb4Schristos 
12949742fdb4Schristos 				kaspkey = ISC_LIST_NEXT(kaspkey, link);
12959742fdb4Schristos 			}
12969742fdb4Schristos 
12979742fdb4Schristos 			dns_kasp_detach(&kasp);
12989742fdb4Schristos 			cfg_obj_destroy(parser, &config);
12999742fdb4Schristos 			cfg_parser_destroy(&parser);
13009742fdb4Schristos 		}
13019742fdb4Schristos 	} else {
13029742fdb4Schristos 		keygen(&ctx, mctx, argc, argv);
13039742fdb4Schristos 	}
13049742fdb4Schristos 
13059742fdb4Schristos 	cleanup_logging(&lctx);
1306e2b1b9c0Schristos 	dst_lib_destroy();
13079742fdb4Schristos 	if (verbose > 10) {
1308e2b1b9c0Schristos 		isc_mem_stats(mctx, stdout);
13099742fdb4Schristos 	}
1310e2b1b9c0Schristos 	isc_mem_destroy(&mctx);
1311e2b1b9c0Schristos 
13129742fdb4Schristos 	if (freeit != NULL) {
1313e2b1b9c0Schristos 		free(freeit);
13149742fdb4Schristos 	}
1315e2b1b9c0Schristos 
1316e2b1b9c0Schristos 	return (0);
1317e2b1b9c0Schristos }
1318