dst_api.c revision 1.9
1/*	$NetBSD: dst_api.c,v 1.9 2021/04/05 11:27:02 rillig Exp $	*/
2
3/*
4 * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 *
13 * Portions Copyright (C) Network Associates, Inc.
14 *
15 * Permission to use, copy, modify, and/or distribute this software for any
16 * purpose with or without fee is hereby granted, provided that the above
17 * copyright notice and this permission notice appear in all copies.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
20 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
22 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
24 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
25 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 */
27
28/*! \file */
29
30#include <inttypes.h>
31#include <stdbool.h>
32#include <stdlib.h>
33#include <time.h>
34
35#include <isc/buffer.h>
36#include <isc/dir.h>
37#include <isc/file.h>
38#include <isc/fsaccess.h>
39#include <isc/lex.h>
40#include <isc/mem.h>
41#include <isc/once.h>
42#include <isc/platform.h>
43#include <isc/print.h>
44#include <isc/random.h>
45#include <isc/refcount.h>
46#include <isc/safe.h>
47#include <isc/string.h>
48#include <isc/time.h>
49#include <isc/util.h>
50
51#include <pk11/site.h>
52
53#define DST_KEY_INTERNAL
54
55#include <dns/fixedname.h>
56#include <dns/keyvalues.h>
57#include <dns/name.h>
58#include <dns/rdata.h>
59#include <dns/rdataclass.h>
60#include <dns/ttl.h>
61#include <dns/types.h>
62
63#include <dst/result.h>
64
65#include "dst_internal.h"
66
67#define DST_AS_STR(t) ((t).value.as_textregion.base)
68
69#define NEXTTOKEN(lex, opt, token)                       \
70	{                                                \
71		ret = isc_lex_gettoken(lex, opt, token); \
72		if (ret != ISC_R_SUCCESS)                \
73			goto cleanup;                    \
74	}
75
76#define NEXTTOKEN_OR_EOF(lex, opt, token)                \
77	do {                                             \
78		ret = isc_lex_gettoken(lex, opt, token); \
79		if (ret == ISC_R_EOF)                    \
80			break;                           \
81		if (ret != ISC_R_SUCCESS)                \
82			goto cleanup;                    \
83	} while ((*token).type == isc_tokentype_eol);
84
85#define READLINE(lex, opt, token)                        \
86	do {                                             \
87		ret = isc_lex_gettoken(lex, opt, token); \
88		if (ret == ISC_R_EOF)                    \
89			break;                           \
90		if (ret != ISC_R_SUCCESS)                \
91			goto cleanup;                    \
92	} while ((*token).type != isc_tokentype_eol)
93
94#define BADTOKEN()                           \
95	{                                    \
96		ret = ISC_R_UNEXPECTEDTOKEN; \
97		goto cleanup;                \
98	}
99
100#define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1)
101static const char *numerictags[NUMERIC_NTAGS] = {
102	"Predecessor:", "Successor:", "MaxTTL:", "RollPeriod:", "Lifetime:"
103};
104
105#define BOOLEAN_NTAGS (DST_MAX_BOOLEAN + 1)
106static const char *booleantags[BOOLEAN_NTAGS] = { "KSK:", "ZSK:" };
107
108#define TIMING_NTAGS (DST_MAX_TIMES + 1)
109static const char *timingtags[TIMING_NTAGS] = {
110	"Generated:",	 "Published:",	  "Active:",	   "Revoked:",
111	"Retired:",	 "Removed:",
112
113	"DSPublish:",	 "SyncPublish:",  "SyncDelete:",
114
115	"DNSKEYChange:", "ZRRSIGChange:", "KRRSIGChange:", "DSChange:",
116
117	"DSRemoved:"
118};
119
120#define KEYSTATES_NTAGS (DST_MAX_KEYSTATES + 1)
121static const char *keystatestags[KEYSTATES_NTAGS] = {
122	"DNSKEYState:", "ZRRSIGState:", "KRRSIGState:", "DSState:", "GoalState:"
123};
124
125#define KEYSTATES_NVALUES 4
126static const char *keystates[KEYSTATES_NVALUES] = {
127	"hidden",
128	"rumoured",
129	"omnipresent",
130	"unretentive",
131};
132
133#define STATE_ALGORITHM_STR "Algorithm:"
134#define STATE_LENGTH_STR    "Length:"
135#define MAX_NTAGS \
136	(DST_MAX_NUMERIC + DST_MAX_BOOLEAN + DST_MAX_TIMES + DST_MAX_KEYSTATES)
137
138static dst_func_t *dst_t_func[DST_MAX_ALGS];
139
140static bool dst_initialized = false;
141
142void
143gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
144
145/*
146 * Static functions.
147 */
148static dst_key_t *
149get_key_struct(const dns_name_t *name, unsigned int alg, unsigned int flags,
150	       unsigned int protocol, unsigned int bits,
151	       dns_rdataclass_t rdclass, dns_ttl_t ttl, isc_mem_t *mctx);
152static isc_result_t
153write_public_key(const dst_key_t *key, int type, const char *directory);
154static isc_result_t
155write_key_state(const dst_key_t *key, int type, const char *directory);
156static isc_result_t
157buildfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg,
158	      unsigned int type, const char *directory, isc_buffer_t *out);
159static isc_result_t
160computeid(dst_key_t *key);
161static isc_result_t
162frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
163	   unsigned int protocol, dns_rdataclass_t rdclass,
164	   isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
165
166static isc_result_t
167algorithm_status(unsigned int alg);
168
169static isc_result_t
170addsuffix(char *filename, int len, const char *dirname, const char *ofilename,
171	  const char *suffix);
172
173#define RETERR(x)                            \
174	do {                                 \
175		result = (x);                \
176		if (result != ISC_R_SUCCESS) \
177			goto out;            \
178	} while (0)
179
180#define CHECKALG(alg)                       \
181	do {                                \
182		isc_result_t _r;            \
183		_r = algorithm_status(alg); \
184		if (_r != ISC_R_SUCCESS)    \
185			return ((_r));      \
186	} while (0)
187
188isc_result_t
189dst_lib_init(isc_mem_t *mctx, const char *engine) {
190	isc_result_t result;
191
192	REQUIRE(mctx != NULL);
193	REQUIRE(!dst_initialized);
194
195	UNUSED(engine);
196
197	dst_result_register();
198
199	memset(dst_t_func, 0, sizeof(dst_t_func));
200	RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
201	RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
202	RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
203	RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
204	RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
205	RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
206	RETERR(dst__openssl_init(mctx, engine));
207	RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
208#if USE_OPENSSL
209	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],
210				    DST_ALG_RSASHA1));
211	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1],
212				    DST_ALG_NSEC3RSASHA1));
213	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256],
214				    DST_ALG_RSASHA256));
215	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512],
216				    DST_ALG_RSASHA512));
217	RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
218	RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
219#ifdef HAVE_OPENSSL_ED25519
220	RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED25519]));
221#endif /* ifdef HAVE_OPENSSL_ED25519 */
222#ifdef HAVE_OPENSSL_ED448
223	RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED448]));
224#endif /* ifdef HAVE_OPENSSL_ED448 */
225#endif /* USE_OPENSSL */
226
227#if USE_PKCS11
228	RETERR(dst__pkcs11_init(mctx, engine));
229	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1]));
230	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
231	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256]));
232	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512]));
233	RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
234	RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
235	RETERR(dst__pkcs11eddsa_init(&dst_t_func[DST_ALG_ED25519]));
236	RETERR(dst__pkcs11eddsa_init(&dst_t_func[DST_ALG_ED448]));
237#endif /* USE_PKCS11 */
238#ifdef GSSAPI
239	RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
240#endif /* ifdef GSSAPI */
241
242	dst_initialized = true;
243	return (ISC_R_SUCCESS);
244
245out:
246	/* avoid immediate crash! */
247	dst_initialized = true;
248	dst_lib_destroy();
249	return (result);
250}
251
252void
253dst_lib_destroy(void) {
254	int i;
255	RUNTIME_CHECK(dst_initialized);
256	dst_initialized = false;
257
258	for (i = 0; i < DST_MAX_ALGS; i++) {
259		if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL) {
260			dst_t_func[i]->cleanup();
261		}
262	}
263	dst__openssl_destroy();
264#if USE_PKCS11
265	(void)dst__pkcs11_destroy();
266#endif /* USE_PKCS11 */
267}
268
269bool
270dst_algorithm_supported(unsigned int alg) {
271	REQUIRE(dst_initialized);
272
273	if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) {
274		return (false);
275	}
276	return (true);
277}
278
279bool
280dst_ds_digest_supported(unsigned int digest_type) {
281	return (digest_type == DNS_DSDIGEST_SHA1 ||
282		digest_type == DNS_DSDIGEST_SHA256 ||
283		digest_type == DNS_DSDIGEST_SHA384);
284}
285
286isc_result_t
287dst_context_create(dst_key_t *key, isc_mem_t *mctx, isc_logcategory_t *category,
288		   bool useforsigning, int maxbits, dst_context_t **dctxp) {
289	dst_context_t *dctx;
290	isc_result_t result;
291
292	REQUIRE(dst_initialized);
293	REQUIRE(VALID_KEY(key));
294	REQUIRE(mctx != NULL);
295	REQUIRE(dctxp != NULL && *dctxp == NULL);
296
297	if (key->func->createctx == NULL && key->func->createctx2 == NULL) {
298		return (DST_R_UNSUPPORTEDALG);
299	}
300	if (key->keydata.generic == NULL) {
301		return (DST_R_NULLKEY);
302	}
303
304	dctx = isc_mem_get(mctx, sizeof(dst_context_t));
305	memset(dctx, 0, sizeof(*dctx));
306	dst_key_attach(key, &dctx->key);
307	isc_mem_attach(mctx, &dctx->mctx);
308	dctx->category = category;
309	if (useforsigning) {
310		dctx->use = DO_SIGN;
311	} else {
312		dctx->use = DO_VERIFY;
313	}
314	if (key->func->createctx2 != NULL) {
315		result = key->func->createctx2(key, maxbits, dctx);
316	} else {
317		result = key->func->createctx(key, dctx);
318	}
319	if (result != ISC_R_SUCCESS) {
320		if (dctx->key != NULL) {
321			dst_key_free(&dctx->key);
322		}
323		isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(dst_context_t));
324		return (result);
325	}
326	dctx->magic = CTX_MAGIC;
327	*dctxp = dctx;
328	return (ISC_R_SUCCESS);
329}
330
331void
332dst_context_destroy(dst_context_t **dctxp) {
333	dst_context_t *dctx;
334
335	REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
336
337	dctx = *dctxp;
338	*dctxp = NULL;
339	INSIST(dctx->key->func->destroyctx != NULL);
340	dctx->key->func->destroyctx(dctx);
341	if (dctx->key != NULL) {
342		dst_key_free(&dctx->key);
343	}
344	dctx->magic = 0;
345	isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(dst_context_t));
346}
347
348isc_result_t
349dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
350	REQUIRE(VALID_CTX(dctx));
351	REQUIRE(data != NULL);
352	INSIST(dctx->key->func->adddata != NULL);
353
354	return (dctx->key->func->adddata(dctx, data));
355}
356
357isc_result_t
358dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
359	dst_key_t *key;
360
361	REQUIRE(VALID_CTX(dctx));
362	REQUIRE(sig != NULL);
363
364	key = dctx->key;
365	CHECKALG(key->key_alg);
366	if (key->keydata.generic == NULL) {
367		return (DST_R_NULLKEY);
368	}
369
370	if (key->func->sign == NULL) {
371		return (DST_R_NOTPRIVATEKEY);
372	}
373	if (key->func->isprivate == NULL || !key->func->isprivate(key)) {
374		return (DST_R_NOTPRIVATEKEY);
375	}
376
377	return (key->func->sign(dctx, sig));
378}
379
380isc_result_t
381dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
382	REQUIRE(VALID_CTX(dctx));
383	REQUIRE(sig != NULL);
384
385	CHECKALG(dctx->key->key_alg);
386	if (dctx->key->keydata.generic == NULL) {
387		return (DST_R_NULLKEY);
388	}
389	if (dctx->key->func->verify == NULL) {
390		return (DST_R_NOTPUBLICKEY);
391	}
392
393	return (dctx->key->func->verify(dctx, sig));
394}
395
396isc_result_t
397dst_context_verify2(dst_context_t *dctx, unsigned int maxbits,
398		    isc_region_t *sig) {
399	REQUIRE(VALID_CTX(dctx));
400	REQUIRE(sig != NULL);
401
402	CHECKALG(dctx->key->key_alg);
403	if (dctx->key->keydata.generic == NULL) {
404		return (DST_R_NULLKEY);
405	}
406	if (dctx->key->func->verify == NULL && dctx->key->func->verify2 == NULL)
407	{
408		return (DST_R_NOTPUBLICKEY);
409	}
410
411	return (dctx->key->func->verify2 != NULL
412			? dctx->key->func->verify2(dctx, maxbits, sig)
413			: dctx->key->func->verify(dctx, sig));
414}
415
416isc_result_t
417dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
418		      isc_buffer_t *secret) {
419	REQUIRE(dst_initialized);
420	REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
421	REQUIRE(secret != NULL);
422
423	CHECKALG(pub->key_alg);
424	CHECKALG(priv->key_alg);
425
426	if (pub->keydata.generic == NULL || priv->keydata.generic == NULL) {
427		return (DST_R_NULLKEY);
428	}
429
430	if (pub->key_alg != priv->key_alg || pub->func->computesecret == NULL ||
431	    priv->func->computesecret == NULL)
432	{
433		return (DST_R_KEYCANNOTCOMPUTESECRET);
434	}
435
436	if (!dst_key_isprivate(priv)) {
437		return (DST_R_NOTPRIVATEKEY);
438	}
439
440	return (pub->func->computesecret(pub, priv, secret));
441}
442
443isc_result_t
444dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
445	isc_result_t ret = ISC_R_SUCCESS;
446
447	REQUIRE(dst_initialized);
448	REQUIRE(VALID_KEY(key));
449	REQUIRE((type &
450		 (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE)) != 0);
451
452	CHECKALG(key->key_alg);
453
454	if (key->func->tofile == NULL) {
455		return (DST_R_UNSUPPORTEDALG);
456	}
457
458	if ((type & DST_TYPE_PUBLIC) != 0) {
459		ret = write_public_key(key, type, directory);
460		if (ret != ISC_R_SUCCESS) {
461			return (ret);
462		}
463	}
464
465	if ((type & DST_TYPE_STATE) != 0) {
466		ret = write_key_state(key, type, directory);
467		if (ret != ISC_R_SUCCESS) {
468			return (ret);
469		}
470	}
471
472	if (((type & DST_TYPE_PRIVATE) != 0) &&
473	    (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
474	{
475		return (key->func->tofile(key, directory));
476	}
477	return (ISC_R_SUCCESS);
478}
479
480void
481dst_key_setexternal(dst_key_t *key, bool value) {
482	key->external = value;
483}
484
485bool
486dst_key_isexternal(dst_key_t *key) {
487	return (key->external);
488}
489
490isc_result_t
491dst_key_getfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg,
492		    int type, const char *directory, isc_mem_t *mctx,
493		    isc_buffer_t *buf) {
494	isc_result_t result;
495
496	REQUIRE(dst_initialized);
497	REQUIRE(dns_name_isabsolute(name));
498	REQUIRE((type &
499		 (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE)) != 0);
500	REQUIRE(mctx != NULL);
501	REQUIRE(buf != NULL);
502
503	CHECKALG(alg);
504
505	result = buildfilename(name, id, alg, type, directory, buf);
506	if (result == ISC_R_SUCCESS) {
507		if (isc_buffer_availablelength(buf) > 0) {
508			isc_buffer_putuint8(buf, 0);
509		} else {
510			result = ISC_R_NOSPACE;
511		}
512	}
513
514	return (result);
515}
516
517isc_result_t
518dst_key_fromfile(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type,
519		 const char *directory, isc_mem_t *mctx, dst_key_t **keyp) {
520	isc_result_t result;
521	char filename[NAME_MAX];
522	isc_buffer_t buf;
523	dst_key_t *key;
524
525	REQUIRE(dst_initialized);
526	REQUIRE(dns_name_isabsolute(name));
527	REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
528	REQUIRE(mctx != NULL);
529	REQUIRE(keyp != NULL && *keyp == NULL);
530
531	CHECKALG(alg);
532
533	key = NULL;
534
535	isc_buffer_init(&buf, filename, NAME_MAX);
536	result = dst_key_getfilename(name, id, alg, type, NULL, mctx, &buf);
537	if (result != ISC_R_SUCCESS) {
538		goto out;
539	}
540
541	result = dst_key_fromnamedfile(filename, directory, type, mctx, &key);
542	if (result != ISC_R_SUCCESS) {
543		goto out;
544	}
545
546	result = computeid(key);
547	if (result != ISC_R_SUCCESS) {
548		goto out;
549	}
550
551	if (!dns_name_equal(name, key->key_name) || id != key->key_id ||
552	    alg != key->key_alg)
553	{
554		result = DST_R_INVALIDPRIVATEKEY;
555		goto out;
556	}
557
558	*keyp = key;
559	result = ISC_R_SUCCESS;
560
561out:
562	if ((key != NULL) && (result != ISC_R_SUCCESS)) {
563		dst_key_free(&key);
564	}
565
566	return (result);
567}
568
569isc_result_t
570dst_key_fromnamedfile(const char *filename, const char *dirname, int type,
571		      isc_mem_t *mctx, dst_key_t **keyp) {
572	isc_result_t result;
573	dst_key_t *pubkey = NULL, *key = NULL;
574	char *newfilename = NULL;
575	int newfilenamelen = 0;
576	isc_lex_t *lex = NULL;
577
578	REQUIRE(dst_initialized);
579	REQUIRE(filename != NULL);
580	REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
581	REQUIRE(mctx != NULL);
582	REQUIRE(keyp != NULL && *keyp == NULL);
583
584	/* If an absolute path is specified, don't use the key directory */
585#ifndef WIN32
586	if (filename[0] == '/') {
587		dirname = NULL;
588	}
589#else  /* WIN32 */
590	if (filename[0] == '/' || filename[0] == '\\') {
591		dirname = NULL;
592	}
593#endif /* ifndef WIN32 */
594
595	newfilenamelen = strlen(filename) + 5;
596	if (dirname != NULL) {
597		newfilenamelen += strlen(dirname) + 1;
598	}
599	newfilename = isc_mem_get(mctx, newfilenamelen);
600	result = addsuffix(newfilename, newfilenamelen, dirname, filename,
601			   ".key");
602	INSIST(result == ISC_R_SUCCESS);
603
604	result = dst_key_read_public(newfilename, type, mctx, &pubkey);
605	isc_mem_put(mctx, newfilename, newfilenamelen);
606	newfilename = NULL;
607	RETERR(result);
608
609	if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
610	    (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY)
611	{
612		result = computeid(pubkey);
613		if (result != ISC_R_SUCCESS) {
614			dst_key_free(&pubkey);
615			return (result);
616		}
617
618		*keyp = pubkey;
619		return (ISC_R_SUCCESS);
620	}
621
622	result = algorithm_status(pubkey->key_alg);
623	if (result != ISC_R_SUCCESS) {
624		dst_key_free(&pubkey);
625		return (result);
626	}
627
628	key = get_key_struct(pubkey->key_name, pubkey->key_alg,
629			     pubkey->key_flags, pubkey->key_proto,
630			     pubkey->key_size, pubkey->key_class,
631			     pubkey->key_ttl, mctx);
632	if (key == NULL) {
633		dst_key_free(&pubkey);
634		return (ISC_R_NOMEMORY);
635	}
636
637	if (key->func->parse == NULL) {
638		RETERR(DST_R_UNSUPPORTEDALG);
639	}
640
641	/*
642	 * Read the state file, if requested by type.
643	 */
644	if ((type & DST_TYPE_STATE) != 0) {
645		newfilenamelen = strlen(filename) + 7;
646		if (dirname != NULL) {
647			newfilenamelen += strlen(dirname) + 1;
648		}
649		newfilename = isc_mem_get(mctx, newfilenamelen);
650		result = addsuffix(newfilename, newfilenamelen, dirname,
651				   filename, ".state");
652		INSIST(result == ISC_R_SUCCESS);
653
654		key->kasp = false;
655		result = dst_key_read_state(newfilename, mctx, &key);
656		if (result == ISC_R_SUCCESS) {
657			key->kasp = true;
658		} else if (result == ISC_R_FILENOTFOUND) {
659			/* Having no state is valid. */
660			result = ISC_R_SUCCESS;
661		}
662		isc_mem_put(mctx, newfilename, newfilenamelen);
663		newfilename = NULL;
664		RETERR(result);
665	}
666
667	newfilenamelen = strlen(filename) + 9;
668	if (dirname != NULL) {
669		newfilenamelen += strlen(dirname) + 1;
670	}
671	newfilename = isc_mem_get(mctx, newfilenamelen);
672	result = addsuffix(newfilename, newfilenamelen, dirname, filename,
673			   ".private");
674	INSIST(result == ISC_R_SUCCESS);
675
676	RETERR(isc_lex_create(mctx, 1500, &lex));
677	RETERR(isc_lex_openfile(lex, newfilename));
678	isc_mem_put(mctx, newfilename, newfilenamelen);
679
680	RETERR(key->func->parse(key, lex, pubkey));
681	isc_lex_destroy(&lex);
682
683	RETERR(computeid(key));
684
685	if (pubkey->key_id != key->key_id) {
686		RETERR(DST_R_INVALIDPRIVATEKEY);
687	}
688	dst_key_free(&pubkey);
689
690	*keyp = key;
691	return (ISC_R_SUCCESS);
692
693out:
694	if (pubkey != NULL) {
695		dst_key_free(&pubkey);
696	}
697	if (newfilename != NULL) {
698		isc_mem_put(mctx, newfilename, newfilenamelen);
699	}
700	if (lex != NULL) {
701		isc_lex_destroy(&lex);
702	}
703	if (key != NULL) {
704		dst_key_free(&key);
705	}
706	return (result);
707}
708
709isc_result_t
710dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
711	REQUIRE(dst_initialized);
712	REQUIRE(VALID_KEY(key));
713	REQUIRE(target != NULL);
714
715	CHECKALG(key->key_alg);
716
717	if (key->func->todns == NULL) {
718		return (DST_R_UNSUPPORTEDALG);
719	}
720
721	if (isc_buffer_availablelength(target) < 4) {
722		return (ISC_R_NOSPACE);
723	}
724	isc_buffer_putuint16(target, (uint16_t)(key->key_flags & 0xffff));
725	isc_buffer_putuint8(target, (uint8_t)key->key_proto);
726	isc_buffer_putuint8(target, (uint8_t)key->key_alg);
727
728	if ((key->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
729		if (isc_buffer_availablelength(target) < 2) {
730			return (ISC_R_NOSPACE);
731		}
732		isc_buffer_putuint16(
733			target, (uint16_t)((key->key_flags >> 16) & 0xffff));
734	}
735
736	if (key->keydata.generic == NULL) { /*%< NULL KEY */
737		return (ISC_R_SUCCESS);
738	}
739
740	return (key->func->todns(key, target));
741}
742
743isc_result_t
744dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
745		isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
746	uint8_t alg, proto;
747	uint32_t flags, extflags;
748	dst_key_t *key = NULL;
749	dns_keytag_t id, rid;
750	isc_region_t r;
751	isc_result_t result;
752
753	REQUIRE(dst_initialized);
754
755	isc_buffer_remainingregion(source, &r);
756
757	if (isc_buffer_remaininglength(source) < 4) {
758		return (DST_R_INVALIDPUBLICKEY);
759	}
760	flags = isc_buffer_getuint16(source);
761	proto = isc_buffer_getuint8(source);
762	alg = isc_buffer_getuint8(source);
763
764	id = dst_region_computeid(&r);
765	rid = dst_region_computerid(&r);
766
767	if ((flags & DNS_KEYFLAG_EXTENDED) != 0) {
768		if (isc_buffer_remaininglength(source) < 2) {
769			return (DST_R_INVALIDPUBLICKEY);
770		}
771		extflags = isc_buffer_getuint16(source);
772		flags |= (extflags << 16);
773	}
774
775	result = frombuffer(name, alg, flags, proto, rdclass, source, mctx,
776			    &key);
777	if (result != ISC_R_SUCCESS) {
778		return (result);
779	}
780	key->key_id = id;
781	key->key_rid = rid;
782
783	*keyp = key;
784	return (ISC_R_SUCCESS);
785}
786
787isc_result_t
788dst_key_frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
789		   unsigned int protocol, dns_rdataclass_t rdclass,
790		   isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
791	dst_key_t *key = NULL;
792	isc_result_t result;
793
794	REQUIRE(dst_initialized);
795
796	result = frombuffer(name, alg, flags, protocol, rdclass, source, mctx,
797			    &key);
798	if (result != ISC_R_SUCCESS) {
799		return (result);
800	}
801
802	result = computeid(key);
803	if (result != ISC_R_SUCCESS) {
804		dst_key_free(&key);
805		return (result);
806	}
807
808	*keyp = key;
809	return (ISC_R_SUCCESS);
810}
811
812isc_result_t
813dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
814	REQUIRE(dst_initialized);
815	REQUIRE(VALID_KEY(key));
816	REQUIRE(target != NULL);
817
818	CHECKALG(key->key_alg);
819
820	if (key->func->todns == NULL) {
821		return (DST_R_UNSUPPORTEDALG);
822	}
823
824	return (key->func->todns(key, target));
825}
826
827isc_result_t
828dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
829	isc_lex_t *lex = NULL;
830	isc_result_t result = ISC_R_SUCCESS;
831
832	REQUIRE(dst_initialized);
833	REQUIRE(VALID_KEY(key));
834	REQUIRE(!dst_key_isprivate(key));
835	REQUIRE(buffer != NULL);
836
837	if (key->func->parse == NULL) {
838		RETERR(DST_R_UNSUPPORTEDALG);
839	}
840
841	RETERR(isc_lex_create(key->mctx, 1500, &lex));
842	RETERR(isc_lex_openbuffer(lex, buffer));
843	RETERR(key->func->parse(key, lex, NULL));
844out:
845	if (lex != NULL) {
846		isc_lex_destroy(&lex);
847	}
848	return (result);
849}
850
851gss_ctx_id_t
852dst_key_getgssctx(const dst_key_t *key) {
853	REQUIRE(key != NULL);
854
855	return (key->keydata.gssctx);
856}
857
858isc_result_t
859dst_key_fromgssapi(const dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx,
860		   dst_key_t **keyp, isc_region_t *intoken) {
861	dst_key_t *key;
862	isc_result_t result;
863
864	REQUIRE(gssctx != NULL);
865	REQUIRE(keyp != NULL && *keyp == NULL);
866
867	key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 0,
868			     dns_rdataclass_in, 0, mctx);
869	if (key == NULL) {
870		return (ISC_R_NOMEMORY);
871	}
872
873	if (intoken != NULL) {
874		/*
875		 * Keep the token for use by external ssu rules. They may need
876		 * to examine the PAC in the kerberos ticket.
877		 */
878		isc_buffer_allocate(key->mctx, &key->key_tkeytoken,
879				    intoken->length);
880		RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken));
881	}
882
883	key->keydata.gssctx = gssctx;
884	*keyp = key;
885	result = ISC_R_SUCCESS;
886out:
887	if (result != ISC_R_SUCCESS) {
888		dst_key_free(&key);
889	}
890	return (result);
891}
892
893isc_result_t
894dst_key_buildinternal(const dns_name_t *name, unsigned int alg,
895		      unsigned int bits, unsigned int flags,
896		      unsigned int protocol, dns_rdataclass_t rdclass,
897		      void *data, isc_mem_t *mctx, dst_key_t **keyp) {
898	dst_key_t *key;
899	isc_result_t result;
900
901	REQUIRE(dst_initialized);
902	REQUIRE(dns_name_isabsolute(name));
903	REQUIRE(mctx != NULL);
904	REQUIRE(keyp != NULL && *keyp == NULL);
905	REQUIRE(data != NULL);
906
907	CHECKALG(alg);
908
909	key = get_key_struct(name, alg, flags, protocol, bits, rdclass, 0,
910			     mctx);
911	if (key == NULL) {
912		return (ISC_R_NOMEMORY);
913	}
914
915	key->keydata.generic = data;
916
917	result = computeid(key);
918	if (result != ISC_R_SUCCESS) {
919		dst_key_free(&key);
920		return (result);
921	}
922
923	*keyp = key;
924	return (ISC_R_SUCCESS);
925}
926
927isc_result_t
928dst_key_fromlabel(const dns_name_t *name, int alg, unsigned int flags,
929		  unsigned int protocol, dns_rdataclass_t rdclass,
930		  const char *engine, const char *label, const char *pin,
931		  isc_mem_t *mctx, dst_key_t **keyp) {
932	dst_key_t *key;
933	isc_result_t result;
934
935	REQUIRE(dst_initialized);
936	REQUIRE(dns_name_isabsolute(name));
937	REQUIRE(mctx != NULL);
938	REQUIRE(keyp != NULL && *keyp == NULL);
939	REQUIRE(label != NULL);
940
941	CHECKALG(alg);
942
943	key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
944	if (key == NULL) {
945		return (ISC_R_NOMEMORY);
946	}
947
948	if (key->func->fromlabel == NULL) {
949		dst_key_free(&key);
950		return (DST_R_UNSUPPORTEDALG);
951	}
952
953	result = key->func->fromlabel(key, engine, label, pin);
954	if (result != ISC_R_SUCCESS) {
955		dst_key_free(&key);
956		return (result);
957	}
958
959	result = computeid(key);
960	if (result != ISC_R_SUCCESS) {
961		dst_key_free(&key);
962		return (result);
963	}
964
965	*keyp = key;
966	return (ISC_R_SUCCESS);
967}
968
969isc_result_t
970dst_key_generate(const dns_name_t *name, unsigned int alg, unsigned int bits,
971		 unsigned int param, unsigned int flags, unsigned int protocol,
972		 dns_rdataclass_t rdclass, isc_mem_t *mctx, dst_key_t **keyp,
973		 void (*callback)(int)) {
974	dst_key_t *key;
975	isc_result_t ret;
976
977	REQUIRE(dst_initialized);
978	REQUIRE(dns_name_isabsolute(name));
979	REQUIRE(mctx != NULL);
980	REQUIRE(keyp != NULL && *keyp == NULL);
981
982	CHECKALG(alg);
983
984	key = get_key_struct(name, alg, flags, protocol, bits, rdclass, 0,
985			     mctx);
986	if (key == NULL) {
987		return (ISC_R_NOMEMORY);
988	}
989
990	if (bits == 0) { /*%< NULL KEY */
991		key->key_flags |= DNS_KEYTYPE_NOKEY;
992		*keyp = key;
993		return (ISC_R_SUCCESS);
994	}
995
996	if (key->func->generate == NULL) {
997		dst_key_free(&key);
998		return (DST_R_UNSUPPORTEDALG);
999	}
1000
1001	ret = key->func->generate(key, param, callback);
1002	if (ret != ISC_R_SUCCESS) {
1003		dst_key_free(&key);
1004		return (ret);
1005	}
1006
1007	ret = computeid(key);
1008	if (ret != ISC_R_SUCCESS) {
1009		dst_key_free(&key);
1010		return (ret);
1011	}
1012
1013	*keyp = key;
1014	return (ISC_R_SUCCESS);
1015}
1016
1017isc_result_t
1018dst_key_getbool(const dst_key_t *key, int type, bool *valuep) {
1019	REQUIRE(VALID_KEY(key));
1020	REQUIRE(valuep != NULL);
1021	REQUIRE(type <= DST_MAX_BOOLEAN);
1022	if (!key->boolset[type]) {
1023		return (ISC_R_NOTFOUND);
1024	}
1025	*valuep = key->bools[type];
1026	return (ISC_R_SUCCESS);
1027}
1028
1029void
1030dst_key_setbool(dst_key_t *key, int type, bool value) {
1031	REQUIRE(VALID_KEY(key));
1032	REQUIRE(type <= DST_MAX_BOOLEAN);
1033	key->bools[type] = value;
1034	key->boolset[type] = true;
1035}
1036
1037void
1038dst_key_unsetbool(dst_key_t *key, int type) {
1039	REQUIRE(VALID_KEY(key));
1040	REQUIRE(type <= DST_MAX_BOOLEAN);
1041	key->boolset[type] = false;
1042}
1043
1044isc_result_t
1045dst_key_getnum(const dst_key_t *key, int type, uint32_t *valuep) {
1046	REQUIRE(VALID_KEY(key));
1047	REQUIRE(valuep != NULL);
1048	REQUIRE(type <= DST_MAX_NUMERIC);
1049	if (!key->numset[type]) {
1050		return (ISC_R_NOTFOUND);
1051	}
1052	*valuep = key->nums[type];
1053	return (ISC_R_SUCCESS);
1054}
1055
1056void
1057dst_key_setnum(dst_key_t *key, int type, uint32_t value) {
1058	REQUIRE(VALID_KEY(key));
1059	REQUIRE(type <= DST_MAX_NUMERIC);
1060	key->nums[type] = value;
1061	key->numset[type] = true;
1062}
1063
1064void
1065dst_key_unsetnum(dst_key_t *key, int type) {
1066	REQUIRE(VALID_KEY(key));
1067	REQUIRE(type <= DST_MAX_NUMERIC);
1068	key->numset[type] = false;
1069}
1070
1071isc_result_t
1072dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) {
1073	REQUIRE(VALID_KEY(key));
1074	REQUIRE(timep != NULL);
1075	REQUIRE(type <= DST_MAX_TIMES);
1076	if (!key->timeset[type]) {
1077		return (ISC_R_NOTFOUND);
1078	}
1079	*timep = key->times[type];
1080	return (ISC_R_SUCCESS);
1081}
1082
1083void
1084dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) {
1085	REQUIRE(VALID_KEY(key));
1086	REQUIRE(type <= DST_MAX_TIMES);
1087	key->times[type] = when;
1088	key->timeset[type] = true;
1089}
1090
1091void
1092dst_key_unsettime(dst_key_t *key, int type) {
1093	REQUIRE(VALID_KEY(key));
1094	REQUIRE(type <= DST_MAX_TIMES);
1095	key->timeset[type] = false;
1096}
1097
1098isc_result_t
1099dst_key_getstate(const dst_key_t *key, int type, dst_key_state_t *statep) {
1100	REQUIRE(VALID_KEY(key));
1101	REQUIRE(statep != NULL);
1102	REQUIRE(type <= DST_MAX_KEYSTATES);
1103	if (!key->keystateset[type]) {
1104		return (ISC_R_NOTFOUND);
1105	}
1106	*statep = key->keystates[type];
1107	return (ISC_R_SUCCESS);
1108}
1109
1110void
1111dst_key_setstate(dst_key_t *key, int type, dst_key_state_t state) {
1112	REQUIRE(VALID_KEY(key));
1113	REQUIRE(type <= DST_MAX_KEYSTATES);
1114	key->keystates[type] = state;
1115	key->keystateset[type] = true;
1116}
1117
1118void
1119dst_key_unsetstate(dst_key_t *key, int type) {
1120	REQUIRE(VALID_KEY(key));
1121	REQUIRE(type <= DST_MAX_KEYSTATES);
1122	key->keystateset[type] = false;
1123}
1124
1125isc_result_t
1126dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) {
1127	REQUIRE(VALID_KEY(key));
1128	REQUIRE(majorp != NULL);
1129	REQUIRE(minorp != NULL);
1130	*majorp = key->fmt_major;
1131	*minorp = key->fmt_minor;
1132	return (ISC_R_SUCCESS);
1133}
1134
1135void
1136dst_key_setprivateformat(dst_key_t *key, int major, int minor) {
1137	REQUIRE(VALID_KEY(key));
1138	key->fmt_major = major;
1139	key->fmt_minor = minor;
1140}
1141
1142static bool
1143comparekeys(const dst_key_t *key1, const dst_key_t *key2,
1144	    bool match_revoked_key,
1145	    bool (*compare)(const dst_key_t *key1, const dst_key_t *key2)) {
1146	REQUIRE(dst_initialized);
1147	REQUIRE(VALID_KEY(key1));
1148	REQUIRE(VALID_KEY(key2));
1149
1150	if (key1 == key2) {
1151		return (true);
1152	}
1153
1154	if (key1->key_alg != key2->key_alg) {
1155		return (false);
1156	}
1157
1158	if (key1->key_id != key2->key_id) {
1159		if (!match_revoked_key) {
1160			return (false);
1161		}
1162		if ((key1->key_flags & DNS_KEYFLAG_REVOKE) ==
1163		    (key2->key_flags & DNS_KEYFLAG_REVOKE))
1164		{
1165			return (false);
1166		}
1167		if (key1->key_id != key2->key_rid &&
1168		    key1->key_rid != key2->key_id) {
1169			return (false);
1170		}
1171	}
1172
1173	if (compare != NULL) {
1174		return (compare(key1, key2));
1175	} else {
1176		return (false);
1177	}
1178}
1179
1180/*
1181 * Compares only the public portion of two keys, by converting them
1182 * both to wire format and comparing the results.
1183 */
1184static bool
1185pub_compare(const dst_key_t *key1, const dst_key_t *key2) {
1186	isc_result_t result;
1187	unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE];
1188	isc_buffer_t b1, b2;
1189	isc_region_t r1, r2;
1190
1191	isc_buffer_init(&b1, buf1, sizeof(buf1));
1192	result = dst_key_todns(key1, &b1);
1193	if (result != ISC_R_SUCCESS) {
1194		return (false);
1195	}
1196	/* Zero out flags. */
1197	buf1[0] = buf1[1] = 0;
1198	if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1199		isc_buffer_subtract(&b1, 2);
1200	}
1201
1202	isc_buffer_init(&b2, buf2, sizeof(buf2));
1203	result = dst_key_todns(key2, &b2);
1204	if (result != ISC_R_SUCCESS) {
1205		return (false);
1206	}
1207	/* Zero out flags. */
1208	buf2[0] = buf2[1] = 0;
1209	if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1210		isc_buffer_subtract(&b2, 2);
1211	}
1212
1213	isc_buffer_usedregion(&b1, &r1);
1214	/* Remove extended flags. */
1215	if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1216		memmove(&buf1[4], &buf1[6], r1.length - 6);
1217		r1.length -= 2;
1218	}
1219
1220	isc_buffer_usedregion(&b2, &r2);
1221	/* Remove extended flags. */
1222	if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1223		memmove(&buf2[4], &buf2[6], r2.length - 6);
1224		r2.length -= 2;
1225	}
1226	return (isc_region_compare(&r1, &r2) == 0);
1227}
1228
1229bool
1230dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
1231	return (comparekeys(key1, key2, false, key1->func->compare));
1232}
1233
1234bool
1235dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2,
1236		   bool match_revoked_key) {
1237	return (comparekeys(key1, key2, match_revoked_key, pub_compare));
1238}
1239
1240bool
1241dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
1242	REQUIRE(dst_initialized);
1243	REQUIRE(VALID_KEY(key1));
1244	REQUIRE(VALID_KEY(key2));
1245
1246	if (key1 == key2) {
1247		return (true);
1248	}
1249	if (key1->key_alg == key2->key_alg &&
1250	    key1->func->paramcompare != NULL &&
1251	    key1->func->paramcompare(key1, key2))
1252	{
1253		return (true);
1254	} else {
1255		return (false);
1256	}
1257}
1258
1259void
1260dst_key_attach(dst_key_t *source, dst_key_t **target) {
1261	REQUIRE(dst_initialized);
1262	REQUIRE(target != NULL && *target == NULL);
1263	REQUIRE(VALID_KEY(source));
1264
1265	isc_refcount_increment(&source->refs);
1266	*target = source;
1267}
1268
1269void
1270dst_key_free(dst_key_t **keyp) {
1271	REQUIRE(dst_initialized);
1272	REQUIRE(keyp != NULL && VALID_KEY(*keyp));
1273	dst_key_t *key = *keyp;
1274	*keyp = NULL;
1275
1276	if (isc_refcount_decrement(&key->refs) == 1) {
1277		isc_refcount_destroy(&key->refs);
1278		isc_mem_t *mctx = key->mctx;
1279		if (key->keydata.generic != NULL) {
1280			INSIST(key->func->destroy != NULL);
1281			key->func->destroy(key);
1282		}
1283		if (key->engine != NULL) {
1284			isc_mem_free(mctx, key->engine);
1285		}
1286		if (key->label != NULL) {
1287			isc_mem_free(mctx, key->label);
1288		}
1289		dns_name_free(key->key_name, mctx);
1290		isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1291		if (key->key_tkeytoken) {
1292			isc_buffer_free(&key->key_tkeytoken);
1293		}
1294		isc_safe_memwipe(key, sizeof(*key));
1295		isc_mem_putanddetach(&mctx, key, sizeof(*key));
1296	}
1297}
1298
1299bool
1300dst_key_isprivate(const dst_key_t *key) {
1301	REQUIRE(VALID_KEY(key));
1302	INSIST(key->func->isprivate != NULL);
1303	return (key->func->isprivate(key));
1304}
1305
1306isc_result_t
1307dst_key_buildfilename(const dst_key_t *key, int type, const char *directory,
1308		      isc_buffer_t *out) {
1309	REQUIRE(VALID_KEY(key));
1310	REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
1311		type == DST_TYPE_STATE || type == 0);
1312
1313	return (buildfilename(key->key_name, key->key_id, key->key_alg, type,
1314			      directory, out));
1315}
1316
1317isc_result_t
1318dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
1319	REQUIRE(dst_initialized);
1320	REQUIRE(VALID_KEY(key));
1321	REQUIRE(n != NULL);
1322
1323	/* XXXVIX this switch statement is too sparse to gen a jump table. */
1324	switch (key->key_alg) {
1325	case DST_ALG_RSASHA1:
1326	case DST_ALG_NSEC3RSASHA1:
1327	case DST_ALG_RSASHA256:
1328	case DST_ALG_RSASHA512:
1329		*n = (key->key_size + 7) / 8;
1330		break;
1331	case DST_ALG_ECDSA256:
1332		*n = DNS_SIG_ECDSA256SIZE;
1333		break;
1334	case DST_ALG_ECDSA384:
1335		*n = DNS_SIG_ECDSA384SIZE;
1336		break;
1337	case DST_ALG_ED25519:
1338		*n = DNS_SIG_ED25519SIZE;
1339		break;
1340	case DST_ALG_ED448:
1341		*n = DNS_SIG_ED448SIZE;
1342		break;
1343	case DST_ALG_HMACMD5:
1344		*n = isc_md_type_get_size(ISC_MD_MD5);
1345		break;
1346	case DST_ALG_HMACSHA1:
1347		*n = isc_md_type_get_size(ISC_MD_SHA1);
1348		break;
1349	case DST_ALG_HMACSHA224:
1350		*n = isc_md_type_get_size(ISC_MD_SHA224);
1351		break;
1352	case DST_ALG_HMACSHA256:
1353		*n = isc_md_type_get_size(ISC_MD_SHA256);
1354		break;
1355	case DST_ALG_HMACSHA384:
1356		*n = isc_md_type_get_size(ISC_MD_SHA384);
1357		break;
1358	case DST_ALG_HMACSHA512:
1359		*n = isc_md_type_get_size(ISC_MD_SHA512);
1360		break;
1361	case DST_ALG_GSSAPI:
1362		*n = 128; /*%< XXX */
1363		break;
1364	case DST_ALG_DH:
1365	default:
1366		return (DST_R_UNSUPPORTEDALG);
1367	}
1368	return (ISC_R_SUCCESS);
1369}
1370
1371isc_result_t
1372dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
1373	REQUIRE(dst_initialized);
1374	REQUIRE(VALID_KEY(key));
1375	REQUIRE(n != NULL);
1376
1377	if (key->key_alg == DST_ALG_DH) {
1378		*n = (key->key_size + 7) / 8;
1379		return (ISC_R_SUCCESS);
1380	}
1381	return (DST_R_UNSUPPORTEDALG);
1382}
1383
1384/*%
1385 * Set the flags on a key, then recompute the key ID
1386 */
1387isc_result_t
1388dst_key_setflags(dst_key_t *key, uint32_t flags) {
1389	REQUIRE(VALID_KEY(key));
1390	key->key_flags = flags;
1391	return (computeid(key));
1392}
1393
1394void
1395dst_key_format(const dst_key_t *key, char *cp, unsigned int size) {
1396	char namestr[DNS_NAME_FORMATSIZE];
1397	char algstr[DNS_NAME_FORMATSIZE];
1398
1399	dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
1400	dns_secalg_format((dns_secalg_t)dst_key_alg(key), algstr,
1401			  sizeof(algstr));
1402	snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
1403}
1404
1405isc_result_t
1406dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
1407	REQUIRE(buffer != NULL && *buffer == NULL);
1408	REQUIRE(length != NULL && *length == 0);
1409	REQUIRE(VALID_KEY(key));
1410
1411	if (key->func->dump == NULL) {
1412		return (ISC_R_NOTIMPLEMENTED);
1413	}
1414	return (key->func->dump(key, mctx, buffer, length));
1415}
1416
1417isc_result_t
1418dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags,
1419		unsigned int protocol, dns_rdataclass_t rdclass,
1420		isc_mem_t *mctx, const char *keystr, dst_key_t **keyp) {
1421	isc_result_t result;
1422	dst_key_t *key;
1423
1424	REQUIRE(dst_initialized);
1425	REQUIRE(keyp != NULL && *keyp == NULL);
1426
1427	if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) {
1428		return (DST_R_UNSUPPORTEDALG);
1429	}
1430
1431	if (dst_t_func[alg]->restore == NULL) {
1432		return (ISC_R_NOTIMPLEMENTED);
1433	}
1434
1435	key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
1436	if (key == NULL) {
1437		return (ISC_R_NOMEMORY);
1438	}
1439
1440	result = (dst_t_func[alg]->restore)(key, keystr);
1441	if (result == ISC_R_SUCCESS) {
1442		*keyp = key;
1443	} else {
1444		dst_key_free(&key);
1445	}
1446
1447	return (result);
1448}
1449
1450/***
1451 *** Static methods
1452 ***/
1453
1454/*%
1455 * Allocates a key structure and fills in some of the fields.
1456 */
1457static dst_key_t *
1458get_key_struct(const dns_name_t *name, unsigned int alg, unsigned int flags,
1459	       unsigned int protocol, unsigned int bits,
1460	       dns_rdataclass_t rdclass, dns_ttl_t ttl, isc_mem_t *mctx) {
1461	dst_key_t *key;
1462	int i;
1463
1464	key = isc_mem_get(mctx, sizeof(dst_key_t));
1465
1466	memset(key, 0, sizeof(dst_key_t));
1467
1468	key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
1469
1470	dns_name_init(key->key_name, NULL);
1471	dns_name_dup(name, mctx, key->key_name);
1472
1473	isc_refcount_init(&key->refs, 1);
1474	isc_mem_attach(mctx, &key->mctx);
1475	key->key_alg = alg;
1476	key->key_flags = flags;
1477	key->key_proto = protocol;
1478	key->keydata.generic = NULL;
1479	key->key_size = bits;
1480	key->key_class = rdclass;
1481	key->key_ttl = ttl;
1482	key->func = dst_t_func[alg];
1483	key->fmt_major = 0;
1484	key->fmt_minor = 0;
1485	for (i = 0; i < (DST_MAX_TIMES + 1); i++) {
1486		key->times[i] = 0;
1487		key->timeset[i] = false;
1488	}
1489	key->inactive = false;
1490	key->magic = KEY_MAGIC;
1491	return (key);
1492}
1493
1494bool
1495dst_key_inactive(const dst_key_t *key) {
1496	REQUIRE(VALID_KEY(key));
1497
1498	return (key->inactive);
1499}
1500
1501void
1502dst_key_setinactive(dst_key_t *key, bool inactive) {
1503	REQUIRE(VALID_KEY(key));
1504
1505	key->inactive = inactive;
1506}
1507
1508/*%
1509 * Reads a public key from disk.
1510 */
1511isc_result_t
1512dst_key_read_public(const char *filename, int type, isc_mem_t *mctx,
1513		    dst_key_t **keyp) {
1514	u_char rdatabuf[DST_KEY_MAXSIZE];
1515	isc_buffer_t b;
1516	dns_fixedname_t name;
1517	isc_lex_t *lex = NULL;
1518	isc_token_t token;
1519	isc_result_t ret;
1520	dns_rdata_t rdata = DNS_RDATA_INIT;
1521	unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
1522	dns_rdataclass_t rdclass = dns_rdataclass_in;
1523	isc_lexspecials_t specials;
1524	uint32_t ttl = 0;
1525	isc_result_t result;
1526	dns_rdatatype_t keytype;
1527
1528	/*
1529	 * Open the file and read its formatted contents
1530	 * File format:
1531	 *    domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol>
1532	 * <algorithm> <key>
1533	 */
1534
1535	/* 1500 should be large enough for any key */
1536	ret = isc_lex_create(mctx, 1500, &lex);
1537	if (ret != ISC_R_SUCCESS) {
1538		goto cleanup;
1539	}
1540
1541	memset(specials, 0, sizeof(specials));
1542	specials['('] = 1;
1543	specials[')'] = 1;
1544	specials['"'] = 1;
1545	isc_lex_setspecials(lex, specials);
1546	isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
1547
1548	ret = isc_lex_openfile(lex, filename);
1549	if (ret != ISC_R_SUCCESS) {
1550		goto cleanup;
1551	}
1552
1553	/* Read the domain name */
1554	NEXTTOKEN(lex, opt, &token);
1555	if (token.type != isc_tokentype_string) {
1556		BADTOKEN();
1557	}
1558
1559	/*
1560	 * We don't support "@" in .key files.
1561	 */
1562	if (!strcmp(DST_AS_STR(token), "@")) {
1563		BADTOKEN();
1564	}
1565
1566	dns_fixedname_init(&name);
1567	isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
1568	isc_buffer_add(&b, strlen(DST_AS_STR(token)));
1569	ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, 0,
1570				NULL);
1571	if (ret != ISC_R_SUCCESS) {
1572		goto cleanup;
1573	}
1574
1575	/* Read the next word: either TTL, class, or 'KEY' */
1576	NEXTTOKEN(lex, opt, &token);
1577
1578	if (token.type != isc_tokentype_string) {
1579		BADTOKEN();
1580	}
1581
1582	/* If it's a TTL, read the next one */
1583	result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
1584	if (result == ISC_R_SUCCESS) {
1585		NEXTTOKEN(lex, opt, &token);
1586	}
1587
1588	if (token.type != isc_tokentype_string) {
1589		BADTOKEN();
1590	}
1591
1592	ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
1593	if (ret == ISC_R_SUCCESS) {
1594		NEXTTOKEN(lex, opt, &token);
1595	}
1596
1597	if (token.type != isc_tokentype_string) {
1598		BADTOKEN();
1599	}
1600
1601	if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) {
1602		keytype = dns_rdatatype_dnskey;
1603	} else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) {
1604		keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */
1605	} else {
1606		BADTOKEN();
1607	}
1608
1609	if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
1610	    ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey))
1611	{
1612		ret = DST_R_BADKEYTYPE;
1613		goto cleanup;
1614	}
1615
1616	isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1617	ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, false,
1618				 mctx, &b, NULL);
1619	if (ret != ISC_R_SUCCESS) {
1620		goto cleanup;
1621	}
1622
1623	ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
1624			      keyp);
1625	if (ret != ISC_R_SUCCESS) {
1626		goto cleanup;
1627	}
1628
1629	dst_key_setttl(*keyp, ttl);
1630
1631cleanup:
1632	if (lex != NULL) {
1633		isc_lex_destroy(&lex);
1634	}
1635	return (ret);
1636}
1637
1638static int
1639find_metadata(const char *s, const char *tags[], int ntags) {
1640	for (int i = 0; i < ntags; i++) {
1641		if (tags[i] != NULL && strcasecmp(s, tags[i]) == 0) {
1642			return (i);
1643		}
1644	}
1645	return (-1);
1646}
1647
1648static int
1649find_numericdata(const char *s) {
1650	return (find_metadata(s, numerictags, NUMERIC_NTAGS));
1651}
1652
1653static int
1654find_booleandata(const char *s) {
1655	return (find_metadata(s, booleantags, BOOLEAN_NTAGS));
1656}
1657
1658static int
1659find_timingdata(const char *s) {
1660	return (find_metadata(s, timingtags, TIMING_NTAGS));
1661}
1662
1663static int
1664find_keystatedata(const char *s) {
1665	return (find_metadata(s, keystatestags, KEYSTATES_NTAGS));
1666}
1667
1668static isc_result_t
1669keystate_fromtext(const char *s, dst_key_state_t *state) {
1670	for (int i = 0; i < KEYSTATES_NVALUES; i++) {
1671		if (keystates[i] != NULL && strcasecmp(s, keystates[i]) == 0) {
1672			*state = (dst_key_state_t)i;
1673			return (ISC_R_SUCCESS);
1674		}
1675	}
1676	return (ISC_R_NOTFOUND);
1677}
1678
1679/*%
1680 * Reads a key state from disk.
1681 */
1682isc_result_t
1683dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t **keyp) {
1684	isc_lex_t *lex = NULL;
1685	isc_token_t token;
1686	isc_result_t ret;
1687	unsigned int opt = ISC_LEXOPT_EOL;
1688
1689	ret = isc_lex_create(mctx, 1500, &lex);
1690	if (ret != ISC_R_SUCCESS) {
1691		goto cleanup;
1692	}
1693	isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
1694
1695	ret = isc_lex_openfile(lex, filename);
1696	if (ret != ISC_R_SUCCESS) {
1697		goto cleanup;
1698	}
1699
1700	/*
1701	 * Read the comment line.
1702	 */
1703	READLINE(lex, opt, &token);
1704
1705	/*
1706	 * Read the algorithm line.
1707	 */
1708	NEXTTOKEN(lex, opt, &token);
1709	if (token.type != isc_tokentype_string ||
1710	    strcmp(DST_AS_STR(token), STATE_ALGORITHM_STR) != 0)
1711	{
1712		BADTOKEN();
1713	}
1714
1715	NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
1716	if (token.type != isc_tokentype_number ||
1717	    token.value.as_ulong != (unsigned long)dst_key_alg(*keyp))
1718	{
1719		BADTOKEN();
1720	}
1721
1722	READLINE(lex, opt, &token);
1723
1724	/*
1725	 * Read the length line.
1726	 */
1727	NEXTTOKEN(lex, opt, &token);
1728	if (token.type != isc_tokentype_string ||
1729	    strcmp(DST_AS_STR(token), STATE_LENGTH_STR) != 0)
1730	{
1731		BADTOKEN();
1732	}
1733
1734	NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
1735	if (token.type != isc_tokentype_number ||
1736	    token.value.as_ulong != (unsigned long)dst_key_size(*keyp))
1737	{
1738		BADTOKEN();
1739	}
1740
1741	READLINE(lex, opt, &token);
1742
1743	/*
1744	 * Read the metadata.
1745	 */
1746	for (int n = 0; n < MAX_NTAGS; n++) {
1747		int tag;
1748
1749		NEXTTOKEN_OR_EOF(lex, opt, &token);
1750		if (ret == ISC_R_EOF) {
1751			break;
1752		}
1753		if (token.type != isc_tokentype_string) {
1754			BADTOKEN();
1755		}
1756
1757		/* Numeric metadata */
1758		tag = find_numericdata(DST_AS_STR(token));
1759		if (tag >= 0) {
1760			INSIST(tag < NUMERIC_NTAGS);
1761
1762			NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
1763			if (token.type != isc_tokentype_number) {
1764				BADTOKEN();
1765			}
1766
1767			dst_key_setnum(*keyp, tag, token.value.as_ulong);
1768			goto next;
1769		}
1770
1771		/* Boolean metadata */
1772		tag = find_booleandata(DST_AS_STR(token));
1773		if (tag >= 0) {
1774			INSIST(tag < BOOLEAN_NTAGS);
1775
1776			NEXTTOKEN(lex, opt, &token);
1777			if (token.type != isc_tokentype_string) {
1778				BADTOKEN();
1779			}
1780
1781			if (strcmp(DST_AS_STR(token), "yes") == 0) {
1782				dst_key_setbool(*keyp, tag, true);
1783			} else if (strcmp(DST_AS_STR(token), "no") == 0) {
1784				dst_key_setbool(*keyp, tag, false);
1785			} else {
1786				BADTOKEN();
1787			}
1788			goto next;
1789		}
1790
1791		/* Timing metadata */
1792		tag = find_timingdata(DST_AS_STR(token));
1793		if (tag >= 0) {
1794			uint32_t when;
1795
1796			INSIST(tag < TIMING_NTAGS);
1797
1798			NEXTTOKEN(lex, opt, &token);
1799			if (token.type != isc_tokentype_string) {
1800				BADTOKEN();
1801			}
1802
1803			ret = dns_time32_fromtext(DST_AS_STR(token), &when);
1804			if (ret != ISC_R_SUCCESS) {
1805				goto cleanup;
1806			}
1807
1808			dst_key_settime(*keyp, tag, when);
1809			goto next;
1810		}
1811
1812		/* Keystate metadata */
1813		tag = find_keystatedata(DST_AS_STR(token));
1814		if (tag >= 0) {
1815			dst_key_state_t state;
1816
1817			INSIST(tag < KEYSTATES_NTAGS);
1818
1819			NEXTTOKEN(lex, opt, &token);
1820			if (token.type != isc_tokentype_string) {
1821				BADTOKEN();
1822			}
1823
1824			ret = keystate_fromtext(DST_AS_STR(token), &state);
1825			if (ret != ISC_R_SUCCESS) {
1826				goto cleanup;
1827			}
1828
1829			dst_key_setstate(*keyp, tag, state);
1830			goto next;
1831		}
1832
1833	next:
1834		READLINE(lex, opt, &token);
1835	}
1836
1837	/* Done, successfully parsed the whole file. */
1838	ret = ISC_R_SUCCESS;
1839
1840cleanup:
1841	if (lex != NULL) {
1842		isc_lex_destroy(&lex);
1843	}
1844	return (ret);
1845}
1846
1847static bool
1848issymmetric(const dst_key_t *key) {
1849	REQUIRE(dst_initialized);
1850	REQUIRE(VALID_KEY(key));
1851
1852	/* XXXVIX this switch statement is too sparse to gen a jump table. */
1853	switch (key->key_alg) {
1854	case DST_ALG_RSASHA1:
1855	case DST_ALG_NSEC3RSASHA1:
1856	case DST_ALG_RSASHA256:
1857	case DST_ALG_RSASHA512:
1858	case DST_ALG_DH:
1859	case DST_ALG_ECDSA256:
1860	case DST_ALG_ECDSA384:
1861	case DST_ALG_ED25519:
1862	case DST_ALG_ED448:
1863		return (false);
1864	case DST_ALG_HMACMD5:
1865	case DST_ALG_HMACSHA1:
1866	case DST_ALG_HMACSHA224:
1867	case DST_ALG_HMACSHA256:
1868	case DST_ALG_HMACSHA384:
1869	case DST_ALG_HMACSHA512:
1870	case DST_ALG_GSSAPI:
1871		return (true);
1872	default:
1873		return (false);
1874	}
1875}
1876
1877/*%
1878 * Write key boolean metadata to a file pointer, preceded by 'tag'
1879 */
1880static void
1881printbool(const dst_key_t *key, int type, const char *tag, FILE *stream) {
1882	isc_result_t result;
1883	bool value = 0;
1884
1885	result = dst_key_getbool(key, type, &value);
1886	if (result != ISC_R_SUCCESS) {
1887		return;
1888	}
1889	fprintf(stream, "%s: %s\n", tag, value ? "yes" : "no");
1890}
1891
1892/*%
1893 * Write key numeric metadata to a file pointer, preceded by 'tag'
1894 */
1895static void
1896printnum(const dst_key_t *key, int type, const char *tag, FILE *stream) {
1897	isc_result_t result;
1898	uint32_t value = 0;
1899
1900	result = dst_key_getnum(key, type, &value);
1901	if (result != ISC_R_SUCCESS) {
1902		return;
1903	}
1904	fprintf(stream, "%s: %u\n", tag, value);
1905}
1906
1907/*%
1908 * Write key timing metadata to a file pointer, preceded by 'tag'
1909 */
1910static void
1911printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
1912	isc_result_t result;
1913	char output[26]; /* Minimum buffer as per ctime_r() specification. */
1914	isc_stdtime_t when;
1915	char utc[sizeof("YYYYMMDDHHSSMM")];
1916	isc_buffer_t b;
1917	isc_region_t r;
1918
1919	result = dst_key_gettime(key, type, &when);
1920	if (result == ISC_R_NOTFOUND) {
1921		return;
1922	}
1923
1924	isc_stdtime_tostring(when, output, sizeof(output));
1925	isc_buffer_init(&b, utc, sizeof(utc));
1926	result = dns_time32_totext(when, &b);
1927	if (result != ISC_R_SUCCESS) {
1928		goto error;
1929	}
1930
1931	isc_buffer_usedregion(&b, &r);
1932	fprintf(stream, "%s: %.*s (%s)\n", tag, (int)r.length, r.base, output);
1933	return;
1934
1935error:
1936	fprintf(stream, "%s: (set, unable to display)\n", tag);
1937}
1938
1939/*%
1940 * Write key state metadata to a file pointer, preceded by 'tag'
1941 */
1942static void
1943printstate(const dst_key_t *key, int type, const char *tag, FILE *stream) {
1944	isc_result_t result;
1945	dst_key_state_t value = 0;
1946
1947	result = dst_key_getstate(key, type, &value);
1948	if (result != ISC_R_SUCCESS) {
1949		return;
1950	}
1951	fprintf(stream, "%s: %s\n", tag, keystates[value]);
1952}
1953
1954/*%
1955 * Writes a key state to disk.
1956 */
1957static isc_result_t
1958write_key_state(const dst_key_t *key, int type, const char *directory) {
1959	FILE *fp;
1960	isc_buffer_t fileb;
1961	char filename[NAME_MAX];
1962	isc_result_t ret;
1963	isc_fsaccess_t access;
1964
1965	REQUIRE(VALID_KEY(key));
1966
1967	/*
1968	 * Make the filename.
1969	 */
1970	isc_buffer_init(&fileb, filename, sizeof(filename));
1971	ret = dst_key_buildfilename(key, DST_TYPE_STATE, directory, &fileb);
1972	if (ret != ISC_R_SUCCESS) {
1973		return (ret);
1974	}
1975
1976	/*
1977	 * Create public key file.
1978	 */
1979	if ((fp = fopen(filename, "w")) == NULL) {
1980		return (DST_R_WRITEERROR);
1981	}
1982
1983	if (issymmetric(key)) {
1984		access = 0;
1985		isc_fsaccess_add(ISC_FSACCESS_OWNER,
1986				 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
1987				 &access);
1988		(void)isc_fsaccess_set(filename, access);
1989	}
1990
1991	/* Write key state */
1992	if ((type & DST_TYPE_KEY) == 0) {
1993		fprintf(fp, "; This is the state of key %d, for ", key->key_id);
1994		ret = dns_name_print(key->key_name, fp);
1995		if (ret != ISC_R_SUCCESS) {
1996			fclose(fp);
1997			return (ret);
1998		}
1999		fputc('\n', fp);
2000
2001		fprintf(fp, "Algorithm: %u\n", key->key_alg);
2002		fprintf(fp, "Length: %u\n", key->key_size);
2003
2004		printnum(key, DST_NUM_LIFETIME, "Lifetime", fp);
2005		printnum(key, DST_NUM_PREDECESSOR, "Predecessor", fp);
2006		printnum(key, DST_NUM_SUCCESSOR, "Successor", fp);
2007
2008		printbool(key, DST_BOOL_KSK, "KSK", fp);
2009		printbool(key, DST_BOOL_ZSK, "ZSK", fp);
2010
2011		printtime(key, DST_TIME_CREATED, "Generated", fp);
2012		printtime(key, DST_TIME_PUBLISH, "Published", fp);
2013		printtime(key, DST_TIME_ACTIVATE, "Active", fp);
2014		printtime(key, DST_TIME_INACTIVE, "Retired", fp);
2015		printtime(key, DST_TIME_REVOKE, "Revoked", fp);
2016		printtime(key, DST_TIME_DELETE, "Removed", fp);
2017		printtime(key, DST_TIME_DSPUBLISH, "DSPublish", fp);
2018		printtime(key, DST_TIME_DSDELETE, "DSRemoved", fp);
2019		printtime(key, DST_TIME_SYNCPUBLISH, "PublishCDS", fp);
2020		printtime(key, DST_TIME_SYNCDELETE, "DeleteCDS", fp);
2021
2022		printtime(key, DST_TIME_DNSKEY, "DNSKEYChange", fp);
2023		printtime(key, DST_TIME_ZRRSIG, "ZRRSIGChange", fp);
2024		printtime(key, DST_TIME_KRRSIG, "KRRSIGChange", fp);
2025		printtime(key, DST_TIME_DS, "DSChange", fp);
2026
2027		printstate(key, DST_KEY_DNSKEY, "DNSKEYState", fp);
2028		printstate(key, DST_KEY_ZRRSIG, "ZRRSIGState", fp);
2029		printstate(key, DST_KEY_KRRSIG, "KRRSIGState", fp);
2030		printstate(key, DST_KEY_DS, "DSState", fp);
2031		printstate(key, DST_KEY_GOAL, "GoalState", fp);
2032	}
2033
2034	fflush(fp);
2035	if (ferror(fp)) {
2036		ret = DST_R_WRITEERROR;
2037	}
2038	fclose(fp);
2039
2040	return (ret);
2041}
2042
2043/*%
2044 * Writes a public key to disk in DNS format.
2045 */
2046static isc_result_t
2047write_public_key(const dst_key_t *key, int type, const char *directory) {
2048	FILE *fp;
2049	isc_buffer_t keyb, textb, fileb, classb;
2050	isc_region_t r;
2051	char filename[NAME_MAX];
2052	unsigned char key_array[DST_KEY_MAXSIZE];
2053	char text_array[DST_KEY_MAXTEXTSIZE];
2054	char class_array[10];
2055	isc_result_t ret;
2056	dns_rdata_t rdata = DNS_RDATA_INIT;
2057	isc_fsaccess_t access;
2058
2059	REQUIRE(VALID_KEY(key));
2060
2061	isc_buffer_init(&keyb, key_array, sizeof(key_array));
2062	isc_buffer_init(&textb, text_array, sizeof(text_array));
2063	isc_buffer_init(&classb, class_array, sizeof(class_array));
2064
2065	ret = dst_key_todns(key, &keyb);
2066	if (ret != ISC_R_SUCCESS) {
2067		return (ret);
2068	}
2069
2070	isc_buffer_usedregion(&keyb, &r);
2071	dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
2072
2073	ret = dns_rdata_totext(&rdata, (dns_name_t *)NULL, &textb);
2074	if (ret != ISC_R_SUCCESS) {
2075		return (DST_R_INVALIDPUBLICKEY);
2076	}
2077
2078	ret = dns_rdataclass_totext(key->key_class, &classb);
2079	if (ret != ISC_R_SUCCESS) {
2080		return (DST_R_INVALIDPUBLICKEY);
2081	}
2082
2083	/*
2084	 * Make the filename.
2085	 */
2086	isc_buffer_init(&fileb, filename, sizeof(filename));
2087	ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
2088	if (ret != ISC_R_SUCCESS) {
2089		return (ret);
2090	}
2091
2092	/*
2093	 * Create public key file.
2094	 */
2095	if ((fp = fopen(filename, "w")) == NULL) {
2096		return (DST_R_WRITEERROR);
2097	}
2098
2099	if (issymmetric(key)) {
2100		access = 0;
2101		isc_fsaccess_add(ISC_FSACCESS_OWNER,
2102				 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
2103				 &access);
2104		(void)isc_fsaccess_set(filename, access);
2105	}
2106
2107	/* Write key information in comments */
2108	if ((type & DST_TYPE_KEY) == 0) {
2109		fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ",
2110			(key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ? "revoked "
2111								   : "",
2112			(key->key_flags & DNS_KEYFLAG_KSK) != 0 ? "key"
2113								: "zone",
2114			key->key_id);
2115		ret = dns_name_print(key->key_name, fp);
2116		if (ret != ISC_R_SUCCESS) {
2117			fclose(fp);
2118			return (ret);
2119		}
2120		fputc('\n', fp);
2121
2122		printtime(key, DST_TIME_CREATED, "; Created", fp);
2123		printtime(key, DST_TIME_PUBLISH, "; Publish", fp);
2124		printtime(key, DST_TIME_ACTIVATE, "; Activate", fp);
2125		printtime(key, DST_TIME_REVOKE, "; Revoke", fp);
2126		printtime(key, DST_TIME_INACTIVE, "; Inactive", fp);
2127		printtime(key, DST_TIME_DELETE, "; Delete", fp);
2128		printtime(key, DST_TIME_SYNCPUBLISH, "; SyncPublish", fp);
2129		printtime(key, DST_TIME_SYNCDELETE, "; SyncDelete", fp);
2130	}
2131
2132	/* Now print the actual key */
2133	ret = dns_name_print(key->key_name, fp);
2134	fprintf(fp, " ");
2135
2136	if (key->key_ttl != 0) {
2137		fprintf(fp, "%u ", key->key_ttl);
2138	}
2139
2140	isc_buffer_usedregion(&classb, &r);
2141	if ((unsigned)fwrite(r.base, 1, r.length, fp) != r.length) {
2142		ret = DST_R_WRITEERROR;
2143	}
2144
2145	if ((type & DST_TYPE_KEY) != 0) {
2146		fprintf(fp, " KEY ");
2147	} else {
2148		fprintf(fp, " DNSKEY ");
2149	}
2150
2151	isc_buffer_usedregion(&textb, &r);
2152	if ((unsigned)fwrite(r.base, 1, r.length, fp) != r.length) {
2153		ret = DST_R_WRITEERROR;
2154	}
2155
2156	fputc('\n', fp);
2157	fflush(fp);
2158	if (ferror(fp)) {
2159		ret = DST_R_WRITEERROR;
2160	}
2161	fclose(fp);
2162
2163	return (ret);
2164}
2165
2166static isc_result_t
2167buildfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg,
2168	      unsigned int type, const char *directory, isc_buffer_t *out) {
2169	const char *suffix = "";
2170	isc_result_t result;
2171
2172	REQUIRE(out != NULL);
2173	if ((type & DST_TYPE_PRIVATE) != 0) {
2174		suffix = ".private";
2175	} else if ((type & DST_TYPE_PUBLIC) != 0) {
2176		suffix = ".key";
2177	} else if ((type & DST_TYPE_STATE) != 0) {
2178		suffix = ".state";
2179	}
2180
2181	if (directory != NULL) {
2182		if (isc_buffer_availablelength(out) < strlen(directory)) {
2183			return (ISC_R_NOSPACE);
2184		}
2185		isc_buffer_putstr(out, directory);
2186		if (strlen(directory) > 0U &&
2187		    directory[strlen(directory) - 1] != '/') {
2188			isc_buffer_putstr(out, "/");
2189		}
2190	}
2191	if (isc_buffer_availablelength(out) < 1) {
2192		return (ISC_R_NOSPACE);
2193	}
2194	isc_buffer_putstr(out, "K");
2195	result = dns_name_tofilenametext(name, false, out);
2196	if (result != ISC_R_SUCCESS) {
2197		return (result);
2198	}
2199
2200	return (isc_buffer_printf(out, "+%03d+%05d%s", alg, id, suffix));
2201}
2202
2203static isc_result_t
2204computeid(dst_key_t *key) {
2205	isc_buffer_t dnsbuf;
2206	unsigned char dns_array[DST_KEY_MAXSIZE];
2207	isc_region_t r;
2208	isc_result_t ret;
2209
2210	isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
2211	ret = dst_key_todns(key, &dnsbuf);
2212	if (ret != ISC_R_SUCCESS) {
2213		return (ret);
2214	}
2215
2216	isc_buffer_usedregion(&dnsbuf, &r);
2217	key->key_id = dst_region_computeid(&r);
2218	key->key_rid = dst_region_computerid(&r);
2219	return (ISC_R_SUCCESS);
2220}
2221
2222static isc_result_t
2223frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
2224	   unsigned int protocol, dns_rdataclass_t rdclass,
2225	   isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
2226	dst_key_t *key;
2227	isc_result_t ret;
2228
2229	REQUIRE(dns_name_isabsolute(name));
2230	REQUIRE(source != NULL);
2231	REQUIRE(mctx != NULL);
2232	REQUIRE(keyp != NULL && *keyp == NULL);
2233
2234	key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
2235	if (key == NULL) {
2236		return (ISC_R_NOMEMORY);
2237	}
2238
2239	if (isc_buffer_remaininglength(source) > 0) {
2240		ret = algorithm_status(alg);
2241		if (ret != ISC_R_SUCCESS) {
2242			dst_key_free(&key);
2243			return (ret);
2244		}
2245		if (key->func->fromdns == NULL) {
2246			dst_key_free(&key);
2247			return (DST_R_UNSUPPORTEDALG);
2248		}
2249
2250		ret = key->func->fromdns(key, source);
2251		if (ret != ISC_R_SUCCESS) {
2252			dst_key_free(&key);
2253			return (ret);
2254		}
2255	}
2256
2257	*keyp = key;
2258	return (ISC_R_SUCCESS);
2259}
2260
2261static isc_result_t
2262algorithm_status(unsigned int alg) {
2263	REQUIRE(dst_initialized);
2264
2265	if (dst_algorithm_supported(alg)) {
2266		return (ISC_R_SUCCESS);
2267	}
2268	return (DST_R_UNSUPPORTEDALG);
2269}
2270
2271static isc_result_t
2272addsuffix(char *filename, int len, const char *odirname, const char *ofilename,
2273	  const char *suffix) {
2274	int olen = strlen(ofilename);
2275	int n;
2276
2277	if (olen > 1 && ofilename[olen - 1] == '.') {
2278		olen -= 1;
2279	} else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) {
2280		olen -= 8;
2281	} else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) {
2282		olen -= 4;
2283	}
2284
2285	if (odirname == NULL) {
2286		n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
2287	} else {
2288		n = snprintf(filename, len, "%s/%.*s%s", odirname, olen,
2289			     ofilename, suffix);
2290	}
2291	if (n < 0) {
2292		return (ISC_R_FAILURE);
2293	}
2294	if (n >= len) {
2295		return (ISC_R_NOSPACE);
2296	}
2297	return (ISC_R_SUCCESS);
2298}
2299
2300isc_buffer_t *
2301dst_key_tkeytoken(const dst_key_t *key) {
2302	REQUIRE(VALID_KEY(key));
2303	return (key->key_tkeytoken);
2304}
2305
2306/*
2307 * A key is considered unused if it does not have any timing metadata set
2308 * other than "Created".
2309 *
2310 */
2311bool
2312dst_key_is_unused(dst_key_t *key) {
2313	isc_stdtime_t val;
2314	dst_key_state_t st;
2315	int state_type;
2316	bool state_type_set;
2317
2318	REQUIRE(VALID_KEY(key));
2319
2320	/*
2321	 * None of the key timing metadata, except Created, may be set.  Key
2322	 * state times may be set only if their respective state is HIDDEN.
2323	 */
2324	for (int i = 0; i < DST_MAX_TIMES + 1; i++) {
2325		state_type_set = false;
2326
2327		switch (i) {
2328		case DST_TIME_CREATED:
2329			break;
2330		case DST_TIME_DNSKEY:
2331			state_type = DST_KEY_DNSKEY;
2332			state_type_set = true;
2333			break;
2334		case DST_TIME_ZRRSIG:
2335			state_type = DST_KEY_ZRRSIG;
2336			state_type_set = true;
2337			break;
2338		case DST_TIME_KRRSIG:
2339			state_type = DST_KEY_KRRSIG;
2340			state_type_set = true;
2341			break;
2342		case DST_TIME_DS:
2343			state_type = DST_KEY_DS;
2344			state_type_set = true;
2345			break;
2346		default:
2347			break;
2348		}
2349
2350		/* Created is fine. */
2351		if (i == DST_TIME_CREATED) {
2352			continue;
2353		}
2354		/* No such timing metadata found, that is fine too. */
2355		if (dst_key_gettime(key, i, &val) == ISC_R_NOTFOUND) {
2356			continue;
2357		}
2358		/*
2359		 * Found timing metadata and it is not related to key states.
2360		 * This key is used.
2361		 */
2362		if (!state_type_set) {
2363			return (false);
2364		}
2365		/*
2366		 * If the state is not HIDDEN, the key is in use.
2367		 * If the state is not set, this is odd and we default to NA.
2368		 */
2369		if (dst_key_getstate(key, state_type, &st) != ISC_R_SUCCESS) {
2370			st = DST_KEY_STATE_NA;
2371		}
2372		if (st != DST_KEY_STATE_HIDDEN) {
2373			return (false);
2374		}
2375	}
2376	/* This key is unused. */
2377	return (true);
2378}
2379
2380static void
2381get_ksk_zsk(dst_key_t *key, bool *ksk, bool *zsk) {
2382	bool k = false, z = false;
2383
2384	if (dst_key_getbool(key, DST_BOOL_KSK, &k) == ISC_R_SUCCESS) {
2385		*ksk = k;
2386	} else {
2387		*ksk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) != 0);
2388	}
2389	if (dst_key_getbool(key, DST_BOOL_ZSK, &z) == ISC_R_SUCCESS) {
2390		*zsk = z;
2391	} else {
2392		*zsk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0);
2393	}
2394}
2395
2396/* Hints on key whether it can be published and/or used for signing. */
2397
2398bool
2399dst_key_is_published(dst_key_t *key, isc_stdtime_t now,
2400		     isc_stdtime_t *publish) {
2401	dst_key_state_t state;
2402	isc_result_t result;
2403	isc_stdtime_t when;
2404	bool state_ok = true, time_ok = false;
2405
2406	REQUIRE(VALID_KEY(key));
2407
2408	result = dst_key_gettime(key, DST_TIME_PUBLISH, &when);
2409	if (result == ISC_R_SUCCESS) {
2410		*publish = when;
2411		time_ok = (when <= now);
2412	}
2413
2414	/* Check key states:
2415	 * If the DNSKEY state is RUMOURED or OMNIPRESENT, it means it
2416	 * should be published.
2417	 */
2418	result = dst_key_getstate(key, DST_KEY_DNSKEY, &state);
2419	if (result == ISC_R_SUCCESS) {
2420		state_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2421			    (state == DST_KEY_STATE_OMNIPRESENT));
2422		/*
2423		 * Key states trump timing metadata.
2424		 * Ignore inactive time.
2425		 */
2426		time_ok = true;
2427	}
2428
2429	return (state_ok && time_ok);
2430}
2431
2432bool
2433dst_key_is_active(dst_key_t *key, isc_stdtime_t now) {
2434	dst_key_state_t state;
2435	isc_result_t result;
2436	isc_stdtime_t when = 0;
2437	bool ksk = false, zsk = false, inactive = false;
2438	bool ds_ok = true, zrrsig_ok = true, time_ok = false;
2439
2440	REQUIRE(VALID_KEY(key));
2441
2442	result = dst_key_gettime(key, DST_TIME_INACTIVE, &when);
2443	if (result == ISC_R_SUCCESS) {
2444		inactive = (when <= now);
2445	}
2446
2447	result = dst_key_gettime(key, DST_TIME_ACTIVATE, &when);
2448	if (result == ISC_R_SUCCESS) {
2449		time_ok = (when <= now);
2450	}
2451
2452	get_ksk_zsk(key, &ksk, &zsk);
2453
2454	/* Check key states:
2455	 * KSK: If the DS is RUMOURED or OMNIPRESENT the key is considered
2456	 * active.
2457	 */
2458	if (ksk) {
2459		result = dst_key_getstate(key, DST_KEY_DS, &state);
2460		if (result == ISC_R_SUCCESS) {
2461			ds_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2462				 (state == DST_KEY_STATE_OMNIPRESENT));
2463			/*
2464			 * Key states trump timing metadata.
2465			 * Ignore inactive time.
2466			 */
2467			time_ok = true;
2468			inactive = false;
2469		}
2470	}
2471	/*
2472	 * ZSK: If the ZRRSIG state is RUMOURED or OMNIPRESENT, it means the
2473	 * key is active.
2474	 */
2475	if (zsk) {
2476		result = dst_key_getstate(key, DST_KEY_ZRRSIG, &state);
2477		if (result == ISC_R_SUCCESS) {
2478			zrrsig_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2479				     (state == DST_KEY_STATE_OMNIPRESENT));
2480			/*
2481			 * Key states trump timing metadata.
2482			 * Ignore inactive time.
2483			 */
2484			time_ok = true;
2485			inactive = false;
2486		}
2487	}
2488	return (ds_ok && zrrsig_ok && time_ok && !inactive);
2489}
2490
2491bool
2492dst_key_is_signing(dst_key_t *key, int role, isc_stdtime_t now,
2493		   isc_stdtime_t *active) {
2494	dst_key_state_t state;
2495	isc_result_t result;
2496	isc_stdtime_t when = 0;
2497	bool ksk = false, zsk = false, inactive = false;
2498	bool krrsig_ok = true, zrrsig_ok = true, time_ok = false;
2499
2500	REQUIRE(VALID_KEY(key));
2501
2502	result = dst_key_gettime(key, DST_TIME_INACTIVE, &when);
2503	if (result == ISC_R_SUCCESS) {
2504		inactive = (when <= now);
2505	}
2506
2507	result = dst_key_gettime(key, DST_TIME_ACTIVATE, &when);
2508	if (result == ISC_R_SUCCESS) {
2509		*active = when;
2510		time_ok = (when <= now);
2511	}
2512
2513	get_ksk_zsk(key, &ksk, &zsk);
2514
2515	/* Check key states:
2516	 * If the RRSIG state is RUMOURED or OMNIPRESENT, it means the key
2517	 * is active.
2518	 */
2519	if (ksk && role == DST_BOOL_KSK) {
2520		result = dst_key_getstate(key, DST_KEY_KRRSIG, &state);
2521		if (result == ISC_R_SUCCESS) {
2522			krrsig_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2523				     (state == DST_KEY_STATE_OMNIPRESENT));
2524			/*
2525			 * Key states trump timing metadata.
2526			 * Ignore inactive time.
2527			 */
2528			time_ok = true;
2529			inactive = false;
2530		}
2531	} else if (zsk && role == DST_BOOL_ZSK) {
2532		result = dst_key_getstate(key, DST_KEY_ZRRSIG, &state);
2533		if (result == ISC_R_SUCCESS) {
2534			zrrsig_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2535				     (state == DST_KEY_STATE_OMNIPRESENT));
2536			/*
2537			 * Key states trump timing metadata.
2538			 * Ignore inactive time.
2539			 */
2540			time_ok = true;
2541			inactive = false;
2542		}
2543	}
2544	return (krrsig_ok && zrrsig_ok && time_ok && !inactive);
2545}
2546
2547bool
2548dst_key_is_revoked(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *revoke) {
2549	isc_result_t result;
2550	isc_stdtime_t when = 0;
2551	bool time_ok = false;
2552
2553	REQUIRE(VALID_KEY(key));
2554
2555	result = dst_key_gettime(key, DST_TIME_REVOKE, &when);
2556	if (result == ISC_R_SUCCESS) {
2557		*revoke = when;
2558		time_ok = (when <= now);
2559	}
2560
2561	return (time_ok);
2562}
2563
2564bool
2565dst_key_is_removed(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *remove) {
2566	dst_key_state_t state;
2567	isc_result_t result;
2568	isc_stdtime_t when = 0;
2569	bool state_ok = true, time_ok = false;
2570
2571	REQUIRE(VALID_KEY(key));
2572
2573	if (dst_key_is_unused(key)) {
2574		/* This key was never used. */
2575		return (false);
2576	}
2577
2578	result = dst_key_gettime(key, DST_TIME_DELETE, &when);
2579	if (result == ISC_R_SUCCESS) {
2580		*remove = when;
2581		time_ok = (when <= now);
2582	}
2583
2584	/* Check key states:
2585	 * If the DNSKEY state is UNRETENTIVE or HIDDEN, it means the key
2586	 * should not be published.
2587	 */
2588	result = dst_key_getstate(key, DST_KEY_DNSKEY, &state);
2589	if (result == ISC_R_SUCCESS) {
2590		state_ok = ((state == DST_KEY_STATE_UNRETENTIVE) ||
2591			    (state == DST_KEY_STATE_HIDDEN));
2592		/*
2593		 * Key states trump timing metadata.
2594		 * Ignore delete time.
2595		 */
2596		time_ok = true;
2597	}
2598
2599	return (state_ok && time_ok);
2600}
2601
2602dst_key_state_t
2603dst_key_goal(dst_key_t *key) {
2604	dst_key_state_t state;
2605	isc_result_t result;
2606
2607	REQUIRE(VALID_KEY(key));
2608
2609	result = dst_key_getstate(key, DST_KEY_GOAL, &state);
2610	if (result == ISC_R_SUCCESS) {
2611		return (state);
2612	}
2613	return (DST_KEY_STATE_HIDDEN);
2614}
2615
2616bool
2617dst_key_haskasp(dst_key_t *key) {
2618	REQUIRE(VALID_KEY(key));
2619
2620	return (key->kasp);
2621}
2622
2623void
2624dst_key_copy_metadata(dst_key_t *to, dst_key_t *from) {
2625	dst_key_state_t state;
2626	isc_stdtime_t when;
2627	uint32_t num;
2628	bool yesno;
2629	isc_result_t result;
2630
2631	REQUIRE(VALID_KEY(to));
2632	REQUIRE(VALID_KEY(from));
2633
2634	for (int i = 0; i < DST_MAX_TIMES + 1; i++) {
2635		result = dst_key_gettime(from, i, &when);
2636		if (result == ISC_R_SUCCESS) {
2637			dst_key_settime(to, i, when);
2638		} else {
2639			dst_key_unsettime(to, i);
2640		}
2641	}
2642
2643	for (int i = 0; i < DST_MAX_NUMERIC + 1; i++) {
2644		result = dst_key_getnum(from, i, &num);
2645		if (result == ISC_R_SUCCESS) {
2646			dst_key_setnum(to, i, num);
2647		} else {
2648			dst_key_unsetnum(to, i);
2649		}
2650	}
2651
2652	for (int i = 0; i < DST_MAX_BOOLEAN + 1; i++) {
2653		result = dst_key_getbool(from, i, &yesno);
2654		if (result == ISC_R_SUCCESS) {
2655			dst_key_setbool(to, i, yesno);
2656		} else {
2657			dst_key_unsetnum(to, i);
2658		}
2659	}
2660
2661	for (int i = 0; i < DST_MAX_KEYSTATES + 1; i++) {
2662		result = dst_key_getstate(from, i, &state);
2663		if (result == ISC_R_SUCCESS) {
2664			dst_key_setstate(to, i, state);
2665		} else {
2666			dst_key_unsetstate(to, i);
2667		}
2668	}
2669}
2670