dst_parse.c

Go to the documentation of this file.
00001 /*
00002  * Portions Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Portions Copyright (C) 1999-2002  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
00010  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
00011  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
00012  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00013  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00014  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
00015  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00016  *
00017  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
00018  *
00019  * Permission to use, copy, modify, and/or distribute this software for any
00020  * purpose with or without fee is hereby granted, provided that the above
00021  * copyright notice and this permission notice appear in all copies.
00022  *
00023  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
00024  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
00025  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
00026  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00027  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00028  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
00029  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00030  */
00031 
00032 /*%
00033  * Principal Author: Brian Wellington
00034  * $Id: dst_parse.c,v 1.29 2011/08/18 23:46:35 tbox Exp $
00035  */
00036 
00037 #include <config.h>
00038 
00039 #include <isc/base64.h>
00040 #include <isc/dir.h>
00041 #include <isc/fsaccess.h>
00042 #include <isc/lex.h>
00043 #include <isc/mem.h>
00044 #include <isc/stdtime.h>
00045 #include <isc/string.h>
00046 #include <isc/util.h>
00047 #include <isc/file.h>
00048 
00049 #include <dns/time.h>
00050 #include <dns/log.h>
00051 
00052 #include "dst_internal.h"
00053 #include "dst_parse.h"
00054 #include "dst/result.h"
00055 
00056 #define DST_AS_STR(t) ((t).value.as_textregion.base)
00057 
00058 #define PRIVATE_KEY_STR "Private-key-format:"
00059 #define ALGORITHM_STR "Algorithm:"
00060 
00061 #define TIMING_NTAGS (DST_MAX_TIMES + 1)
00062 static const char *timetags[TIMING_NTAGS] = {
00063         "Created:",
00064         "Publish:",
00065         "Activate:",
00066         "Revoke:",
00067         "Inactive:",
00068         "Delete:",
00069         "DSPublish:"
00070 };
00071 
00072 #define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1)
00073 static const char *numerictags[NUMERIC_NTAGS] = {
00074         "Predecessor:",
00075         "Successor:",
00076         "MaxTTL:",
00077         "RollPeriod:"
00078 };
00079 
00080 struct parse_map {
00081         const int value;
00082         const char *tag;
00083 };
00084 
00085 static struct parse_map map[] = {
00086         {TAG_RSA_MODULUS, "Modulus:"},
00087         {TAG_RSA_PUBLICEXPONENT, "PublicExponent:"},
00088         {TAG_RSA_PRIVATEEXPONENT, "PrivateExponent:"},
00089         {TAG_RSA_PRIME1, "Prime1:"},
00090         {TAG_RSA_PRIME2, "Prime2:"},
00091         {TAG_RSA_EXPONENT1, "Exponent1:"},
00092         {TAG_RSA_EXPONENT2, "Exponent2:"},
00093         {TAG_RSA_COEFFICIENT, "Coefficient:"},
00094         {TAG_RSA_ENGINE, "Engine:" },
00095         {TAG_RSA_LABEL, "Label:" },
00096 
00097         {TAG_DH_PRIME, "Prime(p):"},
00098         {TAG_DH_GENERATOR, "Generator(g):"},
00099         {TAG_DH_PRIVATE, "Private_value(x):"},
00100         {TAG_DH_PUBLIC, "Public_value(y):"},
00101 
00102         {TAG_DSA_PRIME, "Prime(p):"},
00103         {TAG_DSA_SUBPRIME, "Subprime(q):"},
00104         {TAG_DSA_BASE, "Base(g):"},
00105         {TAG_DSA_PRIVATE, "Private_value(x):"},
00106         {TAG_DSA_PUBLIC, "Public_value(y):"},
00107 
00108         {TAG_GOST_PRIVASN1, "GostAsn1:"},
00109         {TAG_GOST_PRIVRAW, "PrivateKey:"},
00110 
00111         {TAG_ECDSA_PRIVATEKEY, "PrivateKey:"},
00112         {TAG_ECDSA_ENGINE, "Engine:" },
00113         {TAG_ECDSA_LABEL, "Label:" },
00114 
00115         {TAG_HMACMD5_KEY, "Key:"},
00116         {TAG_HMACMD5_BITS, "Bits:"},
00117 
00118         {TAG_HMACSHA1_KEY, "Key:"},
00119         {TAG_HMACSHA1_BITS, "Bits:"},
00120 
00121         {TAG_HMACSHA224_KEY, "Key:"},
00122         {TAG_HMACSHA224_BITS, "Bits:"},
00123 
00124         {TAG_HMACSHA256_KEY, "Key:"},
00125         {TAG_HMACSHA256_BITS, "Bits:"},
00126 
00127         {TAG_HMACSHA384_KEY, "Key:"},
00128         {TAG_HMACSHA384_BITS, "Bits:"},
00129 
00130         {TAG_HMACSHA512_KEY, "Key:"},
00131         {TAG_HMACSHA512_BITS, "Bits:"},
00132 
00133         {0, NULL}
00134 };
00135 
00136 static int
00137 find_value(const char *s, const unsigned int alg) {
00138         int i;
00139 
00140         for (i = 0; map[i].tag != NULL; i++) {
00141                 if (strcasecmp(s, map[i].tag) == 0 &&
00142                     (TAG_ALG(map[i].value) == alg))
00143                         return (map[i].value);
00144         }
00145         return (-1);
00146 }
00147 
00148 static const char *
00149 find_tag(const int value) {
00150         int i;
00151 
00152         for (i = 0; ; i++) {
00153                 if (map[i].tag == NULL)
00154                         return (NULL);
00155                 else if (value == map[i].value)
00156                         return (map[i].tag);
00157         }
00158 }
00159 
00160 static int
00161 find_metadata(const char *s, const char *tags[], int ntags) {
00162         int i;
00163 
00164         for (i = 0; i < ntags; i++) {
00165                 if (strcasecmp(s, tags[i]) == 0)
00166                         return (i);
00167         }
00168 
00169         return (-1);
00170 }
00171 
00172 static int
00173 find_timedata(const char *s) {
00174         return (find_metadata(s, timetags, TIMING_NTAGS));
00175 }
00176 
00177 static int
00178 find_numericdata(const char *s) {
00179         return (find_metadata(s, numerictags, NUMERIC_NTAGS));
00180 }
00181 
00182 static int
00183 check_rsa(const dst_private_t *priv, isc_boolean_t external) {
00184         int i, j;
00185         isc_boolean_t have[RSA_NTAGS];
00186         isc_boolean_t ok;
00187         unsigned int mask;
00188 
00189         if (external)
00190                 return ((priv->nelements == 0) ? 0 : -1);
00191 
00192         for (i = 0; i < RSA_NTAGS; i++)
00193                 have[i] = ISC_FALSE;
00194 
00195         for (j = 0; j < priv->nelements; j++) {
00196                 for (i = 0; i < RSA_NTAGS; i++)
00197                         if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i))
00198                                 break;
00199                 if (i == RSA_NTAGS)
00200                         return (-1);
00201                 have[i] = ISC_TRUE;
00202         }
00203 
00204         mask = ~0;
00205         mask <<= sizeof(mask) * 8 - TAG_SHIFT;
00206         mask >>= sizeof(mask) * 8 - TAG_SHIFT;
00207 
00208         if (have[TAG_RSA_ENGINE & mask])
00209                 ok = have[TAG_RSA_MODULUS & mask] &&
00210                      have[TAG_RSA_PUBLICEXPONENT & mask] &&
00211                      have[TAG_RSA_LABEL & mask];
00212         else
00213                 ok = have[TAG_RSA_MODULUS & mask] &&
00214                      have[TAG_RSA_PUBLICEXPONENT & mask] &&
00215                      have[TAG_RSA_PRIVATEEXPONENT & mask] &&
00216                      have[TAG_RSA_PRIME1 & mask] &&
00217                      have[TAG_RSA_PRIME2 & mask] &&
00218                      have[TAG_RSA_EXPONENT1 & mask] &&
00219                      have[TAG_RSA_EXPONENT2 & mask] &&
00220                      have[TAG_RSA_COEFFICIENT & mask];
00221         return (ok ? 0 : -1 );
00222 }
00223 
00224 static int
00225 check_dh(const dst_private_t *priv) {
00226         int i, j;
00227         if (priv->nelements != DH_NTAGS)
00228                 return (-1);
00229         for (i = 0; i < DH_NTAGS; i++) {
00230                 for (j = 0; j < priv->nelements; j++)
00231                         if (priv->elements[j].tag == TAG(DST_ALG_DH, i))
00232                                 break;
00233                 if (j == priv->nelements)
00234                         return (-1);
00235         }
00236         return (0);
00237 }
00238 
00239 static int
00240 check_dsa(const dst_private_t *priv, isc_boolean_t external) {
00241         int i, j;
00242 
00243         if (external)
00244                 return ((priv->nelements == 0)? 0 : -1);
00245 
00246         if (priv->nelements != DSA_NTAGS)
00247                 return (-1);
00248 
00249         for (i = 0; i < DSA_NTAGS; i++) {
00250                 for (j = 0; j < priv->nelements; j++)
00251                         if (priv->elements[j].tag == TAG(DST_ALG_DSA, i))
00252                                 break;
00253                 if (j == priv->nelements)
00254                         return (-1);
00255         }
00256         return (0);
00257 }
00258 
00259 static int
00260 check_gost(const dst_private_t *priv, isc_boolean_t external) {
00261 
00262         if (external)
00263                 return ((priv->nelements == 0)? 0 : -1);
00264 
00265         if (priv->nelements != GOST_NTAGS)
00266                 return (-1);
00267         if ((priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0)) &&
00268             (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 1)))
00269                 return (-1);
00270         return (0);
00271 }
00272 
00273 static int
00274 check_ecdsa(const dst_private_t *priv, isc_boolean_t external) {
00275         int i, j;
00276         isc_boolean_t have[ECDSA_NTAGS];
00277         isc_boolean_t ok;
00278         unsigned int mask;
00279 
00280         if (external)
00281                 return ((priv->nelements == 0) ? 0 : -1);
00282 
00283         for (i = 0; i < ECDSA_NTAGS; i++)
00284                 have[i] = ISC_FALSE;
00285         for (j = 0; j < priv->nelements; j++) {
00286                 for (i = 0; i < ECDSA_NTAGS; i++)
00287                         if (priv->elements[j].tag == TAG(DST_ALG_ECDSA256, i))
00288                                 break;
00289                 if (i == ECDSA_NTAGS)
00290                         return (-1);
00291                 have[i] = ISC_TRUE;
00292         }
00293 
00294         mask = ~0;
00295         mask <<= sizeof(mask) * 8 - TAG_SHIFT;
00296         mask >>= sizeof(mask) * 8 - TAG_SHIFT;
00297 
00298         if (have[TAG_ECDSA_ENGINE & mask])
00299                 ok = have[TAG_ECDSA_LABEL & mask];
00300         else
00301                 ok = have[TAG_ECDSA_PRIVATEKEY & mask];
00302         return (ok ? 0 : -1 );
00303 }
00304 
00305 static int
00306 check_hmac_md5(const dst_private_t *priv, isc_boolean_t old) {
00307         int i, j;
00308 
00309         if (priv->nelements != HMACMD5_NTAGS) {
00310                 /*
00311                  * If this is a good old format and we are accepting
00312                  * the old format return success.
00313                  */
00314                 if (old && priv->nelements == OLD_HMACMD5_NTAGS &&
00315                     priv->elements[0].tag == TAG_HMACMD5_KEY)
00316                         return (0);
00317                 return (-1);
00318         }
00319         /*
00320          * We must be new format at this point.
00321          */
00322         for (i = 0; i < HMACMD5_NTAGS; i++) {
00323                 for (j = 0; j < priv->nelements; j++)
00324                         if (priv->elements[j].tag == TAG(DST_ALG_HMACMD5, i))
00325                                 break;
00326                 if (j == priv->nelements)
00327                         return (-1);
00328         }
00329         return (0);
00330 }
00331 
00332 static int
00333 check_hmac_sha(const dst_private_t *priv, unsigned int ntags,
00334                unsigned int alg)
00335 {
00336         unsigned int i, j;
00337         if (priv->nelements != ntags)
00338                 return (-1);
00339         for (i = 0; i < ntags; i++) {
00340                 for (j = 0; j < priv->nelements; j++)
00341                         if (priv->elements[j].tag == TAG(alg, i))
00342                                 break;
00343                 if (j == priv->nelements)
00344                         return (-1);
00345         }
00346         return (0);
00347 }
00348 
00349 static int
00350 check_data(const dst_private_t *priv, const unsigned int alg,
00351            isc_boolean_t old, isc_boolean_t external)
00352 {
00353         /* XXXVIX this switch statement is too sparse to gen a jump table. */
00354         switch (alg) {
00355         case DST_ALG_RSAMD5:
00356         case DST_ALG_RSASHA1:
00357         case DST_ALG_NSEC3RSASHA1:
00358         case DST_ALG_RSASHA256:
00359         case DST_ALG_RSASHA512:
00360                 return (check_rsa(priv, external));
00361         case DST_ALG_DH:
00362                 return (check_dh(priv));
00363         case DST_ALG_DSA:
00364         case DST_ALG_NSEC3DSA:
00365                 return (check_dsa(priv, external));
00366         case DST_ALG_ECCGOST:
00367                 return (check_gost(priv, external));
00368         case DST_ALG_ECDSA256:
00369         case DST_ALG_ECDSA384:
00370                 return (check_ecdsa(priv, external));
00371         case DST_ALG_HMACMD5:
00372                 return (check_hmac_md5(priv, old));
00373         case DST_ALG_HMACSHA1:
00374                 return (check_hmac_sha(priv, HMACSHA1_NTAGS, alg));
00375         case DST_ALG_HMACSHA224:
00376                 return (check_hmac_sha(priv, HMACSHA224_NTAGS, alg));
00377         case DST_ALG_HMACSHA256:
00378                 return (check_hmac_sha(priv, HMACSHA256_NTAGS, alg));
00379         case DST_ALG_HMACSHA384:
00380                 return (check_hmac_sha(priv, HMACSHA384_NTAGS, alg));
00381         case DST_ALG_HMACSHA512:
00382                 return (check_hmac_sha(priv, HMACSHA512_NTAGS, alg));
00383         default:
00384                 return (DST_R_UNSUPPORTEDALG);
00385         }
00386 }
00387 
00388 void
00389 dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) {
00390         int i;
00391 
00392         if (priv == NULL)
00393                 return;
00394         for (i = 0; i < priv->nelements; i++) {
00395                 if (priv->elements[i].data == NULL)
00396                         continue;
00397                 memset(priv->elements[i].data, 0, MAXFIELDSIZE);
00398                 isc_mem_put(mctx, priv->elements[i].data, MAXFIELDSIZE);
00399         }
00400         priv->nelements = 0;
00401 }
00402 
00403 isc_result_t
00404 dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
00405                       isc_mem_t *mctx, dst_private_t *priv)
00406 {
00407         int n = 0, major, minor, check;
00408         isc_buffer_t b;
00409         isc_token_t token;
00410         unsigned char *data = NULL;
00411         unsigned int opt = ISC_LEXOPT_EOL;
00412         isc_stdtime_t when;
00413         isc_result_t ret;
00414         isc_boolean_t external = ISC_FALSE;
00415 
00416         REQUIRE(priv != NULL);
00417 
00418         priv->nelements = 0;
00419         memset(priv->elements, 0, sizeof(priv->elements));
00420 
00421 #define NEXTTOKEN(lex, opt, token)                              \
00422         do {                                                    \
00423                 ret = isc_lex_gettoken(lex, opt, token);        \
00424                 if (ret != ISC_R_SUCCESS)                       \
00425                         goto fail;                              \
00426         } while (0)
00427 
00428 #define READLINE(lex, opt, token)                               \
00429         do {                                                    \
00430                 ret = isc_lex_gettoken(lex, opt, token);        \
00431                 if (ret == ISC_R_EOF)                           \
00432                         break;                                  \
00433                 else if (ret != ISC_R_SUCCESS)                  \
00434                         goto fail;                              \
00435         } while ((*token).type != isc_tokentype_eol)
00436 
00437         /*
00438          * Read the description line.
00439          */
00440         NEXTTOKEN(lex, opt, &token);
00441         if (token.type != isc_tokentype_string ||
00442             strcmp(DST_AS_STR(token), PRIVATE_KEY_STR) != 0)
00443         {
00444                 ret = DST_R_INVALIDPRIVATEKEY;
00445                 goto fail;
00446         }
00447 
00448         NEXTTOKEN(lex, opt, &token);
00449         if (token.type != isc_tokentype_string ||
00450             (DST_AS_STR(token))[0] != 'v')
00451         {
00452                 ret = DST_R_INVALIDPRIVATEKEY;
00453                 goto fail;
00454         }
00455         if (sscanf(DST_AS_STR(token), "v%d.%d", &major, &minor) != 2)
00456         {
00457                 ret = DST_R_INVALIDPRIVATEKEY;
00458                 goto fail;
00459         }
00460 
00461         if (major > DST_MAJOR_VERSION) {
00462                 ret = DST_R_INVALIDPRIVATEKEY;
00463                 goto fail;
00464         }
00465 
00466         /*
00467          * Store the private key format version number
00468          */
00469         dst_key_setprivateformat(key, major, minor);
00470 
00471         READLINE(lex, opt, &token);
00472 
00473         /*
00474          * Read the algorithm line.
00475          */
00476         NEXTTOKEN(lex, opt, &token);
00477         if (token.type != isc_tokentype_string ||
00478             strcmp(DST_AS_STR(token), ALGORITHM_STR) != 0)
00479         {
00480                 ret = DST_R_INVALIDPRIVATEKEY;
00481                 goto fail;
00482         }
00483 
00484         NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
00485         if (token.type != isc_tokentype_number ||
00486             token.value.as_ulong != (unsigned long) dst_key_alg(key))
00487         {
00488                 ret = DST_R_INVALIDPRIVATEKEY;
00489                 goto fail;
00490         }
00491 
00492         READLINE(lex, opt, &token);
00493 
00494         /*
00495          * Read the key data.
00496          */
00497         for (n = 0; n < MAXFIELDS; n++) {
00498                 int tag;
00499                 isc_region_t r;
00500                 do {
00501                         ret = isc_lex_gettoken(lex, opt, &token);
00502                         if (ret == ISC_R_EOF)
00503                                 goto done;
00504                         if (ret != ISC_R_SUCCESS)
00505                                 goto fail;
00506                 } while (token.type == isc_tokentype_eol);
00507 
00508                 if (token.type != isc_tokentype_string) {
00509                         ret = DST_R_INVALIDPRIVATEKEY;
00510                         goto fail;
00511                 }
00512 
00513                 if (strcmp(DST_AS_STR(token), "External:") == 0) {
00514                         external = ISC_TRUE;
00515                         goto next;
00516                 }
00517 
00518                 /* Numeric metadata */
00519                 tag = find_numericdata(DST_AS_STR(token));
00520                 if (tag >= 0) {
00521                         INSIST(tag < NUMERIC_NTAGS);
00522 
00523                         NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
00524                         if (token.type != isc_tokentype_number) {
00525                                 ret = DST_R_INVALIDPRIVATEKEY;
00526                                 goto fail;
00527                         }
00528 
00529                         dst_key_setnum(key, tag, token.value.as_ulong);
00530                         goto next;
00531                 }
00532 
00533                 /* Timing metadata */
00534                 tag = find_timedata(DST_AS_STR(token));
00535                 if (tag >= 0) {
00536                         INSIST(tag < TIMING_NTAGS);
00537 
00538                         NEXTTOKEN(lex, opt, &token);
00539                         if (token.type != isc_tokentype_string) {
00540                                 ret = DST_R_INVALIDPRIVATEKEY;
00541                                 goto fail;
00542                         }
00543 
00544                         ret = dns_time32_fromtext(DST_AS_STR(token), &when);
00545                         if (ret != ISC_R_SUCCESS)
00546                                 goto fail;
00547 
00548                         dst_key_settime(key, tag, when);
00549 
00550                         goto next;
00551                 }
00552 
00553                 /* Key data */
00554                 tag = find_value(DST_AS_STR(token), alg);
00555                 if (tag < 0 && minor > DST_MINOR_VERSION)
00556                         goto next;
00557                 else if (tag < 0) {
00558                         ret = DST_R_INVALIDPRIVATEKEY;
00559                         goto fail;
00560                 }
00561 
00562                 priv->elements[n].tag = tag;
00563 
00564                 data = (unsigned char *) isc_mem_get(mctx, MAXFIELDSIZE);
00565                 if (data == NULL)
00566                         goto fail;
00567 
00568                 isc_buffer_init(&b, data, MAXFIELDSIZE);
00569                 ret = isc_base64_tobuffer(lex, &b, -1);
00570                 if (ret != ISC_R_SUCCESS)
00571                         goto fail;
00572 
00573                 isc_buffer_usedregion(&b, &r);
00574                 priv->elements[n].length = r.length;
00575                 priv->elements[n].data = r.base;
00576                 priv->nelements++;
00577 
00578           next:
00579                 READLINE(lex, opt, &token);
00580                 data = NULL;
00581         }
00582 
00583  done:
00584         if (external && priv->nelements != 0) {
00585                 ret = DST_R_INVALIDPRIVATEKEY;
00586                 goto fail;
00587         }
00588 
00589         check = check_data(priv, alg, ISC_TRUE, external);
00590         if (check < 0) {
00591                 ret = DST_R_INVALIDPRIVATEKEY;
00592                 goto fail;
00593         } else if (check != ISC_R_SUCCESS) {
00594                 ret = check;
00595                 goto fail;
00596         }
00597 
00598         key->external = external;
00599 
00600         return (ISC_R_SUCCESS);
00601 
00602 fail:
00603         dst__privstruct_free(priv, mctx);
00604         if (data != NULL)
00605                 isc_mem_put(mctx, data, MAXFIELDSIZE);
00606 
00607         return (ret);
00608 }
00609 
00610 isc_result_t
00611 dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
00612                           const char *directory)
00613 {
00614         FILE *fp;
00615         isc_result_t result;
00616         char filename[ISC_DIR_NAMEMAX];
00617         char buffer[MAXFIELDSIZE * 2];
00618         isc_fsaccess_t access;
00619         isc_stdtime_t when;
00620         isc_uint32_t value;
00621         isc_buffer_t b;
00622         isc_region_t r;
00623         int major, minor;
00624         mode_t mode;
00625         int i, ret;
00626 
00627         REQUIRE(priv != NULL);
00628 
00629         ret = check_data(priv, dst_key_alg(key), ISC_FALSE, key->external);
00630         if (ret < 0)
00631                 return (DST_R_INVALIDPRIVATEKEY);
00632         else if (ret != ISC_R_SUCCESS)
00633                 return (ret);
00634 
00635         isc_buffer_init(&b, filename, sizeof(filename));
00636         result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &b);
00637         if (result != ISC_R_SUCCESS)
00638                 return (result);
00639 
00640         result = isc_file_mode(filename, &mode);
00641         if (result == ISC_R_SUCCESS && mode != 0600) {
00642                 /* File exists; warn that we are changing its permissions */
00643                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
00644                               DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
00645                               "Permissions on the file %s "
00646                               "have changed from 0%o to 0600 as "
00647                               "a result of this operation.",
00648                               filename, (unsigned int)mode);
00649         }
00650 
00651         if ((fp = fopen(filename, "w")) == NULL)
00652                 return (DST_R_WRITEERROR);
00653 
00654         access = 0;
00655         isc_fsaccess_add(ISC_FSACCESS_OWNER,
00656                          ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
00657                          &access);
00658         (void)isc_fsaccess_set(filename, access);
00659 
00660         dst_key_getprivateformat(key, &major, &minor);
00661         if (major == 0 && minor == 0) {
00662                 major = DST_MAJOR_VERSION;
00663                 minor = DST_MINOR_VERSION;
00664         }
00665 
00666         /* XXXDCL return value should be checked for full filesystem */
00667         fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, major, minor);
00668 
00669         fprintf(fp, "%s %d ", ALGORITHM_STR, dst_key_alg(key));
00670 
00671         /* XXXVIX this switch statement is too sparse to gen a jump table. */
00672         switch (dst_key_alg(key)) {
00673         case DST_ALG_RSAMD5:
00674                 fprintf(fp, "(RSA)\n");
00675                 break;
00676         case DST_ALG_DH:
00677                 fprintf(fp, "(DH)\n");
00678                 break;
00679         case DST_ALG_DSA:
00680                 fprintf(fp, "(DSA)\n");
00681                 break;
00682         case DST_ALG_RSASHA1:
00683                 fprintf(fp, "(RSASHA1)\n");
00684                 break;
00685         case DST_ALG_NSEC3RSASHA1:
00686                 fprintf(fp, "(NSEC3RSASHA1)\n");
00687                 break;
00688         case DST_ALG_NSEC3DSA:
00689                 fprintf(fp, "(NSEC3DSA)\n");
00690                 break;
00691         case DST_ALG_RSASHA256:
00692                 fprintf(fp, "(RSASHA256)\n");
00693                 break;
00694         case DST_ALG_RSASHA512:
00695                 fprintf(fp, "(RSASHA512)\n");
00696                 break;
00697         case DST_ALG_ECCGOST:
00698                 fprintf(fp, "(ECC-GOST)\n");
00699                 break;
00700         case DST_ALG_ECDSA256:
00701                 fprintf(fp, "(ECDSAP256SHA256)\n");
00702                 break;
00703         case DST_ALG_ECDSA384:
00704                 fprintf(fp, "(ECDSAP384SHA384)\n");
00705                 break;
00706         case DST_ALG_HMACMD5:
00707                 fprintf(fp, "(HMAC_MD5)\n");
00708                 break;
00709         case DST_ALG_HMACSHA1:
00710                 fprintf(fp, "(HMAC_SHA1)\n");
00711                 break;
00712         case DST_ALG_HMACSHA224:
00713                 fprintf(fp, "(HMAC_SHA224)\n");
00714                 break;
00715         case DST_ALG_HMACSHA256:
00716                 fprintf(fp, "(HMAC_SHA256)\n");
00717                 break;
00718         case DST_ALG_HMACSHA384:
00719                 fprintf(fp, "(HMAC_SHA384)\n");
00720                 break;
00721         case DST_ALG_HMACSHA512:
00722                 fprintf(fp, "(HMAC_SHA512)\n");
00723                 break;
00724         default:
00725                 fprintf(fp, "(?)\n");
00726                 break;
00727         }
00728 
00729         for (i = 0; i < priv->nelements; i++) {
00730                 const char *s;
00731 
00732                 s = find_tag(priv->elements[i].tag);
00733 
00734                 r.base = priv->elements[i].data;
00735                 r.length = priv->elements[i].length;
00736                 isc_buffer_init(&b, buffer, sizeof(buffer));
00737                 result = isc_base64_totext(&r, sizeof(buffer), "", &b);
00738                 if (result != ISC_R_SUCCESS) {
00739                         fclose(fp);
00740                         return (DST_R_INVALIDPRIVATEKEY);
00741                 }
00742                 isc_buffer_usedregion(&b, &r);
00743 
00744                fprintf(fp, "%s %.*s\n", s, (int)r.length, r.base);
00745         }
00746 
00747         if (key->external)
00748                fprintf(fp, "External:\n");
00749 
00750         /* Add the metadata tags */
00751         if (major > 1 || (major == 1 && minor >= 3)) {
00752                 for (i = 0; i < NUMERIC_NTAGS; i++) {
00753                         result = dst_key_getnum(key, i, &value);
00754                         if (result != ISC_R_SUCCESS)
00755                                 continue;
00756                         fprintf(fp, "%s %u\n", numerictags[i], value);
00757                 }
00758                 for (i = 0; i < TIMING_NTAGS; i++) {
00759                         result = dst_key_gettime(key, i, &when);
00760                         if (result != ISC_R_SUCCESS)
00761                                 continue;
00762 
00763                         isc_buffer_init(&b, buffer, sizeof(buffer));
00764                         result = dns_time32_totext(when, &b);
00765                         if (result != ISC_R_SUCCESS) {
00766                                fclose(fp);
00767                                return (DST_R_INVALIDPRIVATEKEY);
00768                         }
00769 
00770                         isc_buffer_usedregion(&b, &r);
00771 
00772                         fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length,
00773                                 r.base);
00774                 }
00775         }
00776 
00777         fflush(fp);
00778         result = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS;
00779         fclose(fp);
00780         return (result);
00781 }
00782 
00783 /*! \file */

Generated on Tue Apr 28 17:40:56 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha