xref: /minix/external/bsd/bind/dist/lib/dns/dst_api.c (revision bb9622b5)
1 /*	$NetBSD: dst_api.c,v 1.11 2014/12/10 04:37:58 christos Exp $	*/
2 
3 /*
4  * Portions Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
5  * Portions Copyright (C) 1999-2003  Internet Software Consortium.
6  *
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.
10  *
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.
18  *
19  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
20  *
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.
24  *
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.
32  */
33 
34 /*
35  * Principal Author: Brian Wellington
36  * Id: dst_api.c,v 1.65 2011/10/20 21:20:02 marka Exp
37  */
38 
39 /*! \file */
40 
41 #include <config.h>
42 
43 #include <stdlib.h>
44 #include <time.h>
45 
46 #include <isc/buffer.h>
47 #include <isc/dir.h>
48 #include <isc/entropy.h>
49 #include <isc/fsaccess.h>
50 #include <isc/hmacsha.h>
51 #include <isc/lex.h>
52 #include <isc/mem.h>
53 #include <isc/once.h>
54 #include <isc/platform.h>
55 #include <isc/print.h>
56 #include <isc/refcount.h>
57 #include <isc/random.h>
58 #include <isc/string.h>
59 #include <isc/time.h>
60 #include <isc/util.h>
61 #include <isc/file.h>
62 
63 #define DST_KEY_INTERNAL
64 
65 #include <dns/fixedname.h>
66 #include <dns/keyvalues.h>
67 #include <dns/name.h>
68 #include <dns/rdata.h>
69 #include <dns/rdataclass.h>
70 #include <dns/ttl.h>
71 #include <dns/types.h>
72 
73 #include <dst/result.h>
74 
75 #include "dst_internal.h"
76 
77 #define DST_AS_STR(t) ((t).value.as_textregion.base)
78 
79 static dst_func_t *dst_t_func[DST_MAX_ALGS];
80 static isc_entropy_t *dst_entropy_pool = NULL;
81 static unsigned int dst_entropy_flags = 0;
82 static isc_boolean_t dst_initialized = ISC_FALSE;
83 
84 void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
85 
86 isc_mem_t *dst__memory_pool = NULL;
87 
88 /*
89  * Static functions.
90  */
91 static dst_key_t *	get_key_struct(dns_name_t *name,
92 				       unsigned int alg,
93 				       unsigned int flags,
94 				       unsigned int protocol,
95 				       unsigned int bits,
96 				       dns_rdataclass_t rdclass,
97 				       dns_ttl_t ttl,
98 				       isc_mem_t *mctx);
99 static isc_result_t	write_public_key(const dst_key_t *key, int type,
100 					 const char *directory);
101 static isc_result_t	buildfilename(dns_name_t *name,
102 				      dns_keytag_t id,
103 				      unsigned int alg,
104 				      unsigned int type,
105 				      const char *directory,
106 				      isc_buffer_t *out);
107 static isc_result_t	computeid(dst_key_t *key);
108 static isc_result_t	frombuffer(dns_name_t *name,
109 				   unsigned int alg,
110 				   unsigned int flags,
111 				   unsigned int protocol,
112 				   dns_rdataclass_t rdclass,
113 				   isc_buffer_t *source,
114 				   isc_mem_t *mctx,
115 				   dst_key_t **keyp);
116 
117 static isc_result_t	algorithm_status(unsigned int alg);
118 
119 static isc_result_t	addsuffix(char *filename, int len,
120 				  const char *dirname, const char *ofilename,
121 				  const char *suffix);
122 
123 #define RETERR(x)				\
124 	do {					\
125 		result = (x);			\
126 		if (result != ISC_R_SUCCESS)	\
127 			goto out;		\
128 	} while (/*CONSTCOND*/0)
129 
130 #define CHECKALG(alg)				\
131 	do {					\
132 		isc_result_t _r;		\
133 		_r = algorithm_status(alg);	\
134 		if (_r != ISC_R_SUCCESS)	\
135 			return (_r);		\
136 	} while (/*CONSTCOND*/0);				\
137 
138 #if defined(OPENSSL)
139 static void *
140 default_memalloc(void *arg, size_t size) {
141 	UNUSED(arg);
142 	if (size == 0U)
143 		size = 1;
144 	return (malloc(size));
145 }
146 
147 static void
148 default_memfree(void *arg, void *ptr) {
149 	UNUSED(arg);
150 	free(ptr);
151 }
152 #endif
153 
154 isc_result_t
155 dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) {
156 	return (dst_lib_init2(mctx, ectx, NULL, eflags));
157 }
158 
159 isc_result_t
160 dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
161 	      const char *engine, unsigned int eflags) {
162 	isc_result_t result;
163 
164 	REQUIRE(mctx != NULL);
165 	UNUSED(ectx);
166 	REQUIRE(dst_initialized == ISC_FALSE);
167 
168 #if !defined(OPENSSL) && !defined(PKCS11CRYPTO)
169 	UNUSED(engine);
170 #endif
171 
172 	dst__memory_pool = NULL;
173 
174 #if defined(OPENSSL)
175 	UNUSED(mctx);
176 	/*
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
182 	 * by libcrypto.
183 	 */
184 	result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
185 				  NULL, &dst__memory_pool, 0);
186 	if (result != ISC_R_SUCCESS)
187 		return (result);
188 	isc_mem_setname(dst__memory_pool, "dst", NULL);
189 #ifndef OPENSSL_LEAKS
190 	isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE);
191 #endif
192 #else /* OPENSSL */
193 	isc_mem_attach(mctx, &dst__memory_pool);
194 #endif /* OPENSSL */
195 	if (ectx != NULL) {
196 		isc_entropy_attach(ectx, &dst_entropy_pool);
197 		dst_entropy_flags = eflags;
198 	}
199 
200 	dst_result_register();
201 
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]));
209 #ifdef OPENSSL
210 	RETERR(dst__openssl_init(engine));
211 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5],
212 				    DST_ALG_RSAMD5));
213 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],
214 				    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],
218 				    DST_ALG_RSASHA256));
219 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512],
220 				    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]));
224 #endif
225 	RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
226 #ifdef HAVE_OPENSSL_GOST
227 	RETERR(dst__opensslgost_init(&dst_t_func[DST_ALG_ECCGOST]));
228 #endif
229 #ifdef HAVE_OPENSSL_ECDSA
230 	RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
231 	RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
232 #endif
233 #elif PKCS11CRYPTO
234 	RETERR(dst__pkcs11_init(mctx, engine));
235 	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSAMD5]));
236 	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1]));
237 	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
238 	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256]));
239 	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512]));
240 	RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_DSA]));
241 	RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
242 	RETERR(dst__pkcs11dh_init(&dst_t_func[DST_ALG_DH]));
243 #ifdef HAVE_PKCS11_ECDSA
244 	RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
245 	RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
246 #endif
247 #ifdef HAVE_PKCS11_GOST
248 	RETERR(dst__pkcs11gost_init(&dst_t_func[DST_ALG_ECCGOST]));
249 #endif
250 #endif /* if OPENSSL, elif PKCS11CRYPTO */
251 #ifdef GSSAPI
252 	RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
253 #endif
254 	dst_initialized = ISC_TRUE;
255 	return (ISC_R_SUCCESS);
256 
257  out:
258 	/* avoid immediate crash! */
259 	dst_initialized = ISC_TRUE;
260 	dst_lib_destroy();
261 	return (result);
262 }
263 
264 void
265 dst_lib_destroy(void) {
266 	int i;
267 	RUNTIME_CHECK(dst_initialized == ISC_TRUE);
268 	dst_initialized = ISC_FALSE;
269 
270 	for (i = 0; i < DST_MAX_ALGS; i++)
271 		if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL)
272 			dst_t_func[i]->cleanup();
273 #ifdef OPENSSL
274 	dst__openssl_destroy();
275 #elif PKCS11CRYPTO
276 	(void) dst__pkcs11_destroy();
277 #endif /* if OPENSSL, elif PKCS11CRYPTO */
278 	if (dst__memory_pool != NULL)
279 		isc_mem_detach(&dst__memory_pool);
280 	if (dst_entropy_pool != NULL)
281 		isc_entropy_detach(&dst_entropy_pool);
282 }
283 
284 isc_boolean_t
285 dst_algorithm_supported(unsigned int alg) {
286 	REQUIRE(dst_initialized == ISC_TRUE);
287 
288 	if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
289 		return (ISC_FALSE);
290 	return (ISC_TRUE);
291 }
292 
293 isc_boolean_t
294 dst_ds_digest_supported(unsigned int digest_type) {
295 #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
296 	return  (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 ||
297 			digest_type == DNS_DSDIGEST_SHA256 ||
298 			digest_type == DNS_DSDIGEST_GOST ||
299 			digest_type == DNS_DSDIGEST_SHA384));
300 #else
301 	return  (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 ||
302 			digest_type == DNS_DSDIGEST_SHA256 ||
303 			digest_type == DNS_DSDIGEST_SHA384));
304 #endif
305 }
306 
307 isc_result_t
308 dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
309 	return (dst_context_create4(key, mctx, DNS_LOGCATEGORY_GENERAL,
310 				    ISC_TRUE, 0, dctxp));
311 }
312 
313 isc_result_t
314 dst_context_create2(dst_key_t *key, isc_mem_t *mctx,
315 		    isc_logcategory_t *category, dst_context_t **dctxp)
316 {
317 	return (dst_context_create4(key, mctx, category, ISC_TRUE, 0, dctxp));
318 }
319 
320 isc_result_t
321 dst_context_create3(dst_key_t *key, isc_mem_t *mctx,
322 		    isc_logcategory_t *category, isc_boolean_t useforsigning,
323 		    dst_context_t **dctxp)
324 {
325 	return (dst_context_create4(key, mctx, category,
326 				    useforsigning, 0, dctxp));
327 }
328 
329 isc_result_t
330 dst_context_create4(dst_key_t *key, isc_mem_t *mctx,
331 		    isc_logcategory_t *category, isc_boolean_t useforsigning,
332 		    int maxbits, dst_context_t **dctxp)
333 {
334 	dst_context_t *dctx;
335 	isc_result_t result;
336 
337 	REQUIRE(dst_initialized == ISC_TRUE);
338 	REQUIRE(VALID_KEY(key));
339 	REQUIRE(mctx != NULL);
340 	REQUIRE(dctxp != NULL && *dctxp == NULL);
341 
342 	if (key->func->createctx == NULL &&
343 	    key->func->createctx2 == NULL)
344 		return (DST_R_UNSUPPORTEDALG);
345 	if (key->keydata.generic == NULL)
346 		return (DST_R_NULLKEY);
347 
348 	dctx = isc_mem_get(mctx, sizeof(dst_context_t));
349 	if (dctx == NULL)
350 		return (ISC_R_NOMEMORY);
351 	dctx->key = key;
352 	dctx->mctx = mctx;
353 	dctx->category = category;
354 	if (useforsigning)
355 		dctx->use = DO_SIGN;
356 	else
357 		dctx->use = DO_VERIFY;
358 	if (key->func->createctx2 != NULL)
359 		result = key->func->createctx2(key, maxbits, dctx);
360 	else
361 		result = key->func->createctx(key, dctx);
362 	if (result != ISC_R_SUCCESS) {
363 		isc_mem_put(mctx, dctx, sizeof(dst_context_t));
364 		return (result);
365 	}
366 	dctx->magic = CTX_MAGIC;
367 	*dctxp = dctx;
368 	return (ISC_R_SUCCESS);
369 }
370 
371 void
372 dst_context_destroy(dst_context_t **dctxp) {
373 	dst_context_t *dctx;
374 
375 	REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
376 
377 	dctx = *dctxp;
378 	INSIST(dctx->key->func->destroyctx != NULL);
379 	dctx->key->func->destroyctx(dctx);
380 	dctx->magic = 0;
381 	isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t));
382 	*dctxp = NULL;
383 }
384 
385 isc_result_t
386 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
387 	REQUIRE(VALID_CTX(dctx));
388 	REQUIRE(data != NULL);
389 	INSIST(dctx->key->func->adddata != NULL);
390 
391 	return (dctx->key->func->adddata(dctx, data));
392 }
393 
394 isc_result_t
395 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
396 	dst_key_t *key;
397 
398 	REQUIRE(VALID_CTX(dctx));
399 	REQUIRE(sig != NULL);
400 
401 	key = dctx->key;
402 	CHECKALG(key->key_alg);
403 	if (key->keydata.generic == NULL)
404 		return (DST_R_NULLKEY);
405 
406 	if (key->func->sign == NULL)
407 		return (DST_R_NOTPRIVATEKEY);
408 	if (key->func->isprivate == NULL ||
409 	    key->func->isprivate(key) == ISC_FALSE)
410 		return (DST_R_NOTPRIVATEKEY);
411 
412 	return (key->func->sign(dctx, sig));
413 }
414 
415 isc_result_t
416 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
417 	REQUIRE(VALID_CTX(dctx));
418 	REQUIRE(sig != NULL);
419 
420 	CHECKALG(dctx->key->key_alg);
421 	if (dctx->key->keydata.generic == NULL)
422 		return (DST_R_NULLKEY);
423 	if (dctx->key->func->verify == NULL)
424 		return (DST_R_NOTPUBLICKEY);
425 
426 	return (dctx->key->func->verify(dctx, sig));
427 }
428 
429 isc_result_t
430 dst_context_verify2(dst_context_t *dctx, unsigned int maxbits,
431 		    isc_region_t *sig)
432 {
433 	REQUIRE(VALID_CTX(dctx));
434 	REQUIRE(sig != NULL);
435 
436 	CHECKALG(dctx->key->key_alg);
437 	if (dctx->key->keydata.generic == NULL)
438 		return (DST_R_NULLKEY);
439 	if (dctx->key->func->verify == NULL &&
440 	    dctx->key->func->verify2 == NULL)
441 		return (DST_R_NOTPUBLICKEY);
442 
443 	return (dctx->key->func->verify2 != NULL ?
444 		dctx->key->func->verify2(dctx, maxbits, sig) :
445 		dctx->key->func->verify(dctx, sig));
446 }
447 
448 isc_result_t
449 dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
450 		      isc_buffer_t *secret)
451 {
452 	REQUIRE(dst_initialized == ISC_TRUE);
453 	REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
454 	REQUIRE(secret != NULL);
455 
456 	CHECKALG(pub->key_alg);
457 	CHECKALG(priv->key_alg);
458 
459 	if (pub->keydata.generic == NULL || priv->keydata.generic == NULL)
460 		return (DST_R_NULLKEY);
461 
462 	if (pub->key_alg != priv->key_alg ||
463 	    pub->func->computesecret == NULL ||
464 	    priv->func->computesecret == NULL)
465 		return (DST_R_KEYCANNOTCOMPUTESECRET);
466 
467 	if (dst_key_isprivate(priv) == ISC_FALSE)
468 		return (DST_R_NOTPRIVATEKEY);
469 
470 	return (pub->func->computesecret(pub, priv, secret));
471 }
472 
473 isc_result_t
474 dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
475 	isc_result_t ret = ISC_R_SUCCESS;
476 
477 	REQUIRE(dst_initialized == ISC_TRUE);
478 	REQUIRE(VALID_KEY(key));
479 	REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
480 
481 	CHECKALG(key->key_alg);
482 
483 	if (key->func->tofile == NULL)
484 		return (DST_R_UNSUPPORTEDALG);
485 
486 	if (type & DST_TYPE_PUBLIC) {
487 		ret = write_public_key(key, type, directory);
488 		if (ret != ISC_R_SUCCESS)
489 			return (ret);
490 	}
491 
492 	if ((type & DST_TYPE_PRIVATE) &&
493 	    (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
494 		return (key->func->tofile(key, directory));
495 	else
496 		return (ISC_R_SUCCESS);
497 }
498 
499 void
500 dst_key_setexternal(dst_key_t *key, isc_boolean_t value) {
501 	key->external = value;
502 }
503 
504 isc_boolean_t
505 dst_key_isexternal(dst_key_t *key) {
506 	return (key->external);
507 }
508 
509 isc_result_t
510 dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
511 		 unsigned int alg, int type, const char *directory,
512 		 isc_mem_t *mctx, dst_key_t **keyp)
513 {
514 	char filename[ISC_DIR_NAMEMAX];
515 	isc_buffer_t b;
516 	dst_key_t *key;
517 	isc_result_t result;
518 
519 	REQUIRE(dst_initialized == ISC_TRUE);
520 	REQUIRE(dns_name_isabsolute(name));
521 	REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
522 	REQUIRE(mctx != NULL);
523 	REQUIRE(keyp != NULL && *keyp == NULL);
524 
525 	CHECKALG(alg);
526 
527 	isc_buffer_init(&b, filename, sizeof(filename));
528 	result = buildfilename(name, id, alg, type, directory, &b);
529 	if (result != ISC_R_SUCCESS)
530 		return (result);
531 
532 	key = NULL;
533 	result = dst_key_fromnamedfile(filename, NULL, type, mctx, &key);
534 	if (result != ISC_R_SUCCESS)
535 		return (result);
536 
537 	result = computeid(key);
538 	if (result != ISC_R_SUCCESS) {
539 		dst_key_free(&key);
540 		return (result);
541 	}
542 
543 	if (!dns_name_equal(name, key->key_name) || id != key->key_id ||
544 	    alg != key->key_alg) {
545 		dst_key_free(&key);
546 		return (DST_R_INVALIDPRIVATEKEY);
547 	}
548 
549 	*keyp = key;
550 	return (ISC_R_SUCCESS);
551 }
552 
553 isc_result_t
554 dst_key_fromnamedfile(const char *filename, const char *dirname,
555 		      int type, isc_mem_t *mctx, dst_key_t **keyp)
556 {
557 	isc_result_t result;
558 	dst_key_t *pubkey = NULL, *key = NULL;
559 	char *newfilename = NULL;
560 	int newfilenamelen = 0;
561 	isc_lex_t *lex = NULL;
562 
563 	REQUIRE(dst_initialized == ISC_TRUE);
564 	REQUIRE(filename != NULL);
565 	REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
566 	REQUIRE(mctx != NULL);
567 	REQUIRE(keyp != NULL && *keyp == NULL);
568 
569 	/* If an absolute path is specified, don't use the key directory */
570 #ifndef WIN32
571 	if (filename[0] == '/')
572 		dirname = NULL;
573 #else /* WIN32 */
574 	if (filename[0] == '/' || filename[0] == '\\')
575 		dirname = NULL;
576 #endif
577 
578 	newfilenamelen = strlen(filename) + 5;
579 	if (dirname != NULL)
580 		newfilenamelen += strlen(dirname) + 1;
581 	newfilename = isc_mem_get(mctx, newfilenamelen);
582 	if (newfilename == NULL)
583 		return (ISC_R_NOMEMORY);
584 	result = addsuffix(newfilename, newfilenamelen,
585 			   dirname, filename, ".key");
586 	INSIST(result == ISC_R_SUCCESS);
587 
588 	result = dst_key_read_public(newfilename, type, mctx, &pubkey);
589 	isc_mem_put(mctx, newfilename, newfilenamelen);
590 	newfilename = NULL;
591 	RETERR(result);
592 
593 	if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
594 	    (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
595 		result = computeid(pubkey);
596 		if (result != ISC_R_SUCCESS) {
597 			dst_key_free(&pubkey);
598 			return (result);
599 		}
600 
601 		*keyp = pubkey;
602 		return (ISC_R_SUCCESS);
603 	}
604 
605 	result = algorithm_status(pubkey->key_alg);
606 	if (result != ISC_R_SUCCESS) {
607 		dst_key_free(&pubkey);
608 		return (result);
609 	}
610 
611 	key = get_key_struct(pubkey->key_name, pubkey->key_alg,
612 			     pubkey->key_flags, pubkey->key_proto, 0,
613 			     pubkey->key_class, pubkey->key_ttl, mctx);
614 	if (key == NULL) {
615 		dst_key_free(&pubkey);
616 		return (ISC_R_NOMEMORY);
617 	}
618 
619 	if (key->func->parse == NULL)
620 		RETERR(DST_R_UNSUPPORTEDALG);
621 
622 	newfilenamelen = strlen(filename) + 9;
623 	if (dirname != NULL)
624 		newfilenamelen += strlen(dirname) + 1;
625 	newfilename = isc_mem_get(mctx, newfilenamelen);
626 	if (newfilename == NULL)
627 		RETERR(ISC_R_NOMEMORY);
628 	result = addsuffix(newfilename, newfilenamelen,
629 			   dirname, filename, ".private");
630 	INSIST(result == ISC_R_SUCCESS);
631 
632 	RETERR(isc_lex_create(mctx, 1500, &lex));
633 	RETERR(isc_lex_openfile(lex, newfilename));
634 	isc_mem_put(mctx, newfilename, newfilenamelen);
635 
636 	RETERR(key->func->parse(key, lex, pubkey));
637 	isc_lex_destroy(&lex);
638 
639 	RETERR(computeid(key));
640 
641 	if (pubkey->key_id != key->key_id)
642 		RETERR(DST_R_INVALIDPRIVATEKEY);
643 	dst_key_free(&pubkey);
644 
645 	*keyp = key;
646 	return (ISC_R_SUCCESS);
647 
648  out:
649 	if (pubkey != NULL)
650 		dst_key_free(&pubkey);
651 	if (newfilename != NULL)
652 		isc_mem_put(mctx, newfilename, newfilenamelen);
653 	if (lex != NULL)
654 		isc_lex_destroy(&lex);
655 	if (key != NULL)
656 		dst_key_free(&key);
657 	return (result);
658 }
659 
660 isc_result_t
661 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
662 	REQUIRE(dst_initialized == ISC_TRUE);
663 	REQUIRE(VALID_KEY(key));
664 	REQUIRE(target != NULL);
665 
666 	CHECKALG(key->key_alg);
667 
668 	if (key->func->todns == NULL)
669 		return (DST_R_UNSUPPORTEDALG);
670 
671 	if (isc_buffer_availablelength(target) < 4)
672 		return (ISC_R_NOSPACE);
673 	isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff));
674 	isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto);
675 	isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg);
676 
677 	if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
678 		if (isc_buffer_availablelength(target) < 2)
679 			return (ISC_R_NOSPACE);
680 		isc_buffer_putuint16(target,
681 				     (isc_uint16_t)((key->key_flags >> 16)
682 						    & 0xffff));
683 	}
684 
685 	if (key->keydata.generic == NULL) /*%< NULL KEY */
686 		return (ISC_R_SUCCESS);
687 
688 	return (key->func->todns(key, target));
689 }
690 
691 isc_result_t
692 dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass,
693 		isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
694 {
695 	isc_uint8_t alg, proto;
696 	isc_uint32_t flags, extflags;
697 	dst_key_t *key = NULL;
698 	dns_keytag_t id, rid;
699 	isc_region_t r;
700 	isc_result_t result;
701 
702 	REQUIRE(dst_initialized);
703 
704 	isc_buffer_remainingregion(source, &r);
705 
706 	if (isc_buffer_remaininglength(source) < 4)
707 		return (DST_R_INVALIDPUBLICKEY);
708 	flags = isc_buffer_getuint16(source);
709 	proto = isc_buffer_getuint8(source);
710 	alg = isc_buffer_getuint8(source);
711 
712 	id = dst_region_computeid(&r, alg);
713 	rid = dst_region_computerid(&r, alg);
714 
715 	if (flags & DNS_KEYFLAG_EXTENDED) {
716 		if (isc_buffer_remaininglength(source) < 2)
717 			return (DST_R_INVALIDPUBLICKEY);
718 		extflags = isc_buffer_getuint16(source);
719 		flags |= (extflags << 16);
720 	}
721 
722 	result = frombuffer(name, alg, flags, proto, rdclass, source,
723 			    mctx, &key);
724 	if (result != ISC_R_SUCCESS)
725 		return (result);
726 	key->key_id = id;
727 	key->key_rid = rid;
728 
729 	*keyp = key;
730 	return (ISC_R_SUCCESS);
731 }
732 
733 isc_result_t
734 dst_key_frombuffer(dns_name_t *name, unsigned int alg,
735 		   unsigned int flags, unsigned int protocol,
736 		   dns_rdataclass_t rdclass,
737 		   isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
738 {
739 	dst_key_t *key = NULL;
740 	isc_result_t result;
741 
742 	REQUIRE(dst_initialized);
743 
744 	result = frombuffer(name, alg, flags, protocol, rdclass, source,
745 			    mctx, &key);
746 	if (result != ISC_R_SUCCESS)
747 		return (result);
748 
749 	result = computeid(key);
750 	if (result != ISC_R_SUCCESS) {
751 		dst_key_free(&key);
752 		return (result);
753 	}
754 
755 	*keyp = key;
756 	return (ISC_R_SUCCESS);
757 }
758 
759 isc_result_t
760 dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
761 	REQUIRE(dst_initialized == ISC_TRUE);
762 	REQUIRE(VALID_KEY(key));
763 	REQUIRE(target != NULL);
764 
765 	CHECKALG(key->key_alg);
766 
767 	if (key->func->todns == NULL)
768 		return (DST_R_UNSUPPORTEDALG);
769 
770 	return (key->func->todns(key, target));
771 }
772 
773 isc_result_t
774 dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
775 	isc_lex_t *lex = NULL;
776 	isc_result_t result = ISC_R_SUCCESS;
777 
778 	REQUIRE(dst_initialized == ISC_TRUE);
779 	REQUIRE(VALID_KEY(key));
780 	REQUIRE(!dst_key_isprivate(key));
781 	REQUIRE(buffer != NULL);
782 
783 	if (key->func->parse == NULL)
784 		RETERR(DST_R_UNSUPPORTEDALG);
785 
786 	RETERR(isc_lex_create(key->mctx, 1500, &lex));
787 	RETERR(isc_lex_openbuffer(lex, buffer));
788 	RETERR(key->func->parse(key, lex, NULL));
789  out:
790 	if (lex != NULL)
791 		isc_lex_destroy(&lex);
792 	return (result);
793 }
794 
795 gss_ctx_id_t
796 dst_key_getgssctx(const dst_key_t *key)
797 {
798 	REQUIRE(key != NULL);
799 
800 	return (key->keydata.gssctx);
801 }
802 
803 isc_result_t
804 dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx,
805 		   dst_key_t **keyp, isc_region_t *intoken)
806 {
807 	dst_key_t *key;
808 	isc_result_t result;
809 
810 	REQUIRE(gssctx != NULL);
811 	REQUIRE(keyp != NULL && *keyp == NULL);
812 
813 	key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
814 			     0, dns_rdataclass_in, 0, mctx);
815 	if (key == NULL)
816 		return (ISC_R_NOMEMORY);
817 
818 	if (intoken != NULL) {
819 		/*
820 		 * Keep the token for use by external ssu rules. They may need
821 		 * to examine the PAC in the kerberos ticket.
822 		 */
823 		RETERR(isc_buffer_allocate(key->mctx, &key->key_tkeytoken,
824 		       intoken->length));
825 		RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken));
826 	}
827 
828 	key->keydata.gssctx = gssctx;
829 	*keyp = key;
830 	result = ISC_R_SUCCESS;
831 out:
832 	return result;
833 }
834 
835 isc_result_t
836 dst_key_buildinternal(dns_name_t *name, unsigned int alg,
837 		      unsigned int bits, unsigned int flags,
838 		      unsigned int protocol, dns_rdataclass_t rdclass,
839 		      void *data, isc_mem_t *mctx, dst_key_t **keyp)
840 {
841 	dst_key_t *key;
842 	isc_result_t result;
843 
844 	REQUIRE(dst_initialized == ISC_TRUE);
845 	REQUIRE(dns_name_isabsolute(name));
846 	REQUIRE(mctx != NULL);
847 	REQUIRE(keyp != NULL && *keyp == NULL);
848 	REQUIRE(data != NULL);
849 
850 	CHECKALG(alg);
851 
852 	key = get_key_struct(name, alg, flags, protocol, bits, rdclass,
853 			     0, mctx);
854 	if (key == NULL)
855 		return (ISC_R_NOMEMORY);
856 
857 	key->keydata.generic = data;
858 
859 	result = computeid(key);
860 	if (result != ISC_R_SUCCESS) {
861 		dst_key_free(&key);
862 		return (result);
863 	}
864 
865 	*keyp = key;
866 	return (ISC_R_SUCCESS);
867 }
868 
869 isc_result_t
870 dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags,
871 		  unsigned int protocol, dns_rdataclass_t rdclass,
872 		  const char *engine, const char *label, const char *pin,
873 		  isc_mem_t *mctx, dst_key_t **keyp)
874 {
875 	dst_key_t *key;
876 	isc_result_t result;
877 
878 	REQUIRE(dst_initialized == ISC_TRUE);
879 	REQUIRE(dns_name_isabsolute(name));
880 	REQUIRE(mctx != NULL);
881 	REQUIRE(keyp != NULL && *keyp == NULL);
882 	REQUIRE(label != NULL);
883 
884 	CHECKALG(alg);
885 
886 	key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
887 	if (key == NULL)
888 		return (ISC_R_NOMEMORY);
889 
890 	if (key->func->fromlabel == NULL) {
891 		dst_key_free(&key);
892 		return (DST_R_UNSUPPORTEDALG);
893 	}
894 
895 	result = key->func->fromlabel(key, engine, label, pin);
896 	if (result != ISC_R_SUCCESS) {
897 		dst_key_free(&key);
898 		return (result);
899 	}
900 
901 	result = computeid(key);
902 	if (result != ISC_R_SUCCESS) {
903 		dst_key_free(&key);
904 		return (result);
905 	}
906 
907 	*keyp = key;
908 	return (ISC_R_SUCCESS);
909 }
910 
911 isc_result_t
912 dst_key_generate(dns_name_t *name, unsigned int alg,
913 		 unsigned int bits, unsigned int param,
914 		 unsigned int flags, unsigned int protocol,
915 		 dns_rdataclass_t rdclass,
916 		 isc_mem_t *mctx, dst_key_t **keyp)
917 {
918 	return (dst_key_generate2(name, alg, bits, param, flags, protocol,
919 				  rdclass, mctx, keyp, NULL));
920 }
921 
922 isc_result_t
923 dst_key_generate2(dns_name_t *name, unsigned int alg,
924 		  unsigned int bits, unsigned int param,
925 		  unsigned int flags, unsigned int protocol,
926 		  dns_rdataclass_t rdclass,
927 		  isc_mem_t *mctx, dst_key_t **keyp,
928 		  void (*callback)(int))
929 {
930 	dst_key_t *key;
931 	isc_result_t ret;
932 
933 	REQUIRE(dst_initialized == ISC_TRUE);
934 	REQUIRE(dns_name_isabsolute(name));
935 	REQUIRE(mctx != NULL);
936 	REQUIRE(keyp != NULL && *keyp == NULL);
937 
938 	CHECKALG(alg);
939 
940 	key = get_key_struct(name, alg, flags, protocol, bits,
941 			     rdclass, 0, mctx);
942 	if (key == NULL)
943 		return (ISC_R_NOMEMORY);
944 
945 	if (bits == 0) { /*%< NULL KEY */
946 		key->key_flags |= DNS_KEYTYPE_NOKEY;
947 		*keyp = key;
948 		return (ISC_R_SUCCESS);
949 	}
950 
951 	if (key->func->generate == NULL) {
952 		dst_key_free(&key);
953 		return (DST_R_UNSUPPORTEDALG);
954 	}
955 
956 	ret = key->func->generate(key, param, callback);
957 	if (ret != ISC_R_SUCCESS) {
958 		dst_key_free(&key);
959 		return (ret);
960 	}
961 
962 	ret = computeid(key);
963 	if (ret != ISC_R_SUCCESS) {
964 		dst_key_free(&key);
965 		return (ret);
966 	}
967 
968 	*keyp = key;
969 	return (ISC_R_SUCCESS);
970 }
971 
972 isc_result_t
973 dst_key_getnum(const dst_key_t *key, int type, isc_uint32_t *valuep)
974 {
975 	REQUIRE(VALID_KEY(key));
976 	REQUIRE(valuep != NULL);
977 	REQUIRE(type <= DST_MAX_NUMERIC);
978 	if (!key->numset[type])
979 		return (ISC_R_NOTFOUND);
980 	*valuep = key->nums[type];
981 	return (ISC_R_SUCCESS);
982 }
983 
984 void
985 dst_key_setnum(dst_key_t *key, int type, isc_uint32_t value)
986 {
987 	REQUIRE(VALID_KEY(key));
988 	REQUIRE(type <= DST_MAX_NUMERIC);
989 	key->nums[type] = value;
990 	key->numset[type] = ISC_TRUE;
991 }
992 
993 void
994 dst_key_unsetnum(dst_key_t *key, int type)
995 {
996 	REQUIRE(VALID_KEY(key));
997 	REQUIRE(type <= DST_MAX_NUMERIC);
998 	key->numset[type] = ISC_FALSE;
999 }
1000 
1001 isc_result_t
1002 dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) {
1003 	REQUIRE(VALID_KEY(key));
1004 	REQUIRE(timep != NULL);
1005 	REQUIRE(type <= DST_MAX_TIMES);
1006 	if (!key->timeset[type])
1007 		return (ISC_R_NOTFOUND);
1008 	*timep = key->times[type];
1009 	return (ISC_R_SUCCESS);
1010 }
1011 
1012 void
1013 dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) {
1014 	REQUIRE(VALID_KEY(key));
1015 	REQUIRE(type <= DST_MAX_TIMES);
1016 	key->times[type] = when;
1017 	key->timeset[type] = ISC_TRUE;
1018 }
1019 
1020 void
1021 dst_key_unsettime(dst_key_t *key, int type) {
1022 	REQUIRE(VALID_KEY(key));
1023 	REQUIRE(type <= DST_MAX_TIMES);
1024 	key->timeset[type] = ISC_FALSE;
1025 }
1026 
1027 isc_result_t
1028 dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) {
1029 	REQUIRE(VALID_KEY(key));
1030 	REQUIRE(majorp != NULL);
1031 	REQUIRE(minorp != NULL);
1032 	*majorp = key->fmt_major;
1033 	*minorp = key->fmt_minor;
1034 	return (ISC_R_SUCCESS);
1035 }
1036 
1037 void
1038 dst_key_setprivateformat(dst_key_t *key, int major, int minor) {
1039 	REQUIRE(VALID_KEY(key));
1040 	key->fmt_major = major;
1041 	key->fmt_minor = minor;
1042 }
1043 
1044 static isc_boolean_t
1045 comparekeys(const dst_key_t *key1, const dst_key_t *key2,
1046 	    isc_boolean_t match_revoked_key,
1047 	    isc_boolean_t (*compare)(const dst_key_t *key1,
1048 				     const dst_key_t *key2))
1049 {
1050 	REQUIRE(dst_initialized == ISC_TRUE);
1051 	REQUIRE(VALID_KEY(key1));
1052 	REQUIRE(VALID_KEY(key2));
1053 
1054 	if (key1 == key2)
1055 		return (ISC_TRUE);
1056 
1057 	if (key1 == NULL || key2 == NULL)
1058 		return (ISC_FALSE);
1059 
1060 	if (key1->key_alg != key2->key_alg)
1061 		return (ISC_FALSE);
1062 
1063 	if (key1->key_id != key2->key_id) {
1064 		if (!match_revoked_key)
1065 			return (ISC_FALSE);
1066 		if (key1->key_alg == DST_ALG_RSAMD5)
1067 			return (ISC_FALSE);
1068 		if ((key1->key_flags & DNS_KEYFLAG_REVOKE) ==
1069 		    (key2->key_flags & DNS_KEYFLAG_REVOKE))
1070 			return (ISC_FALSE);
1071 		if (key1->key_id != key2->key_rid &&
1072 		    key1->key_rid != key2->key_id)
1073 			return (ISC_FALSE);
1074 	}
1075 
1076 	if (compare != NULL)
1077 		return (compare(key1, key2));
1078 	else
1079 		return (ISC_FALSE);
1080 }
1081 
1082 
1083 /*
1084  * Compares only the public portion of two keys, by converting them
1085  * both to wire format and comparing the results.
1086  */
1087 static isc_boolean_t
1088 pub_compare(const dst_key_t *key1, const dst_key_t *key2) {
1089 	isc_result_t result;
1090 	unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE];
1091 	isc_buffer_t b1, b2;
1092 	isc_region_t r1, r2;
1093 
1094 	isc_buffer_init(&b1, buf1, sizeof(buf1));
1095 	result = dst_key_todns(key1, &b1);
1096 	if (result != ISC_R_SUCCESS)
1097 		return (ISC_FALSE);
1098 	/* Zero out flags. */
1099 	buf1[0] = buf1[1] = 0;
1100 	if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
1101 		isc_buffer_subtract(&b1, 2);
1102 
1103 	isc_buffer_init(&b2, buf2, sizeof(buf2));
1104 	result = dst_key_todns(key2, &b2);
1105 	if (result != ISC_R_SUCCESS)
1106 		return (ISC_FALSE);
1107 	/* Zero out flags. */
1108 	buf2[0] = buf2[1] = 0;
1109 	if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
1110 		isc_buffer_subtract(&b2, 2);
1111 
1112 	isc_buffer_usedregion(&b1, &r1);
1113 	/* Remove extended flags. */
1114 	if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1115 		memmove(&buf1[4], &buf1[6], r1.length - 6);
1116 		r1.length -= 2;
1117 	}
1118 
1119 	isc_buffer_usedregion(&b2, &r2);
1120 	/* Remove extended flags. */
1121 	if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1122 		memmove(&buf2[4], &buf2[6], r2.length - 6);
1123 		r2.length -= 2;
1124 	}
1125 	return (ISC_TF(isc_region_compare(&r1, &r2) == 0));
1126 }
1127 
1128 isc_boolean_t
1129 dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
1130 	return (comparekeys(key1, key2, ISC_FALSE, key1->func->compare));
1131 }
1132 
1133 isc_boolean_t
1134 dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2,
1135 		   isc_boolean_t match_revoked_key)
1136 {
1137 	return (comparekeys(key1, key2, match_revoked_key, pub_compare));
1138 }
1139 
1140 
1141 isc_boolean_t
1142 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
1143 	REQUIRE(dst_initialized == ISC_TRUE);
1144 	REQUIRE(VALID_KEY(key1));
1145 	REQUIRE(VALID_KEY(key2));
1146 
1147 	if (key1 == key2)
1148 		return (ISC_TRUE);
1149 	if (key1 == NULL || key2 == NULL)
1150 		return (ISC_FALSE);
1151 	if (key1->key_alg == key2->key_alg &&
1152 	    key1->func->paramcompare != NULL &&
1153 	    key1->func->paramcompare(key1, key2) == ISC_TRUE)
1154 		return (ISC_TRUE);
1155 	else
1156 		return (ISC_FALSE);
1157 }
1158 
1159 void
1160 dst_key_attach(dst_key_t *source, dst_key_t **target) {
1161 
1162 	REQUIRE(dst_initialized == ISC_TRUE);
1163 	REQUIRE(target != NULL && *target == NULL);
1164 	REQUIRE(VALID_KEY(source));
1165 
1166 	isc_refcount_increment(&source->refs, NULL);
1167 	*target = source;
1168 }
1169 
1170 void
1171 dst_key_free(dst_key_t **keyp) {
1172 	isc_mem_t *mctx;
1173 	dst_key_t *key;
1174 	unsigned int refs;
1175 
1176 	REQUIRE(dst_initialized == ISC_TRUE);
1177 	REQUIRE(keyp != NULL && VALID_KEY(*keyp));
1178 
1179 	key = *keyp;
1180 	mctx = key->mctx;
1181 
1182 	isc_refcount_decrement(&key->refs, &refs);
1183 	if (refs != 0)
1184 		return;
1185 
1186 	isc_refcount_destroy(&key->refs);
1187 	if (key->keydata.generic != NULL) {
1188 		INSIST(key->func->destroy != NULL);
1189 		key->func->destroy(key);
1190 	}
1191 	if (key->engine != NULL)
1192 		isc_mem_free(mctx, key->engine);
1193 	if (key->label != NULL)
1194 		isc_mem_free(mctx, key->label);
1195 	dns_name_free(key->key_name, mctx);
1196 	isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1197 	if (key->key_tkeytoken) {
1198 		isc_buffer_free(&key->key_tkeytoken);
1199 	}
1200 	memset(key, 0, sizeof(dst_key_t));
1201 	isc_mem_putanddetach(&mctx, key, sizeof(dst_key_t));
1202 	*keyp = NULL;
1203 }
1204 
1205 isc_boolean_t
1206 dst_key_isprivate(const dst_key_t *key) {
1207 	REQUIRE(VALID_KEY(key));
1208 	INSIST(key->func->isprivate != NULL);
1209 	return (key->func->isprivate(key));
1210 }
1211 
1212 isc_result_t
1213 dst_key_buildfilename(const dst_key_t *key, int type,
1214 		      const char *directory, isc_buffer_t *out) {
1215 
1216 	REQUIRE(VALID_KEY(key));
1217 	REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
1218 		type == 0);
1219 
1220 	return (buildfilename(key->key_name, key->key_id, key->key_alg,
1221 			      type, directory, out));
1222 }
1223 
1224 isc_result_t
1225 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
1226 	REQUIRE(dst_initialized == ISC_TRUE);
1227 	REQUIRE(VALID_KEY(key));
1228 	REQUIRE(n != NULL);
1229 
1230 	/* XXXVIX this switch statement is too sparse to gen a jump table. */
1231 	switch (key->key_alg) {
1232 	case DST_ALG_RSAMD5:
1233 	case DST_ALG_RSASHA1:
1234 	case DST_ALG_NSEC3RSASHA1:
1235 	case DST_ALG_RSASHA256:
1236 	case DST_ALG_RSASHA512:
1237 		*n = (key->key_size + 7) / 8;
1238 		break;
1239 	case DST_ALG_DSA:
1240 	case DST_ALG_NSEC3DSA:
1241 		*n = DNS_SIG_DSASIGSIZE;
1242 		break;
1243 	case DST_ALG_ECCGOST:
1244 		*n = DNS_SIG_GOSTSIGSIZE;
1245 		break;
1246 	case DST_ALG_ECDSA256:
1247 		*n = DNS_SIG_ECDSA256SIZE;
1248 		break;
1249 	case DST_ALG_ECDSA384:
1250 		*n = DNS_SIG_ECDSA384SIZE;
1251 		break;
1252 	case DST_ALG_HMACMD5:
1253 		*n = 16;
1254 		break;
1255 	case DST_ALG_HMACSHA1:
1256 		*n = ISC_SHA1_DIGESTLENGTH;
1257 		break;
1258 	case DST_ALG_HMACSHA224:
1259 		*n = ISC_SHA224_DIGESTLENGTH;
1260 		break;
1261 	case DST_ALG_HMACSHA256:
1262 		*n = ISC_SHA256_DIGESTLENGTH;
1263 		break;
1264 	case DST_ALG_HMACSHA384:
1265 		*n = ISC_SHA384_DIGESTLENGTH;
1266 		break;
1267 	case DST_ALG_HMACSHA512:
1268 		*n = ISC_SHA512_DIGESTLENGTH;
1269 		break;
1270 	case DST_ALG_GSSAPI:
1271 		*n = 128; /*%< XXX */
1272 		break;
1273 	case DST_ALG_DH:
1274 	default:
1275 		return (DST_R_UNSUPPORTEDALG);
1276 	}
1277 	return (ISC_R_SUCCESS);
1278 }
1279 
1280 isc_result_t
1281 dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
1282 	REQUIRE(dst_initialized == ISC_TRUE);
1283 	REQUIRE(VALID_KEY(key));
1284 	REQUIRE(n != NULL);
1285 
1286 	if (key->key_alg == DST_ALG_DH)
1287 		*n = (key->key_size + 7) / 8;
1288 	else
1289 		return (DST_R_UNSUPPORTEDALG);
1290 	return (ISC_R_SUCCESS);
1291 }
1292 
1293 /*%
1294  * Set the flags on a key, then recompute the key ID
1295  */
1296 isc_result_t
1297 dst_key_setflags(dst_key_t *key, isc_uint32_t flags) {
1298 	REQUIRE(VALID_KEY(key));
1299 	key->key_flags = flags;
1300 	return (computeid(key));
1301 }
1302 
1303 void
1304 dst_key_format(const dst_key_t *key, char *cp, unsigned int size) {
1305 	char namestr[DNS_NAME_FORMATSIZE];
1306 	char algstr[DNS_NAME_FORMATSIZE];
1307 
1308 	dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
1309 	dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr,
1310 			  sizeof(algstr));
1311 	snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
1312 }
1313 
1314 isc_result_t
1315 dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
1316 
1317 	REQUIRE(buffer != NULL && *buffer == NULL);
1318 	REQUIRE(length != NULL && *length == 0);
1319 	REQUIRE(VALID_KEY(key));
1320 
1321 	if (key->func->dump == NULL)
1322 		return (ISC_R_NOTIMPLEMENTED);
1323 	return (key->func->dump(key, mctx, buffer, length));
1324 }
1325 
1326 isc_result_t
1327 dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags,
1328 		unsigned int protocol, dns_rdataclass_t rdclass,
1329 		isc_mem_t *mctx, const char *keystr, dst_key_t **keyp)
1330 {
1331 	isc_result_t result;
1332 	dst_key_t *key;
1333 
1334 	REQUIRE(dst_initialized == ISC_TRUE);
1335 	REQUIRE(keyp != NULL && *keyp == NULL);
1336 
1337 	if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
1338 		return (DST_R_UNSUPPORTEDALG);
1339 
1340 	if (dst_t_func[alg]->restore == NULL)
1341 		return (ISC_R_NOTIMPLEMENTED);
1342 
1343 	key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
1344 	if (key == NULL)
1345 		return (ISC_R_NOMEMORY);
1346 
1347 	result = (dst_t_func[alg]->restore)(key, keystr);
1348 	if (result == ISC_R_SUCCESS)
1349 		*keyp = key;
1350 	else
1351 		dst_key_free(&key);
1352 
1353 	return (result);
1354 }
1355 
1356 /***
1357  *** Static methods
1358  ***/
1359 
1360 /*%
1361  * Allocates a key structure and fills in some of the fields.
1362  */
1363 static dst_key_t *
1364 get_key_struct(dns_name_t *name, unsigned int alg,
1365 	       unsigned int flags, unsigned int protocol,
1366 	       unsigned int bits, dns_rdataclass_t rdclass,
1367 	       dns_ttl_t ttl, isc_mem_t *mctx)
1368 {
1369 	dst_key_t *key;
1370 	isc_result_t result;
1371 	int i;
1372 
1373 	key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t));
1374 	if (key == NULL)
1375 		return (NULL);
1376 
1377 	memset(key, 0, sizeof(dst_key_t));
1378 
1379 	key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
1380 	if (key->key_name == NULL) {
1381 		isc_mem_put(mctx, key, sizeof(dst_key_t));
1382 		return (NULL);
1383 	}
1384 
1385 	dns_name_init(key->key_name, NULL);
1386 	result = dns_name_dup(name, mctx, key->key_name);
1387 	if (result != ISC_R_SUCCESS) {
1388 		isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1389 		isc_mem_put(mctx, key, sizeof(dst_key_t));
1390 		return (NULL);
1391 	}
1392 
1393 	result = isc_refcount_init(&key->refs, 1);
1394 	if (result != ISC_R_SUCCESS) {
1395 		dns_name_free(key->key_name, mctx);
1396 		isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1397 		isc_mem_put(mctx, key, sizeof(dst_key_t));
1398 		return (NULL);
1399 	}
1400 	isc_mem_attach(mctx, &key->mctx);
1401 	key->key_alg = alg;
1402 	key->key_flags = flags;
1403 	key->key_proto = protocol;
1404 	key->keydata.generic = NULL;
1405 	key->key_size = bits;
1406 	key->key_class = rdclass;
1407 	key->key_ttl = ttl;
1408 	key->func = dst_t_func[alg];
1409 	key->fmt_major = 0;
1410 	key->fmt_minor = 0;
1411 	for (i = 0; i < (DST_MAX_TIMES + 1); i++) {
1412 		key->times[i] = 0;
1413 		key->timeset[i] = ISC_FALSE;
1414 	}
1415 	key->inactive = ISC_FALSE;
1416 	key->magic = KEY_MAGIC;
1417 	return (key);
1418 }
1419 
1420 isc_boolean_t
1421 dst_key_inactive(const dst_key_t *key) {
1422 
1423 	REQUIRE(VALID_KEY(key));
1424 
1425 	return (key->inactive);
1426 }
1427 
1428 void
1429 dst_key_setinactive(dst_key_t *key, isc_boolean_t inactive) {
1430 
1431 	REQUIRE(VALID_KEY(key));
1432 
1433 	key->inactive = inactive;
1434 }
1435 
1436 /*%
1437  * Reads a public key from disk
1438  */
1439 isc_result_t
1440 dst_key_read_public(const char *filename, int type,
1441 		    isc_mem_t *mctx, dst_key_t **keyp)
1442 {
1443 	u_char rdatabuf[DST_KEY_MAXSIZE];
1444 	isc_buffer_t b;
1445 	dns_fixedname_t name;
1446 	isc_lex_t *lex = NULL;
1447 	isc_token_t token;
1448 	isc_result_t ret;
1449 	dns_rdata_t rdata = DNS_RDATA_INIT;
1450 	unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
1451 	dns_rdataclass_t rdclass = dns_rdataclass_in;
1452 	isc_lexspecials_t specials;
1453 	isc_uint32_t ttl = 0;
1454 	isc_result_t result;
1455 	dns_rdatatype_t keytype;
1456 
1457 	/*
1458 	 * Open the file and read its formatted contents
1459 	 * File format:
1460 	 *    domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key>
1461 	 */
1462 
1463 	/* 1500 should be large enough for any key */
1464 	ret = isc_lex_create(mctx, 1500, &lex);
1465 	if (ret != ISC_R_SUCCESS)
1466 		goto cleanup;
1467 
1468 	memset(specials, 0, sizeof(specials));
1469 	specials['('] = 1;
1470 	specials[')'] = 1;
1471 	specials['"'] = 1;
1472 	isc_lex_setspecials(lex, specials);
1473 	isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
1474 
1475 	ret = isc_lex_openfile(lex, filename);
1476 	if (ret != ISC_R_SUCCESS)
1477 		goto cleanup;
1478 
1479 #define NEXTTOKEN(lex, opt, token) { \
1480 	ret = isc_lex_gettoken(lex, opt, token); \
1481 	if (ret != ISC_R_SUCCESS) \
1482 		goto cleanup; \
1483 	}
1484 
1485 #define BADTOKEN() { \
1486 	ret = ISC_R_UNEXPECTEDTOKEN; \
1487 	goto cleanup; \
1488 	}
1489 
1490 	/* Read the domain name */
1491 	NEXTTOKEN(lex, opt, &token);
1492 	if (token.type != isc_tokentype_string)
1493 		BADTOKEN();
1494 
1495 	/*
1496 	 * We don't support "@" in .key files.
1497 	 */
1498 	if (!strcmp(DST_AS_STR(token), "@"))
1499 		BADTOKEN();
1500 
1501 	dns_fixedname_init(&name);
1502 	isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
1503 	isc_buffer_add(&b, strlen(DST_AS_STR(token)));
1504 	ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname,
1505 				0, NULL);
1506 	if (ret != ISC_R_SUCCESS)
1507 		goto cleanup;
1508 
1509 	/* Read the next word: either TTL, class, or 'KEY' */
1510 	NEXTTOKEN(lex, opt, &token);
1511 
1512 	if (token.type != isc_tokentype_string)
1513 		BADTOKEN();
1514 
1515 	/* If it's a TTL, read the next one */
1516 	result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
1517 	if (result == ISC_R_SUCCESS)
1518 		NEXTTOKEN(lex, opt, &token);
1519 
1520 	if (token.type != isc_tokentype_string)
1521 		BADTOKEN();
1522 
1523 	ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
1524 	if (ret == ISC_R_SUCCESS)
1525 		NEXTTOKEN(lex, opt, &token);
1526 
1527 	if (token.type != isc_tokentype_string)
1528 		BADTOKEN();
1529 
1530 	if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0)
1531 		keytype = dns_rdatatype_dnskey;
1532 	else if (strcasecmp(DST_AS_STR(token), "KEY") == 0)
1533 		keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */
1534 	else
1535 		BADTOKEN();
1536 
1537 	if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
1538 	    ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) {
1539 		ret = DST_R_BADKEYTYPE;
1540 		goto cleanup;
1541 	}
1542 
1543 	isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1544 	ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL,
1545 				 ISC_FALSE, mctx, &b, NULL);
1546 	if (ret != ISC_R_SUCCESS)
1547 		goto cleanup;
1548 
1549 	ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
1550 			      keyp);
1551 	if (ret != ISC_R_SUCCESS)
1552 		goto cleanup;
1553 
1554 	dst_key_setttl(*keyp, ttl);
1555 
1556  cleanup:
1557 	if (lex != NULL)
1558 		isc_lex_destroy(&lex);
1559 	return (ret);
1560 }
1561 
1562 static isc_boolean_t
1563 issymmetric(const dst_key_t *key) {
1564 	REQUIRE(dst_initialized == ISC_TRUE);
1565 	REQUIRE(VALID_KEY(key));
1566 
1567 	/* XXXVIX this switch statement is too sparse to gen a jump table. */
1568 	switch (key->key_alg) {
1569 	case DST_ALG_RSAMD5:
1570 	case DST_ALG_RSASHA1:
1571 	case DST_ALG_NSEC3RSASHA1:
1572 	case DST_ALG_RSASHA256:
1573 	case DST_ALG_RSASHA512:
1574 	case DST_ALG_DSA:
1575 	case DST_ALG_NSEC3DSA:
1576 	case DST_ALG_DH:
1577 	case DST_ALG_ECCGOST:
1578 	case DST_ALG_ECDSA256:
1579 	case DST_ALG_ECDSA384:
1580 		return (ISC_FALSE);
1581 	case DST_ALG_HMACMD5:
1582 	case DST_ALG_GSSAPI:
1583 		return (ISC_TRUE);
1584 	default:
1585 		return (ISC_FALSE);
1586 	}
1587 }
1588 
1589 /*%
1590  * Write key timing metadata to a file pointer, preceded by 'tag'
1591  */
1592 static void
1593 printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
1594 	isc_result_t result;
1595 #ifdef ISC_PLATFORM_USETHREADS
1596 	char output[26]; /* Minimum buffer as per ctime_r() specification. */
1597 #else
1598 	const char *output;
1599 #endif
1600 	isc_stdtime_t when;
1601 	time_t t;
1602 	char utc[sizeof("YYYYMMDDHHSSMM")];
1603 	isc_buffer_t b;
1604 	isc_region_t r;
1605 
1606 	result = dst_key_gettime(key, type, &when);
1607 	if (result == ISC_R_NOTFOUND)
1608 		return;
1609 
1610 	/* time_t and isc_stdtime_t might be different sizes */
1611 	t = when;
1612 #ifdef ISC_PLATFORM_USETHREADS
1613 #ifdef WIN32
1614 	if (ctime_s(output, sizeof(output), &t) != 0)
1615 		goto error;
1616 #else
1617 	if (ctime_r(&t, output) == NULL)
1618 		goto error;
1619 #endif
1620 #else
1621 	output = ctime(&t);
1622 #endif
1623 
1624 	isc_buffer_init(&b, utc, sizeof(utc));
1625 	result = dns_time32_totext(when, &b);
1626 	if (result != ISC_R_SUCCESS)
1627 		goto error;
1628 
1629 	isc_buffer_usedregion(&b, &r);
1630 	fprintf(stream, "%s: %.*s (%.*s)\n", tag, (int)r.length, r.base,
1631 		 (int)strlen(output) - 1, output);
1632 	return;
1633 
1634  error:
1635 	fprintf(stream, "%s: (set, unable to display)\n", tag);
1636 }
1637 
1638 /*%
1639  * Writes a public key to disk in DNS format.
1640  */
1641 static isc_result_t
1642 write_public_key(const dst_key_t *key, int type, const char *directory) {
1643 	FILE *fp;
1644 	isc_buffer_t keyb, textb, fileb, classb;
1645 	isc_region_t r;
1646 	char filename[ISC_DIR_NAMEMAX];
1647 	unsigned char key_array[DST_KEY_MAXSIZE];
1648 	char text_array[DST_KEY_MAXTEXTSIZE];
1649 	char class_array[10];
1650 	isc_result_t ret;
1651 	dns_rdata_t rdata = DNS_RDATA_INIT;
1652 	isc_fsaccess_t access;
1653 
1654 	REQUIRE(VALID_KEY(key));
1655 
1656 	isc_buffer_init(&keyb, key_array, sizeof(key_array));
1657 	isc_buffer_init(&textb, text_array, sizeof(text_array));
1658 	isc_buffer_init(&classb, class_array, sizeof(class_array));
1659 
1660 	ret = dst_key_todns(key, &keyb);
1661 	if (ret != ISC_R_SUCCESS)
1662 		return (ret);
1663 
1664 	isc_buffer_usedregion(&keyb, &r);
1665 	dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
1666 
1667 	ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
1668 	if (ret != ISC_R_SUCCESS)
1669 		return (DST_R_INVALIDPUBLICKEY);
1670 
1671 	ret = dns_rdataclass_totext(key->key_class, &classb);
1672 	if (ret != ISC_R_SUCCESS)
1673 		return (DST_R_INVALIDPUBLICKEY);
1674 
1675 	/*
1676 	 * Make the filename.
1677 	 */
1678 	isc_buffer_init(&fileb, filename, sizeof(filename));
1679 	ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
1680 	if (ret != ISC_R_SUCCESS)
1681 		return (ret);
1682 
1683 	/*
1684 	 * Create public key file.
1685 	 */
1686 	if ((fp = fopen(filename, "w")) == NULL)
1687 		return (DST_R_WRITEERROR);
1688 
1689 	if (issymmetric(key)) {
1690 		access = 0;
1691 		isc_fsaccess_add(ISC_FSACCESS_OWNER,
1692 				 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
1693 				 &access);
1694 		(void)isc_fsaccess_set(filename, access);
1695 	}
1696 
1697 	/* Write key information in comments */
1698 	if ((type & DST_TYPE_KEY) == 0) {
1699 		fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ",
1700 			(key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ?
1701 				"revoked " :
1702 				"",
1703 			(key->key_flags & DNS_KEYFLAG_KSK) != 0 ?
1704 				"key" :
1705 				"zone",
1706 			key->key_id);
1707 		ret = dns_name_print(key->key_name, fp);
1708 		if (ret != ISC_R_SUCCESS) {
1709 			fclose(fp);
1710 			return (ret);
1711 		}
1712 		fputc('\n', fp);
1713 
1714 		printtime(key, DST_TIME_CREATED, "; Created", fp);
1715 		printtime(key, DST_TIME_PUBLISH, "; Publish", fp);
1716 		printtime(key, DST_TIME_ACTIVATE, "; Activate", fp);
1717 		printtime(key, DST_TIME_REVOKE, "; Revoke", fp);
1718 		printtime(key, DST_TIME_INACTIVE, "; Inactive", fp);
1719 		printtime(key, DST_TIME_DELETE, "; Delete", fp);
1720 	}
1721 
1722 	/* Now print the actual key */
1723 	ret = dns_name_print(key->key_name, fp);
1724 	fprintf(fp, " ");
1725 
1726 	if (key->key_ttl != 0)
1727 		fprintf(fp, "%d ", key->key_ttl);
1728 
1729 	isc_buffer_usedregion(&classb, &r);
1730 	if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length)
1731 	       ret = DST_R_WRITEERROR;
1732 
1733 	if ((type & DST_TYPE_KEY) != 0)
1734 		fprintf(fp, " KEY ");
1735 	else
1736 		fprintf(fp, " DNSKEY ");
1737 
1738 	isc_buffer_usedregion(&textb, &r);
1739 	if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length)
1740 	       ret = DST_R_WRITEERROR;
1741 
1742 	fputc('\n', fp);
1743 	fflush(fp);
1744 	if (ferror(fp))
1745 		ret = DST_R_WRITEERROR;
1746 	fclose(fp);
1747 
1748 	return (ret);
1749 }
1750 
1751 static isc_result_t
1752 buildfilename(dns_name_t *name, dns_keytag_t id,
1753 	      unsigned int alg, unsigned int type,
1754 	      const char *directory, isc_buffer_t *out)
1755 {
1756 	const char *suffix = "";
1757 	unsigned int len;
1758 	isc_result_t result;
1759 
1760 	REQUIRE(out != NULL);
1761 	if ((type & DST_TYPE_PRIVATE) != 0)
1762 		suffix = ".private";
1763 	else if (type == DST_TYPE_PUBLIC)
1764 		suffix = ".key";
1765 	if (directory != NULL) {
1766 		if (isc_buffer_availablelength(out) < strlen(directory))
1767 			return (ISC_R_NOSPACE);
1768 		isc_buffer_putstr(out, directory);
1769 		if (strlen(directory) > 0U &&
1770 		    directory[strlen(directory) - 1] != '/')
1771 			isc_buffer_putstr(out, "/");
1772 	}
1773 	if (isc_buffer_availablelength(out) < 1)
1774 		return (ISC_R_NOSPACE);
1775 	isc_buffer_putstr(out, "K");
1776 	result = dns_name_tofilenametext(name, ISC_FALSE, out);
1777 	if (result != ISC_R_SUCCESS)
1778 		return (result);
1779 	len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
1780 	if (isc_buffer_availablelength(out) < len)
1781 		return (ISC_R_NOSPACE);
1782 	sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id,
1783 		suffix);
1784 	isc_buffer_add(out, len);
1785 
1786 	return (ISC_R_SUCCESS);
1787 }
1788 
1789 static isc_result_t
1790 computeid(dst_key_t *key) {
1791 	isc_buffer_t dnsbuf;
1792 	unsigned char dns_array[DST_KEY_MAXSIZE];
1793 	isc_region_t r;
1794 	isc_result_t ret;
1795 
1796 	isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
1797 	ret = dst_key_todns(key, &dnsbuf);
1798 	if (ret != ISC_R_SUCCESS)
1799 		return (ret);
1800 
1801 	isc_buffer_usedregion(&dnsbuf, &r);
1802 	key->key_id = dst_region_computeid(&r, key->key_alg);
1803 	key->key_rid = dst_region_computerid(&r, key->key_alg);
1804 	return (ISC_R_SUCCESS);
1805 }
1806 
1807 static isc_result_t
1808 frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags,
1809 	   unsigned int protocol, dns_rdataclass_t rdclass,
1810 	   isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
1811 {
1812 	dst_key_t *key;
1813 	isc_result_t ret;
1814 
1815 	REQUIRE(dns_name_isabsolute(name));
1816 	REQUIRE(source != NULL);
1817 	REQUIRE(mctx != NULL);
1818 	REQUIRE(keyp != NULL && *keyp == NULL);
1819 
1820 	key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
1821 	if (key == NULL)
1822 		return (ISC_R_NOMEMORY);
1823 
1824 	if (isc_buffer_remaininglength(source) > 0) {
1825 		ret = algorithm_status(alg);
1826 		if (ret != ISC_R_SUCCESS) {
1827 			dst_key_free(&key);
1828 			return (ret);
1829 		}
1830 		if (key->func->fromdns == NULL) {
1831 			dst_key_free(&key);
1832 			return (DST_R_UNSUPPORTEDALG);
1833 		}
1834 
1835 		ret = key->func->fromdns(key, source);
1836 		if (ret != ISC_R_SUCCESS) {
1837 			dst_key_free(&key);
1838 			return (ret);
1839 		}
1840 	}
1841 
1842 	*keyp = key;
1843 	return (ISC_R_SUCCESS);
1844 }
1845 
1846 static isc_result_t
1847 algorithm_status(unsigned int alg) {
1848 	REQUIRE(dst_initialized == ISC_TRUE);
1849 
1850 	if (dst_algorithm_supported(alg))
1851 		return (ISC_R_SUCCESS);
1852 #if !defined(OPENSSL) && !defined(PKCS11CRYPTO)
1853 	if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
1854 	    alg == DST_ALG_DSA || alg == DST_ALG_DH ||
1855 	    alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA ||
1856 	    alg == DST_ALG_NSEC3RSASHA1 ||
1857 	    alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512 ||
1858 	    alg == DST_ALG_ECCGOST ||
1859 	    alg == DST_ALG_ECDSA256 || alg == DST_ALG_ECDSA384)
1860 		return (DST_R_NOCRYPTO);
1861 #endif
1862 	return (DST_R_UNSUPPORTEDALG);
1863 }
1864 
1865 static isc_result_t
1866 addsuffix(char *filename, int len, const char *odirname,
1867 	  const char *ofilename, const char *suffix)
1868 {
1869 	int olen = strlen(ofilename);
1870 	int n;
1871 
1872 	if (olen > 1 && ofilename[olen - 1] == '.')
1873 		olen -= 1;
1874 	else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0)
1875 		olen -= 8;
1876 	else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0)
1877 		olen -= 4;
1878 
1879 	if (odirname == NULL)
1880 		n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
1881 	else
1882 		n = snprintf(filename, len, "%s/%.*s%s",
1883 			     odirname, olen, ofilename, suffix);
1884 	if (n < 0)
1885 		return (ISC_R_FAILURE);
1886 	if (n >= len)
1887 		return (ISC_R_NOSPACE);
1888 	return (ISC_R_SUCCESS);
1889 }
1890 
1891 isc_result_t
1892 dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
1893 	unsigned int flags = dst_entropy_flags;
1894 
1895 	if (dst_entropy_pool == NULL)
1896 		return (ISC_R_FAILURE);
1897 
1898 	if (len == 0)
1899 		return (ISC_R_SUCCESS);
1900 
1901 #ifdef PKCS11CRYPTO
1902 	UNUSED(pseudo);
1903 	UNUSED(flags);
1904 	return (pk11_rand_bytes(buf, len));
1905 #else /* PKCS11CRYPTO */
1906 	if (pseudo)
1907 		flags &= ~ISC_ENTROPY_GOODONLY;
1908 	else
1909 		flags |= ISC_ENTROPY_BLOCKING;
1910 	return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));
1911 #endif /* PKCS11CRYPTO */
1912 }
1913 
1914 unsigned int
1915 dst__entropy_status(void) {
1916 #ifndef PKCS11CRYPTO
1917 #ifdef GSSAPI
1918 	unsigned int flags = dst_entropy_flags;
1919 	isc_result_t ret;
1920 	unsigned char buf[32];
1921 	static isc_boolean_t first = ISC_TRUE;
1922 
1923 	if (dst_entropy_pool == NULL)
1924 		return (0);
1925 
1926 	if (first) {
1927 		/* Someone believes RAND_status() initializes the PRNG */
1928 		flags &= ~ISC_ENTROPY_GOODONLY;
1929 		ret = isc_entropy_getdata(dst_entropy_pool, buf,
1930 					  sizeof(buf), NULL, flags);
1931 		INSIST(ret == ISC_R_SUCCESS);
1932 		isc_entropy_putdata(dst_entropy_pool, buf,
1933 				    sizeof(buf), 2 * sizeof(buf));
1934 		first = ISC_FALSE;
1935 	}
1936 #endif
1937 	return (isc_entropy_status(dst_entropy_pool));
1938 #else
1939 	return (0);
1940 #endif
1941 }
1942 
1943 isc_buffer_t *
1944 dst_key_tkeytoken(const dst_key_t *key) {
1945 	REQUIRE(VALID_KEY(key));
1946 	return (key->key_tkeytoken);
1947 }
1948