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