dst_api.c revision 218384
1143731Sdougb/* 2204619Sdougb * Portions Copyright (C) 2004-2010 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 34218384Sdougb * $Id: dst_api.c,v 1.16.12.12 2010-12-09 01:12:55 marka Exp $ 35143731Sdougb */ 36143731Sdougb 37170222Sdougb/*! \file */ 38170222Sdougb 39143731Sdougb#include <config.h> 40143731Sdougb 41143731Sdougb#include <stdlib.h> 42143731Sdougb 43143731Sdougb#include <isc/buffer.h> 44143731Sdougb#include <isc/dir.h> 45143731Sdougb#include <isc/entropy.h> 46143731Sdougb#include <isc/fsaccess.h> 47170222Sdougb#include <isc/hmacsha.h> 48143731Sdougb#include <isc/lex.h> 49143731Sdougb#include <isc/mem.h> 50143731Sdougb#include <isc/once.h> 51143731Sdougb#include <isc/print.h> 52218384Sdougb#include <isc/refcount.h> 53143731Sdougb#include <isc/random.h> 54143731Sdougb#include <isc/string.h> 55143731Sdougb#include <isc/time.h> 56143731Sdougb#include <isc/util.h> 57143731Sdougb 58143731Sdougb#include <dns/fixedname.h> 59143731Sdougb#include <dns/keyvalues.h> 60143731Sdougb#include <dns/name.h> 61143731Sdougb#include <dns/rdata.h> 62143731Sdougb#include <dns/rdataclass.h> 63143731Sdougb#include <dns/ttl.h> 64143731Sdougb#include <dns/types.h> 65143731Sdougb 66143731Sdougb#include <dst/result.h> 67143731Sdougb 68143731Sdougb#include "dst_internal.h" 69143731Sdougb 70143731Sdougb#define DST_AS_STR(t) ((t).value.as_textregion.base) 71143731Sdougb 72143731Sdougbstatic dst_func_t *dst_t_func[DST_MAX_ALGS]; 73143731Sdougbstatic isc_entropy_t *dst_entropy_pool = NULL; 74143731Sdougbstatic unsigned int dst_entropy_flags = 0; 75143731Sdougbstatic isc_boolean_t dst_initialized = ISC_FALSE; 76143731Sdougb 77193149Sdougbvoid gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); 78193149Sdougb 79143731Sdougbisc_mem_t *dst__memory_pool = NULL; 80143731Sdougb 81143731Sdougb/* 82143731Sdougb * Static functions. 83143731Sdougb */ 84143731Sdougbstatic dst_key_t * get_key_struct(dns_name_t *name, 85143731Sdougb unsigned int alg, 86143731Sdougb unsigned int flags, 87143731Sdougb unsigned int protocol, 88143731Sdougb unsigned int bits, 89143731Sdougb dns_rdataclass_t rdclass, 90143731Sdougb isc_mem_t *mctx); 91143731Sdougbstatic isc_result_t write_public_key(const dst_key_t *key, int type, 92143731Sdougb const char *directory); 93143731Sdougbstatic isc_result_t buildfilename(dns_name_t *name, 94143731Sdougb dns_keytag_t id, 95143731Sdougb unsigned int alg, 96143731Sdougb unsigned int type, 97143731Sdougb const char *directory, 98143731Sdougb isc_buffer_t *out); 99143731Sdougbstatic isc_result_t computeid(dst_key_t *key); 100143731Sdougbstatic isc_result_t frombuffer(dns_name_t *name, 101143731Sdougb unsigned int alg, 102143731Sdougb unsigned int flags, 103143731Sdougb unsigned int protocol, 104143731Sdougb dns_rdataclass_t rdclass, 105143731Sdougb isc_buffer_t *source, 106143731Sdougb isc_mem_t *mctx, 107143731Sdougb dst_key_t **keyp); 108143731Sdougb 109143731Sdougbstatic isc_result_t algorithm_status(unsigned int alg); 110143731Sdougb 111143731Sdougbstatic isc_result_t addsuffix(char *filename, unsigned int len, 112143731Sdougb const char *ofilename, const char *suffix); 113143731Sdougb 114143731Sdougb#define RETERR(x) \ 115143731Sdougb do { \ 116143731Sdougb result = (x); \ 117143731Sdougb if (result != ISC_R_SUCCESS) \ 118143731Sdougb goto out; \ 119143731Sdougb } while (0) 120143731Sdougb 121143731Sdougb#define CHECKALG(alg) \ 122143731Sdougb do { \ 123143731Sdougb isc_result_t _r; \ 124143731Sdougb _r = algorithm_status(alg); \ 125143731Sdougb if (_r != ISC_R_SUCCESS) \ 126143731Sdougb return (_r); \ 127143731Sdougb } while (0); \ 128143731Sdougb 129193149Sdougb#ifdef OPENSSL 130170222Sdougbstatic void * 131170222Sdougbdefault_memalloc(void *arg, size_t size) { 132193149Sdougb UNUSED(arg); 133193149Sdougb if (size == 0U) 134193149Sdougb size = 1; 135193149Sdougb return (malloc(size)); 136170222Sdougb} 137170222Sdougb 138170222Sdougbstatic void 139170222Sdougbdefault_memfree(void *arg, void *ptr) { 140193149Sdougb UNUSED(arg); 141193149Sdougb free(ptr); 142170222Sdougb} 143193149Sdougb#endif 144170222Sdougb 145143731Sdougbisc_result_t 146143731Sdougbdst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { 147143731Sdougb isc_result_t result; 148143731Sdougb 149143731Sdougb REQUIRE(mctx != NULL && ectx != NULL); 150143731Sdougb REQUIRE(dst_initialized == ISC_FALSE); 151143731Sdougb 152143731Sdougb dst__memory_pool = NULL; 153143731Sdougb 154143731Sdougb#ifdef OPENSSL 155143731Sdougb UNUSED(mctx); 156143731Sdougb /* 157143731Sdougb * When using --with-openssl, there seems to be no good way of not 158143731Sdougb * leaking memory due to the openssl error handling mechanism. 159143731Sdougb * Avoid assertions by using a local memory context and not checking 160170222Sdougb * for leaks on exit. Note: as there are leaks we cannot use 161170222Sdougb * ISC_MEMFLAG_INTERNAL as it will free up memory still being used 162170222Sdougb * by libcrypto. 163143731Sdougb */ 164170222Sdougb result = isc_mem_createx2(0, 0, default_memalloc, default_memfree, 165170222Sdougb NULL, &dst__memory_pool, 0); 166143731Sdougb if (result != ISC_R_SUCCESS) 167143731Sdougb return (result); 168193149Sdougb isc_mem_setname(dst__memory_pool, "dst", NULL); 169143731Sdougb isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE); 170143731Sdougb#else 171143731Sdougb isc_mem_attach(mctx, &dst__memory_pool); 172143731Sdougb#endif 173143731Sdougb isc_entropy_attach(ectx, &dst_entropy_pool); 174143731Sdougb dst_entropy_flags = eflags; 175143731Sdougb 176143731Sdougb dst_result_register(); 177143731Sdougb 178143731Sdougb memset(dst_t_func, 0, sizeof(dst_t_func)); 179143731Sdougb RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5])); 180170222Sdougb RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1])); 181170222Sdougb RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224])); 182170222Sdougb RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256])); 183170222Sdougb RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384])); 184170222Sdougb RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512])); 185143731Sdougb#ifdef OPENSSL 186143731Sdougb RETERR(dst__openssl_init()); 187204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5], 188204619Sdougb DST_ALG_RSAMD5)); 189204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1], 190204619Sdougb DST_ALG_RSASHA1)); 191204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1], 192204619Sdougb DST_ALG_NSEC3RSASHA1)); 193204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256], 194204619Sdougb DST_ALG_RSASHA256)); 195204619Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512], 196204619Sdougb DST_ALG_RSASHA512)); 197143731Sdougb#ifdef HAVE_OPENSSL_DSA 198143731Sdougb RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA])); 199193149Sdougb RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA])); 200143731Sdougb#endif 201143731Sdougb RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH])); 202143731Sdougb#endif /* OPENSSL */ 203143731Sdougb#ifdef GSSAPI 204143731Sdougb RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI])); 205143731Sdougb#endif 206143731Sdougb dst_initialized = ISC_TRUE; 207143731Sdougb return (ISC_R_SUCCESS); 208143731Sdougb 209143731Sdougb out: 210143731Sdougb dst_lib_destroy(); 211143731Sdougb return (result); 212143731Sdougb} 213143731Sdougb 214143731Sdougbvoid 215143731Sdougbdst_lib_destroy(void) { 216143731Sdougb int i; 217143731Sdougb RUNTIME_CHECK(dst_initialized == ISC_TRUE); 218143731Sdougb dst_initialized = ISC_FALSE; 219143731Sdougb 220143731Sdougb for (i = 0; i < DST_MAX_ALGS; i++) 221143731Sdougb if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL) 222143731Sdougb dst_t_func[i]->cleanup(); 223143731Sdougb#ifdef OPENSSL 224143731Sdougb dst__openssl_destroy(); 225143731Sdougb#endif 226143731Sdougb if (dst__memory_pool != NULL) 227143731Sdougb isc_mem_detach(&dst__memory_pool); 228143731Sdougb if (dst_entropy_pool != NULL) 229143731Sdougb isc_entropy_detach(&dst_entropy_pool); 230143731Sdougb 231143731Sdougb} 232143731Sdougb 233143731Sdougbisc_boolean_t 234143731Sdougbdst_algorithm_supported(unsigned int alg) { 235143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 236143731Sdougb 237143731Sdougb if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) 238143731Sdougb return (ISC_FALSE); 239143731Sdougb return (ISC_TRUE); 240143731Sdougb} 241143731Sdougb 242143731Sdougbisc_result_t 243143731Sdougbdst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) { 244143731Sdougb dst_context_t *dctx; 245143731Sdougb isc_result_t result; 246143731Sdougb 247143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 248143731Sdougb REQUIRE(VALID_KEY(key)); 249143731Sdougb REQUIRE(mctx != NULL); 250143731Sdougb REQUIRE(dctxp != NULL && *dctxp == NULL); 251143731Sdougb 252143731Sdougb if (key->func->createctx == NULL) 253143731Sdougb return (DST_R_UNSUPPORTEDALG); 254193149Sdougb if (key->keydata.generic == NULL) 255143731Sdougb return (DST_R_NULLKEY); 256143731Sdougb 257143731Sdougb dctx = isc_mem_get(mctx, sizeof(dst_context_t)); 258143731Sdougb if (dctx == NULL) 259143731Sdougb return (ISC_R_NOMEMORY); 260143731Sdougb dctx->key = key; 261143731Sdougb dctx->mctx = mctx; 262143731Sdougb result = key->func->createctx(key, dctx); 263143731Sdougb if (result != ISC_R_SUCCESS) { 264143731Sdougb isc_mem_put(mctx, dctx, sizeof(dst_context_t)); 265143731Sdougb return (result); 266143731Sdougb } 267143731Sdougb dctx->magic = CTX_MAGIC; 268143731Sdougb *dctxp = dctx; 269143731Sdougb return (ISC_R_SUCCESS); 270143731Sdougb} 271143731Sdougb 272143731Sdougbvoid 273143731Sdougbdst_context_destroy(dst_context_t **dctxp) { 274143731Sdougb dst_context_t *dctx; 275143731Sdougb 276143731Sdougb REQUIRE(dctxp != NULL && VALID_CTX(*dctxp)); 277143731Sdougb 278143731Sdougb dctx = *dctxp; 279143731Sdougb INSIST(dctx->key->func->destroyctx != NULL); 280143731Sdougb dctx->key->func->destroyctx(dctx); 281143731Sdougb dctx->magic = 0; 282143731Sdougb isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t)); 283143731Sdougb *dctxp = NULL; 284143731Sdougb} 285143731Sdougb 286143731Sdougbisc_result_t 287143731Sdougbdst_context_adddata(dst_context_t *dctx, const isc_region_t *data) { 288143731Sdougb REQUIRE(VALID_CTX(dctx)); 289143731Sdougb REQUIRE(data != NULL); 290143731Sdougb INSIST(dctx->key->func->adddata != NULL); 291143731Sdougb 292143731Sdougb return (dctx->key->func->adddata(dctx, data)); 293143731Sdougb} 294143731Sdougb 295143731Sdougbisc_result_t 296143731Sdougbdst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) { 297143731Sdougb dst_key_t *key; 298143731Sdougb 299143731Sdougb REQUIRE(VALID_CTX(dctx)); 300143731Sdougb REQUIRE(sig != NULL); 301143731Sdougb 302143731Sdougb key = dctx->key; 303143731Sdougb CHECKALG(key->key_alg); 304193149Sdougb if (key->keydata.generic == NULL) 305143731Sdougb return (DST_R_NULLKEY); 306193149Sdougb 307143731Sdougb if (key->func->sign == NULL) 308143731Sdougb return (DST_R_NOTPRIVATEKEY); 309143731Sdougb if (key->func->isprivate == NULL || 310143731Sdougb key->func->isprivate(key) == ISC_FALSE) 311143731Sdougb return (DST_R_NOTPRIVATEKEY); 312143731Sdougb 313143731Sdougb return (key->func->sign(dctx, sig)); 314143731Sdougb} 315143731Sdougb 316143731Sdougbisc_result_t 317143731Sdougbdst_context_verify(dst_context_t *dctx, isc_region_t *sig) { 318143731Sdougb REQUIRE(VALID_CTX(dctx)); 319143731Sdougb REQUIRE(sig != NULL); 320143731Sdougb 321143731Sdougb CHECKALG(dctx->key->key_alg); 322193149Sdougb if (dctx->key->keydata.generic == NULL) 323143731Sdougb return (DST_R_NULLKEY); 324143731Sdougb if (dctx->key->func->verify == NULL) 325143731Sdougb return (DST_R_NOTPUBLICKEY); 326143731Sdougb 327143731Sdougb return (dctx->key->func->verify(dctx, sig)); 328143731Sdougb} 329143731Sdougb 330143731Sdougbisc_result_t 331143731Sdougbdst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv, 332143731Sdougb isc_buffer_t *secret) 333143731Sdougb{ 334143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 335143731Sdougb REQUIRE(VALID_KEY(pub) && VALID_KEY(priv)); 336143731Sdougb REQUIRE(secret != NULL); 337143731Sdougb 338143731Sdougb CHECKALG(pub->key_alg); 339143731Sdougb CHECKALG(priv->key_alg); 340143731Sdougb 341193149Sdougb if (pub->keydata.generic == NULL || priv->keydata.generic == NULL) 342143731Sdougb return (DST_R_NULLKEY); 343143731Sdougb 344143731Sdougb if (pub->key_alg != priv->key_alg || 345143731Sdougb pub->func->computesecret == NULL || 346143731Sdougb priv->func->computesecret == NULL) 347143731Sdougb return (DST_R_KEYCANNOTCOMPUTESECRET); 348143731Sdougb 349143731Sdougb if (dst_key_isprivate(priv) == ISC_FALSE) 350143731Sdougb return (DST_R_NOTPRIVATEKEY); 351143731Sdougb 352143731Sdougb return (pub->func->computesecret(pub, priv, secret)); 353143731Sdougb} 354143731Sdougb 355143731Sdougbisc_result_t 356143731Sdougbdst_key_tofile(const dst_key_t *key, int type, const char *directory) { 357143731Sdougb isc_result_t ret = ISC_R_SUCCESS; 358143731Sdougb 359143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 360143731Sdougb REQUIRE(VALID_KEY(key)); 361143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 362143731Sdougb 363143731Sdougb CHECKALG(key->key_alg); 364143731Sdougb 365143731Sdougb if (key->func->tofile == NULL) 366143731Sdougb return (DST_R_UNSUPPORTEDALG); 367143731Sdougb 368143731Sdougb if (type & DST_TYPE_PUBLIC) { 369143731Sdougb ret = write_public_key(key, type, directory); 370143731Sdougb if (ret != ISC_R_SUCCESS) 371143731Sdougb return (ret); 372143731Sdougb } 373143731Sdougb 374143731Sdougb if ((type & DST_TYPE_PRIVATE) && 375143731Sdougb (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY) 376143731Sdougb return (key->func->tofile(key, directory)); 377143731Sdougb else 378143731Sdougb return (ISC_R_SUCCESS); 379143731Sdougb} 380143731Sdougb 381143731Sdougbisc_result_t 382143731Sdougbdst_key_fromfile(dns_name_t *name, dns_keytag_t id, 383143731Sdougb unsigned int alg, int type, const char *directory, 384143731Sdougb isc_mem_t *mctx, dst_key_t **keyp) 385143731Sdougb{ 386143731Sdougb char filename[ISC_DIR_NAMEMAX]; 387143731Sdougb isc_buffer_t b; 388143731Sdougb dst_key_t *key; 389143731Sdougb isc_result_t result; 390143731Sdougb 391143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 392143731Sdougb REQUIRE(dns_name_isabsolute(name)); 393143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 394143731Sdougb REQUIRE(mctx != NULL); 395143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 396143731Sdougb 397143731Sdougb CHECKALG(alg); 398143731Sdougb 399143731Sdougb isc_buffer_init(&b, filename, sizeof(filename)); 400143731Sdougb result = buildfilename(name, id, alg, type, directory, &b); 401143731Sdougb if (result != ISC_R_SUCCESS) 402143731Sdougb return (result); 403143731Sdougb 404143731Sdougb key = NULL; 405143731Sdougb result = dst_key_fromnamedfile(filename, type, mctx, &key); 406143731Sdougb if (result != ISC_R_SUCCESS) 407143731Sdougb return (result); 408143731Sdougb 409143731Sdougb result = computeid(key); 410143731Sdougb if (result != ISC_R_SUCCESS) { 411143731Sdougb dst_key_free(&key); 412143731Sdougb return (result); 413143731Sdougb } 414143731Sdougb 415193149Sdougb if (!dns_name_equal(name, key->key_name) || id != key->key_id || 416193149Sdougb alg != key->key_alg) { 417143731Sdougb dst_key_free(&key); 418143731Sdougb return (DST_R_INVALIDPRIVATEKEY); 419143731Sdougb } 420143731Sdougb key->key_id = id; 421143731Sdougb 422143731Sdougb *keyp = key; 423143731Sdougb return (ISC_R_SUCCESS); 424143731Sdougb} 425143731Sdougb 426143731Sdougbisc_result_t 427143731Sdougbdst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, 428143731Sdougb dst_key_t **keyp) 429143731Sdougb{ 430143731Sdougb isc_result_t result; 431143731Sdougb dst_key_t *pubkey = NULL, *key = NULL; 432143731Sdougb dns_keytag_t id; 433143731Sdougb char *newfilename = NULL; 434143731Sdougb int newfilenamelen = 0; 435143731Sdougb isc_lex_t *lex = NULL; 436143731Sdougb 437143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 438143731Sdougb REQUIRE(filename != NULL); 439143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 440143731Sdougb REQUIRE(mctx != NULL); 441143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 442143731Sdougb 443170222Sdougb newfilenamelen = strlen(filename) + 5; 444170222Sdougb newfilename = isc_mem_get(mctx, newfilenamelen); 445170222Sdougb if (newfilename == NULL) 446170222Sdougb return (ISC_R_NOMEMORY); 447170222Sdougb result = addsuffix(newfilename, newfilenamelen, filename, ".key"); 448170222Sdougb INSIST(result == ISC_R_SUCCESS); 449170222Sdougb 450170222Sdougb result = dst_key_read_public(newfilename, type, mctx, &pubkey); 451170222Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 452170222Sdougb newfilename = NULL; 453143731Sdougb if (result != ISC_R_SUCCESS) 454143731Sdougb return (result); 455143731Sdougb 456143731Sdougb if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC || 457193149Sdougb (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { 458143731Sdougb result = computeid(pubkey); 459143731Sdougb if (result != ISC_R_SUCCESS) { 460143731Sdougb dst_key_free(&pubkey); 461143731Sdougb return (result); 462143731Sdougb } 463143731Sdougb 464143731Sdougb *keyp = pubkey; 465143731Sdougb return (ISC_R_SUCCESS); 466143731Sdougb } 467143731Sdougb 468143731Sdougb result = algorithm_status(pubkey->key_alg); 469143731Sdougb if (result != ISC_R_SUCCESS) { 470143731Sdougb dst_key_free(&pubkey); 471143731Sdougb return (result); 472143731Sdougb } 473143731Sdougb 474143731Sdougb key = get_key_struct(pubkey->key_name, pubkey->key_alg, 475143731Sdougb pubkey->key_flags, pubkey->key_proto, 0, 476143731Sdougb pubkey->key_class, mctx); 477143731Sdougb id = pubkey->key_id; 478143731Sdougb dst_key_free(&pubkey); 479143731Sdougb 480143731Sdougb if (key == NULL) 481143731Sdougb return (ISC_R_NOMEMORY); 482143731Sdougb 483143731Sdougb if (key->func->parse == NULL) 484143731Sdougb RETERR(DST_R_UNSUPPORTEDALG); 485143731Sdougb 486143731Sdougb newfilenamelen = strlen(filename) + 9; 487143731Sdougb newfilename = isc_mem_get(mctx, newfilenamelen); 488143731Sdougb if (newfilename == NULL) 489143731Sdougb RETERR(ISC_R_NOMEMORY); 490143731Sdougb result = addsuffix(newfilename, newfilenamelen, filename, ".private"); 491143731Sdougb INSIST(result == ISC_R_SUCCESS); 492143731Sdougb 493143731Sdougb RETERR(isc_lex_create(mctx, 1500, &lex)); 494143731Sdougb RETERR(isc_lex_openfile(lex, newfilename)); 495143731Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 496143731Sdougb 497143731Sdougb RETERR(key->func->parse(key, lex)); 498143731Sdougb isc_lex_destroy(&lex); 499143731Sdougb 500143731Sdougb RETERR(computeid(key)); 501143731Sdougb 502143731Sdougb if (id != key->key_id) 503143731Sdougb RETERR(DST_R_INVALIDPRIVATEKEY); 504143731Sdougb 505143731Sdougb *keyp = key; 506143731Sdougb return (ISC_R_SUCCESS); 507218384Sdougb 508143731Sdougb out: 509143731Sdougb if (newfilename != NULL) 510143731Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 511143731Sdougb if (lex != NULL) 512143731Sdougb isc_lex_destroy(&lex); 513143731Sdougb dst_key_free(&key); 514143731Sdougb return (result); 515143731Sdougb} 516143731Sdougb 517143731Sdougbisc_result_t 518143731Sdougbdst_key_todns(const dst_key_t *key, isc_buffer_t *target) { 519143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 520143731Sdougb REQUIRE(VALID_KEY(key)); 521143731Sdougb REQUIRE(target != NULL); 522143731Sdougb 523143731Sdougb CHECKALG(key->key_alg); 524143731Sdougb 525143731Sdougb if (key->func->todns == NULL) 526143731Sdougb return (DST_R_UNSUPPORTEDALG); 527143731Sdougb 528143731Sdougb if (isc_buffer_availablelength(target) < 4) 529143731Sdougb return (ISC_R_NOSPACE); 530143731Sdougb isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff)); 531143731Sdougb isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto); 532143731Sdougb isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg); 533143731Sdougb 534143731Sdougb if (key->key_flags & DNS_KEYFLAG_EXTENDED) { 535143731Sdougb if (isc_buffer_availablelength(target) < 2) 536143731Sdougb return (ISC_R_NOSPACE); 537143731Sdougb isc_buffer_putuint16(target, 538143731Sdougb (isc_uint16_t)((key->key_flags >> 16) 539143731Sdougb & 0xffff)); 540143731Sdougb } 541143731Sdougb 542193149Sdougb if (key->keydata.generic == NULL) /*%< NULL KEY */ 543143731Sdougb return (ISC_R_SUCCESS); 544143731Sdougb 545143731Sdougb return (key->func->todns(key, target)); 546143731Sdougb} 547143731Sdougb 548143731Sdougbisc_result_t 549143731Sdougbdst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, 550143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 551143731Sdougb{ 552143731Sdougb isc_uint8_t alg, proto; 553143731Sdougb isc_uint32_t flags, extflags; 554143731Sdougb dst_key_t *key = NULL; 555143731Sdougb dns_keytag_t id; 556143731Sdougb isc_region_t r; 557143731Sdougb isc_result_t result; 558143731Sdougb 559143731Sdougb REQUIRE(dst_initialized); 560143731Sdougb 561143731Sdougb isc_buffer_remainingregion(source, &r); 562143731Sdougb 563143731Sdougb if (isc_buffer_remaininglength(source) < 4) 564143731Sdougb return (DST_R_INVALIDPUBLICKEY); 565143731Sdougb flags = isc_buffer_getuint16(source); 566143731Sdougb proto = isc_buffer_getuint8(source); 567143731Sdougb alg = isc_buffer_getuint8(source); 568143731Sdougb 569143731Sdougb id = dst_region_computeid(&r, alg); 570143731Sdougb 571143731Sdougb if (flags & DNS_KEYFLAG_EXTENDED) { 572143731Sdougb if (isc_buffer_remaininglength(source) < 2) 573143731Sdougb return (DST_R_INVALIDPUBLICKEY); 574143731Sdougb extflags = isc_buffer_getuint16(source); 575143731Sdougb flags |= (extflags << 16); 576143731Sdougb } 577143731Sdougb 578143731Sdougb result = frombuffer(name, alg, flags, proto, rdclass, source, 579143731Sdougb mctx, &key); 580143731Sdougb if (result != ISC_R_SUCCESS) 581143731Sdougb return (result); 582143731Sdougb key->key_id = id; 583143731Sdougb 584143731Sdougb *keyp = key; 585143731Sdougb return (ISC_R_SUCCESS); 586143731Sdougb} 587143731Sdougb 588143731Sdougbisc_result_t 589143731Sdougbdst_key_frombuffer(dns_name_t *name, unsigned int alg, 590143731Sdougb unsigned int flags, unsigned int protocol, 591143731Sdougb dns_rdataclass_t rdclass, 592143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 593143731Sdougb{ 594143731Sdougb dst_key_t *key = NULL; 595143731Sdougb isc_result_t result; 596143731Sdougb 597143731Sdougb REQUIRE(dst_initialized); 598143731Sdougb 599143731Sdougb result = frombuffer(name, alg, flags, protocol, rdclass, source, 600143731Sdougb mctx, &key); 601143731Sdougb if (result != ISC_R_SUCCESS) 602143731Sdougb return (result); 603143731Sdougb 604143731Sdougb result = computeid(key); 605143731Sdougb if (result != ISC_R_SUCCESS) { 606143731Sdougb dst_key_free(&key); 607143731Sdougb return (result); 608143731Sdougb } 609143731Sdougb 610143731Sdougb *keyp = key; 611143731Sdougb return (ISC_R_SUCCESS); 612143731Sdougb} 613143731Sdougb 614143731Sdougbisc_result_t 615143731Sdougbdst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) { 616143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 617143731Sdougb REQUIRE(VALID_KEY(key)); 618143731Sdougb REQUIRE(target != NULL); 619143731Sdougb 620143731Sdougb CHECKALG(key->key_alg); 621143731Sdougb 622143731Sdougb if (key->func->todns == NULL) 623143731Sdougb return (DST_R_UNSUPPORTEDALG); 624143731Sdougb 625143731Sdougb return (key->func->todns(key, target)); 626143731Sdougb} 627143731Sdougb 628143731Sdougbisc_result_t 629143731Sdougbdst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { 630143731Sdougb isc_lex_t *lex = NULL; 631143731Sdougb isc_result_t result = ISC_R_SUCCESS; 632143731Sdougb 633143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 634143731Sdougb REQUIRE(VALID_KEY(key)); 635143731Sdougb REQUIRE(!dst_key_isprivate(key)); 636143731Sdougb REQUIRE(buffer != NULL); 637143731Sdougb 638143731Sdougb if (key->func->parse == NULL) 639143731Sdougb RETERR(DST_R_UNSUPPORTEDALG); 640143731Sdougb 641143731Sdougb RETERR(isc_lex_create(key->mctx, 1500, &lex)); 642143731Sdougb RETERR(isc_lex_openbuffer(lex, buffer)); 643143731Sdougb RETERR(key->func->parse(key, lex)); 644143731Sdougb out: 645143731Sdougb if (lex != NULL) 646143731Sdougb isc_lex_destroy(&lex); 647143731Sdougb return (result); 648143731Sdougb} 649143731Sdougb 650193149Sdougbgss_ctx_id_t 651193149Sdougbdst_key_getgssctx(const dst_key_t *key) 652193149Sdougb{ 653193149Sdougb REQUIRE(key != NULL); 654193149Sdougb 655193149Sdougb return (key->keydata.gssctx); 656193149Sdougb} 657193149Sdougb 658143731Sdougbisc_result_t 659193149Sdougbdst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx, 660143731Sdougb dst_key_t **keyp) 661143731Sdougb{ 662143731Sdougb dst_key_t *key; 663143731Sdougb 664193149Sdougb REQUIRE(gssctx != NULL); 665143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 666143731Sdougb 667143731Sdougb key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 668143731Sdougb 0, dns_rdataclass_in, mctx); 669143731Sdougb if (key == NULL) 670143731Sdougb return (ISC_R_NOMEMORY); 671193149Sdougb 672193149Sdougb key->keydata.gssctx = gssctx; 673143731Sdougb *keyp = key; 674143731Sdougb return (ISC_R_SUCCESS); 675143731Sdougb} 676143731Sdougb 677143731Sdougbisc_result_t 678193149Sdougbdst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags, 679193149Sdougb unsigned int protocol, dns_rdataclass_t rdclass, 680193149Sdougb const char *engine, const char *label, const char *pin, 681193149Sdougb isc_mem_t *mctx, dst_key_t **keyp) 682193149Sdougb{ 683193149Sdougb dst_key_t *key; 684193149Sdougb isc_result_t result; 685193149Sdougb 686193149Sdougb REQUIRE(dst_initialized == ISC_TRUE); 687193149Sdougb REQUIRE(dns_name_isabsolute(name)); 688193149Sdougb REQUIRE(mctx != NULL); 689193149Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 690193149Sdougb REQUIRE(label != NULL); 691193149Sdougb 692193149Sdougb CHECKALG(alg); 693193149Sdougb 694193149Sdougb key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 695193149Sdougb if (key == NULL) 696193149Sdougb return (ISC_R_NOMEMORY); 697193149Sdougb 698193149Sdougb if (key->func->fromlabel == NULL) { 699193149Sdougb dst_key_free(&key); 700193149Sdougb return (DST_R_UNSUPPORTEDALG); 701193149Sdougb } 702193149Sdougb 703193149Sdougb result = key->func->fromlabel(key, engine, label, pin); 704193149Sdougb if (result != ISC_R_SUCCESS) { 705193149Sdougb dst_key_free(&key); 706193149Sdougb return (result); 707193149Sdougb } 708193149Sdougb 709193149Sdougb result = computeid(key); 710193149Sdougb if (result != ISC_R_SUCCESS) { 711193149Sdougb dst_key_free(&key); 712193149Sdougb return (result); 713193149Sdougb } 714193149Sdougb 715193149Sdougb *keyp = key; 716193149Sdougb return (ISC_R_SUCCESS); 717193149Sdougb} 718193149Sdougb 719193149Sdougbisc_result_t 720143731Sdougbdst_key_generate(dns_name_t *name, unsigned int alg, 721143731Sdougb unsigned int bits, unsigned int param, 722143731Sdougb unsigned int flags, unsigned int protocol, 723143731Sdougb dns_rdataclass_t rdclass, 724143731Sdougb isc_mem_t *mctx, dst_key_t **keyp) 725143731Sdougb{ 726143731Sdougb dst_key_t *key; 727143731Sdougb isc_result_t ret; 728143731Sdougb 729143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 730143731Sdougb REQUIRE(dns_name_isabsolute(name)); 731143731Sdougb REQUIRE(mctx != NULL); 732143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 733143731Sdougb 734143731Sdougb CHECKALG(alg); 735143731Sdougb 736143731Sdougb key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx); 737143731Sdougb if (key == NULL) 738143731Sdougb return (ISC_R_NOMEMORY); 739143731Sdougb 740170222Sdougb if (bits == 0) { /*%< NULL KEY */ 741143731Sdougb key->key_flags |= DNS_KEYTYPE_NOKEY; 742143731Sdougb *keyp = key; 743143731Sdougb return (ISC_R_SUCCESS); 744143731Sdougb } 745143731Sdougb 746143731Sdougb if (key->func->generate == NULL) { 747143731Sdougb dst_key_free(&key); 748143731Sdougb return (DST_R_UNSUPPORTEDALG); 749143731Sdougb } 750143731Sdougb 751143731Sdougb ret = key->func->generate(key, param); 752143731Sdougb if (ret != ISC_R_SUCCESS) { 753143731Sdougb dst_key_free(&key); 754143731Sdougb return (ret); 755143731Sdougb } 756143731Sdougb 757143731Sdougb ret = computeid(key); 758143731Sdougb if (ret != ISC_R_SUCCESS) { 759143731Sdougb dst_key_free(&key); 760143731Sdougb return (ret); 761143731Sdougb } 762143731Sdougb 763143731Sdougb *keyp = key; 764143731Sdougb return (ISC_R_SUCCESS); 765143731Sdougb} 766143731Sdougb 767143731Sdougbisc_boolean_t 768143731Sdougbdst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { 769143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 770143731Sdougb REQUIRE(VALID_KEY(key1)); 771143731Sdougb REQUIRE(VALID_KEY(key2)); 772143731Sdougb 773143731Sdougb if (key1 == key2) 774143731Sdougb return (ISC_TRUE); 775143731Sdougb if (key1 == NULL || key2 == NULL) 776143731Sdougb return (ISC_FALSE); 777143731Sdougb if (key1->key_alg == key2->key_alg && 778143731Sdougb key1->key_id == key2->key_id && 779143731Sdougb key1->func->compare != NULL && 780143731Sdougb key1->func->compare(key1, key2) == ISC_TRUE) 781143731Sdougb return (ISC_TRUE); 782143731Sdougb else 783143731Sdougb return (ISC_FALSE); 784143731Sdougb} 785143731Sdougb 786143731Sdougbisc_boolean_t 787143731Sdougbdst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { 788143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 789143731Sdougb REQUIRE(VALID_KEY(key1)); 790143731Sdougb REQUIRE(VALID_KEY(key2)); 791143731Sdougb 792143731Sdougb if (key1 == key2) 793143731Sdougb return (ISC_TRUE); 794143731Sdougb if (key1 == NULL || key2 == NULL) 795143731Sdougb return (ISC_FALSE); 796143731Sdougb if (key1->key_alg == key2->key_alg && 797143731Sdougb key1->func->paramcompare != NULL && 798143731Sdougb key1->func->paramcompare(key1, key2) == ISC_TRUE) 799143731Sdougb return (ISC_TRUE); 800143731Sdougb else 801143731Sdougb return (ISC_FALSE); 802143731Sdougb} 803143731Sdougb 804143731Sdougbvoid 805218384Sdougbdst_key_attach(dst_key_t *source, dst_key_t **target) { 806218384Sdougb 807218384Sdougb REQUIRE(dst_initialized == ISC_TRUE); 808218384Sdougb REQUIRE(target != NULL && *target == NULL); 809218384Sdougb REQUIRE(VALID_KEY(source)); 810218384Sdougb 811218384Sdougb isc_refcount_increment(&source->refs, NULL); 812218384Sdougb *target = source; 813218384Sdougb} 814218384Sdougb 815218384Sdougbvoid 816143731Sdougbdst_key_free(dst_key_t **keyp) { 817143731Sdougb isc_mem_t *mctx; 818143731Sdougb dst_key_t *key; 819218384Sdougb unsigned int refs; 820143731Sdougb 821143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 822143731Sdougb REQUIRE(keyp != NULL && VALID_KEY(*keyp)); 823143731Sdougb 824143731Sdougb key = *keyp; 825143731Sdougb mctx = key->mctx; 826143731Sdougb 827218384Sdougb isc_refcount_decrement(&key->refs, &refs); 828218384Sdougb if (refs != 0) 829218384Sdougb return; 830218384Sdougb 831218384Sdougb isc_refcount_destroy(&key->refs); 832193149Sdougb if (key->keydata.generic != NULL) { 833143731Sdougb INSIST(key->func->destroy != NULL); 834143731Sdougb key->func->destroy(key); 835143731Sdougb } 836193149Sdougb if (key->engine != NULL) 837193149Sdougb isc_mem_free(mctx, key->engine); 838193149Sdougb if (key->label != NULL) 839193149Sdougb isc_mem_free(mctx, key->label); 840143731Sdougb dns_name_free(key->key_name, mctx); 841143731Sdougb isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 842143731Sdougb memset(key, 0, sizeof(dst_key_t)); 843143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 844143731Sdougb *keyp = NULL; 845143731Sdougb} 846143731Sdougb 847143731Sdougbisc_boolean_t 848143731Sdougbdst_key_isprivate(const dst_key_t *key) { 849143731Sdougb REQUIRE(VALID_KEY(key)); 850143731Sdougb INSIST(key->func->isprivate != NULL); 851143731Sdougb return (key->func->isprivate(key)); 852143731Sdougb} 853143731Sdougb 854143731Sdougbisc_result_t 855143731Sdougbdst_key_buildfilename(const dst_key_t *key, int type, 856143731Sdougb const char *directory, isc_buffer_t *out) { 857143731Sdougb 858143731Sdougb REQUIRE(VALID_KEY(key)); 859143731Sdougb REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC || 860143731Sdougb type == 0); 861143731Sdougb 862143731Sdougb return (buildfilename(key->key_name, key->key_id, key->key_alg, 863143731Sdougb type, directory, out)); 864143731Sdougb} 865143731Sdougb 866143731Sdougbisc_result_t 867143731Sdougbdst_key_sigsize(const dst_key_t *key, unsigned int *n) { 868143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 869143731Sdougb REQUIRE(VALID_KEY(key)); 870143731Sdougb REQUIRE(n != NULL); 871143731Sdougb 872143731Sdougb /* XXXVIX this switch statement is too sparse to gen a jump table. */ 873143731Sdougb switch (key->key_alg) { 874143731Sdougb case DST_ALG_RSAMD5: 875143731Sdougb case DST_ALG_RSASHA1: 876193149Sdougb case DST_ALG_NSEC3RSASHA1: 877204619Sdougb case DST_ALG_RSASHA256: 878204619Sdougb case DST_ALG_RSASHA512: 879143731Sdougb *n = (key->key_size + 7) / 8; 880143731Sdougb break; 881143731Sdougb case DST_ALG_DSA: 882193149Sdougb case DST_ALG_NSEC3DSA: 883143731Sdougb *n = DNS_SIG_DSASIGSIZE; 884143731Sdougb break; 885143731Sdougb case DST_ALG_HMACMD5: 886143731Sdougb *n = 16; 887143731Sdougb break; 888170222Sdougb case DST_ALG_HMACSHA1: 889170222Sdougb *n = ISC_SHA1_DIGESTLENGTH; 890170222Sdougb break; 891170222Sdougb case DST_ALG_HMACSHA224: 892170222Sdougb *n = ISC_SHA224_DIGESTLENGTH; 893170222Sdougb break; 894170222Sdougb case DST_ALG_HMACSHA256: 895170222Sdougb *n = ISC_SHA256_DIGESTLENGTH; 896170222Sdougb break; 897170222Sdougb case DST_ALG_HMACSHA384: 898170222Sdougb *n = ISC_SHA384_DIGESTLENGTH; 899170222Sdougb break; 900170222Sdougb case DST_ALG_HMACSHA512: 901170222Sdougb *n = ISC_SHA512_DIGESTLENGTH; 902170222Sdougb break; 903143731Sdougb case DST_ALG_GSSAPI: 904170222Sdougb *n = 128; /*%< XXX */ 905143731Sdougb break; 906143731Sdougb case DST_ALG_DH: 907143731Sdougb default: 908143731Sdougb return (DST_R_UNSUPPORTEDALG); 909143731Sdougb } 910143731Sdougb return (ISC_R_SUCCESS); 911143731Sdougb} 912143731Sdougb 913143731Sdougbisc_result_t 914143731Sdougbdst_key_secretsize(const dst_key_t *key, unsigned int *n) { 915143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 916143731Sdougb REQUIRE(VALID_KEY(key)); 917143731Sdougb REQUIRE(n != NULL); 918143731Sdougb 919143731Sdougb if (key->key_alg == DST_ALG_DH) 920143731Sdougb *n = (key->key_size + 7) / 8; 921143731Sdougb else 922143731Sdougb return (DST_R_UNSUPPORTEDALG); 923143731Sdougb return (ISC_R_SUCCESS); 924143731Sdougb} 925143731Sdougb 926143731Sdougb/*** 927143731Sdougb *** Static methods 928143731Sdougb ***/ 929143731Sdougb 930170222Sdougb/*% 931143731Sdougb * Allocates a key structure and fills in some of the fields. 932143731Sdougb */ 933143731Sdougbstatic dst_key_t * 934143731Sdougbget_key_struct(dns_name_t *name, unsigned int alg, 935143731Sdougb unsigned int flags, unsigned int protocol, 936143731Sdougb unsigned int bits, dns_rdataclass_t rdclass, 937143731Sdougb isc_mem_t *mctx) 938143731Sdougb{ 939143731Sdougb dst_key_t *key; 940143731Sdougb isc_result_t result; 941143731Sdougb 942143731Sdougb key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); 943143731Sdougb if (key == NULL) 944143731Sdougb return (NULL); 945143731Sdougb 946143731Sdougb memset(key, 0, sizeof(dst_key_t)); 947143731Sdougb key->magic = KEY_MAGIC; 948143731Sdougb 949218384Sdougb result = isc_refcount_init(&key->refs, 1); 950218384Sdougb if (result != ISC_R_SUCCESS) { 951218384Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 952218384Sdougb return (NULL); 953218384Sdougb } 954218384Sdougb 955143731Sdougb key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); 956143731Sdougb if (key->key_name == NULL) { 957218384Sdougb isc_refcount_destroy(&key->refs); 958143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 959143731Sdougb return (NULL); 960143731Sdougb } 961143731Sdougb dns_name_init(key->key_name, NULL); 962143731Sdougb result = dns_name_dup(name, mctx, key->key_name); 963143731Sdougb if (result != ISC_R_SUCCESS) { 964218384Sdougb isc_refcount_destroy(&key->refs); 965143731Sdougb isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 966143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 967143731Sdougb return (NULL); 968143731Sdougb } 969143731Sdougb key->key_alg = alg; 970143731Sdougb key->key_flags = flags; 971143731Sdougb key->key_proto = protocol; 972143731Sdougb key->mctx = mctx; 973193149Sdougb key->keydata.generic = NULL; 974143731Sdougb key->key_size = bits; 975143731Sdougb key->key_class = rdclass; 976143731Sdougb key->func = dst_t_func[alg]; 977143731Sdougb return (key); 978143731Sdougb} 979143731Sdougb 980170222Sdougb/*% 981143731Sdougb * Reads a public key from disk 982143731Sdougb */ 983170222Sdougbisc_result_t 984170222Sdougbdst_key_read_public(const char *filename, int type, 985170222Sdougb isc_mem_t *mctx, dst_key_t **keyp) 986143731Sdougb{ 987143731Sdougb u_char rdatabuf[DST_KEY_MAXSIZE]; 988143731Sdougb isc_buffer_t b; 989143731Sdougb dns_fixedname_t name; 990143731Sdougb isc_lex_t *lex = NULL; 991143731Sdougb isc_token_t token; 992143731Sdougb isc_result_t ret; 993143731Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 994143731Sdougb unsigned int opt = ISC_LEXOPT_DNSMULTILINE; 995143731Sdougb dns_rdataclass_t rdclass = dns_rdataclass_in; 996143731Sdougb isc_lexspecials_t specials; 997143731Sdougb isc_uint32_t ttl; 998143731Sdougb isc_result_t result; 999143731Sdougb dns_rdatatype_t keytype; 1000143731Sdougb 1001143731Sdougb /* 1002143731Sdougb * Open the file and read its formatted contents 1003143731Sdougb * File format: 1004170222Sdougb * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key> 1005143731Sdougb */ 1006143731Sdougb 1007143731Sdougb /* 1500 should be large enough for any key */ 1008143731Sdougb ret = isc_lex_create(mctx, 1500, &lex); 1009143731Sdougb if (ret != ISC_R_SUCCESS) 1010143731Sdougb goto cleanup; 1011143731Sdougb 1012143731Sdougb memset(specials, 0, sizeof(specials)); 1013143731Sdougb specials['('] = 1; 1014143731Sdougb specials[')'] = 1; 1015143731Sdougb specials['"'] = 1; 1016143731Sdougb isc_lex_setspecials(lex, specials); 1017143731Sdougb isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); 1018143731Sdougb 1019170222Sdougb ret = isc_lex_openfile(lex, filename); 1020143731Sdougb if (ret != ISC_R_SUCCESS) 1021143731Sdougb goto cleanup; 1022143731Sdougb 1023143731Sdougb#define NEXTTOKEN(lex, opt, token) { \ 1024143731Sdougb ret = isc_lex_gettoken(lex, opt, token); \ 1025143731Sdougb if (ret != ISC_R_SUCCESS) \ 1026143731Sdougb goto cleanup; \ 1027143731Sdougb } 1028143731Sdougb 1029143731Sdougb#define BADTOKEN() { \ 1030143731Sdougb ret = ISC_R_UNEXPECTEDTOKEN; \ 1031143731Sdougb goto cleanup; \ 1032143731Sdougb } 1033143731Sdougb 1034143731Sdougb /* Read the domain name */ 1035143731Sdougb NEXTTOKEN(lex, opt, &token); 1036143731Sdougb if (token.type != isc_tokentype_string) 1037143731Sdougb BADTOKEN(); 1038193149Sdougb 1039193149Sdougb /* 1040193149Sdougb * We don't support "@" in .key files. 1041193149Sdougb */ 1042193149Sdougb if (!strcmp(DST_AS_STR(token), "@")) 1043193149Sdougb BADTOKEN(); 1044193149Sdougb 1045143731Sdougb dns_fixedname_init(&name); 1046143731Sdougb isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); 1047143731Sdougb isc_buffer_add(&b, strlen(DST_AS_STR(token))); 1048143731Sdougb ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, 1049143731Sdougb ISC_FALSE, NULL); 1050143731Sdougb if (ret != ISC_R_SUCCESS) 1051143731Sdougb goto cleanup; 1052143731Sdougb 1053143731Sdougb /* Read the next word: either TTL, class, or 'KEY' */ 1054143731Sdougb NEXTTOKEN(lex, opt, &token); 1055143731Sdougb 1056204619Sdougb if (token.type != isc_tokentype_string) 1057204619Sdougb BADTOKEN(); 1058204619Sdougb 1059143731Sdougb /* If it's a TTL, read the next one */ 1060143731Sdougb result = dns_ttl_fromtext(&token.value.as_textregion, &ttl); 1061143731Sdougb if (result == ISC_R_SUCCESS) 1062143731Sdougb NEXTTOKEN(lex, opt, &token); 1063143731Sdougb 1064143731Sdougb if (token.type != isc_tokentype_string) 1065143731Sdougb BADTOKEN(); 1066143731Sdougb 1067143731Sdougb ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion); 1068143731Sdougb if (ret == ISC_R_SUCCESS) 1069143731Sdougb NEXTTOKEN(lex, opt, &token); 1070143731Sdougb 1071143731Sdougb if (token.type != isc_tokentype_string) 1072143731Sdougb BADTOKEN(); 1073143731Sdougb 1074143731Sdougb if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) 1075143731Sdougb keytype = dns_rdatatype_dnskey; 1076143731Sdougb else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) 1077170222Sdougb keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */ 1078143731Sdougb else 1079143731Sdougb BADTOKEN(); 1080143731Sdougb 1081143731Sdougb if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) || 1082143731Sdougb ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) { 1083143731Sdougb ret = DST_R_BADKEYTYPE; 1084143731Sdougb goto cleanup; 1085143731Sdougb } 1086143731Sdougb 1087143731Sdougb isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); 1088143731Sdougb ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, 1089143731Sdougb ISC_FALSE, mctx, &b, NULL); 1090143731Sdougb if (ret != ISC_R_SUCCESS) 1091143731Sdougb goto cleanup; 1092143731Sdougb 1093143731Sdougb ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx, 1094143731Sdougb keyp); 1095143731Sdougb if (ret != ISC_R_SUCCESS) 1096143731Sdougb goto cleanup; 1097143731Sdougb 1098143731Sdougb cleanup: 1099143731Sdougb if (lex != NULL) 1100143731Sdougb isc_lex_destroy(&lex); 1101143731Sdougb return (ret); 1102143731Sdougb} 1103143731Sdougb 1104143731Sdougbstatic isc_boolean_t 1105143731Sdougbissymmetric(const dst_key_t *key) { 1106143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1107143731Sdougb REQUIRE(VALID_KEY(key)); 1108143731Sdougb 1109143731Sdougb /* XXXVIX this switch statement is too sparse to gen a jump table. */ 1110143731Sdougb switch (key->key_alg) { 1111143731Sdougb case DST_ALG_RSAMD5: 1112143731Sdougb case DST_ALG_RSASHA1: 1113193149Sdougb case DST_ALG_NSEC3RSASHA1: 1114204619Sdougb case DST_ALG_RSASHA256: 1115204619Sdougb case DST_ALG_RSASHA512: 1116143731Sdougb case DST_ALG_DSA: 1117193149Sdougb case DST_ALG_NSEC3DSA: 1118143731Sdougb case DST_ALG_DH: 1119143731Sdougb return (ISC_FALSE); 1120143731Sdougb case DST_ALG_HMACMD5: 1121143731Sdougb case DST_ALG_GSSAPI: 1122143731Sdougb return (ISC_TRUE); 1123143731Sdougb default: 1124143731Sdougb return (ISC_FALSE); 1125143731Sdougb } 1126143731Sdougb} 1127143731Sdougb 1128170222Sdougb/*% 1129143731Sdougb * Writes a public key to disk in DNS format. 1130143731Sdougb */ 1131143731Sdougbstatic isc_result_t 1132143731Sdougbwrite_public_key(const dst_key_t *key, int type, const char *directory) { 1133143731Sdougb FILE *fp; 1134143731Sdougb isc_buffer_t keyb, textb, fileb, classb; 1135143731Sdougb isc_region_t r; 1136143731Sdougb char filename[ISC_DIR_NAMEMAX]; 1137143731Sdougb unsigned char key_array[DST_KEY_MAXSIZE]; 1138143731Sdougb char text_array[DST_KEY_MAXTEXTSIZE]; 1139143731Sdougb char class_array[10]; 1140143731Sdougb isc_result_t ret; 1141143731Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 1142143731Sdougb isc_fsaccess_t access; 1143143731Sdougb 1144143731Sdougb REQUIRE(VALID_KEY(key)); 1145143731Sdougb 1146143731Sdougb isc_buffer_init(&keyb, key_array, sizeof(key_array)); 1147143731Sdougb isc_buffer_init(&textb, text_array, sizeof(text_array)); 1148143731Sdougb isc_buffer_init(&classb, class_array, sizeof(class_array)); 1149143731Sdougb 1150143731Sdougb ret = dst_key_todns(key, &keyb); 1151143731Sdougb if (ret != ISC_R_SUCCESS) 1152143731Sdougb return (ret); 1153143731Sdougb 1154143731Sdougb isc_buffer_usedregion(&keyb, &r); 1155143731Sdougb dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r); 1156143731Sdougb 1157143731Sdougb ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb); 1158143731Sdougb if (ret != ISC_R_SUCCESS) 1159143731Sdougb return (DST_R_INVALIDPUBLICKEY); 1160143731Sdougb 1161143731Sdougb ret = dns_rdataclass_totext(key->key_class, &classb); 1162143731Sdougb if (ret != ISC_R_SUCCESS) 1163143731Sdougb return (DST_R_INVALIDPUBLICKEY); 1164143731Sdougb 1165143731Sdougb /* 1166143731Sdougb * Make the filename. 1167143731Sdougb */ 1168143731Sdougb isc_buffer_init(&fileb, filename, sizeof(filename)); 1169143731Sdougb ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb); 1170143731Sdougb if (ret != ISC_R_SUCCESS) 1171143731Sdougb return (ret); 1172143731Sdougb 1173143731Sdougb /* 1174143731Sdougb * Create public key file. 1175143731Sdougb */ 1176143731Sdougb if ((fp = fopen(filename, "w")) == NULL) 1177143731Sdougb return (DST_R_WRITEERROR); 1178143731Sdougb 1179143731Sdougb if (issymmetric(key)) { 1180143731Sdougb access = 0; 1181143731Sdougb isc_fsaccess_add(ISC_FSACCESS_OWNER, 1182143731Sdougb ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, 1183143731Sdougb &access); 1184143731Sdougb (void)isc_fsaccess_set(filename, access); 1185143731Sdougb } 1186143731Sdougb 1187143731Sdougb ret = dns_name_print(key->key_name, fp); 1188165071Sdougb if (ret != ISC_R_SUCCESS) { 1189165071Sdougb fclose(fp); 1190143731Sdougb return (ret); 1191165071Sdougb } 1192143731Sdougb 1193143731Sdougb fprintf(fp, " "); 1194143731Sdougb 1195143731Sdougb isc_buffer_usedregion(&classb, &r); 1196204619Sdougb isc_util_fwrite(r.base, 1, r.length, fp); 1197143731Sdougb 1198143731Sdougb if ((type & DST_TYPE_KEY) != 0) 1199143731Sdougb fprintf(fp, " KEY "); 1200143731Sdougb else 1201143731Sdougb fprintf(fp, " DNSKEY "); 1202143731Sdougb 1203143731Sdougb isc_buffer_usedregion(&textb, &r); 1204204619Sdougb isc_util_fwrite(r.base, 1, r.length, fp); 1205143731Sdougb 1206143731Sdougb fputc('\n', fp); 1207193149Sdougb fflush(fp); 1208193149Sdougb if (ferror(fp)) 1209193149Sdougb ret = DST_R_WRITEERROR; 1210143731Sdougb fclose(fp); 1211143731Sdougb 1212193149Sdougb return (ret); 1213143731Sdougb} 1214143731Sdougb 1215143731Sdougbstatic isc_result_t 1216143731Sdougbbuildfilename(dns_name_t *name, dns_keytag_t id, 1217143731Sdougb unsigned int alg, unsigned int type, 1218143731Sdougb const char *directory, isc_buffer_t *out) 1219143731Sdougb{ 1220143731Sdougb const char *suffix = ""; 1221143731Sdougb unsigned int len; 1222143731Sdougb isc_result_t result; 1223143731Sdougb 1224143731Sdougb REQUIRE(out != NULL); 1225143731Sdougb if ((type & DST_TYPE_PRIVATE) != 0) 1226143731Sdougb suffix = ".private"; 1227143731Sdougb else if (type == DST_TYPE_PUBLIC) 1228143731Sdougb suffix = ".key"; 1229143731Sdougb if (directory != NULL) { 1230143731Sdougb if (isc_buffer_availablelength(out) < strlen(directory)) 1231143731Sdougb return (ISC_R_NOSPACE); 1232143731Sdougb isc_buffer_putstr(out, directory); 1233143731Sdougb if (strlen(directory) > 0U && 1234143731Sdougb directory[strlen(directory) - 1] != '/') 1235143731Sdougb isc_buffer_putstr(out, "/"); 1236143731Sdougb } 1237143731Sdougb if (isc_buffer_availablelength(out) < 1) 1238143731Sdougb return (ISC_R_NOSPACE); 1239143731Sdougb isc_buffer_putstr(out, "K"); 1240143731Sdougb result = dns_name_tofilenametext(name, ISC_FALSE, out); 1241143731Sdougb if (result != ISC_R_SUCCESS) 1242143731Sdougb return (result); 1243143731Sdougb len = 1 + 3 + 1 + 5 + strlen(suffix) + 1; 1244143731Sdougb if (isc_buffer_availablelength(out) < len) 1245143731Sdougb return (ISC_R_NOSPACE); 1246193149Sdougb sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, 1247193149Sdougb suffix); 1248143731Sdougb isc_buffer_add(out, len); 1249193149Sdougb 1250143731Sdougb return (ISC_R_SUCCESS); 1251143731Sdougb} 1252143731Sdougb 1253143731Sdougbstatic isc_result_t 1254143731Sdougbcomputeid(dst_key_t *key) { 1255143731Sdougb isc_buffer_t dnsbuf; 1256143731Sdougb unsigned char dns_array[DST_KEY_MAXSIZE]; 1257143731Sdougb isc_region_t r; 1258143731Sdougb isc_result_t ret; 1259143731Sdougb 1260143731Sdougb isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array)); 1261143731Sdougb ret = dst_key_todns(key, &dnsbuf); 1262143731Sdougb if (ret != ISC_R_SUCCESS) 1263143731Sdougb return (ret); 1264143731Sdougb 1265143731Sdougb isc_buffer_usedregion(&dnsbuf, &r); 1266143731Sdougb key->key_id = dst_region_computeid(&r, key->key_alg); 1267143731Sdougb return (ISC_R_SUCCESS); 1268143731Sdougb} 1269143731Sdougb 1270143731Sdougbstatic isc_result_t 1271143731Sdougbfrombuffer(dns_name_t *name, unsigned int alg, unsigned int flags, 1272143731Sdougb unsigned int protocol, dns_rdataclass_t rdclass, 1273143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 1274143731Sdougb{ 1275143731Sdougb dst_key_t *key; 1276143731Sdougb isc_result_t ret; 1277143731Sdougb 1278143731Sdougb REQUIRE(dns_name_isabsolute(name)); 1279143731Sdougb REQUIRE(source != NULL); 1280143731Sdougb REQUIRE(mctx != NULL); 1281143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 1282143731Sdougb 1283143731Sdougb key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 1284143731Sdougb if (key == NULL) 1285143731Sdougb return (ISC_R_NOMEMORY); 1286143731Sdougb 1287143731Sdougb if (isc_buffer_remaininglength(source) > 0) { 1288143731Sdougb ret = algorithm_status(alg); 1289143731Sdougb if (ret != ISC_R_SUCCESS) { 1290143731Sdougb dst_key_free(&key); 1291143731Sdougb return (ret); 1292143731Sdougb } 1293143731Sdougb if (key->func->fromdns == NULL) { 1294143731Sdougb dst_key_free(&key); 1295143731Sdougb return (DST_R_UNSUPPORTEDALG); 1296143731Sdougb } 1297143731Sdougb 1298143731Sdougb ret = key->func->fromdns(key, source); 1299143731Sdougb if (ret != ISC_R_SUCCESS) { 1300143731Sdougb dst_key_free(&key); 1301143731Sdougb return (ret); 1302143731Sdougb } 1303143731Sdougb } 1304143731Sdougb 1305143731Sdougb *keyp = key; 1306143731Sdougb return (ISC_R_SUCCESS); 1307143731Sdougb} 1308143731Sdougb 1309143731Sdougbstatic isc_result_t 1310143731Sdougbalgorithm_status(unsigned int alg) { 1311143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1312143731Sdougb 1313143731Sdougb if (dst_algorithm_supported(alg)) 1314143731Sdougb return (ISC_R_SUCCESS); 1315143731Sdougb#ifndef OPENSSL 1316143731Sdougb if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || 1317143731Sdougb alg == DST_ALG_DSA || alg == DST_ALG_DH || 1318193149Sdougb alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA || 1319204619Sdougb alg == DST_ALG_NSEC3RSASHA1 || 1320204619Sdougb alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512) 1321143731Sdougb return (DST_R_NOCRYPTO); 1322143731Sdougb#endif 1323143731Sdougb return (DST_R_UNSUPPORTEDALG); 1324143731Sdougb} 1325143731Sdougb 1326143731Sdougbstatic isc_result_t 1327143731Sdougbaddsuffix(char *filename, unsigned int len, const char *ofilename, 1328143731Sdougb const char *suffix) 1329143731Sdougb{ 1330143731Sdougb int olen = strlen(ofilename); 1331143731Sdougb int n; 1332143731Sdougb 1333143731Sdougb if (olen > 1 && ofilename[olen - 1] == '.') 1334143731Sdougb olen -= 1; 1335143731Sdougb else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) 1336143731Sdougb olen -= 8; 1337143731Sdougb else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) 1338143731Sdougb olen -= 4; 1339143731Sdougb 1340143731Sdougb n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); 1341143731Sdougb if (n < 0) 1342204619Sdougb return (ISC_R_FAILURE); 1343204619Sdougb if ((unsigned int)n >= len) 1344143731Sdougb return (ISC_R_NOSPACE); 1345143731Sdougb return (ISC_R_SUCCESS); 1346143731Sdougb} 1347143731Sdougb 1348143731Sdougbisc_result_t 1349143731Sdougbdst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { 1350143731Sdougb unsigned int flags = dst_entropy_flags; 1351204619Sdougb 1352204619Sdougb if (len == 0) 1353204619Sdougb return (ISC_R_SUCCESS); 1354143731Sdougb if (pseudo) 1355143731Sdougb flags &= ~ISC_ENTROPY_GOODONLY; 1356143731Sdougb return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); 1357143731Sdougb} 1358193149Sdougb 1359193149Sdougbunsigned int 1360193149Sdougbdst__entropy_status(void) { 1361204619Sdougb#ifdef GSSAPI 1362204619Sdougb unsigned int flags = dst_entropy_flags; 1363204619Sdougb isc_result_t ret; 1364204619Sdougb unsigned char buf[32]; 1365204619Sdougb static isc_boolean_t first = ISC_TRUE; 1366204619Sdougb 1367204619Sdougb if (first) { 1368204619Sdougb /* Someone believes RAND_status() initializes the PRNG */ 1369204619Sdougb flags &= ~ISC_ENTROPY_GOODONLY; 1370204619Sdougb ret = isc_entropy_getdata(dst_entropy_pool, buf, 1371204619Sdougb sizeof(buf), NULL, flags); 1372204619Sdougb INSIST(ret == ISC_R_SUCCESS); 1373204619Sdougb isc_entropy_putdata(dst_entropy_pool, buf, 1374204619Sdougb sizeof(buf), 2 * sizeof(buf)); 1375204619Sdougb first = ISC_FALSE; 1376204619Sdougb } 1377204619Sdougb#endif 1378193149Sdougb return (isc_entropy_status(dst_entropy_pool)); 1379193149Sdougb} 1380