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