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