4 * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
12 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
14 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
17 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
21 * Permission to use, copy, modify, and/or distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
28 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
31 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 * Principal Author: Brian Wellington
36 * Id: dst_api.c,v 1.47 2009/11/07 03:36:58 each Exp
46 #include <isc/buffer.h>
48 #include <isc/entropy.h>
49 #include <isc/fsaccess.h>
50 #include <isc/hmacsha.h>
54 #include <isc/print.h>
55 #include <isc/random.h>
56 #include <isc/string.h>
60 #include <dns/fixedname.h>
61 #include <dns/keyvalues.h>
63 #include <dns/rdata.h>
64 #include <dns/rdataclass.h>
66 #include <dns/types.h>
68 #include <dst/result.h>
70 #include "dst_internal.h"
72 #define DST_AS_STR(t) ((t).value.as_textregion.base)
74 static dst_func_t
*dst_t_func
[DST_MAX_ALGS
];
76 static isc_entropy_t
*dst_entropy_pool
= NULL
;
78 static unsigned int dst_entropy_flags
= 0;
79 static isc_boolean_t dst_initialized
= ISC_FALSE
;
81 void gss_log(int level
, const char *fmt
, ...) ISC_FORMAT_PRINTF(2, 3);
83 isc_mem_t
*dst__memory_pool
= NULL
;
88 static dst_key_t
* get_key_struct(dns_name_t
*name
,
91 unsigned int protocol
,
93 dns_rdataclass_t rdclass
,
95 static isc_result_t
write_public_key(const dst_key_t
*key
, int type
,
96 const char *directory
);
97 static isc_result_t
buildfilename(dns_name_t
*name
,
101 const char *directory
,
103 static isc_result_t
computeid(dst_key_t
*key
);
104 static isc_result_t
frombuffer(dns_name_t
*name
,
107 unsigned int protocol
,
108 dns_rdataclass_t rdclass
,
109 isc_buffer_t
*source
,
113 static isc_result_t
algorithm_status(unsigned int alg
);
115 static isc_result_t
addsuffix(char *filename
, int len
,
116 const char *dirname
, const char *ofilename
,
122 if (result != ISC_R_SUCCESS) \
126 #define CHECKALG(alg) \
129 _r = algorithm_status(alg); \
130 if (_r != ISC_R_SUCCESS) \
134 #if defined(OPENSSL) && defined(BIND9)
136 default_memalloc(void *arg
, size_t size
) {
140 return (malloc(size
));
144 default_memfree(void *arg
, void *ptr
) {
151 dst_lib_init(isc_mem_t
*mctx
, isc_entropy_t
*ectx
, unsigned int eflags
) {
152 return (dst_lib_init2(mctx
, ectx
, NULL
, eflags
));
156 dst_lib_init2(isc_mem_t
*mctx
, isc_entropy_t
*ectx
,
157 const char *engine
, unsigned int eflags
) {
160 REQUIRE(mctx
!= NULL
);
162 REQUIRE(ectx
!= NULL
);
166 REQUIRE(dst_initialized
== ISC_FALSE
);
172 dst__memory_pool
= NULL
;
174 #if defined(OPENSSL) && defined(BIND9)
177 * When using --with-openssl, there seems to be no good way of not
178 * leaking memory due to the openssl error handling mechanism.
179 * Avoid assertions by using a local memory context and not checking
180 * for leaks on exit. Note: as there are leaks we cannot use
181 * ISC_MEMFLAG_INTERNAL as it will free up memory still being used
184 result
= isc_mem_createx2(0, 0, default_memalloc
, default_memfree
,
185 NULL
, &dst__memory_pool
, 0);
186 if (result
!= ISC_R_SUCCESS
)
188 isc_mem_setname(dst__memory_pool
, "dst", NULL
);
189 #ifndef OPENSSL_LEAKS
190 isc_mem_setdestroycheck(dst__memory_pool
, ISC_FALSE
);
193 isc_mem_attach(mctx
, &dst__memory_pool
);
196 isc_entropy_attach(ectx
, &dst_entropy_pool
);
198 dst_entropy_flags
= eflags
;
200 dst_result_register();
202 memset(dst_t_func
, 0, sizeof(dst_t_func
));
203 RETERR(dst__hmacmd5_init(&dst_t_func
[DST_ALG_HMACMD5
]));
204 RETERR(dst__hmacsha1_init(&dst_t_func
[DST_ALG_HMACSHA1
]));
205 RETERR(dst__hmacsha224_init(&dst_t_func
[DST_ALG_HMACSHA224
]));
206 RETERR(dst__hmacsha256_init(&dst_t_func
[DST_ALG_HMACSHA256
]));
207 RETERR(dst__hmacsha384_init(&dst_t_func
[DST_ALG_HMACSHA384
]));
208 RETERR(dst__hmacsha512_init(&dst_t_func
[DST_ALG_HMACSHA512
]));
210 RETERR(dst__openssl_init(engine
));
211 RETERR(dst__opensslrsa_init(&dst_t_func
[DST_ALG_RSAMD5
],
213 RETERR(dst__opensslrsa_init(&dst_t_func
[DST_ALG_RSASHA1
],
215 RETERR(dst__opensslrsa_init(&dst_t_func
[DST_ALG_NSEC3RSASHA1
],
216 DST_ALG_NSEC3RSASHA1
));
217 RETERR(dst__opensslrsa_init(&dst_t_func
[DST_ALG_RSASHA256
],
219 RETERR(dst__opensslrsa_init(&dst_t_func
[DST_ALG_RSASHA512
],
221 #ifdef HAVE_OPENSSL_DSA
222 RETERR(dst__openssldsa_init(&dst_t_func
[DST_ALG_DSA
]));
223 RETERR(dst__openssldsa_init(&dst_t_func
[DST_ALG_NSEC3DSA
]));
225 RETERR(dst__openssldh_init(&dst_t_func
[DST_ALG_DH
]));
228 RETERR(dst__gssapi_init(&dst_t_func
[DST_ALG_GSSAPI
]));
230 dst_initialized
= ISC_TRUE
;
231 return (ISC_R_SUCCESS
);
234 /* avoid immediate crash! */
235 dst_initialized
= ISC_TRUE
;
241 dst_lib_destroy(void) {
243 RUNTIME_CHECK(dst_initialized
== ISC_TRUE
);
244 dst_initialized
= ISC_FALSE
;
246 for (i
= 0; i
< DST_MAX_ALGS
; i
++)
247 if (dst_t_func
[i
] != NULL
&& dst_t_func
[i
]->cleanup
!= NULL
)
248 dst_t_func
[i
]->cleanup();
250 dst__openssl_destroy();
252 if (dst__memory_pool
!= NULL
)
253 isc_mem_detach(&dst__memory_pool
);
255 if (dst_entropy_pool
!= NULL
)
256 isc_entropy_detach(&dst_entropy_pool
);
261 dst_algorithm_supported(unsigned int alg
) {
262 REQUIRE(dst_initialized
== ISC_TRUE
);
264 if (alg
>= DST_MAX_ALGS
|| dst_t_func
[alg
] == NULL
)
270 dst_context_create(dst_key_t
*key
, isc_mem_t
*mctx
, dst_context_t
**dctxp
) {
274 REQUIRE(dst_initialized
== ISC_TRUE
);
275 REQUIRE(VALID_KEY(key
));
276 REQUIRE(mctx
!= NULL
);
277 REQUIRE(dctxp
!= NULL
&& *dctxp
== NULL
);
279 if (key
->func
->createctx
== NULL
)
280 return (DST_R_UNSUPPORTEDALG
);
281 if (key
->keydata
.generic
== NULL
)
282 return (DST_R_NULLKEY
);
284 dctx
= isc_mem_get(mctx
, sizeof(dst_context_t
));
286 return (ISC_R_NOMEMORY
);
289 result
= key
->func
->createctx(key
, dctx
);
290 if (result
!= ISC_R_SUCCESS
) {
291 isc_mem_put(mctx
, dctx
, sizeof(dst_context_t
));
294 dctx
->magic
= CTX_MAGIC
;
296 return (ISC_R_SUCCESS
);
300 dst_context_destroy(dst_context_t
**dctxp
) {
303 REQUIRE(dctxp
!= NULL
&& VALID_CTX(*dctxp
));
306 INSIST(dctx
->key
->func
->destroyctx
!= NULL
);
307 dctx
->key
->func
->destroyctx(dctx
);
309 isc_mem_put(dctx
->mctx
, dctx
, sizeof(dst_context_t
));
314 dst_context_adddata(dst_context_t
*dctx
, const isc_region_t
*data
) {
315 REQUIRE(VALID_CTX(dctx
));
316 REQUIRE(data
!= NULL
);
317 INSIST(dctx
->key
->func
->adddata
!= NULL
);
319 return (dctx
->key
->func
->adddata(dctx
, data
));
323 dst_context_sign(dst_context_t
*dctx
, isc_buffer_t
*sig
) {
326 REQUIRE(VALID_CTX(dctx
));
327 REQUIRE(sig
!= NULL
);
330 CHECKALG(key
->key_alg
);
331 if (key
->keydata
.generic
== NULL
)
332 return (DST_R_NULLKEY
);
334 if (key
->func
->sign
== NULL
)
335 return (DST_R_NOTPRIVATEKEY
);
336 if (key
->func
->isprivate
== NULL
||
337 key
->func
->isprivate(key
) == ISC_FALSE
)
338 return (DST_R_NOTPRIVATEKEY
);
340 return (key
->func
->sign(dctx
, sig
));
344 dst_context_verify(dst_context_t
*dctx
, isc_region_t
*sig
) {
345 REQUIRE(VALID_CTX(dctx
));
346 REQUIRE(sig
!= NULL
);
348 CHECKALG(dctx
->key
->key_alg
);
349 if (dctx
->key
->keydata
.generic
== NULL
)
350 return (DST_R_NULLKEY
);
351 if (dctx
->key
->func
->verify
== NULL
)
352 return (DST_R_NOTPUBLICKEY
);
354 return (dctx
->key
->func
->verify(dctx
, sig
));
358 dst_key_computesecret(const dst_key_t
*pub
, const dst_key_t
*priv
,
359 isc_buffer_t
*secret
)
361 REQUIRE(dst_initialized
== ISC_TRUE
);
362 REQUIRE(VALID_KEY(pub
) && VALID_KEY(priv
));
363 REQUIRE(secret
!= NULL
);
365 CHECKALG(pub
->key_alg
);
366 CHECKALG(priv
->key_alg
);
368 if (pub
->keydata
.generic
== NULL
|| priv
->keydata
.generic
== NULL
)
369 return (DST_R_NULLKEY
);
371 if (pub
->key_alg
!= priv
->key_alg
||
372 pub
->func
->computesecret
== NULL
||
373 priv
->func
->computesecret
== NULL
)
374 return (DST_R_KEYCANNOTCOMPUTESECRET
);
376 if (dst_key_isprivate(priv
) == ISC_FALSE
)
377 return (DST_R_NOTPRIVATEKEY
);
379 return (pub
->func
->computesecret(pub
, priv
, secret
));
383 dst_key_tofile(const dst_key_t
*key
, int type
, const char *directory
) {
384 isc_result_t ret
= ISC_R_SUCCESS
;
386 REQUIRE(dst_initialized
== ISC_TRUE
);
387 REQUIRE(VALID_KEY(key
));
388 REQUIRE((type
& (DST_TYPE_PRIVATE
| DST_TYPE_PUBLIC
)) != 0);
390 CHECKALG(key
->key_alg
);
392 if (key
->func
->tofile
== NULL
)
393 return (DST_R_UNSUPPORTEDALG
);
395 if (type
& DST_TYPE_PUBLIC
) {
396 ret
= write_public_key(key
, type
, directory
);
397 if (ret
!= ISC_R_SUCCESS
)
401 if ((type
& DST_TYPE_PRIVATE
) &&
402 (key
->key_flags
& DNS_KEYFLAG_TYPEMASK
) != DNS_KEYTYPE_NOKEY
)
403 return (key
->func
->tofile(key
, directory
));
405 return (ISC_R_SUCCESS
);
409 dst_key_fromfile(dns_name_t
*name
, dns_keytag_t id
,
410 unsigned int alg
, int type
, const char *directory
,
411 isc_mem_t
*mctx
, dst_key_t
**keyp
)
413 char filename
[ISC_DIR_NAMEMAX
];
418 REQUIRE(dst_initialized
== ISC_TRUE
);
419 REQUIRE(dns_name_isabsolute(name
));
420 REQUIRE((type
& (DST_TYPE_PRIVATE
| DST_TYPE_PUBLIC
)) != 0);
421 REQUIRE(mctx
!= NULL
);
422 REQUIRE(keyp
!= NULL
&& *keyp
== NULL
);
426 isc_buffer_init(&b
, filename
, sizeof(filename
));
427 result
= buildfilename(name
, id
, alg
, type
, directory
, &b
);
428 if (result
!= ISC_R_SUCCESS
)
432 result
= dst_key_fromnamedfile(filename
, NULL
, type
, mctx
, &key
);
433 if (result
!= ISC_R_SUCCESS
)
436 result
= computeid(key
);
437 if (result
!= ISC_R_SUCCESS
) {
442 if (!dns_name_equal(name
, key
->key_name
) || id
!= key
->key_id
||
443 alg
!= key
->key_alg
) {
445 return (DST_R_INVALIDPRIVATEKEY
);
450 return (ISC_R_SUCCESS
);
454 dst_key_fromnamedfile(const char *filename
, const char *dirname
,
455 int type
, isc_mem_t
*mctx
, dst_key_t
**keyp
)
458 dst_key_t
*pubkey
= NULL
, *key
= NULL
;
459 char *newfilename
= NULL
;
460 int newfilenamelen
= 0;
461 isc_lex_t
*lex
= NULL
;
463 REQUIRE(dst_initialized
== ISC_TRUE
);
464 REQUIRE(filename
!= NULL
);
465 REQUIRE((type
& (DST_TYPE_PRIVATE
| DST_TYPE_PUBLIC
)) != 0);
466 REQUIRE(mctx
!= NULL
);
467 REQUIRE(keyp
!= NULL
&& *keyp
== NULL
);
469 /* If an absolute path is specified, don't use the key directory */
471 if (filename
[0] == '/')
474 if (filename
[0] == '/' || filename
[0] == '\\')
478 newfilenamelen
= strlen(filename
) + 5;
480 newfilenamelen
+= strlen(dirname
) + 1;
481 newfilename
= isc_mem_get(mctx
, newfilenamelen
);
482 if (newfilename
== NULL
)
483 return (ISC_R_NOMEMORY
);
484 result
= addsuffix(newfilename
, newfilenamelen
,
485 dirname
, filename
, ".key");
486 INSIST(result
== ISC_R_SUCCESS
);
488 result
= dst_key_read_public(newfilename
, type
, mctx
, &pubkey
);
489 isc_mem_put(mctx
, newfilename
, newfilenamelen
);
491 if (result
!= ISC_R_SUCCESS
)
494 if ((type
& (DST_TYPE_PRIVATE
| DST_TYPE_PUBLIC
)) == DST_TYPE_PUBLIC
||
495 (pubkey
->key_flags
& DNS_KEYFLAG_TYPEMASK
) == DNS_KEYTYPE_NOKEY
) {
496 result
= computeid(pubkey
);
497 if (result
!= ISC_R_SUCCESS
) {
498 dst_key_free(&pubkey
);
503 return (ISC_R_SUCCESS
);
506 result
= algorithm_status(pubkey
->key_alg
);
507 if (result
!= ISC_R_SUCCESS
) {
508 dst_key_free(&pubkey
);
512 key
= get_key_struct(pubkey
->key_name
, pubkey
->key_alg
,
513 pubkey
->key_flags
, pubkey
->key_proto
, 0,
514 pubkey
->key_class
, mctx
);
516 dst_key_free(&pubkey
);
517 return (ISC_R_NOMEMORY
);
520 if (key
->func
->parse
== NULL
)
521 RETERR(DST_R_UNSUPPORTEDALG
);
523 newfilenamelen
= strlen(filename
) + 9;
525 newfilenamelen
+= strlen(dirname
) + 1;
526 newfilename
= isc_mem_get(mctx
, newfilenamelen
);
527 if (newfilename
== NULL
)
528 RETERR(ISC_R_NOMEMORY
);
529 result
= addsuffix(newfilename
, newfilenamelen
,
530 dirname
, filename
, ".private");
531 INSIST(result
== ISC_R_SUCCESS
);
533 RETERR(isc_lex_create(mctx
, 1500, &lex
));
534 RETERR(isc_lex_openfile(lex
, newfilename
));
535 isc_mem_put(mctx
, newfilename
, newfilenamelen
);
537 RETERR(key
->func
->parse(key
, lex
, pubkey
));
538 isc_lex_destroy(&lex
);
540 RETERR(computeid(key
));
542 if (pubkey
->key_id
!= key
->key_id
)
543 RETERR(DST_R_INVALIDPRIVATEKEY
);
544 dst_key_free(&pubkey
);
547 return (ISC_R_SUCCESS
);
550 dst_key_free(&pubkey
);
551 if (newfilename
!= NULL
)
552 isc_mem_put(mctx
, newfilename
, newfilenamelen
);
554 isc_lex_destroy(&lex
);
560 dst_key_todns(const dst_key_t
*key
, isc_buffer_t
*target
) {
561 REQUIRE(dst_initialized
== ISC_TRUE
);
562 REQUIRE(VALID_KEY(key
));
563 REQUIRE(target
!= NULL
);
565 CHECKALG(key
->key_alg
);
567 if (key
->func
->todns
== NULL
)
568 return (DST_R_UNSUPPORTEDALG
);
570 if (isc_buffer_availablelength(target
) < 4)
571 return (ISC_R_NOSPACE
);
572 isc_buffer_putuint16(target
, (isc_uint16_t
)(key
->key_flags
& 0xffff));
573 isc_buffer_putuint8(target
, (isc_uint8_t
)key
->key_proto
);
574 isc_buffer_putuint8(target
, (isc_uint8_t
)key
->key_alg
);
576 if (key
->key_flags
& DNS_KEYFLAG_EXTENDED
) {
577 if (isc_buffer_availablelength(target
) < 2)
578 return (ISC_R_NOSPACE
);
579 isc_buffer_putuint16(target
,
580 (isc_uint16_t
)((key
->key_flags
>> 16)
584 if (key
->keydata
.generic
== NULL
) /*%< NULL KEY */
585 return (ISC_R_SUCCESS
);
587 return (key
->func
->todns(key
, target
));
591 dst_key_fromdns(dns_name_t
*name
, dns_rdataclass_t rdclass
,
592 isc_buffer_t
*source
, isc_mem_t
*mctx
, dst_key_t
**keyp
)
594 isc_uint8_t alg
, proto
;
595 isc_uint32_t flags
, extflags
;
596 dst_key_t
*key
= NULL
;
601 REQUIRE(dst_initialized
);
603 isc_buffer_remainingregion(source
, &r
);
605 if (isc_buffer_remaininglength(source
) < 4)
606 return (DST_R_INVALIDPUBLICKEY
);
607 flags
= isc_buffer_getuint16(source
);
608 proto
= isc_buffer_getuint8(source
);
609 alg
= isc_buffer_getuint8(source
);
611 id
= dst_region_computeid(&r
, alg
);
613 if (flags
& DNS_KEYFLAG_EXTENDED
) {
614 if (isc_buffer_remaininglength(source
) < 2)
615 return (DST_R_INVALIDPUBLICKEY
);
616 extflags
= isc_buffer_getuint16(source
);
617 flags
|= (extflags
<< 16);
620 result
= frombuffer(name
, alg
, flags
, proto
, rdclass
, source
,
622 if (result
!= ISC_R_SUCCESS
)
627 return (ISC_R_SUCCESS
);
631 dst_key_frombuffer(dns_name_t
*name
, unsigned int alg
,
632 unsigned int flags
, unsigned int protocol
,
633 dns_rdataclass_t rdclass
,
634 isc_buffer_t
*source
, isc_mem_t
*mctx
, dst_key_t
**keyp
)
636 dst_key_t
*key
= NULL
;
639 REQUIRE(dst_initialized
);
641 result
= frombuffer(name
, alg
, flags
, protocol
, rdclass
, source
,
643 if (result
!= ISC_R_SUCCESS
)
646 result
= computeid(key
);
647 if (result
!= ISC_R_SUCCESS
) {
653 return (ISC_R_SUCCESS
);
657 dst_key_tobuffer(const dst_key_t
*key
, isc_buffer_t
*target
) {
658 REQUIRE(dst_initialized
== ISC_TRUE
);
659 REQUIRE(VALID_KEY(key
));
660 REQUIRE(target
!= NULL
);
662 CHECKALG(key
->key_alg
);
664 if (key
->func
->todns
== NULL
)
665 return (DST_R_UNSUPPORTEDALG
);
667 return (key
->func
->todns(key
, target
));
671 dst_key_privatefrombuffer(dst_key_t
*key
, isc_buffer_t
*buffer
) {
672 isc_lex_t
*lex
= NULL
;
673 isc_result_t result
= ISC_R_SUCCESS
;
675 REQUIRE(dst_initialized
== ISC_TRUE
);
676 REQUIRE(VALID_KEY(key
));
677 REQUIRE(!dst_key_isprivate(key
));
678 REQUIRE(buffer
!= NULL
);
680 if (key
->func
->parse
== NULL
)
681 RETERR(DST_R_UNSUPPORTEDALG
);
683 RETERR(isc_lex_create(key
->mctx
, 1500, &lex
));
684 RETERR(isc_lex_openbuffer(lex
, buffer
));
685 RETERR(key
->func
->parse(key
, lex
, NULL
));
688 isc_lex_destroy(&lex
);
693 dst_key_getgssctx(const dst_key_t
*key
)
695 REQUIRE(key
!= NULL
);
697 return (key
->keydata
.gssctx
);
701 dst_key_fromgssapi(dns_name_t
*name
, gss_ctx_id_t gssctx
, isc_mem_t
*mctx
,
706 REQUIRE(gssctx
!= NULL
);
707 REQUIRE(keyp
!= NULL
&& *keyp
== NULL
);
709 key
= get_key_struct(name
, DST_ALG_GSSAPI
, 0, DNS_KEYPROTO_DNSSEC
,
710 0, dns_rdataclass_in
, mctx
);
712 return (ISC_R_NOMEMORY
);
714 key
->keydata
.gssctx
= gssctx
;
716 return (ISC_R_SUCCESS
);
720 dst_key_fromlabel(dns_name_t
*name
, int alg
, unsigned int flags
,
721 unsigned int protocol
, dns_rdataclass_t rdclass
,
722 const char *engine
, const char *label
, const char *pin
,
723 isc_mem_t
*mctx
, dst_key_t
**keyp
)
728 REQUIRE(dst_initialized
== ISC_TRUE
);
729 REQUIRE(dns_name_isabsolute(name
));
730 REQUIRE(mctx
!= NULL
);
731 REQUIRE(keyp
!= NULL
&& *keyp
== NULL
);
732 REQUIRE(label
!= NULL
);
736 key
= get_key_struct(name
, alg
, flags
, protocol
, 0, rdclass
, mctx
);
738 return (ISC_R_NOMEMORY
);
740 if (key
->func
->fromlabel
== NULL
) {
742 return (DST_R_UNSUPPORTEDALG
);
745 result
= key
->func
->fromlabel(key
, engine
, label
, pin
);
746 if (result
!= ISC_R_SUCCESS
) {
751 result
= computeid(key
);
752 if (result
!= ISC_R_SUCCESS
) {
758 return (ISC_R_SUCCESS
);
762 dst_key_generate(dns_name_t
*name
, unsigned int alg
,
763 unsigned int bits
, unsigned int param
,
764 unsigned int flags
, unsigned int protocol
,
765 dns_rdataclass_t rdclass
,
766 isc_mem_t
*mctx
, dst_key_t
**keyp
)
768 return (dst_key_generate2(name
, alg
, bits
, param
, flags
, protocol
,
769 rdclass
, mctx
, keyp
, NULL
));
773 dst_key_generate2(dns_name_t
*name
, unsigned int alg
,
774 unsigned int bits
, unsigned int param
,
775 unsigned int flags
, unsigned int protocol
,
776 dns_rdataclass_t rdclass
,
777 isc_mem_t
*mctx
, dst_key_t
**keyp
,
778 void (*callback
)(int))
783 REQUIRE(dst_initialized
== ISC_TRUE
);
784 REQUIRE(dns_name_isabsolute(name
));
785 REQUIRE(mctx
!= NULL
);
786 REQUIRE(keyp
!= NULL
&& *keyp
== NULL
);
790 key
= get_key_struct(name
, alg
, flags
, protocol
, bits
, rdclass
, mctx
);
792 return (ISC_R_NOMEMORY
);
794 if (bits
== 0) { /*%< NULL KEY */
795 key
->key_flags
|= DNS_KEYTYPE_NOKEY
;
797 return (ISC_R_SUCCESS
);
800 if (key
->func
->generate
== NULL
) {
802 return (DST_R_UNSUPPORTEDALG
);
805 ret
= key
->func
->generate(key
, param
, callback
);
806 if (ret
!= ISC_R_SUCCESS
) {
811 ret
= computeid(key
);
812 if (ret
!= ISC_R_SUCCESS
) {
818 return (ISC_R_SUCCESS
);
822 dst_key_getnum(const dst_key_t
*key
, int type
, isc_uint32_t
*valuep
)
824 REQUIRE(VALID_KEY(key
));
825 REQUIRE(valuep
!= NULL
);
826 REQUIRE(type
<= DST_MAX_NUMERIC
);
827 if (!key
->numset
[type
])
828 return (ISC_R_NOTFOUND
);
829 *valuep
= key
->nums
[type
];
830 return (ISC_R_SUCCESS
);
834 dst_key_setnum(dst_key_t
*key
, int type
, isc_uint32_t value
)
836 REQUIRE(VALID_KEY(key
));
837 REQUIRE(type
<= DST_MAX_NUMERIC
);
838 key
->nums
[type
] = value
;
839 key
->numset
[type
] = ISC_TRUE
;
843 dst_key_unsetnum(dst_key_t
*key
, int type
)
845 REQUIRE(VALID_KEY(key
));
846 REQUIRE(type
<= DST_MAX_NUMERIC
);
847 key
->numset
[type
] = ISC_FALSE
;
851 dst_key_gettime(const dst_key_t
*key
, int type
, isc_stdtime_t
*timep
) {
852 REQUIRE(VALID_KEY(key
));
853 REQUIRE(timep
!= NULL
);
854 REQUIRE(type
<= DST_MAX_TIMES
);
855 if (!key
->timeset
[type
])
856 return (ISC_R_NOTFOUND
);
857 *timep
= key
->times
[type
];
858 return (ISC_R_SUCCESS
);
862 dst_key_settime(dst_key_t
*key
, int type
, isc_stdtime_t when
) {
863 REQUIRE(VALID_KEY(key
));
864 REQUIRE(type
<= DST_MAX_TIMES
);
865 key
->times
[type
] = when
;
866 key
->timeset
[type
] = ISC_TRUE
;
870 dst_key_unsettime(dst_key_t
*key
, int type
) {
871 REQUIRE(VALID_KEY(key
));
872 REQUIRE(type
<= DST_MAX_TIMES
);
873 key
->timeset
[type
] = ISC_FALSE
;
877 dst_key_getprivateformat(const dst_key_t
*key
, int *majorp
, int *minorp
) {
878 REQUIRE(VALID_KEY(key
));
879 REQUIRE(majorp
!= NULL
);
880 REQUIRE(minorp
!= NULL
);
881 *majorp
= key
->fmt_major
;
882 *minorp
= key
->fmt_minor
;
883 return (ISC_R_SUCCESS
);
887 dst_key_setprivateformat(dst_key_t
*key
, int major
, int minor
) {
888 REQUIRE(VALID_KEY(key
));
889 key
->fmt_major
= major
;
890 key
->fmt_minor
= minor
;
894 comparekeys(const dst_key_t
*key1
, const dst_key_t
*key2
,
895 isc_boolean_t match_revoked_key
,
896 isc_boolean_t (*compare
)(const dst_key_t
*key1
,
897 const dst_key_t
*key2
))
899 REQUIRE(dst_initialized
== ISC_TRUE
);
900 REQUIRE(VALID_KEY(key1
));
901 REQUIRE(VALID_KEY(key2
));
906 if (key1
== NULL
|| key2
== NULL
)
909 if (key1
->key_alg
!= key2
->key_alg
)
913 * For all algorithms except RSAMD5, revoking the key
914 * changes the key ID, increasing it by 128. If we want to
915 * be able to find matching keys even if one of them is the
916 * revoked version of the other one, then we need to check
917 * for that possibility.
919 if (key1
->key_id
!= key2
->key_id
) {
920 if (!match_revoked_key
)
922 if (key1
->key_alg
== DST_ALG_RSAMD5
)
924 if ((key1
->key_flags
& DNS_KEYFLAG_REVOKE
) ==
925 (key2
->key_flags
& DNS_KEYFLAG_REVOKE
))
927 if ((key1
->key_flags
& DNS_KEYFLAG_REVOKE
) != 0 &&
928 key1
->key_id
!= ((key2
->key_id
+ 128) & 0xffff))
930 if ((key2
->key_flags
& DNS_KEYFLAG_REVOKE
) != 0 &&
931 key2
->key_id
!= ((key1
->key_id
+ 128) & 0xffff))
936 return (compare(key1
, key2
));
943 * Compares only the public portion of two keys, by converting them
944 * both to wire format and comparing the results.
947 pub_compare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
949 unsigned char buf1
[DST_KEY_MAXSIZE
], buf2
[DST_KEY_MAXSIZE
];
953 isc_buffer_init(&b1
, buf1
, sizeof(buf1
));
954 result
= dst_key_todns(key1
, &b1
);
955 if (result
!= ISC_R_SUCCESS
)
957 /* Zero out flags. */
958 buf1
[0] = buf1
[1] = 0;
959 if ((key1
->key_flags
& DNS_KEYFLAG_EXTENDED
) != 0)
960 isc_buffer_subtract(&b1
, 2);
962 isc_buffer_init(&b2
, buf2
, sizeof(buf2
));
963 result
= dst_key_todns(key2
, &b2
);
964 if (result
!= ISC_R_SUCCESS
)
966 /* Zero out flags. */
967 buf2
[0] = buf2
[1] = 0;
968 if ((key2
->key_flags
& DNS_KEYFLAG_EXTENDED
) != 0)
969 isc_buffer_subtract(&b2
, 2);
971 isc_buffer_usedregion(&b1
, &r1
);
972 /* Remove extended flags. */
973 if ((key1
->key_flags
& DNS_KEYFLAG_EXTENDED
) != 0) {
974 memmove(&buf1
[4], &buf1
[6], r1
.length
- 6);
978 isc_buffer_usedregion(&b2
, &r2
);
979 /* Remove extended flags. */
980 if ((key2
->key_flags
& DNS_KEYFLAG_EXTENDED
) != 0) {
981 memmove(&buf2
[4], &buf2
[6], r2
.length
- 6);
984 return (ISC_TF(isc_region_compare(&r1
, &r2
) == 0));
988 dst_key_compare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
989 return (comparekeys(key1
, key2
, ISC_FALSE
, key1
->func
->compare
));
993 dst_key_pubcompare(const dst_key_t
*key1
, const dst_key_t
*key2
,
994 isc_boolean_t match_revoked_key
)
996 return (comparekeys(key1
, key2
, match_revoked_key
, pub_compare
));
1001 dst_key_paramcompare(const dst_key_t
*key1
, const dst_key_t
*key2
) {
1002 REQUIRE(dst_initialized
== ISC_TRUE
);
1003 REQUIRE(VALID_KEY(key1
));
1004 REQUIRE(VALID_KEY(key2
));
1008 if (key1
== NULL
|| key2
== NULL
)
1010 if (key1
->key_alg
== key2
->key_alg
&&
1011 key1
->func
->paramcompare
!= NULL
&&
1012 key1
->func
->paramcompare(key1
, key2
) == ISC_TRUE
)
1019 dst_key_free(dst_key_t
**keyp
) {
1023 REQUIRE(dst_initialized
== ISC_TRUE
);
1024 REQUIRE(keyp
!= NULL
&& VALID_KEY(*keyp
));
1029 if (key
->keydata
.generic
!= NULL
) {
1030 INSIST(key
->func
->destroy
!= NULL
);
1031 key
->func
->destroy(key
);
1033 if (key
->engine
!= NULL
)
1034 isc_mem_free(mctx
, key
->engine
);
1035 if (key
->label
!= NULL
)
1036 isc_mem_free(mctx
, key
->label
);
1037 dns_name_free(key
->key_name
, mctx
);
1038 isc_mem_put(mctx
, key
->key_name
, sizeof(dns_name_t
));
1039 memset(key
, 0, sizeof(dst_key_t
));
1040 isc_mem_put(mctx
, key
, sizeof(dst_key_t
));
1045 dst_key_isprivate(const dst_key_t
*key
) {
1046 REQUIRE(VALID_KEY(key
));
1047 INSIST(key
->func
->isprivate
!= NULL
);
1048 return (key
->func
->isprivate(key
));
1052 dst_key_buildfilename(const dst_key_t
*key
, int type
,
1053 const char *directory
, isc_buffer_t
*out
) {
1055 REQUIRE(VALID_KEY(key
));
1056 REQUIRE(type
== DST_TYPE_PRIVATE
|| type
== DST_TYPE_PUBLIC
||
1059 return (buildfilename(key
->key_name
, key
->key_id
, key
->key_alg
,
1060 type
, directory
, out
));
1064 dst_key_sigsize(const dst_key_t
*key
, unsigned int *n
) {
1065 REQUIRE(dst_initialized
== ISC_TRUE
);
1066 REQUIRE(VALID_KEY(key
));
1069 /* XXXVIX this switch statement is too sparse to gen a jump table. */
1070 switch (key
->key_alg
) {
1071 case DST_ALG_RSAMD5
:
1072 case DST_ALG_RSASHA1
:
1073 case DST_ALG_NSEC3RSASHA1
:
1074 case DST_ALG_RSASHA256
:
1075 case DST_ALG_RSASHA512
:
1076 *n
= (key
->key_size
+ 7) / 8;
1079 case DST_ALG_NSEC3DSA
:
1080 *n
= DNS_SIG_DSASIGSIZE
;
1082 case DST_ALG_HMACMD5
:
1085 case DST_ALG_HMACSHA1
:
1086 *n
= ISC_SHA1_DIGESTLENGTH
;
1088 case DST_ALG_HMACSHA224
:
1089 *n
= ISC_SHA224_DIGESTLENGTH
;
1091 case DST_ALG_HMACSHA256
:
1092 *n
= ISC_SHA256_DIGESTLENGTH
;
1094 case DST_ALG_HMACSHA384
:
1095 *n
= ISC_SHA384_DIGESTLENGTH
;
1097 case DST_ALG_HMACSHA512
:
1098 *n
= ISC_SHA512_DIGESTLENGTH
;
1100 case DST_ALG_GSSAPI
:
1101 *n
= 128; /*%< XXX */
1105 return (DST_R_UNSUPPORTEDALG
);
1107 return (ISC_R_SUCCESS
);
1111 dst_key_secretsize(const dst_key_t
*key
, unsigned int *n
) {
1112 REQUIRE(dst_initialized
== ISC_TRUE
);
1113 REQUIRE(VALID_KEY(key
));
1116 if (key
->key_alg
== DST_ALG_DH
)
1117 *n
= (key
->key_size
+ 7) / 8;
1119 return (DST_R_UNSUPPORTEDALG
);
1120 return (ISC_R_SUCCESS
);
1124 * Set the flags on a key, then recompute the key ID
1127 dst_key_setflags(dst_key_t
*key
, isc_uint32_t flags
) {
1128 REQUIRE(VALID_KEY(key
));
1129 key
->key_flags
= flags
;
1130 return (computeid(key
));
1134 dst_key_format(dst_key_t
*key
, char *cp
, unsigned int size
) {
1135 char namestr
[DNS_NAME_FORMATSIZE
];
1136 char algstr
[DNS_NAME_FORMATSIZE
];
1138 dns_name_format(dst_key_name(key
), namestr
, sizeof(namestr
));
1139 dns_secalg_format((dns_secalg_t
) dst_key_alg(key
), algstr
,
1141 snprintf(cp
, size
, "%s/%s/%d", namestr
, algstr
, dst_key_id(key
));
1149 * Allocates a key structure and fills in some of the fields.
1152 get_key_struct(dns_name_t
*name
, unsigned int alg
,
1153 unsigned int flags
, unsigned int protocol
,
1154 unsigned int bits
, dns_rdataclass_t rdclass
,
1158 isc_result_t result
;
1161 key
= (dst_key_t
*) isc_mem_get(mctx
, sizeof(dst_key_t
));
1165 memset(key
, 0, sizeof(dst_key_t
));
1166 key
->magic
= KEY_MAGIC
;
1168 key
->key_name
= isc_mem_get(mctx
, sizeof(dns_name_t
));
1169 if (key
->key_name
== NULL
) {
1170 isc_mem_put(mctx
, key
, sizeof(dst_key_t
));
1173 dns_name_init(key
->key_name
, NULL
);
1174 result
= dns_name_dup(name
, mctx
, key
->key_name
);
1175 if (result
!= ISC_R_SUCCESS
) {
1176 isc_mem_put(mctx
, key
->key_name
, sizeof(dns_name_t
));
1177 isc_mem_put(mctx
, key
, sizeof(dst_key_t
));
1181 key
->key_flags
= flags
;
1182 key
->key_proto
= protocol
;
1184 key
->keydata
.generic
= NULL
;
1185 key
->key_size
= bits
;
1186 key
->key_class
= rdclass
;
1187 key
->func
= dst_t_func
[alg
];
1190 for (i
= 0; i
< (DST_MAX_TIMES
+ 1); i
++) {
1192 key
->timeset
[i
] = ISC_FALSE
;
1198 * Reads a public key from disk
1201 dst_key_read_public(const char *filename
, int type
,
1202 isc_mem_t
*mctx
, dst_key_t
**keyp
)
1204 u_char rdatabuf
[DST_KEY_MAXSIZE
];
1206 dns_fixedname_t name
;
1207 isc_lex_t
*lex
= NULL
;
1210 dns_rdata_t rdata
= DNS_RDATA_INIT
;
1211 unsigned int opt
= ISC_LEXOPT_DNSMULTILINE
;
1212 dns_rdataclass_t rdclass
= dns_rdataclass_in
;
1213 isc_lexspecials_t specials
;
1215 isc_result_t result
;
1216 dns_rdatatype_t keytype
;
1219 * Open the file and read its formatted contents
1221 * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key>
1224 /* 1500 should be large enough for any key */
1225 ret
= isc_lex_create(mctx
, 1500, &lex
);
1226 if (ret
!= ISC_R_SUCCESS
)
1229 memset(specials
, 0, sizeof(specials
));
1233 isc_lex_setspecials(lex
, specials
);
1234 isc_lex_setcomments(lex
, ISC_LEXCOMMENT_DNSMASTERFILE
);
1236 ret
= isc_lex_openfile(lex
, filename
);
1237 if (ret
!= ISC_R_SUCCESS
)
1240 #define NEXTTOKEN(lex, opt, token) { \
1241 ret = isc_lex_gettoken(lex, opt, token); \
1242 if (ret != ISC_R_SUCCESS) \
1246 #define BADTOKEN() { \
1247 ret = ISC_R_UNEXPECTEDTOKEN; \
1251 /* Read the domain name */
1252 NEXTTOKEN(lex
, opt
, &token
);
1253 if (token
.type
!= isc_tokentype_string
)
1257 * We don't support "@" in .key files.
1259 if (!strcmp(DST_AS_STR(token
), "@"))
1262 dns_fixedname_init(&name
);
1263 isc_buffer_init(&b
, DST_AS_STR(token
), strlen(DST_AS_STR(token
)));
1264 isc_buffer_add(&b
, strlen(DST_AS_STR(token
)));
1265 ret
= dns_name_fromtext(dns_fixedname_name(&name
), &b
, dns_rootname
,
1267 if (ret
!= ISC_R_SUCCESS
)
1270 /* Read the next word: either TTL, class, or 'KEY' */
1271 NEXTTOKEN(lex
, opt
, &token
);
1273 if (token
.type
!= isc_tokentype_string
)
1276 /* If it's a TTL, read the next one */
1277 result
= dns_ttl_fromtext(&token
.value
.as_textregion
, &ttl
);
1278 if (result
== ISC_R_SUCCESS
)
1279 NEXTTOKEN(lex
, opt
, &token
);
1281 if (token
.type
!= isc_tokentype_string
)
1284 ret
= dns_rdataclass_fromtext(&rdclass
, &token
.value
.as_textregion
);
1285 if (ret
== ISC_R_SUCCESS
)
1286 NEXTTOKEN(lex
, opt
, &token
);
1288 if (token
.type
!= isc_tokentype_string
)
1291 if (strcasecmp(DST_AS_STR(token
), "DNSKEY") == 0)
1292 keytype
= dns_rdatatype_dnskey
;
1293 else if (strcasecmp(DST_AS_STR(token
), "KEY") == 0)
1294 keytype
= dns_rdatatype_key
; /*%< SIG(0), TKEY */
1298 if (((type
& DST_TYPE_KEY
) != 0 && keytype
!= dns_rdatatype_key
) ||
1299 ((type
& DST_TYPE_KEY
) == 0 && keytype
!= dns_rdatatype_dnskey
)) {
1300 ret
= DST_R_BADKEYTYPE
;
1304 isc_buffer_init(&b
, rdatabuf
, sizeof(rdatabuf
));
1305 ret
= dns_rdata_fromtext(&rdata
, rdclass
, keytype
, lex
, NULL
,
1306 ISC_FALSE
, mctx
, &b
, NULL
);
1307 if (ret
!= ISC_R_SUCCESS
)
1310 ret
= dst_key_fromdns(dns_fixedname_name(&name
), rdclass
, &b
, mctx
,
1312 if (ret
!= ISC_R_SUCCESS
)
1317 isc_lex_destroy(&lex
);
1321 static isc_boolean_t
1322 issymmetric(const dst_key_t
*key
) {
1323 REQUIRE(dst_initialized
== ISC_TRUE
);
1324 REQUIRE(VALID_KEY(key
));
1326 /* XXXVIX this switch statement is too sparse to gen a jump table. */
1327 switch (key
->key_alg
) {
1328 case DST_ALG_RSAMD5
:
1329 case DST_ALG_RSASHA1
:
1330 case DST_ALG_NSEC3RSASHA1
:
1331 case DST_ALG_RSASHA256
:
1332 case DST_ALG_RSASHA512
:
1334 case DST_ALG_NSEC3DSA
:
1337 case DST_ALG_HMACMD5
:
1338 case DST_ALG_GSSAPI
:
1346 * Write key timing metadata to a file pointer, preceded by 'tag'
1349 printtime(const dst_key_t
*key
, int type
, const char *tag
, FILE *stream
) {
1350 isc_result_t result
;
1355 result
= dst_key_gettime(key
, type
, &when
);
1356 if (result
== ISC_R_NOTFOUND
)
1359 /* time_t and isc_stdtime_t might be different sizes */
1362 fprintf(stream
, "%s: %s", tag
, output
);
1366 * Writes a public key to disk in DNS format.
1369 write_public_key(const dst_key_t
*key
, int type
, const char *directory
) {
1371 isc_buffer_t keyb
, textb
, fileb
, classb
;
1373 char filename
[ISC_DIR_NAMEMAX
];
1374 unsigned char key_array
[DST_KEY_MAXSIZE
];
1375 char text_array
[DST_KEY_MAXTEXTSIZE
];
1376 char class_array
[10];
1378 dns_rdata_t rdata
= DNS_RDATA_INIT
;
1379 isc_fsaccess_t access
;
1381 REQUIRE(VALID_KEY(key
));
1383 isc_buffer_init(&keyb
, key_array
, sizeof(key_array
));
1384 isc_buffer_init(&textb
, text_array
, sizeof(text_array
));
1385 isc_buffer_init(&classb
, class_array
, sizeof(class_array
));
1387 ret
= dst_key_todns(key
, &keyb
);
1388 if (ret
!= ISC_R_SUCCESS
)
1391 isc_buffer_usedregion(&keyb
, &r
);
1392 dns_rdata_fromregion(&rdata
, key
->key_class
, dns_rdatatype_dnskey
, &r
);
1394 ret
= dns_rdata_totext(&rdata
, (dns_name_t
*) NULL
, &textb
);
1395 if (ret
!= ISC_R_SUCCESS
)
1396 return (DST_R_INVALIDPUBLICKEY
);
1398 ret
= dns_rdataclass_totext(key
->key_class
, &classb
);
1399 if (ret
!= ISC_R_SUCCESS
)
1400 return (DST_R_INVALIDPUBLICKEY
);
1403 * Make the filename.
1405 isc_buffer_init(&fileb
, filename
, sizeof(filename
));
1406 ret
= dst_key_buildfilename(key
, DST_TYPE_PUBLIC
, directory
, &fileb
);
1407 if (ret
!= ISC_R_SUCCESS
)
1411 * Create public key file.
1413 if ((fp
= fopen(filename
, "w")) == NULL
)
1414 return (DST_R_WRITEERROR
);
1416 if (issymmetric(key
)) {
1418 isc_fsaccess_add(ISC_FSACCESS_OWNER
,
1419 ISC_FSACCESS_READ
| ISC_FSACCESS_WRITE
,
1421 (void)isc_fsaccess_set(filename
, access
);
1424 /* Write key information in comments */
1425 if ((type
& DST_TYPE_KEY
) == 0) {
1426 fprintf(fp
, "; This is a %s%s-signing key, keyid %d, for ",
1427 (key
->key_flags
& DNS_KEYFLAG_REVOKE
) != 0 ?
1430 (key
->key_flags
& DNS_KEYFLAG_KSK
) != 0 ?
1434 ret
= dns_name_print(key
->key_name
, fp
);
1435 if (ret
!= ISC_R_SUCCESS
) {
1441 printtime(key
, DST_TIME_CREATED
, "; Created", fp
);
1442 printtime(key
, DST_TIME_PUBLISH
, "; Publish", fp
);
1443 printtime(key
, DST_TIME_ACTIVATE
, "; Activate", fp
);
1444 printtime(key
, DST_TIME_REVOKE
, "; Revoke", fp
);
1445 printtime(key
, DST_TIME_INACTIVE
, "; Inactive", fp
);
1446 printtime(key
, DST_TIME_DELETE
, "; Delete", fp
);
1449 /* Now print the actual key */
1450 ret
= dns_name_print(key
->key_name
, fp
);
1454 isc_buffer_usedregion(&classb
, &r
);
1455 fwrite(r
.base
, 1, r
.length
, fp
);
1457 if ((type
& DST_TYPE_KEY
) != 0)
1458 fprintf(fp
, " KEY ");
1460 fprintf(fp
, " DNSKEY ");
1462 isc_buffer_usedregion(&textb
, &r
);
1463 fwrite(r
.base
, 1, r
.length
, fp
);
1468 ret
= DST_R_WRITEERROR
;
1475 buildfilename(dns_name_t
*name
, dns_keytag_t id
,
1476 unsigned int alg
, unsigned int type
,
1477 const char *directory
, isc_buffer_t
*out
)
1479 const char *suffix
= "";
1481 isc_result_t result
;
1483 REQUIRE(out
!= NULL
);
1484 if ((type
& DST_TYPE_PRIVATE
) != 0)
1485 suffix
= ".private";
1486 else if (type
== DST_TYPE_PUBLIC
)
1488 if (directory
!= NULL
) {
1489 if (isc_buffer_availablelength(out
) < strlen(directory
))
1490 return (ISC_R_NOSPACE
);
1491 isc_buffer_putstr(out
, directory
);
1492 if (strlen(directory
) > 0U &&
1493 directory
[strlen(directory
) - 1] != '/')
1494 isc_buffer_putstr(out
, "/");
1496 if (isc_buffer_availablelength(out
) < 1)
1497 return (ISC_R_NOSPACE
);
1498 isc_buffer_putstr(out
, "K");
1499 result
= dns_name_tofilenametext(name
, ISC_FALSE
, out
);
1500 if (result
!= ISC_R_SUCCESS
)
1502 len
= 1 + 3 + 1 + 5 + strlen(suffix
) + 1;
1503 if (isc_buffer_availablelength(out
) < len
)
1504 return (ISC_R_NOSPACE
);
1505 sprintf((char *) isc_buffer_used(out
), "+%03d+%05d%s", alg
, id
,
1507 isc_buffer_add(out
, len
);
1509 return (ISC_R_SUCCESS
);
1513 computeid(dst_key_t
*key
) {
1514 isc_buffer_t dnsbuf
;
1515 unsigned char dns_array
[DST_KEY_MAXSIZE
];
1519 isc_buffer_init(&dnsbuf
, dns_array
, sizeof(dns_array
));
1520 ret
= dst_key_todns(key
, &dnsbuf
);
1521 if (ret
!= ISC_R_SUCCESS
)
1524 isc_buffer_usedregion(&dnsbuf
, &r
);
1525 key
->key_id
= dst_region_computeid(&r
, key
->key_alg
);
1526 return (ISC_R_SUCCESS
);
1530 frombuffer(dns_name_t
*name
, unsigned int alg
, unsigned int flags
,
1531 unsigned int protocol
, dns_rdataclass_t rdclass
,
1532 isc_buffer_t
*source
, isc_mem_t
*mctx
, dst_key_t
**keyp
)
1537 REQUIRE(dns_name_isabsolute(name
));
1538 REQUIRE(source
!= NULL
);
1539 REQUIRE(mctx
!= NULL
);
1540 REQUIRE(keyp
!= NULL
&& *keyp
== NULL
);
1542 key
= get_key_struct(name
, alg
, flags
, protocol
, 0, rdclass
, mctx
);
1544 return (ISC_R_NOMEMORY
);
1546 if (isc_buffer_remaininglength(source
) > 0) {
1547 ret
= algorithm_status(alg
);
1548 if (ret
!= ISC_R_SUCCESS
) {
1552 if (key
->func
->fromdns
== NULL
) {
1554 return (DST_R_UNSUPPORTEDALG
);
1557 ret
= key
->func
->fromdns(key
, source
);
1558 if (ret
!= ISC_R_SUCCESS
) {
1565 return (ISC_R_SUCCESS
);
1569 algorithm_status(unsigned int alg
) {
1570 REQUIRE(dst_initialized
== ISC_TRUE
);
1572 if (dst_algorithm_supported(alg
))
1573 return (ISC_R_SUCCESS
);
1575 if (alg
== DST_ALG_RSAMD5
|| alg
== DST_ALG_RSASHA1
||
1576 alg
== DST_ALG_DSA
|| alg
== DST_ALG_DH
||
1577 alg
== DST_ALG_HMACMD5
|| alg
== DST_ALG_NSEC3DSA
||
1578 alg
== DST_ALG_NSEC3RSASHA1
||
1579 alg
== DST_ALG_RSASHA256
|| alg
== DST_ALG_RSASHA512
)
1580 return (DST_R_NOCRYPTO
);
1582 return (DST_R_UNSUPPORTEDALG
);
1586 addsuffix(char *filename
, int len
, const char *odirname
,
1587 const char *ofilename
, const char *suffix
)
1589 int olen
= strlen(ofilename
);
1592 if (olen
> 1 && ofilename
[olen
- 1] == '.')
1594 else if (olen
> 8 && strcmp(ofilename
+ olen
- 8, ".private") == 0)
1596 else if (olen
> 4 && strcmp(ofilename
+ olen
- 4, ".key") == 0)
1599 if (odirname
== NULL
)
1600 n
= snprintf(filename
, len
, "%.*s%s", olen
, ofilename
, suffix
);
1602 n
= snprintf(filename
, len
, "%s/%.*s%s",
1603 odirname
, olen
, ofilename
, suffix
);
1605 return (ISC_R_FAILURE
);
1607 return (ISC_R_NOSPACE
);
1608 return (ISC_R_SUCCESS
);
1612 dst__entropy_getdata(void *buf
, unsigned int len
, isc_boolean_t pseudo
) {
1614 unsigned int flags
= dst_entropy_flags
;
1617 return (ISC_R_SUCCESS
);
1619 flags
&= ~ISC_ENTROPY_GOODONLY
;
1621 flags
|= ISC_ENTROPY_BLOCKING
;
1622 return (isc_entropy_getdata(dst_entropy_pool
, buf
, len
, NULL
, flags
));
1628 return (ISC_R_NOTIMPLEMENTED
);
1633 dst__entropy_status(void) {
1636 unsigned int flags
= dst_entropy_flags
;
1638 unsigned char buf
[32];
1639 static isc_boolean_t first
= ISC_TRUE
;
1642 /* Someone believes RAND_status() initializes the PRNG */
1643 flags
&= ~ISC_ENTROPY_GOODONLY
;
1644 ret
= isc_entropy_getdata(dst_entropy_pool
, buf
,
1645 sizeof(buf
), NULL
, flags
);
1646 INSIST(ret
== ISC_R_SUCCESS
);
1647 isc_entropy_putdata(dst_entropy_pool
, buf
,
1648 sizeof(buf
), 2 * sizeof(buf
));
1652 return (isc_entropy_status(dst_entropy_pool
));