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