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