mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 01:59:26 +00:00
The OpenSSL 1.x Engines support has been deprecated in the OpenSSL 3.x and is going to be removed. Remove the OpenSSL Engine support in favor of OpenSSL Providers.
283 lines
7.5 KiB
C
283 lines
7.5 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
/*! \file */
|
|
|
|
#include <string.h>
|
|
|
|
#include <isc/assertions.h>
|
|
#include <isc/buffer.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/time.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/fixedname.h>
|
|
#include <dns/keystore.h>
|
|
#include <dns/keyvalues.h>
|
|
|
|
isc_result_t
|
|
dns_keystore_create(isc_mem_t *mctx, const char *name, dns_keystore_t **kspp) {
|
|
dns_keystore_t *keystore;
|
|
|
|
REQUIRE(name != NULL);
|
|
REQUIRE(kspp != NULL && *kspp == NULL);
|
|
|
|
keystore = isc_mem_get(mctx, sizeof(*keystore));
|
|
keystore->mctx = NULL;
|
|
isc_mem_attach(mctx, &keystore->mctx);
|
|
|
|
keystore->name = isc_mem_strdup(mctx, name);
|
|
isc_mutex_init(&keystore->lock);
|
|
|
|
isc_refcount_init(&keystore->references, 1);
|
|
|
|
ISC_LINK_INIT(keystore, link);
|
|
|
|
keystore->directory = NULL;
|
|
keystore->pkcs11uri = NULL;
|
|
|
|
keystore->magic = DNS_KEYSTORE_MAGIC;
|
|
*kspp = keystore;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
}
|
|
|
|
static inline void
|
|
dns__keystore_destroy(dns_keystore_t *keystore) {
|
|
char *name;
|
|
|
|
REQUIRE(!ISC_LINK_LINKED(keystore, link));
|
|
|
|
isc_mutex_destroy(&keystore->lock);
|
|
name = UNCONST(keystore->name);
|
|
isc_mem_free(keystore->mctx, name);
|
|
if (keystore->directory != NULL) {
|
|
isc_mem_free(keystore->mctx, keystore->directory);
|
|
}
|
|
if (keystore->pkcs11uri != NULL) {
|
|
isc_mem_free(keystore->mctx, keystore->pkcs11uri);
|
|
}
|
|
isc_mem_putanddetach(&keystore->mctx, keystore, sizeof(*keystore));
|
|
}
|
|
|
|
#ifdef DNS_KEYSTORE_TRACE
|
|
ISC_REFCOUNT_TRACE_IMPL(dns_keystore, dns__keystore_destroy);
|
|
#else
|
|
ISC_REFCOUNT_IMPL(dns_keystore, dns__keystore_destroy);
|
|
#endif
|
|
|
|
const char *
|
|
dns_keystore_name(dns_keystore_t *keystore) {
|
|
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
|
|
|
return (keystore->name);
|
|
}
|
|
|
|
const char *
|
|
dns_keystore_directory(dns_keystore_t *keystore, const char *keydir) {
|
|
if (keystore == NULL) {
|
|
return (keydir);
|
|
}
|
|
|
|
INSIST(DNS_KEYSTORE_VALID(keystore));
|
|
|
|
if (keystore->directory == NULL) {
|
|
return (keydir);
|
|
}
|
|
|
|
return (keystore->directory);
|
|
}
|
|
|
|
void
|
|
dns_keystore_setdirectory(dns_keystore_t *keystore, const char *dir) {
|
|
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
|
|
|
if (keystore->directory != NULL) {
|
|
isc_mem_free(keystore->mctx, keystore->directory);
|
|
}
|
|
keystore->directory = (dir == NULL)
|
|
? NULL
|
|
: isc_mem_strdup(keystore->mctx, dir);
|
|
}
|
|
|
|
const char *
|
|
dns_keystore_pkcs11uri(dns_keystore_t *keystore) {
|
|
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
|
|
|
return (keystore->pkcs11uri);
|
|
}
|
|
|
|
void
|
|
dns_keystore_setpkcs11uri(dns_keystore_t *keystore, const char *uri) {
|
|
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
|
|
|
if (keystore->pkcs11uri != NULL) {
|
|
isc_mem_free(keystore->mctx, keystore->pkcs11uri);
|
|
}
|
|
keystore->pkcs11uri = (uri == NULL)
|
|
? NULL
|
|
: isc_mem_strdup(keystore->mctx, uri);
|
|
}
|
|
|
|
static isc_result_t
|
|
buildpkcs11label(const char *uri, const dns_name_t *zname, const char *policy,
|
|
int flags, isc_buffer_t *buf) {
|
|
bool ksk = ((flags & DNS_KEYFLAG_KSK) != 0);
|
|
char timebuf[18];
|
|
isc_time_t now = isc_time_now();
|
|
isc_result_t result;
|
|
dns_fixedname_t fname;
|
|
dns_name_t *pname = dns_fixedname_initname(&fname);
|
|
|
|
/* uri + object */
|
|
if (isc_buffer_availablelength(buf) < strlen(uri) + strlen(";object="))
|
|
{
|
|
return (ISC_R_NOSPACE);
|
|
}
|
|
isc_buffer_putstr(buf, uri);
|
|
isc_buffer_putstr(buf, ";object=");
|
|
/* zone name */
|
|
result = dns_name_tofilenametext(zname, false, buf);
|
|
if (result != ISC_R_SUCCESS) {
|
|
return (result);
|
|
}
|
|
/*
|
|
* policy name
|
|
*
|
|
* Note that strlen(policy) is not the actual length, but if this
|
|
* already does not fit, the escaped version returned from
|
|
* dns_name_tofilenametext() certainly won't fit.
|
|
*/
|
|
if (isc_buffer_availablelength(buf) < (strlen(policy) + 1)) {
|
|
return (ISC_R_NOSPACE);
|
|
}
|
|
isc_buffer_putstr(buf, "-");
|
|
result = dns_name_fromstring(pname, policy, dns_rootname, 0, NULL);
|
|
if (result != ISC_R_SUCCESS) {
|
|
return (result);
|
|
}
|
|
result = dns_name_tofilenametext(pname, false, buf);
|
|
if (result != ISC_R_SUCCESS) {
|
|
return (result);
|
|
}
|
|
/* key type + current time */
|
|
isc_time_formatshorttimestamp(&now, timebuf, sizeof(timebuf));
|
|
return isc_buffer_printf(buf, "-%s-%s", ksk ? "ksk" : "zsk", timebuf);
|
|
}
|
|
|
|
isc_result_t
|
|
dns_keystore_keygen(dns_keystore_t *keystore, const dns_name_t *origin,
|
|
const char *policy, dns_rdataclass_t rdclass,
|
|
isc_mem_t *mctx, uint32_t alg, int size, int flags,
|
|
dst_key_t **dstkey) {
|
|
isc_result_t result;
|
|
dst_key_t *newkey = NULL;
|
|
const char *uri = NULL;
|
|
|
|
REQUIRE(DNS_KEYSTORE_VALID(keystore));
|
|
REQUIRE(dns_name_isvalid(origin));
|
|
REQUIRE(policy != NULL);
|
|
REQUIRE(mctx != NULL);
|
|
REQUIRE(dstkey != NULL && *dstkey == NULL);
|
|
|
|
uri = dns_keystore_pkcs11uri(keystore);
|
|
if (uri != NULL) {
|
|
/*
|
|
* Create the PKCS#11 label.
|
|
* The label consists of the configured URI, and the object
|
|
* parameter. The object parameter needs to be unique. We
|
|
* know that for a given point in time, there will be at most
|
|
* one key per type created for each zone in a given DNSSEC
|
|
* policy. Hence the object is constructed out of the following
|
|
* parts: the zone name, policy name, key type, and the
|
|
* current time.
|
|
*
|
|
* The object may not contain any characters that conflict with
|
|
* special characters in the PKCS#11 URI scheme syntax (see
|
|
* RFC 7512, Section 2.3). Therefore, we mangle the zone name
|
|
* and policy name through 'dns_name_tofilenametext()'. We
|
|
* could create a new function to convert a name to PKCS#11
|
|
* text, but this existing function will suffice.
|
|
*/
|
|
char label[NAME_MAX];
|
|
isc_buffer_t buf;
|
|
isc_buffer_init(&buf, label, sizeof(label));
|
|
result = buildpkcs11label(uri, origin, policy, flags, &buf);
|
|
if (result != ISC_R_SUCCESS) {
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
dns_name_format(origin, namebuf, sizeof(namebuf));
|
|
isc_log_write(
|
|
dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
|
DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
|
|
"keystore: failed to create PKCS#11 object "
|
|
"for zone %s, policy %s: %s",
|
|
namebuf, policy, isc_result_totext(result));
|
|
return (result);
|
|
}
|
|
|
|
/* Generate the key */
|
|
result = dst_key_generate(origin, alg, size, 0, flags,
|
|
DNS_KEYPROTO_DNSSEC, rdclass, label,
|
|
mctx, &newkey, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
isc_log_write(
|
|
dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
|
DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
|
|
"keystore: failed to generate PKCS#11 object "
|
|
"%s: %s",
|
|
label, isc_result_totext(result));
|
|
return (result);
|
|
}
|
|
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
|
|
DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
|
|
"keystore: generated PKCS#11 object %s", label);
|
|
} else {
|
|
result = dst_key_generate(origin, alg, size, 0, flags,
|
|
DNS_KEYPROTO_DNSSEC, rdclass, NULL,
|
|
mctx, &newkey, NULL);
|
|
}
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
*dstkey = newkey;
|
|
}
|
|
return (result);
|
|
}
|
|
|
|
isc_result_t
|
|
dns_keystorelist_find(dns_keystorelist_t *list, const char *name,
|
|
dns_keystore_t **kspp) {
|
|
dns_keystore_t *keystore = NULL;
|
|
|
|
REQUIRE(kspp != NULL && *kspp == NULL);
|
|
|
|
if (list == NULL) {
|
|
return (ISC_R_NOTFOUND);
|
|
}
|
|
|
|
for (keystore = ISC_LIST_HEAD(*list); keystore != NULL;
|
|
keystore = ISC_LIST_NEXT(keystore, link))
|
|
{
|
|
if (strcmp(keystore->name, name) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (keystore == NULL) {
|
|
return (ISC_R_NOTFOUND);
|
|
}
|
|
|
|
dns_keystore_attach(keystore, kspp);
|
|
return (ISC_R_SUCCESS);
|
|
}
|