dst_api.c revision 224092
1143731Sdougb/* 2224092Sdougb * Portions Copyright (C) 2004-2011 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 34224092Sdougb * $Id: dst_api.c,v 1.57 2011-01-11 23:47:13 tbox Exp $ 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 key->key_id = id; 451143731Sdougb 452143731Sdougb *keyp = key; 453143731Sdougb return (ISC_R_SUCCESS); 454143731Sdougb} 455143731Sdougb 456143731Sdougbisc_result_t 457224092Sdougbdst_key_fromnamedfile(const char *filename, const char *dirname, 458224092Sdougb int type, isc_mem_t *mctx, dst_key_t **keyp) 459143731Sdougb{ 460143731Sdougb isc_result_t result; 461143731Sdougb dst_key_t *pubkey = NULL, *key = NULL; 462143731Sdougb char *newfilename = NULL; 463143731Sdougb int newfilenamelen = 0; 464143731Sdougb isc_lex_t *lex = NULL; 465143731Sdougb 466143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 467143731Sdougb REQUIRE(filename != NULL); 468143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 469143731Sdougb REQUIRE(mctx != NULL); 470143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 471143731Sdougb 472224092Sdougb /* If an absolute path is specified, don't use the key directory */ 473224092Sdougb#ifndef WIN32 474224092Sdougb if (filename[0] == '/') 475224092Sdougb dirname = NULL; 476224092Sdougb#else /* WIN32 */ 477224092Sdougb if (filename[0] == '/' || filename[0] == '\\') 478224092Sdougb dirname = NULL; 479224092Sdougb#endif 480224092Sdougb 481170222Sdougb newfilenamelen = strlen(filename) + 5; 482224092Sdougb if (dirname != NULL) 483224092Sdougb newfilenamelen += strlen(dirname) + 1; 484170222Sdougb newfilename = isc_mem_get(mctx, newfilenamelen); 485170222Sdougb if (newfilename == NULL) 486170222Sdougb return (ISC_R_NOMEMORY); 487224092Sdougb result = addsuffix(newfilename, newfilenamelen, 488224092Sdougb dirname, filename, ".key"); 489170222Sdougb INSIST(result == ISC_R_SUCCESS); 490170222Sdougb 491170222Sdougb result = dst_key_read_public(newfilename, type, mctx, &pubkey); 492170222Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 493170222Sdougb newfilename = NULL; 494143731Sdougb if (result != ISC_R_SUCCESS) 495143731Sdougb return (result); 496143731Sdougb 497143731Sdougb if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC || 498193149Sdougb (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { 499143731Sdougb result = computeid(pubkey); 500143731Sdougb if (result != ISC_R_SUCCESS) { 501143731Sdougb dst_key_free(&pubkey); 502143731Sdougb return (result); 503143731Sdougb } 504143731Sdougb 505143731Sdougb *keyp = pubkey; 506143731Sdougb return (ISC_R_SUCCESS); 507143731Sdougb } 508143731Sdougb 509143731Sdougb result = algorithm_status(pubkey->key_alg); 510143731Sdougb if (result != ISC_R_SUCCESS) { 511143731Sdougb dst_key_free(&pubkey); 512143731Sdougb return (result); 513143731Sdougb } 514143731Sdougb 515143731Sdougb key = get_key_struct(pubkey->key_name, pubkey->key_alg, 516143731Sdougb pubkey->key_flags, pubkey->key_proto, 0, 517143731Sdougb pubkey->key_class, mctx); 518224092Sdougb if (key == NULL) { 519224092Sdougb dst_key_free(&pubkey); 520143731Sdougb return (ISC_R_NOMEMORY); 521224092Sdougb } 522143731Sdougb 523143731Sdougb if (key->func->parse == NULL) 524143731Sdougb RETERR(DST_R_UNSUPPORTEDALG); 525143731Sdougb 526143731Sdougb newfilenamelen = strlen(filename) + 9; 527224092Sdougb if (dirname != NULL) 528224092Sdougb newfilenamelen += strlen(dirname) + 1; 529143731Sdougb newfilename = isc_mem_get(mctx, newfilenamelen); 530143731Sdougb if (newfilename == NULL) 531143731Sdougb RETERR(ISC_R_NOMEMORY); 532224092Sdougb result = addsuffix(newfilename, newfilenamelen, 533224092Sdougb dirname, filename, ".private"); 534143731Sdougb INSIST(result == ISC_R_SUCCESS); 535143731Sdougb 536143731Sdougb RETERR(isc_lex_create(mctx, 1500, &lex)); 537143731Sdougb RETERR(isc_lex_openfile(lex, newfilename)); 538143731Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 539143731Sdougb 540224092Sdougb RETERR(key->func->parse(key, lex, pubkey)); 541143731Sdougb isc_lex_destroy(&lex); 542143731Sdougb 543143731Sdougb RETERR(computeid(key)); 544143731Sdougb 545224092Sdougb if (pubkey->key_id != key->key_id) 546143731Sdougb RETERR(DST_R_INVALIDPRIVATEKEY); 547224092Sdougb dst_key_free(&pubkey); 548143731Sdougb 549143731Sdougb *keyp = key; 550143731Sdougb return (ISC_R_SUCCESS); 551218384Sdougb 552143731Sdougb out: 553224092Sdougb if (pubkey != NULL) 554224092Sdougb dst_key_free(&pubkey); 555143731Sdougb if (newfilename != NULL) 556143731Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 557143731Sdougb if (lex != NULL) 558143731Sdougb isc_lex_destroy(&lex); 559143731Sdougb dst_key_free(&key); 560143731Sdougb return (result); 561143731Sdougb} 562143731Sdougb 563143731Sdougbisc_result_t 564143731Sdougbdst_key_todns(const dst_key_t *key, isc_buffer_t *target) { 565143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 566143731Sdougb REQUIRE(VALID_KEY(key)); 567143731Sdougb REQUIRE(target != NULL); 568143731Sdougb 569143731Sdougb CHECKALG(key->key_alg); 570143731Sdougb 571143731Sdougb if (key->func->todns == NULL) 572143731Sdougb return (DST_R_UNSUPPORTEDALG); 573143731Sdougb 574143731Sdougb if (isc_buffer_availablelength(target) < 4) 575143731Sdougb return (ISC_R_NOSPACE); 576143731Sdougb isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff)); 577143731Sdougb isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto); 578143731Sdougb isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg); 579143731Sdougb 580143731Sdougb if (key->key_flags & DNS_KEYFLAG_EXTENDED) { 581143731Sdougb if (isc_buffer_availablelength(target) < 2) 582143731Sdougb return (ISC_R_NOSPACE); 583143731Sdougb isc_buffer_putuint16(target, 584143731Sdougb (isc_uint16_t)((key->key_flags >> 16) 585143731Sdougb & 0xffff)); 586143731Sdougb } 587143731Sdougb 588193149Sdougb if (key->keydata.generic == NULL) /*%< NULL KEY */ 589143731Sdougb return (ISC_R_SUCCESS); 590143731Sdougb 591143731Sdougb return (key->func->todns(key, target)); 592143731Sdougb} 593143731Sdougb 594143731Sdougbisc_result_t 595143731Sdougbdst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, 596143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 597143731Sdougb{ 598143731Sdougb isc_uint8_t alg, proto; 599143731Sdougb isc_uint32_t flags, extflags; 600143731Sdougb dst_key_t *key = NULL; 601143731Sdougb dns_keytag_t id; 602143731Sdougb isc_region_t r; 603143731Sdougb isc_result_t result; 604143731Sdougb 605143731Sdougb REQUIRE(dst_initialized); 606143731Sdougb 607143731Sdougb isc_buffer_remainingregion(source, &r); 608143731Sdougb 609143731Sdougb if (isc_buffer_remaininglength(source) < 4) 610143731Sdougb return (DST_R_INVALIDPUBLICKEY); 611143731Sdougb flags = isc_buffer_getuint16(source); 612143731Sdougb proto = isc_buffer_getuint8(source); 613143731Sdougb alg = isc_buffer_getuint8(source); 614143731Sdougb 615143731Sdougb id = dst_region_computeid(&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; 629143731Sdougb 630143731Sdougb *keyp = key; 631143731Sdougb return (ISC_R_SUCCESS); 632143731Sdougb} 633143731Sdougb 634143731Sdougbisc_result_t 635143731Sdougbdst_key_frombuffer(dns_name_t *name, unsigned int alg, 636143731Sdougb unsigned int flags, unsigned int protocol, 637143731Sdougb dns_rdataclass_t rdclass, 638143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 639143731Sdougb{ 640143731Sdougb dst_key_t *key = NULL; 641143731Sdougb isc_result_t result; 642143731Sdougb 643143731Sdougb REQUIRE(dst_initialized); 644143731Sdougb 645143731Sdougb result = frombuffer(name, alg, flags, protocol, rdclass, source, 646143731Sdougb mctx, &key); 647143731Sdougb if (result != ISC_R_SUCCESS) 648143731Sdougb return (result); 649143731Sdougb 650143731Sdougb result = computeid(key); 651143731Sdougb if (result != ISC_R_SUCCESS) { 652143731Sdougb dst_key_free(&key); 653143731Sdougb return (result); 654143731Sdougb } 655143731Sdougb 656143731Sdougb *keyp = key; 657143731Sdougb return (ISC_R_SUCCESS); 658143731Sdougb} 659143731Sdougb 660143731Sdougbisc_result_t 661143731Sdougbdst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) { 662143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 663143731Sdougb REQUIRE(VALID_KEY(key)); 664143731Sdougb REQUIRE(target != NULL); 665143731Sdougb 666143731Sdougb CHECKALG(key->key_alg); 667143731Sdougb 668143731Sdougb if (key->func->todns == NULL) 669143731Sdougb return (DST_R_UNSUPPORTEDALG); 670143731Sdougb 671143731Sdougb return (key->func->todns(key, target)); 672143731Sdougb} 673143731Sdougb 674143731Sdougbisc_result_t 675143731Sdougbdst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { 676143731Sdougb isc_lex_t *lex = NULL; 677143731Sdougb isc_result_t result = ISC_R_SUCCESS; 678143731Sdougb 679143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 680143731Sdougb REQUIRE(VALID_KEY(key)); 681143731Sdougb REQUIRE(!dst_key_isprivate(key)); 682143731Sdougb REQUIRE(buffer != NULL); 683143731Sdougb 684143731Sdougb if (key->func->parse == NULL) 685143731Sdougb RETERR(DST_R_UNSUPPORTEDALG); 686143731Sdougb 687143731Sdougb RETERR(isc_lex_create(key->mctx, 1500, &lex)); 688143731Sdougb RETERR(isc_lex_openbuffer(lex, buffer)); 689224092Sdougb RETERR(key->func->parse(key, lex, NULL)); 690143731Sdougb out: 691143731Sdougb if (lex != NULL) 692143731Sdougb isc_lex_destroy(&lex); 693143731Sdougb return (result); 694143731Sdougb} 695143731Sdougb 696193149Sdougbgss_ctx_id_t 697193149Sdougbdst_key_getgssctx(const dst_key_t *key) 698193149Sdougb{ 699193149Sdougb REQUIRE(key != NULL); 700193149Sdougb 701193149Sdougb return (key->keydata.gssctx); 702193149Sdougb} 703193149Sdougb 704143731Sdougbisc_result_t 705193149Sdougbdst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, 706224092Sdougb dst_key_t **keyp, isc_region_t *intoken) 707143731Sdougb{ 708143731Sdougb dst_key_t *key; 709224092Sdougb isc_result_t result; 710143731Sdougb 711193149Sdougb REQUIRE(gssctx != NULL); 712143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 713143731Sdougb 714143731Sdougb key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 715143731Sdougb 0, dns_rdataclass_in, mctx); 716143731Sdougb if (key == NULL) 717143731Sdougb return (ISC_R_NOMEMORY); 718193149Sdougb 719224092Sdougb if (intoken != NULL) { 720224092Sdougb /* 721224092Sdougb * Keep the token for use by external ssu rules. They may need 722224092Sdougb * to examine the PAC in the kerberos ticket. 723224092Sdougb */ 724224092Sdougb RETERR(isc_buffer_allocate(key->mctx, &key->key_tkeytoken, 725224092Sdougb intoken->length)); 726224092Sdougb RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken)); 727224092Sdougb } 728224092Sdougb 729193149Sdougb key->keydata.gssctx = gssctx; 730143731Sdougb *keyp = key; 731224092Sdougb result = ISC_R_SUCCESS; 732224092Sdougbout: 733224092Sdougb return result; 734143731Sdougb} 735143731Sdougb 736143731Sdougbisc_result_t 737193149Sdougbdst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags, 738193149Sdougb unsigned int protocol, dns_rdataclass_t rdclass, 739193149Sdougb const char *engine, const char *label, const char *pin, 740193149Sdougb isc_mem_t *mctx, dst_key_t **keyp) 741193149Sdougb{ 742193149Sdougb dst_key_t *key; 743193149Sdougb isc_result_t result; 744193149Sdougb 745193149Sdougb REQUIRE(dst_initialized == ISC_TRUE); 746193149Sdougb REQUIRE(dns_name_isabsolute(name)); 747193149Sdougb REQUIRE(mctx != NULL); 748193149Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 749193149Sdougb REQUIRE(label != NULL); 750193149Sdougb 751193149Sdougb CHECKALG(alg); 752193149Sdougb 753193149Sdougb key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 754193149Sdougb if (key == NULL) 755193149Sdougb return (ISC_R_NOMEMORY); 756193149Sdougb 757193149Sdougb if (key->func->fromlabel == NULL) { 758193149Sdougb dst_key_free(&key); 759193149Sdougb return (DST_R_UNSUPPORTEDALG); 760193149Sdougb } 761193149Sdougb 762193149Sdougb result = key->func->fromlabel(key, engine, label, pin); 763193149Sdougb if (result != ISC_R_SUCCESS) { 764193149Sdougb dst_key_free(&key); 765193149Sdougb return (result); 766193149Sdougb } 767193149Sdougb 768193149Sdougb result = computeid(key); 769193149Sdougb if (result != ISC_R_SUCCESS) { 770193149Sdougb dst_key_free(&key); 771193149Sdougb return (result); 772193149Sdougb } 773193149Sdougb 774193149Sdougb *keyp = key; 775193149Sdougb return (ISC_R_SUCCESS); 776193149Sdougb} 777193149Sdougb 778193149Sdougbisc_result_t 779143731Sdougbdst_key_generate(dns_name_t *name, unsigned int alg, 780143731Sdougb unsigned int bits, unsigned int param, 781143731Sdougb unsigned int flags, unsigned int protocol, 782143731Sdougb dns_rdataclass_t rdclass, 783143731Sdougb isc_mem_t *mctx, dst_key_t **keyp) 784143731Sdougb{ 785224092Sdougb return (dst_key_generate2(name, alg, bits, param, flags, protocol, 786224092Sdougb rdclass, mctx, keyp, NULL)); 787224092Sdougb} 788224092Sdougb 789224092Sdougbisc_result_t 790224092Sdougbdst_key_generate2(dns_name_t *name, unsigned int alg, 791224092Sdougb unsigned int bits, unsigned int param, 792224092Sdougb unsigned int flags, unsigned int protocol, 793224092Sdougb dns_rdataclass_t rdclass, 794224092Sdougb isc_mem_t *mctx, dst_key_t **keyp, 795224092Sdougb void (*callback)(int)) 796224092Sdougb{ 797143731Sdougb dst_key_t *key; 798143731Sdougb isc_result_t ret; 799143731Sdougb 800143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 801143731Sdougb REQUIRE(dns_name_isabsolute(name)); 802143731Sdougb REQUIRE(mctx != NULL); 803143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 804143731Sdougb 805143731Sdougb CHECKALG(alg); 806143731Sdougb 807143731Sdougb key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx); 808143731Sdougb if (key == NULL) 809143731Sdougb return (ISC_R_NOMEMORY); 810143731Sdougb 811170222Sdougb if (bits == 0) { /*%< NULL KEY */ 812143731Sdougb key->key_flags |= DNS_KEYTYPE_NOKEY; 813143731Sdougb *keyp = key; 814143731Sdougb return (ISC_R_SUCCESS); 815143731Sdougb } 816143731Sdougb 817143731Sdougb if (key->func->generate == NULL) { 818143731Sdougb dst_key_free(&key); 819143731Sdougb return (DST_R_UNSUPPORTEDALG); 820143731Sdougb } 821143731Sdougb 822224092Sdougb ret = key->func->generate(key, param, callback); 823143731Sdougb if (ret != ISC_R_SUCCESS) { 824143731Sdougb dst_key_free(&key); 825143731Sdougb return (ret); 826143731Sdougb } 827143731Sdougb 828143731Sdougb ret = computeid(key); 829143731Sdougb if (ret != ISC_R_SUCCESS) { 830143731Sdougb dst_key_free(&key); 831143731Sdougb return (ret); 832143731Sdougb } 833143731Sdougb 834143731Sdougb *keyp = key; 835143731Sdougb return (ISC_R_SUCCESS); 836143731Sdougb} 837143731Sdougb 838224092Sdougbisc_result_t 839224092Sdougbdst_key_getnum(const dst_key_t *key, int type, isc_uint32_t *valuep) 840224092Sdougb{ 841224092Sdougb REQUIRE(VALID_KEY(key)); 842224092Sdougb REQUIRE(valuep != NULL); 843224092Sdougb REQUIRE(type <= DST_MAX_NUMERIC); 844224092Sdougb if (!key->numset[type]) 845224092Sdougb return (ISC_R_NOTFOUND); 846224092Sdougb *valuep = key->nums[type]; 847224092Sdougb return (ISC_R_SUCCESS); 848224092Sdougb} 849224092Sdougb 850224092Sdougbvoid 851224092Sdougbdst_key_setnum(dst_key_t *key, int type, isc_uint32_t value) 852224092Sdougb{ 853224092Sdougb REQUIRE(VALID_KEY(key)); 854224092Sdougb REQUIRE(type <= DST_MAX_NUMERIC); 855224092Sdougb key->nums[type] = value; 856224092Sdougb key->numset[type] = ISC_TRUE; 857224092Sdougb} 858224092Sdougb 859224092Sdougbvoid 860224092Sdougbdst_key_unsetnum(dst_key_t *key, int type) 861224092Sdougb{ 862224092Sdougb REQUIRE(VALID_KEY(key)); 863224092Sdougb REQUIRE(type <= DST_MAX_NUMERIC); 864224092Sdougb key->numset[type] = ISC_FALSE; 865224092Sdougb} 866224092Sdougb 867224092Sdougbisc_result_t 868224092Sdougbdst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) { 869224092Sdougb REQUIRE(VALID_KEY(key)); 870224092Sdougb REQUIRE(timep != NULL); 871224092Sdougb REQUIRE(type <= DST_MAX_TIMES); 872224092Sdougb if (!key->timeset[type]) 873224092Sdougb return (ISC_R_NOTFOUND); 874224092Sdougb *timep = key->times[type]; 875224092Sdougb return (ISC_R_SUCCESS); 876224092Sdougb} 877224092Sdougb 878224092Sdougbvoid 879224092Sdougbdst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) { 880224092Sdougb REQUIRE(VALID_KEY(key)); 881224092Sdougb REQUIRE(type <= DST_MAX_TIMES); 882224092Sdougb key->times[type] = when; 883224092Sdougb key->timeset[type] = ISC_TRUE; 884224092Sdougb} 885224092Sdougb 886224092Sdougbvoid 887224092Sdougbdst_key_unsettime(dst_key_t *key, int type) { 888224092Sdougb REQUIRE(VALID_KEY(key)); 889224092Sdougb REQUIRE(type <= DST_MAX_TIMES); 890224092Sdougb key->timeset[type] = ISC_FALSE; 891224092Sdougb} 892224092Sdougb 893224092Sdougbisc_result_t 894224092Sdougbdst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) { 895224092Sdougb REQUIRE(VALID_KEY(key)); 896224092Sdougb REQUIRE(majorp != NULL); 897224092Sdougb REQUIRE(minorp != NULL); 898224092Sdougb *majorp = key->fmt_major; 899224092Sdougb *minorp = key->fmt_minor; 900224092Sdougb return (ISC_R_SUCCESS); 901224092Sdougb} 902224092Sdougb 903224092Sdougbvoid 904224092Sdougbdst_key_setprivateformat(dst_key_t *key, int major, int minor) { 905224092Sdougb REQUIRE(VALID_KEY(key)); 906224092Sdougb key->fmt_major = major; 907224092Sdougb key->fmt_minor = minor; 908224092Sdougb} 909224092Sdougb 910224092Sdougbstatic isc_boolean_t 911224092Sdougbcomparekeys(const dst_key_t *key1, const dst_key_t *key2, 912224092Sdougb isc_boolean_t match_revoked_key, 913224092Sdougb isc_boolean_t (*compare)(const dst_key_t *key1, 914224092Sdougb const dst_key_t *key2)) 915224092Sdougb{ 916143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 917143731Sdougb REQUIRE(VALID_KEY(key1)); 918143731Sdougb REQUIRE(VALID_KEY(key2)); 919143731Sdougb 920143731Sdougb if (key1 == key2) 921143731Sdougb return (ISC_TRUE); 922224092Sdougb 923143731Sdougb if (key1 == NULL || key2 == NULL) 924143731Sdougb return (ISC_FALSE); 925224092Sdougb 926224092Sdougb if (key1->key_alg != key2->key_alg) 927224092Sdougb return (ISC_FALSE); 928224092Sdougb 929224092Sdougb /* 930224092Sdougb * For all algorithms except RSAMD5, revoking the key 931224092Sdougb * changes the key ID, increasing it by 128. If we want to 932224092Sdougb * be able to find matching keys even if one of them is the 933224092Sdougb * revoked version of the other one, then we need to check 934224092Sdougb * for that possibility. 935224092Sdougb */ 936224092Sdougb if (key1->key_id != key2->key_id) { 937224092Sdougb if (!match_revoked_key) 938224092Sdougb return (ISC_FALSE); 939224092Sdougb if (key1->key_alg == DST_ALG_RSAMD5) 940224092Sdougb return (ISC_FALSE); 941224092Sdougb if ((key1->key_flags & DNS_KEYFLAG_REVOKE) == 942224092Sdougb (key2->key_flags & DNS_KEYFLAG_REVOKE)) 943224092Sdougb return (ISC_FALSE); 944224092Sdougb if ((key1->key_flags & DNS_KEYFLAG_REVOKE) != 0 && 945224092Sdougb key1->key_id != ((key2->key_id + 128) & 0xffff)) 946224092Sdougb return (ISC_FALSE); 947224092Sdougb if ((key2->key_flags & DNS_KEYFLAG_REVOKE) != 0 && 948224092Sdougb key2->key_id != ((key1->key_id + 128) & 0xffff)) 949224092Sdougb return (ISC_FALSE); 950224092Sdougb } 951224092Sdougb 952224092Sdougb if (compare != NULL) 953224092Sdougb return (compare(key1, key2)); 954143731Sdougb else 955143731Sdougb return (ISC_FALSE); 956143731Sdougb} 957143731Sdougb 958224092Sdougb 959224092Sdougb/* 960224092Sdougb * Compares only the public portion of two keys, by converting them 961224092Sdougb * both to wire format and comparing the results. 962224092Sdougb */ 963224092Sdougbstatic isc_boolean_t 964224092Sdougbpub_compare(const dst_key_t *key1, const dst_key_t *key2) { 965224092Sdougb isc_result_t result; 966224092Sdougb unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE]; 967224092Sdougb isc_buffer_t b1, b2; 968224092Sdougb isc_region_t r1, r2; 969224092Sdougb 970224092Sdougb isc_buffer_init(&b1, buf1, sizeof(buf1)); 971224092Sdougb result = dst_key_todns(key1, &b1); 972224092Sdougb if (result != ISC_R_SUCCESS) 973224092Sdougb return (ISC_FALSE); 974224092Sdougb /* Zero out flags. */ 975224092Sdougb buf1[0] = buf1[1] = 0; 976224092Sdougb if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) 977224092Sdougb isc_buffer_subtract(&b1, 2); 978224092Sdougb 979224092Sdougb isc_buffer_init(&b2, buf2, sizeof(buf2)); 980224092Sdougb result = dst_key_todns(key2, &b2); 981224092Sdougb if (result != ISC_R_SUCCESS) 982224092Sdougb return (ISC_FALSE); 983224092Sdougb /* Zero out flags. */ 984224092Sdougb buf2[0] = buf2[1] = 0; 985224092Sdougb if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) 986224092Sdougb isc_buffer_subtract(&b2, 2); 987224092Sdougb 988224092Sdougb isc_buffer_usedregion(&b1, &r1); 989224092Sdougb /* Remove extended flags. */ 990224092Sdougb if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { 991224092Sdougb memmove(&buf1[4], &buf1[6], r1.length - 6); 992224092Sdougb r1.length -= 2; 993224092Sdougb } 994224092Sdougb 995224092Sdougb isc_buffer_usedregion(&b2, &r2); 996224092Sdougb /* Remove extended flags. */ 997224092Sdougb if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) { 998224092Sdougb memmove(&buf2[4], &buf2[6], r2.length - 6); 999224092Sdougb r2.length -= 2; 1000224092Sdougb } 1001224092Sdougb return (ISC_TF(isc_region_compare(&r1, &r2) == 0)); 1002224092Sdougb} 1003224092Sdougb 1004143731Sdougbisc_boolean_t 1005224092Sdougbdst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { 1006224092Sdougb return (comparekeys(key1, key2, ISC_FALSE, key1->func->compare)); 1007224092Sdougb} 1008224092Sdougb 1009224092Sdougbisc_boolean_t 1010224092Sdougbdst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2, 1011224092Sdougb isc_boolean_t match_revoked_key) 1012224092Sdougb{ 1013224092Sdougb return (comparekeys(key1, key2, match_revoked_key, pub_compare)); 1014224092Sdougb} 1015224092Sdougb 1016224092Sdougb 1017224092Sdougbisc_boolean_t 1018143731Sdougbdst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { 1019143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1020143731Sdougb REQUIRE(VALID_KEY(key1)); 1021143731Sdougb REQUIRE(VALID_KEY(key2)); 1022143731Sdougb 1023143731Sdougb if (key1 == key2) 1024143731Sdougb return (ISC_TRUE); 1025143731Sdougb if (key1 == NULL || key2 == NULL) 1026143731Sdougb return (ISC_FALSE); 1027143731Sdougb if (key1->key_alg == key2->key_alg && 1028143731Sdougb key1->func->paramcompare != NULL && 1029143731Sdougb key1->func->paramcompare(key1, key2) == ISC_TRUE) 1030143731Sdougb return (ISC_TRUE); 1031143731Sdougb else 1032143731Sdougb return (ISC_FALSE); 1033143731Sdougb} 1034143731Sdougb 1035143731Sdougbvoid 1036218384Sdougbdst_key_attach(dst_key_t *source, dst_key_t **target) { 1037218384Sdougb 1038218384Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1039218384Sdougb REQUIRE(target != NULL && *target == NULL); 1040218384Sdougb REQUIRE(VALID_KEY(source)); 1041218384Sdougb 1042218384Sdougb isc_refcount_increment(&source->refs, NULL); 1043218384Sdougb *target = source; 1044218384Sdougb} 1045218384Sdougb 1046218384Sdougbvoid 1047143731Sdougbdst_key_free(dst_key_t **keyp) { 1048143731Sdougb isc_mem_t *mctx; 1049143731Sdougb dst_key_t *key; 1050218384Sdougb unsigned int refs; 1051143731Sdougb 1052143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1053143731Sdougb REQUIRE(keyp != NULL && VALID_KEY(*keyp)); 1054143731Sdougb 1055143731Sdougb key = *keyp; 1056143731Sdougb mctx = key->mctx; 1057143731Sdougb 1058218384Sdougb isc_refcount_decrement(&key->refs, &refs); 1059218384Sdougb if (refs != 0) 1060218384Sdougb return; 1061218384Sdougb 1062218384Sdougb isc_refcount_destroy(&key->refs); 1063193149Sdougb if (key->keydata.generic != NULL) { 1064143731Sdougb INSIST(key->func->destroy != NULL); 1065143731Sdougb key->func->destroy(key); 1066143731Sdougb } 1067193149Sdougb if (key->engine != NULL) 1068193149Sdougb isc_mem_free(mctx, key->engine); 1069193149Sdougb if (key->label != NULL) 1070193149Sdougb isc_mem_free(mctx, key->label); 1071143731Sdougb dns_name_free(key->key_name, mctx); 1072143731Sdougb isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 1073224092Sdougb if (key->key_tkeytoken) { 1074224092Sdougb isc_buffer_free(&key->key_tkeytoken); 1075224092Sdougb } 1076143731Sdougb memset(key, 0, sizeof(dst_key_t)); 1077143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 1078143731Sdougb *keyp = NULL; 1079143731Sdougb} 1080143731Sdougb 1081143731Sdougbisc_boolean_t 1082143731Sdougbdst_key_isprivate(const dst_key_t *key) { 1083143731Sdougb REQUIRE(VALID_KEY(key)); 1084143731Sdougb INSIST(key->func->isprivate != NULL); 1085143731Sdougb return (key->func->isprivate(key)); 1086143731Sdougb} 1087143731Sdougb 1088143731Sdougbisc_result_t 1089143731Sdougbdst_key_buildfilename(const dst_key_t *key, int type, 1090143731Sdougb const char *directory, isc_buffer_t *out) { 1091143731Sdougb 1092143731Sdougb REQUIRE(VALID_KEY(key)); 1093143731Sdougb REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC || 1094143731Sdougb type == 0); 1095143731Sdougb 1096143731Sdougb return (buildfilename(key->key_name, key->key_id, key->key_alg, 1097143731Sdougb type, directory, out)); 1098143731Sdougb} 1099143731Sdougb 1100143731Sdougbisc_result_t 1101143731Sdougbdst_key_sigsize(const dst_key_t *key, unsigned int *n) { 1102143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1103143731Sdougb REQUIRE(VALID_KEY(key)); 1104143731Sdougb REQUIRE(n != NULL); 1105143731Sdougb 1106143731Sdougb /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1107143731Sdougb switch (key->key_alg) { 1108143731Sdougb case DST_ALG_RSAMD5: 1109143731Sdougb case DST_ALG_RSASHA1: 1110193149Sdougb case DST_ALG_NSEC3RSASHA1: 1111204619Sdougb case DST_ALG_RSASHA256: 1112204619Sdougb case DST_ALG_RSASHA512: 1113143731Sdougb *n = (key->key_size + 7) / 8; 1114143731Sdougb break; 1115143731Sdougb case DST_ALG_DSA: 1116193149Sdougb case DST_ALG_NSEC3DSA: 1117143731Sdougb *n = DNS_SIG_DSASIGSIZE; 1118143731Sdougb break; 1119224092Sdougb case DST_ALG_ECCGOST: 1120224092Sdougb *n = DNS_SIG_GOSTSIGSIZE; 1121224092Sdougb break; 1122143731Sdougb case DST_ALG_HMACMD5: 1123143731Sdougb *n = 16; 1124143731Sdougb break; 1125170222Sdougb case DST_ALG_HMACSHA1: 1126170222Sdougb *n = ISC_SHA1_DIGESTLENGTH; 1127170222Sdougb break; 1128170222Sdougb case DST_ALG_HMACSHA224: 1129170222Sdougb *n = ISC_SHA224_DIGESTLENGTH; 1130170222Sdougb break; 1131170222Sdougb case DST_ALG_HMACSHA256: 1132170222Sdougb *n = ISC_SHA256_DIGESTLENGTH; 1133170222Sdougb break; 1134170222Sdougb case DST_ALG_HMACSHA384: 1135170222Sdougb *n = ISC_SHA384_DIGESTLENGTH; 1136170222Sdougb break; 1137170222Sdougb case DST_ALG_HMACSHA512: 1138170222Sdougb *n = ISC_SHA512_DIGESTLENGTH; 1139170222Sdougb break; 1140143731Sdougb case DST_ALG_GSSAPI: 1141170222Sdougb *n = 128; /*%< XXX */ 1142143731Sdougb break; 1143143731Sdougb case DST_ALG_DH: 1144143731Sdougb default: 1145143731Sdougb return (DST_R_UNSUPPORTEDALG); 1146143731Sdougb } 1147143731Sdougb return (ISC_R_SUCCESS); 1148143731Sdougb} 1149143731Sdougb 1150143731Sdougbisc_result_t 1151143731Sdougbdst_key_secretsize(const dst_key_t *key, unsigned int *n) { 1152143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1153143731Sdougb REQUIRE(VALID_KEY(key)); 1154143731Sdougb REQUIRE(n != NULL); 1155143731Sdougb 1156143731Sdougb if (key->key_alg == DST_ALG_DH) 1157143731Sdougb *n = (key->key_size + 7) / 8; 1158143731Sdougb else 1159143731Sdougb return (DST_R_UNSUPPORTEDALG); 1160143731Sdougb return (ISC_R_SUCCESS); 1161143731Sdougb} 1162143731Sdougb 1163224092Sdougb/*% 1164224092Sdougb * Set the flags on a key, then recompute the key ID 1165224092Sdougb */ 1166224092Sdougbisc_result_t 1167224092Sdougbdst_key_setflags(dst_key_t *key, isc_uint32_t flags) { 1168224092Sdougb REQUIRE(VALID_KEY(key)); 1169224092Sdougb key->key_flags = flags; 1170224092Sdougb return (computeid(key)); 1171224092Sdougb} 1172224092Sdougb 1173224092Sdougbvoid 1174224092Sdougbdst_key_format(const dst_key_t *key, char *cp, unsigned int size) { 1175224092Sdougb char namestr[DNS_NAME_FORMATSIZE]; 1176224092Sdougb char algstr[DNS_NAME_FORMATSIZE]; 1177224092Sdougb 1178224092Sdougb dns_name_format(dst_key_name(key), namestr, sizeof(namestr)); 1179224092Sdougb dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr, 1180224092Sdougb sizeof(algstr)); 1181224092Sdougb snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key)); 1182224092Sdougb} 1183224092Sdougb 1184224092Sdougbisc_result_t 1185224092Sdougbdst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) { 1186224092Sdougb 1187224092Sdougb REQUIRE(buffer != NULL && *buffer == NULL); 1188224092Sdougb REQUIRE(length != NULL && *length == 0); 1189224092Sdougb REQUIRE(VALID_KEY(key)); 1190224092Sdougb 1191224092Sdougb if (key->func->isprivate == NULL) 1192224092Sdougb return (ISC_R_NOTIMPLEMENTED); 1193224092Sdougb return (key->func->dump(key, mctx, buffer, length)); 1194224092Sdougb} 1195224092Sdougb 1196224092Sdougbisc_result_t 1197224092Sdougbdst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags, 1198224092Sdougb unsigned int protocol, dns_rdataclass_t rdclass, 1199224092Sdougb isc_mem_t *mctx, const char *keystr, dst_key_t **keyp) 1200224092Sdougb{ 1201224092Sdougb isc_result_t result; 1202224092Sdougb dst_key_t *key; 1203224092Sdougb 1204224092Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1205224092Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 1206224092Sdougb 1207224092Sdougb if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) 1208224092Sdougb return (DST_R_UNSUPPORTEDALG); 1209224092Sdougb 1210224092Sdougb if (dst_t_func[alg]->restore == NULL) 1211224092Sdougb return (ISC_R_NOTIMPLEMENTED); 1212224092Sdougb 1213224092Sdougb key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 1214224092Sdougb if (key == NULL) 1215224092Sdougb return (ISC_R_NOMEMORY); 1216224092Sdougb 1217224092Sdougb result = (dst_t_func[alg]->restore)(key, keystr); 1218224092Sdougb if (result == ISC_R_SUCCESS) 1219224092Sdougb *keyp = key; 1220224092Sdougb else 1221224092Sdougb dst_key_free(&key); 1222224092Sdougb 1223224092Sdougb return (result); 1224224092Sdougb} 1225224092Sdougb 1226143731Sdougb/*** 1227143731Sdougb *** Static methods 1228143731Sdougb ***/ 1229143731Sdougb 1230170222Sdougb/*% 1231143731Sdougb * Allocates a key structure and fills in some of the fields. 1232143731Sdougb */ 1233143731Sdougbstatic dst_key_t * 1234143731Sdougbget_key_struct(dns_name_t *name, unsigned int alg, 1235143731Sdougb unsigned int flags, unsigned int protocol, 1236143731Sdougb unsigned int bits, dns_rdataclass_t rdclass, 1237143731Sdougb isc_mem_t *mctx) 1238143731Sdougb{ 1239143731Sdougb dst_key_t *key; 1240143731Sdougb isc_result_t result; 1241224092Sdougb int i; 1242143731Sdougb 1243143731Sdougb key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); 1244143731Sdougb if (key == NULL) 1245143731Sdougb return (NULL); 1246143731Sdougb 1247143731Sdougb memset(key, 0, sizeof(dst_key_t)); 1248143731Sdougb key->magic = KEY_MAGIC; 1249143731Sdougb 1250218384Sdougb result = isc_refcount_init(&key->refs, 1); 1251218384Sdougb if (result != ISC_R_SUCCESS) { 1252218384Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 1253218384Sdougb return (NULL); 1254218384Sdougb } 1255218384Sdougb 1256143731Sdougb key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); 1257143731Sdougb if (key->key_name == NULL) { 1258218384Sdougb isc_refcount_destroy(&key->refs); 1259143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 1260143731Sdougb return (NULL); 1261143731Sdougb } 1262143731Sdougb dns_name_init(key->key_name, NULL); 1263143731Sdougb result = dns_name_dup(name, mctx, key->key_name); 1264143731Sdougb if (result != ISC_R_SUCCESS) { 1265218384Sdougb isc_refcount_destroy(&key->refs); 1266143731Sdougb isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 1267143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 1268143731Sdougb return (NULL); 1269143731Sdougb } 1270143731Sdougb key->key_alg = alg; 1271143731Sdougb key->key_flags = flags; 1272143731Sdougb key->key_proto = protocol; 1273143731Sdougb key->mctx = mctx; 1274193149Sdougb key->keydata.generic = NULL; 1275143731Sdougb key->key_size = bits; 1276143731Sdougb key->key_class = rdclass; 1277143731Sdougb key->func = dst_t_func[alg]; 1278224092Sdougb key->fmt_major = 0; 1279224092Sdougb key->fmt_minor = 0; 1280224092Sdougb for (i = 0; i < (DST_MAX_TIMES + 1); i++) { 1281224092Sdougb key->times[i] = 0; 1282224092Sdougb key->timeset[i] = ISC_FALSE; 1283224092Sdougb } 1284143731Sdougb return (key); 1285143731Sdougb} 1286143731Sdougb 1287170222Sdougb/*% 1288143731Sdougb * Reads a public key from disk 1289143731Sdougb */ 1290170222Sdougbisc_result_t 1291170222Sdougbdst_key_read_public(const char *filename, int type, 1292170222Sdougb isc_mem_t *mctx, dst_key_t **keyp) 1293143731Sdougb{ 1294143731Sdougb u_char rdatabuf[DST_KEY_MAXSIZE]; 1295143731Sdougb isc_buffer_t b; 1296143731Sdougb dns_fixedname_t name; 1297143731Sdougb isc_lex_t *lex = NULL; 1298143731Sdougb isc_token_t token; 1299143731Sdougb isc_result_t ret; 1300143731Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 1301143731Sdougb unsigned int opt = ISC_LEXOPT_DNSMULTILINE; 1302143731Sdougb dns_rdataclass_t rdclass = dns_rdataclass_in; 1303143731Sdougb isc_lexspecials_t specials; 1304143731Sdougb isc_uint32_t ttl; 1305143731Sdougb isc_result_t result; 1306143731Sdougb dns_rdatatype_t keytype; 1307143731Sdougb 1308143731Sdougb /* 1309143731Sdougb * Open the file and read its formatted contents 1310143731Sdougb * File format: 1311170222Sdougb * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key> 1312143731Sdougb */ 1313143731Sdougb 1314143731Sdougb /* 1500 should be large enough for any key */ 1315143731Sdougb ret = isc_lex_create(mctx, 1500, &lex); 1316143731Sdougb if (ret != ISC_R_SUCCESS) 1317143731Sdougb goto cleanup; 1318143731Sdougb 1319143731Sdougb memset(specials, 0, sizeof(specials)); 1320143731Sdougb specials['('] = 1; 1321143731Sdougb specials[')'] = 1; 1322143731Sdougb specials['"'] = 1; 1323143731Sdougb isc_lex_setspecials(lex, specials); 1324143731Sdougb isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); 1325143731Sdougb 1326170222Sdougb ret = isc_lex_openfile(lex, filename); 1327143731Sdougb if (ret != ISC_R_SUCCESS) 1328143731Sdougb goto cleanup; 1329143731Sdougb 1330143731Sdougb#define NEXTTOKEN(lex, opt, token) { \ 1331143731Sdougb ret = isc_lex_gettoken(lex, opt, token); \ 1332143731Sdougb if (ret != ISC_R_SUCCESS) \ 1333143731Sdougb goto cleanup; \ 1334143731Sdougb } 1335143731Sdougb 1336143731Sdougb#define BADTOKEN() { \ 1337143731Sdougb ret = ISC_R_UNEXPECTEDTOKEN; \ 1338143731Sdougb goto cleanup; \ 1339143731Sdougb } 1340143731Sdougb 1341143731Sdougb /* Read the domain name */ 1342143731Sdougb NEXTTOKEN(lex, opt, &token); 1343143731Sdougb if (token.type != isc_tokentype_string) 1344143731Sdougb BADTOKEN(); 1345193149Sdougb 1346193149Sdougb /* 1347193149Sdougb * We don't support "@" in .key files. 1348193149Sdougb */ 1349193149Sdougb if (!strcmp(DST_AS_STR(token), "@")) 1350193149Sdougb BADTOKEN(); 1351193149Sdougb 1352143731Sdougb dns_fixedname_init(&name); 1353143731Sdougb isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); 1354143731Sdougb isc_buffer_add(&b, strlen(DST_AS_STR(token))); 1355143731Sdougb ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, 1356224092Sdougb 0, NULL); 1357143731Sdougb if (ret != ISC_R_SUCCESS) 1358143731Sdougb goto cleanup; 1359143731Sdougb 1360143731Sdougb /* Read the next word: either TTL, class, or 'KEY' */ 1361143731Sdougb NEXTTOKEN(lex, opt, &token); 1362143731Sdougb 1363204619Sdougb if (token.type != isc_tokentype_string) 1364204619Sdougb BADTOKEN(); 1365204619Sdougb 1366143731Sdougb /* If it's a TTL, read the next one */ 1367143731Sdougb result = dns_ttl_fromtext(&token.value.as_textregion, &ttl); 1368143731Sdougb if (result == ISC_R_SUCCESS) 1369143731Sdougb NEXTTOKEN(lex, opt, &token); 1370143731Sdougb 1371143731Sdougb if (token.type != isc_tokentype_string) 1372143731Sdougb BADTOKEN(); 1373143731Sdougb 1374143731Sdougb ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion); 1375143731Sdougb if (ret == ISC_R_SUCCESS) 1376143731Sdougb NEXTTOKEN(lex, opt, &token); 1377143731Sdougb 1378143731Sdougb if (token.type != isc_tokentype_string) 1379143731Sdougb BADTOKEN(); 1380143731Sdougb 1381143731Sdougb if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) 1382143731Sdougb keytype = dns_rdatatype_dnskey; 1383143731Sdougb else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) 1384170222Sdougb keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */ 1385143731Sdougb else 1386143731Sdougb BADTOKEN(); 1387143731Sdougb 1388143731Sdougb if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) || 1389143731Sdougb ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) { 1390143731Sdougb ret = DST_R_BADKEYTYPE; 1391143731Sdougb goto cleanup; 1392143731Sdougb } 1393143731Sdougb 1394143731Sdougb isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); 1395143731Sdougb ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, 1396143731Sdougb ISC_FALSE, mctx, &b, NULL); 1397143731Sdougb if (ret != ISC_R_SUCCESS) 1398143731Sdougb goto cleanup; 1399143731Sdougb 1400143731Sdougb ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx, 1401143731Sdougb keyp); 1402143731Sdougb if (ret != ISC_R_SUCCESS) 1403143731Sdougb goto cleanup; 1404143731Sdougb 1405143731Sdougb cleanup: 1406143731Sdougb if (lex != NULL) 1407143731Sdougb isc_lex_destroy(&lex); 1408143731Sdougb return (ret); 1409143731Sdougb} 1410143731Sdougb 1411143731Sdougbstatic isc_boolean_t 1412143731Sdougbissymmetric(const dst_key_t *key) { 1413143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1414143731Sdougb REQUIRE(VALID_KEY(key)); 1415143731Sdougb 1416143731Sdougb /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1417143731Sdougb switch (key->key_alg) { 1418143731Sdougb case DST_ALG_RSAMD5: 1419143731Sdougb case DST_ALG_RSASHA1: 1420193149Sdougb case DST_ALG_NSEC3RSASHA1: 1421204619Sdougb case DST_ALG_RSASHA256: 1422204619Sdougb case DST_ALG_RSASHA512: 1423143731Sdougb case DST_ALG_DSA: 1424193149Sdougb case DST_ALG_NSEC3DSA: 1425143731Sdougb case DST_ALG_DH: 1426224092Sdougb case DST_ALG_ECCGOST: 1427143731Sdougb return (ISC_FALSE); 1428143731Sdougb case DST_ALG_HMACMD5: 1429143731Sdougb case DST_ALG_GSSAPI: 1430143731Sdougb return (ISC_TRUE); 1431143731Sdougb default: 1432143731Sdougb return (ISC_FALSE); 1433143731Sdougb } 1434143731Sdougb} 1435143731Sdougb 1436170222Sdougb/*% 1437224092Sdougb * Write key timing metadata to a file pointer, preceded by 'tag' 1438224092Sdougb */ 1439224092Sdougbstatic void 1440224092Sdougbprinttime(const dst_key_t *key, int type, const char *tag, FILE *stream) { 1441224092Sdougb isc_result_t result; 1442224092Sdougb#ifdef ISC_PLATFORM_USETHREADS 1443224092Sdougb char output[26]; /* Minimum buffer as per ctime_r() specification. */ 1444224092Sdougb#else 1445224092Sdougb const char *output; 1446224092Sdougb#endif 1447224092Sdougb isc_stdtime_t when; 1448224092Sdougb time_t t; 1449224092Sdougb char utc[sizeof("YYYYMMDDHHSSMM")]; 1450224092Sdougb isc_buffer_t b; 1451224092Sdougb isc_region_t r; 1452224092Sdougb 1453224092Sdougb result = dst_key_gettime(key, type, &when); 1454224092Sdougb if (result == ISC_R_NOTFOUND) 1455224092Sdougb return; 1456224092Sdougb 1457224092Sdougb /* time_t and isc_stdtime_t might be different sizes */ 1458224092Sdougb t = when; 1459224092Sdougb#ifdef ISC_PLATFORM_USETHREADS 1460224092Sdougb#ifdef WIN32 1461224092Sdougb if (ctime_s(output, sizeof(output), &t) != 0) 1462224092Sdougb goto error; 1463224092Sdougb#else 1464224092Sdougb if (ctime_r(&t, output) == NULL) 1465224092Sdougb goto error; 1466224092Sdougb#endif 1467224092Sdougb#else 1468224092Sdougb output = ctime(&t); 1469224092Sdougb#endif 1470224092Sdougb 1471224092Sdougb isc_buffer_init(&b, utc, sizeof(utc)); 1472224092Sdougb result = dns_time32_totext(when, &b); 1473224092Sdougb if (result != ISC_R_SUCCESS) 1474224092Sdougb goto error; 1475224092Sdougb 1476224092Sdougb isc_buffer_usedregion(&b, &r); 1477224092Sdougb fprintf(stream, "%s: %.*s (%.*s)\n", tag, (int)r.length, r.base, 1478224092Sdougb (int)strlen(output) - 1, output); 1479224092Sdougb return; 1480224092Sdougb 1481224092Sdougb error: 1482224092Sdougb fprintf(stream, "%s: (set, unable to display)\n", tag); 1483224092Sdougb} 1484224092Sdougb 1485224092Sdougb/*% 1486143731Sdougb * Writes a public key to disk in DNS format. 1487143731Sdougb */ 1488143731Sdougbstatic isc_result_t 1489143731Sdougbwrite_public_key(const dst_key_t *key, int type, const char *directory) { 1490143731Sdougb FILE *fp; 1491143731Sdougb isc_buffer_t keyb, textb, fileb, classb; 1492143731Sdougb isc_region_t r; 1493143731Sdougb char filename[ISC_DIR_NAMEMAX]; 1494143731Sdougb unsigned char key_array[DST_KEY_MAXSIZE]; 1495143731Sdougb char text_array[DST_KEY_MAXTEXTSIZE]; 1496143731Sdougb char class_array[10]; 1497143731Sdougb isc_result_t ret; 1498143731Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 1499143731Sdougb isc_fsaccess_t access; 1500143731Sdougb 1501143731Sdougb REQUIRE(VALID_KEY(key)); 1502143731Sdougb 1503143731Sdougb isc_buffer_init(&keyb, key_array, sizeof(key_array)); 1504143731Sdougb isc_buffer_init(&textb, text_array, sizeof(text_array)); 1505143731Sdougb isc_buffer_init(&classb, class_array, sizeof(class_array)); 1506143731Sdougb 1507143731Sdougb ret = dst_key_todns(key, &keyb); 1508143731Sdougb if (ret != ISC_R_SUCCESS) 1509143731Sdougb return (ret); 1510143731Sdougb 1511143731Sdougb isc_buffer_usedregion(&keyb, &r); 1512143731Sdougb dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r); 1513143731Sdougb 1514143731Sdougb ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb); 1515143731Sdougb if (ret != ISC_R_SUCCESS) 1516143731Sdougb return (DST_R_INVALIDPUBLICKEY); 1517143731Sdougb 1518143731Sdougb ret = dns_rdataclass_totext(key->key_class, &classb); 1519143731Sdougb if (ret != ISC_R_SUCCESS) 1520143731Sdougb return (DST_R_INVALIDPUBLICKEY); 1521143731Sdougb 1522143731Sdougb /* 1523143731Sdougb * Make the filename. 1524143731Sdougb */ 1525143731Sdougb isc_buffer_init(&fileb, filename, sizeof(filename)); 1526143731Sdougb ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb); 1527143731Sdougb if (ret != ISC_R_SUCCESS) 1528143731Sdougb return (ret); 1529143731Sdougb 1530143731Sdougb /* 1531143731Sdougb * Create public key file. 1532143731Sdougb */ 1533143731Sdougb if ((fp = fopen(filename, "w")) == NULL) 1534143731Sdougb return (DST_R_WRITEERROR); 1535143731Sdougb 1536143731Sdougb if (issymmetric(key)) { 1537143731Sdougb access = 0; 1538143731Sdougb isc_fsaccess_add(ISC_FSACCESS_OWNER, 1539143731Sdougb ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, 1540143731Sdougb &access); 1541143731Sdougb (void)isc_fsaccess_set(filename, access); 1542143731Sdougb } 1543143731Sdougb 1544224092Sdougb /* Write key information in comments */ 1545224092Sdougb if ((type & DST_TYPE_KEY) == 0) { 1546224092Sdougb fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ", 1547224092Sdougb (key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ? 1548224092Sdougb "revoked " : 1549224092Sdougb "", 1550224092Sdougb (key->key_flags & DNS_KEYFLAG_KSK) != 0 ? 1551224092Sdougb "key" : 1552224092Sdougb "zone", 1553224092Sdougb key->key_id); 1554224092Sdougb ret = dns_name_print(key->key_name, fp); 1555224092Sdougb if (ret != ISC_R_SUCCESS) { 1556224092Sdougb fclose(fp); 1557224092Sdougb return (ret); 1558224092Sdougb } 1559224092Sdougb fputc('\n', fp); 1560224092Sdougb 1561224092Sdougb printtime(key, DST_TIME_CREATED, "; Created", fp); 1562224092Sdougb printtime(key, DST_TIME_PUBLISH, "; Publish", fp); 1563224092Sdougb printtime(key, DST_TIME_ACTIVATE, "; Activate", fp); 1564224092Sdougb printtime(key, DST_TIME_REVOKE, "; Revoke", fp); 1565224092Sdougb printtime(key, DST_TIME_INACTIVE, "; Inactive", fp); 1566224092Sdougb printtime(key, DST_TIME_DELETE, "; Delete", fp); 1567165071Sdougb } 1568143731Sdougb 1569224092Sdougb /* Now print the actual key */ 1570224092Sdougb ret = dns_name_print(key->key_name, fp); 1571224092Sdougb 1572143731Sdougb fprintf(fp, " "); 1573143731Sdougb 1574143731Sdougb isc_buffer_usedregion(&classb, &r); 1575204619Sdougb isc_util_fwrite(r.base, 1, r.length, fp); 1576143731Sdougb 1577143731Sdougb if ((type & DST_TYPE_KEY) != 0) 1578143731Sdougb fprintf(fp, " KEY "); 1579143731Sdougb else 1580143731Sdougb fprintf(fp, " DNSKEY "); 1581143731Sdougb 1582143731Sdougb isc_buffer_usedregion(&textb, &r); 1583204619Sdougb isc_util_fwrite(r.base, 1, r.length, fp); 1584143731Sdougb 1585143731Sdougb fputc('\n', fp); 1586193149Sdougb fflush(fp); 1587193149Sdougb if (ferror(fp)) 1588193149Sdougb ret = DST_R_WRITEERROR; 1589143731Sdougb fclose(fp); 1590143731Sdougb 1591193149Sdougb return (ret); 1592143731Sdougb} 1593143731Sdougb 1594143731Sdougbstatic isc_result_t 1595143731Sdougbbuildfilename(dns_name_t *name, dns_keytag_t id, 1596143731Sdougb unsigned int alg, unsigned int type, 1597143731Sdougb const char *directory, isc_buffer_t *out) 1598143731Sdougb{ 1599143731Sdougb const char *suffix = ""; 1600143731Sdougb unsigned int len; 1601143731Sdougb isc_result_t result; 1602143731Sdougb 1603143731Sdougb REQUIRE(out != NULL); 1604143731Sdougb if ((type & DST_TYPE_PRIVATE) != 0) 1605143731Sdougb suffix = ".private"; 1606143731Sdougb else if (type == DST_TYPE_PUBLIC) 1607143731Sdougb suffix = ".key"; 1608143731Sdougb if (directory != NULL) { 1609143731Sdougb if (isc_buffer_availablelength(out) < strlen(directory)) 1610143731Sdougb return (ISC_R_NOSPACE); 1611143731Sdougb isc_buffer_putstr(out, directory); 1612143731Sdougb if (strlen(directory) > 0U && 1613143731Sdougb directory[strlen(directory) - 1] != '/') 1614143731Sdougb isc_buffer_putstr(out, "/"); 1615143731Sdougb } 1616143731Sdougb if (isc_buffer_availablelength(out) < 1) 1617143731Sdougb return (ISC_R_NOSPACE); 1618143731Sdougb isc_buffer_putstr(out, "K"); 1619143731Sdougb result = dns_name_tofilenametext(name, ISC_FALSE, out); 1620143731Sdougb if (result != ISC_R_SUCCESS) 1621143731Sdougb return (result); 1622143731Sdougb len = 1 + 3 + 1 + 5 + strlen(suffix) + 1; 1623143731Sdougb if (isc_buffer_availablelength(out) < len) 1624143731Sdougb return (ISC_R_NOSPACE); 1625193149Sdougb sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, 1626193149Sdougb suffix); 1627143731Sdougb isc_buffer_add(out, len); 1628193149Sdougb 1629143731Sdougb return (ISC_R_SUCCESS); 1630143731Sdougb} 1631143731Sdougb 1632143731Sdougbstatic isc_result_t 1633143731Sdougbcomputeid(dst_key_t *key) { 1634143731Sdougb isc_buffer_t dnsbuf; 1635143731Sdougb unsigned char dns_array[DST_KEY_MAXSIZE]; 1636143731Sdougb isc_region_t r; 1637143731Sdougb isc_result_t ret; 1638143731Sdougb 1639143731Sdougb isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array)); 1640143731Sdougb ret = dst_key_todns(key, &dnsbuf); 1641143731Sdougb if (ret != ISC_R_SUCCESS) 1642143731Sdougb return (ret); 1643143731Sdougb 1644143731Sdougb isc_buffer_usedregion(&dnsbuf, &r); 1645143731Sdougb key->key_id = dst_region_computeid(&r, key->key_alg); 1646143731Sdougb return (ISC_R_SUCCESS); 1647143731Sdougb} 1648143731Sdougb 1649143731Sdougbstatic isc_result_t 1650143731Sdougbfrombuffer(dns_name_t *name, unsigned int alg, unsigned int flags, 1651143731Sdougb unsigned int protocol, dns_rdataclass_t rdclass, 1652143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 1653143731Sdougb{ 1654143731Sdougb dst_key_t *key; 1655143731Sdougb isc_result_t ret; 1656143731Sdougb 1657143731Sdougb REQUIRE(dns_name_isabsolute(name)); 1658143731Sdougb REQUIRE(source != NULL); 1659143731Sdougb REQUIRE(mctx != NULL); 1660143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 1661143731Sdougb 1662143731Sdougb key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 1663143731Sdougb if (key == NULL) 1664143731Sdougb return (ISC_R_NOMEMORY); 1665143731Sdougb 1666143731Sdougb if (isc_buffer_remaininglength(source) > 0) { 1667143731Sdougb ret = algorithm_status(alg); 1668143731Sdougb if (ret != ISC_R_SUCCESS) { 1669143731Sdougb dst_key_free(&key); 1670143731Sdougb return (ret); 1671143731Sdougb } 1672143731Sdougb if (key->func->fromdns == NULL) { 1673143731Sdougb dst_key_free(&key); 1674143731Sdougb return (DST_R_UNSUPPORTEDALG); 1675143731Sdougb } 1676143731Sdougb 1677143731Sdougb ret = key->func->fromdns(key, source); 1678143731Sdougb if (ret != ISC_R_SUCCESS) { 1679143731Sdougb dst_key_free(&key); 1680143731Sdougb return (ret); 1681143731Sdougb } 1682143731Sdougb } 1683143731Sdougb 1684143731Sdougb *keyp = key; 1685143731Sdougb return (ISC_R_SUCCESS); 1686143731Sdougb} 1687143731Sdougb 1688143731Sdougbstatic isc_result_t 1689143731Sdougbalgorithm_status(unsigned int alg) { 1690143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1691143731Sdougb 1692143731Sdougb if (dst_algorithm_supported(alg)) 1693143731Sdougb return (ISC_R_SUCCESS); 1694143731Sdougb#ifndef OPENSSL 1695143731Sdougb if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || 1696143731Sdougb alg == DST_ALG_DSA || alg == DST_ALG_DH || 1697193149Sdougb alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA || 1698204619Sdougb alg == DST_ALG_NSEC3RSASHA1 || 1699224092Sdougb alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512 || 1700224092Sdougb alg == DST_ALG_ECCGOST) 1701143731Sdougb return (DST_R_NOCRYPTO); 1702143731Sdougb#endif 1703143731Sdougb return (DST_R_UNSUPPORTEDALG); 1704143731Sdougb} 1705143731Sdougb 1706143731Sdougbstatic isc_result_t 1707224092Sdougbaddsuffix(char *filename, int len, const char *odirname, 1708224092Sdougb const char *ofilename, const char *suffix) 1709143731Sdougb{ 1710143731Sdougb int olen = strlen(ofilename); 1711143731Sdougb int n; 1712143731Sdougb 1713143731Sdougb if (olen > 1 && ofilename[olen - 1] == '.') 1714143731Sdougb olen -= 1; 1715143731Sdougb else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) 1716143731Sdougb olen -= 8; 1717143731Sdougb else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) 1718143731Sdougb olen -= 4; 1719143731Sdougb 1720224092Sdougb if (odirname == NULL) 1721224092Sdougb n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); 1722224092Sdougb else 1723224092Sdougb n = snprintf(filename, len, "%s/%.*s%s", 1724224092Sdougb odirname, olen, ofilename, suffix); 1725143731Sdougb if (n < 0) 1726204619Sdougb return (ISC_R_FAILURE); 1727224092Sdougb if (n >= len) 1728143731Sdougb return (ISC_R_NOSPACE); 1729143731Sdougb return (ISC_R_SUCCESS); 1730143731Sdougb} 1731143731Sdougb 1732143731Sdougbisc_result_t 1733143731Sdougbdst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { 1734224092Sdougb#ifdef BIND9 1735143731Sdougb unsigned int flags = dst_entropy_flags; 1736204619Sdougb 1737204619Sdougb if (len == 0) 1738204619Sdougb return (ISC_R_SUCCESS); 1739143731Sdougb if (pseudo) 1740143731Sdougb flags &= ~ISC_ENTROPY_GOODONLY; 1741224092Sdougb else 1742224092Sdougb flags |= ISC_ENTROPY_BLOCKING; 1743143731Sdougb return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); 1744224092Sdougb#else 1745224092Sdougb UNUSED(buf); 1746224092Sdougb UNUSED(len); 1747224092Sdougb UNUSED(pseudo); 1748224092Sdougb 1749224092Sdougb return (ISC_R_NOTIMPLEMENTED); 1750224092Sdougb#endif 1751143731Sdougb} 1752193149Sdougb 1753193149Sdougbunsigned int 1754193149Sdougbdst__entropy_status(void) { 1755224092Sdougb#ifdef BIND9 1756204619Sdougb#ifdef GSSAPI 1757204619Sdougb unsigned int flags = dst_entropy_flags; 1758204619Sdougb isc_result_t ret; 1759204619Sdougb unsigned char buf[32]; 1760204619Sdougb static isc_boolean_t first = ISC_TRUE; 1761204619Sdougb 1762204619Sdougb if (first) { 1763204619Sdougb /* Someone believes RAND_status() initializes the PRNG */ 1764204619Sdougb flags &= ~ISC_ENTROPY_GOODONLY; 1765204619Sdougb ret = isc_entropy_getdata(dst_entropy_pool, buf, 1766204619Sdougb sizeof(buf), NULL, flags); 1767204619Sdougb INSIST(ret == ISC_R_SUCCESS); 1768204619Sdougb isc_entropy_putdata(dst_entropy_pool, buf, 1769204619Sdougb sizeof(buf), 2 * sizeof(buf)); 1770204619Sdougb first = ISC_FALSE; 1771204619Sdougb } 1772204619Sdougb#endif 1773193149Sdougb return (isc_entropy_status(dst_entropy_pool)); 1774224092Sdougb#else 1775224092Sdougb return (0); 1776224092Sdougb#endif 1777193149Sdougb} 1778224092Sdougb 1779224092Sdougbisc_buffer_t * 1780224092Sdougbdst_key_tkeytoken(const dst_key_t *key) { 1781224092Sdougb return (key->key_tkeytoken); 1782224092Sdougb} 1783