2 * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-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.1.4.1 2004/12/09 04:07:16 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>
42 #include <dns/keyvalues.h>
44 #include <dns/rdata.h>
45 #include <dns/rdataclass.h>
47 #include <dns/types.h>
49 #include <dst/result.h>
51 #include "dst_internal.h"
53 #define DST_AS_STR(t) ((t).value.as_textregion.base)
55 static dst_func_t *dst_t_func[DST_MAX_ALGS];
56 static isc_entropy_t *dst_entropy_pool = NULL;
57 static unsigned int dst_entropy_flags = 0;
58 static isc_boolean_t dst_initialized = ISC_FALSE;
60 isc_mem_t *dst__memory_pool = NULL;
65 static dst_key_t * get_key_struct(dns_name_t *name,
68 unsigned int protocol,
70 dns_rdataclass_t rdclass,
72 static isc_result_t read_public_key(const char *filename,
76 static isc_result_t write_public_key(const dst_key_t *key, int type,
77 const char *directory);
78 static isc_result_t buildfilename(dns_name_t *name,
82 const char *directory,
84 static isc_result_t computeid(dst_key_t *key);
85 static isc_result_t frombuffer(dns_name_t *name,
88 unsigned int protocol,
89 dns_rdataclass_t rdclass,
94 static isc_result_t algorithm_status(unsigned int alg);
96 static isc_result_t addsuffix(char *filename, unsigned int len,
97 const char *ofilename, const char *suffix);
102 if (result != ISC_R_SUCCESS) \
106 #define CHECKALG(alg) \
109 _r = algorithm_status(alg); \
110 if (_r != ISC_R_SUCCESS) \
115 dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) {
118 REQUIRE(mctx != NULL && ectx != NULL);
119 REQUIRE(dst_initialized == ISC_FALSE);
121 dst__memory_pool = NULL;
126 * When using --with-openssl, there seems to be no good way of not
127 * leaking memory due to the openssl error handling mechanism.
128 * Avoid assertions by using a local memory context and not checking
131 result = isc_mem_create(0, 0, &dst__memory_pool);
132 if (result != ISC_R_SUCCESS)
134 isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE);
136 isc_mem_attach(mctx, &dst__memory_pool);
138 isc_entropy_attach(ectx, &dst_entropy_pool);
139 dst_entropy_flags = eflags;
141 dst_result_register();
143 memset(dst_t_func, 0, sizeof(dst_t_func));
144 RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
146 RETERR(dst__openssl_init());
147 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5]));
148 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1]));
149 #ifdef HAVE_OPENSSL_DSA
150 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA]));
152 RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
155 RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
157 dst_initialized = ISC_TRUE;
158 return (ISC_R_SUCCESS);
166 dst_lib_destroy(void) {
168 RUNTIME_CHECK(dst_initialized == ISC_TRUE);
169 dst_initialized = ISC_FALSE;
171 for (i = 0; i < DST_MAX_ALGS; i++)
172 if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL)
173 dst_t_func[i]->cleanup();
175 dst__openssl_destroy();
177 if (dst__memory_pool != NULL)
178 isc_mem_detach(&dst__memory_pool);
179 if (dst_entropy_pool != NULL)
180 isc_entropy_detach(&dst_entropy_pool);
185 dst_algorithm_supported(unsigned int alg) {
186 REQUIRE(dst_initialized == ISC_TRUE);
188 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
194 dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
198 REQUIRE(dst_initialized == ISC_TRUE);
199 REQUIRE(VALID_KEY(key));
200 REQUIRE(mctx != NULL);
201 REQUIRE(dctxp != NULL && *dctxp == NULL);
203 if (key->func->createctx == NULL)
204 return (DST_R_UNSUPPORTEDALG);
205 if (key->opaque == NULL)
206 return (DST_R_NULLKEY);
208 dctx = isc_mem_get(mctx, sizeof(dst_context_t));
210 return (ISC_R_NOMEMORY);
213 result = key->func->createctx(key, dctx);
214 if (result != ISC_R_SUCCESS) {
215 isc_mem_put(mctx, dctx, sizeof(dst_context_t));
218 dctx->magic = CTX_MAGIC;
220 return (ISC_R_SUCCESS);
224 dst_context_destroy(dst_context_t **dctxp) {
227 REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
230 INSIST(dctx->key->func->destroyctx != NULL);
231 dctx->key->func->destroyctx(dctx);
233 isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t));
238 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
239 REQUIRE(VALID_CTX(dctx));
240 REQUIRE(data != NULL);
241 INSIST(dctx->key->func->adddata != NULL);
243 return (dctx->key->func->adddata(dctx, data));
247 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
250 REQUIRE(VALID_CTX(dctx));
251 REQUIRE(sig != NULL);
254 CHECKALG(key->key_alg);
255 if (key->opaque == NULL)
256 return (DST_R_NULLKEY);
257 if (key->func->sign == NULL)
258 return (DST_R_NOTPRIVATEKEY);
259 if (key->func->isprivate == NULL ||
260 key->func->isprivate(key) == ISC_FALSE)
261 return (DST_R_NOTPRIVATEKEY);
263 return (key->func->sign(dctx, sig));
267 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
268 REQUIRE(VALID_CTX(dctx));
269 REQUIRE(sig != NULL);
271 CHECKALG(dctx->key->key_alg);
272 if (dctx->key->opaque == NULL)
273 return (DST_R_NULLKEY);
274 if (dctx->key->func->verify == NULL)
275 return (DST_R_NOTPUBLICKEY);
277 return (dctx->key->func->verify(dctx, sig));
281 dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
282 isc_buffer_t *secret)
284 REQUIRE(dst_initialized == ISC_TRUE);
285 REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
286 REQUIRE(secret != NULL);
288 CHECKALG(pub->key_alg);
289 CHECKALG(priv->key_alg);
291 if (pub->opaque == NULL || priv->opaque == NULL)
292 return (DST_R_NULLKEY);
294 if (pub->key_alg != priv->key_alg ||
295 pub->func->computesecret == NULL ||
296 priv->func->computesecret == NULL)
297 return (DST_R_KEYCANNOTCOMPUTESECRET);
299 if (dst_key_isprivate(priv) == ISC_FALSE)
300 return (DST_R_NOTPRIVATEKEY);
302 return (pub->func->computesecret(pub, priv, secret));
306 dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
307 isc_result_t ret = ISC_R_SUCCESS;
309 REQUIRE(dst_initialized == ISC_TRUE);
310 REQUIRE(VALID_KEY(key));
311 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
313 CHECKALG(key->key_alg);
315 if (key->func->tofile == NULL)
316 return (DST_R_UNSUPPORTEDALG);
318 if (type & DST_TYPE_PUBLIC) {
319 ret = write_public_key(key, type, directory);
320 if (ret != ISC_R_SUCCESS)
324 if ((type & DST_TYPE_PRIVATE) &&
325 (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
326 return (key->func->tofile(key, directory));
328 return (ISC_R_SUCCESS);
332 dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
333 unsigned int alg, int type, const char *directory,
334 isc_mem_t *mctx, dst_key_t **keyp)
336 char filename[ISC_DIR_NAMEMAX];
341 REQUIRE(dst_initialized == ISC_TRUE);
342 REQUIRE(dns_name_isabsolute(name));
343 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
344 REQUIRE(mctx != NULL);
345 REQUIRE(keyp != NULL && *keyp == NULL);
349 isc_buffer_init(&b, filename, sizeof(filename));
350 result = buildfilename(name, id, alg, type, directory, &b);
351 if (result != ISC_R_SUCCESS)
355 result = dst_key_fromnamedfile(filename, type, mctx, &key);
356 if (result != ISC_R_SUCCESS)
359 result = computeid(key);
360 if (result != ISC_R_SUCCESS) {
365 if (!dns_name_equal(name, key->key_name) ||
370 return (DST_R_INVALIDPRIVATEKEY);
375 return (ISC_R_SUCCESS);
379 dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx,
383 dst_key_t *pubkey = NULL, *key = NULL;
385 char *newfilename = NULL;
386 int newfilenamelen = 0;
387 isc_lex_t *lex = NULL;
389 REQUIRE(dst_initialized == ISC_TRUE);
390 REQUIRE(filename != NULL);
391 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
392 REQUIRE(mctx != NULL);
393 REQUIRE(keyp != NULL && *keyp == NULL);
395 result = read_public_key(filename, type, mctx, &pubkey);
396 if (result != ISC_R_SUCCESS)
399 if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
400 (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY)
402 result = computeid(pubkey);
403 if (result != ISC_R_SUCCESS) {
404 dst_key_free(&pubkey);
409 return (ISC_R_SUCCESS);
412 result = algorithm_status(pubkey->key_alg);
413 if (result != ISC_R_SUCCESS) {
414 dst_key_free(&pubkey);
418 key = get_key_struct(pubkey->key_name, pubkey->key_alg,
419 pubkey->key_flags, pubkey->key_proto, 0,
420 pubkey->key_class, mctx);
422 dst_key_free(&pubkey);
425 return (ISC_R_NOMEMORY);
427 if (key->func->parse == NULL)
428 RETERR(DST_R_UNSUPPORTEDALG);
430 newfilenamelen = strlen(filename) + 9;
431 newfilename = isc_mem_get(mctx, newfilenamelen);
432 if (newfilename == NULL)
433 RETERR(ISC_R_NOMEMORY);
434 result = addsuffix(newfilename, newfilenamelen, filename, ".private");
435 INSIST(result == ISC_R_SUCCESS);
437 RETERR(isc_lex_create(mctx, 1500, &lex));
438 RETERR(isc_lex_openfile(lex, newfilename));
439 isc_mem_put(mctx, newfilename, newfilenamelen);
441 RETERR(key->func->parse(key, lex));
442 isc_lex_destroy(&lex);
444 RETERR(computeid(key));
446 if (id != key->key_id)
447 RETERR(DST_R_INVALIDPRIVATEKEY);
450 return (ISC_R_SUCCESS);
452 if (newfilename != NULL)
453 isc_mem_put(mctx, newfilename, newfilenamelen);
455 isc_lex_destroy(&lex);
461 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
462 REQUIRE(dst_initialized == ISC_TRUE);
463 REQUIRE(VALID_KEY(key));
464 REQUIRE(target != NULL);
466 CHECKALG(key->key_alg);
468 if (key->func->todns == NULL)
469 return (DST_R_UNSUPPORTEDALG);
471 if (isc_buffer_availablelength(target) < 4)
472 return (ISC_R_NOSPACE);
473 isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff));
474 isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto);
475 isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg);
477 if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
478 if (isc_buffer_availablelength(target) < 2)
479 return (ISC_R_NOSPACE);
480 isc_buffer_putuint16(target,
481 (isc_uint16_t)((key->key_flags >> 16)
485 if (key->opaque == NULL) /* NULL KEY */
486 return (ISC_R_SUCCESS);
488 return (key->func->todns(key, target));
492 dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass,
493 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
495 isc_uint8_t alg, proto;
496 isc_uint32_t flags, extflags;
497 dst_key_t *key = NULL;
502 REQUIRE(dst_initialized);
504 isc_buffer_remainingregion(source, &r);
506 if (isc_buffer_remaininglength(source) < 4)
507 return (DST_R_INVALIDPUBLICKEY);
508 flags = isc_buffer_getuint16(source);
509 proto = isc_buffer_getuint8(source);
510 alg = isc_buffer_getuint8(source);
512 id = dst_region_computeid(&r, alg);
514 if (flags & DNS_KEYFLAG_EXTENDED) {
515 if (isc_buffer_remaininglength(source) < 2)
516 return (DST_R_INVALIDPUBLICKEY);
517 extflags = isc_buffer_getuint16(source);
518 flags |= (extflags << 16);
521 result = frombuffer(name, alg, flags, proto, rdclass, source,
523 if (result != ISC_R_SUCCESS)
528 return (ISC_R_SUCCESS);
532 dst_key_frombuffer(dns_name_t *name, unsigned int alg,
533 unsigned int flags, unsigned int protocol,
534 dns_rdataclass_t rdclass,
535 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
537 dst_key_t *key = NULL;
540 REQUIRE(dst_initialized);
542 result = frombuffer(name, alg, flags, protocol, rdclass, source,
544 if (result != ISC_R_SUCCESS)
547 result = computeid(key);
548 if (result != ISC_R_SUCCESS) {
554 return (ISC_R_SUCCESS);
558 dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
559 REQUIRE(dst_initialized == ISC_TRUE);
560 REQUIRE(VALID_KEY(key));
561 REQUIRE(target != NULL);
563 CHECKALG(key->key_alg);
565 if (key->func->todns == NULL)
566 return (DST_R_UNSUPPORTEDALG);
568 return (key->func->todns(key, target));
572 dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
573 isc_lex_t *lex = NULL;
574 isc_result_t result = ISC_R_SUCCESS;
576 REQUIRE(dst_initialized == ISC_TRUE);
577 REQUIRE(VALID_KEY(key));
578 REQUIRE(!dst_key_isprivate(key));
579 REQUIRE(buffer != NULL);
581 if (key->func->parse == NULL)
582 RETERR(DST_R_UNSUPPORTEDALG);
584 RETERR(isc_lex_create(key->mctx, 1500, &lex));
585 RETERR(isc_lex_openbuffer(lex, buffer));
586 RETERR(key->func->parse(key, lex));
589 isc_lex_destroy(&lex);
594 dst_key_fromgssapi(dns_name_t *name, void *opaque, isc_mem_t *mctx,
599 REQUIRE(opaque != NULL);
600 REQUIRE(keyp != NULL && *keyp == NULL);
602 key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
603 0, dns_rdataclass_in, mctx);
605 return (ISC_R_NOMEMORY);
606 key->opaque = opaque;
608 return (ISC_R_SUCCESS);
612 dst_key_generate(dns_name_t *name, unsigned int alg,
613 unsigned int bits, unsigned int param,
614 unsigned int flags, unsigned int protocol,
615 dns_rdataclass_t rdclass,
616 isc_mem_t *mctx, dst_key_t **keyp)
621 REQUIRE(dst_initialized == ISC_TRUE);
622 REQUIRE(dns_name_isabsolute(name));
623 REQUIRE(mctx != NULL);
624 REQUIRE(keyp != NULL && *keyp == NULL);
628 key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx);
630 return (ISC_R_NOMEMORY);
632 if (bits == 0) { /* NULL KEY */
633 key->key_flags |= DNS_KEYTYPE_NOKEY;
635 return (ISC_R_SUCCESS);
638 if (key->func->generate == NULL) {
640 return (DST_R_UNSUPPORTEDALG);
643 ret = key->func->generate(key, param);
644 if (ret != ISC_R_SUCCESS) {
649 ret = computeid(key);
650 if (ret != ISC_R_SUCCESS) {
656 return (ISC_R_SUCCESS);
660 dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
661 REQUIRE(dst_initialized == ISC_TRUE);
662 REQUIRE(VALID_KEY(key1));
663 REQUIRE(VALID_KEY(key2));
667 if (key1 == NULL || key2 == NULL)
669 if (key1->key_alg == key2->key_alg &&
670 key1->key_id == key2->key_id &&
671 key1->func->compare != NULL &&
672 key1->func->compare(key1, key2) == ISC_TRUE)
679 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
680 REQUIRE(dst_initialized == ISC_TRUE);
681 REQUIRE(VALID_KEY(key1));
682 REQUIRE(VALID_KEY(key2));
686 if (key1 == NULL || key2 == NULL)
688 if (key1->key_alg == key2->key_alg &&
689 key1->func->paramcompare != NULL &&
690 key1->func->paramcompare(key1, key2) == ISC_TRUE)
697 dst_key_free(dst_key_t **keyp) {
701 REQUIRE(dst_initialized == ISC_TRUE);
702 REQUIRE(keyp != NULL && VALID_KEY(*keyp));
707 if (key->opaque != NULL) {
708 INSIST(key->func->destroy != NULL);
709 key->func->destroy(key);
712 dns_name_free(key->key_name, mctx);
713 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
714 memset(key, 0, sizeof(dst_key_t));
715 isc_mem_put(mctx, key, sizeof(dst_key_t));
720 dst_key_isprivate(const dst_key_t *key) {
721 REQUIRE(VALID_KEY(key));
722 INSIST(key->func->isprivate != NULL);
723 return (key->func->isprivate(key));
727 dst_key_buildfilename(const dst_key_t *key, int type,
728 const char *directory, isc_buffer_t *out) {
730 REQUIRE(VALID_KEY(key));
731 REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
734 return (buildfilename(key->key_name, key->key_id, key->key_alg,
735 type, directory, out));
739 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
740 REQUIRE(dst_initialized == ISC_TRUE);
741 REQUIRE(VALID_KEY(key));
744 /* XXXVIX this switch statement is too sparse to gen a jump table. */
745 switch (key->key_alg) {
747 case DST_ALG_RSASHA1:
748 *n = (key->key_size + 7) / 8;
751 *n = DNS_SIG_DSASIGSIZE;
753 case DST_ALG_HMACMD5:
761 return (DST_R_UNSUPPORTEDALG);
763 return (ISC_R_SUCCESS);
767 dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
768 REQUIRE(dst_initialized == ISC_TRUE);
769 REQUIRE(VALID_KEY(key));
772 if (key->key_alg == DST_ALG_DH)
773 *n = (key->key_size + 7) / 8;
775 return (DST_R_UNSUPPORTEDALG);
776 return (ISC_R_SUCCESS);
784 * Allocates a key structure and fills in some of the fields.
787 get_key_struct(dns_name_t *name, unsigned int alg,
788 unsigned int flags, unsigned int protocol,
789 unsigned int bits, dns_rdataclass_t rdclass,
795 key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t));
799 memset(key, 0, sizeof(dst_key_t));
800 key->magic = KEY_MAGIC;
802 key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
803 if (key->key_name == NULL) {
804 isc_mem_put(mctx, key, sizeof(dst_key_t));
807 dns_name_init(key->key_name, NULL);
808 result = dns_name_dup(name, mctx, key->key_name);
809 if (result != ISC_R_SUCCESS) {
810 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
811 isc_mem_put(mctx, key, sizeof(dst_key_t));
815 key->key_flags = flags;
816 key->key_proto = protocol;
819 key->key_size = bits;
820 key->key_class = rdclass;
821 key->func = dst_t_func[alg];
826 * Reads a public key from disk
829 read_public_key(const char *filename, int type,
830 isc_mem_t *mctx, dst_key_t **keyp)
832 u_char rdatabuf[DST_KEY_MAXSIZE];
834 dns_fixedname_t name;
835 isc_lex_t *lex = NULL;
838 dns_rdata_t rdata = DNS_RDATA_INIT;
839 unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
841 unsigned int newfilenamelen;
842 dns_rdataclass_t rdclass = dns_rdataclass_in;
843 isc_lexspecials_t specials;
846 dns_rdatatype_t keytype;
848 newfilenamelen = strlen(filename) + 5;
849 newfilename = isc_mem_get(mctx, newfilenamelen);
850 if (newfilename == NULL)
851 return (ISC_R_NOMEMORY);
852 ret = addsuffix(newfilename, newfilenamelen, filename, ".key");
853 INSIST(ret == ISC_R_SUCCESS);
856 * Open the file and read its formatted contents
858 * domain.name [ttl] [class] KEY <flags> <protocol> <algorithm> <key>
861 /* 1500 should be large enough for any key */
862 ret = isc_lex_create(mctx, 1500, &lex);
863 if (ret != ISC_R_SUCCESS)
866 memset(specials, 0, sizeof(specials));
870 isc_lex_setspecials(lex, specials);
871 isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
873 ret = isc_lex_openfile(lex, newfilename);
874 if (ret != ISC_R_SUCCESS)
877 #define NEXTTOKEN(lex, opt, token) { \
878 ret = isc_lex_gettoken(lex, opt, token); \
879 if (ret != ISC_R_SUCCESS) \
883 #define BADTOKEN() { \
884 ret = ISC_R_UNEXPECTEDTOKEN; \
888 /* Read the domain name */
889 NEXTTOKEN(lex, opt, &token);
890 if (token.type != isc_tokentype_string)
892 dns_fixedname_init(&name);
893 isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
894 isc_buffer_add(&b, strlen(DST_AS_STR(token)));
895 ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname,
897 if (ret != ISC_R_SUCCESS)
900 /* Read the next word: either TTL, class, or 'KEY' */
901 NEXTTOKEN(lex, opt, &token);
903 /* If it's a TTL, read the next one */
904 result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
905 if (result == ISC_R_SUCCESS)
906 NEXTTOKEN(lex, opt, &token);
908 if (token.type != isc_tokentype_string)
911 ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
912 if (ret == ISC_R_SUCCESS)
913 NEXTTOKEN(lex, opt, &token);
915 if (token.type != isc_tokentype_string)
918 if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0)
919 keytype = dns_rdatatype_dnskey;
920 else if (strcasecmp(DST_AS_STR(token), "KEY") == 0)
921 keytype = dns_rdatatype_key; /* SIG(0), TKEY */
925 if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
926 ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) {
927 ret = DST_R_BADKEYTYPE;
931 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
932 ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL,
933 ISC_FALSE, mctx, &b, NULL);
934 if (ret != ISC_R_SUCCESS)
937 ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
939 if (ret != ISC_R_SUCCESS)
944 isc_lex_destroy(&lex);
945 isc_mem_put(mctx, newfilename, newfilenamelen);
951 issymmetric(const dst_key_t *key) {
952 REQUIRE(dst_initialized == ISC_TRUE);
953 REQUIRE(VALID_KEY(key));
955 /* XXXVIX this switch statement is too sparse to gen a jump table. */
956 switch (key->key_alg) {
958 case DST_ALG_RSASHA1:
962 case DST_ALG_HMACMD5:
971 * Writes a public key to disk in DNS format.
974 write_public_key(const dst_key_t *key, int type, const char *directory) {
976 isc_buffer_t keyb, textb, fileb, classb;
978 char filename[ISC_DIR_NAMEMAX];
979 unsigned char key_array[DST_KEY_MAXSIZE];
980 char text_array[DST_KEY_MAXTEXTSIZE];
981 char class_array[10];
983 dns_rdata_t rdata = DNS_RDATA_INIT;
984 isc_fsaccess_t access;
986 REQUIRE(VALID_KEY(key));
988 isc_buffer_init(&keyb, key_array, sizeof(key_array));
989 isc_buffer_init(&textb, text_array, sizeof(text_array));
990 isc_buffer_init(&classb, class_array, sizeof(class_array));
992 ret = dst_key_todns(key, &keyb);
993 if (ret != ISC_R_SUCCESS)
996 isc_buffer_usedregion(&keyb, &r);
997 dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
999 ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
1000 if (ret != ISC_R_SUCCESS)
1001 return (DST_R_INVALIDPUBLICKEY);
1003 ret = dns_rdataclass_totext(key->key_class, &classb);
1004 if (ret != ISC_R_SUCCESS)
1005 return (DST_R_INVALIDPUBLICKEY);
1008 * Make the filename.
1010 isc_buffer_init(&fileb, filename, sizeof(filename));
1011 ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
1012 if (ret != ISC_R_SUCCESS)
1016 * Create public key file.
1018 if ((fp = fopen(filename, "w")) == NULL)
1019 return (DST_R_WRITEERROR);
1021 if (issymmetric(key)) {
1023 isc_fsaccess_add(ISC_FSACCESS_OWNER,
1024 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
1026 (void)isc_fsaccess_set(filename, access);
1029 ret = dns_name_print(key->key_name, fp);
1030 if (ret != ISC_R_SUCCESS)
1035 isc_buffer_usedregion(&classb, &r);
1036 fwrite(r.base, 1, r.length, fp);
1038 if ((type & DST_TYPE_KEY) != 0)
1039 fprintf(fp, " KEY ");
1041 fprintf(fp, " DNSKEY ");
1043 isc_buffer_usedregion(&textb, &r);
1044 fwrite(r.base, 1, r.length, fp);
1049 return (ISC_R_SUCCESS);
1053 buildfilename(dns_name_t *name, dns_keytag_t id,
1054 unsigned int alg, unsigned int type,
1055 const char *directory, isc_buffer_t *out)
1057 const char *suffix = "";
1059 isc_result_t result;
1061 REQUIRE(out != NULL);
1062 if ((type & DST_TYPE_PRIVATE) != 0)
1063 suffix = ".private";
1064 else if (type == DST_TYPE_PUBLIC)
1066 if (directory != NULL) {
1067 if (isc_buffer_availablelength(out) < strlen(directory))
1068 return (ISC_R_NOSPACE);
1069 isc_buffer_putstr(out, directory);
1070 if (strlen(directory) > 0U &&
1071 directory[strlen(directory) - 1] != '/')
1072 isc_buffer_putstr(out, "/");
1074 if (isc_buffer_availablelength(out) < 1)
1075 return (ISC_R_NOSPACE);
1076 isc_buffer_putstr(out, "K");
1077 result = dns_name_tofilenametext(name, ISC_FALSE, out);
1078 if (result != ISC_R_SUCCESS)
1080 len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
1081 if (isc_buffer_availablelength(out) < len)
1082 return (ISC_R_NOSPACE);
1083 sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id, suffix);
1084 isc_buffer_add(out, len);
1085 return (ISC_R_SUCCESS);
1089 computeid(dst_key_t *key) {
1090 isc_buffer_t dnsbuf;
1091 unsigned char dns_array[DST_KEY_MAXSIZE];
1095 isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
1096 ret = dst_key_todns(key, &dnsbuf);
1097 if (ret != ISC_R_SUCCESS)
1100 isc_buffer_usedregion(&dnsbuf, &r);
1101 key->key_id = dst_region_computeid(&r, key->key_alg);
1102 return (ISC_R_SUCCESS);
1106 frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags,
1107 unsigned int protocol, dns_rdataclass_t rdclass,
1108 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
1113 REQUIRE(dns_name_isabsolute(name));
1114 REQUIRE(source != NULL);
1115 REQUIRE(mctx != NULL);
1116 REQUIRE(keyp != NULL && *keyp == NULL);
1118 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx);
1120 return (ISC_R_NOMEMORY);
1122 if (isc_buffer_remaininglength(source) > 0) {
1123 ret = algorithm_status(alg);
1124 if (ret != ISC_R_SUCCESS) {
1128 if (key->func->fromdns == NULL) {
1130 return (DST_R_UNSUPPORTEDALG);
1133 ret = key->func->fromdns(key, source);
1134 if (ret != ISC_R_SUCCESS) {
1141 return (ISC_R_SUCCESS);
1145 algorithm_status(unsigned int alg) {
1146 REQUIRE(dst_initialized == ISC_TRUE);
1148 if (dst_algorithm_supported(alg))
1149 return (ISC_R_SUCCESS);
1151 if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
1152 alg == DST_ALG_DSA || alg == DST_ALG_DH ||
1153 alg == DST_ALG_HMACMD5)
1154 return (DST_R_NOCRYPTO);
1156 return (DST_R_UNSUPPORTEDALG);
1160 addsuffix(char *filename, unsigned int len, const char *ofilename,
1163 int olen = strlen(ofilename);
1166 if (olen > 1 && ofilename[olen - 1] == '.')
1168 else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0)
1170 else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0)
1173 n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
1175 return (ISC_R_NOSPACE);
1176 return (ISC_R_SUCCESS);
1180 dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
1181 unsigned int flags = dst_entropy_flags;
1183 flags &= ~ISC_ENTROPY_GOODONLY;
1184 return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));