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