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