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