Use pkcs11 provider to resolve PKCS11 URIs
Resolves: RHEL-86951 Signed-off-by: Davide Caratti <dcaratti@redhat.com>
This commit is contained in:
parent
a48fe1614a
commit
39eb6edff3
@ -0,0 +1,386 @@
|
||||
From 400b89162294f0344d82334218e8950fd01bb12f Mon Sep 17 00:00:00 2001
|
||||
Message-ID: <400b89162294f0344d82334218e8950fd01bb12f.1744107874.git.davide.caratti@gmail.com>
|
||||
From: Davide Caratti <davide.caratti@gmail.com>
|
||||
Date: Wed, 15 Jan 2025 18:04:54 +0100
|
||||
Subject: [PATCH] OpenSSL: Use pkcs11-provider when OPENSSL_NO_ENGINE is
|
||||
defined
|
||||
|
||||
Now that ENGINE API starts being deprecated in distros (like Fedora [1])
|
||||
wpa_supplicant users might need a way to load certificates and keys from
|
||||
PKCS11 URIs even when OPENSSL_NO_ENGINE is defined. We can do that using
|
||||
pkcs11-provider: load it by default in wpa_supplicant, and try to use it
|
||||
when OPENSSL_NO_ENGINE is defined and configuration requests PKCS11 URIs
|
||||
for certificates / keys.
|
||||
|
||||
Inspired by pkcs11-provider test program 'tlssetkey.c' [2]
|
||||
|
||||
[1] https://fedoraproject.org/wiki/Changes/OpensslDeprecateEngine
|
||||
[2] https://github.com/latchset/pkcs11-provider/blob/main/tests/tlssetkey.c
|
||||
|
||||
Signed-off-by: Davide Caratti <davide.caratti@gmail.com>
|
||||
---
|
||||
src/crypto/tls_openssl.c | 215 ++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 190 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
|
||||
index 17283f998..e225817fe 100644
|
||||
--- a/src/crypto/tls_openssl.c
|
||||
+++ b/src/crypto/tls_openssl.c
|
||||
@@ -33,6 +33,8 @@
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/decoder.h>
|
||||
#include <openssl/param_build.h>
|
||||
+#include <openssl/store.h>
|
||||
+#include <openssl/provider.h>
|
||||
#else /* OpenSSL version >= 3.0 */
|
||||
#ifndef OPENSSL_NO_DSA
|
||||
#include <openssl/dsa.h>
|
||||
@@ -244,8 +246,8 @@ struct tls_connection {
|
||||
BIO *ssl_in, *ssl_out;
|
||||
#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
|
||||
ENGINE *engine; /* functional reference to the engine */
|
||||
- EVP_PKEY *private_key; /* the private key if using engine */
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
+ EVP_PKEY *private_key; /* the private key if using engine/provider */
|
||||
char *subject_match, *altsubject_match, *suffix_match, *domain_match;
|
||||
char *check_cert_subject;
|
||||
int read_alerts, write_alerts, failed;
|
||||
@@ -357,6 +359,149 @@ static X509_STORE * tls_crl_cert_reload(const char *ca_cert, int check_crl)
|
||||
}
|
||||
|
||||
|
||||
+#ifdef OPENSSL_NO_ENGINE
|
||||
+
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+static OSSL_PROVIDER *openssl_pkcs11_provider = NULL;
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
+
|
||||
+static void openssl_load_pkcs11_provider(void)
|
||||
+{
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+ if (openssl_pkcs11_provider)
|
||||
+ return;
|
||||
+
|
||||
+ openssl_pkcs11_provider = OSSL_PROVIDER_try_load(NULL, "pkcs11", 1);
|
||||
+ if (!openssl_pkcs11_provider)
|
||||
+ wpa_printf(MSG_WARNING, "PKCS11 provider not present");
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void openssl_unload_pkcs11_provider(void)
|
||||
+{
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+ if (openssl_pkcs11_provider) {
|
||||
+ OSSL_PROVIDER_unload(openssl_pkcs11_provider);
|
||||
+ openssl_pkcs11_provider = NULL;
|
||||
+ }
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static bool openssl_can_use_provider(const char *engine_id, const char *req)
|
||||
+{
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+ if (!os_strcmp(engine_id, "pkcs11") && openssl_pkcs11_provider)
|
||||
+ return true;
|
||||
+
|
||||
+ wpa_printf(MSG_ERROR,
|
||||
+ "Cannot find OpenSSL provider for '%s' (missing '%s')",
|
||||
+ req, engine_id);
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static EVP_PKEY * provider_load_key(const char *uri)
|
||||
+{
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+ OSSL_STORE_CTX *store;
|
||||
+ OSSL_STORE_INFO *info;
|
||||
+ EVP_PKEY *key = NULL;
|
||||
+
|
||||
+ if (!uri) {
|
||||
+ tls_show_errors(MSG_ERROR, __func__,
|
||||
+ "Invalid NULL uri for key");
|
||||
+ goto err_key;
|
||||
+ }
|
||||
+
|
||||
+ store = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL);
|
||||
+ if (!store) {
|
||||
+ wpa_printf(MSG_DEBUG, "Bad uri for private key:%s", uri);
|
||||
+
|
||||
+ tls_show_errors(MSG_ERROR, __func__,
|
||||
+ "Failed to open key store");
|
||||
+ goto err_key;
|
||||
+ }
|
||||
+
|
||||
+ if (os_strncmp(uri, "pkcs11:", 7) &&
|
||||
+ os_strstr(uri, "type=private") == NULL) {
|
||||
+ /* This is a workaround for OpenSSL < 3.2.0 where the code fails
|
||||
+ * to correctly source public keys unless explicitly requested
|
||||
+ * via an expect hint. */
|
||||
+ if (OSSL_STORE_expect(store, OSSL_STORE_INFO_PUBKEY) != 1) {
|
||||
+ tls_show_errors(MSG_ERROR, __func__,
|
||||
+ "Failed to expect Public Key File");
|
||||
+ goto err_store;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ while (!OSSL_STORE_eof(store)) {
|
||||
+ info = OSSL_STORE_load(store);
|
||||
+ if ((OSSL_STORE_INFO_get_type(info)) == OSSL_STORE_INFO_PKEY)
|
||||
+ key = OSSL_STORE_INFO_get1_PKEY(info);
|
||||
+
|
||||
+ OSSL_STORE_INFO_free(info);
|
||||
+ if (key)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+err_store:
|
||||
+ OSSL_STORE_close(store);
|
||||
+err_key:
|
||||
+ if (!key)
|
||||
+ wpa_printf(MSG_ERROR, "OpenSSL: Failed to load key from URI");
|
||||
+
|
||||
+ return key;
|
||||
+#else /* OpenSSL version >= 3.0 */
|
||||
+ return NULL;
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static X509 * provider_load_cert(const char *cert_id)
|
||||
+{
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+ OSSL_STORE_CTX *store;
|
||||
+ OSSL_STORE_INFO *info;
|
||||
+ X509 *cert = NULL;
|
||||
+
|
||||
+ if (!cert_id) {
|
||||
+ tls_show_errors(MSG_ERROR, __func__, "Invalid NULL uri");
|
||||
+ goto err_cert;
|
||||
+ }
|
||||
+
|
||||
+ store = OSSL_STORE_open(cert_id, NULL, NULL, NULL, NULL);
|
||||
+ if (!store) {
|
||||
+ tls_show_errors(MSG_ERROR, __func__, "Failed to open store");
|
||||
+ goto err_cert;
|
||||
+ }
|
||||
+
|
||||
+ while (!OSSL_STORE_eof(store)) {
|
||||
+ info = OSSL_STORE_load(store);
|
||||
+ if ((OSSL_STORE_INFO_get_type(info)) == OSSL_STORE_INFO_CERT)
|
||||
+ cert = OSSL_STORE_INFO_get1_CERT(info);
|
||||
+
|
||||
+ OSSL_STORE_INFO_free(info);
|
||||
+ if (cert)
|
||||
+ break;
|
||||
+ }
|
||||
+ OSSL_STORE_close(store);
|
||||
+
|
||||
+err_cert:
|
||||
+ if (!cert)
|
||||
+ tls_show_errors(MSG_ERROR, __func__,
|
||||
+ "Failed to load cert from URI");
|
||||
+ return cert;
|
||||
+#else /* OpenSSL version >= 3.0 */
|
||||
+ return NULL;
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
+}
|
||||
+
|
||||
+#endif /* OPENSSL_NO_ENGINE */
|
||||
+
|
||||
+
|
||||
#ifdef CONFIG_NATIVE_WINDOWS
|
||||
|
||||
/* Windows CryptoAPI and access to certificate stores */
|
||||
@@ -1020,6 +1165,9 @@ void * tls_init(const struct tls_config *conf)
|
||||
void openssl_load_legacy_provider(void);
|
||||
|
||||
openssl_load_legacy_provider();
|
||||
+#ifdef OPENSSL_NO_ENGINE
|
||||
+ openssl_load_pkcs11_provider();
|
||||
+#endif /* OPENSSL_NO_ENGINE */
|
||||
|
||||
tls_global = context = tls_context_new(conf);
|
||||
if (context == NULL)
|
||||
@@ -1211,6 +1359,9 @@ void tls_deinit(void *ssl_ctx)
|
||||
|
||||
tls_openssl_ref_count--;
|
||||
if (tls_openssl_ref_count == 0) {
|
||||
+#ifdef OPENSSL_NO_ENGINE
|
||||
+ openssl_unload_pkcs11_provider();
|
||||
+#endif /* OPENSSL_NO_ENGINE */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE_cleanup();
|
||||
@@ -1369,6 +1520,10 @@ err:
|
||||
|
||||
return ret;
|
||||
#else /* OPENSSL_NO_ENGINE */
|
||||
+ conn->private_key = provider_load_key(key_id);
|
||||
+ if (!conn->private_key)
|
||||
+ return -1;
|
||||
+
|
||||
return 0;
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
}
|
||||
@@ -1376,12 +1531,12 @@ err:
|
||||
|
||||
static void tls_engine_deinit(struct tls_connection *conn)
|
||||
{
|
||||
-#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
|
||||
- wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
|
||||
if (conn->private_key) {
|
||||
EVP_PKEY_free(conn->private_key);
|
||||
conn->private_key = NULL;
|
||||
}
|
||||
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
|
||||
+ wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
|
||||
if (conn->engine) {
|
||||
#if !defined(OPENSSL_IS_BORINGSSL)
|
||||
ENGINE_finish(conn->engine);
|
||||
@@ -3799,11 +3954,16 @@ static int tls_engine_get_cert(struct tls_connection *conn,
|
||||
static int tls_connection_engine_client_cert(struct tls_connection *conn,
|
||||
const char *cert_id)
|
||||
{
|
||||
-#ifndef OPENSSL_NO_ENGINE
|
||||
X509 *cert;
|
||||
|
||||
+#ifndef OPENSSL_NO_ENGINE
|
||||
if (tls_engine_get_cert(conn, cert_id, &cert))
|
||||
return -1;
|
||||
+#else /* OPENSSL_NO_ENGINE */
|
||||
+ cert = provider_load_cert(cert_id);
|
||||
+ if (!cert)
|
||||
+ return -1;
|
||||
+#endif /* OPENSSL_NO_ENGINE */
|
||||
|
||||
if (!SSL_use_certificate(conn->ssl, cert)) {
|
||||
tls_show_errors(MSG_ERROR, __func__,
|
||||
@@ -3812,13 +3972,9 @@ static int tls_connection_engine_client_cert(struct tls_connection *conn,
|
||||
return -1;
|
||||
}
|
||||
X509_free(cert);
|
||||
- wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
|
||||
+ wpa_printf(MSG_DEBUG, "ENGINE/provider: SSL_use_certificate --> "
|
||||
"OK");
|
||||
return 0;
|
||||
-
|
||||
-#else /* OPENSSL_NO_ENGINE */
|
||||
- return -1;
|
||||
-#endif /* OPENSSL_NO_ENGINE */
|
||||
}
|
||||
|
||||
|
||||
@@ -3826,13 +3982,18 @@ static int tls_connection_engine_ca_cert(struct tls_data *data,
|
||||
struct tls_connection *conn,
|
||||
const char *ca_cert_id)
|
||||
{
|
||||
-#ifndef OPENSSL_NO_ENGINE
|
||||
X509 *cert;
|
||||
SSL_CTX *ssl_ctx = data->ssl;
|
||||
X509_STORE *store;
|
||||
|
||||
+#ifndef OPENSSL_NO_ENGINE
|
||||
if (tls_engine_get_cert(conn, ca_cert_id, &cert))
|
||||
return -1;
|
||||
+#else /* OPENSSL_NO_ENGINE */
|
||||
+ cert = provider_load_cert(ca_cert_id);
|
||||
+ if (!cert)
|
||||
+ return -1;
|
||||
+#endif /* OPENSSL_NO_ENGINE */
|
||||
|
||||
/* start off the same as tls_connection_ca_cert */
|
||||
store = X509_STORE_new();
|
||||
@@ -3846,7 +4007,7 @@ static int tls_connection_engine_ca_cert(struct tls_data *data,
|
||||
if (!X509_STORE_add_cert(store, cert)) {
|
||||
unsigned long err = ERR_peek_error();
|
||||
tls_show_errors(MSG_WARNING, __func__,
|
||||
- "Failed to add CA certificate from engine "
|
||||
+ "Failed to add CA certificate from engine/provider "
|
||||
"to certificate store");
|
||||
if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
|
||||
ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
|
||||
@@ -3859,25 +4020,21 @@ static int tls_connection_engine_ca_cert(struct tls_data *data,
|
||||
}
|
||||
}
|
||||
X509_free(cert);
|
||||
- wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
|
||||
- "to certificate store", __func__);
|
||||
+ wpa_printf(MSG_DEBUG,
|
||||
+ "OpenSSL: %s - added CA certificate from engine/provider to certificate store",
|
||||
+ __func__);
|
||||
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
|
||||
conn->ca_cert_verify = 1;
|
||||
|
||||
return 0;
|
||||
-
|
||||
-#else /* OPENSSL_NO_ENGINE */
|
||||
- return -1;
|
||||
-#endif /* OPENSSL_NO_ENGINE */
|
||||
}
|
||||
|
||||
|
||||
static int tls_connection_engine_private_key(struct tls_connection *conn)
|
||||
{
|
||||
-#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
|
||||
if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
|
||||
tls_show_errors(MSG_ERROR, __func__,
|
||||
- "ENGINE: cannot use private key for TLS");
|
||||
+ "ENGINE/provider: cannot use private key for TLS");
|
||||
return -1;
|
||||
}
|
||||
if (!SSL_check_private_key(conn->ssl)) {
|
||||
@@ -3886,11 +4043,6 @@ static int tls_connection_engine_private_key(struct tls_connection *conn)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
-#else /* OPENSSL_NO_ENGINE */
|
||||
- wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
|
||||
- "engine support was not compiled in");
|
||||
- return -1;
|
||||
-#endif /* OPENSSL_NO_ENGINE */
|
||||
}
|
||||
|
||||
|
||||
@@ -5437,6 +5589,10 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
return -1;
|
||||
|
||||
if (engine_id && ca_cert_id) {
|
||||
+#ifdef OPENSSL_NO_ENGINE
|
||||
+ if (!openssl_can_use_provider(engine_id, ca_cert_id))
|
||||
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
|
||||
+#endif /* OPENSSL_NO_ENGINE */
|
||||
if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
|
||||
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
|
||||
} else if (tls_connection_ca_cert(data, conn, params->ca_cert,
|
||||
@@ -5446,6 +5602,10 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
return -1;
|
||||
|
||||
if (engine_id && cert_id) {
|
||||
+#ifdef OPENSSL_NO_ENGINE
|
||||
+ if (!openssl_can_use_provider(engine_id, cert_id))
|
||||
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
|
||||
+#endif /* OPENSSL_NO_ENGINE */
|
||||
if (tls_connection_engine_client_cert(conn, cert_id))
|
||||
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
|
||||
} else if (tls_connection_client_cert(conn, params->client_cert,
|
||||
@@ -5454,7 +5614,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
return -1;
|
||||
|
||||
if (engine_id && key_id) {
|
||||
- wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
|
||||
+#ifdef OPENSSL_NO_ENGINE
|
||||
+ if (!openssl_can_use_provider(engine_id, key_id))
|
||||
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
|
||||
+#endif /* OPENSSL_NO_ENGINE */
|
||||
+ wpa_printf(MSG_DEBUG,
|
||||
+ "TLS: Using private key from engine/provider");
|
||||
if (tls_connection_engine_private_key(conn))
|
||||
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
|
||||
} else if (tls_connection_private_key(data, conn,
|
||||
--
|
||||
2.47.0
|
||||
|
@ -31,6 +31,8 @@ Patch3: wpa_supplicant-quiet-scan-results-message.patch
|
||||
Patch4: wpa_supplicant-gui-qt4.patch
|
||||
# fix known regression on brcmfmac (rhbz#2302577)
|
||||
Patch5: wpa_supplicant-Revert-Mark-authorization-completed-on-driver-indica.patch
|
||||
# use pkcs11-provider instead of OpenSSL engine
|
||||
Patch6: wpa_supplicant-OpenSSL-Use-pkcs11-provider-when-OPENSSL_NO_ENGINE-i.patch
|
||||
|
||||
URL: http://w1.fi/wpa_supplicant/
|
||||
|
||||
@ -48,6 +50,8 @@ Requires(post): systemd-sysv
|
||||
Requires(post): systemd
|
||||
Requires(preun): systemd
|
||||
Requires(postun): systemd
|
||||
Requires: pkcs11-provider >= 1.0
|
||||
|
||||
# libeap used to be built from wpa_supplicant with some fairly horrible
|
||||
# hackery, solely for use by WiMAX. We dropped all WiMAX support around
|
||||
# F21. This is here so people don't wind up with obsolete libeap packages
|
||||
|
Loading…
Reference in New Issue
Block a user