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