"Fossies" - the Fresh Open Source Software Archive

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