2 * Portions Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
10 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
12 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
19 * Permission to use, copy, modify, and/or distribute this software for any
20 * purpose with or without fee is hereby granted, provided that the above
21 * copyright notice and this permission notice appear in all copies.
23 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
24 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
26 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
29 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 * Principal Author: Brian Wellington
34 * $Id: dst_api.c,v 1.16.12.12 2010-12-09 01:12:55 marka Exp $
43 #include <isc/buffer.h>
45 #include <isc/entropy.h>
46 #include <isc/fsaccess.h>
47 #include <isc/hmacsha.h>
51 #include <isc/print.h>
52 #include <isc/refcount.h>
53 #include <isc/random.h>
54 #include <isc/string.h>
58 #include <dns/fixedname.h>
59 #include <dns/keyvalues.h>
61 #include <dns/rdata.h>
62 #include <dns/rdataclass.h>
64 #include <dns/types.h>
66 #include <dst/result.h>
68 #include "dst_internal.h"
70 #define DST_AS_STR(t) ((t).value.as_textregion.base)
72 static dst_func_t *dst_t_func[DST_MAX_ALGS];
73 static isc_entropy_t *dst_entropy_pool = NULL;
74 static unsigned int dst_entropy_flags = 0;
75 static isc_boolean_t dst_initialized = ISC_FALSE;
77 void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
79 isc_mem_t *dst__memory_pool = NULL;
84 static dst_key_t * get_key_struct(dns_name_t *name,
87 unsigned int protocol,
89 dns_rdataclass_t rdclass,
91 static isc_result_t write_public_key(const dst_key_t *key, int type,
92 const char *directory);
93 static isc_result_t buildfilename(dns_name_t *name,
97 const char *directory,
99 static isc_result_t computeid(dst_key_t *key);
100 static isc_result_t frombuffer(dns_name_t *name,
103 unsigned int protocol,
104 dns_rdataclass_t rdclass,
105 isc_buffer_t *source,
109 static isc_result_t algorithm_status(unsigned int alg);
111 static isc_result_t addsuffix(char *filename, unsigned int len,
112 const char *ofilename, const char *suffix);
117 if (result != ISC_R_SUCCESS) \
121 #define CHECKALG(alg) \
124 _r = algorithm_status(alg); \
125 if (_r != ISC_R_SUCCESS) \
131 default_memalloc(void *arg, size_t size) {
135 return (malloc(size));
139 default_memfree(void *arg, void *ptr) {
146 dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) {
149 REQUIRE(mctx != NULL && ectx != NULL);
150 REQUIRE(dst_initialized == ISC_FALSE);
152 dst__memory_pool = NULL;
157 * When using --with-openssl, there seems to be no good way of not
158 * leaking memory due to the openssl error handling mechanism.
159 * Avoid assertions by using a local memory context and not checking
160 * for leaks on exit. Note: as there are leaks we cannot use
161 * ISC_MEMFLAG_INTERNAL as it will free up memory still being used
164 result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
165 NULL, &dst__memory_pool, 0);
166 if (result != ISC_R_SUCCESS)
168 isc_mem_setname(dst__memory_pool, "dst", NULL);
169 isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE);
171 isc_mem_attach(mctx, &dst__memory_pool);
173 isc_entropy_attach(ectx, &dst_entropy_pool);
174 dst_entropy_flags = eflags;
176 dst_result_register();
178 memset(dst_t_func, 0, sizeof(dst_t_func));
179 RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
180 RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
181 RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
182 RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
183 RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
184 RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
186 RETERR(dst__openssl_init());
187 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5],
189 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],
191 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1],
192 DST_ALG_NSEC3RSASHA1));
193 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256],
195 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512],
197 #ifdef HAVE_OPENSSL_DSA
198 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA]));
199 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
201 RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
204 RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
206 dst_initialized = ISC_TRUE;
207 return (ISC_R_SUCCESS);
215 dst_lib_destroy(void) {
217 RUNTIME_CHECK(dst_initialized == ISC_TRUE);
218 dst_initialized = ISC_FALSE;
220 for (i = 0; i < DST_MAX_ALGS; i++)
221 if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL)
222 dst_t_func[i]->cleanup();
224 dst__openssl_destroy();
226 if (dst__memory_pool != NULL)
227 isc_mem_detach(&dst__memory_pool);
228 if (dst_entropy_pool != NULL)
229 isc_entropy_detach(&dst_entropy_pool);
234 dst_algorithm_supported(unsigned int alg) {
235 REQUIRE(dst_initialized == ISC_TRUE);
237 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
243 dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
247 REQUIRE(dst_initialized == ISC_TRUE);
248 REQUIRE(VALID_KEY(key));
249 REQUIRE(mctx != NULL);
250 REQUIRE(dctxp != NULL && *dctxp == NULL);
252 if (key->func->createctx == NULL)
253 return (DST_R_UNSUPPORTEDALG);
254 if (key->keydata.generic == NULL)
255 return (DST_R_NULLKEY);
257 dctx = isc_mem_get(mctx, sizeof(dst_context_t));
259 return (ISC_R_NOMEMORY);
262 result = key->func->createctx(key, dctx);
263 if (result != ISC_R_SUCCESS) {
264 isc_mem_put(mctx, dctx, sizeof(dst_context_t));
267 dctx->magic = CTX_MAGIC;
269 return (ISC_R_SUCCESS);
273 dst_context_destroy(dst_context_t **dctxp) {
276 REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
279 INSIST(dctx->key->func->destroyctx != NULL);
280 dctx->key->func->destroyctx(dctx);
282 isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t));
287 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
288 REQUIRE(VALID_CTX(dctx));
289 REQUIRE(data != NULL);
290 INSIST(dctx->key->func->adddata != NULL);
292 return (dctx->key->func->adddata(dctx, data));
296 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
299 REQUIRE(VALID_CTX(dctx));
300 REQUIRE(sig != NULL);
303 CHECKALG(key->key_alg);
304 if (key->keydata.generic == NULL)
305 return (DST_R_NULLKEY);
307 if (key->func->sign == NULL)
308 return (DST_R_NOTPRIVATEKEY);
309 if (key->func->isprivate == NULL ||
310 key->func->isprivate(key) == ISC_FALSE)
311 return (DST_R_NOTPRIVATEKEY);
313 return (key->func->sign(dctx, sig));
317 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
318 REQUIRE(VALID_CTX(dctx));
319 REQUIRE(sig != NULL);
321 CHECKALG(dctx->key->key_alg);
322 if (dctx->key->keydata.generic == NULL)
323 return (DST_R_NULLKEY);
324 if (dctx->key->func->verify == NULL)
325 return (DST_R_NOTPUBLICKEY);
327 return (dctx->key->func->verify(dctx, sig));
331 dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
332 isc_buffer_t *secret)
334 REQUIRE(dst_initialized == ISC_TRUE);
335 REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
336 REQUIRE(secret != NULL);
338 CHECKALG(pub->key_alg);
339 CHECKALG(priv->key_alg);
341 if (pub->keydata.generic == NULL || priv->keydata.generic == NULL)
342 return (DST_R_NULLKEY);
344 if (pub->key_alg != priv->key_alg ||
345 pub->func->computesecret == NULL ||
346 priv->func->computesecret == NULL)
347 return (DST_R_KEYCANNOTCOMPUTESECRET);
349 if (dst_key_isprivate(priv) == ISC_FALSE)
350 return (DST_R_NOTPRIVATEKEY);
352 return (pub->func->computesecret(pub, priv, secret));
356 dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
357 isc_result_t ret = ISC_R_SUCCESS;
359 REQUIRE(dst_initialized == ISC_TRUE);
360 REQUIRE(VALID_KEY(key));
361 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
363 CHECKALG(key->key_alg);
365 if (key->func->tofile == NULL)
366 return (DST_R_UNSUPPORTEDALG);
368 if (type & DST_TYPE_PUBLIC) {
369 ret = write_public_key(key, type, directory);
370 if (ret != ISC_R_SUCCESS)
374 if ((type & DST_TYPE_PRIVATE) &&
375 (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
376 return (key->func->tofile(key, directory));
378 return (ISC_R_SUCCESS);
382 dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
383 unsigned int alg, int type, const char *directory,
384 isc_mem_t *mctx, dst_key_t **keyp)
386 char filename[ISC_DIR_NAMEMAX];
391 REQUIRE(dst_initialized == ISC_TRUE);
392 REQUIRE(dns_name_isabsolute(name));
393 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
394 REQUIRE(mctx != NULL);
395 REQUIRE(keyp != NULL && *keyp == NULL);
399 isc_buffer_init(&b, filename, sizeof(filename));
400 result = buildfilename(name, id, alg, type, directory, &b);
401 if (result != ISC_R_SUCCESS)
405 result = dst_key_fromnamedfile(filename, type, mctx, &key);
406 if (result != ISC_R_SUCCESS)
409 result = computeid(key);
410 if (result != ISC_R_SUCCESS) {
415 if (!dns_name_equal(name, key->key_name) || id != key->key_id ||
416 alg != key->key_alg) {
418 return (DST_R_INVALIDPRIVATEKEY);
423 return (ISC_R_SUCCESS);
427 dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx,
431 dst_key_t *pubkey = NULL, *key = NULL;
433 char *newfilename = NULL;
434 int newfilenamelen = 0;
435 isc_lex_t *lex = NULL;
437 REQUIRE(dst_initialized == ISC_TRUE);
438 REQUIRE(filename != NULL);
439 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
440 REQUIRE(mctx != NULL);
441 REQUIRE(keyp != NULL && *keyp == NULL);
443 newfilenamelen = strlen(filename) + 5;
444 newfilename = isc_mem_get(mctx, newfilenamelen);
445 if (newfilename == NULL)
446 return (ISC_R_NOMEMORY);
447 result = addsuffix(newfilename, newfilenamelen, filename, ".key");
448 INSIST(result == ISC_R_SUCCESS);
450 result = dst_key_read_public(newfilename, type, mctx, &pubkey);
451 isc_mem_put(mctx, newfilename, newfilenamelen);
453 if (result != ISC_R_SUCCESS)
456 if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
457 (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
458 result = computeid(pubkey);
459 if (result != ISC_R_SUCCESS) {
460 dst_key_free(&pubkey);
465 return (ISC_R_SUCCESS);
468 result = algorithm_status(pubkey->key_alg);
469 if (result != ISC_R_SUCCESS) {
470 dst_key_free(&pubkey);
474 key = get_key_struct(pubkey->key_name, pubkey->key_alg,
475 pubkey->key_flags, pubkey->key_proto, 0,
476 pubkey->key_class, mctx);
478 dst_key_free(&pubkey);
481 return (ISC_R_NOMEMORY);
483 if (key->func->parse == NULL)
484 RETERR(DST_R_UNSUPPORTEDALG);
486 newfilenamelen = strlen(filename) + 9;
487 newfilename = isc_mem_get(mctx, newfilenamelen);
488 if (newfilename == NULL)
489 RETERR(ISC_R_NOMEMORY);
490 result = addsuffix(newfilename, newfilenamelen, filename, ".private");
491 INSIST(result == ISC_R_SUCCESS);
493 RETERR(isc_lex_create(mctx, 1500, &lex));
494 RETERR(isc_lex_openfile(lex, newfilename));
495 isc_mem_put(mctx, newfilename, newfilenamelen);
497 RETERR(key->func->parse(key, lex));
498 isc_lex_destroy(&lex);
500 RETERR(computeid(key));
502 if (id != key->key_id)
503 RETERR(DST_R_INVALIDPRIVATEKEY);
506 return (ISC_R_SUCCESS);
509 if (newfilename != NULL)
510 isc_mem_put(mctx, newfilename, newfilenamelen);
512 isc_lex_destroy(&lex);
518 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
519 REQUIRE(dst_initialized == ISC_TRUE);
520 REQUIRE(VALID_KEY(key));
521 REQUIRE(target != NULL);
523 CHECKALG(key->key_alg);
525 if (key->func->todns == NULL)
526 return (DST_R_UNSUPPORTEDALG);
528 if (isc_buffer_availablelength(target) < 4)
529 return (ISC_R_NOSPACE);
530 isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff));
531 isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto);
532 isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg);
534 if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
535 if (isc_buffer_availablelength(target) < 2)
536 return (ISC_R_NOSPACE);
537 isc_buffer_putuint16(target,
538 (isc_uint16_t)((key->key_flags >> 16)
542 if (key->keydata.generic == NULL) /*%< NULL KEY */
543 return (ISC_R_SUCCESS);
545 return (key->func->todns(key, target));
549 dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass,
550 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
552 isc_uint8_t alg, proto;
553 isc_uint32_t flags, extflags;
554 dst_key_t *key = NULL;
559 REQUIRE(dst_initialized);
561 isc_buffer_remainingregion(source, &r);
563 if (isc_buffer_remaininglength(source) < 4)
564 return (DST_R_INVALIDPUBLICKEY);
565 flags = isc_buffer_getuint16(source);
566 proto = isc_buffer_getuint8(source);
567 alg = isc_buffer_getuint8(source);
569 id = dst_region_computeid(&r, alg);
571 if (flags & DNS_KEYFLAG_EXTENDED) {
572 if (isc_buffer_remaininglength(source) < 2)
573 return (DST_R_INVALIDPUBLICKEY);
574 extflags = isc_buffer_getuint16(source);
575 flags |= (extflags << 16);
578 result = frombuffer(name, alg, flags, proto, rdclass, source,
580 if (result != ISC_R_SUCCESS)
585 return (ISC_R_SUCCESS);
589 dst_key_frombuffer(dns_name_t *name, unsigned int alg,
590 unsigned int flags, unsigned int protocol,
591 dns_rdataclass_t rdclass,
592 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
594 dst_key_t *key = NULL;
597 REQUIRE(dst_initialized);
599 result = frombuffer(name, alg, flags, protocol, rdclass, source,
601 if (result != ISC_R_SUCCESS)
604 result = computeid(key);
605 if (result != ISC_R_SUCCESS) {
611 return (ISC_R_SUCCESS);
615 dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
616 REQUIRE(dst_initialized == ISC_TRUE);
617 REQUIRE(VALID_KEY(key));
618 REQUIRE(target != NULL);
620 CHECKALG(key->key_alg);
622 if (key->func->todns == NULL)
623 return (DST_R_UNSUPPORTEDALG);
625 return (key->func->todns(key, target));
629 dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
630 isc_lex_t *lex = NULL;
631 isc_result_t result = ISC_R_SUCCESS;
633 REQUIRE(dst_initialized == ISC_TRUE);
634 REQUIRE(VALID_KEY(key));
635 REQUIRE(!dst_key_isprivate(key));
636 REQUIRE(buffer != NULL);
638 if (key->func->parse == NULL)
639 RETERR(DST_R_UNSUPPORTEDALG);
641 RETERR(isc_lex_create(key->mctx, 1500, &lex));
642 RETERR(isc_lex_openbuffer(lex, buffer));
643 RETERR(key->func->parse(key, lex));
646 isc_lex_destroy(&lex);
651 dst_key_getgssctx(const dst_key_t *key)
653 REQUIRE(key != NULL);
655 return (key->keydata.gssctx);
659 dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx,
664 REQUIRE(gssctx != NULL);
665 REQUIRE(keyp != NULL && *keyp == NULL);
667 key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
668 0, dns_rdataclass_in, mctx);
670 return (ISC_R_NOMEMORY);
672 key->keydata.gssctx = gssctx;
674 return (ISC_R_SUCCESS);
678 dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags,
679 unsigned int protocol, dns_rdataclass_t rdclass,
680 const char *engine, const char *label, const char *pin,
681 isc_mem_t *mctx, dst_key_t **keyp)
686 REQUIRE(dst_initialized == ISC_TRUE);
687 REQUIRE(dns_name_isabsolute(name));
688 REQUIRE(mctx != NULL);
689 REQUIRE(keyp != NULL && *keyp == NULL);
690 REQUIRE(label != NULL);
694 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx);
696 return (ISC_R_NOMEMORY);
698 if (key->func->fromlabel == NULL) {
700 return (DST_R_UNSUPPORTEDALG);
703 result = key->func->fromlabel(key, engine, label, pin);
704 if (result != ISC_R_SUCCESS) {
709 result = computeid(key);
710 if (result != ISC_R_SUCCESS) {
716 return (ISC_R_SUCCESS);
720 dst_key_generate(dns_name_t *name, unsigned int alg,
721 unsigned int bits, unsigned int param,
722 unsigned int flags, unsigned int protocol,
723 dns_rdataclass_t rdclass,
724 isc_mem_t *mctx, dst_key_t **keyp)
729 REQUIRE(dst_initialized == ISC_TRUE);
730 REQUIRE(dns_name_isabsolute(name));
731 REQUIRE(mctx != NULL);
732 REQUIRE(keyp != NULL && *keyp == NULL);
736 key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx);
738 return (ISC_R_NOMEMORY);
740 if (bits == 0) { /*%< NULL KEY */
741 key->key_flags |= DNS_KEYTYPE_NOKEY;
743 return (ISC_R_SUCCESS);
746 if (key->func->generate == NULL) {
748 return (DST_R_UNSUPPORTEDALG);
751 ret = key->func->generate(key, param);
752 if (ret != ISC_R_SUCCESS) {
757 ret = computeid(key);
758 if (ret != ISC_R_SUCCESS) {
764 return (ISC_R_SUCCESS);
768 dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
769 REQUIRE(dst_initialized == ISC_TRUE);
770 REQUIRE(VALID_KEY(key1));
771 REQUIRE(VALID_KEY(key2));
775 if (key1 == NULL || key2 == NULL)
777 if (key1->key_alg == key2->key_alg &&
778 key1->key_id == key2->key_id &&
779 key1->func->compare != NULL &&
780 key1->func->compare(key1, key2) == ISC_TRUE)
787 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
788 REQUIRE(dst_initialized == ISC_TRUE);
789 REQUIRE(VALID_KEY(key1));
790 REQUIRE(VALID_KEY(key2));
794 if (key1 == NULL || key2 == NULL)
796 if (key1->key_alg == key2->key_alg &&
797 key1->func->paramcompare != NULL &&
798 key1->func->paramcompare(key1, key2) == ISC_TRUE)
805 dst_key_attach(dst_key_t *source, dst_key_t **target) {
807 REQUIRE(dst_initialized == ISC_TRUE);
808 REQUIRE(target != NULL && *target == NULL);
809 REQUIRE(VALID_KEY(source));
811 isc_refcount_increment(&source->refs, NULL);
816 dst_key_free(dst_key_t **keyp) {
821 REQUIRE(dst_initialized == ISC_TRUE);
822 REQUIRE(keyp != NULL && VALID_KEY(*keyp));
827 isc_refcount_decrement(&key->refs, &refs);
831 isc_refcount_destroy(&key->refs);
832 if (key->keydata.generic != NULL) {
833 INSIST(key->func->destroy != NULL);
834 key->func->destroy(key);
836 if (key->engine != NULL)
837 isc_mem_free(mctx, key->engine);
838 if (key->label != NULL)
839 isc_mem_free(mctx, key->label);
840 dns_name_free(key->key_name, mctx);
841 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
842 memset(key, 0, sizeof(dst_key_t));
843 isc_mem_put(mctx, key, sizeof(dst_key_t));
848 dst_key_isprivate(const dst_key_t *key) {
849 REQUIRE(VALID_KEY(key));
850 INSIST(key->func->isprivate != NULL);
851 return (key->func->isprivate(key));
855 dst_key_buildfilename(const dst_key_t *key, int type,
856 const char *directory, isc_buffer_t *out) {
858 REQUIRE(VALID_KEY(key));
859 REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
862 return (buildfilename(key->key_name, key->key_id, key->key_alg,
863 type, directory, out));
867 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
868 REQUIRE(dst_initialized == ISC_TRUE);
869 REQUIRE(VALID_KEY(key));
872 /* XXXVIX this switch statement is too sparse to gen a jump table. */
873 switch (key->key_alg) {
875 case DST_ALG_RSASHA1:
876 case DST_ALG_NSEC3RSASHA1:
877 case DST_ALG_RSASHA256:
878 case DST_ALG_RSASHA512:
879 *n = (key->key_size + 7) / 8;
882 case DST_ALG_NSEC3DSA:
883 *n = DNS_SIG_DSASIGSIZE;
885 case DST_ALG_HMACMD5:
888 case DST_ALG_HMACSHA1:
889 *n = ISC_SHA1_DIGESTLENGTH;
891 case DST_ALG_HMACSHA224:
892 *n = ISC_SHA224_DIGESTLENGTH;
894 case DST_ALG_HMACSHA256:
895 *n = ISC_SHA256_DIGESTLENGTH;
897 case DST_ALG_HMACSHA384:
898 *n = ISC_SHA384_DIGESTLENGTH;
900 case DST_ALG_HMACSHA512:
901 *n = ISC_SHA512_DIGESTLENGTH;
904 *n = 128; /*%< XXX */
908 return (DST_R_UNSUPPORTEDALG);
910 return (ISC_R_SUCCESS);
914 dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
915 REQUIRE(dst_initialized == ISC_TRUE);
916 REQUIRE(VALID_KEY(key));
919 if (key->key_alg == DST_ALG_DH)
920 *n = (key->key_size + 7) / 8;
922 return (DST_R_UNSUPPORTEDALG);
923 return (ISC_R_SUCCESS);
931 * Allocates a key structure and fills in some of the fields.
934 get_key_struct(dns_name_t *name, unsigned int alg,
935 unsigned int flags, unsigned int protocol,
936 unsigned int bits, dns_rdataclass_t rdclass,
942 key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t));
946 memset(key, 0, sizeof(dst_key_t));
947 key->magic = KEY_MAGIC;
949 result = isc_refcount_init(&key->refs, 1);
950 if (result != ISC_R_SUCCESS) {
951 isc_mem_put(mctx, key, sizeof(dst_key_t));
955 key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
956 if (key->key_name == NULL) {
957 isc_refcount_destroy(&key->refs);
958 isc_mem_put(mctx, key, sizeof(dst_key_t));
961 dns_name_init(key->key_name, NULL);
962 result = dns_name_dup(name, mctx, key->key_name);
963 if (result != ISC_R_SUCCESS) {
964 isc_refcount_destroy(&key->refs);
965 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
966 isc_mem_put(mctx, key, sizeof(dst_key_t));
970 key->key_flags = flags;
971 key->key_proto = protocol;
973 key->keydata.generic = NULL;
974 key->key_size = bits;
975 key->key_class = rdclass;
976 key->func = dst_t_func[alg];
981 * Reads a public key from disk
984 dst_key_read_public(const char *filename, int type,
985 isc_mem_t *mctx, dst_key_t **keyp)
987 u_char rdatabuf[DST_KEY_MAXSIZE];
989 dns_fixedname_t name;
990 isc_lex_t *lex = NULL;
993 dns_rdata_t rdata = DNS_RDATA_INIT;
994 unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
995 dns_rdataclass_t rdclass = dns_rdataclass_in;
996 isc_lexspecials_t specials;
999 dns_rdatatype_t keytype;
1002 * Open the file and read its formatted contents
1004 * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key>
1007 /* 1500 should be large enough for any key */
1008 ret = isc_lex_create(mctx, 1500, &lex);
1009 if (ret != ISC_R_SUCCESS)
1012 memset(specials, 0, sizeof(specials));
1016 isc_lex_setspecials(lex, specials);
1017 isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
1019 ret = isc_lex_openfile(lex, filename);
1020 if (ret != ISC_R_SUCCESS)
1023 #define NEXTTOKEN(lex, opt, token) { \
1024 ret = isc_lex_gettoken(lex, opt, token); \
1025 if (ret != ISC_R_SUCCESS) \
1029 #define BADTOKEN() { \
1030 ret = ISC_R_UNEXPECTEDTOKEN; \
1034 /* Read the domain name */
1035 NEXTTOKEN(lex, opt, &token);
1036 if (token.type != isc_tokentype_string)
1040 * We don't support "@" in .key files.
1042 if (!strcmp(DST_AS_STR(token), "@"))
1045 dns_fixedname_init(&name);
1046 isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
1047 isc_buffer_add(&b, strlen(DST_AS_STR(token)));
1048 ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname,
1050 if (ret != ISC_R_SUCCESS)
1053 /* Read the next word: either TTL, class, or 'KEY' */
1054 NEXTTOKEN(lex, opt, &token);
1056 if (token.type != isc_tokentype_string)
1059 /* If it's a TTL, read the next one */
1060 result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
1061 if (result == ISC_R_SUCCESS)
1062 NEXTTOKEN(lex, opt, &token);
1064 if (token.type != isc_tokentype_string)
1067 ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
1068 if (ret == ISC_R_SUCCESS)
1069 NEXTTOKEN(lex, opt, &token);
1071 if (token.type != isc_tokentype_string)
1074 if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0)
1075 keytype = dns_rdatatype_dnskey;
1076 else if (strcasecmp(DST_AS_STR(token), "KEY") == 0)
1077 keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */
1081 if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
1082 ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) {
1083 ret = DST_R_BADKEYTYPE;
1087 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1088 ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL,
1089 ISC_FALSE, mctx, &b, NULL);
1090 if (ret != ISC_R_SUCCESS)
1093 ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
1095 if (ret != ISC_R_SUCCESS)
1100 isc_lex_destroy(&lex);
1104 static isc_boolean_t
1105 issymmetric(const dst_key_t *key) {
1106 REQUIRE(dst_initialized == ISC_TRUE);
1107 REQUIRE(VALID_KEY(key));
1109 /* XXXVIX this switch statement is too sparse to gen a jump table. */
1110 switch (key->key_alg) {
1111 case DST_ALG_RSAMD5:
1112 case DST_ALG_RSASHA1:
1113 case DST_ALG_NSEC3RSASHA1:
1114 case DST_ALG_RSASHA256:
1115 case DST_ALG_RSASHA512:
1117 case DST_ALG_NSEC3DSA:
1120 case DST_ALG_HMACMD5:
1121 case DST_ALG_GSSAPI:
1129 * Writes a public key to disk in DNS format.
1132 write_public_key(const dst_key_t *key, int type, const char *directory) {
1134 isc_buffer_t keyb, textb, fileb, classb;
1136 char filename[ISC_DIR_NAMEMAX];
1137 unsigned char key_array[DST_KEY_MAXSIZE];
1138 char text_array[DST_KEY_MAXTEXTSIZE];
1139 char class_array[10];
1141 dns_rdata_t rdata = DNS_RDATA_INIT;
1142 isc_fsaccess_t access;
1144 REQUIRE(VALID_KEY(key));
1146 isc_buffer_init(&keyb, key_array, sizeof(key_array));
1147 isc_buffer_init(&textb, text_array, sizeof(text_array));
1148 isc_buffer_init(&classb, class_array, sizeof(class_array));
1150 ret = dst_key_todns(key, &keyb);
1151 if (ret != ISC_R_SUCCESS)
1154 isc_buffer_usedregion(&keyb, &r);
1155 dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
1157 ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
1158 if (ret != ISC_R_SUCCESS)
1159 return (DST_R_INVALIDPUBLICKEY);
1161 ret = dns_rdataclass_totext(key->key_class, &classb);
1162 if (ret != ISC_R_SUCCESS)
1163 return (DST_R_INVALIDPUBLICKEY);
1166 * Make the filename.
1168 isc_buffer_init(&fileb, filename, sizeof(filename));
1169 ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
1170 if (ret != ISC_R_SUCCESS)
1174 * Create public key file.
1176 if ((fp = fopen(filename, "w")) == NULL)
1177 return (DST_R_WRITEERROR);
1179 if (issymmetric(key)) {
1181 isc_fsaccess_add(ISC_FSACCESS_OWNER,
1182 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
1184 (void)isc_fsaccess_set(filename, access);
1187 ret = dns_name_print(key->key_name, fp);
1188 if (ret != ISC_R_SUCCESS) {
1195 isc_buffer_usedregion(&classb, &r);
1196 isc_util_fwrite(r.base, 1, r.length, fp);
1198 if ((type & DST_TYPE_KEY) != 0)
1199 fprintf(fp, " KEY ");
1201 fprintf(fp, " DNSKEY ");
1203 isc_buffer_usedregion(&textb, &r);
1204 isc_util_fwrite(r.base, 1, r.length, fp);
1209 ret = DST_R_WRITEERROR;
1216 buildfilename(dns_name_t *name, dns_keytag_t id,
1217 unsigned int alg, unsigned int type,
1218 const char *directory, isc_buffer_t *out)
1220 const char *suffix = "";
1222 isc_result_t result;
1224 REQUIRE(out != NULL);
1225 if ((type & DST_TYPE_PRIVATE) != 0)
1226 suffix = ".private";
1227 else if (type == DST_TYPE_PUBLIC)
1229 if (directory != NULL) {
1230 if (isc_buffer_availablelength(out) < strlen(directory))
1231 return (ISC_R_NOSPACE);
1232 isc_buffer_putstr(out, directory);
1233 if (strlen(directory) > 0U &&
1234 directory[strlen(directory) - 1] != '/')
1235 isc_buffer_putstr(out, "/");
1237 if (isc_buffer_availablelength(out) < 1)
1238 return (ISC_R_NOSPACE);
1239 isc_buffer_putstr(out, "K");
1240 result = dns_name_tofilenametext(name, ISC_FALSE, out);
1241 if (result != ISC_R_SUCCESS)
1243 len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
1244 if (isc_buffer_availablelength(out) < len)
1245 return (ISC_R_NOSPACE);
1246 sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id,
1248 isc_buffer_add(out, len);
1250 return (ISC_R_SUCCESS);
1254 computeid(dst_key_t *key) {
1255 isc_buffer_t dnsbuf;
1256 unsigned char dns_array[DST_KEY_MAXSIZE];
1260 isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
1261 ret = dst_key_todns(key, &dnsbuf);
1262 if (ret != ISC_R_SUCCESS)
1265 isc_buffer_usedregion(&dnsbuf, &r);
1266 key->key_id = dst_region_computeid(&r, key->key_alg);
1267 return (ISC_R_SUCCESS);
1271 frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags,
1272 unsigned int protocol, dns_rdataclass_t rdclass,
1273 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
1278 REQUIRE(dns_name_isabsolute(name));
1279 REQUIRE(source != NULL);
1280 REQUIRE(mctx != NULL);
1281 REQUIRE(keyp != NULL && *keyp == NULL);
1283 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx);
1285 return (ISC_R_NOMEMORY);
1287 if (isc_buffer_remaininglength(source) > 0) {
1288 ret = algorithm_status(alg);
1289 if (ret != ISC_R_SUCCESS) {
1293 if (key->func->fromdns == NULL) {
1295 return (DST_R_UNSUPPORTEDALG);
1298 ret = key->func->fromdns(key, source);
1299 if (ret != ISC_R_SUCCESS) {
1306 return (ISC_R_SUCCESS);
1310 algorithm_status(unsigned int alg) {
1311 REQUIRE(dst_initialized == ISC_TRUE);
1313 if (dst_algorithm_supported(alg))
1314 return (ISC_R_SUCCESS);
1316 if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
1317 alg == DST_ALG_DSA || alg == DST_ALG_DH ||
1318 alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA ||
1319 alg == DST_ALG_NSEC3RSASHA1 ||
1320 alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512)
1321 return (DST_R_NOCRYPTO);
1323 return (DST_R_UNSUPPORTEDALG);
1327 addsuffix(char *filename, unsigned int len, const char *ofilename,
1330 int olen = strlen(ofilename);
1333 if (olen > 1 && ofilename[olen - 1] == '.')
1335 else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0)
1337 else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0)
1340 n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
1342 return (ISC_R_FAILURE);
1343 if ((unsigned int)n >= len)
1344 return (ISC_R_NOSPACE);
1345 return (ISC_R_SUCCESS);
1349 dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
1350 unsigned int flags = dst_entropy_flags;
1353 return (ISC_R_SUCCESS);
1355 flags &= ~ISC_ENTROPY_GOODONLY;
1356 return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));
1360 dst__entropy_status(void) {
1362 unsigned int flags = dst_entropy_flags;
1364 unsigned char buf[32];
1365 static isc_boolean_t first = ISC_TRUE;
1368 /* Someone believes RAND_status() initializes the PRNG */
1369 flags &= ~ISC_ENTROPY_GOODONLY;
1370 ret = isc_entropy_getdata(dst_entropy_pool, buf,
1371 sizeof(buf), NULL, flags);
1372 INSIST(ret == ISC_R_SUCCESS);
1373 isc_entropy_putdata(dst_entropy_pool, buf,
1374 sizeof(buf), 2 * sizeof(buf));
1378 return (isc_entropy_status(dst_entropy_pool));