"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/dns/dst_parse.c" (4 Sep 2020, 18551 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 "dst_parse.c" see the Fossies "Dox" file reference documentation.

    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 #include "dst_parse.h"
   27 #include <inttypes.h>
   28 #include <stdbool.h>
   29 
   30 #include <isc/base64.h>
   31 #include <isc/dir.h>
   32 #include <isc/file.h>
   33 #include <isc/fsaccess.h>
   34 #include <isc/lex.h>
   35 #include <isc/mem.h>
   36 #include <isc/print.h>
   37 #include <isc/stdtime.h>
   38 #include <isc/string.h>
   39 #include <isc/util.h>
   40 
   41 #include <pk11/site.h>
   42 
   43 #include <dns/log.h>
   44 #include <dns/time.h>
   45 
   46 #include "dst/result.h"
   47 #include "dst_internal.h"
   48 
   49 #define DST_AS_STR(t) ((t).value.as_textregion.base)
   50 
   51 #define PRIVATE_KEY_STR "Private-key-format:"
   52 #define ALGORITHM_STR   "Algorithm:"
   53 
   54 #define TIMING_NTAGS (DST_MAX_TIMES + 1)
   55 static const char *timetags[TIMING_NTAGS] = {
   56     "Created:",    "Publish:", "Activate:",  "Revoke:",
   57     "Inactive:",   "Delete:",  "DSPublish:", "SyncPublish:",
   58     "SyncDelete:", NULL,       NULL,     NULL,
   59     NULL
   60 };
   61 
   62 #define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1)
   63 static const char *numerictags[NUMERIC_NTAGS] = {
   64     "Predecessor:", "Successor:", "MaxTTL:", "RollPeriod:", NULL
   65 };
   66 
   67 struct parse_map {
   68     const int value;
   69     const char *tag;
   70 };
   71 
   72 static struct parse_map map[] = { { TAG_RSA_MODULUS, "Modulus:" },
   73                   { TAG_RSA_PUBLICEXPONENT, "PublicExponent:" },
   74                   { TAG_RSA_PRIVATEEXPONENT, "PrivateExponent"
   75                                  ":" },
   76                   { TAG_RSA_PRIME1, "Prime1:" },
   77                   { TAG_RSA_PRIME2, "Prime2:" },
   78                   { TAG_RSA_EXPONENT1, "Exponent1:" },
   79                   { TAG_RSA_EXPONENT2, "Exponent2:" },
   80                   { TAG_RSA_COEFFICIENT, "Coefficient:" },
   81                   { TAG_RSA_ENGINE, "Engine:" },
   82                   { TAG_RSA_LABEL, "Label:" },
   83 
   84                   { TAG_DH_PRIME, "Prime(p):" },
   85                   { TAG_DH_GENERATOR, "Generator(g):" },
   86                   { TAG_DH_PRIVATE, "Private_value(x):" },
   87                   { TAG_DH_PUBLIC, "Public_value(y):" },
   88 
   89                   { TAG_ECDSA_PRIVATEKEY, "PrivateKey:" },
   90                   { TAG_ECDSA_ENGINE, "Engine:" },
   91                   { TAG_ECDSA_LABEL, "Label:" },
   92 
   93                   { TAG_EDDSA_PRIVATEKEY, "PrivateKey:" },
   94                   { TAG_EDDSA_ENGINE, "Engine:" },
   95                   { TAG_EDDSA_LABEL, "Label:" },
   96 
   97                   { TAG_HMACMD5_KEY, "Key:" },
   98                   { TAG_HMACMD5_BITS, "Bits:" },
   99 
  100                   { TAG_HMACSHA1_KEY, "Key:" },
  101                   { TAG_HMACSHA1_BITS, "Bits:" },
  102 
  103                   { TAG_HMACSHA224_KEY, "Key:" },
  104                   { TAG_HMACSHA224_BITS, "Bits:" },
  105 
  106                   { TAG_HMACSHA256_KEY, "Key:" },
  107                   { TAG_HMACSHA256_BITS, "Bits:" },
  108 
  109                   { TAG_HMACSHA384_KEY, "Key:" },
  110                   { TAG_HMACSHA384_BITS, "Bits:" },
  111 
  112                   { TAG_HMACSHA512_KEY, "Key:" },
  113                   { TAG_HMACSHA512_BITS, "Bits:" },
  114 
  115                   { 0, NULL } };
  116 
  117 static int
  118 find_value(const char *s, const unsigned int alg) {
  119     int i;
  120 
  121     for (i = 0; map[i].tag != NULL; i++) {
  122         if (strcasecmp(s, map[i].tag) == 0 &&
  123             (TAG_ALG(map[i].value) == alg)) {
  124             return (map[i].value);
  125         }
  126     }
  127     return (-1);
  128 }
  129 
  130 static const char *
  131 find_tag(const int value) {
  132     int i;
  133 
  134     for (i = 0;; i++) {
  135         if (map[i].tag == NULL) {
  136             return (NULL);
  137         } else if (value == map[i].value) {
  138             return (map[i].tag);
  139         }
  140     }
  141 }
  142 
  143 static int
  144 find_metadata(const char *s, const char *tags[], int ntags) {
  145     int i;
  146 
  147     for (i = 0; i < ntags; i++) {
  148         if (tags[i] != NULL && strcasecmp(s, tags[i]) == 0) {
  149             return (i);
  150         }
  151     }
  152 
  153     return (-1);
  154 }
  155 
  156 static int
  157 find_timedata(const char *s) {
  158     return (find_metadata(s, timetags, TIMING_NTAGS));
  159 }
  160 
  161 static int
  162 find_numericdata(const char *s) {
  163     return (find_metadata(s, numerictags, NUMERIC_NTAGS));
  164 }
  165 
  166 static int
  167 check_rsa(const dst_private_t *priv, bool external) {
  168     int i, j;
  169     bool have[RSA_NTAGS];
  170     bool ok;
  171     unsigned int mask;
  172 
  173     if (external) {
  174         return ((priv->nelements == 0) ? 0 : -1);
  175     }
  176 
  177     for (i = 0; i < RSA_NTAGS; i++) {
  178         have[i] = false;
  179     }
  180 
  181     for (j = 0; j < priv->nelements; j++) {
  182         for (i = 0; i < RSA_NTAGS; i++) {
  183             if (priv->elements[j].tag == TAG(DST_ALG_RSA, i)) {
  184                 break;
  185             }
  186         }
  187         if (i == RSA_NTAGS) {
  188             return (-1);
  189         }
  190         have[i] = true;
  191     }
  192 
  193     mask = (1ULL << TAG_SHIFT) - 1;
  194 
  195     if (have[TAG_RSA_ENGINE & mask]) {
  196         ok = have[TAG_RSA_MODULUS & mask] &&
  197              have[TAG_RSA_PUBLICEXPONENT & mask] &&
  198              have[TAG_RSA_LABEL & mask];
  199     } else {
  200         ok = have[TAG_RSA_MODULUS & mask] &&
  201              have[TAG_RSA_PUBLICEXPONENT & mask] &&
  202              have[TAG_RSA_PRIVATEEXPONENT & mask] &&
  203              have[TAG_RSA_PRIME1 & mask] &&
  204              have[TAG_RSA_PRIME2 & mask] &&
  205              have[TAG_RSA_EXPONENT1 & mask] &&
  206              have[TAG_RSA_EXPONENT2 & mask] &&
  207              have[TAG_RSA_COEFFICIENT & mask];
  208     }
  209     return (ok ? 0 : -1);
  210 }
  211 
  212 static int
  213 check_dh(const dst_private_t *priv) {
  214     int i, j;
  215     if (priv->nelements != DH_NTAGS) {
  216         return (-1);
  217     }
  218     for (i = 0; i < DH_NTAGS; i++) {
  219         for (j = 0; j < priv->nelements; j++) {
  220             if (priv->elements[j].tag == TAG(DST_ALG_DH, i)) {
  221                 break;
  222             }
  223         }
  224         if (j == priv->nelements) {
  225             return (-1);
  226         }
  227     }
  228     return (0);
  229 }
  230 
  231 static int
  232 check_ecdsa(const dst_private_t *priv, bool external) {
  233     int i, j;
  234     bool have[ECDSA_NTAGS];
  235     bool ok;
  236     unsigned int mask;
  237 
  238     if (external) {
  239         return ((priv->nelements == 0) ? 0 : -1);
  240     }
  241 
  242     for (i = 0; i < ECDSA_NTAGS; i++) {
  243         have[i] = false;
  244     }
  245     for (j = 0; j < priv->nelements; j++) {
  246         for (i = 0; i < ECDSA_NTAGS; i++) {
  247             if (priv->elements[j].tag == TAG(DST_ALG_ECDSA256, i)) {
  248                 break;
  249             }
  250         }
  251         if (i == ECDSA_NTAGS) {
  252             return (-1);
  253         }
  254         have[i] = true;
  255     }
  256 
  257     mask = (1ULL << TAG_SHIFT) - 1;
  258 
  259     if (have[TAG_ECDSA_ENGINE & mask]) {
  260         ok = have[TAG_ECDSA_LABEL & mask];
  261     } else {
  262         ok = have[TAG_ECDSA_PRIVATEKEY & mask];
  263     }
  264     return (ok ? 0 : -1);
  265 }
  266 
  267 static int
  268 check_eddsa(const dst_private_t *priv, bool external) {
  269     int i, j;
  270     bool have[EDDSA_NTAGS];
  271     bool ok;
  272     unsigned int mask;
  273 
  274     if (external) {
  275         return ((priv->nelements == 0) ? 0 : -1);
  276     }
  277 
  278     for (i = 0; i < EDDSA_NTAGS; i++) {
  279         have[i] = false;
  280     }
  281     for (j = 0; j < priv->nelements; j++) {
  282         for (i = 0; i < EDDSA_NTAGS; i++) {
  283             if (priv->elements[j].tag == TAG(DST_ALG_ED25519, i)) {
  284                 break;
  285             }
  286         }
  287         if (i == EDDSA_NTAGS) {
  288             return (-1);
  289         }
  290         have[i] = true;
  291     }
  292 
  293     mask = (1ULL << TAG_SHIFT) - 1;
  294 
  295     if (have[TAG_EDDSA_ENGINE & mask]) {
  296         ok = have[TAG_EDDSA_LABEL & mask];
  297     } else {
  298         ok = have[TAG_EDDSA_PRIVATEKEY & mask];
  299     }
  300     return (ok ? 0 : -1);
  301 }
  302 
  303 static int
  304 check_hmac_md5(const dst_private_t *priv, bool old) {
  305     int i, j;
  306 
  307     if (priv->nelements != HMACMD5_NTAGS) {
  308         /*
  309          * If this is a good old format and we are accepting
  310          * the old format return success.
  311          */
  312         if (old && priv->nelements == OLD_HMACMD5_NTAGS &&
  313             priv->elements[0].tag == TAG_HMACMD5_KEY)
  314         {
  315             return (0);
  316         }
  317         return (-1);
  318     }
  319     /*
  320      * We must be new format at this point.
  321      */
  322     for (i = 0; i < HMACMD5_NTAGS; i++) {
  323         for (j = 0; j < priv->nelements; j++) {
  324             if (priv->elements[j].tag == TAG(DST_ALG_HMACMD5, i)) {
  325                 break;
  326             }
  327         }
  328         if (j == priv->nelements) {
  329             return (-1);
  330         }
  331     }
  332     return (0);
  333 }
  334 
  335 static int
  336 check_hmac_sha(const dst_private_t *priv, unsigned int ntags,
  337            unsigned int alg) {
  338     unsigned int i, j;
  339     if (priv->nelements != ntags) {
  340         return (-1);
  341     }
  342     for (i = 0; i < ntags; i++) {
  343         for (j = 0; j < priv->nelements; j++) {
  344             if (priv->elements[j].tag == TAG(alg, i)) {
  345                 break;
  346             }
  347         }
  348         if (j == priv->nelements) {
  349             return (-1);
  350         }
  351     }
  352     return (0);
  353 }
  354 
  355 static int
  356 check_data(const dst_private_t *priv, const unsigned int alg, bool old,
  357        bool external) {
  358     /* XXXVIX this switch statement is too sparse to gen a jump table. */
  359     switch (alg) {
  360     case DST_ALG_RSA:
  361     case DST_ALG_RSASHA1:
  362     case DST_ALG_NSEC3RSASHA1:
  363     case DST_ALG_RSASHA256:
  364     case DST_ALG_RSASHA512:
  365         return (check_rsa(priv, external));
  366     case DST_ALG_DH:
  367         return (check_dh(priv));
  368     case DST_ALG_ECDSA256:
  369     case DST_ALG_ECDSA384:
  370         return (check_ecdsa(priv, external));
  371     case DST_ALG_ED25519:
  372     case DST_ALG_ED448:
  373         return (check_eddsa(priv, external));
  374     case DST_ALG_HMACMD5:
  375         return (check_hmac_md5(priv, old));
  376     case DST_ALG_HMACSHA1:
  377         return (check_hmac_sha(priv, HMACSHA1_NTAGS, alg));
  378     case DST_ALG_HMACSHA224:
  379         return (check_hmac_sha(priv, HMACSHA224_NTAGS, alg));
  380     case DST_ALG_HMACSHA256:
  381         return (check_hmac_sha(priv, HMACSHA256_NTAGS, alg));
  382     case DST_ALG_HMACSHA384:
  383         return (check_hmac_sha(priv, HMACSHA384_NTAGS, alg));
  384     case DST_ALG_HMACSHA512:
  385         return (check_hmac_sha(priv, HMACSHA512_NTAGS, alg));
  386     default:
  387         return (DST_R_UNSUPPORTEDALG);
  388     }
  389 }
  390 
  391 void
  392 dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) {
  393     int i;
  394 
  395     if (priv == NULL) {
  396         return;
  397     }
  398     for (i = 0; i < priv->nelements; i++) {
  399         if (priv->elements[i].data == NULL) {
  400             continue;
  401         }
  402         memset(priv->elements[i].data, 0, MAXFIELDSIZE);
  403         isc_mem_put(mctx, priv->elements[i].data, MAXFIELDSIZE);
  404     }
  405     priv->nelements = 0;
  406 }
  407 
  408 isc_result_t
  409 dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
  410               isc_mem_t *mctx, dst_private_t *priv) {
  411     int n = 0, major, minor, check;
  412     isc_buffer_t b;
  413     isc_token_t token;
  414     unsigned char *data = NULL;
  415     unsigned int opt = ISC_LEXOPT_EOL;
  416     isc_stdtime_t when;
  417     isc_result_t ret;
  418     bool external = false;
  419 
  420     REQUIRE(priv != NULL);
  421 
  422     priv->nelements = 0;
  423     memset(priv->elements, 0, sizeof(priv->elements));
  424 
  425 #define NEXTTOKEN(lex, opt, token)                       \
  426     do {                                             \
  427         ret = isc_lex_gettoken(lex, opt, token); \
  428         if (ret != ISC_R_SUCCESS)                \
  429             goto fail;                       \
  430     } while (0)
  431 
  432 #define READLINE(lex, opt, token)                        \
  433     do {                                             \
  434         ret = isc_lex_gettoken(lex, opt, token); \
  435         if (ret == ISC_R_EOF)                    \
  436             break;                           \
  437         else if (ret != ISC_R_SUCCESS)           \
  438             goto fail;                       \
  439     } while ((*token).type != isc_tokentype_eol)
  440 
  441     /*
  442      * Read the description line.
  443      */
  444     NEXTTOKEN(lex, opt, &token);
  445     if (token.type != isc_tokentype_string ||
  446         strcmp(DST_AS_STR(token), PRIVATE_KEY_STR) != 0)
  447     {
  448         ret = DST_R_INVALIDPRIVATEKEY;
  449         goto fail;
  450     }
  451 
  452     NEXTTOKEN(lex, opt, &token);
  453     if (token.type != isc_tokentype_string || (DST_AS_STR(token))[0] != 'v')
  454     {
  455         ret = DST_R_INVALIDPRIVATEKEY;
  456         goto fail;
  457     }
  458     if (sscanf(DST_AS_STR(token), "v%d.%d", &major, &minor) != 2) {
  459         ret = DST_R_INVALIDPRIVATEKEY;
  460         goto fail;
  461     }
  462 
  463     if (major > DST_MAJOR_VERSION) {
  464         ret = DST_R_INVALIDPRIVATEKEY;
  465         goto fail;
  466     }
  467 
  468     /*
  469      * Store the private key format version number
  470      */
  471     dst_key_setprivateformat(key, major, minor);
  472 
  473     READLINE(lex, opt, &token);
  474 
  475     /*
  476      * Read the algorithm line.
  477      */
  478     NEXTTOKEN(lex, opt, &token);
  479     if (token.type != isc_tokentype_string ||
  480         strcmp(DST_AS_STR(token), ALGORITHM_STR) != 0)
  481     {
  482         ret = DST_R_INVALIDPRIVATEKEY;
  483         goto fail;
  484     }
  485 
  486     NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
  487     if (token.type != isc_tokentype_number ||
  488         token.value.as_ulong != (unsigned long)dst_key_alg(key))
  489     {
  490         ret = DST_R_INVALIDPRIVATEKEY;
  491         goto fail;
  492     }
  493 
  494     READLINE(lex, opt, &token);
  495 
  496     /*
  497      * Read the key data.
  498      */
  499     for (n = 0; n < MAXFIELDS; n++) {
  500         int tag;
  501         isc_region_t r;
  502         do {
  503             ret = isc_lex_gettoken(lex, opt, &token);
  504             if (ret == ISC_R_EOF) {
  505                 goto done;
  506             }
  507             if (ret != ISC_R_SUCCESS) {
  508                 goto fail;
  509             }
  510         } while (token.type == isc_tokentype_eol);
  511 
  512         if (token.type != isc_tokentype_string) {
  513             ret = DST_R_INVALIDPRIVATEKEY;
  514             goto fail;
  515         }
  516 
  517         if (strcmp(DST_AS_STR(token), "External:") == 0) {
  518             external = true;
  519             goto next;
  520         }
  521 
  522         /* Numeric metadata */
  523         tag = find_numericdata(DST_AS_STR(token));
  524         if (tag >= 0) {
  525             INSIST(tag < NUMERIC_NTAGS);
  526 
  527             NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
  528             if (token.type != isc_tokentype_number) {
  529                 ret = DST_R_INVALIDPRIVATEKEY;
  530                 goto fail;
  531             }
  532 
  533             dst_key_setnum(key, tag, token.value.as_ulong);
  534             goto next;
  535         }
  536 
  537         /* Timing metadata */
  538         tag = find_timedata(DST_AS_STR(token));
  539         if (tag >= 0) {
  540             INSIST(tag < TIMING_NTAGS);
  541 
  542             NEXTTOKEN(lex, opt, &token);
  543             if (token.type != isc_tokentype_string) {
  544                 ret = DST_R_INVALIDPRIVATEKEY;
  545                 goto fail;
  546             }
  547 
  548             ret = dns_time32_fromtext(DST_AS_STR(token), &when);
  549             if (ret != ISC_R_SUCCESS) {
  550                 goto fail;
  551             }
  552 
  553             dst_key_settime(key, tag, when);
  554 
  555             goto next;
  556         }
  557 
  558         /* Key data */
  559         tag = find_value(DST_AS_STR(token), alg);
  560         if (tag < 0 && minor > DST_MINOR_VERSION) {
  561             goto next;
  562         } else if (tag < 0) {
  563             ret = DST_R_INVALIDPRIVATEKEY;
  564             goto fail;
  565         }
  566 
  567         priv->elements[n].tag = tag;
  568 
  569         data = isc_mem_get(mctx, MAXFIELDSIZE);
  570 
  571         isc_buffer_init(&b, data, MAXFIELDSIZE);
  572         ret = isc_base64_tobuffer(lex, &b, -1);
  573         if (ret != ISC_R_SUCCESS) {
  574             goto fail;
  575         }
  576 
  577         isc_buffer_usedregion(&b, &r);
  578         priv->elements[n].length = r.length;
  579         priv->elements[n].data = r.base;
  580         priv->nelements++;
  581 
  582     next:
  583         READLINE(lex, opt, &token);
  584         data = NULL;
  585     }
  586 
  587 done:
  588     if (external && priv->nelements != 0) {
  589         ret = DST_R_INVALIDPRIVATEKEY;
  590         goto fail;
  591     }
  592 
  593     check = check_data(priv, alg, true, external);
  594     if (check < 0) {
  595         ret = DST_R_INVALIDPRIVATEKEY;
  596         goto fail;
  597     } else if (check != ISC_R_SUCCESS) {
  598         ret = check;
  599         goto fail;
  600     }
  601 
  602     key->external = external;
  603 
  604     return (ISC_R_SUCCESS);
  605 
  606 fail:
  607     dst__privstruct_free(priv, mctx);
  608     if (data != NULL) {
  609         isc_mem_put(mctx, data, MAXFIELDSIZE);
  610     }
  611 
  612     return (ret);
  613 }
  614 
  615 isc_result_t
  616 dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
  617               const char *directory) {
  618     FILE *fp;
  619     isc_result_t result;
  620     char filename[NAME_MAX];
  621     char buffer[MAXFIELDSIZE * 2];
  622     isc_fsaccess_t access;
  623     isc_stdtime_t when;
  624     uint32_t value;
  625     isc_buffer_t b;
  626     isc_region_t r;
  627     int major, minor;
  628     mode_t mode;
  629     int i, ret;
  630 
  631     REQUIRE(priv != NULL);
  632 
  633     ret = check_data(priv, dst_key_alg(key), false, key->external);
  634     if (ret < 0) {
  635         return (DST_R_INVALIDPRIVATEKEY);
  636     } else if (ret != ISC_R_SUCCESS) {
  637         return (ret);
  638     }
  639 
  640     isc_buffer_init(&b, filename, sizeof(filename));
  641     result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &b);
  642     if (result != ISC_R_SUCCESS) {
  643         return (result);
  644     }
  645 
  646     result = isc_file_mode(filename, &mode);
  647     if (result == ISC_R_SUCCESS && mode != 0600) {
  648         /* File exists; warn that we are changing its permissions */
  649         int level;
  650 
  651 #ifdef _WIN32
  652         /* Windows security model is pretty different,
  653          * e.g., there is no umask... */
  654         level = ISC_LOG_NOTICE;
  655 #else  /* ifdef _WIN32 */
  656         level = ISC_LOG_WARNING;
  657 #endif /* ifdef _WIN32 */
  658         isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
  659                   DNS_LOGMODULE_DNSSEC, level,
  660                   "Permissions on the file %s "
  661                   "have changed from 0%o to 0600 as "
  662                   "a result of this operation.",
  663                   filename, (unsigned int)mode);
  664     }
  665 
  666     if ((fp = fopen(filename, "w")) == NULL) {
  667         return (DST_R_WRITEERROR);
  668     }
  669 
  670     access = 0;
  671     isc_fsaccess_add(ISC_FSACCESS_OWNER,
  672              ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, &access);
  673     (void)isc_fsaccess_set(filename, access);
  674 
  675     dst_key_getprivateformat(key, &major, &minor);
  676     if (major == 0 && minor == 0) {
  677         major = DST_MAJOR_VERSION;
  678         minor = DST_MINOR_VERSION;
  679     }
  680 
  681     /* XXXDCL return value should be checked for full filesystem */
  682     fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, major, minor);
  683 
  684     fprintf(fp, "%s %u ", ALGORITHM_STR, dst_key_alg(key));
  685 
  686     /* XXXVIX this switch statement is too sparse to gen a jump table. */
  687     switch (dst_key_alg(key)) {
  688     case DST_ALG_DH:
  689         fprintf(fp, "(DH)\n");
  690         break;
  691     case DST_ALG_RSASHA1:
  692         fprintf(fp, "(RSASHA1)\n");
  693         break;
  694     case DST_ALG_NSEC3RSASHA1:
  695         fprintf(fp, "(NSEC3RSASHA1)\n");
  696         break;
  697     case DST_ALG_RSASHA256:
  698         fprintf(fp, "(RSASHA256)\n");
  699         break;
  700     case DST_ALG_RSASHA512:
  701         fprintf(fp, "(RSASHA512)\n");
  702         break;
  703     case DST_ALG_ECDSA256:
  704         fprintf(fp, "(ECDSAP256SHA256)\n");
  705         break;
  706     case DST_ALG_ECDSA384:
  707         fprintf(fp, "(ECDSAP384SHA384)\n");
  708         break;
  709     case DST_ALG_ED25519:
  710         fprintf(fp, "(ED25519)\n");
  711         break;
  712     case DST_ALG_ED448:
  713         fprintf(fp, "(ED448)\n");
  714         break;
  715     case DST_ALG_HMACMD5:
  716         fprintf(fp, "(HMAC_MD5)\n");
  717         break;
  718     case DST_ALG_HMACSHA1:
  719         fprintf(fp, "(HMAC_SHA1)\n");
  720         break;
  721     case DST_ALG_HMACSHA224:
  722         fprintf(fp, "(HMAC_SHA224)\n");
  723         break;
  724     case DST_ALG_HMACSHA256:
  725         fprintf(fp, "(HMAC_SHA256)\n");
  726         break;
  727     case DST_ALG_HMACSHA384:
  728         fprintf(fp, "(HMAC_SHA384)\n");
  729         break;
  730     case DST_ALG_HMACSHA512:
  731         fprintf(fp, "(HMAC_SHA512)\n");
  732         break;
  733     default:
  734         fprintf(fp, "(?)\n");
  735         break;
  736     }
  737 
  738     for (i = 0; i < priv->nelements; i++) {
  739         const char *s;
  740 
  741         s = find_tag(priv->elements[i].tag);
  742 
  743         r.base = priv->elements[i].data;
  744         r.length = priv->elements[i].length;
  745         isc_buffer_init(&b, buffer, sizeof(buffer));
  746         result = isc_base64_totext(&r, sizeof(buffer), "", &b);
  747         if (result != ISC_R_SUCCESS) {
  748             fclose(fp);
  749             return (DST_R_INVALIDPRIVATEKEY);
  750         }
  751         isc_buffer_usedregion(&b, &r);
  752 
  753         fprintf(fp, "%s %.*s\n", s, (int)r.length, r.base);
  754     }
  755 
  756     if (key->external) {
  757         fprintf(fp, "External:\n");
  758     }
  759 
  760     /* Add the metadata tags */
  761     if (major > 1 || (major == 1 && minor >= 3)) {
  762         for (i = 0; i < NUMERIC_NTAGS; i++) {
  763             result = dst_key_getnum(key, i, &value);
  764             if (result != ISC_R_SUCCESS) {
  765                 continue;
  766             }
  767             if (numerictags[i] != NULL) {
  768                 fprintf(fp, "%s %u\n", numerictags[i], value);
  769             }
  770         }
  771         for (i = 0; i < TIMING_NTAGS; i++) {
  772             result = dst_key_gettime(key, i, &when);
  773             if (result != ISC_R_SUCCESS) {
  774                 continue;
  775             }
  776 
  777             isc_buffer_init(&b, buffer, sizeof(buffer));
  778             result = dns_time32_totext(when, &b);
  779             if (result != ISC_R_SUCCESS) {
  780                 fclose(fp);
  781                 return (DST_R_INVALIDPRIVATEKEY);
  782             }
  783 
  784             isc_buffer_usedregion(&b, &r);
  785 
  786             if (timetags[i] != NULL) {
  787                 fprintf(fp, "%s %.*s\n", timetags[i],
  788                     (int)r.length, r.base);
  789             }
  790         }
  791     }
  792 
  793     fflush(fp);
  794     result = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS;
  795     fclose(fp);
  796     return (result);
  797 }
  798 
  799 /*! \file */