2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 01:59:26 +00:00
bind/lib/dns/openssl_link.c
Ondřej Surý ef7aba7072
Remove OpenSSL Engine support
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.
2024-08-06 15:17:48 +02:00

278 lines
6.7 KiB
C

/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0 AND ISC
*
* 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.
*/
/*
* Copyright (C) Network Associates, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <isc/fips.h>
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/mutexblock.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/thread.h>
#include <isc/tls.h>
#include <isc/util.h>
#include <dns/log.h>
#include "dst_internal.h"
#include "dst_openssl.h"
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/core_names.h>
#include <openssl/store.h>
#endif
#include "openssl_shim.h"
#define DST_RET(a) \
{ \
ret = a; \
goto err; \
}
static void
enable_fips_mode(void) {
#if defined(ENABLE_FIPS_MODE)
if (isc_fips_mode()) {
/*
* FIPS mode is already enabled.
*/
return;
}
if (isc_fips_set_mode(1) != ISC_R_SUCCESS) {
dst__openssl_toresult2("FIPS_mode_set", DST_R_OPENSSLFAILURE);
exit(EXIT_FAILURE);
}
#endif
}
void
dst__openssl_init(void) {
enable_fips_mode();
}
void
dst__openssl_destroy(void) {
/* No-op */
}
static isc_result_t
toresult(isc_result_t fallback) {
isc_result_t result = fallback;
unsigned long err = ERR_peek_error();
#if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
int lib = ERR_GET_LIB(err);
#endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */
int reason = ERR_GET_REASON(err);
switch (reason) {
/*
* ERR_* errors are globally unique; others
* are unique per sublibrary
*/
case ERR_R_MALLOC_FAILURE:
result = ISC_R_NOMEMORY;
break;
default:
#if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
if (lib == ERR_R_ECDSA_LIB &&
reason == ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED)
{
result = ISC_R_NOENTROPY;
break;
}
#endif /* if defined(ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED) */
break;
}
return (result);
}
isc_result_t
dst__openssl_toresult(isc_result_t fallback) {
isc_result_t result;
result = toresult(fallback);
ERR_clear_error();
return (result);
}
isc_result_t
dst___openssl_toresult2(const char *funcname, isc_result_t fallback,
const char *file, int line) {
return (dst___openssl_toresult3(DNS_LOGCATEGORY_GENERAL, funcname,
fallback, file, line));
}
isc_result_t
dst___openssl_toresult3(isc_logcategory_t *category, const char *funcname,
isc_result_t fallback, const char *file, int line) {
isc_result_t result;
unsigned long err;
const char *func, *data;
int flags;
char buf[256];
result = toresult(fallback);
isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
"%s (%s:%d) failed (%s)", funcname, file, line,
isc_result_totext(result));
if (result == ISC_R_NOMEMORY) {
goto done;
}
for (;;) {
err = ERR_get_error_all(&file, &line, &func, &data, &flags);
if (err == 0U) {
goto done;
}
ERR_error_string_n(err, buf, sizeof(buf));
isc_log_write(dns_lctx, category, DNS_LOGMODULE_CRYPTO,
ISC_LOG_INFO, "%s:%s:%d:%s", buf, file, line,
((flags & ERR_TXT_STRING) != 0) ? data : "");
}
done:
ERR_clear_error();
return (result);
}
static isc_result_t
dst__openssl_fromlabel_provider(int key_base_id, const char *label,
const char *pin, EVP_PKEY **ppub,
EVP_PKEY **ppriv) {
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
isc_result_t ret = DST_R_OPENSSLFAILURE;
OSSL_STORE_CTX *ctx = NULL;
UNUSED(pin);
ctx = OSSL_STORE_open(label, NULL, NULL, NULL, NULL);
if (!ctx) {
DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE));
}
while (!OSSL_STORE_eof(ctx)) {
OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
if (info == NULL) {
continue;
}
switch (OSSL_STORE_INFO_get_type(info)) {
case OSSL_STORE_INFO_PKEY:
if (*ppriv != NULL) {
OSSL_STORE_INFO_free(info);
DST_RET(DST_R_INVALIDPRIVATEKEY);
}
*ppriv = OSSL_STORE_INFO_get1_PKEY(info);
if (EVP_PKEY_get_base_id(*ppriv) != key_base_id) {
OSSL_STORE_INFO_free(info);
DST_RET(DST_R_BADKEYTYPE);
}
break;
case OSSL_STORE_INFO_PUBKEY:
if (*ppub != NULL) {
OSSL_STORE_INFO_free(info);
DST_RET(DST_R_INVALIDPUBLICKEY);
}
*ppub = OSSL_STORE_INFO_get1_PUBKEY(info);
if (EVP_PKEY_get_base_id(*ppub) != key_base_id) {
OSSL_STORE_INFO_free(info);
DST_RET(DST_R_BADKEYTYPE);
}
break;
}
OSSL_STORE_INFO_free(info);
}
if (*ppriv != NULL && *ppub != NULL) {
ret = ISC_R_SUCCESS;
}
err:
OSSL_STORE_close(ctx);
return (ret);
#else
UNUSED(key_base_id);
UNUSED(label);
UNUSED(pin);
UNUSED(ppub);
UNUSED(ppriv);
return (DST_R_OPENSSLFAILURE);
#endif
}
isc_result_t
dst__openssl_fromlabel(int key_base_id, const char *label, const char *pin,
EVP_PKEY **ppub, EVP_PKEY **ppriv) {
return (dst__openssl_fromlabel_provider(key_base_id, label, pin, ppub,
ppriv));
}
bool
dst__openssl_keypair_compare(const dst_key_t *key1, const dst_key_t *key2) {
EVP_PKEY *pkey1 = key1->keydata.pkeypair.pub;
EVP_PKEY *pkey2 = key2->keydata.pkeypair.pub;
if (pkey1 == pkey2) {
return (true);
} else if (pkey1 == NULL || pkey2 == NULL) {
return (false);
}
/* `EVP_PKEY_eq` checks only the public components and parameters. */
if (EVP_PKEY_eq(pkey1, pkey2) != 1) {
return (false);
}
/* The private key presence must be same for keys to match. */
if ((key1->keydata.pkeypair.priv != NULL) !=
(key2->keydata.pkeypair.priv != NULL))
{
return (false);
}
return (true);
}
bool
dst__openssl_keypair_isprivate(const dst_key_t *key) {
return (key->keydata.pkeypair.priv != NULL);
}
void
dst__openssl_keypair_destroy(dst_key_t *key) {
if (key->keydata.pkeypair.priv != key->keydata.pkeypair.pub) {
EVP_PKEY_free(key->keydata.pkeypair.priv);
}
EVP_PKEY_free(key->keydata.pkeypair.pub);
key->keydata.pkeypair.pub = NULL;
key->keydata.pkeypair.priv = NULL;
}
/*! \file */