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