Home | History | Annotate | Line # | Download | only in dnssec
      1 /*	$NetBSD: dnssec-keygen.c,v 1.17 2026/06/19 20:09:58 christos Exp $	*/
      2 
      3 /*
      4  * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  *
     15  * Portions Copyright (C) Network Associates, Inc.
     16  *
     17  * Permission to use, copy, modify, and/or distribute this software for any
     18  * purpose with or without fee is hereby granted, provided that the above
     19  * copyright notice and this permission notice appear in all copies.
     20  *
     21  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
     22  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
     23  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
     24  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     25  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     26  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
     27  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     28  */
     29 
     30 /*! \file */
     31 
     32 #include <ctype.h>
     33 #include <inttypes.h>
     34 #include <stdbool.h>
     35 #include <stdlib.h>
     36 #include <unistd.h>
     37 
     38 #include <openssl/opensslv.h>
     39 
     40 #include <isc/attributes.h>
     41 #include <isc/buffer.h>
     42 #include <isc/commandline.h>
     43 #include <isc/fips.h>
     44 #include <isc/mem.h>
     45 #include <isc/region.h>
     46 #include <isc/result.h>
     47 #include <isc/string.h>
     48 #include <isc/util.h>
     49 
     50 #include <dns/dnssec.h>
     51 #include <dns/fixedname.h>
     52 #include <dns/kasp.h>
     53 #include <dns/keyvalues.h>
     54 #include <dns/log.h>
     55 #include <dns/name.h>
     56 #include <dns/rdataclass.h>
     57 #include <dns/secalg.h>
     58 
     59 #include <dst/dst.h>
     60 
     61 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
     62 #include <openssl/err.h>
     63 #include <openssl/provider.h>
     64 #endif
     65 
     66 #include "dnssectool.h"
     67 
     68 const char *program = "dnssec-keygen";
     69 
     70 /*
     71  * These are set here for backwards compatibility.  They are
     72  * raised to 2048 in FIPS mode.
     73  */
     74 static int min_rsa = 1024;
     75 static int min_dh = 128;
     76 
     77 isc_log_t *lctx = NULL;
     78 
     79 noreturn static void
     80 usage(int ret);
     81 
     82 static void
     83 progress(int p);
     84 
     85 struct keygen_ctx {
     86 	const char *predecessor;
     87 	const char *policy;
     88 	const char *configfile;
     89 	const char *directory;
     90 	dns_keystore_t *keystore;
     91 	char *algname;
     92 	char *nametype;
     93 	char *type;
     94 	int protocol;
     95 	int size;
     96 	uint16_t tag_min;
     97 	uint16_t tag_max;
     98 	int signatory;
     99 	dns_rdataclass_t rdclass;
    100 	int options;
    101 	int dbits;
    102 	dns_ttl_t ttl;
    103 	bool wantzsk;
    104 	bool wantksk;
    105 	bool wantrev;
    106 	dns_secalg_t alg;
    107 	/* timing data */
    108 	int prepub;
    109 	isc_stdtime_t now;
    110 	isc_stdtime_t publish;
    111 	isc_stdtime_t activate;
    112 	isc_stdtime_t inactive;
    113 	isc_stdtime_t revokekey;
    114 	isc_stdtime_t deltime;
    115 	isc_stdtime_t syncadd;
    116 	isc_stdtime_t syncdel;
    117 	bool setpub;
    118 	bool setact;
    119 	bool setinact;
    120 	bool setrev;
    121 	bool setdel;
    122 	bool setsyncadd;
    123 	bool setsyncdel;
    124 	bool unsetpub;
    125 	bool unsetact;
    126 	bool unsetinact;
    127 	bool unsetrev;
    128 	bool unsetdel;
    129 	/* how to generate the key */
    130 	bool setttl;
    131 	bool use_nsec3;
    132 	bool genonly;
    133 	bool showprogress;
    134 	bool quiet;
    135 	bool oldstyle;
    136 	/* state */
    137 	time_t lifetime;
    138 	bool ksk;
    139 	bool zsk;
    140 };
    141 
    142 typedef struct keygen_ctx keygen_ctx_t;
    143 
    144 static void
    145 usage(int ret) {
    146 	fprintf(stderr, "Usage:\n");
    147 	fprintf(stderr, "    %s [options] name\n\n", program);
    148 	fprintf(stderr, "Version: %s\n", PACKAGE_VERSION);
    149 	fprintf(stderr, "    name: owner of the key\n");
    150 	fprintf(stderr, "Options:\n");
    151 	fprintf(stderr, "    -K <directory>: write keys into directory\n");
    152 	fprintf(stderr, "    -k <policy>: generate keys for dnssec-policy\n");
    153 	fprintf(stderr, "    -l <file>: configuration file with dnssec-policy "
    154 			"statement\n");
    155 	fprintf(stderr, "    -a <algorithm>:\n");
    156 	if (!isc_fips_mode()) {
    157 		fprintf(stderr, "        RSASHA1 (deprecated) | NSEC3RSASHA1 "
    158 				"(deprecated) |\n");
    159 	}
    160 	fprintf(stderr, "        RSASHA256 | RSASHA512 |\n");
    161 	fprintf(stderr, "        ECDSAP256SHA256 | ECDSAP384SHA384 |\n");
    162 	fprintf(stderr, "        ED25519 | ED448\n");
    163 	fprintf(stderr, "    -3: use NSEC3-capable algorithm\n");
    164 	fprintf(stderr, "    -b <key size in bits>:\n");
    165 	if (!isc_fips_mode()) {
    166 		fprintf(stderr, "        RSASHA1 (deprecated) :\t[%d..%d]\n",
    167 			min_rsa, MAX_RSA);
    168 		fprintf(stderr,
    169 			"        NSEC3RSASHA1 (deprecated) :\t[%d..%d]\n",
    170 			min_rsa, MAX_RSA);
    171 	}
    172 	fprintf(stderr, "        RSASHA256:\t[%d..%d]\n", min_rsa, MAX_RSA);
    173 	fprintf(stderr, "        RSASHA512:\t[%d..%d]\n", min_rsa, MAX_RSA);
    174 	fprintf(stderr, "        ECDSAP256SHA256:\tignored\n");
    175 	fprintf(stderr, "        ECDSAP384SHA384:\tignored\n");
    176 	fprintf(stderr, "        ED25519:\tignored\n");
    177 	fprintf(stderr, "        ED448:\tignored\n");
    178 	fprintf(stderr, "        (key size defaults are set according to\n"
    179 			"        algorithm and usage (ZSK or KSK)\n");
    180 	fprintf(stderr, "    -n <nametype>: ZONE | HOST | ENTITY | "
    181 			"USER | OTHER\n");
    182 	fprintf(stderr, "        (DNSKEY generation defaults to ZONE)\n");
    183 	fprintf(stderr, "    -c <class>: (default: IN)\n");
    184 	fprintf(stderr, "    -d <digest bits> (0 => max, default)\n");
    185 	fprintf(stderr, "    -E <engine>:\n");
    186 	fprintf(stderr, "        name of an OpenSSL engine to use\n");
    187 	fprintf(stderr, "    -f <keyflag>: ZSK | KSK | REVOKE\n");
    188 	fprintf(stderr, "    -F: FIPS mode\n");
    189 	fprintf(stderr, "    -L <ttl>: default key TTL\n");
    190 	fprintf(stderr, "    -M <min>:<max>: allowed Key ID range\n");
    191 	fprintf(stderr, "    -p <protocol>: (default: 3 [dnssec])\n");
    192 	fprintf(stderr, "    -s <strength>: strength value this key signs DNS "
    193 			"records with (default: 0)\n");
    194 	fprintf(stderr, "    -T <rrtype>: DNSKEY | KEY (default: DNSKEY; "
    195 			"use KEY for SIG(0))\n");
    196 	fprintf(stderr, "    -t <type>: "
    197 			"AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF "
    198 			"(default: AUTHCONF)\n");
    199 	fprintf(stderr, "    -h: print usage and exit\n");
    200 	fprintf(stderr, "    -m <memory debugging mode>:\n");
    201 	fprintf(stderr, "       usage | trace | record\n");
    202 	fprintf(stderr, "    -v <level>: set verbosity level (0 - 10)\n");
    203 	fprintf(stderr, "    -V: print version information\n");
    204 	fprintf(stderr, "Timing options:\n");
    205 	fprintf(stderr, "    -P date/[+-]offset/none: set key publication date "
    206 			"(default: now)\n");
    207 	fprintf(stderr, "    -P sync date/[+-]offset/none: set CDS and CDNSKEY "
    208 			"publication date\n");
    209 	fprintf(stderr, "    -A date/[+-]offset/none: set key activation date "
    210 			"(default: now)\n");
    211 	fprintf(stderr, "    -R date/[+-]offset/none: set key "
    212 			"revocation date\n");
    213 	fprintf(stderr, "    -I date/[+-]offset/none: set key "
    214 			"inactivation date\n");
    215 	fprintf(stderr, "    -D date/[+-]offset/none: set key deletion date\n");
    216 	fprintf(stderr, "    -D sync date/[+-]offset/none: set CDS and CDNSKEY "
    217 			"deletion date\n");
    218 
    219 	fprintf(stderr, "    -G: generate key only; do not set -P or -A\n");
    220 	fprintf(stderr, "    -C: generate a backward-compatible key, omitting "
    221 			"all dates\n");
    222 	fprintf(stderr, "    -S <key>: generate a successor to an existing "
    223 			"key\n");
    224 	fprintf(stderr, "    -i <interval>: prepublication interval for "
    225 			"successor key "
    226 			"(default: 30 days)\n");
    227 	fprintf(stderr, "Output:\n");
    228 	fprintf(stderr, "     K<name>+<alg>+<id>.key, "
    229 			"K<name>+<alg>+<id>.private\n");
    230 
    231 	exit(ret);
    232 }
    233 
    234 static void
    235 progress(int p) {
    236 	char c = '*';
    237 
    238 	switch (p) {
    239 	case 0:
    240 		c = '.';
    241 		break;
    242 	case 1:
    243 		c = '+';
    244 		break;
    245 	case 2:
    246 		c = '*';
    247 		break;
    248 	case 3:
    249 		c = ' ';
    250 		break;
    251 	default:
    252 		break;
    253 	}
    254 	(void)putc(c, stderr);
    255 	(void)fflush(stderr);
    256 }
    257 
    258 static void
    259 keygen(keygen_ctx_t *ctx, isc_mem_t *mctx, int argc, char **argv) {
    260 	char filename[255];
    261 	char algstr[DNS_SECALG_FORMATSIZE];
    262 	uint16_t flags = 0;
    263 	int param = 0;
    264 	bool null_key = false;
    265 	bool conflict = false;
    266 	bool show_progress = false;
    267 	isc_buffer_t buf;
    268 	dns_name_t *name;
    269 	dns_fixedname_t fname;
    270 	isc_result_t ret;
    271 	dst_key_t *key = NULL;
    272 	dst_key_t *prevkey = NULL;
    273 
    274 	UNUSED(argc);
    275 
    276 	dns_secalg_format(ctx->alg, algstr, sizeof(algstr));
    277 
    278 	if (ctx->predecessor == NULL) {
    279 		if (ctx->prepub == -1) {
    280 			ctx->prepub = 0;
    281 		}
    282 
    283 		name = dns_fixedname_initname(&fname);
    284 		isc_buffer_init(&buf, argv[isc_commandline_index],
    285 				strlen(argv[isc_commandline_index]));
    286 		isc_buffer_add(&buf, strlen(argv[isc_commandline_index]));
    287 		ret = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
    288 		if (ret != ISC_R_SUCCESS) {
    289 			fatal("invalid key name %s: %s",
    290 			      argv[isc_commandline_index],
    291 			      isc_result_totext(ret));
    292 		}
    293 
    294 		if (!dst_algorithm_supported(ctx->alg)) {
    295 			fatal("unsupported algorithm: %s", algstr);
    296 		}
    297 
    298 		if (isc_fips_mode()) {
    299 			/* verify only in FIPS mode */
    300 			switch (ctx->alg) {
    301 			case DST_ALG_RSASHA1:
    302 			case DST_ALG_NSEC3RSASHA1:
    303 				fatal("unsupported algorithm: %s", algstr);
    304 			default:
    305 				break;
    306 			}
    307 		}
    308 
    309 		if (ctx->use_nsec3) {
    310 			switch (ctx->alg) {
    311 			case DST_ALG_RSASHA1:
    312 				ctx->alg = DST_ALG_NSEC3RSASHA1;
    313 				break;
    314 			case DST_ALG_NSEC3RSASHA1:
    315 			case DST_ALG_RSASHA256:
    316 			case DST_ALG_RSASHA512:
    317 			case DST_ALG_ECDSA256:
    318 			case DST_ALG_ECDSA384:
    319 			case DST_ALG_ED25519:
    320 			case DST_ALG_ED448:
    321 				break;
    322 			default:
    323 				fatal("algorithm %s is incompatible with NSEC3"
    324 				      ", do not use the -3 option",
    325 				      algstr);
    326 			}
    327 		}
    328 
    329 		if (ctx->type != NULL && (ctx->options & DST_TYPE_KEY) != 0) {
    330 			if (strcasecmp(ctx->type, "NOAUTH") == 0) {
    331 				flags |= DNS_KEYTYPE_NOAUTH;
    332 			} else if (strcasecmp(ctx->type, "NOCONF") == 0) {
    333 				flags |= DNS_KEYTYPE_NOCONF;
    334 			} else if (strcasecmp(ctx->type, "NOAUTHCONF") == 0) {
    335 				flags |= (DNS_KEYTYPE_NOAUTH |
    336 					  DNS_KEYTYPE_NOCONF);
    337 				if (ctx->size < 0) {
    338 					ctx->size = 0;
    339 				}
    340 			} else if (strcasecmp(ctx->type, "AUTHCONF") == 0) {
    341 				/* nothing */
    342 			} else {
    343 				fatal("invalid type %s", ctx->type);
    344 			}
    345 		}
    346 
    347 		if (ctx->size < 0) {
    348 			switch (ctx->alg) {
    349 			case DST_ALG_RSASHA1:
    350 			case DST_ALG_NSEC3RSASHA1:
    351 				if (isc_fips_mode()) {
    352 					fatal("key size not specified (-b "
    353 					      "option)");
    354 				}
    355 				FALLTHROUGH;
    356 			case DST_ALG_RSASHA256:
    357 			case DST_ALG_RSASHA512:
    358 				ctx->size = 2048;
    359 				if (verbose > 0) {
    360 					fprintf(stderr,
    361 						"key size not "
    362 						"specified; defaulting"
    363 						" to %d\n",
    364 						ctx->size);
    365 				}
    366 				break;
    367 			case DST_ALG_ECDSA256:
    368 			case DST_ALG_ECDSA384:
    369 			case DST_ALG_ED25519:
    370 			case DST_ALG_ED448:
    371 				break;
    372 			default:
    373 				fatal("key size not specified (-b option)");
    374 			}
    375 		}
    376 
    377 		if (!ctx->oldstyle && ctx->prepub > 0) {
    378 			if (ctx->setpub && ctx->setact &&
    379 			    (ctx->activate - ctx->prepub) < ctx->publish)
    380 			{
    381 				fatal("Activation and publication dates "
    382 				      "are closer together than the\n\t"
    383 				      "prepublication interval.");
    384 			}
    385 
    386 			if (!ctx->setpub && !ctx->setact) {
    387 				ctx->setpub = ctx->setact = true;
    388 				ctx->publish = ctx->now;
    389 				ctx->activate = ctx->now + ctx->prepub;
    390 			} else if (ctx->setpub && !ctx->setact) {
    391 				ctx->setact = true;
    392 				ctx->activate = ctx->publish + ctx->prepub;
    393 			} else if (ctx->setact && !ctx->setpub) {
    394 				ctx->setpub = true;
    395 				ctx->publish = ctx->activate - ctx->prepub;
    396 			}
    397 
    398 			if ((ctx->activate - ctx->prepub) < ctx->now) {
    399 				fatal("Time until activation is shorter "
    400 				      "than the\n\tprepublication interval.");
    401 			}
    402 		}
    403 	} else {
    404 		char keystr[DST_KEY_FORMATSIZE];
    405 		isc_stdtime_t when;
    406 		int major, minor;
    407 
    408 		if (ctx->prepub == -1) {
    409 			ctx->prepub = (30 * 86400);
    410 		}
    411 
    412 		if (ctx->alg != 0) {
    413 			fatal("-S and -a cannot be used together");
    414 		}
    415 		if (ctx->size >= 0) {
    416 			fatal("-S and -b cannot be used together");
    417 		}
    418 		if (ctx->nametype != NULL) {
    419 			fatal("-S and -n cannot be used together");
    420 		}
    421 		if (ctx->type != NULL) {
    422 			fatal("-S and -t cannot be used together");
    423 		}
    424 		if (ctx->setpub || ctx->unsetpub) {
    425 			fatal("-S and -P cannot be used together");
    426 		}
    427 		if (ctx->setact || ctx->unsetact) {
    428 			fatal("-S and -A cannot be used together");
    429 		}
    430 		if (ctx->use_nsec3) {
    431 			fatal("-S and -3 cannot be used together");
    432 		}
    433 		if (ctx->oldstyle) {
    434 			fatal("-S and -C cannot be used together");
    435 		}
    436 		if (ctx->genonly) {
    437 			fatal("-S and -G cannot be used together");
    438 		}
    439 
    440 		ret = dst_key_fromnamedfile(ctx->predecessor, ctx->directory,
    441 					    DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
    442 						    DST_TYPE_STATE,
    443 					    mctx, &prevkey);
    444 		if (ret != ISC_R_SUCCESS) {
    445 			fatal("Invalid keyfile %s: %s", ctx->predecessor,
    446 			      isc_result_totext(ret));
    447 		}
    448 		if (!dst_key_isprivate(prevkey)) {
    449 			fatal("%s is not a private key", ctx->predecessor);
    450 		}
    451 
    452 		name = dst_key_name(prevkey);
    453 		ctx->alg = dst_key_alg(prevkey);
    454 		ctx->size = dst_key_size(prevkey);
    455 		flags = dst_key_flags(prevkey);
    456 
    457 		dst_key_format(prevkey, keystr, sizeof(keystr));
    458 		dst_key_getprivateformat(prevkey, &major, &minor);
    459 		if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) {
    460 			fatal("Key %s has incompatible format version %d.%d\n\t"
    461 			      "It is not possible to generate a successor key.",
    462 			      keystr, major, minor);
    463 		}
    464 
    465 		ret = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &when);
    466 		if (ret != ISC_R_SUCCESS) {
    467 			fatal("Key %s has no activation date.\n\t"
    468 			      "You must use dnssec-settime -A to set one "
    469 			      "before generating a successor.",
    470 			      keystr);
    471 		}
    472 
    473 		ret = dst_key_gettime(prevkey, DST_TIME_INACTIVE,
    474 				      &ctx->activate);
    475 		if (ret != ISC_R_SUCCESS) {
    476 			fatal("Key %s has no inactivation date.\n\t"
    477 			      "You must use dnssec-settime -I to set one "
    478 			      "before generating a successor.",
    479 			      keystr);
    480 		}
    481 
    482 		ctx->publish = ctx->activate - ctx->prepub;
    483 		if (ctx->publish < ctx->now) {
    484 			fatal("Key %s becomes inactive\n\t"
    485 			      "sooner than the prepublication period "
    486 			      "for the new key ends.\n\t"
    487 			      "Either change the inactivation date with "
    488 			      "dnssec-settime -I,\n\t"
    489 			      "or use the -i option to set a shorter "
    490 			      "prepublication interval.",
    491 			      keystr);
    492 		}
    493 
    494 		ret = dst_key_gettime(prevkey, DST_TIME_DELETE, &when);
    495 		if (ret != ISC_R_SUCCESS) {
    496 			fprintf(stderr,
    497 				"%s: WARNING: Key %s has no removal "
    498 				"date;\n\t it will remain in the zone "
    499 				"indefinitely after rollover.\n\t "
    500 				"You can use dnssec-settime -D to "
    501 				"change this.\n",
    502 				program, keystr);
    503 		}
    504 
    505 		ctx->setpub = ctx->setact = true;
    506 	}
    507 
    508 	switch (ctx->alg) {
    509 	case DST_ALG_RSASHA1:
    510 	case DST_ALG_NSEC3RSASHA1:
    511 		dns_secalg_format(ctx->alg, algstr, sizeof(algstr));
    512 		fprintf(stderr,
    513 			"WARNING: DNSKEY algorithm '%s' is deprecated. Please "
    514 			"migrate to another algorithm\n",
    515 			algstr);
    516 		break;
    517 	default:
    518 		break;
    519 	}
    520 
    521 	switch (ctx->alg) {
    522 	case DST_ALG_RSASHA1:
    523 	case DST_ALG_NSEC3RSASHA1:
    524 		if (isc_fips_mode()) {
    525 			fatal("SHA1 based keys not supported in FIPS mode");
    526 		}
    527 		FALLTHROUGH;
    528 	case DST_ALG_RSASHA256:
    529 	case DST_ALG_RSASHA512:
    530 		if (ctx->size != 0 &&
    531 		    (ctx->size < min_rsa || ctx->size > MAX_RSA))
    532 		{
    533 			fatal("RSA key size %d out of range", ctx->size);
    534 		}
    535 		break;
    536 	case DST_ALG_ECDSA256:
    537 		ctx->size = 256;
    538 		break;
    539 	case DST_ALG_ECDSA384:
    540 		ctx->size = 384;
    541 		break;
    542 	case DST_ALG_ED25519:
    543 		ctx->size = 256;
    544 		break;
    545 	case DST_ALG_ED448:
    546 		ctx->size = 456;
    547 		break;
    548 	}
    549 
    550 	if (ctx->nametype == NULL) {
    551 		if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */
    552 			fatal("no nametype specified");
    553 		}
    554 		flags |= DNS_KEYOWNER_ZONE; /* DNSKEY */
    555 	} else if (strcasecmp(ctx->nametype, "zone") == 0) {
    556 		flags |= DNS_KEYOWNER_ZONE;
    557 	} else if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */
    558 		if (strcasecmp(ctx->nametype, "host") == 0 ||
    559 		    strcasecmp(ctx->nametype, "entity") == 0)
    560 		{
    561 			flags |= DNS_KEYOWNER_ENTITY;
    562 		} else if (strcasecmp(ctx->nametype, "user") == 0) {
    563 			/* no owner flags */
    564 		} else {
    565 			fatal("invalid KEY nametype %s", ctx->nametype);
    566 		}
    567 	} else if (strcasecmp(ctx->nametype, "other") != 0) { /* DNSKEY */
    568 		fatal("invalid DNSKEY nametype %s", ctx->nametype);
    569 	}
    570 
    571 	if (ctx->directory == NULL) {
    572 		ctx->directory = ".";
    573 	}
    574 
    575 	if ((ctx->options & DST_TYPE_KEY) != 0) { /* KEY */
    576 		flags |= ctx->signatory;
    577 	} else if ((flags & DNS_KEYOWNER_ZONE) != 0) { /* DNSKEY */
    578 		if (ctx->ksk || ctx->wantksk) {
    579 			flags |= DNS_KEYFLAG_KSK;
    580 		}
    581 		if (ctx->wantrev) {
    582 			flags |= DNS_KEYFLAG_REVOKE;
    583 		}
    584 	}
    585 
    586 	if (ctx->protocol == -1) {
    587 		ctx->protocol = DNS_KEYPROTO_DNSSEC;
    588 	} else if ((ctx->options & DST_TYPE_KEY) == 0 &&
    589 		   ctx->protocol != DNS_KEYPROTO_DNSSEC)
    590 	{
    591 		fatal("invalid DNSKEY protocol: %d", ctx->protocol);
    592 	}
    593 
    594 	if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
    595 		if (ctx->size > 0) {
    596 			fatal("specified null key with non-zero size");
    597 		}
    598 	}
    599 
    600 	switch (ctx->alg) {
    601 	case DNS_KEYALG_RSASHA1:
    602 	case DNS_KEYALG_NSEC3RSASHA1:
    603 	case DNS_KEYALG_RSASHA256:
    604 	case DNS_KEYALG_RSASHA512:
    605 		show_progress = true;
    606 		break;
    607 
    608 	case DST_ALG_ECDSA256:
    609 	case DST_ALG_ECDSA384:
    610 	case DST_ALG_ED25519:
    611 	case DST_ALG_ED448:
    612 		show_progress = true;
    613 		break;
    614 	}
    615 
    616 	if ((flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY &&
    617 	    (ctx->options & DST_TYPE_KEY) != 0)
    618 	{
    619 		null_key = true;
    620 	}
    621 
    622 	isc_buffer_init(&buf, filename, sizeof(filename) - 1);
    623 
    624 	do {
    625 		conflict = false;
    626 
    627 		if (!ctx->quiet && show_progress) {
    628 			fprintf(stderr, "Generating key pair.");
    629 		}
    630 
    631 		if (ctx->keystore != NULL && ctx->policy != NULL) {
    632 			ret = dns_keystore_keygen(
    633 				ctx->keystore, name, ctx->policy, ctx->rdclass,
    634 				mctx, ctx->alg, ctx->size, flags, &key);
    635 		} else if (!ctx->quiet && show_progress) {
    636 			ret = dst_key_generate(name, ctx->alg, ctx->size, param,
    637 					       flags, ctx->protocol,
    638 					       ctx->rdclass, NULL, mctx, &key,
    639 					       &progress);
    640 		} else {
    641 			ret = dst_key_generate(name, ctx->alg, ctx->size, param,
    642 					       flags, ctx->protocol,
    643 					       ctx->rdclass, NULL, mctx, &key,
    644 					       NULL);
    645 		}
    646 
    647 		if (!ctx->quiet && show_progress) {
    648 			putc('\n', stderr);
    649 			fflush(stderr);
    650 		}
    651 
    652 		if (ret != ISC_R_SUCCESS) {
    653 			char namestr[DNS_NAME_FORMATSIZE];
    654 			dns_name_format(name, namestr, sizeof(namestr));
    655 			fatal("failed to generate key %s/%s: %s\n", namestr,
    656 			      algstr, isc_result_totext(ret));
    657 		}
    658 
    659 		dst_key_setbits(key, ctx->dbits);
    660 
    661 		/*
    662 		 * Set key timing metadata (unless using -C)
    663 		 *
    664 		 * Creation date is always set to "now".
    665 		 *
    666 		 * For a new key without an explicit predecessor, publish
    667 		 * and activation dates are set to "now" by default, but
    668 		 * can both be overridden.
    669 		 *
    670 		 * For a successor key, activation is set to match the
    671 		 * predecessor's inactivation date.  Publish is set to 30
    672 		 * days earlier than that (XXX: this should be configurable).
    673 		 * If either of the resulting dates are in the past, that's
    674 		 * an error; the inactivation date of the predecessor key
    675 		 * must be updated before a successor key can be created.
    676 		 */
    677 		if (!ctx->oldstyle) {
    678 			dst_key_settime(key, DST_TIME_CREATED, ctx->now);
    679 
    680 			if (ctx->genonly && (ctx->setpub || ctx->setact)) {
    681 				fatal("cannot use -G together with "
    682 				      "-P or -A options");
    683 			}
    684 
    685 			if (ctx->setpub) {
    686 				dst_key_settime(key, DST_TIME_PUBLISH,
    687 						ctx->publish);
    688 			} else if (ctx->setact && !ctx->unsetpub) {
    689 				dst_key_settime(key, DST_TIME_PUBLISH,
    690 						ctx->activate - ctx->prepub);
    691 			} else if (!ctx->genonly && !ctx->unsetpub) {
    692 				dst_key_settime(key, DST_TIME_PUBLISH,
    693 						ctx->now);
    694 			}
    695 
    696 			if (ctx->setact) {
    697 				dst_key_settime(key, DST_TIME_ACTIVATE,
    698 						ctx->activate);
    699 			} else if (!ctx->genonly && !ctx->unsetact) {
    700 				dst_key_settime(key, DST_TIME_ACTIVATE,
    701 						ctx->now);
    702 			}
    703 
    704 			if (ctx->setrev) {
    705 				if (!ctx->wantksk) {
    706 					fprintf(stderr,
    707 						"%s: warning: Key is "
    708 						"not flagged as a KSK, but -R "
    709 						"was used. Revoking a ZSK is "
    710 						"legal, but undefined.\n",
    711 						program);
    712 				}
    713 				dst_key_settime(key, DST_TIME_REVOKE,
    714 						ctx->revokekey);
    715 			}
    716 
    717 			if (ctx->setinact) {
    718 				dst_key_settime(key, DST_TIME_INACTIVE,
    719 						ctx->inactive);
    720 			}
    721 
    722 			if (ctx->setdel) {
    723 				if (ctx->setinact &&
    724 				    ctx->deltime < ctx->inactive)
    725 				{
    726 					fprintf(stderr,
    727 						"%s: warning: Key is "
    728 						"scheduled to be deleted "
    729 						"before it is scheduled to be "
    730 						"made inactive.\n",
    731 						program);
    732 				}
    733 				dst_key_settime(key, DST_TIME_DELETE,
    734 						ctx->deltime);
    735 			}
    736 
    737 			if (ctx->setsyncadd) {
    738 				dst_key_settime(key, DST_TIME_SYNCPUBLISH,
    739 						ctx->syncadd);
    740 			}
    741 
    742 			if (ctx->setsyncdel) {
    743 				dst_key_settime(key, DST_TIME_SYNCDELETE,
    744 						ctx->syncdel);
    745 			}
    746 		} else {
    747 			if (ctx->setpub || ctx->setact || ctx->setrev ||
    748 			    ctx->setinact || ctx->setdel || ctx->unsetpub ||
    749 			    ctx->unsetact || ctx->unsetrev || ctx->unsetinact ||
    750 			    ctx->unsetdel || ctx->genonly || ctx->setsyncadd ||
    751 			    ctx->setsyncdel)
    752 			{
    753 				fatal("cannot use -C together with "
    754 				      "-P, -A, -R, -I, -D, or -G options");
    755 			}
    756 			/*
    757 			 * Compatibility mode: Private-key-format
    758 			 * should be set to 1.2.
    759 			 */
    760 			dst_key_setprivateformat(key, 1, 2);
    761 		}
    762 
    763 		/* Set the default key TTL */
    764 		if (ctx->setttl) {
    765 			dst_key_setttl(key, ctx->ttl);
    766 		}
    767 
    768 		/* Set dnssec-policy related metadata */
    769 		if (ctx->policy != NULL) {
    770 			dst_key_setnum(key, DST_NUM_LIFETIME, ctx->lifetime);
    771 			dst_key_setbool(key, DST_BOOL_KSK, ctx->ksk);
    772 			dst_key_setbool(key, DST_BOOL_ZSK, ctx->zsk);
    773 		}
    774 
    775 		/*
    776 		 * Do not overwrite an existing key, or create a key
    777 		 * if there is a risk of ID collision due to this key
    778 		 * or another key being revoked.
    779 		 */
    780 		if (key_collision(key, name, ctx->directory, mctx, ctx->tag_min,
    781 				  ctx->tag_max, NULL))
    782 		{
    783 			conflict = true;
    784 			if (null_key) {
    785 				dst_key_free(&key);
    786 				break;
    787 			}
    788 
    789 			if (verbose > 0) {
    790 				isc_buffer_clear(&buf);
    791 				ret = dst_key_buildfilename(
    792 					key, 0, ctx->directory, &buf);
    793 				if (ret == ISC_R_SUCCESS) {
    794 					fprintf(stderr,
    795 						"%s: %s already exists, or "
    796 						"might collide with another "
    797 						"key upon revokation.  "
    798 						"Generating a new key\n",
    799 						program, filename);
    800 				}
    801 			}
    802 
    803 			dst_key_free(&key);
    804 		}
    805 	} while (conflict);
    806 
    807 	if (conflict) {
    808 		fatal("cannot generate a null key due to possible key ID "
    809 		      "collision");
    810 	}
    811 
    812 	if (ctx->predecessor != NULL && prevkey != NULL) {
    813 		dst_key_setnum(prevkey, DST_NUM_SUCCESSOR, dst_key_id(key));
    814 		dst_key_setnum(key, DST_NUM_PREDECESSOR, dst_key_id(prevkey));
    815 
    816 		ret = dst_key_tofile(prevkey, ctx->options, ctx->directory);
    817 		if (ret != ISC_R_SUCCESS) {
    818 			char keystr[DST_KEY_FORMATSIZE];
    819 			dst_key_format(prevkey, keystr, sizeof(keystr));
    820 			fatal("failed to update predecessor %s: %s\n", keystr,
    821 			      isc_result_totext(ret));
    822 		}
    823 	}
    824 
    825 	ret = dst_key_tofile(key, ctx->options, ctx->directory);
    826 	if (ret != ISC_R_SUCCESS) {
    827 		char keystr[DST_KEY_FORMATSIZE];
    828 		dst_key_format(key, keystr, sizeof(keystr));
    829 		fatal("failed to write key %s: %s\n", keystr,
    830 		      isc_result_totext(ret));
    831 	}
    832 
    833 	isc_buffer_clear(&buf);
    834 	ret = dst_key_buildfilename(key, 0, NULL, &buf);
    835 	if (ret != ISC_R_SUCCESS) {
    836 		fatal("dst_key_buildfilename returned: %s\n",
    837 		      isc_result_totext(ret));
    838 	}
    839 	printf("%s\n", filename);
    840 
    841 	dst_key_free(&key);
    842 	if (prevkey != NULL) {
    843 		dst_key_free(&prevkey);
    844 	}
    845 }
    846 
    847 static void
    848 check_keystore_options(keygen_ctx_t *ctx) {
    849 	ctx->directory = dns_keystore_directory(ctx->keystore, NULL);
    850 	if (ctx->directory != NULL) {
    851 		isc_result_t ret = try_dir(ctx->directory);
    852 		if (ret != ISC_R_SUCCESS) {
    853 			fatal("cannot open directory %s: %s", ctx->directory,
    854 			      isc_result_totext(ret));
    855 		}
    856 	}
    857 }
    858 
    859 int
    860 main(int argc, char **argv) {
    861 	char *algname = NULL, *freeit = NULL;
    862 	char *classname = NULL;
    863 	char *endp;
    864 	isc_mem_t *mctx = NULL;
    865 	isc_result_t ret;
    866 	isc_textregion_t r;
    867 	const char *engine = NULL;
    868 	unsigned char c;
    869 	int ch;
    870 	bool set_fips_mode = false;
    871 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
    872 	OSSL_PROVIDER *fips = NULL, *base = NULL;
    873 #endif
    874 
    875 	keygen_ctx_t ctx = {
    876 		.options = DST_TYPE_PRIVATE | DST_TYPE_PUBLIC,
    877 		.prepub = -1,
    878 		.protocol = -1,
    879 		.size = -1,
    880 		.now = isc_stdtime_now(),
    881 	};
    882 
    883 	if (argc == 1) {
    884 		usage(EXIT_FAILURE);
    885 	}
    886 
    887 	isc_commandline_errprint = false;
    888 
    889 	/*
    890 	 * Process memory debugging argument first.
    891 	 */
    892 #define CMDLINE_FLAGS                                          \
    893 	"3A:a:b:Cc:D:d:E:Ff:GhI:i:K:k:L:l:M:m:n:P:p:qR:r:S:s:" \
    894 	"T:t:v:V"
    895 	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
    896 		switch (ch) {
    897 		case 'm':
    898 			if (strcasecmp(isc_commandline_argument, "record") == 0)
    899 			{
    900 				isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
    901 			}
    902 			if (strcasecmp(isc_commandline_argument, "trace") == 0)
    903 			{
    904 				isc_mem_debugging |= ISC_MEM_DEBUGTRACE;
    905 			}
    906 			if (strcasecmp(isc_commandline_argument, "usage") == 0)
    907 			{
    908 				isc_mem_debugging |= ISC_MEM_DEBUGUSAGE;
    909 			}
    910 			break;
    911 		default:
    912 			break;
    913 		}
    914 	}
    915 	isc_commandline_reset = true;
    916 
    917 	isc_mem_create(&mctx);
    918 
    919 	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
    920 		switch (ch) {
    921 		case '3':
    922 			ctx.use_nsec3 = true;
    923 			break;
    924 		case 'a':
    925 			algname = isc_commandline_argument;
    926 			break;
    927 		case 'b':
    928 			ctx.size = strtol(isc_commandline_argument, &endp, 10);
    929 			if (*endp != '\0' || ctx.size < 0) {
    930 				fatal("-b requires a non-negative number");
    931 			}
    932 			break;
    933 		case 'C':
    934 			ctx.oldstyle = true;
    935 			break;
    936 		case 'c':
    937 			classname = isc_commandline_argument;
    938 			break;
    939 		case 'd':
    940 			ctx.dbits = strtol(isc_commandline_argument, &endp, 10);
    941 			if (*endp != '\0' || ctx.dbits < 0) {
    942 				fatal("-d requires a non-negative number");
    943 			}
    944 			break;
    945 		case 'E':
    946 			engine = isc_commandline_argument;
    947 			break;
    948 		case 'f':
    949 			c = (unsigned char)(isc_commandline_argument[0]);
    950 			if (toupper(c) == 'K') {
    951 				ctx.wantksk = true;
    952 			} else if (toupper(c) == 'Z') {
    953 				ctx.wantzsk = true;
    954 			} else if (toupper(c) == 'R') {
    955 				ctx.wantrev = true;
    956 			} else {
    957 				fatal("unknown flag '%s'",
    958 				      isc_commandline_argument);
    959 			}
    960 			break;
    961 		case 'K':
    962 			ctx.directory = isc_commandline_argument;
    963 			ret = try_dir(ctx.directory);
    964 			if (ret != ISC_R_SUCCESS) {
    965 				fatal("cannot open directory %s: %s",
    966 				      ctx.directory, isc_result_totext(ret));
    967 			}
    968 			break;
    969 		case 'k':
    970 			ctx.policy = isc_commandline_argument;
    971 			break;
    972 		case 'L':
    973 			ctx.ttl = strtottl(isc_commandline_argument);
    974 			ctx.setttl = true;
    975 			break;
    976 		case 'l':
    977 			ctx.configfile = isc_commandline_argument;
    978 			break;
    979 		case 'n':
    980 			ctx.nametype = isc_commandline_argument;
    981 			break;
    982 		case 'M': {
    983 			unsigned long ul;
    984 			ctx.tag_min = ul = strtoul(isc_commandline_argument,
    985 						   &endp, 10);
    986 			if (*endp != ':' || ul > 0xffff) {
    987 				fatal("-M range invalid");
    988 			}
    989 			ctx.tag_max = ul = strtoul(endp + 1, &endp, 10);
    990 			if (*endp != '\0' || ul > 0xffff ||
    991 			    ctx.tag_max <= ctx.tag_min)
    992 			{
    993 				fatal("-M range invalid");
    994 			}
    995 			break;
    996 		}
    997 		case 'm':
    998 			break;
    999 		case 'p':
   1000 			ctx.protocol = strtol(isc_commandline_argument, &endp,
   1001 					      10);
   1002 			if (*endp != '\0' || ctx.protocol < 0 ||
   1003 			    ctx.protocol > 255)
   1004 			{
   1005 				fatal("-p must be followed by a number "
   1006 				      "[0..255]");
   1007 			}
   1008 			break;
   1009 		case 'q':
   1010 			ctx.quiet = true;
   1011 			break;
   1012 		case 'r':
   1013 			fatal("The -r option has been deprecated.\n"
   1014 			      "System random data is always used.\n");
   1015 			break;
   1016 		case 's':
   1017 			ctx.signatory = strtol(isc_commandline_argument, &endp,
   1018 					       10);
   1019 			if (*endp != '\0' || ctx.signatory < 0 ||
   1020 			    ctx.signatory > 15)
   1021 			{
   1022 				fatal("-s must be followed by a number "
   1023 				      "[0..15]");
   1024 			}
   1025 			break;
   1026 		case 'T':
   1027 			if (strcasecmp(isc_commandline_argument, "KEY") == 0) {
   1028 				ctx.options |= DST_TYPE_KEY;
   1029 			} else if (strcasecmp(isc_commandline_argument,
   1030 					      "DNSKE"
   1031 					      "Y") == 0)
   1032 			{
   1033 				/* default behavior */
   1034 			} else {
   1035 				fatal("unknown type '%s'",
   1036 				      isc_commandline_argument);
   1037 			}
   1038 			break;
   1039 		case 't':
   1040 			ctx.type = isc_commandline_argument;
   1041 			break;
   1042 		case 'v':
   1043 			endp = NULL;
   1044 			verbose = strtol(isc_commandline_argument, &endp, 0);
   1045 			if (*endp != '\0') {
   1046 				fatal("-v must be followed by a number");
   1047 			}
   1048 			break;
   1049 		case 'G':
   1050 			ctx.genonly = true;
   1051 			break;
   1052 		case 'P':
   1053 			/* -Psync ? */
   1054 			if (isoptarg("sync", argv, usage)) {
   1055 				if (ctx.setsyncadd) {
   1056 					fatal("-P sync specified more than "
   1057 					      "once");
   1058 				}
   1059 
   1060 				ctx.syncadd = strtotime(
   1061 					isc_commandline_argument, ctx.now,
   1062 					ctx.now, &ctx.setsyncadd);
   1063 				break;
   1064 			}
   1065 			(void)isoptarg("dnskey", argv, usage);
   1066 			if (ctx.setpub || ctx.unsetpub) {
   1067 				fatal("-P specified more than once");
   1068 			}
   1069 
   1070 			ctx.publish = strtotime(isc_commandline_argument,
   1071 						ctx.now, ctx.now, &ctx.setpub);
   1072 			ctx.unsetpub = !ctx.setpub;
   1073 			break;
   1074 		case 'A':
   1075 			if (ctx.setact || ctx.unsetact) {
   1076 				fatal("-A specified more than once");
   1077 			}
   1078 
   1079 			ctx.activate = strtotime(isc_commandline_argument,
   1080 						 ctx.now, ctx.now, &ctx.setact);
   1081 			ctx.unsetact = !ctx.setact;
   1082 			break;
   1083 		case 'R':
   1084 			if (ctx.setrev || ctx.unsetrev) {
   1085 				fatal("-R specified more than once");
   1086 			}
   1087 
   1088 			ctx.revokekey = strtotime(isc_commandline_argument,
   1089 						  ctx.now, ctx.now,
   1090 						  &ctx.setrev);
   1091 			ctx.unsetrev = !ctx.setrev;
   1092 			break;
   1093 		case 'I':
   1094 			if (ctx.setinact || ctx.unsetinact) {
   1095 				fatal("-I specified more than once");
   1096 			}
   1097 
   1098 			ctx.inactive = strtotime(isc_commandline_argument,
   1099 						 ctx.now, ctx.now,
   1100 						 &ctx.setinact);
   1101 			ctx.unsetinact = !ctx.setinact;
   1102 			break;
   1103 		case 'D':
   1104 			/* -Dsync ? */
   1105 			if (isoptarg("sync", argv, usage)) {
   1106 				if (ctx.setsyncdel) {
   1107 					fatal("-D sync specified more than "
   1108 					      "once");
   1109 				}
   1110 
   1111 				ctx.syncdel = strtotime(
   1112 					isc_commandline_argument, ctx.now,
   1113 					ctx.now, &ctx.setsyncdel);
   1114 				break;
   1115 			}
   1116 			(void)isoptarg("dnskey", argv, usage);
   1117 			if (ctx.setdel || ctx.unsetdel) {
   1118 				fatal("-D specified more than once");
   1119 			}
   1120 
   1121 			ctx.deltime = strtotime(isc_commandline_argument,
   1122 						ctx.now, ctx.now, &ctx.setdel);
   1123 			ctx.unsetdel = !ctx.setdel;
   1124 			break;
   1125 		case 'S':
   1126 			ctx.predecessor = isc_commandline_argument;
   1127 			break;
   1128 		case 'i':
   1129 			ctx.prepub = strtottl(isc_commandline_argument);
   1130 			break;
   1131 		case 'F':
   1132 			set_fips_mode = true;
   1133 			break;
   1134 		case '?':
   1135 			if (isc_commandline_option != '?') {
   1136 				fprintf(stderr, "%s: invalid argument -%c\n",
   1137 					program, isc_commandline_option);
   1138 			}
   1139 			/* Does not return. */
   1140 			usage(EXIT_FAILURE);
   1141 
   1142 		case 'h':
   1143 			/* Does not return. */
   1144 			usage(EXIT_SUCCESS);
   1145 
   1146 		case 'V':
   1147 			/* Does not return. */
   1148 			version(program);
   1149 
   1150 		default:
   1151 			fprintf(stderr, "%s: unhandled option -%c\n", program,
   1152 				isc_commandline_option);
   1153 			exit(EXIT_FAILURE);
   1154 		}
   1155 	}
   1156 
   1157 	if (!isatty(0)) {
   1158 		ctx.quiet = true;
   1159 	}
   1160 
   1161 	if (set_fips_mode) {
   1162 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
   1163 		fips = OSSL_PROVIDER_load(NULL, "fips");
   1164 		if (fips == NULL) {
   1165 			ERR_clear_error();
   1166 			fatal("Failed to load FIPS provider");
   1167 		}
   1168 		base = OSSL_PROVIDER_load(NULL, "base");
   1169 		if (base == NULL) {
   1170 			OSSL_PROVIDER_unload(fips);
   1171 			ERR_clear_error();
   1172 			fatal("Failed to load base provider");
   1173 		}
   1174 #endif
   1175 		if (!isc_fips_mode()) {
   1176 			if (isc_fips_set_mode(1) != ISC_R_SUCCESS) {
   1177 				fatal("setting FIPS mode failed");
   1178 			}
   1179 		}
   1180 	}
   1181 
   1182 	ret = dst_lib_init(mctx, engine);
   1183 	if (ret != ISC_R_SUCCESS) {
   1184 		fatal("could not initialize dst: %s", isc_result_totext(ret));
   1185 	}
   1186 
   1187 	/*
   1188 	 * After dst_lib_init which will set FIPS mode if requested
   1189 	 * at build time.  The minumums are both raised to 2048.
   1190 	 */
   1191 	if (isc_fips_mode()) {
   1192 		min_rsa = min_dh = 2048;
   1193 	}
   1194 
   1195 	setup_logging(mctx, &lctx);
   1196 
   1197 	ctx.rdclass = strtoclass(classname);
   1198 
   1199 	if (ctx.configfile == NULL || ctx.configfile[0] == '\0') {
   1200 		ctx.configfile = NAMED_CONFFILE;
   1201 	}
   1202 
   1203 	if (ctx.predecessor == NULL) {
   1204 		if (argc < isc_commandline_index + 1) {
   1205 			fatal("the key name was not specified");
   1206 		}
   1207 		if (argc > isc_commandline_index + 1) {
   1208 			fatal("extraneous arguments");
   1209 		}
   1210 	}
   1211 
   1212 	if (ctx.predecessor == NULL && ctx.policy == NULL) {
   1213 		if (algname == NULL) {
   1214 			fatal("no algorithm specified");
   1215 		}
   1216 		r.base = algname;
   1217 		r.length = strlen(algname);
   1218 		ret = dns_secalg_fromtext(&ctx.alg, &r);
   1219 		if (ret != ISC_R_SUCCESS) {
   1220 			fatal("unknown algorithm %s", algname);
   1221 		}
   1222 		if (!dst_algorithm_supported(ctx.alg)) {
   1223 			fatal("unsupported algorithm: %s", algname);
   1224 		}
   1225 	}
   1226 
   1227 	if (ctx.policy != NULL) {
   1228 		if (ctx.nametype != NULL) {
   1229 			fatal("-k and -n cannot be used together");
   1230 		}
   1231 		if (ctx.predecessor != NULL) {
   1232 			fatal("-k and -S cannot be used together");
   1233 		}
   1234 		if (ctx.oldstyle) {
   1235 			fatal("-k and -C cannot be used together");
   1236 		}
   1237 		if (ctx.setttl) {
   1238 			fatal("-k and -L cannot be used together");
   1239 		}
   1240 		if (ctx.prepub > 0) {
   1241 			fatal("-k and -i cannot be used together");
   1242 		}
   1243 		if (ctx.size != -1) {
   1244 			fatal("-k and -b cannot be used together");
   1245 		}
   1246 		if (ctx.wantrev) {
   1247 			fatal("-k and -fR cannot be used together");
   1248 		}
   1249 		if (ctx.options & DST_TYPE_KEY) {
   1250 			fatal("-k and -T KEY cannot be used together");
   1251 		}
   1252 		if (ctx.use_nsec3) {
   1253 			fatal("-k and -3 cannot be used together");
   1254 		}
   1255 
   1256 		ctx.options |= DST_TYPE_STATE;
   1257 
   1258 		if (strcmp(ctx.policy, "default") == 0) {
   1259 			ctx.use_nsec3 = false;
   1260 			ctx.alg = DST_ALG_ECDSA256;
   1261 			ctx.size = 0;
   1262 			ctx.ttl = 3600;
   1263 			ctx.setttl = true;
   1264 			ctx.ksk = true;
   1265 			ctx.zsk = true;
   1266 			ctx.lifetime = 0;
   1267 			ctx.tag_min = 0;
   1268 			ctx.tag_max = 0xffff;
   1269 
   1270 			keygen(&ctx, mctx, argc, argv);
   1271 		} else {
   1272 			cfg_parser_t *parser = NULL;
   1273 			cfg_obj_t *config = NULL;
   1274 			dns_kasp_t *kasp = NULL;
   1275 			dns_kasp_key_t *kaspkey = NULL;
   1276 
   1277 			RUNTIME_CHECK(cfg_parser_create(mctx, lctx, &parser) ==
   1278 				      ISC_R_SUCCESS);
   1279 			if (cfg_parse_file(parser, ctx.configfile,
   1280 					   &cfg_type_namedconf,
   1281 					   &config) != ISC_R_SUCCESS)
   1282 			{
   1283 				fatal("unable to load dnssec-policy '%s' from "
   1284 				      "'%s'",
   1285 				      ctx.policy, ctx.configfile);
   1286 			}
   1287 
   1288 			kasp_from_conf(config, mctx, lctx, ctx.policy,
   1289 				       ctx.directory, engine, &kasp);
   1290 			if (kasp == NULL) {
   1291 				fatal("failed to load dnssec-policy '%s'",
   1292 				      ctx.policy);
   1293 			}
   1294 			if (ISC_LIST_EMPTY(dns_kasp_keys(kasp))) {
   1295 				fatal("dnssec-policy '%s' has no keys "
   1296 				      "configured",
   1297 				      ctx.policy);
   1298 			}
   1299 
   1300 			ctx.ttl = dns_kasp_dnskeyttl(kasp);
   1301 			ctx.setttl = true;
   1302 
   1303 			for (kaspkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
   1304 			     kaspkey != NULL;
   1305 			     kaspkey = ISC_LIST_NEXT(kaspkey, link))
   1306 			{
   1307 				ctx.use_nsec3 = false;
   1308 				ctx.alg = dns_kasp_key_algorithm(kaspkey);
   1309 				ctx.size = dns_kasp_key_size(kaspkey);
   1310 				ctx.ksk = dns_kasp_key_ksk(kaspkey);
   1311 				ctx.zsk = dns_kasp_key_zsk(kaspkey);
   1312 				ctx.lifetime = dns_kasp_key_lifetime(kaspkey);
   1313 				ctx.keystore = dns_kasp_key_keystore(kaspkey);
   1314 				if (ctx.keystore != NULL) {
   1315 					check_keystore_options(&ctx);
   1316 				}
   1317 				ctx.tag_min = dns_kasp_key_tagmin(kaspkey);
   1318 				ctx.tag_max = dns_kasp_key_tagmax(kaspkey);
   1319 				if ((ctx.ksk && !ctx.wantksk && ctx.wantzsk) ||
   1320 				    (ctx.zsk && !ctx.wantzsk && ctx.wantksk))
   1321 				{
   1322 					continue;
   1323 				}
   1324 				keygen(&ctx, mctx, argc, argv);
   1325 			}
   1326 
   1327 			dns_kasp_detach(&kasp);
   1328 			cfg_obj_destroy(parser, &config);
   1329 			cfg_parser_destroy(&parser);
   1330 		}
   1331 	} else {
   1332 		keygen(&ctx, mctx, argc, argv);
   1333 	}
   1334 
   1335 	cleanup_logging(&lctx);
   1336 	dst_lib_destroy();
   1337 	if (verbose > 10) {
   1338 		isc_mem_stats(mctx, stdout);
   1339 	}
   1340 	isc_mem_destroy(&mctx);
   1341 
   1342 #if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_API_LEVEL >= 30000
   1343 	if (base != NULL) {
   1344 		OSSL_PROVIDER_unload(base);
   1345 	}
   1346 	if (fips != NULL) {
   1347 		OSSL_PROVIDER_unload(fips);
   1348 	}
   1349 #endif
   1350 	if (freeit != NULL) {
   1351 		free(freeit);
   1352 	}
   1353 
   1354 	return 0;
   1355 }
   1356