2 * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2001, 2003 Internet Software Consortium.
4 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
11 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
13 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * Principal Author: Brian Wellington
21 * $Id: dst_api.c,v 1.88.2.6 2004/03/09 06:11:39 marka Exp $
28 #include <isc/buffer.h>
30 #include <isc/entropy.h>
31 #include <isc/fsaccess.h>
35 #include <isc/print.h>
36 #include <isc/random.h>
37 #include <isc/string.h>
41 #include <dns/fixedname.h>
43 #include <dns/rdata.h>
44 #include <dns/rdataclass.h>
45 #include <dns/types.h>
46 #include <dns/keyvalues.h>
48 #include <dst/result.h>
50 #include "dst_internal.h"
52 static dst_func_t *dst_t_func[DST_MAX_ALGS];
53 static isc_mem_t *dst_memory_pool = NULL;
54 static isc_entropy_t *dst_entropy_pool = NULL;
55 static unsigned int dst_entropy_flags = 0;
56 static isc_boolean_t dst_initialized = ISC_FALSE;
61 static dst_key_t * get_key_struct(dns_name_t *name,
64 unsigned int protocol,
66 dns_rdataclass_t rdclass,
68 static isc_result_t read_public_key(const char *filename,
71 static isc_result_t write_public_key(const dst_key_t *key,
72 const char *directory);
73 static isc_result_t buildfilename(dns_name_t *name,
77 const char *directory,
79 static isc_result_t computeid(dst_key_t *key);
80 static isc_result_t frombuffer(dns_name_t *name,
83 unsigned int protocol,
84 dns_rdataclass_t rdclass,
89 static isc_result_t algorithm_status(unsigned int alg);
94 if (result != ISC_R_SUCCESS) \
98 #define CHECKALG(alg) \
101 _r = algorithm_status(alg); \
102 if (_r != ISC_R_SUCCESS) \
107 dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) {
110 REQUIRE(mctx != NULL && ectx != NULL);
111 REQUIRE(dst_initialized == ISC_FALSE);
113 dst_memory_pool = NULL;
118 * When using --with-openssl, there seems to be no good way of not
119 * leaking memory due to the openssl error handling mechanism.
120 * Avoid assertions by using a local memory context and not checking
123 result = isc_mem_create(0, 0, &dst_memory_pool);
124 if (result != ISC_R_SUCCESS)
126 isc_mem_setdestroycheck(dst_memory_pool, ISC_FALSE);
128 isc_mem_attach(mctx, &dst_memory_pool);
130 isc_entropy_attach(ectx, &dst_entropy_pool);
131 dst_entropy_flags = eflags;
133 dst_result_register();
135 memset(dst_t_func, 0, sizeof(dst_t_func));
136 RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
138 RETERR(dst__openssl_init());
139 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5]));
140 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA]));
141 RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
144 RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
147 dst_initialized = ISC_TRUE;
148 return (ISC_R_SUCCESS);
156 dst_lib_destroy(void) {
157 RUNTIME_CHECK(dst_initialized == ISC_TRUE);
158 dst_initialized = ISC_FALSE;
160 dst__hmacmd5_destroy();
162 dst__opensslrsa_destroy();
163 dst__openssldsa_destroy();
164 dst__openssldh_destroy();
165 dst__openssl_destroy();
168 dst__gssapi_destroy();
170 if (dst_memory_pool != NULL)
171 isc_mem_detach(&dst_memory_pool);
172 if (dst_entropy_pool != NULL)
173 isc_entropy_detach(&dst_entropy_pool);
178 dst_algorithm_supported(unsigned int alg) {
179 REQUIRE(dst_initialized == ISC_TRUE);
181 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
187 dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
191 REQUIRE(dst_initialized == ISC_TRUE);
192 REQUIRE(VALID_KEY(key));
193 REQUIRE(mctx != NULL);
194 REQUIRE(dctxp != NULL && *dctxp == NULL);
196 if (key->func->createctx == NULL)
197 return (DST_R_UNSUPPORTEDALG);
198 if (key->opaque == NULL)
199 return (DST_R_NULLKEY);
201 dctx = isc_mem_get(mctx, sizeof(dst_context_t));
203 return (ISC_R_NOMEMORY);
206 result = key->func->createctx(key, dctx);
207 if (result != ISC_R_SUCCESS) {
208 isc_mem_put(mctx, dctx, sizeof(dst_context_t));
211 dctx->magic = CTX_MAGIC;
213 return (ISC_R_SUCCESS);
217 dst_context_destroy(dst_context_t **dctxp) {
220 REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
223 INSIST(dctx->key->func->destroyctx != NULL);
224 dctx->key->func->destroyctx(dctx);
226 isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t));
231 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
232 REQUIRE(VALID_CTX(dctx));
233 REQUIRE(data != NULL);
234 INSIST(dctx->key->func->adddata != NULL);
236 return (dctx->key->func->adddata(dctx, data));
240 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
241 REQUIRE(VALID_CTX(dctx));
242 REQUIRE(sig != NULL);
244 CHECKALG(dctx->key->key_alg);
245 if (dctx->key->opaque == NULL)
246 return (DST_R_NULLKEY);
247 if (dctx->key->func->sign == NULL)
248 return (DST_R_NOTPRIVATEKEY);
250 return (dctx->key->func->sign(dctx, sig));
254 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
255 REQUIRE(VALID_CTX(dctx));
256 REQUIRE(sig != NULL);
258 CHECKALG(dctx->key->key_alg);
259 if (dctx->key->opaque == NULL)
260 return (DST_R_NULLKEY);
261 if (dctx->key->func->verify == NULL)
262 return (DST_R_NOTPUBLICKEY);
264 return (dctx->key->func->verify(dctx, sig));
268 dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
269 isc_buffer_t *secret)
271 REQUIRE(dst_initialized == ISC_TRUE);
272 REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
273 REQUIRE(secret != NULL);
275 CHECKALG(pub->key_alg);
276 CHECKALG(priv->key_alg);
278 if (pub->opaque == NULL || priv->opaque == NULL)
279 return (DST_R_NULLKEY);
281 if (pub->key_alg != priv->key_alg ||
282 pub->func->computesecret == NULL ||
283 priv->func->computesecret == NULL)
284 return (DST_R_KEYCANNOTCOMPUTESECRET);
286 if (dst_key_isprivate(priv) == ISC_FALSE)
287 return (DST_R_NOTPRIVATEKEY);
289 return (pub->func->computesecret(pub, priv, secret));
293 dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
294 isc_result_t ret = ISC_R_SUCCESS;
296 REQUIRE(dst_initialized == ISC_TRUE);
297 REQUIRE(VALID_KEY(key));
298 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
300 CHECKALG(key->key_alg);
302 if (key->func->tofile == NULL)
303 return (DST_R_UNSUPPORTEDALG);
305 if (type & DST_TYPE_PUBLIC) {
306 ret = write_public_key(key, directory);
307 if (ret != ISC_R_SUCCESS)
311 if ((type & DST_TYPE_PRIVATE) &&
312 (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
313 return (key->func->tofile(key, directory));
315 return (ISC_R_SUCCESS);
319 dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
320 unsigned int alg, int type, const char *directory,
321 isc_mem_t *mctx, dst_key_t **keyp)
323 char filename[ISC_DIR_NAMEMAX];
328 REQUIRE(dst_initialized == ISC_TRUE);
329 REQUIRE(dns_name_isabsolute(name));
330 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
331 REQUIRE(mctx != NULL);
332 REQUIRE(keyp != NULL && *keyp == NULL);
336 isc_buffer_init(&b, filename, sizeof filename);
337 result = buildfilename(name, id, alg, type, directory, &b);
338 if (result != ISC_R_SUCCESS)
342 result = dst_key_fromnamedfile(filename, type, mctx, &key);
343 if (result != ISC_R_SUCCESS)
346 result = computeid(key);
347 if (result != ISC_R_SUCCESS) {
352 if (!dns_name_equal(name, key->key_name) ||
357 return (DST_R_INVALIDPRIVATEKEY);
362 return (ISC_R_SUCCESS);
366 dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx,
370 dst_key_t *pubkey = NULL, *key = NULL;
373 REQUIRE(dst_initialized == ISC_TRUE);
374 REQUIRE(filename != NULL);
375 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
376 REQUIRE(mctx != NULL);
377 REQUIRE(keyp != NULL && *keyp == NULL);
379 result = read_public_key(filename, mctx, &pubkey);
380 if (result != ISC_R_SUCCESS)
383 if (type == DST_TYPE_PUBLIC ||
384 (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY)
386 result = computeid(pubkey);
387 if (result != ISC_R_SUCCESS) {
388 dst_key_free(&pubkey);
393 return (ISC_R_SUCCESS);
396 key = get_key_struct(pubkey->key_name, pubkey->key_alg,
397 pubkey->key_flags, pubkey->key_proto, 0,
398 pubkey->key_class, mctx);
400 dst_key_free(&pubkey);
403 return (ISC_R_NOMEMORY);
405 if (key->func->fromfile == NULL) {
407 return (DST_R_UNSUPPORTEDALG);
410 result = key->func->fromfile(key, filename);
411 if (result != ISC_R_SUCCESS) {
416 result = computeid(key);
417 if (result != ISC_R_SUCCESS) {
422 if (id != key->key_id) {
424 return (DST_R_INVALIDPRIVATEKEY);
428 return (ISC_R_SUCCESS);
432 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
433 REQUIRE(dst_initialized == ISC_TRUE);
434 REQUIRE(VALID_KEY(key));
435 REQUIRE(target != NULL);
437 CHECKALG(key->key_alg);
439 if (key->func->todns == NULL)
440 return (DST_R_UNSUPPORTEDALG);
442 if (isc_buffer_availablelength(target) < 4)
443 return (ISC_R_NOSPACE);
444 isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff));
445 isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto);
446 isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg);
448 if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
449 if (isc_buffer_availablelength(target) < 2)
450 return (ISC_R_NOSPACE);
451 isc_buffer_putuint16(target,
452 (isc_uint16_t)((key->key_flags >> 16)
456 if (key->opaque == NULL) /* NULL KEY */
457 return (ISC_R_SUCCESS);
459 return (key->func->todns(key, target));
463 dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass,
464 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
466 isc_uint8_t alg, proto;
467 isc_uint32_t flags, extflags;
468 dst_key_t *key = NULL;
473 REQUIRE(dst_initialized);
475 isc_buffer_remainingregion(source, &r);
477 if (isc_buffer_remaininglength(source) < 4)
478 return (DST_R_INVALIDPUBLICKEY);
479 flags = isc_buffer_getuint16(source);
480 proto = isc_buffer_getuint8(source);
481 alg = isc_buffer_getuint8(source);
485 id = dst_region_computeid(&r, alg);
487 if (flags & DNS_KEYFLAG_EXTENDED) {
488 if (isc_buffer_remaininglength(source) < 2)
489 return (DST_R_INVALIDPUBLICKEY);
490 extflags = isc_buffer_getuint16(source);
491 flags |= (extflags << 16);
494 result = frombuffer(name, alg, flags, proto, rdclass, source,
496 if (result != ISC_R_SUCCESS)
501 return (ISC_R_SUCCESS);
505 dst_key_frombuffer(dns_name_t *name, unsigned int alg,
506 unsigned int flags, unsigned int protocol,
507 dns_rdataclass_t rdclass,
508 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
510 dst_key_t *key = NULL;
513 REQUIRE(dst_initialized);
517 result = frombuffer(name, alg, flags, protocol, rdclass, source,
519 if (result != ISC_R_SUCCESS)
522 result = computeid(key);
523 if (result != ISC_R_SUCCESS) {
529 return (ISC_R_SUCCESS);
533 dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
534 REQUIRE(dst_initialized == ISC_TRUE);
535 REQUIRE(VALID_KEY(key));
536 REQUIRE(target != NULL);
538 CHECKALG(key->key_alg);
540 if (key->func->todns == NULL)
541 return (DST_R_UNSUPPORTEDALG);
543 return (key->func->todns(key, target));
547 dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx,
552 REQUIRE(opaque != NULL);
553 REQUIRE(keyp != NULL && *keyp == NULL);
555 key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
556 0, dns_rdataclass_in, mctx);
558 return (ISC_R_NOMEMORY);
559 key->opaque = opaque;
561 return (ISC_R_SUCCESS);
565 dst_key_generate(dns_name_t *name, unsigned int alg,
566 unsigned int bits, unsigned int param,
567 unsigned int flags, unsigned int protocol,
568 dns_rdataclass_t rdclass,
569 isc_mem_t *mctx, dst_key_t **keyp)
574 REQUIRE(dst_initialized == ISC_TRUE);
575 REQUIRE(dns_name_isabsolute(name));
576 REQUIRE(mctx != NULL);
577 REQUIRE(keyp != NULL && *keyp == NULL);
581 key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx);
583 return (ISC_R_NOMEMORY);
585 if (bits == 0) { /* NULL KEY */
586 key->key_flags |= DNS_KEYTYPE_NOKEY;
588 return (ISC_R_SUCCESS);
591 if (key->func->generate == NULL) {
593 return (DST_R_UNSUPPORTEDALG);
596 ret = key->func->generate(key, param);
597 if (ret != ISC_R_SUCCESS) {
602 ret = computeid(key);
603 if (ret != ISC_R_SUCCESS) {
609 return (ISC_R_SUCCESS);
613 dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
614 REQUIRE(dst_initialized == ISC_TRUE);
615 REQUIRE(VALID_KEY(key1));
616 REQUIRE(VALID_KEY(key2));
620 if (key1 == NULL || key2 == NULL)
622 if (key1->key_alg == key2->key_alg &&
623 key1->key_id == key2->key_id &&
624 key1->func->compare != NULL &&
625 key1->func->compare(key1, key2) == ISC_TRUE)
632 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
633 REQUIRE(dst_initialized == ISC_TRUE);
634 REQUIRE(VALID_KEY(key1));
635 REQUIRE(VALID_KEY(key2));
639 if (key1 == NULL || key2 == NULL)
641 if (key1->key_alg == key2->key_alg &&
642 key1->func->paramcompare != NULL &&
643 key1->func->paramcompare(key1, key2) == ISC_TRUE)
650 dst_key_free(dst_key_t **keyp) {
654 REQUIRE(dst_initialized == ISC_TRUE);
655 REQUIRE(keyp != NULL && VALID_KEY(*keyp));
660 INSIST(key->func->destroy != NULL);
662 if (key->opaque != NULL)
663 key->func->destroy(key);
665 dns_name_free(key->key_name, mctx);
666 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
667 memset(key, 0, sizeof(dst_key_t));
668 isc_mem_put(mctx, key, sizeof(dst_key_t));
673 dst_key_isprivate(const dst_key_t *key) {
674 REQUIRE(VALID_KEY(key));
675 INSIST(key->func->isprivate != NULL);
676 return (key->func->isprivate(key));
680 dst_key_buildfilename(const dst_key_t *key, int type,
681 const char *directory, isc_buffer_t *out) {
683 REQUIRE(VALID_KEY(key));
684 REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
687 return (buildfilename(key->key_name, key->key_id, key->key_alg,
688 type, directory, out));
692 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
693 REQUIRE(dst_initialized == ISC_TRUE);
694 REQUIRE(VALID_KEY(key));
697 /* XXXVIX this switch statement is too sparse to gen a jump table. */
698 switch (key->key_alg) {
700 *n = (key->key_size + 7) / 8;
703 *n = DNS_SIG_DSASIGSIZE;
705 case DST_ALG_HMACMD5:
713 return (DST_R_UNSUPPORTEDALG);
715 return (ISC_R_SUCCESS);
719 dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
720 REQUIRE(dst_initialized == ISC_TRUE);
721 REQUIRE(VALID_KEY(key));
724 if (key->key_alg == DST_ALG_DH)
725 *n = (key->key_size + 7) / 8;
727 return (DST_R_UNSUPPORTEDALG);
728 return (ISC_R_SUCCESS);
736 * Allocates a key structure and fills in some of the fields.
739 get_key_struct(dns_name_t *name, unsigned int alg,
740 unsigned int flags, unsigned int protocol,
741 unsigned int bits, dns_rdataclass_t rdclass,
747 REQUIRE(dst_algorithm_supported(alg) != ISC_FALSE);
749 key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t));
753 memset(key, 0, sizeof(dst_key_t));
754 key->magic = KEY_MAGIC;
756 key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
757 if (key->key_name == NULL) {
758 isc_mem_put(mctx, key, sizeof(dst_key_t));
761 dns_name_init(key->key_name, NULL);
762 result = dns_name_dup(name, mctx, key->key_name);
763 if (result != ISC_R_SUCCESS) {
764 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
765 isc_mem_put(mctx, key, sizeof(dst_key_t));
769 key->key_flags = flags;
770 key->key_proto = protocol;
773 key->key_size = bits;
774 key->key_class = rdclass;
775 key->func = dst_t_func[alg];
780 * Reads a public key from disk
783 read_public_key(const char *filename, isc_mem_t *mctx, dst_key_t **keyp) {
784 u_char rdatabuf[DST_KEY_MAXSIZE];
786 dns_fixedname_t name;
787 isc_lex_t *lex = NULL;
790 dns_rdata_t rdata = DNS_RDATA_INIT;
791 unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
793 unsigned int newfilenamelen;
795 dns_rdataclass_t rdclass = dns_rdataclass_in;
797 newfilenamelen = strlen(filename) + 5;
798 newfilename = isc_mem_get(mctx, newfilenamelen);
799 if (newfilename == NULL)
800 return (ISC_R_NOMEMORY);
801 ret = dst__file_addsuffix(newfilename, newfilenamelen, filename,
803 INSIST(ret == ISC_R_SUCCESS);
806 * Open the file and read its formatted contents
808 * domain.name [ttl] [class] KEY <flags> <protocol> <algorithm> <key>
811 /* 1500 should be large enough for any key */
812 ret = isc_lex_create(mctx, 1500, &lex);
813 if (ret != ISC_R_SUCCESS)
816 ret = isc_lex_openfile(lex, newfilename);
817 if (ret != ISC_R_SUCCESS)
820 #define NEXTTOKEN(lex, opt, token) { \
821 ret = isc_lex_gettoken(lex, opt, token); \
822 if (ret != ISC_R_SUCCESS) \
826 #define BADTOKEN() { \
827 ret = ISC_R_UNEXPECTEDTOKEN; \
831 /* Read the domain name */
832 NEXTTOKEN(lex, opt, &token);
833 if (token.type != isc_tokentype_string)
835 dns_fixedname_init(&name);
836 isc_buffer_init(&b, token.value.as_pointer,
837 strlen(token.value.as_pointer));
838 isc_buffer_add(&b, strlen(token.value.as_pointer));
839 ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname,
841 if (ret != ISC_R_SUCCESS)
844 /* Read the next word: either TTL, class, or 'KEY' */
845 NEXTTOKEN(lex, opt, &token);
847 /* If it's a TTL, read the next one */
848 if (token.type == isc_tokentype_number)
849 NEXTTOKEN(lex, opt, &token);
851 if (token.type != isc_tokentype_string)
854 r.base = token.value.as_pointer;
855 r.length = strlen(r.base);
856 ret = dns_rdataclass_fromtext(&rdclass, &r);
857 if (ret == ISC_R_SUCCESS)
858 NEXTTOKEN(lex, opt, &token);
860 if (token.type != isc_tokentype_string)
863 if (strcasecmp(token.value.as_pointer, "KEY") != 0)
866 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
867 ret = dns_rdata_fromtext(&rdata, rdclass, dns_rdatatype_key,
868 lex, NULL, ISC_FALSE, mctx, &b, NULL);
869 if (ret != ISC_R_SUCCESS)
872 ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
874 if (ret != ISC_R_SUCCESS)
880 isc_lex_destroy(&lex);
882 isc_mem_put(mctx, newfilename, newfilenamelen);
888 * Writes a public key to disk in DNS format.
891 write_public_key(const dst_key_t *key, const char *directory) {
893 isc_buffer_t keyb, textb, fileb, classb;
895 char filename[ISC_DIR_NAMEMAX];
896 unsigned char key_array[DST_KEY_MAXSIZE];
897 char text_array[DST_KEY_MAXTEXTSIZE];
898 char class_array[10];
900 dns_rdata_t rdata = DNS_RDATA_INIT;
901 isc_fsaccess_t access;
903 REQUIRE(VALID_KEY(key));
905 isc_buffer_init(&keyb, key_array, sizeof(key_array));
906 isc_buffer_init(&textb, text_array, sizeof(text_array));
907 isc_buffer_init(&classb, class_array, sizeof(class_array));
909 ret = dst_key_todns(key, &keyb);
910 if (ret != ISC_R_SUCCESS)
913 isc_buffer_usedregion(&keyb, &r);
914 dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_key, &r);
916 ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
917 if (ret != ISC_R_SUCCESS)
918 return (DST_R_INVALIDPUBLICKEY);
920 ret = dns_rdataclass_totext(key->key_class, &classb);
921 if (ret != ISC_R_SUCCESS)
922 return (DST_R_INVALIDPUBLICKEY);
927 isc_buffer_init(&fileb, filename, sizeof(filename));
928 ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
929 if (ret != ISC_R_SUCCESS)
933 * Create public key file.
935 if ((fp = fopen(filename, "w")) == NULL)
936 return (DST_R_WRITEERROR);
938 if (key->func->issymmetric()) {
940 isc_fsaccess_add(ISC_FSACCESS_OWNER,
941 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
943 (void)isc_fsaccess_set(filename, access);
946 ret = dns_name_print(key->key_name, fp);
947 if (ret != ISC_R_SUCCESS)
952 isc_buffer_usedregion(&classb, &r);
953 fwrite(r.base, 1, r.length, fp);
955 fprintf(fp, " KEY ");
957 isc_buffer_usedregion(&textb, &r);
958 fwrite(r.base, 1, r.length, fp);
963 return (ISC_R_SUCCESS);
967 buildfilename(dns_name_t *name, dns_keytag_t id,
968 unsigned int alg, unsigned int type,
969 const char *directory, isc_buffer_t *out)
971 const char *suffix = "";
975 REQUIRE(out != NULL);
976 if ((type & DST_TYPE_PRIVATE) != 0)
978 else if (type == DST_TYPE_PUBLIC)
980 if (directory != NULL) {
981 if (isc_buffer_availablelength(out) < strlen(directory))
982 return (ISC_R_NOSPACE);
983 isc_buffer_putstr(out, directory);
984 if (strlen(directory) > 0U &&
985 directory[strlen(directory) - 1] != '/')
986 isc_buffer_putstr(out, "/");
988 if (isc_buffer_availablelength(out) < 1)
989 return (ISC_R_NOSPACE);
990 isc_buffer_putstr(out, "K");
991 result = dns_name_tofilenametext(name, ISC_FALSE, out);
992 if (result != ISC_R_SUCCESS)
994 len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
995 if (isc_buffer_availablelength(out) < len)
996 return (ISC_R_NOSPACE);
997 sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, suffix);
998 isc_buffer_add(out, len);
999 return (ISC_R_SUCCESS);
1003 computeid(dst_key_t *key) {
1004 isc_buffer_t dnsbuf;
1005 unsigned char dns_array[DST_KEY_MAXSIZE];
1009 isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
1010 ret = dst_key_todns(key, &dnsbuf);
1011 if (ret != ISC_R_SUCCESS)
1014 isc_buffer_usedregion(&dnsbuf, &r);
1015 key->key_id = dst_region_computeid(&r, key->key_alg);
1016 return (ISC_R_SUCCESS);
1020 frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags,
1021 unsigned int protocol, dns_rdataclass_t rdclass,
1022 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
1027 REQUIRE(dns_name_isabsolute(name));
1028 REQUIRE(source != NULL);
1029 REQUIRE(mctx != NULL);
1030 REQUIRE(keyp != NULL && *keyp == NULL);
1032 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx);
1034 return (ISC_R_NOMEMORY);
1036 if (key->func->fromdns == NULL) {
1038 return (DST_R_UNSUPPORTEDALG);
1041 ret = key->func->fromdns(key, source);
1042 if (ret != ISC_R_SUCCESS) {
1048 return (ISC_R_SUCCESS);
1052 algorithm_status(unsigned int alg) {
1053 REQUIRE(dst_initialized == ISC_TRUE);
1056 if (alg == DST_ALG_RSA || alg == DST_ALG_DSA || alg == DST_ALG_DH)
1057 return (DST_R_NOCRYPTO);
1059 if (!dst_algorithm_supported(alg))
1060 return (DST_R_UNSUPPORTEDALG);
1061 return (ISC_R_SUCCESS);
1065 dst__file_addsuffix(char *filename, unsigned int len,
1066 const char *ofilename, const char *suffix)
1068 int olen = strlen(ofilename);
1071 if (olen > 1 && ofilename[olen - 1] == '.')
1073 else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0)
1075 else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0)
1078 n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
1080 return (ISC_R_NOSPACE);
1081 return (ISC_R_SUCCESS);
1085 dst__mem_alloc(size_t size) {
1086 INSIST(dst_memory_pool != NULL);
1087 return (isc_mem_allocate(dst_memory_pool, size));
1091 dst__mem_free(void *ptr) {
1092 INSIST(dst_memory_pool != NULL);
1094 isc_mem_free(dst_memory_pool, ptr);
1098 dst__mem_realloc(void *ptr, size_t size) {
1101 INSIST(dst_memory_pool != NULL);
1104 p = dst__mem_alloc(size);
1105 if (p != NULL && ptr != NULL)
1106 memcpy(p, ptr, size);
1114 dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
1115 unsigned int flags = dst_entropy_flags;
1117 flags &= ~ISC_ENTROPY_GOODONLY;
1118 return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));