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