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