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