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