dst_api.c revision 218384
1/* 2 * Portions Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") 3 * Portions Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS 10 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 12 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * Portions Copyright (C) 1995-2000 by Network Associates, Inc. 18 * 19 * Permission to use, copy, modify, and/or distribute this software for any 20 * purpose with or without fee is hereby granted, provided that the above 21 * copyright notice and this permission notice appear in all copies. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS 24 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 26 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 27 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 28 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 29 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 30 */ 31 32/* 33 * Principal Author: Brian Wellington 34 * $Id: dst_api.c,v 1.16.12.12 2010-12-09 01:12:55 marka Exp $ 35 */ 36 37/*! \file */ 38 39#include <config.h> 40 41#include <stdlib.h> 42 43#include <isc/buffer.h> 44#include <isc/dir.h> 45#include <isc/entropy.h> 46#include <isc/fsaccess.h> 47#include <isc/hmacsha.h> 48#include <isc/lex.h> 49#include <isc/mem.h> 50#include <isc/once.h> 51#include <isc/print.h> 52#include <isc/refcount.h> 53#include <isc/random.h> 54#include <isc/string.h> 55#include <isc/time.h> 56#include <isc/util.h> 57 58#include <dns/fixedname.h> 59#include <dns/keyvalues.h> 60#include <dns/name.h> 61#include <dns/rdata.h> 62#include <dns/rdataclass.h> 63#include <dns/ttl.h> 64#include <dns/types.h> 65 66#include <dst/result.h> 67 68#include "dst_internal.h" 69 70#define DST_AS_STR(t) ((t).value.as_textregion.base) 71 72static dst_func_t *dst_t_func[DST_MAX_ALGS]; 73static isc_entropy_t *dst_entropy_pool = NULL; 74static unsigned int dst_entropy_flags = 0; 75static isc_boolean_t dst_initialized = ISC_FALSE; 76 77void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); 78 79isc_mem_t *dst__memory_pool = NULL; 80 81/* 82 * Static functions. 83 */ 84static dst_key_t * get_key_struct(dns_name_t *name, 85 unsigned int alg, 86 unsigned int flags, 87 unsigned int protocol, 88 unsigned int bits, 89 dns_rdataclass_t rdclass, 90 isc_mem_t *mctx); 91static isc_result_t write_public_key(const dst_key_t *key, int type, 92 const char *directory); 93static isc_result_t buildfilename(dns_name_t *name, 94 dns_keytag_t id, 95 unsigned int alg, 96 unsigned int type, 97 const char *directory, 98 isc_buffer_t *out); 99static isc_result_t computeid(dst_key_t *key); 100static isc_result_t frombuffer(dns_name_t *name, 101 unsigned int alg, 102 unsigned int flags, 103 unsigned int protocol, 104 dns_rdataclass_t rdclass, 105 isc_buffer_t *source, 106 isc_mem_t *mctx, 107 dst_key_t **keyp); 108 109static isc_result_t algorithm_status(unsigned int alg); 110 111static isc_result_t addsuffix(char *filename, unsigned int len, 112 const char *ofilename, const char *suffix); 113 114#define RETERR(x) \ 115 do { \ 116 result = (x); \ 117 if (result != ISC_R_SUCCESS) \ 118 goto out; \ 119 } while (0) 120 121#define CHECKALG(alg) \ 122 do { \ 123 isc_result_t _r; \ 124 _r = algorithm_status(alg); \ 125 if (_r != ISC_R_SUCCESS) \ 126 return (_r); \ 127 } while (0); \ 128 129#ifdef OPENSSL 130static void * 131default_memalloc(void *arg, size_t size) { 132 UNUSED(arg); 133 if (size == 0U) 134 size = 1; 135 return (malloc(size)); 136} 137 138static void 139default_memfree(void *arg, void *ptr) { 140 UNUSED(arg); 141 free(ptr); 142} 143#endif 144 145isc_result_t 146dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { 147 isc_result_t result; 148 149 REQUIRE(mctx != NULL && ectx != NULL); 150 REQUIRE(dst_initialized == ISC_FALSE); 151 152 dst__memory_pool = NULL; 153 154#ifdef OPENSSL 155 UNUSED(mctx); 156 /* 157 * When using --with-openssl, there seems to be no good way of not 158 * leaking memory due to the openssl error handling mechanism. 159 * Avoid assertions by using a local memory context and not checking 160 * for leaks on exit. Note: as there are leaks we cannot use 161 * ISC_MEMFLAG_INTERNAL as it will free up memory still being used 162 * by libcrypto. 163 */ 164 result = isc_mem_createx2(0, 0, default_memalloc, default_memfree, 165 NULL, &dst__memory_pool, 0); 166 if (result != ISC_R_SUCCESS) 167 return (result); 168 isc_mem_setname(dst__memory_pool, "dst", NULL); 169 isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE); 170#else 171 isc_mem_attach(mctx, &dst__memory_pool); 172#endif 173 isc_entropy_attach(ectx, &dst_entropy_pool); 174 dst_entropy_flags = eflags; 175 176 dst_result_register(); 177 178 memset(dst_t_func, 0, sizeof(dst_t_func)); 179 RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5])); 180 RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1])); 181 RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224])); 182 RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256])); 183 RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384])); 184 RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512])); 185#ifdef OPENSSL 186 RETERR(dst__openssl_init()); 187 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5], 188 DST_ALG_RSAMD5)); 189 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1], 190 DST_ALG_RSASHA1)); 191 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1], 192 DST_ALG_NSEC3RSASHA1)); 193 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256], 194 DST_ALG_RSASHA256)); 195 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512], 196 DST_ALG_RSASHA512)); 197#ifdef HAVE_OPENSSL_DSA 198 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA])); 199 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA])); 200#endif 201 RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH])); 202#endif /* OPENSSL */ 203#ifdef GSSAPI 204 RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI])); 205#endif 206 dst_initialized = ISC_TRUE; 207 return (ISC_R_SUCCESS); 208 209 out: 210 dst_lib_destroy(); 211 return (result); 212} 213 214void 215dst_lib_destroy(void) { 216 int i; 217 RUNTIME_CHECK(dst_initialized == ISC_TRUE); 218 dst_initialized = ISC_FALSE; 219 220 for (i = 0; i < DST_MAX_ALGS; i++) 221 if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL) 222 dst_t_func[i]->cleanup(); 223#ifdef OPENSSL 224 dst__openssl_destroy(); 225#endif 226 if (dst__memory_pool != NULL) 227 isc_mem_detach(&dst__memory_pool); 228 if (dst_entropy_pool != NULL) 229 isc_entropy_detach(&dst_entropy_pool); 230 231} 232 233isc_boolean_t 234dst_algorithm_supported(unsigned int alg) { 235 REQUIRE(dst_initialized == ISC_TRUE); 236 237 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) 238 return (ISC_FALSE); 239 return (ISC_TRUE); 240} 241 242isc_result_t 243dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) { 244 dst_context_t *dctx; 245 isc_result_t result; 246 247 REQUIRE(dst_initialized == ISC_TRUE); 248 REQUIRE(VALID_KEY(key)); 249 REQUIRE(mctx != NULL); 250 REQUIRE(dctxp != NULL && *dctxp == NULL); 251 252 if (key->func->createctx == NULL) 253 return (DST_R_UNSUPPORTEDALG); 254 if (key->keydata.generic == NULL) 255 return (DST_R_NULLKEY); 256 257 dctx = isc_mem_get(mctx, sizeof(dst_context_t)); 258 if (dctx == NULL) 259 return (ISC_R_NOMEMORY); 260 dctx->key = key; 261 dctx->mctx = mctx; 262 result = key->func->createctx(key, dctx); 263 if (result != ISC_R_SUCCESS) { 264 isc_mem_put(mctx, dctx, sizeof(dst_context_t)); 265 return (result); 266 } 267 dctx->magic = CTX_MAGIC; 268 *dctxp = dctx; 269 return (ISC_R_SUCCESS); 270} 271 272void 273dst_context_destroy(dst_context_t **dctxp) { 274 dst_context_t *dctx; 275 276 REQUIRE(dctxp != NULL && VALID_CTX(*dctxp)); 277 278 dctx = *dctxp; 279 INSIST(dctx->key->func->destroyctx != NULL); 280 dctx->key->func->destroyctx(dctx); 281 dctx->magic = 0; 282 isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t)); 283 *dctxp = NULL; 284} 285 286isc_result_t 287dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) { 288 REQUIRE(VALID_CTX(dctx)); 289 REQUIRE(data != NULL); 290 INSIST(dctx->key->func->adddata != NULL); 291 292 return (dctx->key->func->adddata(dctx, data)); 293} 294 295isc_result_t 296dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) { 297 dst_key_t *key; 298 299 REQUIRE(VALID_CTX(dctx)); 300 REQUIRE(sig != NULL); 301 302 key = dctx->key; 303 CHECKALG(key->key_alg); 304 if (key->keydata.generic == NULL) 305 return (DST_R_NULLKEY); 306 307 if (key->func->sign == NULL) 308 return (DST_R_NOTPRIVATEKEY); 309 if (key->func->isprivate == NULL || 310 key->func->isprivate(key) == ISC_FALSE) 311 return (DST_R_NOTPRIVATEKEY); 312 313 return (key->func->sign(dctx, sig)); 314} 315 316isc_result_t 317dst_context_verify(dst_context_t *dctx, isc_region_t *sig) { 318 REQUIRE(VALID_CTX(dctx)); 319 REQUIRE(sig != NULL); 320 321 CHECKALG(dctx->key->key_alg); 322 if (dctx->key->keydata.generic == NULL) 323 return (DST_R_NULLKEY); 324 if (dctx->key->func->verify == NULL) 325 return (DST_R_NOTPUBLICKEY); 326 327 return (dctx->key->func->verify(dctx, sig)); 328} 329 330isc_result_t 331dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv, 332 isc_buffer_t *secret) 333{ 334 REQUIRE(dst_initialized == ISC_TRUE); 335 REQUIRE(VALID_KEY(pub) && VALID_KEY(priv)); 336 REQUIRE(secret != NULL); 337 338 CHECKALG(pub->key_alg); 339 CHECKALG(priv->key_alg); 340 341 if (pub->keydata.generic == NULL || priv->keydata.generic == NULL) 342 return (DST_R_NULLKEY); 343 344 if (pub->key_alg != priv->key_alg || 345 pub->func->computesecret == NULL || 346 priv->func->computesecret == NULL) 347 return (DST_R_KEYCANNOTCOMPUTESECRET); 348 349 if (dst_key_isprivate(priv) == ISC_FALSE) 350 return (DST_R_NOTPRIVATEKEY); 351 352 return (pub->func->computesecret(pub, priv, secret)); 353} 354 355isc_result_t 356dst_key_tofile(const dst_key_t *key, int type, const char *directory) { 357 isc_result_t ret = ISC_R_SUCCESS; 358 359 REQUIRE(dst_initialized == ISC_TRUE); 360 REQUIRE(VALID_KEY(key)); 361 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 362 363 CHECKALG(key->key_alg); 364 365 if (key->func->tofile == NULL) 366 return (DST_R_UNSUPPORTEDALG); 367 368 if (type & DST_TYPE_PUBLIC) { 369 ret = write_public_key(key, type, directory); 370 if (ret != ISC_R_SUCCESS) 371 return (ret); 372 } 373 374 if ((type & DST_TYPE_PRIVATE) && 375 (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY) 376 return (key->func->tofile(key, directory)); 377 else 378 return (ISC_R_SUCCESS); 379} 380 381isc_result_t 382dst_key_fromfile(dns_name_t *name, dns_keytag_t id, 383 unsigned int alg, int type, const char *directory, 384 isc_mem_t *mctx, dst_key_t **keyp) 385{ 386 char filename[ISC_DIR_NAMEMAX]; 387 isc_buffer_t b; 388 dst_key_t *key; 389 isc_result_t result; 390 391 REQUIRE(dst_initialized == ISC_TRUE); 392 REQUIRE(dns_name_isabsolute(name)); 393 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 394 REQUIRE(mctx != NULL); 395 REQUIRE(keyp != NULL && *keyp == NULL); 396 397 CHECKALG(alg); 398 399 isc_buffer_init(&b, filename, sizeof(filename)); 400 result = buildfilename(name, id, alg, type, directory, &b); 401 if (result != ISC_R_SUCCESS) 402 return (result); 403 404 key = NULL; 405 result = dst_key_fromnamedfile(filename, type, mctx, &key); 406 if (result != ISC_R_SUCCESS) 407 return (result); 408 409 result = computeid(key); 410 if (result != ISC_R_SUCCESS) { 411 dst_key_free(&key); 412 return (result); 413 } 414 415 if (!dns_name_equal(name, key->key_name) || id != key->key_id || 416 alg != key->key_alg) { 417 dst_key_free(&key); 418 return (DST_R_INVALIDPRIVATEKEY); 419 } 420 key->key_id = id; 421 422 *keyp = key; 423 return (ISC_R_SUCCESS); 424} 425 426isc_result_t 427dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, 428 dst_key_t **keyp) 429{ 430 isc_result_t result; 431 dst_key_t *pubkey = NULL, *key = NULL; 432 dns_keytag_t id; 433 char *newfilename = NULL; 434 int newfilenamelen = 0; 435 isc_lex_t *lex = NULL; 436 437 REQUIRE(dst_initialized == ISC_TRUE); 438 REQUIRE(filename != NULL); 439 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 440 REQUIRE(mctx != NULL); 441 REQUIRE(keyp != NULL && *keyp == NULL); 442 443 newfilenamelen = strlen(filename) + 5; 444 newfilename = isc_mem_get(mctx, newfilenamelen); 445 if (newfilename == NULL) 446 return (ISC_R_NOMEMORY); 447 result = addsuffix(newfilename, newfilenamelen, filename, ".key"); 448 INSIST(result == ISC_R_SUCCESS); 449 450 result = dst_key_read_public(newfilename, type, mctx, &pubkey); 451 isc_mem_put(mctx, newfilename, newfilenamelen); 452 newfilename = NULL; 453 if (result != ISC_R_SUCCESS) 454 return (result); 455 456 if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC || 457 (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { 458 result = computeid(pubkey); 459 if (result != ISC_R_SUCCESS) { 460 dst_key_free(&pubkey); 461 return (result); 462 } 463 464 *keyp = pubkey; 465 return (ISC_R_SUCCESS); 466 } 467 468 result = algorithm_status(pubkey->key_alg); 469 if (result != ISC_R_SUCCESS) { 470 dst_key_free(&pubkey); 471 return (result); 472 } 473 474 key = get_key_struct(pubkey->key_name, pubkey->key_alg, 475 pubkey->key_flags, pubkey->key_proto, 0, 476 pubkey->key_class, mctx); 477 id = pubkey->key_id; 478 dst_key_free(&pubkey); 479 480 if (key == NULL) 481 return (ISC_R_NOMEMORY); 482 483 if (key->func->parse == NULL) 484 RETERR(DST_R_UNSUPPORTEDALG); 485 486 newfilenamelen = strlen(filename) + 9; 487 newfilename = isc_mem_get(mctx, newfilenamelen); 488 if (newfilename == NULL) 489 RETERR(ISC_R_NOMEMORY); 490 result = addsuffix(newfilename, newfilenamelen, filename, ".private"); 491 INSIST(result == ISC_R_SUCCESS); 492 493 RETERR(isc_lex_create(mctx, 1500, &lex)); 494 RETERR(isc_lex_openfile(lex, newfilename)); 495 isc_mem_put(mctx, newfilename, newfilenamelen); 496 497 RETERR(key->func->parse(key, lex)); 498 isc_lex_destroy(&lex); 499 500 RETERR(computeid(key)); 501 502 if (id != key->key_id) 503 RETERR(DST_R_INVALIDPRIVATEKEY); 504 505 *keyp = key; 506 return (ISC_R_SUCCESS); 507 508 out: 509 if (newfilename != NULL) 510 isc_mem_put(mctx, newfilename, newfilenamelen); 511 if (lex != NULL) 512 isc_lex_destroy(&lex); 513 dst_key_free(&key); 514 return (result); 515} 516 517isc_result_t 518dst_key_todns(const dst_key_t *key, isc_buffer_t *target) { 519 REQUIRE(dst_initialized == ISC_TRUE); 520 REQUIRE(VALID_KEY(key)); 521 REQUIRE(target != NULL); 522 523 CHECKALG(key->key_alg); 524 525 if (key->func->todns == NULL) 526 return (DST_R_UNSUPPORTEDALG); 527 528 if (isc_buffer_availablelength(target) < 4) 529 return (ISC_R_NOSPACE); 530 isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff)); 531 isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto); 532 isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg); 533 534 if (key->key_flags & DNS_KEYFLAG_EXTENDED) { 535 if (isc_buffer_availablelength(target) < 2) 536 return (ISC_R_NOSPACE); 537 isc_buffer_putuint16(target, 538 (isc_uint16_t)((key->key_flags >> 16) 539 & 0xffff)); 540 } 541 542 if (key->keydata.generic == NULL) /*%< NULL KEY */ 543 return (ISC_R_SUCCESS); 544 545 return (key->func->todns(key, target)); 546} 547 548isc_result_t 549dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, 550 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 551{ 552 isc_uint8_t alg, proto; 553 isc_uint32_t flags, extflags; 554 dst_key_t *key = NULL; 555 dns_keytag_t id; 556 isc_region_t r; 557 isc_result_t result; 558 559 REQUIRE(dst_initialized); 560 561 isc_buffer_remainingregion(source, &r); 562 563 if (isc_buffer_remaininglength(source) < 4) 564 return (DST_R_INVALIDPUBLICKEY); 565 flags = isc_buffer_getuint16(source); 566 proto = isc_buffer_getuint8(source); 567 alg = isc_buffer_getuint8(source); 568 569 id = dst_region_computeid(&r, alg); 570 571 if (flags & DNS_KEYFLAG_EXTENDED) { 572 if (isc_buffer_remaininglength(source) < 2) 573 return (DST_R_INVALIDPUBLICKEY); 574 extflags = isc_buffer_getuint16(source); 575 flags |= (extflags << 16); 576 } 577 578 result = frombuffer(name, alg, flags, proto, rdclass, source, 579 mctx, &key); 580 if (result != ISC_R_SUCCESS) 581 return (result); 582 key->key_id = id; 583 584 *keyp = key; 585 return (ISC_R_SUCCESS); 586} 587 588isc_result_t 589dst_key_frombuffer(dns_name_t *name, unsigned int alg, 590 unsigned int flags, unsigned int protocol, 591 dns_rdataclass_t rdclass, 592 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 593{ 594 dst_key_t *key = NULL; 595 isc_result_t result; 596 597 REQUIRE(dst_initialized); 598 599 result = frombuffer(name, alg, flags, protocol, rdclass, source, 600 mctx, &key); 601 if (result != ISC_R_SUCCESS) 602 return (result); 603 604 result = computeid(key); 605 if (result != ISC_R_SUCCESS) { 606 dst_key_free(&key); 607 return (result); 608 } 609 610 *keyp = key; 611 return (ISC_R_SUCCESS); 612} 613 614isc_result_t 615dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) { 616 REQUIRE(dst_initialized == ISC_TRUE); 617 REQUIRE(VALID_KEY(key)); 618 REQUIRE(target != NULL); 619 620 CHECKALG(key->key_alg); 621 622 if (key->func->todns == NULL) 623 return (DST_R_UNSUPPORTEDALG); 624 625 return (key->func->todns(key, target)); 626} 627 628isc_result_t 629dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { 630 isc_lex_t *lex = NULL; 631 isc_result_t result = ISC_R_SUCCESS; 632 633 REQUIRE(dst_initialized == ISC_TRUE); 634 REQUIRE(VALID_KEY(key)); 635 REQUIRE(!dst_key_isprivate(key)); 636 REQUIRE(buffer != NULL); 637 638 if (key->func->parse == NULL) 639 RETERR(DST_R_UNSUPPORTEDALG); 640 641 RETERR(isc_lex_create(key->mctx, 1500, &lex)); 642 RETERR(isc_lex_openbuffer(lex, buffer)); 643 RETERR(key->func->parse(key, lex)); 644 out: 645 if (lex != NULL) 646 isc_lex_destroy(&lex); 647 return (result); 648} 649 650gss_ctx_id_t 651dst_key_getgssctx(const dst_key_t *key) 652{ 653 REQUIRE(key != NULL); 654 655 return (key->keydata.gssctx); 656} 657 658isc_result_t 659dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, 660 dst_key_t **keyp) 661{ 662 dst_key_t *key; 663 664 REQUIRE(gssctx != NULL); 665 REQUIRE(keyp != NULL && *keyp == NULL); 666 667 key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 668 0, dns_rdataclass_in, mctx); 669 if (key == NULL) 670 return (ISC_R_NOMEMORY); 671 672 key->keydata.gssctx = gssctx; 673 *keyp = key; 674 return (ISC_R_SUCCESS); 675} 676 677isc_result_t 678dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags, 679 unsigned int protocol, dns_rdataclass_t rdclass, 680 const char *engine, const char *label, const char *pin, 681 isc_mem_t *mctx, dst_key_t **keyp) 682{ 683 dst_key_t *key; 684 isc_result_t result; 685 686 REQUIRE(dst_initialized == ISC_TRUE); 687 REQUIRE(dns_name_isabsolute(name)); 688 REQUIRE(mctx != NULL); 689 REQUIRE(keyp != NULL && *keyp == NULL); 690 REQUIRE(label != NULL); 691 692 CHECKALG(alg); 693 694 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 695 if (key == NULL) 696 return (ISC_R_NOMEMORY); 697 698 if (key->func->fromlabel == NULL) { 699 dst_key_free(&key); 700 return (DST_R_UNSUPPORTEDALG); 701 } 702 703 result = key->func->fromlabel(key, engine, label, pin); 704 if (result != ISC_R_SUCCESS) { 705 dst_key_free(&key); 706 return (result); 707 } 708 709 result = computeid(key); 710 if (result != ISC_R_SUCCESS) { 711 dst_key_free(&key); 712 return (result); 713 } 714 715 *keyp = key; 716 return (ISC_R_SUCCESS); 717} 718 719isc_result_t 720dst_key_generate(dns_name_t *name, unsigned int alg, 721 unsigned int bits, unsigned int param, 722 unsigned int flags, unsigned int protocol, 723 dns_rdataclass_t rdclass, 724 isc_mem_t *mctx, dst_key_t **keyp) 725{ 726 dst_key_t *key; 727 isc_result_t ret; 728 729 REQUIRE(dst_initialized == ISC_TRUE); 730 REQUIRE(dns_name_isabsolute(name)); 731 REQUIRE(mctx != NULL); 732 REQUIRE(keyp != NULL && *keyp == NULL); 733 734 CHECKALG(alg); 735 736 key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx); 737 if (key == NULL) 738 return (ISC_R_NOMEMORY); 739 740 if (bits == 0) { /*%< NULL KEY */ 741 key->key_flags |= DNS_KEYTYPE_NOKEY; 742 *keyp = key; 743 return (ISC_R_SUCCESS); 744 } 745 746 if (key->func->generate == NULL) { 747 dst_key_free(&key); 748 return (DST_R_UNSUPPORTEDALG); 749 } 750 751 ret = key->func->generate(key, param); 752 if (ret != ISC_R_SUCCESS) { 753 dst_key_free(&key); 754 return (ret); 755 } 756 757 ret = computeid(key); 758 if (ret != ISC_R_SUCCESS) { 759 dst_key_free(&key); 760 return (ret); 761 } 762 763 *keyp = key; 764 return (ISC_R_SUCCESS); 765} 766 767isc_boolean_t 768dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { 769 REQUIRE(dst_initialized == ISC_TRUE); 770 REQUIRE(VALID_KEY(key1)); 771 REQUIRE(VALID_KEY(key2)); 772 773 if (key1 == key2) 774 return (ISC_TRUE); 775 if (key1 == NULL || key2 == NULL) 776 return (ISC_FALSE); 777 if (key1->key_alg == key2->key_alg && 778 key1->key_id == key2->key_id && 779 key1->func->compare != NULL && 780 key1->func->compare(key1, key2) == ISC_TRUE) 781 return (ISC_TRUE); 782 else 783 return (ISC_FALSE); 784} 785 786isc_boolean_t 787dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { 788 REQUIRE(dst_initialized == ISC_TRUE); 789 REQUIRE(VALID_KEY(key1)); 790 REQUIRE(VALID_KEY(key2)); 791 792 if (key1 == key2) 793 return (ISC_TRUE); 794 if (key1 == NULL || key2 == NULL) 795 return (ISC_FALSE); 796 if (key1->key_alg == key2->key_alg && 797 key1->func->paramcompare != NULL && 798 key1->func->paramcompare(key1, key2) == ISC_TRUE) 799 return (ISC_TRUE); 800 else 801 return (ISC_FALSE); 802} 803 804void 805dst_key_attach(dst_key_t *source, dst_key_t **target) { 806 807 REQUIRE(dst_initialized == ISC_TRUE); 808 REQUIRE(target != NULL && *target == NULL); 809 REQUIRE(VALID_KEY(source)); 810 811 isc_refcount_increment(&source->refs, NULL); 812 *target = source; 813} 814 815void 816dst_key_free(dst_key_t **keyp) { 817 isc_mem_t *mctx; 818 dst_key_t *key; 819 unsigned int refs; 820 821 REQUIRE(dst_initialized == ISC_TRUE); 822 REQUIRE(keyp != NULL && VALID_KEY(*keyp)); 823 824 key = *keyp; 825 mctx = key->mctx; 826 827 isc_refcount_decrement(&key->refs, &refs); 828 if (refs != 0) 829 return; 830 831 isc_refcount_destroy(&key->refs); 832 if (key->keydata.generic != NULL) { 833 INSIST(key->func->destroy != NULL); 834 key->func->destroy(key); 835 } 836 if (key->engine != NULL) 837 isc_mem_free(mctx, key->engine); 838 if (key->label != NULL) 839 isc_mem_free(mctx, key->label); 840 dns_name_free(key->key_name, mctx); 841 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 842 memset(key, 0, sizeof(dst_key_t)); 843 isc_mem_put(mctx, key, sizeof(dst_key_t)); 844 *keyp = NULL; 845} 846 847isc_boolean_t 848dst_key_isprivate(const dst_key_t *key) { 849 REQUIRE(VALID_KEY(key)); 850 INSIST(key->func->isprivate != NULL); 851 return (key->func->isprivate(key)); 852} 853 854isc_result_t 855dst_key_buildfilename(const dst_key_t *key, int type, 856 const char *directory, isc_buffer_t *out) { 857 858 REQUIRE(VALID_KEY(key)); 859 REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC || 860 type == 0); 861 862 return (buildfilename(key->key_name, key->key_id, key->key_alg, 863 type, directory, out)); 864} 865 866isc_result_t 867dst_key_sigsize(const dst_key_t *key, unsigned int *n) { 868 REQUIRE(dst_initialized == ISC_TRUE); 869 REQUIRE(VALID_KEY(key)); 870 REQUIRE(n != NULL); 871 872 /* XXXVIX this switch statement is too sparse to gen a jump table. */ 873 switch (key->key_alg) { 874 case DST_ALG_RSAMD5: 875 case DST_ALG_RSASHA1: 876 case DST_ALG_NSEC3RSASHA1: 877 case DST_ALG_RSASHA256: 878 case DST_ALG_RSASHA512: 879 *n = (key->key_size + 7) / 8; 880 break; 881 case DST_ALG_DSA: 882 case DST_ALG_NSEC3DSA: 883 *n = DNS_SIG_DSASIGSIZE; 884 break; 885 case DST_ALG_HMACMD5: 886 *n = 16; 887 break; 888 case DST_ALG_HMACSHA1: 889 *n = ISC_SHA1_DIGESTLENGTH; 890 break; 891 case DST_ALG_HMACSHA224: 892 *n = ISC_SHA224_DIGESTLENGTH; 893 break; 894 case DST_ALG_HMACSHA256: 895 *n = ISC_SHA256_DIGESTLENGTH; 896 break; 897 case DST_ALG_HMACSHA384: 898 *n = ISC_SHA384_DIGESTLENGTH; 899 break; 900 case DST_ALG_HMACSHA512: 901 *n = ISC_SHA512_DIGESTLENGTH; 902 break; 903 case DST_ALG_GSSAPI: 904 *n = 128; /*%< XXX */ 905 break; 906 case DST_ALG_DH: 907 default: 908 return (DST_R_UNSUPPORTEDALG); 909 } 910 return (ISC_R_SUCCESS); 911} 912 913isc_result_t 914dst_key_secretsize(const dst_key_t *key, unsigned int *n) { 915 REQUIRE(dst_initialized == ISC_TRUE); 916 REQUIRE(VALID_KEY(key)); 917 REQUIRE(n != NULL); 918 919 if (key->key_alg == DST_ALG_DH) 920 *n = (key->key_size + 7) / 8; 921 else 922 return (DST_R_UNSUPPORTEDALG); 923 return (ISC_R_SUCCESS); 924} 925 926/*** 927 *** Static methods 928 ***/ 929 930/*% 931 * Allocates a key structure and fills in some of the fields. 932 */ 933static dst_key_t * 934get_key_struct(dns_name_t *name, unsigned int alg, 935 unsigned int flags, unsigned int protocol, 936 unsigned int bits, dns_rdataclass_t rdclass, 937 isc_mem_t *mctx) 938{ 939 dst_key_t *key; 940 isc_result_t result; 941 942 key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); 943 if (key == NULL) 944 return (NULL); 945 946 memset(key, 0, sizeof(dst_key_t)); 947 key->magic = KEY_MAGIC; 948 949 result = isc_refcount_init(&key->refs, 1); 950 if (result != ISC_R_SUCCESS) { 951 isc_mem_put(mctx, key, sizeof(dst_key_t)); 952 return (NULL); 953 } 954 955 key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); 956 if (key->key_name == NULL) { 957 isc_refcount_destroy(&key->refs); 958 isc_mem_put(mctx, key, sizeof(dst_key_t)); 959 return (NULL); 960 } 961 dns_name_init(key->key_name, NULL); 962 result = dns_name_dup(name, mctx, key->key_name); 963 if (result != ISC_R_SUCCESS) { 964 isc_refcount_destroy(&key->refs); 965 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 966 isc_mem_put(mctx, key, sizeof(dst_key_t)); 967 return (NULL); 968 } 969 key->key_alg = alg; 970 key->key_flags = flags; 971 key->key_proto = protocol; 972 key->mctx = mctx; 973 key->keydata.generic = NULL; 974 key->key_size = bits; 975 key->key_class = rdclass; 976 key->func = dst_t_func[alg]; 977 return (key); 978} 979 980/*% 981 * Reads a public key from disk 982 */ 983isc_result_t 984dst_key_read_public(const char *filename, int type, 985 isc_mem_t *mctx, dst_key_t **keyp) 986{ 987 u_char rdatabuf[DST_KEY_MAXSIZE]; 988 isc_buffer_t b; 989 dns_fixedname_t name; 990 isc_lex_t *lex = NULL; 991 isc_token_t token; 992 isc_result_t ret; 993 dns_rdata_t rdata = DNS_RDATA_INIT; 994 unsigned int opt = ISC_LEXOPT_DNSMULTILINE; 995 dns_rdataclass_t rdclass = dns_rdataclass_in; 996 isc_lexspecials_t specials; 997 isc_uint32_t ttl; 998 isc_result_t result; 999 dns_rdatatype_t keytype; 1000 1001 /* 1002 * Open the file and read its formatted contents 1003 * File format: 1004 * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key> 1005 */ 1006 1007 /* 1500 should be large enough for any key */ 1008 ret = isc_lex_create(mctx, 1500, &lex); 1009 if (ret != ISC_R_SUCCESS) 1010 goto cleanup; 1011 1012 memset(specials, 0, sizeof(specials)); 1013 specials['('] = 1; 1014 specials[')'] = 1; 1015 specials['"'] = 1; 1016 isc_lex_setspecials(lex, specials); 1017 isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); 1018 1019 ret = isc_lex_openfile(lex, filename); 1020 if (ret != ISC_R_SUCCESS) 1021 goto cleanup; 1022 1023#define NEXTTOKEN(lex, opt, token) { \ 1024 ret = isc_lex_gettoken(lex, opt, token); \ 1025 if (ret != ISC_R_SUCCESS) \ 1026 goto cleanup; \ 1027 } 1028 1029#define BADTOKEN() { \ 1030 ret = ISC_R_UNEXPECTEDTOKEN; \ 1031 goto cleanup; \ 1032 } 1033 1034 /* Read the domain name */ 1035 NEXTTOKEN(lex, opt, &token); 1036 if (token.type != isc_tokentype_string) 1037 BADTOKEN(); 1038 1039 /* 1040 * We don't support "@" in .key files. 1041 */ 1042 if (!strcmp(DST_AS_STR(token), "@")) 1043 BADTOKEN(); 1044 1045 dns_fixedname_init(&name); 1046 isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); 1047 isc_buffer_add(&b, strlen(DST_AS_STR(token))); 1048 ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, 1049 ISC_FALSE, NULL); 1050 if (ret != ISC_R_SUCCESS) 1051 goto cleanup; 1052 1053 /* Read the next word: either TTL, class, or 'KEY' */ 1054 NEXTTOKEN(lex, opt, &token); 1055 1056 if (token.type != isc_tokentype_string) 1057 BADTOKEN(); 1058 1059 /* If it's a TTL, read the next one */ 1060 result = dns_ttl_fromtext(&token.value.as_textregion, &ttl); 1061 if (result == ISC_R_SUCCESS) 1062 NEXTTOKEN(lex, opt, &token); 1063 1064 if (token.type != isc_tokentype_string) 1065 BADTOKEN(); 1066 1067 ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion); 1068 if (ret == ISC_R_SUCCESS) 1069 NEXTTOKEN(lex, opt, &token); 1070 1071 if (token.type != isc_tokentype_string) 1072 BADTOKEN(); 1073 1074 if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) 1075 keytype = dns_rdatatype_dnskey; 1076 else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) 1077 keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */ 1078 else 1079 BADTOKEN(); 1080 1081 if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) || 1082 ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) { 1083 ret = DST_R_BADKEYTYPE; 1084 goto cleanup; 1085 } 1086 1087 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); 1088 ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, 1089 ISC_FALSE, mctx, &b, NULL); 1090 if (ret != ISC_R_SUCCESS) 1091 goto cleanup; 1092 1093 ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx, 1094 keyp); 1095 if (ret != ISC_R_SUCCESS) 1096 goto cleanup; 1097 1098 cleanup: 1099 if (lex != NULL) 1100 isc_lex_destroy(&lex); 1101 return (ret); 1102} 1103 1104static isc_boolean_t 1105issymmetric(const dst_key_t *key) { 1106 REQUIRE(dst_initialized == ISC_TRUE); 1107 REQUIRE(VALID_KEY(key)); 1108 1109 /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1110 switch (key->key_alg) { 1111 case DST_ALG_RSAMD5: 1112 case DST_ALG_RSASHA1: 1113 case DST_ALG_NSEC3RSASHA1: 1114 case DST_ALG_RSASHA256: 1115 case DST_ALG_RSASHA512: 1116 case DST_ALG_DSA: 1117 case DST_ALG_NSEC3DSA: 1118 case DST_ALG_DH: 1119 return (ISC_FALSE); 1120 case DST_ALG_HMACMD5: 1121 case DST_ALG_GSSAPI: 1122 return (ISC_TRUE); 1123 default: 1124 return (ISC_FALSE); 1125 } 1126} 1127 1128/*% 1129 * Writes a public key to disk in DNS format. 1130 */ 1131static isc_result_t 1132write_public_key(const dst_key_t *key, int type, const char *directory) { 1133 FILE *fp; 1134 isc_buffer_t keyb, textb, fileb, classb; 1135 isc_region_t r; 1136 char filename[ISC_DIR_NAMEMAX]; 1137 unsigned char key_array[DST_KEY_MAXSIZE]; 1138 char text_array[DST_KEY_MAXTEXTSIZE]; 1139 char class_array[10]; 1140 isc_result_t ret; 1141 dns_rdata_t rdata = DNS_RDATA_INIT; 1142 isc_fsaccess_t access; 1143 1144 REQUIRE(VALID_KEY(key)); 1145 1146 isc_buffer_init(&keyb, key_array, sizeof(key_array)); 1147 isc_buffer_init(&textb, text_array, sizeof(text_array)); 1148 isc_buffer_init(&classb, class_array, sizeof(class_array)); 1149 1150 ret = dst_key_todns(key, &keyb); 1151 if (ret != ISC_R_SUCCESS) 1152 return (ret); 1153 1154 isc_buffer_usedregion(&keyb, &r); 1155 dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r); 1156 1157 ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb); 1158 if (ret != ISC_R_SUCCESS) 1159 return (DST_R_INVALIDPUBLICKEY); 1160 1161 ret = dns_rdataclass_totext(key->key_class, &classb); 1162 if (ret != ISC_R_SUCCESS) 1163 return (DST_R_INVALIDPUBLICKEY); 1164 1165 /* 1166 * Make the filename. 1167 */ 1168 isc_buffer_init(&fileb, filename, sizeof(filename)); 1169 ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb); 1170 if (ret != ISC_R_SUCCESS) 1171 return (ret); 1172 1173 /* 1174 * Create public key file. 1175 */ 1176 if ((fp = fopen(filename, "w")) == NULL) 1177 return (DST_R_WRITEERROR); 1178 1179 if (issymmetric(key)) { 1180 access = 0; 1181 isc_fsaccess_add(ISC_FSACCESS_OWNER, 1182 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, 1183 &access); 1184 (void)isc_fsaccess_set(filename, access); 1185 } 1186 1187 ret = dns_name_print(key->key_name, fp); 1188 if (ret != ISC_R_SUCCESS) { 1189 fclose(fp); 1190 return (ret); 1191 } 1192 1193 fprintf(fp, " "); 1194 1195 isc_buffer_usedregion(&classb, &r); 1196 isc_util_fwrite(r.base, 1, r.length, fp); 1197 1198 if ((type & DST_TYPE_KEY) != 0) 1199 fprintf(fp, " KEY "); 1200 else 1201 fprintf(fp, " DNSKEY "); 1202 1203 isc_buffer_usedregion(&textb, &r); 1204 isc_util_fwrite(r.base, 1, r.length, fp); 1205 1206 fputc('\n', fp); 1207 fflush(fp); 1208 if (ferror(fp)) 1209 ret = DST_R_WRITEERROR; 1210 fclose(fp); 1211 1212 return (ret); 1213} 1214 1215static isc_result_t 1216buildfilename(dns_name_t *name, dns_keytag_t id, 1217 unsigned int alg, unsigned int type, 1218 const char *directory, isc_buffer_t *out) 1219{ 1220 const char *suffix = ""; 1221 unsigned int len; 1222 isc_result_t result; 1223 1224 REQUIRE(out != NULL); 1225 if ((type & DST_TYPE_PRIVATE) != 0) 1226 suffix = ".private"; 1227 else if (type == DST_TYPE_PUBLIC) 1228 suffix = ".key"; 1229 if (directory != NULL) { 1230 if (isc_buffer_availablelength(out) < strlen(directory)) 1231 return (ISC_R_NOSPACE); 1232 isc_buffer_putstr(out, directory); 1233 if (strlen(directory) > 0U && 1234 directory[strlen(directory) - 1] != '/') 1235 isc_buffer_putstr(out, "/"); 1236 } 1237 if (isc_buffer_availablelength(out) < 1) 1238 return (ISC_R_NOSPACE); 1239 isc_buffer_putstr(out, "K"); 1240 result = dns_name_tofilenametext(name, ISC_FALSE, out); 1241 if (result != ISC_R_SUCCESS) 1242 return (result); 1243 len = 1 + 3 + 1 + 5 + strlen(suffix) + 1; 1244 if (isc_buffer_availablelength(out) < len) 1245 return (ISC_R_NOSPACE); 1246 sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, 1247 suffix); 1248 isc_buffer_add(out, len); 1249 1250 return (ISC_R_SUCCESS); 1251} 1252 1253static isc_result_t 1254computeid(dst_key_t *key) { 1255 isc_buffer_t dnsbuf; 1256 unsigned char dns_array[DST_KEY_MAXSIZE]; 1257 isc_region_t r; 1258 isc_result_t ret; 1259 1260 isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array)); 1261 ret = dst_key_todns(key, &dnsbuf); 1262 if (ret != ISC_R_SUCCESS) 1263 return (ret); 1264 1265 isc_buffer_usedregion(&dnsbuf, &r); 1266 key->key_id = dst_region_computeid(&r, key->key_alg); 1267 return (ISC_R_SUCCESS); 1268} 1269 1270static isc_result_t 1271frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags, 1272 unsigned int protocol, dns_rdataclass_t rdclass, 1273 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 1274{ 1275 dst_key_t *key; 1276 isc_result_t ret; 1277 1278 REQUIRE(dns_name_isabsolute(name)); 1279 REQUIRE(source != NULL); 1280 REQUIRE(mctx != NULL); 1281 REQUIRE(keyp != NULL && *keyp == NULL); 1282 1283 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 1284 if (key == NULL) 1285 return (ISC_R_NOMEMORY); 1286 1287 if (isc_buffer_remaininglength(source) > 0) { 1288 ret = algorithm_status(alg); 1289 if (ret != ISC_R_SUCCESS) { 1290 dst_key_free(&key); 1291 return (ret); 1292 } 1293 if (key->func->fromdns == NULL) { 1294 dst_key_free(&key); 1295 return (DST_R_UNSUPPORTEDALG); 1296 } 1297 1298 ret = key->func->fromdns(key, source); 1299 if (ret != ISC_R_SUCCESS) { 1300 dst_key_free(&key); 1301 return (ret); 1302 } 1303 } 1304 1305 *keyp = key; 1306 return (ISC_R_SUCCESS); 1307} 1308 1309static isc_result_t 1310algorithm_status(unsigned int alg) { 1311 REQUIRE(dst_initialized == ISC_TRUE); 1312 1313 if (dst_algorithm_supported(alg)) 1314 return (ISC_R_SUCCESS); 1315#ifndef OPENSSL 1316 if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || 1317 alg == DST_ALG_DSA || alg == DST_ALG_DH || 1318 alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA || 1319 alg == DST_ALG_NSEC3RSASHA1 || 1320 alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512) 1321 return (DST_R_NOCRYPTO); 1322#endif 1323 return (DST_R_UNSUPPORTEDALG); 1324} 1325 1326static isc_result_t 1327addsuffix(char *filename, unsigned int len, const char *ofilename, 1328 const char *suffix) 1329{ 1330 int olen = strlen(ofilename); 1331 int n; 1332 1333 if (olen > 1 && ofilename[olen - 1] == '.') 1334 olen -= 1; 1335 else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) 1336 olen -= 8; 1337 else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) 1338 olen -= 4; 1339 1340 n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); 1341 if (n < 0) 1342 return (ISC_R_FAILURE); 1343 if ((unsigned int)n >= len) 1344 return (ISC_R_NOSPACE); 1345 return (ISC_R_SUCCESS); 1346} 1347 1348isc_result_t 1349dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { 1350 unsigned int flags = dst_entropy_flags; 1351 1352 if (len == 0) 1353 return (ISC_R_SUCCESS); 1354 if (pseudo) 1355 flags &= ~ISC_ENTROPY_GOODONLY; 1356 return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); 1357} 1358 1359unsigned int 1360dst__entropy_status(void) { 1361#ifdef GSSAPI 1362 unsigned int flags = dst_entropy_flags; 1363 isc_result_t ret; 1364 unsigned char buf[32]; 1365 static isc_boolean_t first = ISC_TRUE; 1366 1367 if (first) { 1368 /* Someone believes RAND_status() initializes the PRNG */ 1369 flags &= ~ISC_ENTROPY_GOODONLY; 1370 ret = isc_entropy_getdata(dst_entropy_pool, buf, 1371 sizeof(buf), NULL, flags); 1372 INSIST(ret == ISC_R_SUCCESS); 1373 isc_entropy_putdata(dst_entropy_pool, buf, 1374 sizeof(buf), 2 * sizeof(buf)); 1375 first = ISC_FALSE; 1376 } 1377#endif 1378 return (isc_entropy_status(dst_entropy_pool)); 1379} 1380