Home | History | Annotate | Line # | Download | only in dns
keystore.c revision 1.3.4.2
      1 /*	$NetBSD: keystore.c,v 1.3.4.2 2025/08/02 05:53:26 perseant Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 /*! \file */
     17 
     18 #include <string.h>
     19 
     20 #include <isc/assertions.h>
     21 #include <isc/buffer.h>
     22 #include <isc/dir.h>
     23 #include <isc/mem.h>
     24 #include <isc/time.h>
     25 #include <isc/util.h>
     26 
     27 #include <dns/fixedname.h>
     28 #include <dns/keystore.h>
     29 #include <dns/keyvalues.h>
     30 
     31 isc_result_t
     32 dns_keystore_create(isc_mem_t *mctx, const char *name, const char *engine,
     33 		    dns_keystore_t **kspp) {
     34 	dns_keystore_t *keystore;
     35 
     36 	REQUIRE(name != NULL);
     37 	REQUIRE(kspp != NULL && *kspp == NULL);
     38 
     39 	keystore = isc_mem_get(mctx, sizeof(*keystore));
     40 	keystore->engine = engine;
     41 	keystore->mctx = NULL;
     42 	isc_mem_attach(mctx, &keystore->mctx);
     43 
     44 	keystore->name = isc_mem_strdup(mctx, name);
     45 	isc_mutex_init(&keystore->lock);
     46 
     47 	isc_refcount_init(&keystore->references, 1);
     48 
     49 	ISC_LINK_INIT(keystore, link);
     50 
     51 	keystore->directory = NULL;
     52 	keystore->pkcs11uri = NULL;
     53 
     54 	keystore->magic = DNS_KEYSTORE_MAGIC;
     55 	*kspp = keystore;
     56 
     57 	return ISC_R_SUCCESS;
     58 }
     59 
     60 static inline void
     61 dns__keystore_destroy(dns_keystore_t *keystore) {
     62 	char *name;
     63 
     64 	REQUIRE(!ISC_LINK_LINKED(keystore, link));
     65 
     66 	isc_mutex_destroy(&keystore->lock);
     67 	name = UNCONST(keystore->name);
     68 	isc_mem_free(keystore->mctx, name);
     69 	if (keystore->directory != NULL) {
     70 		isc_mem_free(keystore->mctx, keystore->directory);
     71 	}
     72 	if (keystore->pkcs11uri != NULL) {
     73 		isc_mem_free(keystore->mctx, keystore->pkcs11uri);
     74 	}
     75 	isc_mem_putanddetach(&keystore->mctx, keystore, sizeof(*keystore));
     76 }
     77 
     78 #ifdef DNS_KEYSTORE_TRACE
     79 ISC_REFCOUNT_TRACE_IMPL(dns_keystore, dns__keystore_destroy);
     80 #else
     81 ISC_REFCOUNT_IMPL(dns_keystore, dns__keystore_destroy);
     82 #endif
     83 
     84 const char *
     85 dns_keystore_name(dns_keystore_t *keystore) {
     86 	REQUIRE(DNS_KEYSTORE_VALID(keystore));
     87 
     88 	return keystore->name;
     89 }
     90 
     91 const char *
     92 dns_keystore_engine(dns_keystore_t *keystore) {
     93 	REQUIRE(DNS_KEYSTORE_VALID(keystore));
     94 
     95 	return keystore->engine;
     96 }
     97 
     98 const char *
     99 dns_keystore_directory(dns_keystore_t *keystore, const char *keydir) {
    100 	if (keystore == NULL) {
    101 		return keydir;
    102 	}
    103 
    104 	INSIST(DNS_KEYSTORE_VALID(keystore));
    105 
    106 	if (keystore->directory == NULL) {
    107 		return keydir;
    108 	}
    109 
    110 	return keystore->directory;
    111 }
    112 
    113 void
    114 dns_keystore_setdirectory(dns_keystore_t *keystore, const char *dir) {
    115 	REQUIRE(DNS_KEYSTORE_VALID(keystore));
    116 
    117 	if (keystore->directory != NULL) {
    118 		isc_mem_free(keystore->mctx, keystore->directory);
    119 	}
    120 	keystore->directory = (dir == NULL)
    121 				      ? NULL
    122 				      : isc_mem_strdup(keystore->mctx, dir);
    123 }
    124 
    125 const char *
    126 dns_keystore_pkcs11uri(dns_keystore_t *keystore) {
    127 	REQUIRE(DNS_KEYSTORE_VALID(keystore));
    128 
    129 	return keystore->pkcs11uri;
    130 }
    131 
    132 void
    133 dns_keystore_setpkcs11uri(dns_keystore_t *keystore, const char *uri) {
    134 	REQUIRE(DNS_KEYSTORE_VALID(keystore));
    135 
    136 	if (keystore->pkcs11uri != NULL) {
    137 		isc_mem_free(keystore->mctx, keystore->pkcs11uri);
    138 	}
    139 	keystore->pkcs11uri = (uri == NULL)
    140 				      ? NULL
    141 				      : isc_mem_strdup(keystore->mctx, uri);
    142 }
    143 
    144 static isc_result_t
    145 buildpkcs11label(const char *uri, const dns_name_t *zname, const char *policy,
    146 		 int flags, isc_buffer_t *buf) {
    147 	bool ksk = ((flags & DNS_KEYFLAG_KSK) != 0);
    148 	char timebuf[18];
    149 	isc_time_t now = isc_time_now();
    150 	isc_result_t result;
    151 	dns_fixedname_t fname;
    152 	dns_name_t *pname = dns_fixedname_initname(&fname);
    153 
    154 	/* uri + object */
    155 	if (isc_buffer_availablelength(buf) < strlen(uri) + strlen(";object="))
    156 	{
    157 		return ISC_R_NOSPACE;
    158 	}
    159 	isc_buffer_putstr(buf, uri);
    160 	isc_buffer_putstr(buf, ";object=");
    161 	/* zone name */
    162 	result = dns_name_tofilenametext(zname, false, buf);
    163 	if (result != ISC_R_SUCCESS) {
    164 		return result;
    165 	}
    166 	/*
    167 	 * policy name
    168 	 *
    169 	 * Note that strlen(policy) is not the actual length, but if this
    170 	 * already does not fit, the escaped version returned from
    171 	 * dns_name_tofilenametext() certainly won't fit.
    172 	 */
    173 	if (isc_buffer_availablelength(buf) < (strlen(policy) + 1)) {
    174 		return ISC_R_NOSPACE;
    175 	}
    176 	isc_buffer_putstr(buf, "-");
    177 	result = dns_name_fromstring(pname, policy, dns_rootname, 0, NULL);
    178 	if (result != ISC_R_SUCCESS) {
    179 		return result;
    180 	}
    181 	result = dns_name_tofilenametext(pname, false, buf);
    182 	if (result != ISC_R_SUCCESS) {
    183 		return result;
    184 	}
    185 	/* key type + current time */
    186 	isc_time_formatshorttimestamp(&now, timebuf, sizeof(timebuf));
    187 	return isc_buffer_printf(buf, "-%s-%s", ksk ? "ksk" : "zsk", timebuf);
    188 }
    189 
    190 isc_result_t
    191 dns_keystore_keygen(dns_keystore_t *keystore, const dns_name_t *origin,
    192 		    const char *policy, dns_rdataclass_t rdclass,
    193 		    isc_mem_t *mctx, uint32_t alg, int size, int flags,
    194 		    dst_key_t **dstkey) {
    195 	isc_result_t result;
    196 	dst_key_t *newkey = NULL;
    197 	const char *uri = NULL;
    198 
    199 	REQUIRE(DNS_KEYSTORE_VALID(keystore));
    200 	REQUIRE(dns_name_isvalid(origin));
    201 	REQUIRE(policy != NULL);
    202 	REQUIRE(mctx != NULL);
    203 	REQUIRE(dstkey != NULL && *dstkey == NULL);
    204 
    205 	uri = dns_keystore_pkcs11uri(keystore);
    206 	if (uri != NULL) {
    207 		/*
    208 		 * Create the PKCS#11 label.
    209 		 * The label consists of the configured URI, and the object
    210 		 * parameter.  The object parameter needs to be unique.  We
    211 		 * know that for a given point in time, there will be at most
    212 		 * one key per type created for each zone in a given DNSSEC
    213 		 * policy.  Hence the object is constructed out of the following
    214 		 * parts: the zone name, policy name, key type, and the
    215 		 * current time.
    216 		 *
    217 		 * The object may not contain any characters that conflict with
    218 		 * special characters in the PKCS#11 URI scheme syntax (see
    219 		 * RFC 7512, Section 2.3). Therefore, we mangle the zone name
    220 		 * and policy name through 'dns_name_tofilenametext()'. We
    221 		 * could create a new function to convert a name to PKCS#11
    222 		 * text, but this existing function will suffice.
    223 		 */
    224 		char label[NAME_MAX];
    225 		isc_buffer_t buf;
    226 		isc_buffer_init(&buf, label, sizeof(label));
    227 		result = buildpkcs11label(uri, origin, policy, flags, &buf);
    228 		if (result != ISC_R_SUCCESS) {
    229 			char namebuf[DNS_NAME_FORMATSIZE];
    230 			dns_name_format(origin, namebuf, sizeof(namebuf));
    231 			isc_log_write(
    232 				dns_lctx, DNS_LOGCATEGORY_DNSSEC,
    233 				DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
    234 				"keystore: failed to create PKCS#11 object "
    235 				"for zone %s, policy %s: %s",
    236 				namebuf, policy, isc_result_totext(result));
    237 			return result;
    238 		}
    239 
    240 		/* Generate the key */
    241 		result = dst_key_generate(origin, alg, size, 0, flags,
    242 					  DNS_KEYPROTO_DNSSEC, rdclass, label,
    243 					  mctx, &newkey, NULL);
    244 
    245 		if (result != ISC_R_SUCCESS) {
    246 			isc_log_write(
    247 				dns_lctx, DNS_LOGCATEGORY_DNSSEC,
    248 				DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
    249 				"keystore: failed to generate PKCS#11 object "
    250 				"%s: %s",
    251 				label, isc_result_totext(result));
    252 			return result;
    253 		}
    254 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
    255 			      DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
    256 			      "keystore: generated PKCS#11 object %s", label);
    257 	} else {
    258 		result = dst_key_generate(origin, alg, size, 0, flags,
    259 					  DNS_KEYPROTO_DNSSEC, rdclass, NULL,
    260 					  mctx, &newkey, NULL);
    261 	}
    262 
    263 	if (result == ISC_R_SUCCESS) {
    264 		*dstkey = newkey;
    265 	}
    266 	return result;
    267 }
    268 
    269 isc_result_t
    270 dns_keystorelist_find(dns_keystorelist_t *list, const char *name,
    271 		      dns_keystore_t **kspp) {
    272 	dns_keystore_t *keystore = NULL;
    273 
    274 	REQUIRE(kspp != NULL && *kspp == NULL);
    275 
    276 	if (list == NULL) {
    277 		return ISC_R_NOTFOUND;
    278 	}
    279 
    280 	for (keystore = ISC_LIST_HEAD(*list); keystore != NULL;
    281 	     keystore = ISC_LIST_NEXT(keystore, link))
    282 	{
    283 		if (strcmp(keystore->name, name) == 0) {
    284 			break;
    285 		}
    286 	}
    287 
    288 	if (keystore == NULL) {
    289 		return ISC_R_NOTFOUND;
    290 	}
    291 
    292 	dns_keystore_attach(keystore, kspp);
    293 	return ISC_R_SUCCESS;
    294 }
    295