1/* $NetBSD: dst_api.c,v 1.3.4.2 2012/12/15 05:39:57 riz Exp $ */ 2 3/* 4 * Portions Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 5 * Portions Copyright (C) 1999-2003 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_api.c,v 1.65 2011/10/20 21:20:02 marka Exp 37 */ 38 39/*! \file */ 40 41#include <config.h> 42 43#include <stdlib.h> 44#include <time.h> 45 46#include <isc/buffer.h> 47#include <isc/dir.h> 48#include <isc/entropy.h> 49#include <isc/fsaccess.h> 50#include <isc/hmacsha.h> 51#include <isc/lex.h> 52#include <isc/mem.h> 53#include <isc/once.h> 54#include <isc/platform.h> 55#include <isc/print.h> 56#include <isc/refcount.h> 57#include <isc/random.h> 58#include <isc/string.h> 59#include <isc/time.h> 60#include <isc/util.h> 61#include <isc/file.h> 62 63#define DST_KEY_INTERNAL 64 65#include <dns/fixedname.h> 66#include <dns/keyvalues.h> 67#include <dns/name.h> 68#include <dns/rdata.h> 69#include <dns/rdataclass.h> 70#include <dns/ttl.h> 71#include <dns/types.h> 72 73#include <dst/result.h> 74 75#include "dst_internal.h" 76 77#define DST_AS_STR(t) ((t).value.as_textregion.base) 78 79static dst_func_t *dst_t_func[DST_MAX_ALGS]; 80#ifdef BIND9 81static isc_entropy_t *dst_entropy_pool = NULL; 82#endif 83static unsigned int dst_entropy_flags = 0; 84static isc_boolean_t dst_initialized = ISC_FALSE; 85 86void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); 87 88isc_mem_t *dst__memory_pool = NULL; 89 90/* 91 * Static functions. 92 */ 93static dst_key_t * get_key_struct(dns_name_t *name, 94 unsigned int alg, 95 unsigned int flags, 96 unsigned int protocol, 97 unsigned int bits, 98 dns_rdataclass_t rdclass, 99 dns_ttl_t ttl, 100 isc_mem_t *mctx); 101static isc_result_t write_public_key(const dst_key_t *key, int type, 102 const char *directory); 103static isc_result_t buildfilename(dns_name_t *name, 104 dns_keytag_t id, 105 unsigned int alg, 106 unsigned int type, 107 const char *directory, 108 isc_buffer_t *out); 109static isc_result_t computeid(dst_key_t *key); 110static isc_result_t frombuffer(dns_name_t *name, 111 unsigned int alg, 112 unsigned int flags, 113 unsigned int protocol, 114 dns_rdataclass_t rdclass, 115 isc_buffer_t *source, 116 isc_mem_t *mctx, 117 dst_key_t **keyp); 118 119static isc_result_t algorithm_status(unsigned int alg); 120 121static isc_result_t addsuffix(char *filename, int len, 122 const char *dirname, const char *ofilename, 123 const char *suffix); 124 125#define RETERR(x) \ 126 do { \ 127 result = (x); \ 128 if (result != ISC_R_SUCCESS) \ 129 goto out; \ 130 } while (/*CONSTCOND*/0) 131 132#define CHECKALG(alg) \ 133 do { \ 134 isc_result_t _r; \ 135 _r = algorithm_status(alg); \ 136 if (_r != ISC_R_SUCCESS) \ 137 return (_r); \ 138 } while (/*CONSTCOND*/0); 139 140#if defined(OPENSSL) && defined(BIND9) 141static void * 142default_memalloc(void *arg, size_t size) { 143 UNUSED(arg); 144 if (size == 0U) 145 size = 1; 146 return (malloc(size)); 147} 148 149static void 150default_memfree(void *arg, void *ptr) { 151 UNUSED(arg); 152 free(ptr); 153} 154#endif 155 156isc_result_t 157dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { 158 return (dst_lib_init2(mctx, ectx, NULL, eflags)); 159} 160 161isc_result_t 162dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx, 163 const char *engine, unsigned int eflags) { 164 isc_result_t result; 165 166 REQUIRE(mctx != NULL); 167#ifdef BIND9 168 REQUIRE(ectx != NULL); 169#else 170 UNUSED(ectx); 171#endif 172 REQUIRE(dst_initialized == ISC_FALSE); 173 174#ifndef OPENSSL 175 UNUSED(engine); 176#endif 177 178 dst__memory_pool = NULL; 179 180#if defined(OPENSSL) && defined(BIND9) 181 UNUSED(mctx); 182 /* 183 * When using --with-openssl, there seems to be no good way of not 184 * leaking memory due to the openssl error handling mechanism. 185 * Avoid assertions by using a local memory context and not checking 186 * for leaks on exit. Note: as there are leaks we cannot use 187 * ISC_MEMFLAG_INTERNAL as it will free up memory still being used 188 * by libcrypto. 189 */ 190 result = isc_mem_createx2(0, 0, default_memalloc, default_memfree, 191 NULL, &dst__memory_pool, 0); 192 if (result != ISC_R_SUCCESS) 193 return (result); 194 isc_mem_setname(dst__memory_pool, "dst", NULL); 195#ifndef OPENSSL_LEAKS 196 isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE); 197#endif 198#else 199 isc_mem_attach(mctx, &dst__memory_pool); 200#endif 201#ifdef BIND9 202 isc_entropy_attach(ectx, &dst_entropy_pool); 203#endif 204 dst_entropy_flags = eflags; 205 206 dst_result_register(); 207 208 memset(dst_t_func, 0, sizeof(dst_t_func)); 209 RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5])); 210 RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1])); 211 RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224])); 212 RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256])); 213 RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384])); 214 RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512])); 215#ifdef OPENSSL 216 RETERR(dst__openssl_init(engine)); 217 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5], 218 DST_ALG_RSAMD5)); 219 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1], 220 DST_ALG_RSASHA1)); 221 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1], 222 DST_ALG_NSEC3RSASHA1)); 223 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256], 224 DST_ALG_RSASHA256)); 225 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512], 226 DST_ALG_RSASHA512)); 227#ifdef HAVE_OPENSSL_DSA 228 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA])); 229 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA])); 230#endif 231 RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH])); 232#ifdef HAVE_OPENSSL_GOST 233 RETERR(dst__opensslgost_init(&dst_t_func[DST_ALG_ECCGOST])); 234#endif 235#ifdef HAVE_OPENSSL_ECDSA 236 RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256])); 237 RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384])); 238#endif 239#endif /* OPENSSL */ 240#ifdef GSSAPI 241 RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI])); 242#endif 243 dst_initialized = ISC_TRUE; 244 return (ISC_R_SUCCESS); 245 246 out: 247 /* avoid immediate crash! */ 248 dst_initialized = ISC_TRUE; 249 dst_lib_destroy(); 250 return (result); 251} 252 253void 254dst_lib_destroy(void) { 255 int i; 256 RUNTIME_CHECK(dst_initialized == ISC_TRUE); 257 dst_initialized = ISC_FALSE; 258 259 for (i = 0; i < DST_MAX_ALGS; i++) 260 if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL) 261 dst_t_func[i]->cleanup(); 262#ifdef OPENSSL 263 dst__openssl_destroy(); 264#endif 265 if (dst__memory_pool != NULL) 266 isc_mem_detach(&dst__memory_pool); 267#ifdef BIND9 268 if (dst_entropy_pool != NULL) 269 isc_entropy_detach(&dst_entropy_pool); 270#endif 271} 272 273isc_boolean_t 274dst_algorithm_supported(unsigned int alg) { 275 REQUIRE(dst_initialized == ISC_TRUE); 276 277 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) 278 return (ISC_FALSE); 279 return (ISC_TRUE); 280} 281 282isc_result_t 283dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) { 284 dst_context_t *dctx; 285 isc_result_t result; 286 287 REQUIRE(dst_initialized == ISC_TRUE); 288 REQUIRE(VALID_KEY(key)); 289 REQUIRE(mctx != NULL); 290 REQUIRE(dctxp != NULL && *dctxp == NULL); 291 292 if (key->func->createctx == NULL) 293 return (DST_R_UNSUPPORTEDALG); 294 if (key->keydata.generic == NULL) 295 return (DST_R_NULLKEY); 296 297 dctx = isc_mem_get(mctx, sizeof(dst_context_t)); 298 if (dctx == NULL) 299 return (ISC_R_NOMEMORY); 300 dctx->key = key; 301 dctx->mctx = mctx; 302 result = key->func->createctx(key, dctx); 303 if (result != ISC_R_SUCCESS) { 304 isc_mem_put(mctx, dctx, sizeof(dst_context_t)); 305 return (result); 306 } 307 dctx->magic = CTX_MAGIC; 308 *dctxp = dctx; 309 return (ISC_R_SUCCESS); 310} 311 312void 313dst_context_destroy(dst_context_t **dctxp) { 314 dst_context_t *dctx; 315 316 REQUIRE(dctxp != NULL && VALID_CTX(*dctxp)); 317 318 dctx = *dctxp; 319 INSIST(dctx->key->func->destroyctx != NULL); 320 dctx->key->func->destroyctx(dctx); 321 dctx->magic = 0; 322 isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t)); 323 *dctxp = NULL; 324} 325 326isc_result_t 327dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) { 328 REQUIRE(VALID_CTX(dctx)); 329 REQUIRE(data != NULL); 330 INSIST(dctx->key->func->adddata != NULL); 331 332 return (dctx->key->func->adddata(dctx, data)); 333} 334 335isc_result_t 336dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) { 337 dst_key_t *key; 338 339 REQUIRE(VALID_CTX(dctx)); 340 REQUIRE(sig != NULL); 341 342 key = dctx->key; 343 CHECKALG(key->key_alg); 344 if (key->keydata.generic == NULL) 345 return (DST_R_NULLKEY); 346 347 if (key->func->sign == NULL) 348 return (DST_R_NOTPRIVATEKEY); 349 if (key->func->isprivate == NULL || 350 key->func->isprivate(key) == ISC_FALSE) 351 return (DST_R_NOTPRIVATEKEY); 352 353 return (key->func->sign(dctx, sig)); 354} 355 356isc_result_t 357dst_context_verify(dst_context_t *dctx, isc_region_t *sig) { 358 REQUIRE(VALID_CTX(dctx)); 359 REQUIRE(sig != NULL); 360 361 CHECKALG(dctx->key->key_alg); 362 if (dctx->key->keydata.generic == NULL) 363 return (DST_R_NULLKEY); 364 if (dctx->key->func->verify == NULL) 365 return (DST_R_NOTPUBLICKEY); 366 367 return (dctx->key->func->verify(dctx, sig)); 368} 369 370isc_result_t 371dst_context_verify2(dst_context_t *dctx, unsigned int maxbits, 372 isc_region_t *sig) 373{ 374 REQUIRE(VALID_CTX(dctx)); 375 REQUIRE(sig != NULL); 376 377 CHECKALG(dctx->key->key_alg); 378 if (dctx->key->keydata.generic == NULL) 379 return (DST_R_NULLKEY); 380 if (dctx->key->func->verify == NULL && 381 dctx->key->func->verify2 == NULL) 382 return (DST_R_NOTPUBLICKEY); 383 384 return (dctx->key->func->verify2 != NULL ? 385 dctx->key->func->verify2(dctx, maxbits, sig) : 386 dctx->key->func->verify(dctx, sig)); 387} 388 389isc_result_t 390dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv, 391 isc_buffer_t *secret) 392{ 393 REQUIRE(dst_initialized == ISC_TRUE); 394 REQUIRE(VALID_KEY(pub) && VALID_KEY(priv)); 395 REQUIRE(secret != NULL); 396 397 CHECKALG(pub->key_alg); 398 CHECKALG(priv->key_alg); 399 400 if (pub->keydata.generic == NULL || priv->keydata.generic == NULL) 401 return (DST_R_NULLKEY); 402 403 if (pub->key_alg != priv->key_alg || 404 pub->func->computesecret == NULL || 405 priv->func->computesecret == NULL) 406 return (DST_R_KEYCANNOTCOMPUTESECRET); 407 408 if (dst_key_isprivate(priv) == ISC_FALSE) 409 return (DST_R_NOTPRIVATEKEY); 410 411 return (pub->func->computesecret(pub, priv, secret)); 412} 413 414isc_result_t 415dst_key_tofile(const dst_key_t *key, int type, const char *directory) { 416 isc_result_t ret = ISC_R_SUCCESS; 417 418 REQUIRE(dst_initialized == ISC_TRUE); 419 REQUIRE(VALID_KEY(key)); 420 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 421 422 CHECKALG(key->key_alg); 423 424 if (key->func->tofile == NULL) 425 return (DST_R_UNSUPPORTEDALG); 426 427 if (type & DST_TYPE_PUBLIC) { 428 ret = write_public_key(key, type, directory); 429 if (ret != ISC_R_SUCCESS) 430 return (ret); 431 } 432 433 if ((type & DST_TYPE_PRIVATE) && 434 (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY) 435 return (key->func->tofile(key, directory)); 436 else 437 return (ISC_R_SUCCESS); 438} 439 440isc_result_t 441dst_key_fromfile(dns_name_t *name, dns_keytag_t id, 442 unsigned int alg, int type, const char *directory, 443 isc_mem_t *mctx, dst_key_t **keyp) 444{ 445 char filename[ISC_DIR_NAMEMAX]; 446 isc_buffer_t b; 447 dst_key_t *key; 448 isc_result_t result; 449 450 REQUIRE(dst_initialized == ISC_TRUE); 451 REQUIRE(dns_name_isabsolute(name)); 452 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 453 REQUIRE(mctx != NULL); 454 REQUIRE(keyp != NULL && *keyp == NULL); 455 456 CHECKALG(alg); 457 458 isc_buffer_init(&b, filename, sizeof(filename)); 459 result = buildfilename(name, id, alg, type, directory, &b); 460 if (result != ISC_R_SUCCESS) 461 return (result); 462 463 key = NULL; 464 result = dst_key_fromnamedfile(filename, NULL, type, mctx, &key); 465 if (result != ISC_R_SUCCESS) 466 return (result); 467 468 result = computeid(key); 469 if (result != ISC_R_SUCCESS) { 470 dst_key_free(&key); 471 return (result); 472 } 473 474 if (!dns_name_equal(name, key->key_name) || id != key->key_id || 475 alg != key->key_alg) { 476 dst_key_free(&key); 477 return (DST_R_INVALIDPRIVATEKEY); 478 } 479 480 *keyp = key; 481 return (ISC_R_SUCCESS); 482} 483 484isc_result_t 485dst_key_fromnamedfile(const char *filename, const char *dirname, 486 int type, isc_mem_t *mctx, dst_key_t **keyp) 487{ 488 isc_result_t result; 489 dst_key_t *pubkey = NULL, *key = NULL; 490 char *newfilename = NULL; 491 int newfilenamelen = 0; 492 isc_lex_t *lex = NULL; 493 494 REQUIRE(dst_initialized == ISC_TRUE); 495 REQUIRE(filename != NULL); 496 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 497 REQUIRE(mctx != NULL); 498 REQUIRE(keyp != NULL && *keyp == NULL); 499 500 /* If an absolute path is specified, don't use the key directory */ 501#ifndef WIN32 502 if (filename[0] == '/') 503 dirname = NULL; 504#else /* WIN32 */ 505 if (filename[0] == '/' || filename[0] == '\\') 506 dirname = NULL; 507#endif 508 509 newfilenamelen = strlen(filename) + 5; 510 if (dirname != NULL) 511 newfilenamelen += strlen(dirname) + 1; 512 newfilename = isc_mem_get(mctx, newfilenamelen); 513 if (newfilename == NULL) 514 return (ISC_R_NOMEMORY); 515 result = addsuffix(newfilename, newfilenamelen, 516 dirname, filename, ".key"); 517 INSIST(result == ISC_R_SUCCESS); 518 519 result = dst_key_read_public(newfilename, type, mctx, &pubkey); 520 isc_mem_put(mctx, newfilename, newfilenamelen); 521 newfilename = NULL; 522 if (result != ISC_R_SUCCESS) 523 return (result); 524 525 if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC || 526 (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { 527 result = computeid(pubkey); 528 if (result != ISC_R_SUCCESS) { 529 dst_key_free(&pubkey); 530 return (result); 531 } 532 533 *keyp = pubkey; 534 return (ISC_R_SUCCESS); 535 } 536 537 result = algorithm_status(pubkey->key_alg); 538 if (result != ISC_R_SUCCESS) { 539 dst_key_free(&pubkey); 540 return (result); 541 } 542 543 key = get_key_struct(pubkey->key_name, pubkey->key_alg, 544 pubkey->key_flags, pubkey->key_proto, 0, 545 pubkey->key_class, pubkey->key_ttl, mctx); 546 if (key == NULL) { 547 dst_key_free(&pubkey); 548 return (ISC_R_NOMEMORY); 549 } 550 551 if (key->func->parse == NULL) 552 RETERR(DST_R_UNSUPPORTEDALG); 553 554 newfilenamelen = strlen(filename) + 9; 555 if (dirname != NULL) 556 newfilenamelen += strlen(dirname) + 1; 557 newfilename = isc_mem_get(mctx, newfilenamelen); 558 if (newfilename == NULL) 559 RETERR(ISC_R_NOMEMORY); 560 result = addsuffix(newfilename, newfilenamelen, 561 dirname, filename, ".private"); 562 INSIST(result == ISC_R_SUCCESS); 563 564 RETERR(isc_lex_create(mctx, 1500, &lex)); 565 RETERR(isc_lex_openfile(lex, newfilename)); 566 isc_mem_put(mctx, newfilename, newfilenamelen); 567 568 RETERR(key->func->parse(key, lex, pubkey)); 569 isc_lex_destroy(&lex); 570 571 RETERR(computeid(key)); 572 573 if (pubkey->key_id != key->key_id) 574 RETERR(DST_R_INVALIDPRIVATEKEY); 575 dst_key_free(&pubkey); 576 577 *keyp = key; 578 return (ISC_R_SUCCESS); 579 580 out: 581 if (pubkey != NULL) 582 dst_key_free(&pubkey); 583 if (newfilename != NULL) 584 isc_mem_put(mctx, newfilename, newfilenamelen); 585 if (lex != NULL) 586 isc_lex_destroy(&lex); 587 dst_key_free(&key); 588 return (result); 589} 590 591isc_result_t 592dst_key_todns(const dst_key_t *key, isc_buffer_t *target) { 593 REQUIRE(dst_initialized == ISC_TRUE); 594 REQUIRE(VALID_KEY(key)); 595 REQUIRE(target != NULL); 596 597 CHECKALG(key->key_alg); 598 599 if (key->func->todns == NULL) 600 return (DST_R_UNSUPPORTEDALG); 601 602 if (isc_buffer_availablelength(target) < 4) 603 return (ISC_R_NOSPACE); 604 isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff)); 605 isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto); 606 isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg); 607 608 if (key->key_flags & DNS_KEYFLAG_EXTENDED) { 609 if (isc_buffer_availablelength(target) < 2) 610 return (ISC_R_NOSPACE); 611 isc_buffer_putuint16(target, 612 (isc_uint16_t)((key->key_flags >> 16) 613 & 0xffff)); 614 } 615 616 if (key->keydata.generic == NULL) /*%< NULL KEY */ 617 return (ISC_R_SUCCESS); 618 619 return (key->func->todns(key, target)); 620} 621 622isc_result_t 623dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, 624 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 625{ 626 isc_uint8_t alg, proto; 627 isc_uint32_t flags, extflags; 628 dst_key_t *key = NULL; 629 dns_keytag_t id, rid; 630 isc_region_t r; 631 isc_result_t result; 632 633 REQUIRE(dst_initialized); 634 635 isc_buffer_remainingregion(source, &r); 636 637 if (isc_buffer_remaininglength(source) < 4) 638 return (DST_R_INVALIDPUBLICKEY); 639 flags = isc_buffer_getuint16(source); 640 proto = isc_buffer_getuint8(source); 641 alg = isc_buffer_getuint8(source); 642 643 id = dst_region_computeid(&r, alg); 644 rid = dst_region_computerid(&r, alg); 645 646 if (flags & DNS_KEYFLAG_EXTENDED) { 647 if (isc_buffer_remaininglength(source) < 2) 648 return (DST_R_INVALIDPUBLICKEY); 649 extflags = isc_buffer_getuint16(source); 650 flags |= (extflags << 16); 651 } 652 653 result = frombuffer(name, alg, flags, proto, rdclass, source, 654 mctx, &key); 655 if (result != ISC_R_SUCCESS) 656 return (result); 657 key->key_id = id; 658 key->key_rid = rid; 659 660 *keyp = key; 661 return (ISC_R_SUCCESS); 662} 663 664isc_result_t 665dst_key_frombuffer(dns_name_t *name, unsigned int alg, 666 unsigned int flags, unsigned int protocol, 667 dns_rdataclass_t rdclass, 668 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 669{ 670 dst_key_t *key = NULL; 671 isc_result_t result; 672 673 REQUIRE(dst_initialized); 674 675 result = frombuffer(name, alg, flags, protocol, rdclass, source, 676 mctx, &key); 677 if (result != ISC_R_SUCCESS) 678 return (result); 679 680 result = computeid(key); 681 if (result != ISC_R_SUCCESS) { 682 dst_key_free(&key); 683 return (result); 684 } 685 686 *keyp = key; 687 return (ISC_R_SUCCESS); 688} 689 690isc_result_t 691dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) { 692 REQUIRE(dst_initialized == ISC_TRUE); 693 REQUIRE(VALID_KEY(key)); 694 REQUIRE(target != NULL); 695 696 CHECKALG(key->key_alg); 697 698 if (key->func->todns == NULL) 699 return (DST_R_UNSUPPORTEDALG); 700 701 return (key->func->todns(key, target)); 702} 703 704isc_result_t 705dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { 706 isc_lex_t *lex = NULL; 707 isc_result_t result = ISC_R_SUCCESS; 708 709 REQUIRE(dst_initialized == ISC_TRUE); 710 REQUIRE(VALID_KEY(key)); 711 REQUIRE(!dst_key_isprivate(key)); 712 REQUIRE(buffer != NULL); 713 714 if (key->func->parse == NULL) 715 RETERR(DST_R_UNSUPPORTEDALG); 716 717 RETERR(isc_lex_create(key->mctx, 1500, &lex)); 718 RETERR(isc_lex_openbuffer(lex, buffer)); 719 RETERR(key->func->parse(key, lex, NULL)); 720 out: 721 if (lex != NULL) 722 isc_lex_destroy(&lex); 723 return (result); 724} 725 726gss_ctx_id_t 727dst_key_getgssctx(const dst_key_t *key) 728{ 729 REQUIRE(key != NULL); 730 731 return (key->keydata.gssctx); 732} 733 734isc_result_t 735dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, 736 dst_key_t **keyp, isc_region_t *intoken) 737{ 738 dst_key_t *key; 739 isc_result_t result; 740 741 REQUIRE(gssctx != NULL); 742 REQUIRE(keyp != NULL && *keyp == NULL); 743 744 key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 745 0, dns_rdataclass_in, 0, mctx); 746 if (key == NULL) 747 return (ISC_R_NOMEMORY); 748 749 if (intoken != NULL) { 750 /* 751 * Keep the token for use by external ssu rules. They may need 752 * to examine the PAC in the kerberos ticket. 753 */ 754 RETERR(isc_buffer_allocate(key->mctx, &key->key_tkeytoken, 755 intoken->length)); 756 RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken)); 757 } 758 759 key->keydata.gssctx = gssctx; 760 *keyp = key; 761 result = ISC_R_SUCCESS; 762out: 763 return result; 764} 765 766isc_result_t 767dst_key_buildinternal(dns_name_t *name, unsigned int alg, 768 unsigned int bits, unsigned int flags, 769 unsigned int protocol, dns_rdataclass_t rdclass, 770 void *data, isc_mem_t *mctx, dst_key_t **keyp) 771{ 772 dst_key_t *key; 773 isc_result_t result; 774 775 REQUIRE(dst_initialized == ISC_TRUE); 776 REQUIRE(dns_name_isabsolute(name)); 777 REQUIRE(mctx != NULL); 778 REQUIRE(keyp != NULL && *keyp == NULL); 779 REQUIRE(data != NULL); 780 781 CHECKALG(alg); 782 783 key = get_key_struct(name, alg, flags, protocol, bits, rdclass, 784 0, mctx); 785 if (key == NULL) 786 return (ISC_R_NOMEMORY); 787 788 key->keydata.generic = data; 789 790 result = computeid(key); 791 if (result != ISC_R_SUCCESS) { 792 dst_key_free(&key); 793 return (result); 794 } 795 796 *keyp = key; 797 return (ISC_R_SUCCESS); 798} 799 800isc_result_t 801dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags, 802 unsigned int protocol, dns_rdataclass_t rdclass, 803 const char *engine, const char *label, const char *pin, 804 isc_mem_t *mctx, dst_key_t **keyp) 805{ 806 dst_key_t *key; 807 isc_result_t result; 808 809 REQUIRE(dst_initialized == ISC_TRUE); 810 REQUIRE(dns_name_isabsolute(name)); 811 REQUIRE(mctx != NULL); 812 REQUIRE(keyp != NULL && *keyp == NULL); 813 REQUIRE(label != NULL); 814 815 CHECKALG(alg); 816 817 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx); 818 if (key == NULL) 819 return (ISC_R_NOMEMORY); 820 821 if (key->func->fromlabel == NULL) { 822 dst_key_free(&key); 823 return (DST_R_UNSUPPORTEDALG); 824 } 825 826 result = key->func->fromlabel(key, engine, label, pin); 827 if (result != ISC_R_SUCCESS) { 828 dst_key_free(&key); 829 return (result); 830 } 831 832 result = computeid(key); 833 if (result != ISC_R_SUCCESS) { 834 dst_key_free(&key); 835 return (result); 836 } 837 838 *keyp = key; 839 return (ISC_R_SUCCESS); 840} 841 842isc_result_t 843dst_key_generate(dns_name_t *name, unsigned int alg, 844 unsigned int bits, unsigned int param, 845 unsigned int flags, unsigned int protocol, 846 dns_rdataclass_t rdclass, 847 isc_mem_t *mctx, dst_key_t **keyp) 848{ 849 return (dst_key_generate2(name, alg, bits, param, flags, protocol, 850 rdclass, mctx, keyp, NULL)); 851} 852 853isc_result_t 854dst_key_generate2(dns_name_t *name, unsigned int alg, 855 unsigned int bits, unsigned int param, 856 unsigned int flags, unsigned int protocol, 857 dns_rdataclass_t rdclass, 858 isc_mem_t *mctx, dst_key_t **keyp, 859 void (*callback)(int)) 860{ 861 dst_key_t *key; 862 isc_result_t ret; 863 864 REQUIRE(dst_initialized == ISC_TRUE); 865 REQUIRE(dns_name_isabsolute(name)); 866 REQUIRE(mctx != NULL); 867 REQUIRE(keyp != NULL && *keyp == NULL); 868 869 CHECKALG(alg); 870 871 key = get_key_struct(name, alg, flags, protocol, bits, 872 rdclass, 0, mctx); 873 if (key == NULL) 874 return (ISC_R_NOMEMORY); 875 876 if (bits == 0) { /*%< NULL KEY */ 877 key->key_flags |= DNS_KEYTYPE_NOKEY; 878 *keyp = key; 879 return (ISC_R_SUCCESS); 880 } 881 882 if (key->func->generate == NULL) { 883 dst_key_free(&key); 884 return (DST_R_UNSUPPORTEDALG); 885 } 886 887 ret = key->func->generate(key, param, callback); 888 if (ret != ISC_R_SUCCESS) { 889 dst_key_free(&key); 890 return (ret); 891 } 892 893 ret = computeid(key); 894 if (ret != ISC_R_SUCCESS) { 895 dst_key_free(&key); 896 return (ret); 897 } 898 899 *keyp = key; 900 return (ISC_R_SUCCESS); 901} 902 903isc_result_t 904dst_key_getnum(const dst_key_t *key, int type, isc_uint32_t *valuep) 905{ 906 REQUIRE(VALID_KEY(key)); 907 REQUIRE(valuep != NULL); 908 REQUIRE(type <= DST_MAX_NUMERIC); 909 if (!key->numset[type]) 910 return (ISC_R_NOTFOUND); 911 *valuep = key->nums[type]; 912 return (ISC_R_SUCCESS); 913} 914 915void 916dst_key_setnum(dst_key_t *key, int type, isc_uint32_t value) 917{ 918 REQUIRE(VALID_KEY(key)); 919 REQUIRE(type <= DST_MAX_NUMERIC); 920 key->nums[type] = value; 921 key->numset[type] = ISC_TRUE; 922} 923 924void 925dst_key_unsetnum(dst_key_t *key, int type) 926{ 927 REQUIRE(VALID_KEY(key)); 928 REQUIRE(type <= DST_MAX_NUMERIC); 929 key->numset[type] = ISC_FALSE; 930} 931 932isc_result_t 933dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) { 934 REQUIRE(VALID_KEY(key)); 935 REQUIRE(timep != NULL); 936 REQUIRE(type <= DST_MAX_TIMES); 937 if (!key->timeset[type]) 938 return (ISC_R_NOTFOUND); 939 *timep = key->times[type]; 940 return (ISC_R_SUCCESS); 941} 942 943void 944dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) { 945 REQUIRE(VALID_KEY(key)); 946 REQUIRE(type <= DST_MAX_TIMES); 947 key->times[type] = when; 948 key->timeset[type] = ISC_TRUE; 949} 950 951void 952dst_key_unsettime(dst_key_t *key, int type) { 953 REQUIRE(VALID_KEY(key)); 954 REQUIRE(type <= DST_MAX_TIMES); 955 key->timeset[type] = ISC_FALSE; 956} 957 958isc_result_t 959dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) { 960 REQUIRE(VALID_KEY(key)); 961 REQUIRE(majorp != NULL); 962 REQUIRE(minorp != NULL); 963 *majorp = key->fmt_major; 964 *minorp = key->fmt_minor; 965 return (ISC_R_SUCCESS); 966} 967 968void 969dst_key_setprivateformat(dst_key_t *key, int major, int minor) { 970 REQUIRE(VALID_KEY(key)); 971 key->fmt_major = major; 972 key->fmt_minor = minor; 973} 974 975static isc_boolean_t 976comparekeys(const dst_key_t *key1, const dst_key_t *key2, 977 isc_boolean_t match_revoked_key, 978 isc_boolean_t (*compare)(const dst_key_t *key1, 979 const dst_key_t *key2)) 980{ 981 REQUIRE(dst_initialized == ISC_TRUE); 982 REQUIRE(VALID_KEY(key1)); 983 REQUIRE(VALID_KEY(key2)); 984 985 if (key1 == key2) 986 return (ISC_TRUE); 987 988 if (key1 == NULL || key2 == NULL) 989 return (ISC_FALSE); 990 991 if (key1->key_alg != key2->key_alg) 992 return (ISC_FALSE); 993 994 if (key1->key_id != key2->key_id) { 995 if (!match_revoked_key) 996 return (ISC_FALSE); 997 if (key1->key_alg == DST_ALG_RSAMD5) 998 return (ISC_FALSE); 999 if ((key1->key_flags & DNS_KEYFLAG_REVOKE) == 1000 (key2->key_flags & DNS_KEYFLAG_REVOKE)) 1001 return (ISC_FALSE); 1002 if (key1->key_id != key2->key_rid && 1003 key1->key_rid != key2->key_id) 1004 return (ISC_FALSE); 1005 } 1006 1007 if (compare != NULL) 1008 return (compare(key1, key2)); 1009 else 1010 return (ISC_FALSE); 1011} 1012 1013 1014/* 1015 * Compares only the public portion of two keys, by converting them 1016 * both to wire format and comparing the results. 1017 */ 1018static isc_boolean_t 1019pub_compare(const dst_key_t *key1, const dst_key_t *key2) { 1020 isc_result_t result; 1021 unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE]; 1022 isc_buffer_t b1, b2; 1023 isc_region_t r1, r2; 1024 1025 isc_buffer_init(&b1, buf1, sizeof(buf1)); 1026 result = dst_key_todns(key1, &b1); 1027 if (result != ISC_R_SUCCESS) 1028 return (ISC_FALSE); 1029 /* Zero out flags. */ 1030 buf1[0] = buf1[1] = 0; 1031 if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) 1032 isc_buffer_subtract(&b1, 2); 1033 1034 isc_buffer_init(&b2, buf2, sizeof(buf2)); 1035 result = dst_key_todns(key2, &b2); 1036 if (result != ISC_R_SUCCESS) 1037 return (ISC_FALSE); 1038 /* Zero out flags. */ 1039 buf2[0] = buf2[1] = 0; 1040 if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) 1041 isc_buffer_subtract(&b2, 2); 1042 1043 isc_buffer_usedregion(&b1, &r1); 1044 /* Remove extended flags. */ 1045 if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { 1046 memmove(&buf1[4], &buf1[6], r1.length - 6); 1047 r1.length -= 2; 1048 } 1049 1050 isc_buffer_usedregion(&b2, &r2); 1051 /* Remove extended flags. */ 1052 if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { 1053 memmove(&buf2[4], &buf2[6], r2.length - 6); 1054 r2.length -= 2; 1055 } 1056 return (ISC_TF(isc_region_compare(&r1, &r2) == 0)); 1057} 1058 1059isc_boolean_t 1060dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { 1061 return (comparekeys(key1, key2, ISC_FALSE, key1->func->compare)); 1062} 1063 1064isc_boolean_t 1065dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2, 1066 isc_boolean_t match_revoked_key) 1067{ 1068 return (comparekeys(key1, key2, match_revoked_key, pub_compare)); 1069} 1070 1071 1072isc_boolean_t 1073dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { 1074 REQUIRE(dst_initialized == ISC_TRUE); 1075 REQUIRE(VALID_KEY(key1)); 1076 REQUIRE(VALID_KEY(key2)); 1077 1078 if (key1 == key2) 1079 return (ISC_TRUE); 1080 if (key1 == NULL || key2 == NULL) 1081 return (ISC_FALSE); 1082 if (key1->key_alg == key2->key_alg && 1083 key1->func->paramcompare != NULL && 1084 key1->func->paramcompare(key1, key2) == ISC_TRUE) 1085 return (ISC_TRUE); 1086 else 1087 return (ISC_FALSE); 1088} 1089 1090void 1091dst_key_attach(dst_key_t *source, dst_key_t **target) { 1092 1093 REQUIRE(dst_initialized == ISC_TRUE); 1094 REQUIRE(target != NULL && *target == NULL); 1095 REQUIRE(VALID_KEY(source)); 1096 1097 isc_refcount_increment(&source->refs, NULL); 1098 *target = source; 1099} 1100 1101void 1102dst_key_free(dst_key_t **keyp) { 1103 isc_mem_t *mctx; 1104 dst_key_t *key; 1105 unsigned int refs; 1106 1107 REQUIRE(dst_initialized == ISC_TRUE); 1108 REQUIRE(keyp != NULL && VALID_KEY(*keyp)); 1109 1110 key = *keyp; 1111 mctx = key->mctx; 1112 1113 isc_refcount_decrement(&key->refs, &refs); 1114 if (refs != 0) 1115 return; 1116 1117 isc_refcount_destroy(&key->refs); 1118 if (key->keydata.generic != NULL) { 1119 INSIST(key->func->destroy != NULL); 1120 key->func->destroy(key); 1121 } 1122 if (key->engine != NULL) 1123 isc_mem_free(mctx, key->engine); 1124 if (key->label != NULL) 1125 isc_mem_free(mctx, key->label); 1126 dns_name_free(key->key_name, mctx); 1127 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 1128 if (key->key_tkeytoken) { 1129 isc_buffer_free(&key->key_tkeytoken); 1130 } 1131 memset(key, 0, sizeof(dst_key_t)); 1132 isc_mem_put(mctx, key, sizeof(dst_key_t)); 1133 *keyp = NULL; 1134} 1135 1136isc_boolean_t 1137dst_key_isprivate(const dst_key_t *key) { 1138 REQUIRE(VALID_KEY(key)); 1139 INSIST(key->func->isprivate != NULL); 1140 return (key->func->isprivate(key)); 1141} 1142 1143isc_result_t 1144dst_key_buildfilename(const dst_key_t *key, int type, 1145 const char *directory, isc_buffer_t *out) { 1146 1147 REQUIRE(VALID_KEY(key)); 1148 REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC || 1149 type == 0); 1150 1151 return (buildfilename(key->key_name, key->key_id, key->key_alg, 1152 type, directory, out)); 1153} 1154 1155isc_result_t 1156dst_key_sigsize(const dst_key_t *key, unsigned int *n) { 1157 REQUIRE(dst_initialized == ISC_TRUE); 1158 REQUIRE(VALID_KEY(key)); 1159 REQUIRE(n != NULL); 1160 1161 /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1162 switch (key->key_alg) { 1163 case DST_ALG_RSAMD5: 1164 case DST_ALG_RSASHA1: 1165 case DST_ALG_NSEC3RSASHA1: 1166 case DST_ALG_RSASHA256: 1167 case DST_ALG_RSASHA512: 1168 *n = (key->key_size + 7) / 8; 1169 break; 1170 case DST_ALG_DSA: 1171 case DST_ALG_NSEC3DSA: 1172 *n = DNS_SIG_DSASIGSIZE; 1173 break; 1174 case DST_ALG_ECCGOST: 1175 *n = DNS_SIG_GOSTSIGSIZE; 1176 break; 1177 case DST_ALG_ECDSA256: 1178 *n = DNS_SIG_ECDSA256SIZE; 1179 break; 1180 case DST_ALG_ECDSA384: 1181 *n = DNS_SIG_ECDSA384SIZE; 1182 break; 1183 case DST_ALG_HMACMD5: 1184 *n = 16; 1185 break; 1186 case DST_ALG_HMACSHA1: 1187 *n = ISC_SHA1_DIGESTLENGTH; 1188 break; 1189 case DST_ALG_HMACSHA224: 1190 *n = ISC_SHA224_DIGESTLENGTH; 1191 break; 1192 case DST_ALG_HMACSHA256: 1193 *n = ISC_SHA256_DIGESTLENGTH; 1194 break; 1195 case DST_ALG_HMACSHA384: 1196 *n = ISC_SHA384_DIGESTLENGTH; 1197 break; 1198 case DST_ALG_HMACSHA512: 1199 *n = ISC_SHA512_DIGESTLENGTH; 1200 break; 1201 case DST_ALG_GSSAPI: 1202 *n = 128; /*%< XXX */ 1203 break; 1204 case DST_ALG_DH: 1205 default: 1206 return (DST_R_UNSUPPORTEDALG); 1207 } 1208 return (ISC_R_SUCCESS); 1209} 1210 1211isc_result_t 1212dst_key_secretsize(const dst_key_t *key, unsigned int *n) { 1213 REQUIRE(dst_initialized == ISC_TRUE); 1214 REQUIRE(VALID_KEY(key)); 1215 REQUIRE(n != NULL); 1216 1217 if (key->key_alg == DST_ALG_DH) 1218 *n = (key->key_size + 7) / 8; 1219 else 1220 return (DST_R_UNSUPPORTEDALG); 1221 return (ISC_R_SUCCESS); 1222} 1223 1224/*% 1225 * Set the flags on a key, then recompute the key ID 1226 */ 1227isc_result_t 1228dst_key_setflags(dst_key_t *key, isc_uint32_t flags) { 1229 REQUIRE(VALID_KEY(key)); 1230 key->key_flags = flags; 1231 return (computeid(key)); 1232} 1233 1234void 1235dst_key_format(const dst_key_t *key, char *cp, unsigned int size) { 1236 char namestr[DNS_NAME_FORMATSIZE]; 1237 char algstr[DNS_NAME_FORMATSIZE]; 1238 1239 dns_name_format(dst_key_name(key), namestr, sizeof(namestr)); 1240 dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr, 1241 sizeof(algstr)); 1242 snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key)); 1243} 1244 1245isc_result_t 1246dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) { 1247 1248 REQUIRE(buffer != NULL && *buffer == NULL); 1249 REQUIRE(length != NULL && *length == 0); 1250 REQUIRE(VALID_KEY(key)); 1251 1252 if (key->func->isprivate == NULL) 1253 return (ISC_R_NOTIMPLEMENTED); 1254 return (key->func->dump(key, mctx, buffer, length)); 1255} 1256 1257isc_result_t 1258dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags, 1259 unsigned int protocol, dns_rdataclass_t rdclass, 1260 isc_mem_t *mctx, const char *keystr, dst_key_t **keyp) 1261{ 1262 isc_result_t result; 1263 dst_key_t *key; 1264 1265 REQUIRE(dst_initialized == ISC_TRUE); 1266 REQUIRE(keyp != NULL && *keyp == NULL); 1267 1268 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) 1269 return (DST_R_UNSUPPORTEDALG); 1270 1271 if (dst_t_func[alg]->restore == NULL) 1272 return (ISC_R_NOTIMPLEMENTED); 1273 1274 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx); 1275 if (key == NULL) 1276 return (ISC_R_NOMEMORY); 1277 1278 result = (dst_t_func[alg]->restore)(key, keystr); 1279 if (result == ISC_R_SUCCESS) 1280 *keyp = key; 1281 else 1282 dst_key_free(&key); 1283 1284 return (result); 1285} 1286 1287/*** 1288 *** Static methods 1289 ***/ 1290 1291/*% 1292 * Allocates a key structure and fills in some of the fields. 1293 */ 1294static dst_key_t * 1295get_key_struct(dns_name_t *name, unsigned int alg, 1296 unsigned int flags, unsigned int protocol, 1297 unsigned int bits, dns_rdataclass_t rdclass, 1298 dns_ttl_t ttl, isc_mem_t *mctx) 1299{ 1300 dst_key_t *key; 1301 isc_result_t result; 1302 int i; 1303 1304 key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); 1305 if (key == NULL) 1306 return (NULL); 1307 1308 memset(key, 0, sizeof(dst_key_t)); 1309 key->magic = KEY_MAGIC; 1310 1311 result = isc_refcount_init(&key->refs, 1); 1312 if (result != ISC_R_SUCCESS) { 1313 isc_mem_put(mctx, key, sizeof(dst_key_t)); 1314 return (NULL); 1315 } 1316 1317 key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); 1318 if (key->key_name == NULL) { 1319 isc_refcount_destroy(&key->refs); 1320 isc_mem_put(mctx, key, sizeof(dst_key_t)); 1321 return (NULL); 1322 } 1323 dns_name_init(key->key_name, NULL); 1324 result = dns_name_dup(name, mctx, key->key_name); 1325 if (result != ISC_R_SUCCESS) { 1326 isc_refcount_destroy(&key->refs); 1327 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 1328 isc_mem_put(mctx, key, sizeof(dst_key_t)); 1329 return (NULL); 1330 } 1331 key->key_alg = alg; 1332 key->key_flags = flags; 1333 key->key_proto = protocol; 1334 key->mctx = mctx; 1335 key->keydata.generic = NULL; 1336 key->key_size = bits; 1337 key->key_class = rdclass; 1338 key->key_ttl = ttl; 1339 key->func = dst_t_func[alg]; 1340 key->fmt_major = 0; 1341 key->fmt_minor = 0; 1342 for (i = 0; i < (DST_MAX_TIMES + 1); i++) { 1343 key->times[i] = 0; 1344 key->timeset[i] = ISC_FALSE; 1345 } 1346 return (key); 1347} 1348 1349/*% 1350 * Reads a public key from disk 1351 */ 1352isc_result_t 1353dst_key_read_public(const char *filename, int type, 1354 isc_mem_t *mctx, dst_key_t **keyp) 1355{ 1356 u_char rdatabuf[DST_KEY_MAXSIZE]; 1357 isc_buffer_t b; 1358 dns_fixedname_t name; 1359 isc_lex_t *lex = NULL; 1360 isc_token_t token; 1361 isc_result_t ret; 1362 dns_rdata_t rdata = DNS_RDATA_INIT; 1363 unsigned int opt = ISC_LEXOPT_DNSMULTILINE; 1364 dns_rdataclass_t rdclass = dns_rdataclass_in; 1365 isc_lexspecials_t specials; 1366 isc_uint32_t ttl = 0; 1367 isc_result_t result; 1368 dns_rdatatype_t keytype; 1369 1370 /* 1371 * Open the file and read its formatted contents 1372 * File format: 1373 * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key> 1374 */ 1375 1376 /* 1500 should be large enough for any key */ 1377 ret = isc_lex_create(mctx, 1500, &lex); 1378 if (ret != ISC_R_SUCCESS) 1379 goto cleanup; 1380 1381 memset(specials, 0, sizeof(specials)); 1382 specials['('] = 1; 1383 specials[')'] = 1; 1384 specials['"'] = 1; 1385 isc_lex_setspecials(lex, specials); 1386 isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); 1387 1388 ret = isc_lex_openfile(lex, filename); 1389 if (ret != ISC_R_SUCCESS) 1390 goto cleanup; 1391 1392#define NEXTTOKEN(lex, opt, token) { \ 1393 ret = isc_lex_gettoken(lex, opt, token); \ 1394 if (ret != ISC_R_SUCCESS) \ 1395 goto cleanup; \ 1396 } 1397 1398#define BADTOKEN() { \ 1399 ret = ISC_R_UNEXPECTEDTOKEN; \ 1400 goto cleanup; \ 1401 } 1402 1403 /* Read the domain name */ 1404 NEXTTOKEN(lex, opt, &token); 1405 if (token.type != isc_tokentype_string) 1406 BADTOKEN(); 1407 1408 /* 1409 * We don't support "@" in .key files. 1410 */ 1411 if (!strcmp(DST_AS_STR(token), "@")) 1412 BADTOKEN(); 1413 1414 dns_fixedname_init(&name); 1415 isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); 1416 isc_buffer_add(&b, strlen(DST_AS_STR(token))); 1417 ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, 1418 0, NULL); 1419 if (ret != ISC_R_SUCCESS) 1420 goto cleanup; 1421 1422 /* Read the next word: either TTL, class, or 'KEY' */ 1423 NEXTTOKEN(lex, opt, &token); 1424 1425 if (token.type != isc_tokentype_string) 1426 BADTOKEN(); 1427 1428 /* If it's a TTL, read the next one */ 1429 result = dns_ttl_fromtext(&token.value.as_textregion, &ttl); 1430 if (result == ISC_R_SUCCESS) 1431 NEXTTOKEN(lex, opt, &token); 1432 1433 if (token.type != isc_tokentype_string) 1434 BADTOKEN(); 1435 1436 ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion); 1437 if (ret == ISC_R_SUCCESS) 1438 NEXTTOKEN(lex, opt, &token); 1439 1440 if (token.type != isc_tokentype_string) 1441 BADTOKEN(); 1442 1443 if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) 1444 keytype = dns_rdatatype_dnskey; 1445 else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) 1446 keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */ 1447 else 1448 BADTOKEN(); 1449 1450 if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) || 1451 ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) { 1452 ret = DST_R_BADKEYTYPE; 1453 goto cleanup; 1454 } 1455 1456 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); 1457 ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, 1458 ISC_FALSE, mctx, &b, NULL); 1459 if (ret != ISC_R_SUCCESS) 1460 goto cleanup; 1461 1462 ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx, 1463 keyp); 1464 if (ret != ISC_R_SUCCESS) 1465 goto cleanup; 1466 1467 dst_key_setttl(*keyp, ttl); 1468 1469 cleanup: 1470 if (lex != NULL) 1471 isc_lex_destroy(&lex); 1472 return (ret); 1473} 1474 1475static isc_boolean_t 1476issymmetric(const dst_key_t *key) { 1477 REQUIRE(dst_initialized == ISC_TRUE); 1478 REQUIRE(VALID_KEY(key)); 1479 1480 /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1481 switch (key->key_alg) { 1482 case DST_ALG_RSAMD5: 1483 case DST_ALG_RSASHA1: 1484 case DST_ALG_NSEC3RSASHA1: 1485 case DST_ALG_RSASHA256: 1486 case DST_ALG_RSASHA512: 1487 case DST_ALG_DSA: 1488 case DST_ALG_NSEC3DSA: 1489 case DST_ALG_DH: 1490 case DST_ALG_ECCGOST: 1491 case DST_ALG_ECDSA256: 1492 case DST_ALG_ECDSA384: 1493 return (ISC_FALSE); 1494 case DST_ALG_HMACMD5: 1495 case DST_ALG_GSSAPI: 1496 return (ISC_TRUE); 1497 default: 1498 return (ISC_FALSE); 1499 } 1500} 1501 1502/*% 1503 * Write key timing metadata to a file pointer, preceded by 'tag' 1504 */ 1505static void 1506printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) { 1507 isc_result_t result; 1508#ifdef ISC_PLATFORM_USETHREADS 1509 char output[26]; /* Minimum buffer as per ctime_r() specification. */ 1510#else 1511 const char *output; 1512#endif 1513 isc_stdtime_t when; 1514 time_t t; 1515 char utc[sizeof("YYYYMMDDHHSSMM")]; 1516 isc_buffer_t b; 1517 isc_region_t r; 1518 1519 result = dst_key_gettime(key, type, &when); 1520 if (result == ISC_R_NOTFOUND) 1521 return; 1522 1523 /* time_t and isc_stdtime_t might be different sizes */ 1524 t = when; 1525#ifdef ISC_PLATFORM_USETHREADS 1526#ifdef WIN32 1527 if (ctime_s(output, sizeof(output), &t) != 0) 1528 goto error; 1529#else 1530 if (ctime_r(&t, output) == NULL) 1531 goto error; 1532#endif 1533#else 1534 output = ctime(&t); 1535#endif 1536 1537 isc_buffer_init(&b, utc, sizeof(utc)); 1538 result = dns_time32_totext(when, &b); 1539 if (result != ISC_R_SUCCESS) 1540 goto error; 1541 1542 isc_buffer_usedregion(&b, &r); 1543 fprintf(stream, "%s: %.*s (%.*s)\n", tag, (int)r.length, r.base, 1544 (int)strlen(output) - 1, output); 1545 return; 1546 1547 error: 1548 fprintf(stream, "%s: (set, unable to display)\n", tag); 1549} 1550 1551/*% 1552 * Writes a public key to disk in DNS format. 1553 */ 1554static isc_result_t 1555write_public_key(const dst_key_t *key, int type, const char *directory) { 1556 FILE *fp; 1557 isc_buffer_t keyb, textb, fileb, classb; 1558 isc_region_t r; 1559 char filename[ISC_DIR_NAMEMAX]; 1560 unsigned char key_array[DST_KEY_MAXSIZE]; 1561 char text_array[DST_KEY_MAXTEXTSIZE]; 1562 char class_array[10]; 1563 isc_result_t ret; 1564 dns_rdata_t rdata = DNS_RDATA_INIT; 1565 isc_fsaccess_t access; 1566 1567 REQUIRE(VALID_KEY(key)); 1568 1569 isc_buffer_init(&keyb, key_array, sizeof(key_array)); 1570 isc_buffer_init(&textb, text_array, sizeof(text_array)); 1571 isc_buffer_init(&classb, class_array, sizeof(class_array)); 1572 1573 ret = dst_key_todns(key, &keyb); 1574 if (ret != ISC_R_SUCCESS) 1575 return (ret); 1576 1577 isc_buffer_usedregion(&keyb, &r); 1578 dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r); 1579 1580 ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb); 1581 if (ret != ISC_R_SUCCESS) 1582 return (DST_R_INVALIDPUBLICKEY); 1583 1584 ret = dns_rdataclass_totext(key->key_class, &classb); 1585 if (ret != ISC_R_SUCCESS) 1586 return (DST_R_INVALIDPUBLICKEY); 1587 1588 /* 1589 * Make the filename. 1590 */ 1591 isc_buffer_init(&fileb, filename, sizeof(filename)); 1592 ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb); 1593 if (ret != ISC_R_SUCCESS) 1594 return (ret); 1595 1596 /* 1597 * Create public key file. 1598 */ 1599 if ((fp = fopen(filename, "w")) == NULL) 1600 return (DST_R_WRITEERROR); 1601 1602 if (issymmetric(key)) { 1603 access = 0; 1604 isc_fsaccess_add(ISC_FSACCESS_OWNER, 1605 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, 1606 &access); 1607 (void)isc_fsaccess_set(filename, access); 1608 } 1609 1610 /* Write key information in comments */ 1611 if ((type & DST_TYPE_KEY) == 0) { 1612 fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ", 1613 (key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ? 1614 "revoked " : 1615 "", 1616 (key->key_flags & DNS_KEYFLAG_KSK) != 0 ? 1617 "key" : 1618 "zone", 1619 key->key_id); 1620 ret = dns_name_print(key->key_name, fp); 1621 if (ret != ISC_R_SUCCESS) { 1622 fclose(fp); 1623 return (ret); 1624 } 1625 fputc('\n', fp); 1626 1627 printtime(key, DST_TIME_CREATED, "; Created", fp); 1628 printtime(key, DST_TIME_PUBLISH, "; Publish", fp); 1629 printtime(key, DST_TIME_ACTIVATE, "; Activate", fp); 1630 printtime(key, DST_TIME_REVOKE, "; Revoke", fp); 1631 printtime(key, DST_TIME_INACTIVE, "; Inactive", fp); 1632 printtime(key, DST_TIME_DELETE, "; Delete", fp); 1633 } 1634 1635 /* Now print the actual key */ 1636 ret = dns_name_print(key->key_name, fp); 1637 fprintf(fp, " "); 1638 1639 if (key->key_ttl != 0) 1640 fprintf(fp, "%d ", key->key_ttl); 1641 1642 isc_buffer_usedregion(&classb, &r); 1643 if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length) 1644 ret = DST_R_WRITEERROR; 1645 1646 if ((type & DST_TYPE_KEY) != 0) 1647 fprintf(fp, " KEY "); 1648 else 1649 fprintf(fp, " DNSKEY "); 1650 1651 isc_buffer_usedregion(&textb, &r); 1652 if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length) 1653 ret = DST_R_WRITEERROR; 1654 1655 fputc('\n', fp); 1656 fflush(fp); 1657 if (ferror(fp)) 1658 ret = DST_R_WRITEERROR; 1659 fclose(fp); 1660 1661 return (ret); 1662} 1663 1664static isc_result_t 1665buildfilename(dns_name_t *name, dns_keytag_t id, 1666 unsigned int alg, unsigned int type, 1667 const char *directory, isc_buffer_t *out) 1668{ 1669 const char *suffix = ""; 1670 unsigned int len; 1671 isc_result_t result; 1672 1673 REQUIRE(out != NULL); 1674 if ((type & DST_TYPE_PRIVATE) != 0) 1675 suffix = ".private"; 1676 else if (type == DST_TYPE_PUBLIC) 1677 suffix = ".key"; 1678 if (directory != NULL) { 1679 if (isc_buffer_availablelength(out) < strlen(directory)) 1680 return (ISC_R_NOSPACE); 1681 isc_buffer_putstr(out, directory); 1682 if (strlen(directory) > 0U && 1683 directory[strlen(directory) - 1] != '/') 1684 isc_buffer_putstr(out, "/"); 1685 } 1686 if (isc_buffer_availablelength(out) < 1) 1687 return (ISC_R_NOSPACE); 1688 isc_buffer_putstr(out, "K"); 1689 result = dns_name_tofilenametext(name, ISC_FALSE, out); 1690 if (result != ISC_R_SUCCESS) 1691 return (result); 1692 len = 1 + 3 + 1 + 5 + strlen(suffix) + 1; 1693 if (isc_buffer_availablelength(out) < len) 1694 return (ISC_R_NOSPACE); 1695 sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, 1696 suffix); 1697 isc_buffer_add(out, len); 1698 1699 return (ISC_R_SUCCESS); 1700} 1701 1702static isc_result_t 1703computeid(dst_key_t *key) { 1704 isc_buffer_t dnsbuf; 1705 unsigned char dns_array[DST_KEY_MAXSIZE]; 1706 isc_region_t r; 1707 isc_result_t ret; 1708 1709 isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array)); 1710 ret = dst_key_todns(key, &dnsbuf); 1711 if (ret != ISC_R_SUCCESS) 1712 return (ret); 1713 1714 isc_buffer_usedregion(&dnsbuf, &r); 1715 key->key_id = dst_region_computeid(&r, key->key_alg); 1716 key->key_rid = dst_region_computerid(&r, key->key_alg); 1717 return (ISC_R_SUCCESS); 1718} 1719 1720static isc_result_t 1721frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags, 1722 unsigned int protocol, dns_rdataclass_t rdclass, 1723 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 1724{ 1725 dst_key_t *key; 1726 isc_result_t ret; 1727 1728 REQUIRE(dns_name_isabsolute(name)); 1729 REQUIRE(source != NULL); 1730 REQUIRE(mctx != NULL); 1731 REQUIRE(keyp != NULL && *keyp == NULL); 1732 1733 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx); 1734 if (key == NULL) 1735 return (ISC_R_NOMEMORY); 1736 1737 if (isc_buffer_remaininglength(source) > 0) { 1738 ret = algorithm_status(alg); 1739 if (ret != ISC_R_SUCCESS) { 1740 dst_key_free(&key); 1741 return (ret); 1742 } 1743 if (key->func->fromdns == NULL) { 1744 dst_key_free(&key); 1745 return (DST_R_UNSUPPORTEDALG); 1746 } 1747 1748 ret = key->func->fromdns(key, source); 1749 if (ret != ISC_R_SUCCESS) { 1750 dst_key_free(&key); 1751 return (ret); 1752 } 1753 } 1754 1755 *keyp = key; 1756 return (ISC_R_SUCCESS); 1757} 1758 1759static isc_result_t 1760algorithm_status(unsigned int alg) { 1761 REQUIRE(dst_initialized == ISC_TRUE); 1762 1763 if (dst_algorithm_supported(alg)) 1764 return (ISC_R_SUCCESS); 1765#ifndef OPENSSL 1766 if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || 1767 alg == DST_ALG_DSA || alg == DST_ALG_DH || 1768 alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA || 1769 alg == DST_ALG_NSEC3RSASHA1 || 1770 alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512 || 1771 alg == DST_ALG_ECCGOST || 1772 alg == DST_ALG_ECDSA256 || alg == DST_ALG_ECDSA384) 1773 return (DST_R_NOCRYPTO); 1774#endif 1775 return (DST_R_UNSUPPORTEDALG); 1776} 1777 1778static isc_result_t 1779addsuffix(char *filename, int len, const char *odirname, 1780 const char *ofilename, const char *suffix) 1781{ 1782 int olen = strlen(ofilename); 1783 int n; 1784 1785 if (olen > 1 && ofilename[olen - 1] == '.') 1786 olen -= 1; 1787 else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) 1788 olen -= 8; 1789 else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) 1790 olen -= 4; 1791 1792 if (odirname == NULL) 1793 n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); 1794 else 1795 n = snprintf(filename, len, "%s/%.*s%s", 1796 odirname, olen, ofilename, suffix); 1797 if (n < 0) 1798 return (ISC_R_FAILURE); 1799 if (n >= len) 1800 return (ISC_R_NOSPACE); 1801 return (ISC_R_SUCCESS); 1802} 1803 1804isc_result_t 1805dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { 1806#ifdef BIND9 1807 unsigned int flags = dst_entropy_flags; 1808 1809 if (len == 0) 1810 return (ISC_R_SUCCESS); 1811 if (pseudo) 1812 flags &= ~ISC_ENTROPY_GOODONLY; 1813 else 1814 flags |= ISC_ENTROPY_BLOCKING; 1815 return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); 1816#else 1817 UNUSED(buf); 1818 UNUSED(len); 1819 UNUSED(pseudo); 1820 1821 return (ISC_R_NOTIMPLEMENTED); 1822#endif 1823} 1824 1825unsigned int 1826dst__entropy_status(void) { 1827#ifdef BIND9 1828#ifdef GSSAPI 1829 unsigned int flags = dst_entropy_flags; 1830 isc_result_t ret; 1831 unsigned char buf[32]; 1832 static isc_boolean_t first = ISC_TRUE; 1833 1834 if (first) { 1835 /* Someone believes RAND_status() initializes the PRNG */ 1836 flags &= ~ISC_ENTROPY_GOODONLY; 1837 ret = isc_entropy_getdata(dst_entropy_pool, buf, 1838 sizeof(buf), NULL, flags); 1839 INSIST(ret == ISC_R_SUCCESS); 1840 isc_entropy_putdata(dst_entropy_pool, buf, 1841 sizeof(buf), 2 * sizeof(buf)); 1842 first = ISC_FALSE; 1843 } 1844#endif 1845 return (isc_entropy_status(dst_entropy_pool)); 1846#else 1847 return (0); 1848#endif 1849} 1850 1851isc_buffer_t * 1852dst_key_tkeytoken(const dst_key_t *key) { 1853 REQUIRE(VALID_KEY(key)); 1854 return (key->key_tkeytoken); 1855} 1856