"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/bin/dnssec/dnssec-keygen.c" (4 Sep 2020, 34443 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dnssec-keygen.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 9.17.2_vs_9.17.3.

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