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