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