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