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