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