dst_api.c revision 234010
1143731Sdougb/* 2234010Sdougb * Portions Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 3143731Sdougb * Portions Copyright (C) 1999-2003 Internet Software Consortium. 4193149Sdougb * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6193149Sdougb * purpose with or without fee is hereby granted, provided that the above 7193149Sdougb * copyright notice and this permission notice appear in all copies. 8193149Sdougb * 9193149Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS 10193149Sdougb * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11193149Sdougb * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 12193149Sdougb * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13193149Sdougb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14193149Sdougb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15193149Sdougb * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16193149Sdougb * 17143731Sdougb * Portions Copyright (C) 1995-2000 by Network Associates, Inc. 18143731Sdougb * 19193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 20143731Sdougb * purpose with or without fee is hereby granted, provided that the above 21143731Sdougb * copyright notice and this permission notice appear in all copies. 22143731Sdougb * 23143731Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS 24143731Sdougb * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 25143731Sdougb * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 26143731Sdougb * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 27143731Sdougb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 28143731Sdougb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 29143731Sdougb * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 30143731Sdougb */ 31143731Sdougb 32143731Sdougb/* 33143731Sdougb * Principal Author: Brian Wellington 34234010Sdougb * $Id$ 35143731Sdougb */ 36143731Sdougb 37170222Sdougb/*! \file */ 38170222Sdougb 39143731Sdougb#include <config.h> 40143731Sdougb 41143731Sdougb#include <stdlib.h> 42224092Sdougb#include <time.h> 43143731Sdougb 44143731Sdougb#include <isc/buffer.h> 45143731Sdougb#include <isc/dir.h> 46143731Sdougb#include <isc/entropy.h> 47143731Sdougb#include <isc/fsaccess.h> 48170222Sdougb#include <isc/hmacsha.h> 49143731Sdougb#include <isc/lex.h> 50143731Sdougb#include <isc/mem.h> 51143731Sdougb#include <isc/once.h> 52224092Sdougb#include <isc/platform.h> 53143731Sdougb#include <isc/print.h> 54218384Sdougb#include <isc/refcount.h> 55143731Sdougb#include <isc/random.h> 56143731Sdougb#include <isc/string.h> 57143731Sdougb#include <isc/time.h> 58143731Sdougb#include <isc/util.h> 59143731Sdougb 60143731Sdougb#include <dns/fixedname.h> 61143731Sdougb#include <dns/keyvalues.h> 62143731Sdougb#include <dns/name.h> 63143731Sdougb#include <dns/rdata.h> 64143731Sdougb#include <dns/rdataclass.h> 65143731Sdougb#include <dns/ttl.h> 66143731Sdougb#include <dns/types.h> 67143731Sdougb 68143731Sdougb#include <dst/result.h> 69143731Sdougb 70143731Sdougb#include "dst_internal.h" 71143731Sdougb 72143731Sdougb#define DST_AS_STR(t) ((t).value.as_textregion.base) 73143731Sdougb 74143731Sdougbstatic dst_func_t *dst_t_func[DST_MAX_ALGS]; 75224092Sdougb#ifdef BIND9 76143731Sdougbstatic isc_entropy_t *dst_entropy_pool = NULL; 77224092Sdougb#endif 78143731Sdougbstatic unsigned int dst_entropy_flags = 0; 79143731Sdougbstatic isc_boolean_t dst_initialized = ISC_FALSE; 80143731Sdougb 81193149Sdougbvoid gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); 82193149Sdougb 83143731Sdougbisc_mem_t *dst__memory_pool = NULL; 84143731Sdougb 85143731Sdougb/* 86143731Sdougb * Static functions. 87143731Sdougb */ 88143731Sdougbstatic dst_key_t * get_key_struct(dns_name_t *name, 89143731Sdougb unsigned int alg, 90143731Sdougb unsigned int flags, 91143731Sdougb unsigned int protocol, 92143731Sdougb unsigned int bits, 93143731Sdougb dns_rdataclass_t rdclass, 94143731Sdougb isc_mem_t *mctx); 95143731Sdougbstatic isc_result_t write_public_key(const dst_key_t *key, int type, 96143731Sdougb const char *directory); 97143731Sdougbstatic isc_result_t buildfilename(dns_name_t *name, 98143731Sdougb dns_keytag_t id, 99143731Sdougb unsigned int alg, 100143731Sdougb unsigned int type, 101143731Sdougb const char *directory, 102143731Sdougb isc_buffer_t *out); 103143731Sdougbstatic isc_result_t computeid(dst_key_t *key); 104143731Sdougbstatic isc_result_t frombuffer(dns_name_t *name, 105143731Sdougb unsigned int alg, 106143731Sdougb unsigned int flags, 107143731Sdougb unsigned int protocol, 108143731Sdougb dns_rdataclass_t rdclass, 109143731Sdougb isc_buffer_t *source, 110143731Sdougb isc_mem_t *mctx, 111143731Sdougb dst_key_t **keyp); 112143731Sdougb 113143731Sdougbstatic isc_result_t algorithm_status(unsigned int alg); 114143731Sdougb 115224092Sdougbstatic isc_result_t addsuffix(char *filename, int len, 116224092Sdougb const char *dirname, const char *ofilename, 117224092Sdougb const char *suffix); 118143731Sdougb 119224092Sdougb#define RETERR(x) \ 120143731Sdougb do { \ 121143731Sdougb result = (x); \ 122143731Sdougb if (result != ISC_R_SUCCESS) \ 123143731Sdougb goto out; \ 124143731Sdougb } while (0) 125143731Sdougb 126143731Sdougb#define CHECKALG(alg) \ 127143731Sdougb do { \ 128143731Sdougb isc_result_t _r; \ 129143731Sdougb _r = algorithm_status(alg); \ 130143731Sdougb if (_r != ISC_R_SUCCESS) \ 131143731Sdougb return (_r); \ 132143731Sdougb } while (0); \ 133143731Sdougb 134224092Sdougb#if defined(OPENSSL) && defined(BIND9) 135170222Sdougbstatic void * 136170222Sdougbdefault_memalloc(void *arg, size_t size) { 137193149Sdougb UNUSED(arg); 138193149Sdougb if (size == 0U) 139193149Sdougb size = 1; 140193149Sdougb return (malloc(size)); 141170222Sdougb} 142170222Sdougb 143170222Sdougbstatic void 144170222Sdougbdefault_memfree(void *arg, void *ptr) { 145193149Sdougb UNUSED(arg); 146193149Sdougb free(ptr); 147170222Sdougb} 148193149Sdougb#endif 149170222Sdougb 150143731Sdougbisc_result_t 151143731Sdougbdst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { 152224092Sdougb return (dst_lib_init2(mctx, ectx, NULL, eflags)); 153224092Sdougb} 154224092Sdougb 155224092Sdougbisc_result_t 156224092Sdougbdst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx, 157224092Sdougb const char *engine, unsigned int eflags) { 158143731Sdougb isc_result_t result; 159143731Sdougb 160224092Sdougb REQUIRE(mctx != NULL); 161224092Sdougb#ifdef BIND9 162224092Sdougb REQUIRE(ectx != NULL); 163224092Sdougb#else 164224092Sdougb UNUSED(ectx); 165224092Sdougb#endif 166143731Sdougb REQUIRE(dst_initialized == ISC_FALSE); 167143731Sdougb 168224092Sdougb#ifndef OPENSSL 169224092Sdougb UNUSED(engine); 170224092Sdougb#endif 171224092Sdougb 172143731Sdougb dst__memory_pool = NULL; 173143731Sdougb 174224092Sdougb#if defined(OPENSSL) && defined(BIND9) 175143731Sdougb UNUSED(mctx); 176143731Sdougb /* 177143731Sdougb * When using --with-openssl, there seems to be no good way of not 178143731Sdougb * leaking memory due to the openssl error handling mechanism. 179143731Sdougb * Avoid assertions by using a local memory context and not checking 180170222Sdougb * for leaks on exit. Note: as there are leaks we cannot use 181170222Sdougb * ISC_MEMFLAG_INTERNAL as it will free up memory still being used 182170222Sdougb * by libcrypto. 183143731Sdougb */ 184170222Sdougb result = isc_mem_createx2(0, 0, default_memalloc, default_memfree, 185170222Sdougb NULL, &dst__memory_pool, 0); 186143731Sdougb if (result != ISC_R_SUCCESS) 187143731Sdougb return (result); 188193149Sdougb isc_mem_setname(dst__memory_pool, "dst", NULL); 189224092Sdougb#ifndef OPENSSL_LEAKS 190143731Sdougb isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE); 191224092Sdougb#endif 192143731Sdougb#else 193143731Sdougb isc_mem_attach(mctx, &dst__memory_pool); 194143731Sdougb#endif 195224092Sdougb#ifdef BIND9 196143731Sdougb isc_entropy_attach(ectx, &dst_entropy_pool); 197224092Sdougb#endif 198143731Sdougb dst_entropy_flags = eflags; 199143731Sdougb 200143731Sdougb dst_result_register(); 201143731Sdougb 202143731Sdougb memset(dst_t_func, 0, sizeof(dst_t_func)); 203143731Sdougb RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5])); 204170222Sdougb RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1])); 205170222Sdougb RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224])); 206170222Sdougb RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256])); 207170222Sdougb RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384])); 208170222Sdougb RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512])); 209143731Sdougb#ifdef OPENSSL 210224092Sdougb RETERR(dst__openssl_init(engine)); 211204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5], 212204619Sdougb DST_ALG_RSAMD5)); 213204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1], 214204619Sdougb DST_ALG_RSASHA1)); 215204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1], 216204619Sdougb DST_ALG_NSEC3RSASHA1)); 217204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256], 218204619Sdougb DST_ALG_RSASHA256)); 219204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512], 220204619Sdougb DST_ALG_RSASHA512)); 221143731Sdougb#ifdef HAVE_OPENSSL_DSA 222143731Sdougb RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA])); 223193149Sdougb RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA])); 224143731Sdougb#endif 225143731Sdougb RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH])); 226224092Sdougb#ifdef HAVE_OPENSSL_GOST 227224092Sdougb RETERR(dst__opensslgost_init(&dst_t_func[DST_ALG_ECCGOST])); 228224092Sdougb#endif 229143731Sdougb#endif /* OPENSSL */ 230143731Sdougb#ifdef GSSAPI 231143731Sdougb RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI])); 232143731Sdougb#endif 233143731Sdougb dst_initialized = ISC_TRUE; 234143731Sdougb return (ISC_R_SUCCESS); 235143731Sdougb 236143731Sdougb out: 237224092Sdougb /* avoid immediate crash! */ 238224092Sdougb dst_initialized = ISC_TRUE; 239143731Sdougb dst_lib_destroy(); 240143731Sdougb return (result); 241143731Sdougb} 242143731Sdougb 243143731Sdougbvoid 244143731Sdougbdst_lib_destroy(void) { 245143731Sdougb int i; 246143731Sdougb RUNTIME_CHECK(dst_initialized == ISC_TRUE); 247143731Sdougb dst_initialized = ISC_FALSE; 248143731Sdougb 249143731Sdougb for (i = 0; i < DST_MAX_ALGS; i++) 250143731Sdougb if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL) 251143731Sdougb dst_t_func[i]->cleanup(); 252143731Sdougb#ifdef OPENSSL 253143731Sdougb dst__openssl_destroy(); 254143731Sdougb#endif 255143731Sdougb if (dst__memory_pool != NULL) 256143731Sdougb isc_mem_detach(&dst__memory_pool); 257224092Sdougb#ifdef BIND9 258143731Sdougb if (dst_entropy_pool != NULL) 259143731Sdougb isc_entropy_detach(&dst_entropy_pool); 260224092Sdougb#endif 261143731Sdougb} 262143731Sdougb 263143731Sdougbisc_boolean_t 264143731Sdougbdst_algorithm_supported(unsigned int alg) { 265143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 266143731Sdougb 267143731Sdougb if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) 268143731Sdougb return (ISC_FALSE); 269143731Sdougb return (ISC_TRUE); 270143731Sdougb} 271143731Sdougb 272143731Sdougbisc_result_t 273143731Sdougbdst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) { 274143731Sdougb dst_context_t *dctx; 275143731Sdougb isc_result_t result; 276143731Sdougb 277143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 278143731Sdougb REQUIRE(VALID_KEY(key)); 279143731Sdougb REQUIRE(mctx != NULL); 280143731Sdougb REQUIRE(dctxp != NULL && *dctxp == NULL); 281143731Sdougb 282143731Sdougb if (key->func->createctx == NULL) 283143731Sdougb return (DST_R_UNSUPPORTEDALG); 284193149Sdougb if (key->keydata.generic == NULL) 285143731Sdougb return (DST_R_NULLKEY); 286143731Sdougb 287143731Sdougb dctx = isc_mem_get(mctx, sizeof(dst_context_t)); 288143731Sdougb if (dctx == NULL) 289143731Sdougb return (ISC_R_NOMEMORY); 290143731Sdougb dctx->key = key; 291143731Sdougb dctx->mctx = mctx; 292143731Sdougb result = key->func->createctx(key, dctx); 293143731Sdougb if (result != ISC_R_SUCCESS) { 294143731Sdougb isc_mem_put(mctx, dctx, sizeof(dst_context_t)); 295143731Sdougb return (result); 296143731Sdougb } 297143731Sdougb dctx->magic = CTX_MAGIC; 298143731Sdougb *dctxp = dctx; 299143731Sdougb return (ISC_R_SUCCESS); 300143731Sdougb} 301143731Sdougb 302143731Sdougbvoid 303143731Sdougbdst_context_destroy(dst_context_t **dctxp) { 304143731Sdougb dst_context_t *dctx; 305143731Sdougb 306143731Sdougb REQUIRE(dctxp != NULL && VALID_CTX(*dctxp)); 307143731Sdougb 308143731Sdougb dctx = *dctxp; 309143731Sdougb INSIST(dctx->key->func->destroyctx != NULL); 310143731Sdougb dctx->key->func->destroyctx(dctx); 311143731Sdougb dctx->magic = 0; 312143731Sdougb isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t)); 313143731Sdougb *dctxp = NULL; 314143731Sdougb} 315143731Sdougb 316143731Sdougbisc_result_t 317143731Sdougbdst_context_adddata(dst_context_t *dctx, const isc_region_t *data) { 318143731Sdougb REQUIRE(VALID_CTX(dctx)); 319143731Sdougb REQUIRE(data != NULL); 320143731Sdougb INSIST(dctx->key->func->adddata != NULL); 321143731Sdougb 322143731Sdougb return (dctx->key->func->adddata(dctx, data)); 323143731Sdougb} 324143731Sdougb 325143731Sdougbisc_result_t 326143731Sdougbdst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) { 327143731Sdougb dst_key_t *key; 328143731Sdougb 329143731Sdougb REQUIRE(VALID_CTX(dctx)); 330143731Sdougb REQUIRE(sig != NULL); 331143731Sdougb 332143731Sdougb key = dctx->key; 333143731Sdougb CHECKALG(key->key_alg); 334193149Sdougb if (key->keydata.generic == NULL) 335143731Sdougb return (DST_R_NULLKEY); 336193149Sdougb 337143731Sdougb if (key->func->sign == NULL) 338143731Sdougb return (DST_R_NOTPRIVATEKEY); 339143731Sdougb if (key->func->isprivate == NULL || 340143731Sdougb key->func->isprivate(key) == ISC_FALSE) 341143731Sdougb return (DST_R_NOTPRIVATEKEY); 342143731Sdougb 343143731Sdougb return (key->func->sign(dctx, sig)); 344143731Sdougb} 345143731Sdougb 346143731Sdougbisc_result_t 347143731Sdougbdst_context_verify(dst_context_t *dctx, isc_region_t *sig) { 348143731Sdougb REQUIRE(VALID_CTX(dctx)); 349143731Sdougb REQUIRE(sig != NULL); 350143731Sdougb 351143731Sdougb CHECKALG(dctx->key->key_alg); 352193149Sdougb if (dctx->key->keydata.generic == NULL) 353143731Sdougb return (DST_R_NULLKEY); 354143731Sdougb if (dctx->key->func->verify == NULL) 355143731Sdougb return (DST_R_NOTPUBLICKEY); 356143731Sdougb 357143731Sdougb return (dctx->key->func->verify(dctx, sig)); 358143731Sdougb} 359143731Sdougb 360143731Sdougbisc_result_t 361143731Sdougbdst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv, 362143731Sdougb isc_buffer_t *secret) 363143731Sdougb{ 364143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 365143731Sdougb REQUIRE(VALID_KEY(pub) && VALID_KEY(priv)); 366143731Sdougb REQUIRE(secret != NULL); 367143731Sdougb 368143731Sdougb CHECKALG(pub->key_alg); 369143731Sdougb CHECKALG(priv->key_alg); 370143731Sdougb 371193149Sdougb if (pub->keydata.generic == NULL || priv->keydata.generic == NULL) 372143731Sdougb return (DST_R_NULLKEY); 373143731Sdougb 374143731Sdougb if (pub->key_alg != priv->key_alg || 375143731Sdougb pub->func->computesecret == NULL || 376143731Sdougb priv->func->computesecret == NULL) 377143731Sdougb return (DST_R_KEYCANNOTCOMPUTESECRET); 378143731Sdougb 379143731Sdougb if (dst_key_isprivate(priv) == ISC_FALSE) 380143731Sdougb return (DST_R_NOTPRIVATEKEY); 381143731Sdougb 382143731Sdougb return (pub->func->computesecret(pub, priv, secret)); 383143731Sdougb} 384143731Sdougb 385143731Sdougbisc_result_t 386143731Sdougbdst_key_tofile(const dst_key_t *key, int type, const char *directory) { 387143731Sdougb isc_result_t ret = ISC_R_SUCCESS; 388143731Sdougb 389143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 390143731Sdougb REQUIRE(VALID_KEY(key)); 391143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 392143731Sdougb 393143731Sdougb CHECKALG(key->key_alg); 394143731Sdougb 395143731Sdougb if (key->func->tofile == NULL) 396143731Sdougb return (DST_R_UNSUPPORTEDALG); 397143731Sdougb 398143731Sdougb if (type & DST_TYPE_PUBLIC) { 399143731Sdougb ret = write_public_key(key, type, directory); 400143731Sdougb if (ret != ISC_R_SUCCESS) 401143731Sdougb return (ret); 402143731Sdougb } 403143731Sdougb 404143731Sdougb if ((type & DST_TYPE_PRIVATE) && 405143731Sdougb (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY) 406143731Sdougb return (key->func->tofile(key, directory)); 407143731Sdougb else 408143731Sdougb return (ISC_R_SUCCESS); 409143731Sdougb} 410143731Sdougb 411143731Sdougbisc_result_t 412143731Sdougbdst_key_fromfile(dns_name_t *name, dns_keytag_t id, 413143731Sdougb unsigned int alg, int type, const char *directory, 414143731Sdougb isc_mem_t *mctx, dst_key_t **keyp) 415143731Sdougb{ 416143731Sdougb char filename[ISC_DIR_NAMEMAX]; 417143731Sdougb isc_buffer_t b; 418143731Sdougb dst_key_t *key; 419143731Sdougb isc_result_t result; 420143731Sdougb 421143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 422143731Sdougb REQUIRE(dns_name_isabsolute(name)); 423143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 424143731Sdougb REQUIRE(mctx != NULL); 425143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 426143731Sdougb 427143731Sdougb CHECKALG(alg); 428143731Sdougb 429143731Sdougb isc_buffer_init(&b, filename, sizeof(filename)); 430143731Sdougb result = buildfilename(name, id, alg, type, directory, &b); 431143731Sdougb if (result != ISC_R_SUCCESS) 432143731Sdougb return (result); 433143731Sdougb 434143731Sdougb key = NULL; 435224092Sdougb result = dst_key_fromnamedfile(filename, NULL, type, mctx, &key); 436143731Sdougb if (result != ISC_R_SUCCESS) 437143731Sdougb return (result); 438143731Sdougb 439143731Sdougb result = computeid(key); 440143731Sdougb if (result != ISC_R_SUCCESS) { 441143731Sdougb dst_key_free(&key); 442143731Sdougb return (result); 443143731Sdougb } 444143731Sdougb 445193149Sdougb if (!dns_name_equal(name, key->key_name) || id != key->key_id || 446193149Sdougb alg != key->key_alg) { 447143731Sdougb dst_key_free(&key); 448143731Sdougb return (DST_R_INVALIDPRIVATEKEY); 449143731Sdougb } 450143731Sdougb 451143731Sdougb *keyp = key; 452143731Sdougb return (ISC_R_SUCCESS); 453143731Sdougb} 454143731Sdougb 455143731Sdougbisc_result_t 456224092Sdougbdst_key_fromnamedfile(const char *filename, const char *dirname, 457224092Sdougb int type, isc_mem_t *mctx, dst_key_t **keyp) 458143731Sdougb{ 459143731Sdougb isc_result_t result; 460143731Sdougb dst_key_t *pubkey = NULL, *key = NULL; 461143731Sdougb char *newfilename = NULL; 462143731Sdougb int newfilenamelen = 0; 463143731Sdougb isc_lex_t *lex = NULL; 464143731Sdougb 465143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 466143731Sdougb REQUIRE(filename != NULL); 467143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 468143731Sdougb REQUIRE(mctx != NULL); 469143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 470143731Sdougb 471224092Sdougb /* If an absolute path is specified, don't use the key directory */ 472224092Sdougb#ifndef WIN32 473224092Sdougb if (filename[0] == '/') 474224092Sdougb dirname = NULL; 475224092Sdougb#else /* WIN32 */ 476224092Sdougb if (filename[0] == '/' || filename[0] == '\\') 477224092Sdougb dirname = NULL; 478224092Sdougb#endif 479224092Sdougb 480170222Sdougb newfilenamelen = strlen(filename) + 5; 481224092Sdougb if (dirname != NULL) 482224092Sdougb newfilenamelen += strlen(dirname) + 1; 483170222Sdougb newfilename = isc_mem_get(mctx, newfilenamelen); 484170222Sdougb if (newfilename == NULL) 485170222Sdougb return (ISC_R_NOMEMORY); 486224092Sdougb result = addsuffix(newfilename, newfilenamelen, 487224092Sdougb dirname, filename, ".key"); 488170222Sdougb INSIST(result == ISC_R_SUCCESS); 489170222Sdougb 490170222Sdougb result = dst_key_read_public(newfilename, type, mctx, &pubkey); 491170222Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 492170222Sdougb newfilename = NULL; 493143731Sdougb if (result != ISC_R_SUCCESS) 494143731Sdougb return (result); 495143731Sdougb 496143731Sdougb if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC || 497193149Sdougb (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { 498143731Sdougb result = computeid(pubkey); 499143731Sdougb if (result != ISC_R_SUCCESS) { 500143731Sdougb dst_key_free(&pubkey); 501143731Sdougb return (result); 502143731Sdougb } 503143731Sdougb 504143731Sdougb *keyp = pubkey; 505143731Sdougb return (ISC_R_SUCCESS); 506143731Sdougb } 507143731Sdougb 508143731Sdougb result = algorithm_status(pubkey->key_alg); 509143731Sdougb if (result != ISC_R_SUCCESS) { 510143731Sdougb dst_key_free(&pubkey); 511143731Sdougb return (result); 512143731Sdougb } 513143731Sdougb 514143731Sdougb key = get_key_struct(pubkey->key_name, pubkey->key_alg, 515143731Sdougb pubkey->key_flags, pubkey->key_proto, 0, 516143731Sdougb pubkey->key_class, mctx); 517224092Sdougb if (key == NULL) { 518224092Sdougb dst_key_free(&pubkey); 519143731Sdougb return (ISC_R_NOMEMORY); 520224092Sdougb } 521143731Sdougb 522143731Sdougb if (key->func->parse == NULL) 523143731Sdougb RETERR(DST_R_UNSUPPORTEDALG); 524143731Sdougb 525143731Sdougb newfilenamelen = strlen(filename) + 9; 526224092Sdougb if (dirname != NULL) 527224092Sdougb newfilenamelen += strlen(dirname) + 1; 528143731Sdougb newfilename = isc_mem_get(mctx, newfilenamelen); 529143731Sdougb if (newfilename == NULL) 530143731Sdougb RETERR(ISC_R_NOMEMORY); 531224092Sdougb result = addsuffix(newfilename, newfilenamelen, 532224092Sdougb dirname, filename, ".private"); 533143731Sdougb INSIST(result == ISC_R_SUCCESS); 534143731Sdougb 535143731Sdougb RETERR(isc_lex_create(mctx, 1500, &lex)); 536143731Sdougb RETERR(isc_lex_openfile(lex, newfilename)); 537143731Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 538143731Sdougb 539224092Sdougb RETERR(key->func->parse(key, lex, pubkey)); 540143731Sdougb isc_lex_destroy(&lex); 541143731Sdougb 542143731Sdougb RETERR(computeid(key)); 543143731Sdougb 544224092Sdougb if (pubkey->key_id != key->key_id) 545143731Sdougb RETERR(DST_R_INVALIDPRIVATEKEY); 546224092Sdougb dst_key_free(&pubkey); 547143731Sdougb 548143731Sdougb *keyp = key; 549143731Sdougb return (ISC_R_SUCCESS); 550218384Sdougb 551143731Sdougb out: 552224092Sdougb if (pubkey != NULL) 553224092Sdougb dst_key_free(&pubkey); 554143731Sdougb if (newfilename != NULL) 555143731Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 556143731Sdougb if (lex != NULL) 557143731Sdougb isc_lex_destroy(&lex); 558143731Sdougb dst_key_free(&key); 559143731Sdougb return (result); 560143731Sdougb} 561143731Sdougb 562143731Sdougbisc_result_t 563143731Sdougbdst_key_todns(const dst_key_t *key, isc_buffer_t *target) { 564143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 565143731Sdougb REQUIRE(VALID_KEY(key)); 566143731Sdougb REQUIRE(target != NULL); 567143731Sdougb 568143731Sdougb CHECKALG(key->key_alg); 569143731Sdougb 570143731Sdougb if (key->func->todns == NULL) 571143731Sdougb return (DST_R_UNSUPPORTEDALG); 572143731Sdougb 573143731Sdougb if (isc_buffer_availablelength(target) < 4) 574143731Sdougb return (ISC_R_NOSPACE); 575143731Sdougb isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff)); 576143731Sdougb isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto); 577143731Sdougb isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg); 578143731Sdougb 579143731Sdougb if (key->key_flags & DNS_KEYFLAG_EXTENDED) { 580143731Sdougb if (isc_buffer_availablelength(target) < 2) 581143731Sdougb return (ISC_R_NOSPACE); 582143731Sdougb isc_buffer_putuint16(target, 583143731Sdougb (isc_uint16_t)((key->key_flags >> 16) 584143731Sdougb & 0xffff)); 585143731Sdougb } 586143731Sdougb 587193149Sdougb if (key->keydata.generic == NULL) /*%< NULL KEY */ 588143731Sdougb return (ISC_R_SUCCESS); 589143731Sdougb 590143731Sdougb return (key->func->todns(key, target)); 591143731Sdougb} 592143731Sdougb 593143731Sdougbisc_result_t 594143731Sdougbdst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, 595143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 596143731Sdougb{ 597143731Sdougb isc_uint8_t alg, proto; 598143731Sdougb isc_uint32_t flags, extflags; 599143731Sdougb dst_key_t *key = NULL; 600234010Sdougb dns_keytag_t id, rid; 601143731Sdougb isc_region_t r; 602143731Sdougb isc_result_t result; 603143731Sdougb 604143731Sdougb REQUIRE(dst_initialized); 605143731Sdougb 606143731Sdougb isc_buffer_remainingregion(source, &r); 607143731Sdougb 608143731Sdougb if (isc_buffer_remaininglength(source) < 4) 609143731Sdougb return (DST_R_INVALIDPUBLICKEY); 610143731Sdougb flags = isc_buffer_getuint16(source); 611143731Sdougb proto = isc_buffer_getuint8(source); 612143731Sdougb alg = isc_buffer_getuint8(source); 613143731Sdougb 614143731Sdougb id = dst_region_computeid(&r, alg); 615234010Sdougb rid = dst_region_computerid(&r, alg); 616143731Sdougb 617143731Sdougb if (flags & DNS_KEYFLAG_EXTENDED) { 618143731Sdougb if (isc_buffer_remaininglength(source) < 2) 619143731Sdougb return (DST_R_INVALIDPUBLICKEY); 620143731Sdougb extflags = isc_buffer_getuint16(source); 621143731Sdougb flags |= (extflags << 16); 622143731Sdougb } 623143731Sdougb 624143731Sdougb result = frombuffer(name, alg, flags, proto, rdclass, source, 625143731Sdougb mctx, &key); 626143731Sdougb if (result != ISC_R_SUCCESS) 627143731Sdougb return (result); 628143731Sdougb key->key_id = id; 629234010Sdougb key->key_rid = rid; 630143731Sdougb 631143731Sdougb *keyp = key; 632143731Sdougb return (ISC_R_SUCCESS); 633143731Sdougb} 634143731Sdougb 635143731Sdougbisc_result_t 636143731Sdougbdst_key_frombuffer(dns_name_t *name, unsigned int alg, 637143731Sdougb unsigned int flags, unsigned int protocol, 638143731Sdougb dns_rdataclass_t rdclass, 639143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 640143731Sdougb{ 641143731Sdougb dst_key_t *key = NULL; 642143731Sdougb isc_result_t result; 643143731Sdougb 644143731Sdougb REQUIRE(dst_initialized); 645143731Sdougb 646143731Sdougb result = frombuffer(name, alg, flags, protocol, rdclass, source, 647143731Sdougb mctx, &key); 648143731Sdougb if (result != ISC_R_SUCCESS) 649143731Sdougb return (result); 650143731Sdougb 651143731Sdougb result = computeid(key); 652143731Sdougb if (result != ISC_R_SUCCESS) { 653143731Sdougb dst_key_free(&key); 654143731Sdougb return (result); 655143731Sdougb } 656143731Sdougb 657143731Sdougb *keyp = key; 658143731Sdougb return (ISC_R_SUCCESS); 659143731Sdougb} 660143731Sdougb 661143731Sdougbisc_result_t 662143731Sdougbdst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) { 663143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 664143731Sdougb REQUIRE(VALID_KEY(key)); 665143731Sdougb REQUIRE(target != NULL); 666143731Sdougb 667143731Sdougb CHECKALG(key->key_alg); 668143731Sdougb 669143731Sdougb if (key->func->todns == NULL) 670143731Sdougb return (DST_R_UNSUPPORTEDALG); 671143731Sdougb 672143731Sdougb return (key->func->todns(key, target)); 673143731Sdougb} 674143731Sdougb 675143731Sdougbisc_result_t 676143731Sdougbdst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { 677143731Sdougb isc_lex_t *lex = NULL; 678143731Sdougb isc_result_t result = ISC_R_SUCCESS; 679143731Sdougb 680143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 681143731Sdougb REQUIRE(VALID_KEY(key)); 682143731Sdougb REQUIRE(!dst_key_isprivate(key)); 683143731Sdougb REQUIRE(buffer != NULL); 684143731Sdougb 685143731Sdougb if (key->func->parse == NULL) 686143731Sdougb RETERR(DST_R_UNSUPPORTEDALG); 687143731Sdougb 688143731Sdougb RETERR(isc_lex_create(key->mctx, 1500, &lex)); 689143731Sdougb RETERR(isc_lex_openbuffer(lex, buffer)); 690224092Sdougb RETERR(key->func->parse(key, lex, NULL)); 691143731Sdougb out: 692143731Sdougb if (lex != NULL) 693143731Sdougb isc_lex_destroy(&lex); 694143731Sdougb return (result); 695143731Sdougb} 696143731Sdougb 697193149Sdougbgss_ctx_id_t 698193149Sdougbdst_key_getgssctx(const dst_key_t *key) 699193149Sdougb{ 700193149Sdougb REQUIRE(key != NULL); 701193149Sdougb 702193149Sdougb return (key->keydata.gssctx); 703193149Sdougb} 704193149Sdougb 705143731Sdougbisc_result_t 706193149Sdougbdst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, 707224092Sdougb dst_key_t **keyp, isc_region_t *intoken) 708143731Sdougb{ 709143731Sdougb dst_key_t *key; 710224092Sdougb isc_result_t result; 711143731Sdougb 712193149Sdougb REQUIRE(gssctx != NULL); 713143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 714143731Sdougb 715143731Sdougb key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 716143731Sdougb 0, dns_rdataclass_in, mctx); 717143731Sdougb if (key == NULL) 718143731Sdougb return (ISC_R_NOMEMORY); 719193149Sdougb 720224092Sdougb if (intoken != NULL) { 721224092Sdougb /* 722224092Sdougb * Keep the token for use by external ssu rules. They may need 723224092Sdougb * to examine the PAC in the kerberos ticket. 724224092Sdougb */ 725224092Sdougb RETERR(isc_buffer_allocate(key->mctx, &key->key_tkeytoken, 726224092Sdougb intoken->length)); 727224092Sdougb RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken)); 728224092Sdougb } 729224092Sdougb 730193149Sdougb key->keydata.gssctx = gssctx; 731143731Sdougb *keyp = key; 732224092Sdougb result = ISC_R_SUCCESS; 733224092Sdougbout: 734224092Sdougb return result; 735143731Sdougb} 736143731Sdougb 737143731Sdougbisc_result_t 738193149Sdougbdst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags, 739193149Sdougb unsigned int protocol, dns_rdataclass_t rdclass, 740193149Sdougb const char *engine, const char *label, const char *pin, 741193149Sdougb isc_mem_t *mctx, dst_key_t **keyp) 742193149Sdougb{ 743193149Sdougb dst_key_t *key; 744193149Sdougb isc_result_t result; 745193149Sdougb 746193149Sdougb REQUIRE(dst_initialized == ISC_TRUE); 747193149Sdougb REQUIRE(dns_name_isabsolute(name)); 748193149Sdougb REQUIRE(mctx != NULL); 749193149Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 750193149Sdougb REQUIRE(label != NULL); 751193149Sdougb 752193149Sdougb CHECKALG(alg); 753193149Sdougb 754193149Sdougb key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 755193149Sdougb if (key == NULL) 756193149Sdougb return (ISC_R_NOMEMORY); 757193149Sdougb 758193149Sdougb if (key->func->fromlabel == NULL) { 759193149Sdougb dst_key_free(&key); 760193149Sdougb return (DST_R_UNSUPPORTEDALG); 761193149Sdougb } 762193149Sdougb 763193149Sdougb result = key->func->fromlabel(key, engine, label, pin); 764193149Sdougb if (result != ISC_R_SUCCESS) { 765193149Sdougb dst_key_free(&key); 766193149Sdougb return (result); 767193149Sdougb } 768193149Sdougb 769193149Sdougb result = computeid(key); 770193149Sdougb if (result != ISC_R_SUCCESS) { 771193149Sdougb dst_key_free(&key); 772193149Sdougb return (result); 773193149Sdougb } 774193149Sdougb 775193149Sdougb *keyp = key; 776193149Sdougb return (ISC_R_SUCCESS); 777193149Sdougb} 778193149Sdougb 779193149Sdougbisc_result_t 780143731Sdougbdst_key_generate(dns_name_t *name, unsigned int alg, 781143731Sdougb unsigned int bits, unsigned int param, 782143731Sdougb unsigned int flags, unsigned int protocol, 783143731Sdougb dns_rdataclass_t rdclass, 784143731Sdougb isc_mem_t *mctx, dst_key_t **keyp) 785143731Sdougb{ 786224092Sdougb return (dst_key_generate2(name, alg, bits, param, flags, protocol, 787224092Sdougb rdclass, mctx, keyp, NULL)); 788224092Sdougb} 789224092Sdougb 790224092Sdougbisc_result_t 791224092Sdougbdst_key_generate2(dns_name_t *name, unsigned int alg, 792224092Sdougb unsigned int bits, unsigned int param, 793224092Sdougb unsigned int flags, unsigned int protocol, 794224092Sdougb dns_rdataclass_t rdclass, 795224092Sdougb isc_mem_t *mctx, dst_key_t **keyp, 796224092Sdougb void (*callback)(int)) 797224092Sdougb{ 798143731Sdougb dst_key_t *key; 799143731Sdougb isc_result_t ret; 800143731Sdougb 801143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 802143731Sdougb REQUIRE(dns_name_isabsolute(name)); 803143731Sdougb REQUIRE(mctx != NULL); 804143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 805143731Sdougb 806143731Sdougb CHECKALG(alg); 807143731Sdougb 808143731Sdougb key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx); 809143731Sdougb if (key == NULL) 810143731Sdougb return (ISC_R_NOMEMORY); 811143731Sdougb 812170222Sdougb if (bits == 0) { /*%< NULL KEY */ 813143731Sdougb key->key_flags |= DNS_KEYTYPE_NOKEY; 814143731Sdougb *keyp = key; 815143731Sdougb return (ISC_R_SUCCESS); 816143731Sdougb } 817143731Sdougb 818143731Sdougb if (key->func->generate == NULL) { 819143731Sdougb dst_key_free(&key); 820143731Sdougb return (DST_R_UNSUPPORTEDALG); 821143731Sdougb } 822143731Sdougb 823224092Sdougb ret = key->func->generate(key, param, callback); 824143731Sdougb if (ret != ISC_R_SUCCESS) { 825143731Sdougb dst_key_free(&key); 826143731Sdougb return (ret); 827143731Sdougb } 828143731Sdougb 829143731Sdougb ret = computeid(key); 830143731Sdougb if (ret != ISC_R_SUCCESS) { 831143731Sdougb dst_key_free(&key); 832143731Sdougb return (ret); 833143731Sdougb } 834143731Sdougb 835143731Sdougb *keyp = key; 836143731Sdougb return (ISC_R_SUCCESS); 837143731Sdougb} 838143731Sdougb 839224092Sdougbisc_result_t 840224092Sdougbdst_key_getnum(const dst_key_t *key, int type, isc_uint32_t *valuep) 841224092Sdougb{ 842224092Sdougb REQUIRE(VALID_KEY(key)); 843224092Sdougb REQUIRE(valuep != NULL); 844224092Sdougb REQUIRE(type <= DST_MAX_NUMERIC); 845224092Sdougb if (!key->numset[type]) 846224092Sdougb return (ISC_R_NOTFOUND); 847224092Sdougb *valuep = key->nums[type]; 848224092Sdougb return (ISC_R_SUCCESS); 849224092Sdougb} 850224092Sdougb 851224092Sdougbvoid 852224092Sdougbdst_key_setnum(dst_key_t *key, int type, isc_uint32_t value) 853224092Sdougb{ 854224092Sdougb REQUIRE(VALID_KEY(key)); 855224092Sdougb REQUIRE(type <= DST_MAX_NUMERIC); 856224092Sdougb key->nums[type] = value; 857224092Sdougb key->numset[type] = ISC_TRUE; 858224092Sdougb} 859224092Sdougb 860224092Sdougbvoid 861224092Sdougbdst_key_unsetnum(dst_key_t *key, int type) 862224092Sdougb{ 863224092Sdougb REQUIRE(VALID_KEY(key)); 864224092Sdougb REQUIRE(type <= DST_MAX_NUMERIC); 865224092Sdougb key->numset[type] = ISC_FALSE; 866224092Sdougb} 867224092Sdougb 868224092Sdougbisc_result_t 869224092Sdougbdst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) { 870224092Sdougb REQUIRE(VALID_KEY(key)); 871224092Sdougb REQUIRE(timep != NULL); 872224092Sdougb REQUIRE(type <= DST_MAX_TIMES); 873224092Sdougb if (!key->timeset[type]) 874224092Sdougb return (ISC_R_NOTFOUND); 875224092Sdougb *timep = key->times[type]; 876224092Sdougb return (ISC_R_SUCCESS); 877224092Sdougb} 878224092Sdougb 879224092Sdougbvoid 880224092Sdougbdst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) { 881224092Sdougb REQUIRE(VALID_KEY(key)); 882224092Sdougb REQUIRE(type <= DST_MAX_TIMES); 883224092Sdougb key->times[type] = when; 884224092Sdougb key->timeset[type] = ISC_TRUE; 885224092Sdougb} 886224092Sdougb 887224092Sdougbvoid 888224092Sdougbdst_key_unsettime(dst_key_t *key, int type) { 889224092Sdougb REQUIRE(VALID_KEY(key)); 890224092Sdougb REQUIRE(type <= DST_MAX_TIMES); 891224092Sdougb key->timeset[type] = ISC_FALSE; 892224092Sdougb} 893224092Sdougb 894224092Sdougbisc_result_t 895224092Sdougbdst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) { 896224092Sdougb REQUIRE(VALID_KEY(key)); 897224092Sdougb REQUIRE(majorp != NULL); 898224092Sdougb REQUIRE(minorp != NULL); 899224092Sdougb *majorp = key->fmt_major; 900224092Sdougb *minorp = key->fmt_minor; 901224092Sdougb return (ISC_R_SUCCESS); 902224092Sdougb} 903224092Sdougb 904224092Sdougbvoid 905224092Sdougbdst_key_setprivateformat(dst_key_t *key, int major, int minor) { 906224092Sdougb REQUIRE(VALID_KEY(key)); 907224092Sdougb key->fmt_major = major; 908224092Sdougb key->fmt_minor = minor; 909224092Sdougb} 910224092Sdougb 911224092Sdougbstatic isc_boolean_t 912224092Sdougbcomparekeys(const dst_key_t *key1, const dst_key_t *key2, 913224092Sdougb isc_boolean_t match_revoked_key, 914224092Sdougb isc_boolean_t (*compare)(const dst_key_t *key1, 915224092Sdougb const dst_key_t *key2)) 916224092Sdougb{ 917143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 918143731Sdougb REQUIRE(VALID_KEY(key1)); 919143731Sdougb REQUIRE(VALID_KEY(key2)); 920143731Sdougb 921143731Sdougb if (key1 == key2) 922143731Sdougb return (ISC_TRUE); 923224092Sdougb 924143731Sdougb if (key1 == NULL || key2 == NULL) 925143731Sdougb return (ISC_FALSE); 926224092Sdougb 927224092Sdougb if (key1->key_alg != key2->key_alg) 928224092Sdougb return (ISC_FALSE); 929224092Sdougb 930224092Sdougb if (key1->key_id != key2->key_id) { 931224092Sdougb if (!match_revoked_key) 932224092Sdougb return (ISC_FALSE); 933224092Sdougb if (key1->key_alg == DST_ALG_RSAMD5) 934224092Sdougb return (ISC_FALSE); 935224092Sdougb if ((key1->key_flags & DNS_KEYFLAG_REVOKE) == 936224092Sdougb (key2->key_flags & DNS_KEYFLAG_REVOKE)) 937224092Sdougb return (ISC_FALSE); 938234010Sdougb if (key1->key_id != key2->key_rid && 939234010Sdougb key1->key_rid != key2->key_id) 940224092Sdougb return (ISC_FALSE); 941224092Sdougb } 942224092Sdougb 943224092Sdougb if (compare != NULL) 944224092Sdougb return (compare(key1, key2)); 945143731Sdougb else 946143731Sdougb return (ISC_FALSE); 947143731Sdougb} 948143731Sdougb 949224092Sdougb 950224092Sdougb/* 951224092Sdougb * Compares only the public portion of two keys, by converting them 952224092Sdougb * both to wire format and comparing the results. 953224092Sdougb */ 954224092Sdougbstatic isc_boolean_t 955224092Sdougbpub_compare(const dst_key_t *key1, const dst_key_t *key2) { 956224092Sdougb isc_result_t result; 957224092Sdougb unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE]; 958224092Sdougb isc_buffer_t b1, b2; 959224092Sdougb isc_region_t r1, r2; 960224092Sdougb 961224092Sdougb isc_buffer_init(&b1, buf1, sizeof(buf1)); 962224092Sdougb result = dst_key_todns(key1, &b1); 963224092Sdougb if (result != ISC_R_SUCCESS) 964224092Sdougb return (ISC_FALSE); 965224092Sdougb /* Zero out flags. */ 966224092Sdougb buf1[0] = buf1[1] = 0; 967224092Sdougb if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) 968224092Sdougb isc_buffer_subtract(&b1, 2); 969224092Sdougb 970224092Sdougb isc_buffer_init(&b2, buf2, sizeof(buf2)); 971224092Sdougb result = dst_key_todns(key2, &b2); 972224092Sdougb if (result != ISC_R_SUCCESS) 973224092Sdougb return (ISC_FALSE); 974224092Sdougb /* Zero out flags. */ 975224092Sdougb buf2[0] = buf2[1] = 0; 976224092Sdougb if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) 977224092Sdougb isc_buffer_subtract(&b2, 2); 978224092Sdougb 979224092Sdougb isc_buffer_usedregion(&b1, &r1); 980224092Sdougb /* Remove extended flags. */ 981224092Sdougb if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { 982224092Sdougb memmove(&buf1[4], &buf1[6], r1.length - 6); 983224092Sdougb r1.length -= 2; 984224092Sdougb } 985224092Sdougb 986224092Sdougb isc_buffer_usedregion(&b2, &r2); 987224092Sdougb /* Remove extended flags. */ 988224092Sdougb if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { 989224092Sdougb memmove(&buf2[4], &buf2[6], r2.length - 6); 990224092Sdougb r2.length -= 2; 991224092Sdougb } 992224092Sdougb return (ISC_TF(isc_region_compare(&r1, &r2) == 0)); 993224092Sdougb} 994224092Sdougb 995143731Sdougbisc_boolean_t 996224092Sdougbdst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { 997224092Sdougb return (comparekeys(key1, key2, ISC_FALSE, key1->func->compare)); 998224092Sdougb} 999224092Sdougb 1000224092Sdougbisc_boolean_t 1001224092Sdougbdst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2, 1002224092Sdougb isc_boolean_t match_revoked_key) 1003224092Sdougb{ 1004224092Sdougb return (comparekeys(key1, key2, match_revoked_key, pub_compare)); 1005224092Sdougb} 1006224092Sdougb 1007224092Sdougb 1008224092Sdougbisc_boolean_t 1009143731Sdougbdst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { 1010143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1011143731Sdougb REQUIRE(VALID_KEY(key1)); 1012143731Sdougb REQUIRE(VALID_KEY(key2)); 1013143731Sdougb 1014143731Sdougb if (key1 == key2) 1015143731Sdougb return (ISC_TRUE); 1016143731Sdougb if (key1 == NULL || key2 == NULL) 1017143731Sdougb return (ISC_FALSE); 1018143731Sdougb if (key1->key_alg == key2->key_alg && 1019143731Sdougb key1->func->paramcompare != NULL && 1020143731Sdougb key1->func->paramcompare(key1, key2) == ISC_TRUE) 1021143731Sdougb return (ISC_TRUE); 1022143731Sdougb else 1023143731Sdougb return (ISC_FALSE); 1024143731Sdougb} 1025143731Sdougb 1026143731Sdougbvoid 1027218384Sdougbdst_key_attach(dst_key_t *source, dst_key_t **target) { 1028218384Sdougb 1029218384Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1030218384Sdougb REQUIRE(target != NULL && *target == NULL); 1031218384Sdougb REQUIRE(VALID_KEY(source)); 1032218384Sdougb 1033218384Sdougb isc_refcount_increment(&source->refs, NULL); 1034218384Sdougb *target = source; 1035218384Sdougb} 1036218384Sdougb 1037218384Sdougbvoid 1038143731Sdougbdst_key_free(dst_key_t **keyp) { 1039143731Sdougb isc_mem_t *mctx; 1040143731Sdougb dst_key_t *key; 1041218384Sdougb unsigned int refs; 1042143731Sdougb 1043143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1044143731Sdougb REQUIRE(keyp != NULL && VALID_KEY(*keyp)); 1045143731Sdougb 1046143731Sdougb key = *keyp; 1047143731Sdougb mctx = key->mctx; 1048143731Sdougb 1049218384Sdougb isc_refcount_decrement(&key->refs, &refs); 1050218384Sdougb if (refs != 0) 1051218384Sdougb return; 1052218384Sdougb 1053218384Sdougb isc_refcount_destroy(&key->refs); 1054193149Sdougb if (key->keydata.generic != NULL) { 1055143731Sdougb INSIST(key->func->destroy != NULL); 1056143731Sdougb key->func->destroy(key); 1057143731Sdougb } 1058193149Sdougb if (key->engine != NULL) 1059193149Sdougb isc_mem_free(mctx, key->engine); 1060193149Sdougb if (key->label != NULL) 1061193149Sdougb isc_mem_free(mctx, key->label); 1062143731Sdougb dns_name_free(key->key_name, mctx); 1063143731Sdougb isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 1064224092Sdougb if (key->key_tkeytoken) { 1065224092Sdougb isc_buffer_free(&key->key_tkeytoken); 1066224092Sdougb } 1067143731Sdougb memset(key, 0, sizeof(dst_key_t)); 1068143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 1069143731Sdougb *keyp = NULL; 1070143731Sdougb} 1071143731Sdougb 1072143731Sdougbisc_boolean_t 1073143731Sdougbdst_key_isprivate(const dst_key_t *key) { 1074143731Sdougb REQUIRE(VALID_KEY(key)); 1075143731Sdougb INSIST(key->func->isprivate != NULL); 1076143731Sdougb return (key->func->isprivate(key)); 1077143731Sdougb} 1078143731Sdougb 1079143731Sdougbisc_result_t 1080143731Sdougbdst_key_buildfilename(const dst_key_t *key, int type, 1081143731Sdougb const char *directory, isc_buffer_t *out) { 1082143731Sdougb 1083143731Sdougb REQUIRE(VALID_KEY(key)); 1084143731Sdougb REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC || 1085143731Sdougb type == 0); 1086143731Sdougb 1087143731Sdougb return (buildfilename(key->key_name, key->key_id, key->key_alg, 1088143731Sdougb type, directory, out)); 1089143731Sdougb} 1090143731Sdougb 1091143731Sdougbisc_result_t 1092143731Sdougbdst_key_sigsize(const dst_key_t *key, unsigned int *n) { 1093143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1094143731Sdougb REQUIRE(VALID_KEY(key)); 1095143731Sdougb REQUIRE(n != NULL); 1096143731Sdougb 1097143731Sdougb /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1098143731Sdougb switch (key->key_alg) { 1099143731Sdougb case DST_ALG_RSAMD5: 1100143731Sdougb case DST_ALG_RSASHA1: 1101193149Sdougb case DST_ALG_NSEC3RSASHA1: 1102204619Sdougb case DST_ALG_RSASHA256: 1103204619Sdougb case DST_ALG_RSASHA512: 1104143731Sdougb *n = (key->key_size + 7) / 8; 1105143731Sdougb break; 1106143731Sdougb case DST_ALG_DSA: 1107193149Sdougb case DST_ALG_NSEC3DSA: 1108143731Sdougb *n = DNS_SIG_DSASIGSIZE; 1109143731Sdougb break; 1110224092Sdougb case DST_ALG_ECCGOST: 1111224092Sdougb *n = DNS_SIG_GOSTSIGSIZE; 1112224092Sdougb break; 1113143731Sdougb case DST_ALG_HMACMD5: 1114143731Sdougb *n = 16; 1115143731Sdougb break; 1116170222Sdougb case DST_ALG_HMACSHA1: 1117170222Sdougb *n = ISC_SHA1_DIGESTLENGTH; 1118170222Sdougb break; 1119170222Sdougb case DST_ALG_HMACSHA224: 1120170222Sdougb *n = ISC_SHA224_DIGESTLENGTH; 1121170222Sdougb break; 1122170222Sdougb case DST_ALG_HMACSHA256: 1123170222Sdougb *n = ISC_SHA256_DIGESTLENGTH; 1124170222Sdougb break; 1125170222Sdougb case DST_ALG_HMACSHA384: 1126170222Sdougb *n = ISC_SHA384_DIGESTLENGTH; 1127170222Sdougb break; 1128170222Sdougb case DST_ALG_HMACSHA512: 1129170222Sdougb *n = ISC_SHA512_DIGESTLENGTH; 1130170222Sdougb break; 1131143731Sdougb case DST_ALG_GSSAPI: 1132170222Sdougb *n = 128; /*%< XXX */ 1133143731Sdougb break; 1134143731Sdougb case DST_ALG_DH: 1135143731Sdougb default: 1136143731Sdougb return (DST_R_UNSUPPORTEDALG); 1137143731Sdougb } 1138143731Sdougb return (ISC_R_SUCCESS); 1139143731Sdougb} 1140143731Sdougb 1141143731Sdougbisc_result_t 1142143731Sdougbdst_key_secretsize(const dst_key_t *key, unsigned int *n) { 1143143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1144143731Sdougb REQUIRE(VALID_KEY(key)); 1145143731Sdougb REQUIRE(n != NULL); 1146143731Sdougb 1147143731Sdougb if (key->key_alg == DST_ALG_DH) 1148143731Sdougb *n = (key->key_size + 7) / 8; 1149143731Sdougb else 1150143731Sdougb return (DST_R_UNSUPPORTEDALG); 1151143731Sdougb return (ISC_R_SUCCESS); 1152143731Sdougb} 1153143731Sdougb 1154224092Sdougb/*% 1155224092Sdougb * Set the flags on a key, then recompute the key ID 1156224092Sdougb */ 1157224092Sdougbisc_result_t 1158224092Sdougbdst_key_setflags(dst_key_t *key, isc_uint32_t flags) { 1159224092Sdougb REQUIRE(VALID_KEY(key)); 1160224092Sdougb key->key_flags = flags; 1161224092Sdougb return (computeid(key)); 1162224092Sdougb} 1163224092Sdougb 1164224092Sdougbvoid 1165224092Sdougbdst_key_format(const dst_key_t *key, char *cp, unsigned int size) { 1166224092Sdougb char namestr[DNS_NAME_FORMATSIZE]; 1167224092Sdougb char algstr[DNS_NAME_FORMATSIZE]; 1168224092Sdougb 1169224092Sdougb dns_name_format(dst_key_name(key), namestr, sizeof(namestr)); 1170224092Sdougb dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr, 1171224092Sdougb sizeof(algstr)); 1172224092Sdougb snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key)); 1173224092Sdougb} 1174224092Sdougb 1175224092Sdougbisc_result_t 1176224092Sdougbdst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) { 1177224092Sdougb 1178224092Sdougb REQUIRE(buffer != NULL && *buffer == NULL); 1179224092Sdougb REQUIRE(length != NULL && *length == 0); 1180224092Sdougb REQUIRE(VALID_KEY(key)); 1181224092Sdougb 1182224092Sdougb if (key->func->isprivate == NULL) 1183224092Sdougb return (ISC_R_NOTIMPLEMENTED); 1184224092Sdougb return (key->func->dump(key, mctx, buffer, length)); 1185224092Sdougb} 1186224092Sdougb 1187224092Sdougbisc_result_t 1188224092Sdougbdst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags, 1189224092Sdougb unsigned int protocol, dns_rdataclass_t rdclass, 1190224092Sdougb isc_mem_t *mctx, const char *keystr, dst_key_t **keyp) 1191224092Sdougb{ 1192224092Sdougb isc_result_t result; 1193224092Sdougb dst_key_t *key; 1194224092Sdougb 1195224092Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1196224092Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 1197224092Sdougb 1198224092Sdougb if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) 1199224092Sdougb return (DST_R_UNSUPPORTEDALG); 1200224092Sdougb 1201224092Sdougb if (dst_t_func[alg]->restore == NULL) 1202224092Sdougb return (ISC_R_NOTIMPLEMENTED); 1203224092Sdougb 1204224092Sdougb key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 1205224092Sdougb if (key == NULL) 1206224092Sdougb return (ISC_R_NOMEMORY); 1207224092Sdougb 1208224092Sdougb result = (dst_t_func[alg]->restore)(key, keystr); 1209224092Sdougb if (result == ISC_R_SUCCESS) 1210224092Sdougb *keyp = key; 1211224092Sdougb else 1212224092Sdougb dst_key_free(&key); 1213224092Sdougb 1214224092Sdougb return (result); 1215224092Sdougb} 1216224092Sdougb 1217143731Sdougb/*** 1218143731Sdougb *** Static methods 1219143731Sdougb ***/ 1220143731Sdougb 1221170222Sdougb/*% 1222143731Sdougb * Allocates a key structure and fills in some of the fields. 1223143731Sdougb */ 1224143731Sdougbstatic dst_key_t * 1225143731Sdougbget_key_struct(dns_name_t *name, unsigned int alg, 1226143731Sdougb unsigned int flags, unsigned int protocol, 1227143731Sdougb unsigned int bits, dns_rdataclass_t rdclass, 1228143731Sdougb isc_mem_t *mctx) 1229143731Sdougb{ 1230143731Sdougb dst_key_t *key; 1231143731Sdougb isc_result_t result; 1232224092Sdougb int i; 1233143731Sdougb 1234143731Sdougb key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); 1235143731Sdougb if (key == NULL) 1236143731Sdougb return (NULL); 1237143731Sdougb 1238143731Sdougb memset(key, 0, sizeof(dst_key_t)); 1239143731Sdougb key->magic = KEY_MAGIC; 1240143731Sdougb 1241218384Sdougb result = isc_refcount_init(&key->refs, 1); 1242218384Sdougb if (result != ISC_R_SUCCESS) { 1243218384Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 1244218384Sdougb return (NULL); 1245218384Sdougb } 1246218384Sdougb 1247143731Sdougb key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); 1248143731Sdougb if (key->key_name == NULL) { 1249218384Sdougb isc_refcount_destroy(&key->refs); 1250143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 1251143731Sdougb return (NULL); 1252143731Sdougb } 1253143731Sdougb dns_name_init(key->key_name, NULL); 1254143731Sdougb result = dns_name_dup(name, mctx, key->key_name); 1255143731Sdougb if (result != ISC_R_SUCCESS) { 1256218384Sdougb isc_refcount_destroy(&key->refs); 1257143731Sdougb isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 1258143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 1259143731Sdougb return (NULL); 1260143731Sdougb } 1261143731Sdougb key->key_alg = alg; 1262143731Sdougb key->key_flags = flags; 1263143731Sdougb key->key_proto = protocol; 1264143731Sdougb key->mctx = mctx; 1265193149Sdougb key->keydata.generic = NULL; 1266143731Sdougb key->key_size = bits; 1267143731Sdougb key->key_class = rdclass; 1268143731Sdougb key->func = dst_t_func[alg]; 1269224092Sdougb key->fmt_major = 0; 1270224092Sdougb key->fmt_minor = 0; 1271224092Sdougb for (i = 0; i < (DST_MAX_TIMES + 1); i++) { 1272224092Sdougb key->times[i] = 0; 1273224092Sdougb key->timeset[i] = ISC_FALSE; 1274224092Sdougb } 1275143731Sdougb return (key); 1276143731Sdougb} 1277143731Sdougb 1278170222Sdougb/*% 1279143731Sdougb * Reads a public key from disk 1280143731Sdougb */ 1281170222Sdougbisc_result_t 1282170222Sdougbdst_key_read_public(const char *filename, int type, 1283170222Sdougb isc_mem_t *mctx, dst_key_t **keyp) 1284143731Sdougb{ 1285143731Sdougb u_char rdatabuf[DST_KEY_MAXSIZE]; 1286143731Sdougb isc_buffer_t b; 1287143731Sdougb dns_fixedname_t name; 1288143731Sdougb isc_lex_t *lex = NULL; 1289143731Sdougb isc_token_t token; 1290143731Sdougb isc_result_t ret; 1291143731Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 1292143731Sdougb unsigned int opt = ISC_LEXOPT_DNSMULTILINE; 1293143731Sdougb dns_rdataclass_t rdclass = dns_rdataclass_in; 1294143731Sdougb isc_lexspecials_t specials; 1295143731Sdougb isc_uint32_t ttl; 1296143731Sdougb isc_result_t result; 1297143731Sdougb dns_rdatatype_t keytype; 1298143731Sdougb 1299143731Sdougb /* 1300143731Sdougb * Open the file and read its formatted contents 1301143731Sdougb * File format: 1302170222Sdougb * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key> 1303143731Sdougb */ 1304143731Sdougb 1305143731Sdougb /* 1500 should be large enough for any key */ 1306143731Sdougb ret = isc_lex_create(mctx, 1500, &lex); 1307143731Sdougb if (ret != ISC_R_SUCCESS) 1308143731Sdougb goto cleanup; 1309143731Sdougb 1310143731Sdougb memset(specials, 0, sizeof(specials)); 1311143731Sdougb specials['('] = 1; 1312143731Sdougb specials[')'] = 1; 1313143731Sdougb specials['"'] = 1; 1314143731Sdougb isc_lex_setspecials(lex, specials); 1315143731Sdougb isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); 1316143731Sdougb 1317170222Sdougb ret = isc_lex_openfile(lex, filename); 1318143731Sdougb if (ret != ISC_R_SUCCESS) 1319143731Sdougb goto cleanup; 1320143731Sdougb 1321143731Sdougb#define NEXTTOKEN(lex, opt, token) { \ 1322143731Sdougb ret = isc_lex_gettoken(lex, opt, token); \ 1323143731Sdougb if (ret != ISC_R_SUCCESS) \ 1324143731Sdougb goto cleanup; \ 1325143731Sdougb } 1326143731Sdougb 1327143731Sdougb#define BADTOKEN() { \ 1328143731Sdougb ret = ISC_R_UNEXPECTEDTOKEN; \ 1329143731Sdougb goto cleanup; \ 1330143731Sdougb } 1331143731Sdougb 1332143731Sdougb /* Read the domain name */ 1333143731Sdougb NEXTTOKEN(lex, opt, &token); 1334143731Sdougb if (token.type != isc_tokentype_string) 1335143731Sdougb BADTOKEN(); 1336193149Sdougb 1337193149Sdougb /* 1338193149Sdougb * We don't support "@" in .key files. 1339193149Sdougb */ 1340193149Sdougb if (!strcmp(DST_AS_STR(token), "@")) 1341193149Sdougb BADTOKEN(); 1342193149Sdougb 1343143731Sdougb dns_fixedname_init(&name); 1344143731Sdougb isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); 1345143731Sdougb isc_buffer_add(&b, strlen(DST_AS_STR(token))); 1346143731Sdougb ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, 1347224092Sdougb 0, NULL); 1348143731Sdougb if (ret != ISC_R_SUCCESS) 1349143731Sdougb goto cleanup; 1350143731Sdougb 1351143731Sdougb /* Read the next word: either TTL, class, or 'KEY' */ 1352143731Sdougb NEXTTOKEN(lex, opt, &token); 1353143731Sdougb 1354204619Sdougb if (token.type != isc_tokentype_string) 1355204619Sdougb BADTOKEN(); 1356204619Sdougb 1357143731Sdougb /* If it's a TTL, read the next one */ 1358143731Sdougb result = dns_ttl_fromtext(&token.value.as_textregion, &ttl); 1359143731Sdougb if (result == ISC_R_SUCCESS) 1360143731Sdougb NEXTTOKEN(lex, opt, &token); 1361143731Sdougb 1362143731Sdougb if (token.type != isc_tokentype_string) 1363143731Sdougb BADTOKEN(); 1364143731Sdougb 1365143731Sdougb ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion); 1366143731Sdougb if (ret == ISC_R_SUCCESS) 1367143731Sdougb NEXTTOKEN(lex, opt, &token); 1368143731Sdougb 1369143731Sdougb if (token.type != isc_tokentype_string) 1370143731Sdougb BADTOKEN(); 1371143731Sdougb 1372143731Sdougb if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) 1373143731Sdougb keytype = dns_rdatatype_dnskey; 1374143731Sdougb else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) 1375170222Sdougb keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */ 1376143731Sdougb else 1377143731Sdougb BADTOKEN(); 1378143731Sdougb 1379143731Sdougb if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) || 1380143731Sdougb ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) { 1381143731Sdougb ret = DST_R_BADKEYTYPE; 1382143731Sdougb goto cleanup; 1383143731Sdougb } 1384143731Sdougb 1385143731Sdougb isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); 1386143731Sdougb ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, 1387143731Sdougb ISC_FALSE, mctx, &b, NULL); 1388143731Sdougb if (ret != ISC_R_SUCCESS) 1389143731Sdougb goto cleanup; 1390143731Sdougb 1391143731Sdougb ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx, 1392143731Sdougb keyp); 1393143731Sdougb if (ret != ISC_R_SUCCESS) 1394143731Sdougb goto cleanup; 1395143731Sdougb 1396143731Sdougb cleanup: 1397143731Sdougb if (lex != NULL) 1398143731Sdougb isc_lex_destroy(&lex); 1399143731Sdougb return (ret); 1400143731Sdougb} 1401143731Sdougb 1402143731Sdougbstatic isc_boolean_t 1403143731Sdougbissymmetric(const dst_key_t *key) { 1404143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1405143731Sdougb REQUIRE(VALID_KEY(key)); 1406143731Sdougb 1407143731Sdougb /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1408143731Sdougb switch (key->key_alg) { 1409143731Sdougb case DST_ALG_RSAMD5: 1410143731Sdougb case DST_ALG_RSASHA1: 1411193149Sdougb case DST_ALG_NSEC3RSASHA1: 1412204619Sdougb case DST_ALG_RSASHA256: 1413204619Sdougb case DST_ALG_RSASHA512: 1414143731Sdougb case DST_ALG_DSA: 1415193149Sdougb case DST_ALG_NSEC3DSA: 1416143731Sdougb case DST_ALG_DH: 1417224092Sdougb case DST_ALG_ECCGOST: 1418143731Sdougb return (ISC_FALSE); 1419143731Sdougb case DST_ALG_HMACMD5: 1420143731Sdougb case DST_ALG_GSSAPI: 1421143731Sdougb return (ISC_TRUE); 1422143731Sdougb default: 1423143731Sdougb return (ISC_FALSE); 1424143731Sdougb } 1425143731Sdougb} 1426143731Sdougb 1427170222Sdougb/*% 1428224092Sdougb * Write key timing metadata to a file pointer, preceded by 'tag' 1429224092Sdougb */ 1430224092Sdougbstatic void 1431224092Sdougbprinttime(const dst_key_t *key, int type, const char *tag, FILE *stream) { 1432224092Sdougb isc_result_t result; 1433224092Sdougb#ifdef ISC_PLATFORM_USETHREADS 1434224092Sdougb char output[26]; /* Minimum buffer as per ctime_r() specification. */ 1435224092Sdougb#else 1436224092Sdougb const char *output; 1437224092Sdougb#endif 1438224092Sdougb isc_stdtime_t when; 1439224092Sdougb time_t t; 1440224092Sdougb char utc[sizeof("YYYYMMDDHHSSMM")]; 1441224092Sdougb isc_buffer_t b; 1442224092Sdougb isc_region_t r; 1443224092Sdougb 1444224092Sdougb result = dst_key_gettime(key, type, &when); 1445224092Sdougb if (result == ISC_R_NOTFOUND) 1446224092Sdougb return; 1447224092Sdougb 1448224092Sdougb /* time_t and isc_stdtime_t might be different sizes */ 1449224092Sdougb t = when; 1450224092Sdougb#ifdef ISC_PLATFORM_USETHREADS 1451224092Sdougb#ifdef WIN32 1452224092Sdougb if (ctime_s(output, sizeof(output), &t) != 0) 1453224092Sdougb goto error; 1454224092Sdougb#else 1455224092Sdougb if (ctime_r(&t, output) == NULL) 1456224092Sdougb goto error; 1457224092Sdougb#endif 1458224092Sdougb#else 1459224092Sdougb output = ctime(&t); 1460224092Sdougb#endif 1461224092Sdougb 1462224092Sdougb isc_buffer_init(&b, utc, sizeof(utc)); 1463224092Sdougb result = dns_time32_totext(when, &b); 1464224092Sdougb if (result != ISC_R_SUCCESS) 1465224092Sdougb goto error; 1466224092Sdougb 1467224092Sdougb isc_buffer_usedregion(&b, &r); 1468224092Sdougb fprintf(stream, "%s: %.*s (%.*s)\n", tag, (int)r.length, r.base, 1469224092Sdougb (int)strlen(output) - 1, output); 1470224092Sdougb return; 1471224092Sdougb 1472224092Sdougb error: 1473224092Sdougb fprintf(stream, "%s: (set, unable to display)\n", tag); 1474224092Sdougb} 1475224092Sdougb 1476224092Sdougb/*% 1477143731Sdougb * Writes a public key to disk in DNS format. 1478143731Sdougb */ 1479143731Sdougbstatic isc_result_t 1480143731Sdougbwrite_public_key(const dst_key_t *key, int type, const char *directory) { 1481143731Sdougb FILE *fp; 1482143731Sdougb isc_buffer_t keyb, textb, fileb, classb; 1483143731Sdougb isc_region_t r; 1484143731Sdougb char filename[ISC_DIR_NAMEMAX]; 1485143731Sdougb unsigned char key_array[DST_KEY_MAXSIZE]; 1486143731Sdougb char text_array[DST_KEY_MAXTEXTSIZE]; 1487143731Sdougb char class_array[10]; 1488143731Sdougb isc_result_t ret; 1489143731Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 1490143731Sdougb isc_fsaccess_t access; 1491143731Sdougb 1492143731Sdougb REQUIRE(VALID_KEY(key)); 1493143731Sdougb 1494143731Sdougb isc_buffer_init(&keyb, key_array, sizeof(key_array)); 1495143731Sdougb isc_buffer_init(&textb, text_array, sizeof(text_array)); 1496143731Sdougb isc_buffer_init(&classb, class_array, sizeof(class_array)); 1497143731Sdougb 1498143731Sdougb ret = dst_key_todns(key, &keyb); 1499143731Sdougb if (ret != ISC_R_SUCCESS) 1500143731Sdougb return (ret); 1501143731Sdougb 1502143731Sdougb isc_buffer_usedregion(&keyb, &r); 1503143731Sdougb dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r); 1504143731Sdougb 1505143731Sdougb ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb); 1506143731Sdougb if (ret != ISC_R_SUCCESS) 1507143731Sdougb return (DST_R_INVALIDPUBLICKEY); 1508143731Sdougb 1509143731Sdougb ret = dns_rdataclass_totext(key->key_class, &classb); 1510143731Sdougb if (ret != ISC_R_SUCCESS) 1511143731Sdougb return (DST_R_INVALIDPUBLICKEY); 1512143731Sdougb 1513143731Sdougb /* 1514143731Sdougb * Make the filename. 1515143731Sdougb */ 1516143731Sdougb isc_buffer_init(&fileb, filename, sizeof(filename)); 1517143731Sdougb ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb); 1518143731Sdougb if (ret != ISC_R_SUCCESS) 1519143731Sdougb return (ret); 1520143731Sdougb 1521143731Sdougb /* 1522143731Sdougb * Create public key file. 1523143731Sdougb */ 1524143731Sdougb if ((fp = fopen(filename, "w")) == NULL) 1525143731Sdougb return (DST_R_WRITEERROR); 1526143731Sdougb 1527143731Sdougb if (issymmetric(key)) { 1528143731Sdougb access = 0; 1529143731Sdougb isc_fsaccess_add(ISC_FSACCESS_OWNER, 1530143731Sdougb ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, 1531143731Sdougb &access); 1532143731Sdougb (void)isc_fsaccess_set(filename, access); 1533143731Sdougb } 1534143731Sdougb 1535224092Sdougb /* Write key information in comments */ 1536224092Sdougb if ((type & DST_TYPE_KEY) == 0) { 1537224092Sdougb fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ", 1538224092Sdougb (key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ? 1539224092Sdougb "revoked " : 1540224092Sdougb "", 1541224092Sdougb (key->key_flags & DNS_KEYFLAG_KSK) != 0 ? 1542224092Sdougb "key" : 1543224092Sdougb "zone", 1544224092Sdougb key->key_id); 1545224092Sdougb ret = dns_name_print(key->key_name, fp); 1546224092Sdougb if (ret != ISC_R_SUCCESS) { 1547224092Sdougb fclose(fp); 1548224092Sdougb return (ret); 1549224092Sdougb } 1550224092Sdougb fputc('\n', fp); 1551224092Sdougb 1552224092Sdougb printtime(key, DST_TIME_CREATED, "; Created", fp); 1553224092Sdougb printtime(key, DST_TIME_PUBLISH, "; Publish", fp); 1554224092Sdougb printtime(key, DST_TIME_ACTIVATE, "; Activate", fp); 1555224092Sdougb printtime(key, DST_TIME_REVOKE, "; Revoke", fp); 1556224092Sdougb printtime(key, DST_TIME_INACTIVE, "; Inactive", fp); 1557224092Sdougb printtime(key, DST_TIME_DELETE, "; Delete", fp); 1558165071Sdougb } 1559143731Sdougb 1560224092Sdougb /* Now print the actual key */ 1561224092Sdougb ret = dns_name_print(key->key_name, fp); 1562224092Sdougb 1563143731Sdougb fprintf(fp, " "); 1564143731Sdougb 1565143731Sdougb isc_buffer_usedregion(&classb, &r); 1566234010Sdougb if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length) 1567234010Sdougb ret = DST_R_WRITEERROR; 1568143731Sdougb 1569143731Sdougb if ((type & DST_TYPE_KEY) != 0) 1570143731Sdougb fprintf(fp, " KEY "); 1571143731Sdougb else 1572143731Sdougb fprintf(fp, " DNSKEY "); 1573143731Sdougb 1574143731Sdougb isc_buffer_usedregion(&textb, &r); 1575234010Sdougb if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length) 1576234010Sdougb ret = DST_R_WRITEERROR; 1577143731Sdougb 1578143731Sdougb fputc('\n', fp); 1579193149Sdougb fflush(fp); 1580193149Sdougb if (ferror(fp)) 1581193149Sdougb ret = DST_R_WRITEERROR; 1582143731Sdougb fclose(fp); 1583143731Sdougb 1584193149Sdougb return (ret); 1585143731Sdougb} 1586143731Sdougb 1587143731Sdougbstatic isc_result_t 1588143731Sdougbbuildfilename(dns_name_t *name, dns_keytag_t id, 1589143731Sdougb unsigned int alg, unsigned int type, 1590143731Sdougb const char *directory, isc_buffer_t *out) 1591143731Sdougb{ 1592143731Sdougb const char *suffix = ""; 1593143731Sdougb unsigned int len; 1594143731Sdougb isc_result_t result; 1595143731Sdougb 1596143731Sdougb REQUIRE(out != NULL); 1597143731Sdougb if ((type & DST_TYPE_PRIVATE) != 0) 1598143731Sdougb suffix = ".private"; 1599143731Sdougb else if (type == DST_TYPE_PUBLIC) 1600143731Sdougb suffix = ".key"; 1601143731Sdougb if (directory != NULL) { 1602143731Sdougb if (isc_buffer_availablelength(out) < strlen(directory)) 1603143731Sdougb return (ISC_R_NOSPACE); 1604143731Sdougb isc_buffer_putstr(out, directory); 1605143731Sdougb if (strlen(directory) > 0U && 1606143731Sdougb directory[strlen(directory) - 1] != '/') 1607143731Sdougb isc_buffer_putstr(out, "/"); 1608143731Sdougb } 1609143731Sdougb if (isc_buffer_availablelength(out) < 1) 1610143731Sdougb return (ISC_R_NOSPACE); 1611143731Sdougb isc_buffer_putstr(out, "K"); 1612143731Sdougb result = dns_name_tofilenametext(name, ISC_FALSE, out); 1613143731Sdougb if (result != ISC_R_SUCCESS) 1614143731Sdougb return (result); 1615143731Sdougb len = 1 + 3 + 1 + 5 + strlen(suffix) + 1; 1616143731Sdougb if (isc_buffer_availablelength(out) < len) 1617143731Sdougb return (ISC_R_NOSPACE); 1618193149Sdougb sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, 1619193149Sdougb suffix); 1620143731Sdougb isc_buffer_add(out, len); 1621193149Sdougb 1622143731Sdougb return (ISC_R_SUCCESS); 1623143731Sdougb} 1624143731Sdougb 1625143731Sdougbstatic isc_result_t 1626143731Sdougbcomputeid(dst_key_t *key) { 1627143731Sdougb isc_buffer_t dnsbuf; 1628143731Sdougb unsigned char dns_array[DST_KEY_MAXSIZE]; 1629143731Sdougb isc_region_t r; 1630143731Sdougb isc_result_t ret; 1631143731Sdougb 1632143731Sdougb isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array)); 1633143731Sdougb ret = dst_key_todns(key, &dnsbuf); 1634143731Sdougb if (ret != ISC_R_SUCCESS) 1635143731Sdougb return (ret); 1636143731Sdougb 1637143731Sdougb isc_buffer_usedregion(&dnsbuf, &r); 1638143731Sdougb key->key_id = dst_region_computeid(&r, key->key_alg); 1639234010Sdougb key->key_rid = dst_region_computerid(&r, key->key_alg); 1640143731Sdougb return (ISC_R_SUCCESS); 1641143731Sdougb} 1642143731Sdougb 1643143731Sdougbstatic isc_result_t 1644143731Sdougbfrombuffer(dns_name_t *name, unsigned int alg, unsigned int flags, 1645143731Sdougb unsigned int protocol, dns_rdataclass_t rdclass, 1646143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 1647143731Sdougb{ 1648143731Sdougb dst_key_t *key; 1649143731Sdougb isc_result_t ret; 1650143731Sdougb 1651143731Sdougb REQUIRE(dns_name_isabsolute(name)); 1652143731Sdougb REQUIRE(source != NULL); 1653143731Sdougb REQUIRE(mctx != NULL); 1654143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 1655143731Sdougb 1656143731Sdougb key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 1657143731Sdougb if (key == NULL) 1658143731Sdougb return (ISC_R_NOMEMORY); 1659143731Sdougb 1660143731Sdougb if (isc_buffer_remaininglength(source) > 0) { 1661143731Sdougb ret = algorithm_status(alg); 1662143731Sdougb if (ret != ISC_R_SUCCESS) { 1663143731Sdougb dst_key_free(&key); 1664143731Sdougb return (ret); 1665143731Sdougb } 1666143731Sdougb if (key->func->fromdns == NULL) { 1667143731Sdougb dst_key_free(&key); 1668143731Sdougb return (DST_R_UNSUPPORTEDALG); 1669143731Sdougb } 1670143731Sdougb 1671143731Sdougb ret = key->func->fromdns(key, source); 1672143731Sdougb if (ret != ISC_R_SUCCESS) { 1673143731Sdougb dst_key_free(&key); 1674143731Sdougb return (ret); 1675143731Sdougb } 1676143731Sdougb } 1677143731Sdougb 1678143731Sdougb *keyp = key; 1679143731Sdougb return (ISC_R_SUCCESS); 1680143731Sdougb} 1681143731Sdougb 1682143731Sdougbstatic isc_result_t 1683143731Sdougbalgorithm_status(unsigned int alg) { 1684143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1685143731Sdougb 1686143731Sdougb if (dst_algorithm_supported(alg)) 1687143731Sdougb return (ISC_R_SUCCESS); 1688143731Sdougb#ifndef OPENSSL 1689143731Sdougb if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || 1690143731Sdougb alg == DST_ALG_DSA || alg == DST_ALG_DH || 1691193149Sdougb alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA || 1692204619Sdougb alg == DST_ALG_NSEC3RSASHA1 || 1693224092Sdougb alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512 || 1694224092Sdougb alg == DST_ALG_ECCGOST) 1695143731Sdougb return (DST_R_NOCRYPTO); 1696143731Sdougb#endif 1697143731Sdougb return (DST_R_UNSUPPORTEDALG); 1698143731Sdougb} 1699143731Sdougb 1700143731Sdougbstatic isc_result_t 1701224092Sdougbaddsuffix(char *filename, int len, const char *odirname, 1702224092Sdougb const char *ofilename, const char *suffix) 1703143731Sdougb{ 1704143731Sdougb int olen = strlen(ofilename); 1705143731Sdougb int n; 1706143731Sdougb 1707143731Sdougb if (olen > 1 && ofilename[olen - 1] == '.') 1708143731Sdougb olen -= 1; 1709143731Sdougb else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) 1710143731Sdougb olen -= 8; 1711143731Sdougb else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) 1712143731Sdougb olen -= 4; 1713143731Sdougb 1714224092Sdougb if (odirname == NULL) 1715224092Sdougb n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); 1716224092Sdougb else 1717224092Sdougb n = snprintf(filename, len, "%s/%.*s%s", 1718224092Sdougb odirname, olen, ofilename, suffix); 1719143731Sdougb if (n < 0) 1720204619Sdougb return (ISC_R_FAILURE); 1721224092Sdougb if (n >= len) 1722143731Sdougb return (ISC_R_NOSPACE); 1723143731Sdougb return (ISC_R_SUCCESS); 1724143731Sdougb} 1725143731Sdougb 1726143731Sdougbisc_result_t 1727143731Sdougbdst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { 1728224092Sdougb#ifdef BIND9 1729143731Sdougb unsigned int flags = dst_entropy_flags; 1730204619Sdougb 1731204619Sdougb if (len == 0) 1732204619Sdougb return (ISC_R_SUCCESS); 1733143731Sdougb if (pseudo) 1734143731Sdougb flags &= ~ISC_ENTROPY_GOODONLY; 1735224092Sdougb else 1736224092Sdougb flags |= ISC_ENTROPY_BLOCKING; 1737143731Sdougb return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); 1738224092Sdougb#else 1739224092Sdougb UNUSED(buf); 1740224092Sdougb UNUSED(len); 1741224092Sdougb UNUSED(pseudo); 1742224092Sdougb 1743224092Sdougb return (ISC_R_NOTIMPLEMENTED); 1744224092Sdougb#endif 1745143731Sdougb} 1746193149Sdougb 1747193149Sdougbunsigned int 1748193149Sdougbdst__entropy_status(void) { 1749224092Sdougb#ifdef BIND9 1750204619Sdougb#ifdef GSSAPI 1751204619Sdougb unsigned int flags = dst_entropy_flags; 1752204619Sdougb isc_result_t ret; 1753204619Sdougb unsigned char buf[32]; 1754204619Sdougb static isc_boolean_t first = ISC_TRUE; 1755204619Sdougb 1756204619Sdougb if (first) { 1757204619Sdougb /* Someone believes RAND_status() initializes the PRNG */ 1758204619Sdougb flags &= ~ISC_ENTROPY_GOODONLY; 1759204619Sdougb ret = isc_entropy_getdata(dst_entropy_pool, buf, 1760204619Sdougb sizeof(buf), NULL, flags); 1761204619Sdougb INSIST(ret == ISC_R_SUCCESS); 1762204619Sdougb isc_entropy_putdata(dst_entropy_pool, buf, 1763204619Sdougb sizeof(buf), 2 * sizeof(buf)); 1764204619Sdougb first = ISC_FALSE; 1765204619Sdougb } 1766204619Sdougb#endif 1767193149Sdougb return (isc_entropy_status(dst_entropy_pool)); 1768224092Sdougb#else 1769224092Sdougb return (0); 1770224092Sdougb#endif 1771193149Sdougb} 1772224092Sdougb 1773224092Sdougbisc_buffer_t * 1774224092Sdougbdst_key_tkeytoken(const dst_key_t *key) { 1775225361Sdougb REQUIRE(VALID_KEY(key)); 1776224092Sdougb return (key->key_tkeytoken); 1777224092Sdougb} 1778