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