dst_api.c revision 165071
1143731Sdougb/* 2165071Sdougb * Portions Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC") 3143731Sdougb * Portions Copyright (C) 1999-2003 Internet Software Consortium. 4143731Sdougb * Portions Copyright (C) 1995-2000 by Network Associates, Inc. 5143731Sdougb * 6143731Sdougb * Permission to use, copy, modify, and distribute this software for any 7143731Sdougb * purpose with or without fee is hereby granted, provided that the above 8143731Sdougb * copyright notice and this permission notice appear in all copies. 9143731Sdougb * 10143731Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS 11143731Sdougb * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12143731Sdougb * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 13143731Sdougb * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14143731Sdougb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15143731Sdougb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 16143731Sdougb * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17143731Sdougb */ 18143731Sdougb 19143731Sdougb/* 20143731Sdougb * Principal Author: Brian Wellington 21165071Sdougb * $Id: dst_api.c,v 1.1.4.3 2006/01/04 23:50:20 marka Exp $ 22143731Sdougb */ 23143731Sdougb 24143731Sdougb#include <config.h> 25143731Sdougb 26143731Sdougb#include <stdlib.h> 27143731Sdougb 28143731Sdougb#include <isc/buffer.h> 29143731Sdougb#include <isc/dir.h> 30143731Sdougb#include <isc/entropy.h> 31143731Sdougb#include <isc/fsaccess.h> 32143731Sdougb#include <isc/lex.h> 33143731Sdougb#include <isc/mem.h> 34143731Sdougb#include <isc/once.h> 35143731Sdougb#include <isc/print.h> 36143731Sdougb#include <isc/random.h> 37143731Sdougb#include <isc/string.h> 38143731Sdougb#include <isc/time.h> 39143731Sdougb#include <isc/util.h> 40143731Sdougb 41143731Sdougb#include <dns/fixedname.h> 42143731Sdougb#include <dns/keyvalues.h> 43143731Sdougb#include <dns/name.h> 44143731Sdougb#include <dns/rdata.h> 45143731Sdougb#include <dns/rdataclass.h> 46143731Sdougb#include <dns/ttl.h> 47143731Sdougb#include <dns/types.h> 48143731Sdougb 49143731Sdougb#include <dst/result.h> 50143731Sdougb 51143731Sdougb#include "dst_internal.h" 52143731Sdougb 53143731Sdougb#define DST_AS_STR(t) ((t).value.as_textregion.base) 54143731Sdougb 55143731Sdougbstatic dst_func_t *dst_t_func[DST_MAX_ALGS]; 56143731Sdougbstatic isc_entropy_t *dst_entropy_pool = NULL; 57143731Sdougbstatic unsigned int dst_entropy_flags = 0; 58143731Sdougbstatic isc_boolean_t dst_initialized = ISC_FALSE; 59143731Sdougb 60143731Sdougbisc_mem_t *dst__memory_pool = NULL; 61143731Sdougb 62143731Sdougb/* 63143731Sdougb * Static functions. 64143731Sdougb */ 65143731Sdougbstatic dst_key_t * get_key_struct(dns_name_t *name, 66143731Sdougb unsigned int alg, 67143731Sdougb unsigned int flags, 68143731Sdougb unsigned int protocol, 69143731Sdougb unsigned int bits, 70143731Sdougb dns_rdataclass_t rdclass, 71143731Sdougb isc_mem_t *mctx); 72143731Sdougbstatic isc_result_t read_public_key(const char *filename, 73143731Sdougb int type, 74143731Sdougb isc_mem_t *mctx, 75143731Sdougb dst_key_t **keyp); 76143731Sdougbstatic isc_result_t write_public_key(const dst_key_t *key, int type, 77143731Sdougb const char *directory); 78143731Sdougbstatic isc_result_t buildfilename(dns_name_t *name, 79143731Sdougb dns_keytag_t id, 80143731Sdougb unsigned int alg, 81143731Sdougb unsigned int type, 82143731Sdougb const char *directory, 83143731Sdougb isc_buffer_t *out); 84143731Sdougbstatic isc_result_t computeid(dst_key_t *key); 85143731Sdougbstatic isc_result_t frombuffer(dns_name_t *name, 86143731Sdougb unsigned int alg, 87143731Sdougb unsigned int flags, 88143731Sdougb unsigned int protocol, 89143731Sdougb dns_rdataclass_t rdclass, 90143731Sdougb isc_buffer_t *source, 91143731Sdougb isc_mem_t *mctx, 92143731Sdougb dst_key_t **keyp); 93143731Sdougb 94143731Sdougbstatic isc_result_t algorithm_status(unsigned int alg); 95143731Sdougb 96143731Sdougbstatic isc_result_t addsuffix(char *filename, unsigned int len, 97143731Sdougb const char *ofilename, const char *suffix); 98143731Sdougb 99143731Sdougb#define RETERR(x) \ 100143731Sdougb do { \ 101143731Sdougb result = (x); \ 102143731Sdougb if (result != ISC_R_SUCCESS) \ 103143731Sdougb goto out; \ 104143731Sdougb } while (0) 105143731Sdougb 106143731Sdougb#define CHECKALG(alg) \ 107143731Sdougb do { \ 108143731Sdougb isc_result_t _r; \ 109143731Sdougb _r = algorithm_status(alg); \ 110143731Sdougb if (_r != ISC_R_SUCCESS) \ 111143731Sdougb return (_r); \ 112143731Sdougb } while (0); \ 113143731Sdougb 114143731Sdougbisc_result_t 115143731Sdougbdst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) { 116143731Sdougb isc_result_t result; 117143731Sdougb 118143731Sdougb REQUIRE(mctx != NULL && ectx != NULL); 119143731Sdougb REQUIRE(dst_initialized == ISC_FALSE); 120143731Sdougb 121143731Sdougb dst__memory_pool = NULL; 122143731Sdougb 123143731Sdougb#ifdef OPENSSL 124143731Sdougb UNUSED(mctx); 125143731Sdougb /* 126143731Sdougb * When using --with-openssl, there seems to be no good way of not 127143731Sdougb * leaking memory due to the openssl error handling mechanism. 128143731Sdougb * Avoid assertions by using a local memory context and not checking 129143731Sdougb * for leaks on exit. 130143731Sdougb */ 131143731Sdougb result = isc_mem_create(0, 0, &dst__memory_pool); 132143731Sdougb if (result != ISC_R_SUCCESS) 133143731Sdougb return (result); 134143731Sdougb isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE); 135143731Sdougb#else 136143731Sdougb isc_mem_attach(mctx, &dst__memory_pool); 137143731Sdougb#endif 138143731Sdougb isc_entropy_attach(ectx, &dst_entropy_pool); 139143731Sdougb dst_entropy_flags = eflags; 140143731Sdougb 141143731Sdougb dst_result_register(); 142143731Sdougb 143143731Sdougb memset(dst_t_func, 0, sizeof(dst_t_func)); 144143731Sdougb RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5])); 145143731Sdougb#ifdef OPENSSL 146143731Sdougb RETERR(dst__openssl_init()); 147143731Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5])); 148143731Sdougb RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1])); 149143731Sdougb#ifdef HAVE_OPENSSL_DSA 150143731Sdougb RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA])); 151143731Sdougb#endif 152143731Sdougb RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH])); 153143731Sdougb#endif /* OPENSSL */ 154143731Sdougb#ifdef GSSAPI 155143731Sdougb RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI])); 156143731Sdougb#endif 157143731Sdougb dst_initialized = ISC_TRUE; 158143731Sdougb return (ISC_R_SUCCESS); 159143731Sdougb 160143731Sdougb out: 161143731Sdougb dst_lib_destroy(); 162143731Sdougb return (result); 163143731Sdougb} 164143731Sdougb 165143731Sdougbvoid 166143731Sdougbdst_lib_destroy(void) { 167143731Sdougb int i; 168143731Sdougb RUNTIME_CHECK(dst_initialized == ISC_TRUE); 169143731Sdougb dst_initialized = ISC_FALSE; 170143731Sdougb 171143731Sdougb for (i = 0; i < DST_MAX_ALGS; i++) 172143731Sdougb if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL) 173143731Sdougb dst_t_func[i]->cleanup(); 174143731Sdougb#ifdef OPENSSL 175143731Sdougb dst__openssl_destroy(); 176143731Sdougb#endif 177143731Sdougb if (dst__memory_pool != NULL) 178143731Sdougb isc_mem_detach(&dst__memory_pool); 179143731Sdougb if (dst_entropy_pool != NULL) 180143731Sdougb isc_entropy_detach(&dst_entropy_pool); 181143731Sdougb 182143731Sdougb} 183143731Sdougb 184143731Sdougbisc_boolean_t 185143731Sdougbdst_algorithm_supported(unsigned int alg) { 186143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 187143731Sdougb 188143731Sdougb if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) 189143731Sdougb return (ISC_FALSE); 190143731Sdougb return (ISC_TRUE); 191143731Sdougb} 192143731Sdougb 193143731Sdougbisc_result_t 194143731Sdougbdst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) { 195143731Sdougb dst_context_t *dctx; 196143731Sdougb isc_result_t result; 197143731Sdougb 198143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 199143731Sdougb REQUIRE(VALID_KEY(key)); 200143731Sdougb REQUIRE(mctx != NULL); 201143731Sdougb REQUIRE(dctxp != NULL && *dctxp == NULL); 202143731Sdougb 203143731Sdougb if (key->func->createctx == NULL) 204143731Sdougb return (DST_R_UNSUPPORTEDALG); 205143731Sdougb if (key->opaque == NULL) 206143731Sdougb return (DST_R_NULLKEY); 207143731Sdougb 208143731Sdougb dctx = isc_mem_get(mctx, sizeof(dst_context_t)); 209143731Sdougb if (dctx == NULL) 210143731Sdougb return (ISC_R_NOMEMORY); 211143731Sdougb dctx->key = key; 212143731Sdougb dctx->mctx = mctx; 213143731Sdougb result = key->func->createctx(key, dctx); 214143731Sdougb if (result != ISC_R_SUCCESS) { 215143731Sdougb isc_mem_put(mctx, dctx, sizeof(dst_context_t)); 216143731Sdougb return (result); 217143731Sdougb } 218143731Sdougb dctx->magic = CTX_MAGIC; 219143731Sdougb *dctxp = dctx; 220143731Sdougb return (ISC_R_SUCCESS); 221143731Sdougb} 222143731Sdougb 223143731Sdougbvoid 224143731Sdougbdst_context_destroy(dst_context_t **dctxp) { 225143731Sdougb dst_context_t *dctx; 226143731Sdougb 227143731Sdougb REQUIRE(dctxp != NULL && VALID_CTX(*dctxp)); 228143731Sdougb 229143731Sdougb dctx = *dctxp; 230143731Sdougb INSIST(dctx->key->func->destroyctx != NULL); 231143731Sdougb dctx->key->func->destroyctx(dctx); 232143731Sdougb dctx->magic = 0; 233143731Sdougb isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t)); 234143731Sdougb *dctxp = NULL; 235143731Sdougb} 236143731Sdougb 237143731Sdougbisc_result_t 238143731Sdougbdst_context_adddata(dst_context_t *dctx, const isc_region_t *data) { 239143731Sdougb REQUIRE(VALID_CTX(dctx)); 240143731Sdougb REQUIRE(data != NULL); 241143731Sdougb INSIST(dctx->key->func->adddata != NULL); 242143731Sdougb 243143731Sdougb return (dctx->key->func->adddata(dctx, data)); 244143731Sdougb} 245143731Sdougb 246143731Sdougbisc_result_t 247143731Sdougbdst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) { 248143731Sdougb dst_key_t *key; 249143731Sdougb 250143731Sdougb REQUIRE(VALID_CTX(dctx)); 251143731Sdougb REQUIRE(sig != NULL); 252143731Sdougb 253143731Sdougb key = dctx->key; 254143731Sdougb CHECKALG(key->key_alg); 255143731Sdougb if (key->opaque == NULL) 256143731Sdougb return (DST_R_NULLKEY); 257143731Sdougb if (key->func->sign == NULL) 258143731Sdougb return (DST_R_NOTPRIVATEKEY); 259143731Sdougb if (key->func->isprivate == NULL || 260143731Sdougb key->func->isprivate(key) == ISC_FALSE) 261143731Sdougb return (DST_R_NOTPRIVATEKEY); 262143731Sdougb 263143731Sdougb return (key->func->sign(dctx, sig)); 264143731Sdougb} 265143731Sdougb 266143731Sdougbisc_result_t 267143731Sdougbdst_context_verify(dst_context_t *dctx, isc_region_t *sig) { 268143731Sdougb REQUIRE(VALID_CTX(dctx)); 269143731Sdougb REQUIRE(sig != NULL); 270143731Sdougb 271143731Sdougb CHECKALG(dctx->key->key_alg); 272143731Sdougb if (dctx->key->opaque == NULL) 273143731Sdougb return (DST_R_NULLKEY); 274143731Sdougb if (dctx->key->func->verify == NULL) 275143731Sdougb return (DST_R_NOTPUBLICKEY); 276143731Sdougb 277143731Sdougb return (dctx->key->func->verify(dctx, sig)); 278143731Sdougb} 279143731Sdougb 280143731Sdougbisc_result_t 281143731Sdougbdst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv, 282143731Sdougb isc_buffer_t *secret) 283143731Sdougb{ 284143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 285143731Sdougb REQUIRE(VALID_KEY(pub) && VALID_KEY(priv)); 286143731Sdougb REQUIRE(secret != NULL); 287143731Sdougb 288143731Sdougb CHECKALG(pub->key_alg); 289143731Sdougb CHECKALG(priv->key_alg); 290143731Sdougb 291143731Sdougb if (pub->opaque == NULL || priv->opaque == NULL) 292143731Sdougb return (DST_R_NULLKEY); 293143731Sdougb 294143731Sdougb if (pub->key_alg != priv->key_alg || 295143731Sdougb pub->func->computesecret == NULL || 296143731Sdougb priv->func->computesecret == NULL) 297143731Sdougb return (DST_R_KEYCANNOTCOMPUTESECRET); 298143731Sdougb 299143731Sdougb if (dst_key_isprivate(priv) == ISC_FALSE) 300143731Sdougb return (DST_R_NOTPRIVATEKEY); 301143731Sdougb 302143731Sdougb return (pub->func->computesecret(pub, priv, secret)); 303143731Sdougb} 304143731Sdougb 305143731Sdougbisc_result_t 306143731Sdougbdst_key_tofile(const dst_key_t *key, int type, const char *directory) { 307143731Sdougb isc_result_t ret = ISC_R_SUCCESS; 308143731Sdougb 309143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 310143731Sdougb REQUIRE(VALID_KEY(key)); 311143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 312143731Sdougb 313143731Sdougb CHECKALG(key->key_alg); 314143731Sdougb 315143731Sdougb if (key->func->tofile == NULL) 316143731Sdougb return (DST_R_UNSUPPORTEDALG); 317143731Sdougb 318143731Sdougb if (type & DST_TYPE_PUBLIC) { 319143731Sdougb ret = write_public_key(key, type, directory); 320143731Sdougb if (ret != ISC_R_SUCCESS) 321143731Sdougb return (ret); 322143731Sdougb } 323143731Sdougb 324143731Sdougb if ((type & DST_TYPE_PRIVATE) && 325143731Sdougb (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY) 326143731Sdougb return (key->func->tofile(key, directory)); 327143731Sdougb else 328143731Sdougb return (ISC_R_SUCCESS); 329143731Sdougb} 330143731Sdougb 331143731Sdougbisc_result_t 332143731Sdougbdst_key_fromfile(dns_name_t *name, dns_keytag_t id, 333143731Sdougb unsigned int alg, int type, const char *directory, 334143731Sdougb isc_mem_t *mctx, dst_key_t **keyp) 335143731Sdougb{ 336143731Sdougb char filename[ISC_DIR_NAMEMAX]; 337143731Sdougb isc_buffer_t b; 338143731Sdougb dst_key_t *key; 339143731Sdougb isc_result_t result; 340143731Sdougb 341143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 342143731Sdougb REQUIRE(dns_name_isabsolute(name)); 343143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 344143731Sdougb REQUIRE(mctx != NULL); 345143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 346143731Sdougb 347143731Sdougb CHECKALG(alg); 348143731Sdougb 349143731Sdougb isc_buffer_init(&b, filename, sizeof(filename)); 350143731Sdougb result = buildfilename(name, id, alg, type, directory, &b); 351143731Sdougb if (result != ISC_R_SUCCESS) 352143731Sdougb return (result); 353143731Sdougb 354143731Sdougb key = NULL; 355143731Sdougb result = dst_key_fromnamedfile(filename, type, mctx, &key); 356143731Sdougb if (result != ISC_R_SUCCESS) 357143731Sdougb return (result); 358143731Sdougb 359143731Sdougb result = computeid(key); 360143731Sdougb if (result != ISC_R_SUCCESS) { 361143731Sdougb dst_key_free(&key); 362143731Sdougb return (result); 363143731Sdougb } 364143731Sdougb 365143731Sdougb if (!dns_name_equal(name, key->key_name) || 366143731Sdougb id != key->key_id || 367143731Sdougb alg != key->key_alg) 368143731Sdougb { 369143731Sdougb dst_key_free(&key); 370143731Sdougb return (DST_R_INVALIDPRIVATEKEY); 371143731Sdougb } 372143731Sdougb key->key_id = id; 373143731Sdougb 374143731Sdougb *keyp = key; 375143731Sdougb return (ISC_R_SUCCESS); 376143731Sdougb} 377143731Sdougb 378143731Sdougbisc_result_t 379143731Sdougbdst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx, 380143731Sdougb dst_key_t **keyp) 381143731Sdougb{ 382143731Sdougb isc_result_t result; 383143731Sdougb dst_key_t *pubkey = NULL, *key = NULL; 384143731Sdougb dns_keytag_t id; 385143731Sdougb char *newfilename = NULL; 386143731Sdougb int newfilenamelen = 0; 387143731Sdougb isc_lex_t *lex = NULL; 388143731Sdougb 389143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 390143731Sdougb REQUIRE(filename != NULL); 391143731Sdougb REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0); 392143731Sdougb REQUIRE(mctx != NULL); 393143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 394143731Sdougb 395143731Sdougb result = read_public_key(filename, type, mctx, &pubkey); 396143731Sdougb if (result != ISC_R_SUCCESS) 397143731Sdougb return (result); 398143731Sdougb 399143731Sdougb if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC || 400143731Sdougb (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) 401143731Sdougb { 402143731Sdougb result = computeid(pubkey); 403143731Sdougb if (result != ISC_R_SUCCESS) { 404143731Sdougb dst_key_free(&pubkey); 405143731Sdougb return (result); 406143731Sdougb } 407143731Sdougb 408143731Sdougb *keyp = pubkey; 409143731Sdougb return (ISC_R_SUCCESS); 410143731Sdougb } 411143731Sdougb 412143731Sdougb result = algorithm_status(pubkey->key_alg); 413143731Sdougb if (result != ISC_R_SUCCESS) { 414143731Sdougb dst_key_free(&pubkey); 415143731Sdougb return (result); 416143731Sdougb } 417143731Sdougb 418143731Sdougb key = get_key_struct(pubkey->key_name, pubkey->key_alg, 419143731Sdougb pubkey->key_flags, pubkey->key_proto, 0, 420143731Sdougb pubkey->key_class, mctx); 421143731Sdougb id = pubkey->key_id; 422143731Sdougb dst_key_free(&pubkey); 423143731Sdougb 424143731Sdougb if (key == NULL) 425143731Sdougb return (ISC_R_NOMEMORY); 426143731Sdougb 427143731Sdougb if (key->func->parse == NULL) 428143731Sdougb RETERR(DST_R_UNSUPPORTEDALG); 429143731Sdougb 430143731Sdougb newfilenamelen = strlen(filename) + 9; 431143731Sdougb newfilename = isc_mem_get(mctx, newfilenamelen); 432143731Sdougb if (newfilename == NULL) 433143731Sdougb RETERR(ISC_R_NOMEMORY); 434143731Sdougb result = addsuffix(newfilename, newfilenamelen, filename, ".private"); 435143731Sdougb INSIST(result == ISC_R_SUCCESS); 436143731Sdougb 437143731Sdougb RETERR(isc_lex_create(mctx, 1500, &lex)); 438143731Sdougb RETERR(isc_lex_openfile(lex, newfilename)); 439143731Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 440143731Sdougb 441143731Sdougb RETERR(key->func->parse(key, lex)); 442143731Sdougb isc_lex_destroy(&lex); 443143731Sdougb 444143731Sdougb RETERR(computeid(key)); 445143731Sdougb 446143731Sdougb if (id != key->key_id) 447143731Sdougb RETERR(DST_R_INVALIDPRIVATEKEY); 448143731Sdougb 449143731Sdougb *keyp = key; 450143731Sdougb return (ISC_R_SUCCESS); 451143731Sdougb out: 452143731Sdougb if (newfilename != NULL) 453143731Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 454143731Sdougb if (lex != NULL) 455143731Sdougb isc_lex_destroy(&lex); 456143731Sdougb dst_key_free(&key); 457143731Sdougb return (result); 458143731Sdougb} 459143731Sdougb 460143731Sdougbisc_result_t 461143731Sdougbdst_key_todns(const dst_key_t *key, isc_buffer_t *target) { 462143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 463143731Sdougb REQUIRE(VALID_KEY(key)); 464143731Sdougb REQUIRE(target != NULL); 465143731Sdougb 466143731Sdougb CHECKALG(key->key_alg); 467143731Sdougb 468143731Sdougb if (key->func->todns == NULL) 469143731Sdougb return (DST_R_UNSUPPORTEDALG); 470143731Sdougb 471143731Sdougb if (isc_buffer_availablelength(target) < 4) 472143731Sdougb return (ISC_R_NOSPACE); 473143731Sdougb isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff)); 474143731Sdougb isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto); 475143731Sdougb isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg); 476143731Sdougb 477143731Sdougb if (key->key_flags & DNS_KEYFLAG_EXTENDED) { 478143731Sdougb if (isc_buffer_availablelength(target) < 2) 479143731Sdougb return (ISC_R_NOSPACE); 480143731Sdougb isc_buffer_putuint16(target, 481143731Sdougb (isc_uint16_t)((key->key_flags >> 16) 482143731Sdougb & 0xffff)); 483143731Sdougb } 484143731Sdougb 485143731Sdougb if (key->opaque == NULL) /* NULL KEY */ 486143731Sdougb return (ISC_R_SUCCESS); 487143731Sdougb 488143731Sdougb return (key->func->todns(key, target)); 489143731Sdougb} 490143731Sdougb 491143731Sdougbisc_result_t 492143731Sdougbdst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, 493143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 494143731Sdougb{ 495143731Sdougb isc_uint8_t alg, proto; 496143731Sdougb isc_uint32_t flags, extflags; 497143731Sdougb dst_key_t *key = NULL; 498143731Sdougb dns_keytag_t id; 499143731Sdougb isc_region_t r; 500143731Sdougb isc_result_t result; 501143731Sdougb 502143731Sdougb REQUIRE(dst_initialized); 503143731Sdougb 504143731Sdougb isc_buffer_remainingregion(source, &r); 505143731Sdougb 506143731Sdougb if (isc_buffer_remaininglength(source) < 4) 507143731Sdougb return (DST_R_INVALIDPUBLICKEY); 508143731Sdougb flags = isc_buffer_getuint16(source); 509143731Sdougb proto = isc_buffer_getuint8(source); 510143731Sdougb alg = isc_buffer_getuint8(source); 511143731Sdougb 512143731Sdougb id = dst_region_computeid(&r, alg); 513143731Sdougb 514143731Sdougb if (flags & DNS_KEYFLAG_EXTENDED) { 515143731Sdougb if (isc_buffer_remaininglength(source) < 2) 516143731Sdougb return (DST_R_INVALIDPUBLICKEY); 517143731Sdougb extflags = isc_buffer_getuint16(source); 518143731Sdougb flags |= (extflags << 16); 519143731Sdougb } 520143731Sdougb 521143731Sdougb result = frombuffer(name, alg, flags, proto, rdclass, source, 522143731Sdougb mctx, &key); 523143731Sdougb if (result != ISC_R_SUCCESS) 524143731Sdougb return (result); 525143731Sdougb key->key_id = id; 526143731Sdougb 527143731Sdougb *keyp = key; 528143731Sdougb return (ISC_R_SUCCESS); 529143731Sdougb} 530143731Sdougb 531143731Sdougbisc_result_t 532143731Sdougbdst_key_frombuffer(dns_name_t *name, unsigned int alg, 533143731Sdougb unsigned int flags, unsigned int protocol, 534143731Sdougb dns_rdataclass_t rdclass, 535143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 536143731Sdougb{ 537143731Sdougb dst_key_t *key = NULL; 538143731Sdougb isc_result_t result; 539143731Sdougb 540143731Sdougb REQUIRE(dst_initialized); 541143731Sdougb 542143731Sdougb result = frombuffer(name, alg, flags, protocol, rdclass, source, 543143731Sdougb mctx, &key); 544143731Sdougb if (result != ISC_R_SUCCESS) 545143731Sdougb return (result); 546143731Sdougb 547143731Sdougb result = computeid(key); 548143731Sdougb if (result != ISC_R_SUCCESS) { 549143731Sdougb dst_key_free(&key); 550143731Sdougb return (result); 551143731Sdougb } 552143731Sdougb 553143731Sdougb *keyp = key; 554143731Sdougb return (ISC_R_SUCCESS); 555143731Sdougb} 556143731Sdougb 557143731Sdougbisc_result_t 558143731Sdougbdst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) { 559143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 560143731Sdougb REQUIRE(VALID_KEY(key)); 561143731Sdougb REQUIRE(target != NULL); 562143731Sdougb 563143731Sdougb CHECKALG(key->key_alg); 564143731Sdougb 565143731Sdougb if (key->func->todns == NULL) 566143731Sdougb return (DST_R_UNSUPPORTEDALG); 567143731Sdougb 568143731Sdougb return (key->func->todns(key, target)); 569143731Sdougb} 570143731Sdougb 571143731Sdougbisc_result_t 572143731Sdougbdst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) { 573143731Sdougb isc_lex_t *lex = NULL; 574143731Sdougb isc_result_t result = ISC_R_SUCCESS; 575143731Sdougb 576143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 577143731Sdougb REQUIRE(VALID_KEY(key)); 578143731Sdougb REQUIRE(!dst_key_isprivate(key)); 579143731Sdougb REQUIRE(buffer != NULL); 580143731Sdougb 581143731Sdougb if (key->func->parse == NULL) 582143731Sdougb RETERR(DST_R_UNSUPPORTEDALG); 583143731Sdougb 584143731Sdougb RETERR(isc_lex_create(key->mctx, 1500, &lex)); 585143731Sdougb RETERR(isc_lex_openbuffer(lex, buffer)); 586143731Sdougb RETERR(key->func->parse(key, lex)); 587143731Sdougb out: 588143731Sdougb if (lex != NULL) 589143731Sdougb isc_lex_destroy(&lex); 590143731Sdougb return (result); 591143731Sdougb} 592143731Sdougb 593143731Sdougbisc_result_t 594143731Sdougbdst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx, 595143731Sdougb dst_key_t **keyp) 596143731Sdougb{ 597143731Sdougb dst_key_t *key; 598143731Sdougb 599143731Sdougb REQUIRE(opaque != NULL); 600143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 601143731Sdougb 602143731Sdougb key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 603143731Sdougb 0, dns_rdataclass_in, mctx); 604143731Sdougb if (key == NULL) 605143731Sdougb return (ISC_R_NOMEMORY); 606143731Sdougb key->opaque = opaque; 607143731Sdougb *keyp = key; 608143731Sdougb return (ISC_R_SUCCESS); 609143731Sdougb} 610143731Sdougb 611143731Sdougbisc_result_t 612143731Sdougbdst_key_generate(dns_name_t *name, unsigned int alg, 613143731Sdougb unsigned int bits, unsigned int param, 614143731Sdougb unsigned int flags, unsigned int protocol, 615143731Sdougb dns_rdataclass_t rdclass, 616143731Sdougb isc_mem_t *mctx, dst_key_t **keyp) 617143731Sdougb{ 618143731Sdougb dst_key_t *key; 619143731Sdougb isc_result_t ret; 620143731Sdougb 621143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 622143731Sdougb REQUIRE(dns_name_isabsolute(name)); 623143731Sdougb REQUIRE(mctx != NULL); 624143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 625143731Sdougb 626143731Sdougb CHECKALG(alg); 627143731Sdougb 628143731Sdougb key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx); 629143731Sdougb if (key == NULL) 630143731Sdougb return (ISC_R_NOMEMORY); 631143731Sdougb 632143731Sdougb if (bits == 0) { /* NULL KEY */ 633143731Sdougb key->key_flags |= DNS_KEYTYPE_NOKEY; 634143731Sdougb *keyp = key; 635143731Sdougb return (ISC_R_SUCCESS); 636143731Sdougb } 637143731Sdougb 638143731Sdougb if (key->func->generate == NULL) { 639143731Sdougb dst_key_free(&key); 640143731Sdougb return (DST_R_UNSUPPORTEDALG); 641143731Sdougb } 642143731Sdougb 643143731Sdougb ret = key->func->generate(key, param); 644143731Sdougb if (ret != ISC_R_SUCCESS) { 645143731Sdougb dst_key_free(&key); 646143731Sdougb return (ret); 647143731Sdougb } 648143731Sdougb 649143731Sdougb ret = computeid(key); 650143731Sdougb if (ret != ISC_R_SUCCESS) { 651143731Sdougb dst_key_free(&key); 652143731Sdougb return (ret); 653143731Sdougb } 654143731Sdougb 655143731Sdougb *keyp = key; 656143731Sdougb return (ISC_R_SUCCESS); 657143731Sdougb} 658143731Sdougb 659143731Sdougbisc_boolean_t 660143731Sdougbdst_key_compare(const dst_key_t *key1, const dst_key_t *key2) { 661143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 662143731Sdougb REQUIRE(VALID_KEY(key1)); 663143731Sdougb REQUIRE(VALID_KEY(key2)); 664143731Sdougb 665143731Sdougb if (key1 == key2) 666143731Sdougb return (ISC_TRUE); 667143731Sdougb if (key1 == NULL || key2 == NULL) 668143731Sdougb return (ISC_FALSE); 669143731Sdougb if (key1->key_alg == key2->key_alg && 670143731Sdougb key1->key_id == key2->key_id && 671143731Sdougb key1->func->compare != NULL && 672143731Sdougb key1->func->compare(key1, key2) == ISC_TRUE) 673143731Sdougb return (ISC_TRUE); 674143731Sdougb else 675143731Sdougb return (ISC_FALSE); 676143731Sdougb} 677143731Sdougb 678143731Sdougbisc_boolean_t 679143731Sdougbdst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { 680143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 681143731Sdougb REQUIRE(VALID_KEY(key1)); 682143731Sdougb REQUIRE(VALID_KEY(key2)); 683143731Sdougb 684143731Sdougb if (key1 == key2) 685143731Sdougb return (ISC_TRUE); 686143731Sdougb if (key1 == NULL || key2 == NULL) 687143731Sdougb return (ISC_FALSE); 688143731Sdougb if (key1->key_alg == key2->key_alg && 689143731Sdougb key1->func->paramcompare != NULL && 690143731Sdougb key1->func->paramcompare(key1, key2) == ISC_TRUE) 691143731Sdougb return (ISC_TRUE); 692143731Sdougb else 693143731Sdougb return (ISC_FALSE); 694143731Sdougb} 695143731Sdougb 696143731Sdougbvoid 697143731Sdougbdst_key_free(dst_key_t **keyp) { 698143731Sdougb isc_mem_t *mctx; 699143731Sdougb dst_key_t *key; 700143731Sdougb 701143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 702143731Sdougb REQUIRE(keyp != NULL && VALID_KEY(*keyp)); 703143731Sdougb 704143731Sdougb key = *keyp; 705143731Sdougb mctx = key->mctx; 706143731Sdougb 707143731Sdougb if (key->opaque != NULL) { 708143731Sdougb INSIST(key->func->destroy != NULL); 709143731Sdougb key->func->destroy(key); 710143731Sdougb } 711143731Sdougb 712143731Sdougb dns_name_free(key->key_name, mctx); 713143731Sdougb isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 714143731Sdougb memset(key, 0, sizeof(dst_key_t)); 715143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 716143731Sdougb *keyp = NULL; 717143731Sdougb} 718143731Sdougb 719143731Sdougbisc_boolean_t 720143731Sdougbdst_key_isprivate(const dst_key_t *key) { 721143731Sdougb REQUIRE(VALID_KEY(key)); 722143731Sdougb INSIST(key->func->isprivate != NULL); 723143731Sdougb return (key->func->isprivate(key)); 724143731Sdougb} 725143731Sdougb 726143731Sdougbisc_result_t 727143731Sdougbdst_key_buildfilename(const dst_key_t *key, int type, 728143731Sdougb const char *directory, isc_buffer_t *out) { 729143731Sdougb 730143731Sdougb REQUIRE(VALID_KEY(key)); 731143731Sdougb REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC || 732143731Sdougb type == 0); 733143731Sdougb 734143731Sdougb return (buildfilename(key->key_name, key->key_id, key->key_alg, 735143731Sdougb type, directory, out)); 736143731Sdougb} 737143731Sdougb 738143731Sdougbisc_result_t 739143731Sdougbdst_key_sigsize(const dst_key_t *key, unsigned int *n) { 740143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 741143731Sdougb REQUIRE(VALID_KEY(key)); 742143731Sdougb REQUIRE(n != NULL); 743143731Sdougb 744143731Sdougb /* XXXVIX this switch statement is too sparse to gen a jump table. */ 745143731Sdougb switch (key->key_alg) { 746143731Sdougb case DST_ALG_RSAMD5: 747143731Sdougb case DST_ALG_RSASHA1: 748143731Sdougb *n = (key->key_size + 7) / 8; 749143731Sdougb break; 750143731Sdougb case DST_ALG_DSA: 751143731Sdougb *n = DNS_SIG_DSASIGSIZE; 752143731Sdougb break; 753143731Sdougb case DST_ALG_HMACMD5: 754143731Sdougb *n = 16; 755143731Sdougb break; 756143731Sdougb case DST_ALG_GSSAPI: 757143731Sdougb *n = 128; /* XXX */ 758143731Sdougb break; 759143731Sdougb case DST_ALG_DH: 760143731Sdougb default: 761143731Sdougb return (DST_R_UNSUPPORTEDALG); 762143731Sdougb } 763143731Sdougb return (ISC_R_SUCCESS); 764143731Sdougb} 765143731Sdougb 766143731Sdougbisc_result_t 767143731Sdougbdst_key_secretsize(const dst_key_t *key, unsigned int *n) { 768143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 769143731Sdougb REQUIRE(VALID_KEY(key)); 770143731Sdougb REQUIRE(n != NULL); 771143731Sdougb 772143731Sdougb if (key->key_alg == DST_ALG_DH) 773143731Sdougb *n = (key->key_size + 7) / 8; 774143731Sdougb else 775143731Sdougb return (DST_R_UNSUPPORTEDALG); 776143731Sdougb return (ISC_R_SUCCESS); 777143731Sdougb} 778143731Sdougb 779143731Sdougb/*** 780143731Sdougb *** Static methods 781143731Sdougb ***/ 782143731Sdougb 783143731Sdougb/* 784143731Sdougb * Allocates a key structure and fills in some of the fields. 785143731Sdougb */ 786143731Sdougbstatic dst_key_t * 787143731Sdougbget_key_struct(dns_name_t *name, unsigned int alg, 788143731Sdougb unsigned int flags, unsigned int protocol, 789143731Sdougb unsigned int bits, dns_rdataclass_t rdclass, 790143731Sdougb isc_mem_t *mctx) 791143731Sdougb{ 792143731Sdougb dst_key_t *key; 793143731Sdougb isc_result_t result; 794143731Sdougb 795143731Sdougb key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t)); 796143731Sdougb if (key == NULL) 797143731Sdougb return (NULL); 798143731Sdougb 799143731Sdougb memset(key, 0, sizeof(dst_key_t)); 800143731Sdougb key->magic = KEY_MAGIC; 801143731Sdougb 802143731Sdougb key->key_name = isc_mem_get(mctx, sizeof(dns_name_t)); 803143731Sdougb if (key->key_name == NULL) { 804143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 805143731Sdougb return (NULL); 806143731Sdougb } 807143731Sdougb dns_name_init(key->key_name, NULL); 808143731Sdougb result = dns_name_dup(name, mctx, key->key_name); 809143731Sdougb if (result != ISC_R_SUCCESS) { 810143731Sdougb isc_mem_put(mctx, key->key_name, sizeof(dns_name_t)); 811143731Sdougb isc_mem_put(mctx, key, sizeof(dst_key_t)); 812143731Sdougb return (NULL); 813143731Sdougb } 814143731Sdougb key->key_alg = alg; 815143731Sdougb key->key_flags = flags; 816143731Sdougb key->key_proto = protocol; 817143731Sdougb key->mctx = mctx; 818143731Sdougb key->opaque = NULL; 819143731Sdougb key->key_size = bits; 820143731Sdougb key->key_class = rdclass; 821143731Sdougb key->func = dst_t_func[alg]; 822143731Sdougb return (key); 823143731Sdougb} 824143731Sdougb 825143731Sdougb/* 826143731Sdougb * Reads a public key from disk 827143731Sdougb */ 828143731Sdougbstatic isc_result_t 829143731Sdougbread_public_key(const char *filename, int type, 830143731Sdougb isc_mem_t *mctx, dst_key_t **keyp) 831143731Sdougb{ 832143731Sdougb u_char rdatabuf[DST_KEY_MAXSIZE]; 833143731Sdougb isc_buffer_t b; 834143731Sdougb dns_fixedname_t name; 835143731Sdougb isc_lex_t *lex = NULL; 836143731Sdougb isc_token_t token; 837143731Sdougb isc_result_t ret; 838143731Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 839143731Sdougb unsigned int opt = ISC_LEXOPT_DNSMULTILINE; 840143731Sdougb char *newfilename; 841143731Sdougb unsigned int newfilenamelen; 842143731Sdougb dns_rdataclass_t rdclass = dns_rdataclass_in; 843143731Sdougb isc_lexspecials_t specials; 844143731Sdougb isc_uint32_t ttl; 845143731Sdougb isc_result_t result; 846143731Sdougb dns_rdatatype_t keytype; 847143731Sdougb 848143731Sdougb newfilenamelen = strlen(filename) + 5; 849143731Sdougb newfilename = isc_mem_get(mctx, newfilenamelen); 850143731Sdougb if (newfilename == NULL) 851143731Sdougb return (ISC_R_NOMEMORY); 852143731Sdougb ret = addsuffix(newfilename, newfilenamelen, filename, ".key"); 853143731Sdougb INSIST(ret == ISC_R_SUCCESS); 854143731Sdougb 855143731Sdougb /* 856143731Sdougb * Open the file and read its formatted contents 857143731Sdougb * File format: 858143731Sdougb * domain.name [ttl] [class] KEY <flags> <protocol> <algorithm> <key> 859143731Sdougb */ 860143731Sdougb 861143731Sdougb /* 1500 should be large enough for any key */ 862143731Sdougb ret = isc_lex_create(mctx, 1500, &lex); 863143731Sdougb if (ret != ISC_R_SUCCESS) 864143731Sdougb goto cleanup; 865143731Sdougb 866143731Sdougb memset(specials, 0, sizeof(specials)); 867143731Sdougb specials['('] = 1; 868143731Sdougb specials[')'] = 1; 869143731Sdougb specials['"'] = 1; 870143731Sdougb isc_lex_setspecials(lex, specials); 871143731Sdougb isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE); 872143731Sdougb 873143731Sdougb ret = isc_lex_openfile(lex, newfilename); 874143731Sdougb if (ret != ISC_R_SUCCESS) 875143731Sdougb goto cleanup; 876143731Sdougb 877143731Sdougb#define NEXTTOKEN(lex, opt, token) { \ 878143731Sdougb ret = isc_lex_gettoken(lex, opt, token); \ 879143731Sdougb if (ret != ISC_R_SUCCESS) \ 880143731Sdougb goto cleanup; \ 881143731Sdougb } 882143731Sdougb 883143731Sdougb#define BADTOKEN() { \ 884143731Sdougb ret = ISC_R_UNEXPECTEDTOKEN; \ 885143731Sdougb goto cleanup; \ 886143731Sdougb } 887143731Sdougb 888143731Sdougb /* Read the domain name */ 889143731Sdougb NEXTTOKEN(lex, opt, &token); 890143731Sdougb if (token.type != isc_tokentype_string) 891143731Sdougb BADTOKEN(); 892143731Sdougb dns_fixedname_init(&name); 893143731Sdougb isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token))); 894143731Sdougb isc_buffer_add(&b, strlen(DST_AS_STR(token))); 895143731Sdougb ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, 896143731Sdougb ISC_FALSE, NULL); 897143731Sdougb if (ret != ISC_R_SUCCESS) 898143731Sdougb goto cleanup; 899143731Sdougb 900143731Sdougb /* Read the next word: either TTL, class, or 'KEY' */ 901143731Sdougb NEXTTOKEN(lex, opt, &token); 902143731Sdougb 903143731Sdougb /* If it's a TTL, read the next one */ 904143731Sdougb result = dns_ttl_fromtext(&token.value.as_textregion, &ttl); 905143731Sdougb if (result == ISC_R_SUCCESS) 906143731Sdougb NEXTTOKEN(lex, opt, &token); 907143731Sdougb 908143731Sdougb if (token.type != isc_tokentype_string) 909143731Sdougb BADTOKEN(); 910143731Sdougb 911143731Sdougb ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion); 912143731Sdougb if (ret == ISC_R_SUCCESS) 913143731Sdougb NEXTTOKEN(lex, opt, &token); 914143731Sdougb 915143731Sdougb if (token.type != isc_tokentype_string) 916143731Sdougb BADTOKEN(); 917143731Sdougb 918143731Sdougb if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) 919143731Sdougb keytype = dns_rdatatype_dnskey; 920143731Sdougb else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) 921143731Sdougb keytype = dns_rdatatype_key; /* SIG(0), TKEY */ 922143731Sdougb else 923143731Sdougb BADTOKEN(); 924143731Sdougb 925143731Sdougb if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) || 926143731Sdougb ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) { 927143731Sdougb ret = DST_R_BADKEYTYPE; 928143731Sdougb goto cleanup; 929143731Sdougb } 930143731Sdougb 931143731Sdougb isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); 932143731Sdougb ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, 933143731Sdougb ISC_FALSE, mctx, &b, NULL); 934143731Sdougb if (ret != ISC_R_SUCCESS) 935143731Sdougb goto cleanup; 936143731Sdougb 937143731Sdougb ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx, 938143731Sdougb keyp); 939143731Sdougb if (ret != ISC_R_SUCCESS) 940143731Sdougb goto cleanup; 941143731Sdougb 942143731Sdougb cleanup: 943143731Sdougb if (lex != NULL) 944143731Sdougb isc_lex_destroy(&lex); 945143731Sdougb isc_mem_put(mctx, newfilename, newfilenamelen); 946143731Sdougb 947143731Sdougb return (ret); 948143731Sdougb} 949143731Sdougb 950143731Sdougbstatic isc_boolean_t 951143731Sdougbissymmetric(const dst_key_t *key) { 952143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 953143731Sdougb REQUIRE(VALID_KEY(key)); 954143731Sdougb 955143731Sdougb /* XXXVIX this switch statement is too sparse to gen a jump table. */ 956143731Sdougb switch (key->key_alg) { 957143731Sdougb case DST_ALG_RSAMD5: 958143731Sdougb case DST_ALG_RSASHA1: 959143731Sdougb case DST_ALG_DSA: 960143731Sdougb case DST_ALG_DH: 961143731Sdougb return (ISC_FALSE); 962143731Sdougb case DST_ALG_HMACMD5: 963143731Sdougb case DST_ALG_GSSAPI: 964143731Sdougb return (ISC_TRUE); 965143731Sdougb default: 966143731Sdougb return (ISC_FALSE); 967143731Sdougb } 968143731Sdougb} 969143731Sdougb 970143731Sdougb/* 971143731Sdougb * Writes a public key to disk in DNS format. 972143731Sdougb */ 973143731Sdougbstatic isc_result_t 974143731Sdougbwrite_public_key(const dst_key_t *key, int type, const char *directory) { 975143731Sdougb FILE *fp; 976143731Sdougb isc_buffer_t keyb, textb, fileb, classb; 977143731Sdougb isc_region_t r; 978143731Sdougb char filename[ISC_DIR_NAMEMAX]; 979143731Sdougb unsigned char key_array[DST_KEY_MAXSIZE]; 980143731Sdougb char text_array[DST_KEY_MAXTEXTSIZE]; 981143731Sdougb char class_array[10]; 982143731Sdougb isc_result_t ret; 983143731Sdougb dns_rdata_t rdata = DNS_RDATA_INIT; 984143731Sdougb isc_fsaccess_t access; 985143731Sdougb 986143731Sdougb REQUIRE(VALID_KEY(key)); 987143731Sdougb 988143731Sdougb isc_buffer_init(&keyb, key_array, sizeof(key_array)); 989143731Sdougb isc_buffer_init(&textb, text_array, sizeof(text_array)); 990143731Sdougb isc_buffer_init(&classb, class_array, sizeof(class_array)); 991143731Sdougb 992143731Sdougb ret = dst_key_todns(key, &keyb); 993143731Sdougb if (ret != ISC_R_SUCCESS) 994143731Sdougb return (ret); 995143731Sdougb 996143731Sdougb isc_buffer_usedregion(&keyb, &r); 997143731Sdougb dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r); 998143731Sdougb 999143731Sdougb ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb); 1000143731Sdougb if (ret != ISC_R_SUCCESS) 1001143731Sdougb return (DST_R_INVALIDPUBLICKEY); 1002143731Sdougb 1003143731Sdougb ret = dns_rdataclass_totext(key->key_class, &classb); 1004143731Sdougb if (ret != ISC_R_SUCCESS) 1005143731Sdougb return (DST_R_INVALIDPUBLICKEY); 1006143731Sdougb 1007143731Sdougb /* 1008143731Sdougb * Make the filename. 1009143731Sdougb */ 1010143731Sdougb isc_buffer_init(&fileb, filename, sizeof(filename)); 1011143731Sdougb ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb); 1012143731Sdougb if (ret != ISC_R_SUCCESS) 1013143731Sdougb return (ret); 1014143731Sdougb 1015143731Sdougb /* 1016143731Sdougb * Create public key file. 1017143731Sdougb */ 1018143731Sdougb if ((fp = fopen(filename, "w")) == NULL) 1019143731Sdougb return (DST_R_WRITEERROR); 1020143731Sdougb 1021143731Sdougb if (issymmetric(key)) { 1022143731Sdougb access = 0; 1023143731Sdougb isc_fsaccess_add(ISC_FSACCESS_OWNER, 1024143731Sdougb ISC_FSACCESS_READ | ISC_FSACCESS_WRITE, 1025143731Sdougb &access); 1026143731Sdougb (void)isc_fsaccess_set(filename, access); 1027143731Sdougb } 1028143731Sdougb 1029143731Sdougb ret = dns_name_print(key->key_name, fp); 1030165071Sdougb if (ret != ISC_R_SUCCESS) { 1031165071Sdougb fclose(fp); 1032143731Sdougb return (ret); 1033165071Sdougb } 1034143731Sdougb 1035143731Sdougb fprintf(fp, " "); 1036143731Sdougb 1037143731Sdougb isc_buffer_usedregion(&classb, &r); 1038143731Sdougb fwrite(r.base, 1, r.length, fp); 1039143731Sdougb 1040143731Sdougb if ((type & DST_TYPE_KEY) != 0) 1041143731Sdougb fprintf(fp, " KEY "); 1042143731Sdougb else 1043143731Sdougb fprintf(fp, " DNSKEY "); 1044143731Sdougb 1045143731Sdougb isc_buffer_usedregion(&textb, &r); 1046143731Sdougb fwrite(r.base, 1, r.length, fp); 1047143731Sdougb 1048143731Sdougb fputc('\n', fp); 1049143731Sdougb fclose(fp); 1050143731Sdougb 1051143731Sdougb return (ISC_R_SUCCESS); 1052143731Sdougb} 1053143731Sdougb 1054143731Sdougbstatic isc_result_t 1055143731Sdougbbuildfilename(dns_name_t *name, dns_keytag_t id, 1056143731Sdougb unsigned int alg, unsigned int type, 1057143731Sdougb const char *directory, isc_buffer_t *out) 1058143731Sdougb{ 1059143731Sdougb const char *suffix = ""; 1060143731Sdougb unsigned int len; 1061143731Sdougb isc_result_t result; 1062143731Sdougb 1063143731Sdougb REQUIRE(out != NULL); 1064143731Sdougb if ((type & DST_TYPE_PRIVATE) != 0) 1065143731Sdougb suffix = ".private"; 1066143731Sdougb else if (type == DST_TYPE_PUBLIC) 1067143731Sdougb suffix = ".key"; 1068143731Sdougb if (directory != NULL) { 1069143731Sdougb if (isc_buffer_availablelength(out) < strlen(directory)) 1070143731Sdougb return (ISC_R_NOSPACE); 1071143731Sdougb isc_buffer_putstr(out, directory); 1072143731Sdougb if (strlen(directory) > 0U && 1073143731Sdougb directory[strlen(directory) - 1] != '/') 1074143731Sdougb isc_buffer_putstr(out, "/"); 1075143731Sdougb } 1076143731Sdougb if (isc_buffer_availablelength(out) < 1) 1077143731Sdougb return (ISC_R_NOSPACE); 1078143731Sdougb isc_buffer_putstr(out, "K"); 1079143731Sdougb result = dns_name_tofilenametext(name, ISC_FALSE, out); 1080143731Sdougb if (result != ISC_R_SUCCESS) 1081143731Sdougb return (result); 1082143731Sdougb len = 1 + 3 + 1 + 5 + strlen(suffix) + 1; 1083143731Sdougb if (isc_buffer_availablelength(out) < len) 1084143731Sdougb return (ISC_R_NOSPACE); 1085143731Sdougb sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, suffix); 1086143731Sdougb isc_buffer_add(out, len); 1087143731Sdougb return (ISC_R_SUCCESS); 1088143731Sdougb} 1089143731Sdougb 1090143731Sdougbstatic isc_result_t 1091143731Sdougbcomputeid(dst_key_t *key) { 1092143731Sdougb isc_buffer_t dnsbuf; 1093143731Sdougb unsigned char dns_array[DST_KEY_MAXSIZE]; 1094143731Sdougb isc_region_t r; 1095143731Sdougb isc_result_t ret; 1096143731Sdougb 1097143731Sdougb isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array)); 1098143731Sdougb ret = dst_key_todns(key, &dnsbuf); 1099143731Sdougb if (ret != ISC_R_SUCCESS) 1100143731Sdougb return (ret); 1101143731Sdougb 1102143731Sdougb isc_buffer_usedregion(&dnsbuf, &r); 1103143731Sdougb key->key_id = dst_region_computeid(&r, key->key_alg); 1104143731Sdougb return (ISC_R_SUCCESS); 1105143731Sdougb} 1106143731Sdougb 1107143731Sdougbstatic isc_result_t 1108143731Sdougbfrombuffer(dns_name_t *name, unsigned int alg, unsigned int flags, 1109143731Sdougb unsigned int protocol, dns_rdataclass_t rdclass, 1110143731Sdougb isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) 1111143731Sdougb{ 1112143731Sdougb dst_key_t *key; 1113143731Sdougb isc_result_t ret; 1114143731Sdougb 1115143731Sdougb REQUIRE(dns_name_isabsolute(name)); 1116143731Sdougb REQUIRE(source != NULL); 1117143731Sdougb REQUIRE(mctx != NULL); 1118143731Sdougb REQUIRE(keyp != NULL && *keyp == NULL); 1119143731Sdougb 1120143731Sdougb key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx); 1121143731Sdougb if (key == NULL) 1122143731Sdougb return (ISC_R_NOMEMORY); 1123143731Sdougb 1124143731Sdougb if (isc_buffer_remaininglength(source) > 0) { 1125143731Sdougb ret = algorithm_status(alg); 1126143731Sdougb if (ret != ISC_R_SUCCESS) { 1127143731Sdougb dst_key_free(&key); 1128143731Sdougb return (ret); 1129143731Sdougb } 1130143731Sdougb if (key->func->fromdns == NULL) { 1131143731Sdougb dst_key_free(&key); 1132143731Sdougb return (DST_R_UNSUPPORTEDALG); 1133143731Sdougb } 1134143731Sdougb 1135143731Sdougb ret = key->func->fromdns(key, source); 1136143731Sdougb if (ret != ISC_R_SUCCESS) { 1137143731Sdougb dst_key_free(&key); 1138143731Sdougb return (ret); 1139143731Sdougb } 1140143731Sdougb } 1141143731Sdougb 1142143731Sdougb *keyp = key; 1143143731Sdougb return (ISC_R_SUCCESS); 1144143731Sdougb} 1145143731Sdougb 1146143731Sdougbstatic isc_result_t 1147143731Sdougbalgorithm_status(unsigned int alg) { 1148143731Sdougb REQUIRE(dst_initialized == ISC_TRUE); 1149143731Sdougb 1150143731Sdougb if (dst_algorithm_supported(alg)) 1151143731Sdougb return (ISC_R_SUCCESS); 1152143731Sdougb#ifndef OPENSSL 1153143731Sdougb if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || 1154143731Sdougb alg == DST_ALG_DSA || alg == DST_ALG_DH || 1155143731Sdougb alg == DST_ALG_HMACMD5) 1156143731Sdougb return (DST_R_NOCRYPTO); 1157143731Sdougb#endif 1158143731Sdougb return (DST_R_UNSUPPORTEDALG); 1159143731Sdougb} 1160143731Sdougb 1161143731Sdougbstatic isc_result_t 1162143731Sdougbaddsuffix(char *filename, unsigned int len, const char *ofilename, 1163143731Sdougb const char *suffix) 1164143731Sdougb{ 1165143731Sdougb int olen = strlen(ofilename); 1166143731Sdougb int n; 1167143731Sdougb 1168143731Sdougb if (olen > 1 && ofilename[olen - 1] == '.') 1169143731Sdougb olen -= 1; 1170143731Sdougb else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) 1171143731Sdougb olen -= 8; 1172143731Sdougb else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) 1173143731Sdougb olen -= 4; 1174143731Sdougb 1175143731Sdougb n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix); 1176143731Sdougb if (n < 0) 1177143731Sdougb return (ISC_R_NOSPACE); 1178143731Sdougb return (ISC_R_SUCCESS); 1179143731Sdougb} 1180143731Sdougb 1181143731Sdougbisc_result_t 1182143731Sdougbdst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { 1183143731Sdougb unsigned int flags = dst_entropy_flags; 1184143731Sdougb if (pseudo) 1185143731Sdougb flags &= ~ISC_ENTROPY_GOODONLY; 1186143731Sdougb return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); 1187143731Sdougb} 1188