1/* 2 * Portions Copyright (C) 2004-2012 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$ 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 451 *keyp = key; 452 return (ISC_R_SUCCESS); 453} 454 455isc_result_t 456dst_key_fromnamedfile(const char *filename, const char *dirname, 457 int type, isc_mem_t *mctx, dst_key_t **keyp) 458{ 459 isc_result_t result; 460 dst_key_t *pubkey = NULL, *key = NULL; 461 char *newfilename = NULL; 462 int newfilenamelen = 0; 463 isc_lex_t *lex = NULL; 464 465 REQUIRE(dst_initialized == ISC_TRUE); 466 REQUIRE(filename != NULL); 467 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 468 REQUIRE(mctx != NULL); 469 REQUIRE(keyp != NULL && *keyp == NULL); 470 471 /* If an absolute path is specified, don't use the key directory */ 472#ifndef WIN32 473 if (filename[0] == '/') 474 dirname = NULL; 475#else /* WIN32 */ 476 if (filename[0] == '/' || filename[0] == '\\') 477 dirname = NULL; 478#endif 479 480 newfilenamelen = strlen(filename) + 5; 481 if (dirname != NULL) 482 newfilenamelen += strlen(dirname) + 1; 483 newfilename = isc_mem_get(mctx, newfilenamelen); 484 if (newfilename == NULL) 485 return (ISC_R_NOMEMORY); 486 result = addsuffix(newfilename, newfilenamelen, 487 dirname, filename, ".key"); 488 INSIST(result == ISC_R_SUCCESS); 489 490 result = dst_key_read_public(newfilename, type, mctx, &pubkey); 491 isc_mem_put(mctx, newfilename, newfilenamelen); 492 newfilename = NULL; 493 if (result != ISC_R_SUCCESS) 494 return (result); 495 496 if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC || 497 (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { 498 result = computeid(pubkey); 499 if (result != ISC_R_SUCCESS) { 500 dst_key_free(&pubkey); 501 return (result); 502 } 503 504 *keyp = pubkey; 505 return (ISC_R_SUCCESS); 506 } 507 508 result = algorithm_status(pubkey->key_alg); 509 if (result != ISC_R_SUCCESS) { 510 dst_key_free(&pubkey); 511 return (result); 512 } 513 514 key = get_key_struct(pubkey->key_name, pubkey->key_alg, 515 pubkey->key_flags, pubkey->key_proto, 0, 516 pubkey->key_class, mctx); 517 if (key == NULL) { 518 dst_key_free(&pubkey); 519 return (ISC_R_NOMEMORY); 520 } 521 522 if (key->func->parse == NULL) 523 RETERR(DST_R_UNSUPPORTEDALG); 524 525 newfilenamelen = strlen(filename) + 9; 526 if (dirname != NULL) 527 newfilenamelen += strlen(dirname) + 1; 528 newfilename = isc_mem_get(mctx, newfilenamelen); 529 if (newfilename == NULL) 530 RETERR(ISC_R_NOMEMORY); 531 result = addsuffix(newfilename, newfilenamelen, 532 dirname, filename, ".private"); 533 INSIST(result == ISC_R_SUCCESS); 534 535 RETERR(isc_lex_create(mctx, 1500, &lex)); 536 RETERR(isc_lex_openfile(lex, newfilename)); 537 isc_mem_put(mctx, newfilename, newfilenamelen); 538 539 RETERR(key->func->parse(key, lex, pubkey)); 540 isc_lex_destroy(&lex); 541 542 RETERR(computeid(key)); 543 544 if (pubkey->key_id != key->key_id) 545 RETERR(DST_R_INVALIDPRIVATEKEY); 546 dst_key_free(&pubkey); 547 548 *keyp = key; 549 return (ISC_R_SUCCESS); 550 551 out: 552 if (pubkey != NULL) 553 dst_key_free(&pubkey); 554 if (newfilename != NULL) 555 isc_mem_put(mctx, newfilename, newfilenamelen); 556 if (lex != NULL) 557 isc_lex_destroy(&lex); 558 dst_key_free(&key); 559 return (result); 560} 561 562isc_result_t 563dst_key_todns(const dst_key_t *key, isc_buffer_t *target) { 564 REQUIRE(dst_initialized == ISC_TRUE); 565 REQUIRE(VALID_KEY(key)); 566 REQUIRE(target != NULL); 567 568 CHECKALG(key->key_alg); 569 570 if (key->func->todns == NULL) 571 return (DST_R_UNSUPPORTEDALG); 572 573 if (isc_buffer_availablelength(target) < 4) 574 return (ISC_R_NOSPACE); 575 isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff)); 576 isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto); 577 isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg); 578 579 if (key->key_flags & DNS_KEYFLAG_EXTENDED) { 580 if (isc_buffer_availablelength(target) < 2) 581 return (ISC_R_NOSPACE); 582 isc_buffer_putuint16(target, 583 (isc_uint16_t)((key->key_flags >> 16) 584 & 0xffff)); 585 } 586 587 if (key->keydata.generic == NULL) /*%< NULL KEY */ 588 return (ISC_R_SUCCESS); 589 590 return (key->func->todns(key, target)); 591} 592 593isc_result_t 594dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, 595 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 596{ 597 isc_uint8_t alg, proto; 598 isc_uint32_t flags, extflags; 599 dst_key_t *key = NULL; 600 dns_keytag_t id, rid; 601 isc_region_t r; 602 isc_result_t result; 603 604 REQUIRE(dst_initialized); 605 606 isc_buffer_remainingregion(source, &r); 607 608 if (isc_buffer_remaininglength(source) < 4) 609 return (DST_R_INVALIDPUBLICKEY); 610 flags = isc_buffer_getuint16(source); 611 proto = isc_buffer_getuint8(source); 612 alg = isc_buffer_getuint8(source); 613 614 id = dst_region_computeid(&r, alg); 615 rid = dst_region_computerid(&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 key->key_rid = rid; 630 631 *keyp = key; 632 return (ISC_R_SUCCESS); 633} 634 635isc_result_t 636dst_key_frombuffer(dns_name_t *name, unsigned int alg, 637 unsigned int flags, unsigned int protocol, 638 dns_rdataclass_t rdclass, 639 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 640{ 641 dst_key_t *key = NULL; 642 isc_result_t result; 643 644 REQUIRE(dst_initialized); 645 646 result = frombuffer(name, alg, flags, protocol, rdclass, source, 647 mctx, &key); 648 if (result != ISC_R_SUCCESS) 649 return (result); 650 651 result = computeid(key); 652 if (result != ISC_R_SUCCESS) { 653 dst_key_free(&key); 654 return (result); 655 } 656 657 *keyp = key; 658 return (ISC_R_SUCCESS); 659} 660 661isc_result_t 662dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) { 663 REQUIRE(dst_initialized == ISC_TRUE); 664 REQUIRE(VALID_KEY(key)); 665 REQUIRE(target != NULL); 666 667 CHECKALG(key->key_alg); 668 669 if (key->func->todns == NULL) 670 return (DST_R_UNSUPPORTEDALG); 671 672 return (key->func->todns(key, target)); 673} 674 675isc_result_t 676dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { 677 isc_lex_t *lex = NULL; 678 isc_result_t result = ISC_R_SUCCESS; 679 680 REQUIRE(dst_initialized == ISC_TRUE); 681 REQUIRE(VALID_KEY(key)); 682 REQUIRE(!dst_key_isprivate(key)); 683 REQUIRE(buffer != NULL); 684 685 if (key->func->parse == NULL) 686 RETERR(DST_R_UNSUPPORTEDALG); 687 688 RETERR(isc_lex_create(key->mctx, 1500, &lex)); 689 RETERR(isc_lex_openbuffer(lex, buffer)); 690 RETERR(key->func->parse(key, lex, NULL)); 691 out: 692 if (lex != NULL) 693 isc_lex_destroy(&lex); 694 return (result); 695} 696 697gss_ctx_id_t 698dst_key_getgssctx(const dst_key_t *key) 699{ 700 REQUIRE(key != NULL); 701 702 return (key->keydata.gssctx); 703} 704 705isc_result_t 706dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, 707 dst_key_t **keyp, isc_region_t *intoken) 708{ 709 dst_key_t *key; 710 isc_result_t result; 711 712 REQUIRE(gssctx != NULL); 713 REQUIRE(keyp != NULL && *keyp == NULL); 714 715 key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 716 0, dns_rdataclass_in, mctx); 717 if (key == NULL) 718 return (ISC_R_NOMEMORY); 719 720 if (intoken != NULL) { 721 /* 722 * Keep the token for use by external ssu rules. They may need 723 * to examine the PAC in the kerberos ticket. 724 */ 725 RETERR(isc_buffer_allocate(key->mctx, &key->key_tkeytoken, 726 intoken->length)); 727 RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken)); 728 } 729 730 key->keydata.gssctx = gssctx; 731 *keyp = key; 732 result = ISC_R_SUCCESS; 733out: 734 return result; 735} 736 737isc_result_t 738dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags, 739 unsigned int protocol, dns_rdataclass_t rdclass, 740 const char *engine, const char *label, const char *pin, 741 isc_mem_t *mctx, dst_key_t **keyp) 742{ 743 dst_key_t *key; 744 isc_result_t result; 745 746 REQUIRE(dst_initialized == ISC_TRUE); 747 REQUIRE(dns_name_isabsolute(name)); 748 REQUIRE(mctx != NULL); 749 REQUIRE(keyp != NULL && *keyp == NULL); 750 REQUIRE(label != NULL); 751 752 CHECKALG(alg); 753 754 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 755 if (key == NULL) 756 return (ISC_R_NOMEMORY); 757 758 if (key->func->fromlabel == NULL) { 759 dst_key_free(&key); 760 return (DST_R_UNSUPPORTEDALG); 761 } 762 763 result = key->func->fromlabel(key, engine, label, pin); 764 if (result != ISC_R_SUCCESS) { 765 dst_key_free(&key); 766 return (result); 767 } 768 769 result = computeid(key); 770 if (result != ISC_R_SUCCESS) { 771 dst_key_free(&key); 772 return (result); 773 } 774 775 *keyp = key; 776 return (ISC_R_SUCCESS); 777} 778 779isc_result_t 780dst_key_generate(dns_name_t *name, unsigned int alg, 781 unsigned int bits, unsigned int param, 782 unsigned int flags, unsigned int protocol, 783 dns_rdataclass_t rdclass, 784 isc_mem_t *mctx, dst_key_t **keyp) 785{ 786 return (dst_key_generate2(name, alg, bits, param, flags, protocol, 787 rdclass, mctx, keyp, NULL)); 788} 789 790isc_result_t 791dst_key_generate2(dns_name_t *name, unsigned int alg, 792 unsigned int bits, unsigned int param, 793 unsigned int flags, unsigned int protocol, 794 dns_rdataclass_t rdclass, 795 isc_mem_t *mctx, dst_key_t **keyp, 796 void (*callback)(int)) 797{ 798 dst_key_t *key; 799 isc_result_t ret; 800 801 REQUIRE(dst_initialized == ISC_TRUE); 802 REQUIRE(dns_name_isabsolute(name)); 803 REQUIRE(mctx != NULL); 804 REQUIRE(keyp != NULL && *keyp == NULL); 805 806 CHECKALG(alg); 807 808 key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx); 809 if (key == NULL) 810 return (ISC_R_NOMEMORY); 811 812 if (bits == 0) { /*%< NULL KEY */ 813 key->key_flags |= DNS_KEYTYPE_NOKEY; 814 *keyp = key; 815 return (ISC_R_SUCCESS); 816 } 817 818 if (key->func->generate == NULL) { 819 dst_key_free(&key); 820 return (DST_R_UNSUPPORTEDALG); 821 } 822 823 ret = key->func->generate(key, param, callback); 824 if (ret != ISC_R_SUCCESS) { 825 dst_key_free(&key); 826 return (ret); 827 } 828 829 ret = computeid(key); 830 if (ret != ISC_R_SUCCESS) { 831 dst_key_free(&key); 832 return (ret); 833 } 834 835 *keyp = key; 836 return (ISC_R_SUCCESS); 837} 838 839isc_result_t 840dst_key_getnum(const dst_key_t *key, int type, isc_uint32_t *valuep) 841{ 842 REQUIRE(VALID_KEY(key)); 843 REQUIRE(valuep != NULL); 844 REQUIRE(type <= DST_MAX_NUMERIC); 845 if (!key->numset[type]) 846 return (ISC_R_NOTFOUND); 847 *valuep = key->nums[type]; 848 return (ISC_R_SUCCESS); 849} 850 851void 852dst_key_setnum(dst_key_t *key, int type, isc_uint32_t value) 853{ 854 REQUIRE(VALID_KEY(key)); 855 REQUIRE(type <= DST_MAX_NUMERIC); 856 key->nums[type] = value; 857 key->numset[type] = ISC_TRUE; 858} 859 860void 861dst_key_unsetnum(dst_key_t *key, int type) 862{ 863 REQUIRE(VALID_KEY(key)); 864 REQUIRE(type <= DST_MAX_NUMERIC); 865 key->numset[type] = ISC_FALSE; 866} 867 868isc_result_t 869dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) { 870 REQUIRE(VALID_KEY(key)); 871 REQUIRE(timep != NULL); 872 REQUIRE(type <= DST_MAX_TIMES); 873 if (!key->timeset[type]) 874 return (ISC_R_NOTFOUND); 875 *timep = key->times[type]; 876 return (ISC_R_SUCCESS); 877} 878 879void 880dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) { 881 REQUIRE(VALID_KEY(key)); 882 REQUIRE(type <= DST_MAX_TIMES); 883 key->times[type] = when; 884 key->timeset[type] = ISC_TRUE; 885} 886 887void 888dst_key_unsettime(dst_key_t *key, int type) { 889 REQUIRE(VALID_KEY(key)); 890 REQUIRE(type <= DST_MAX_TIMES); 891 key->timeset[type] = ISC_FALSE; 892} 893 894isc_result_t 895dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) { 896 REQUIRE(VALID_KEY(key)); 897 REQUIRE(majorp != NULL); 898 REQUIRE(minorp != NULL); 899 *majorp = key->fmt_major; 900 *minorp = key->fmt_minor; 901 return (ISC_R_SUCCESS); 902} 903 904void 905dst_key_setprivateformat(dst_key_t *key, int major, int minor) { 906 REQUIRE(VALID_KEY(key)); 907 key->fmt_major = major; 908 key->fmt_minor = minor; 909} 910 911static isc_boolean_t 912comparekeys(const dst_key_t *key1, const dst_key_t *key2, 913 isc_boolean_t match_revoked_key, 914 isc_boolean_t (*compare)(const dst_key_t *key1, 915 const dst_key_t *key2)) 916{ 917 REQUIRE(dst_initialized == ISC_TRUE); 918 REQUIRE(VALID_KEY(key1)); 919 REQUIRE(VALID_KEY(key2)); 920 921 if (key1 == key2) 922 return (ISC_TRUE); 923 924 if (key1 == NULL || key2 == NULL) 925 return (ISC_FALSE); 926 927 if (key1->key_alg != key2->key_alg) 928 return (ISC_FALSE); 929 930 if (key1->key_id != key2->key_id) { 931 if (!match_revoked_key) 932 return (ISC_FALSE); 933 if (key1->key_alg == DST_ALG_RSAMD5) 934 return (ISC_FALSE); 935 if ((key1->key_flags & DNS_KEYFLAG_REVOKE) == 936 (key2->key_flags & DNS_KEYFLAG_REVOKE)) 937 return (ISC_FALSE); 938 if (key1->key_id != key2->key_rid && 939 key1->key_rid != key2->key_id) 940 return (ISC_FALSE); 941 } 942 943 if (compare != NULL) 944 return (compare(key1, key2)); 945 else 946 return (ISC_FALSE); 947} 948 949 950/* 951 * Compares only the public portion of two keys, by converting them 952 * both to wire format and comparing the results. 953 */ 954static isc_boolean_t 955pub_compare(const dst_key_t *key1, const dst_key_t *key2) { 956 isc_result_t result; 957 unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE]; 958 isc_buffer_t b1, b2; 959 isc_region_t r1, r2; 960 961 isc_buffer_init(&b1, buf1, sizeof(buf1)); 962 result = dst_key_todns(key1, &b1); 963 if (result != ISC_R_SUCCESS) 964 return (ISC_FALSE); 965 /* Zero out flags. */ 966 buf1[0] = buf1[1] = 0; 967 if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) 968 isc_buffer_subtract(&b1, 2); 969 970 isc_buffer_init(&b2, buf2, sizeof(buf2)); 971 result = dst_key_todns(key2, &b2); 972 if (result != ISC_R_SUCCESS) 973 return (ISC_FALSE); 974 /* Zero out flags. */ 975 buf2[0] = buf2[1] = 0; 976 if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) 977 isc_buffer_subtract(&b2, 2); 978 979 isc_buffer_usedregion(&b1, &r1); 980 /* Remove extended flags. */ 981 if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { 982 memmove(&buf1[4], &buf1[6], r1.length - 6); 983 r1.length -= 2; 984 } 985 986 isc_buffer_usedregion(&b2, &r2); 987 /* Remove extended flags. */ 988 if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { 989 memmove(&buf2[4], &buf2[6], r2.length - 6); 990 r2.length -= 2; 991 } 992 return (ISC_TF(isc_region_compare(&r1, &r2) == 0)); 993} 994 995isc_boolean_t 996dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { 997 return (comparekeys(key1, key2, ISC_FALSE, key1->func->compare)); 998} 999 1000isc_boolean_t 1001dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2, 1002 isc_boolean_t match_revoked_key) 1003{ 1004 return (comparekeys(key1, key2, match_revoked_key, pub_compare)); 1005} 1006 1007 1008isc_boolean_t 1009dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { 1010 REQUIRE(dst_initialized == ISC_TRUE); 1011 REQUIRE(VALID_KEY(key1)); 1012 REQUIRE(VALID_KEY(key2)); 1013 1014 if (key1 == key2) 1015 return (ISC_TRUE); 1016 if (key1 == NULL || key2 == NULL) 1017 return (ISC_FALSE); 1018 if (key1->key_alg == key2->key_alg && 1019 key1->func->paramcompare != NULL && 1020 key1->func->paramcompare(key1, key2) == ISC_TRUE) 1021 return (ISC_TRUE); 1022 else 1023 return (ISC_FALSE); 1024} 1025 1026void 1027dst_key_attach(dst_key_t *source, dst_key_t **target) { 1028 1029 REQUIRE(dst_initialized == ISC_TRUE); 1030 REQUIRE(target != NULL && *target == NULL); 1031 REQUIRE(VALID_KEY(source)); 1032 1033 isc_refcount_increment(&source->refs, NULL); 1034 *target = source; 1035} 1036 1037void 1038dst_key_free(dst_key_t **keyp) { 1039 isc_mem_t *mctx; 1040 dst_key_t *key; 1041 unsigned int refs; 1042 1043 REQUIRE(dst_initialized == ISC_TRUE); 1044 REQUIRE(keyp != NULL && VALID_KEY(*keyp)); 1045 1046 key = *keyp; 1047 mctx = key->mctx; 1048 1049 isc_refcount_decrement(&key->refs, &refs); 1050 if (refs != 0) 1051 return; 1052 1053 isc_refcount_destroy(&key->refs); 1054 if (key->keydata.generic != NULL) { 1055 INSIST(key->func->destroy != NULL); 1056 key->func->destroy(key); 1057 } 1058 if (key->engine != NULL) 1059 isc_mem_free(mctx, key->engine); 1060 if (key->label != NULL) 1061 isc_mem_free(mctx, key->label); 1062 dns_name_free(key->key_name, mctx); 1063 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 1064 if (key->key_tkeytoken) { 1065 isc_buffer_free(&key->key_tkeytoken); 1066 } 1067 memset(key, 0, sizeof(dst_key_t)); 1068 isc_mem_put(mctx, key, sizeof(dst_key_t)); 1069 *keyp = NULL; 1070} 1071 1072isc_boolean_t 1073dst_key_isprivate(const dst_key_t *key) { 1074 REQUIRE(VALID_KEY(key)); 1075 INSIST(key->func->isprivate != NULL); 1076 return (key->func->isprivate(key)); 1077} 1078 1079isc_result_t 1080dst_key_buildfilename(const dst_key_t *key, int type, 1081 const char *directory, isc_buffer_t *out) { 1082 1083 REQUIRE(VALID_KEY(key)); 1084 REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC || 1085 type == 0); 1086 1087 return (buildfilename(key->key_name, key->key_id, key->key_alg, 1088 type, directory, out)); 1089} 1090 1091isc_result_t 1092dst_key_sigsize(const dst_key_t *key, unsigned int *n) { 1093 REQUIRE(dst_initialized == ISC_TRUE); 1094 REQUIRE(VALID_KEY(key)); 1095 REQUIRE(n != NULL); 1096 1097 /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1098 switch (key->key_alg) { 1099 case DST_ALG_RSAMD5: 1100 case DST_ALG_RSASHA1: 1101 case DST_ALG_NSEC3RSASHA1: 1102 case DST_ALG_RSASHA256: 1103 case DST_ALG_RSASHA512: 1104 *n = (key->key_size + 7) / 8; 1105 break; 1106 case DST_ALG_DSA: 1107 case DST_ALG_NSEC3DSA: 1108 *n = DNS_SIG_DSASIGSIZE; 1109 break; 1110 case DST_ALG_ECCGOST: 1111 *n = DNS_SIG_GOSTSIGSIZE; 1112 break; 1113 case DST_ALG_HMACMD5: 1114 *n = 16; 1115 break; 1116 case DST_ALG_HMACSHA1: 1117 *n = ISC_SHA1_DIGESTLENGTH; 1118 break; 1119 case DST_ALG_HMACSHA224: 1120 *n = ISC_SHA224_DIGESTLENGTH; 1121 break; 1122 case DST_ALG_HMACSHA256: 1123 *n = ISC_SHA256_DIGESTLENGTH; 1124 break; 1125 case DST_ALG_HMACSHA384: 1126 *n = ISC_SHA384_DIGESTLENGTH; 1127 break; 1128 case DST_ALG_HMACSHA512: 1129 *n = ISC_SHA512_DIGESTLENGTH; 1130 break; 1131 case DST_ALG_GSSAPI: 1132 *n = 128; /*%< XXX */ 1133 break; 1134 case DST_ALG_DH: 1135 default: 1136 return (DST_R_UNSUPPORTEDALG); 1137 } 1138 return (ISC_R_SUCCESS); 1139} 1140 1141isc_result_t 1142dst_key_secretsize(const dst_key_t *key, unsigned int *n) { 1143 REQUIRE(dst_initialized == ISC_TRUE); 1144 REQUIRE(VALID_KEY(key)); 1145 REQUIRE(n != NULL); 1146 1147 if (key->key_alg == DST_ALG_DH) 1148 *n = (key->key_size + 7) / 8; 1149 else 1150 return (DST_R_UNSUPPORTEDALG); 1151 return (ISC_R_SUCCESS); 1152} 1153 1154/*% 1155 * Set the flags on a key, then recompute the key ID 1156 */ 1157isc_result_t 1158dst_key_setflags(dst_key_t *key, isc_uint32_t flags) { 1159 REQUIRE(VALID_KEY(key)); 1160 key->key_flags = flags; 1161 return (computeid(key)); 1162} 1163 1164void 1165dst_key_format(const dst_key_t *key, char *cp, unsigned int size) { 1166 char namestr[DNS_NAME_FORMATSIZE]; 1167 char algstr[DNS_NAME_FORMATSIZE]; 1168 1169 dns_name_format(dst_key_name(key), namestr, sizeof(namestr)); 1170 dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr, 1171 sizeof(algstr)); 1172 snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key)); 1173} 1174 1175isc_result_t 1176dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) { 1177 1178 REQUIRE(buffer != NULL && *buffer == NULL); 1179 REQUIRE(length != NULL && *length == 0); 1180 REQUIRE(VALID_KEY(key)); 1181 1182 if (key->func->isprivate == NULL) 1183 return (ISC_R_NOTIMPLEMENTED); 1184 return (key->func->dump(key, mctx, buffer, length)); 1185} 1186 1187isc_result_t 1188dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags, 1189 unsigned int protocol, dns_rdataclass_t rdclass, 1190 isc_mem_t *mctx, const char *keystr, dst_key_t **keyp) 1191{ 1192 isc_result_t result; 1193 dst_key_t *key; 1194 1195 REQUIRE(dst_initialized == ISC_TRUE); 1196 REQUIRE(keyp != NULL && *keyp == NULL); 1197 1198 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) 1199 return (DST_R_UNSUPPORTEDALG); 1200 1201 if (dst_t_func[alg]->restore == NULL) 1202 return (ISC_R_NOTIMPLEMENTED); 1203 1204 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 1205 if (key == NULL) 1206 return (ISC_R_NOMEMORY); 1207 1208 result = (dst_t_func[alg]->restore)(key, keystr); 1209 if (result == ISC_R_SUCCESS) 1210 *keyp = key; 1211 else 1212 dst_key_free(&key); 1213 1214 return (result); 1215} 1216 1217/*** 1218 *** Static methods 1219 ***/ 1220 1221/*% 1222 * Allocates a key structure and fills in some of the fields. 1223 */ 1224static dst_key_t * 1225get_key_struct(dns_name_t *name, unsigned int alg, 1226 unsigned int flags, unsigned int protocol, 1227 unsigned int bits, dns_rdataclass_t rdclass, 1228 isc_mem_t *mctx) 1229{ 1230 dst_key_t *key; 1231 isc_result_t result; 1232 int i; 1233 1234 key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); 1235 if (key == NULL) 1236 return (NULL); 1237 1238 memset(key, 0, sizeof(dst_key_t)); 1239 key->magic = KEY_MAGIC; 1240 1241 result = isc_refcount_init(&key->refs, 1); 1242 if (result != ISC_R_SUCCESS) { 1243 isc_mem_put(mctx, key, sizeof(dst_key_t)); 1244 return (NULL); 1245 } 1246 1247 key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); 1248 if (key->key_name == NULL) { 1249 isc_refcount_destroy(&key->refs); 1250 isc_mem_put(mctx, key, sizeof(dst_key_t)); 1251 return (NULL); 1252 } 1253 dns_name_init(key->key_name, NULL); 1254 result = dns_name_dup(name, mctx, key->key_name); 1255 if (result != ISC_R_SUCCESS) { 1256 isc_refcount_destroy(&key->refs); 1257 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 1258 isc_mem_put(mctx, key, sizeof(dst_key_t)); 1259 return (NULL); 1260 } 1261 key->key_alg = alg; 1262 key->key_flags = flags; 1263 key->key_proto = protocol; 1264 key->mctx = mctx; 1265 key->keydata.generic = NULL; 1266 key->key_size = bits; 1267 key->key_class = rdclass; 1268 key->func = dst_t_func[alg]; 1269 key->fmt_major = 0; 1270 key->fmt_minor = 0; 1271 for (i = 0; i < (DST_MAX_TIMES + 1); i++) { 1272 key->times[i] = 0; 1273 key->timeset[i] = ISC_FALSE; 1274 } 1275 return (key); 1276} 1277 1278/*% 1279 * Reads a public key from disk 1280 */ 1281isc_result_t 1282dst_key_read_public(const char *filename, int type, 1283 isc_mem_t *mctx, dst_key_t **keyp) 1284{ 1285 u_char rdatabuf[DST_KEY_MAXSIZE]; 1286 isc_buffer_t b; 1287 dns_fixedname_t name; 1288 isc_lex_t *lex = NULL; 1289 isc_token_t token; 1290 isc_result_t ret; 1291 dns_rdata_t rdata = DNS_RDATA_INIT; 1292 unsigned int opt = ISC_LEXOPT_DNSMULTILINE; 1293 dns_rdataclass_t rdclass = dns_rdataclass_in; 1294 isc_lexspecials_t specials; 1295 isc_uint32_t ttl; 1296 isc_result_t result; 1297 dns_rdatatype_t keytype; 1298 1299 /* 1300 * Open the file and read its formatted contents 1301 * File format: 1302 * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key> 1303 */ 1304 1305 /* 1500 should be large enough for any key */ 1306 ret = isc_lex_create(mctx, 1500, &lex); 1307 if (ret != ISC_R_SUCCESS) 1308 goto cleanup; 1309 1310 memset(specials, 0, sizeof(specials)); 1311 specials['('] = 1; 1312 specials[')'] = 1; 1313 specials['"'] = 1; 1314 isc_lex_setspecials(lex, specials); 1315 isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); 1316 1317 ret = isc_lex_openfile(lex, filename); 1318 if (ret != ISC_R_SUCCESS) 1319 goto cleanup; 1320 1321#define NEXTTOKEN(lex, opt, token) { \ 1322 ret = isc_lex_gettoken(lex, opt, token); \ 1323 if (ret != ISC_R_SUCCESS) \ 1324 goto cleanup; \ 1325 } 1326 1327#define BADTOKEN() { \ 1328 ret = ISC_R_UNEXPECTEDTOKEN; \ 1329 goto cleanup; \ 1330 } 1331 1332 /* Read the domain name */ 1333 NEXTTOKEN(lex, opt, &token); 1334 if (token.type != isc_tokentype_string) 1335 BADTOKEN(); 1336 1337 /* 1338 * We don't support "@" in .key files. 1339 */ 1340 if (!strcmp(DST_AS_STR(token), "@")) 1341 BADTOKEN(); 1342 1343 dns_fixedname_init(&name); 1344 isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); 1345 isc_buffer_add(&b, strlen(DST_AS_STR(token))); 1346 ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, 1347 0, NULL); 1348 if (ret != ISC_R_SUCCESS) 1349 goto cleanup; 1350 1351 /* Read the next word: either TTL, class, or 'KEY' */ 1352 NEXTTOKEN(lex, opt, &token); 1353 1354 if (token.type != isc_tokentype_string) 1355 BADTOKEN(); 1356 1357 /* If it's a TTL, read the next one */ 1358 result = dns_ttl_fromtext(&token.value.as_textregion, &ttl); 1359 if (result == ISC_R_SUCCESS) 1360 NEXTTOKEN(lex, opt, &token); 1361 1362 if (token.type != isc_tokentype_string) 1363 BADTOKEN(); 1364 1365 ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion); 1366 if (ret == ISC_R_SUCCESS) 1367 NEXTTOKEN(lex, opt, &token); 1368 1369 if (token.type != isc_tokentype_string) 1370 BADTOKEN(); 1371 1372 if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) 1373 keytype = dns_rdatatype_dnskey; 1374 else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) 1375 keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */ 1376 else 1377 BADTOKEN(); 1378 1379 if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) || 1380 ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) { 1381 ret = DST_R_BADKEYTYPE; 1382 goto cleanup; 1383 } 1384 1385 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); 1386 ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, 1387 ISC_FALSE, mctx, &b, NULL); 1388 if (ret != ISC_R_SUCCESS) 1389 goto cleanup; 1390 1391 ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx, 1392 keyp); 1393 if (ret != ISC_R_SUCCESS) 1394 goto cleanup; 1395 1396 cleanup: 1397 if (lex != NULL) 1398 isc_lex_destroy(&lex); 1399 return (ret); 1400} 1401 1402static isc_boolean_t 1403issymmetric(const dst_key_t *key) { 1404 REQUIRE(dst_initialized == ISC_TRUE); 1405 REQUIRE(VALID_KEY(key)); 1406 1407 /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1408 switch (key->key_alg) { 1409 case DST_ALG_RSAMD5: 1410 case DST_ALG_RSASHA1: 1411 case DST_ALG_NSEC3RSASHA1: 1412 case DST_ALG_RSASHA256: 1413 case DST_ALG_RSASHA512: 1414 case DST_ALG_DSA: 1415 case DST_ALG_NSEC3DSA: 1416 case DST_ALG_DH: 1417 case DST_ALG_ECCGOST: 1418 return (ISC_FALSE); 1419 case DST_ALG_HMACMD5: 1420 case DST_ALG_GSSAPI: 1421 return (ISC_TRUE); 1422 default: 1423 return (ISC_FALSE); 1424 } 1425} 1426 1427/*% 1428 * Write key timing metadata to a file pointer, preceded by 'tag' 1429 */ 1430static void 1431printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) { 1432 isc_result_t result; 1433#ifdef ISC_PLATFORM_USETHREADS 1434 char output[26]; /* Minimum buffer as per ctime_r() specification. */ 1435#else 1436 const char *output; 1437#endif 1438 isc_stdtime_t when; 1439 time_t t; 1440 char utc[sizeof("YYYYMMDDHHSSMM")]; 1441 isc_buffer_t b; 1442 isc_region_t r; 1443 1444 result = dst_key_gettime(key, type, &when); 1445 if (result == ISC_R_NOTFOUND) 1446 return; 1447 1448 /* time_t and isc_stdtime_t might be different sizes */ 1449 t = when; 1450#ifdef ISC_PLATFORM_USETHREADS 1451#ifdef WIN32 1452 if (ctime_s(output, sizeof(output), &t) != 0) 1453 goto error; 1454#else 1455 if (ctime_r(&t, output) == NULL) 1456 goto error; 1457#endif 1458#else 1459 output = ctime(&t); 1460#endif 1461 1462 isc_buffer_init(&b, utc, sizeof(utc)); 1463 result = dns_time32_totext(when, &b); 1464 if (result != ISC_R_SUCCESS) 1465 goto error; 1466 1467 isc_buffer_usedregion(&b, &r); 1468 fprintf(stream, "%s: %.*s (%.*s)\n", tag, (int)r.length, r.base, 1469 (int)strlen(output) - 1, output); 1470 return; 1471 1472 error: 1473 fprintf(stream, "%s: (set, unable to display)\n", tag); 1474} 1475 1476/*% 1477 * Writes a public key to disk in DNS format. 1478 */ 1479static isc_result_t 1480write_public_key(const dst_key_t *key, int type, const char *directory) { 1481 FILE *fp; 1482 isc_buffer_t keyb, textb, fileb, classb; 1483 isc_region_t r; 1484 char filename[ISC_DIR_NAMEMAX]; 1485 unsigned char key_array[DST_KEY_MAXSIZE]; 1486 char text_array[DST_KEY_MAXTEXTSIZE]; 1487 char class_array[10]; 1488 isc_result_t ret; 1489 dns_rdata_t rdata = DNS_RDATA_INIT; 1490 isc_fsaccess_t access; 1491 1492 REQUIRE(VALID_KEY(key)); 1493 1494 isc_buffer_init(&keyb, key_array, sizeof(key_array)); 1495 isc_buffer_init(&textb, text_array, sizeof(text_array)); 1496 isc_buffer_init(&classb, class_array, sizeof(class_array)); 1497 1498 ret = dst_key_todns(key, &keyb); 1499 if (ret != ISC_R_SUCCESS) 1500 return (ret); 1501 1502 isc_buffer_usedregion(&keyb, &r); 1503 dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r); 1504 1505 ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb); 1506 if (ret != ISC_R_SUCCESS) 1507 return (DST_R_INVALIDPUBLICKEY); 1508 1509 ret = dns_rdataclass_totext(key->key_class, &classb); 1510 if (ret != ISC_R_SUCCESS) 1511 return (DST_R_INVALIDPUBLICKEY); 1512 1513 /* 1514 * Make the filename. 1515 */ 1516 isc_buffer_init(&fileb, filename, sizeof(filename)); 1517 ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb); 1518 if (ret != ISC_R_SUCCESS) 1519 return (ret); 1520 1521 /* 1522 * Create public key file. 1523 */ 1524 if ((fp = fopen(filename, "w")) == NULL) 1525 return (DST_R_WRITEERROR); 1526 1527 if (issymmetric(key)) { 1528 access = 0; 1529 isc_fsaccess_add(ISC_FSACCESS_OWNER, 1530 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, 1531 &access); 1532 (void)isc_fsaccess_set(filename, access); 1533 } 1534 1535 /* Write key information in comments */ 1536 if ((type & DST_TYPE_KEY) == 0) { 1537 fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ", 1538 (key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ? 1539 "revoked " : 1540 "", 1541 (key->key_flags & DNS_KEYFLAG_KSK) != 0 ? 1542 "key" : 1543 "zone", 1544 key->key_id); 1545 ret = dns_name_print(key->key_name, fp); 1546 if (ret != ISC_R_SUCCESS) { 1547 fclose(fp); 1548 return (ret); 1549 } 1550 fputc('\n', fp); 1551 1552 printtime(key, DST_TIME_CREATED, "; Created", fp); 1553 printtime(key, DST_TIME_PUBLISH, "; Publish", fp); 1554 printtime(key, DST_TIME_ACTIVATE, "; Activate", fp); 1555 printtime(key, DST_TIME_REVOKE, "; Revoke", fp); 1556 printtime(key, DST_TIME_INACTIVE, "; Inactive", fp); 1557 printtime(key, DST_TIME_DELETE, "; Delete", fp); 1558 } 1559 1560 /* Now print the actual key */ 1561 ret = dns_name_print(key->key_name, fp); 1562 1563 fprintf(fp, " "); 1564 1565 isc_buffer_usedregion(&classb, &r); 1566 if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length) 1567 ret = DST_R_WRITEERROR; 1568 1569 if ((type & DST_TYPE_KEY) != 0) 1570 fprintf(fp, " KEY "); 1571 else 1572 fprintf(fp, " DNSKEY "); 1573 1574 isc_buffer_usedregion(&textb, &r); 1575 if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length) 1576 ret = DST_R_WRITEERROR; 1577 1578 fputc('\n', fp); 1579 fflush(fp); 1580 if (ferror(fp)) 1581 ret = DST_R_WRITEERROR; 1582 fclose(fp); 1583 1584 return (ret); 1585} 1586 1587static isc_result_t 1588buildfilename(dns_name_t *name, dns_keytag_t id, 1589 unsigned int alg, unsigned int type, 1590 const char *directory, isc_buffer_t *out) 1591{ 1592 const char *suffix = ""; 1593 unsigned int len; 1594 isc_result_t result; 1595 1596 REQUIRE(out != NULL); 1597 if ((type & DST_TYPE_PRIVATE) != 0) 1598 suffix = ".private"; 1599 else if (type == DST_TYPE_PUBLIC) 1600 suffix = ".key"; 1601 if (directory != NULL) { 1602 if (isc_buffer_availablelength(out) < strlen(directory)) 1603 return (ISC_R_NOSPACE); 1604 isc_buffer_putstr(out, directory); 1605 if (strlen(directory) > 0U && 1606 directory[strlen(directory) - 1] != '/') 1607 isc_buffer_putstr(out, "/"); 1608 } 1609 if (isc_buffer_availablelength(out) < 1) 1610 return (ISC_R_NOSPACE); 1611 isc_buffer_putstr(out, "K"); 1612 result = dns_name_tofilenametext(name, ISC_FALSE, out); 1613 if (result != ISC_R_SUCCESS) 1614 return (result); 1615 len = 1 + 3 + 1 + 5 + strlen(suffix) + 1; 1616 if (isc_buffer_availablelength(out) < len) 1617 return (ISC_R_NOSPACE); 1618 sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, 1619 suffix); 1620 isc_buffer_add(out, len); 1621 1622 return (ISC_R_SUCCESS); 1623} 1624 1625static isc_result_t 1626computeid(dst_key_t *key) { 1627 isc_buffer_t dnsbuf; 1628 unsigned char dns_array[DST_KEY_MAXSIZE]; 1629 isc_region_t r; 1630 isc_result_t ret; 1631 1632 isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array)); 1633 ret = dst_key_todns(key, &dnsbuf); 1634 if (ret != ISC_R_SUCCESS) 1635 return (ret); 1636 1637 isc_buffer_usedregion(&dnsbuf, &r); 1638 key->key_id = dst_region_computeid(&r, key->key_alg); 1639 key->key_rid = dst_region_computerid(&r, key->key_alg); 1640 return (ISC_R_SUCCESS); 1641} 1642 1643static isc_result_t 1644frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags, 1645 unsigned int protocol, dns_rdataclass_t rdclass, 1646 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 1647{ 1648 dst_key_t *key; 1649 isc_result_t ret; 1650 1651 REQUIRE(dns_name_isabsolute(name)); 1652 REQUIRE(source != NULL); 1653 REQUIRE(mctx != NULL); 1654 REQUIRE(keyp != NULL && *keyp == NULL); 1655 1656 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 1657 if (key == NULL) 1658 return (ISC_R_NOMEMORY); 1659 1660 if (isc_buffer_remaininglength(source) > 0) { 1661 ret = algorithm_status(alg); 1662 if (ret != ISC_R_SUCCESS) { 1663 dst_key_free(&key); 1664 return (ret); 1665 } 1666 if (key->func->fromdns == NULL) { 1667 dst_key_free(&key); 1668 return (DST_R_UNSUPPORTEDALG); 1669 } 1670 1671 ret = key->func->fromdns(key, source); 1672 if (ret != ISC_R_SUCCESS) { 1673 dst_key_free(&key); 1674 return (ret); 1675 } 1676 } 1677 1678 *keyp = key; 1679 return (ISC_R_SUCCESS); 1680} 1681 1682static isc_result_t 1683algorithm_status(unsigned int alg) { 1684 REQUIRE(dst_initialized == ISC_TRUE); 1685 1686 if (dst_algorithm_supported(alg)) 1687 return (ISC_R_SUCCESS); 1688#ifndef OPENSSL 1689 if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || 1690 alg == DST_ALG_DSA || alg == DST_ALG_DH || 1691 alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA || 1692 alg == DST_ALG_NSEC3RSASHA1 || 1693 alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512 || 1694 alg == DST_ALG_ECCGOST) 1695 return (DST_R_NOCRYPTO); 1696#endif 1697 return (DST_R_UNSUPPORTEDALG); 1698} 1699 1700static isc_result_t 1701addsuffix(char *filename, int len, const char *odirname, 1702 const char *ofilename, const char *suffix) 1703{ 1704 int olen = strlen(ofilename); 1705 int n; 1706 1707 if (olen > 1 && ofilename[olen - 1] == '.') 1708 olen -= 1; 1709 else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) 1710 olen -= 8; 1711 else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) 1712 olen -= 4; 1713 1714 if (odirname == NULL) 1715 n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); 1716 else 1717 n = snprintf(filename, len, "%s/%.*s%s", 1718 odirname, olen, ofilename, suffix); 1719 if (n < 0) 1720 return (ISC_R_FAILURE); 1721 if (n >= len) 1722 return (ISC_R_NOSPACE); 1723 return (ISC_R_SUCCESS); 1724} 1725 1726isc_result_t 1727dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { 1728#ifdef BIND9 1729 unsigned int flags = dst_entropy_flags; 1730 1731 if (len == 0) 1732 return (ISC_R_SUCCESS); 1733 if (pseudo) 1734 flags &= ~ISC_ENTROPY_GOODONLY; 1735 else 1736 flags |= ISC_ENTROPY_BLOCKING; 1737 return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); 1738#else 1739 UNUSED(buf); 1740 UNUSED(len); 1741 UNUSED(pseudo); 1742 1743 return (ISC_R_NOTIMPLEMENTED); 1744#endif 1745} 1746 1747unsigned int 1748dst__entropy_status(void) { 1749#ifdef BIND9 1750#ifdef GSSAPI 1751 unsigned int flags = dst_entropy_flags; 1752 isc_result_t ret; 1753 unsigned char buf[32]; 1754 static isc_boolean_t first = ISC_TRUE; 1755 1756 if (first) { 1757 /* Someone believes RAND_status() initializes the PRNG */ 1758 flags &= ~ISC_ENTROPY_GOODONLY; 1759 ret = isc_entropy_getdata(dst_entropy_pool, buf, 1760 sizeof(buf), NULL, flags); 1761 INSIST(ret == ISC_R_SUCCESS); 1762 isc_entropy_putdata(dst_entropy_pool, buf, 1763 sizeof(buf), 2 * sizeof(buf)); 1764 first = ISC_FALSE; 1765 } 1766#endif 1767 return (isc_entropy_status(dst_entropy_pool)); 1768#else 1769 return (0); 1770#endif 1771} 1772 1773isc_buffer_t * 1774dst_key_tkeytoken(const dst_key_t *key) { 1775 REQUIRE(VALID_KEY(key)); 1776 return (key->key_tkeytoken); 1777} 1778