Skip to content

Commit 1bf73f3

Browse files
authored
Add OpenSSL 3.0+ PKCS#11 support using OSSL_STORE API (#1289)
* Add OpenSSL 3.0+ PKCS#11 support using OSSL_STORE API - Supports both OpenSSL < 3.0 (ENGINE API) and OpenSSL 3.0+ (Provider API) - Implements proper PKCS#11 certificate and key loading using OSSL_STORE * Improve PKCS#11 certificate/key loading from store with multiple object detection - Add detection for multiple certificates/keys in PKCS#11 store with helpful error messages directing users to use more specific URL parameters - Fix indentation to use tabs consistently (Linux kernel style) - Add proper memory cleanup in error cases to prevent leaks
1 parent 13f072f commit 1bf73f3

File tree

1 file changed

+100
-1
lines changed

1 file changed

+100
-1
lines changed

src/tunnel.c

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@
3333

3434
#include <openssl/err.h>
3535
#ifndef OPENSSL_NO_ENGINE
36+
#if OPENSSL_VERSION_NUMBER < 0x30000000L
3637
#include <openssl/engine.h>
38+
#else // OPENSSL_VERSION_NUMBER >= 0x30000000L
39+
#include <openssl/store.h>
40+
#endif
3741
#endif
3842
#include <openssl/ui.h>
3943
#include <openssl/x509v3.h>
@@ -1089,6 +1093,7 @@ int ssl_connect(struct tunnel *tunnel)
10891093
#endif
10901094

10911095
#ifndef OPENSSL_NO_ENGINE
1096+
#if OPENSSL_VERSION_NUMBER < 0x30000000L
10921097
/* Use PKCS11 engine for PIV if user-cert config starts with pkcs11 URI: */
10931098
if (tunnel->config->use_engine > 0) {
10941099
ENGINE *e;
@@ -1149,7 +1154,101 @@ int ssl_connect(struct tunnel *tunnel)
11491154
goto err_ssl_context;
11501155
}
11511156
} else { /* end PKCS11 engine */
1152-
#endif
1157+
#else // OPENSSL_VERSION_NUMBER >= 0x30000000L
1158+
/* OpenSSL 3.0+ provider-based PKCS#11 support */
1159+
if (tunnel->config->use_engine > 0) {
1160+
// Debug: Print the certificate path/URI being used
1161+
log_debug_details("Attempting to load certificate from: %s\n",
1162+
tunnel->config->user_cert);
1163+
1164+
// Use OSSL_STORE to load certificate and private key from PKCS#11
1165+
OSSL_STORE_CTX *store_ctx = OSSL_STORE_open(tunnel->config->user_cert,
1166+
NULL, NULL, NULL, NULL);
1167+
1168+
if (!store_ctx) {
1169+
log_error("PKCS11 OSSL_STORE_open failed: %s\n",
1170+
ERR_error_string(ERR_peek_last_error(), NULL));
1171+
goto err_ssl_context;
1172+
}
1173+
1174+
X509 *cert = NULL;
1175+
EVP_PKEY *pkey = NULL;
1176+
OSSL_STORE_INFO *info;
1177+
1178+
// Load all objects from the store
1179+
while ((info = OSSL_STORE_load(store_ctx)) != NULL) {
1180+
int type = OSSL_STORE_INFO_get_type(info);
1181+
1182+
if (type == OSSL_STORE_INFO_CERT) {
1183+
if (!cert) {
1184+
cert = OSSL_STORE_INFO_get1_CERT(info);
1185+
log_debug_details("Loaded certificate from PKCS#11 store\n");
1186+
} else {
1187+
// Second certificate - indicates multiple certs
1188+
log_error("PKCS11: Multiple certificates found in store. Please specify more specific URL parameters (e.g., ?id=... or ?label=...) to select the desired certificate.\n");
1189+
OSSL_STORE_INFO_free(info);
1190+
goto err_ssl_context;
1191+
}
1192+
} else if (type == OSSL_STORE_INFO_PKEY) {
1193+
if (!pkey) {
1194+
pkey = OSSL_STORE_INFO_get1_PKEY(info);
1195+
log_debug_details("Loaded private key from PKCS#11 store\n");
1196+
} else {
1197+
// Second private key - indicates multiple keys
1198+
log_error("PKCS11: Multiple private keys found in store. Please specify more specific URL parameters (e.g., ?id=... or ?label=...) to select the desired private key.\n");
1199+
OSSL_STORE_INFO_free(info);
1200+
goto err_ssl_context;
1201+
}
1202+
}
1203+
1204+
OSSL_STORE_INFO_free(info);
1205+
}
1206+
1207+
OSSL_STORE_close(store_ctx);
1208+
1209+
// Check if we successfully loaded both certificate and private key
1210+
if (!cert) {
1211+
log_error("PKCS11: Could not load certificate from store\n");
1212+
EVP_PKEY_free(pkey); // Free pkey if it was loaded but cert failed
1213+
goto err_ssl_context;
1214+
}
1215+
if (!pkey) {
1216+
log_error("PKCS11: Could not load private key from store\n");
1217+
X509_free(cert); // Free cert if it was loaded but pkey failed
1218+
goto err_ssl_context;
1219+
}
1220+
1221+
// Use the loaded certificate and private key
1222+
if (!SSL_CTX_use_certificate(tunnel->ssl_context, cert)) {
1223+
log_error("PKCS11 SSL_CTX_use_certificate failed: %s\n",
1224+
ERR_error_string(ERR_peek_last_error(), NULL));
1225+
X509_free(cert);
1226+
EVP_PKEY_free(pkey);
1227+
goto err_ssl_context;
1228+
}
1229+
1230+
if (!SSL_CTX_use_PrivateKey(tunnel->ssl_context, pkey)) {
1231+
log_error("PKCS11 SSL_CTX_use_PrivateKey failed: %s\n",
1232+
ERR_error_string(ERR_peek_last_error(), NULL));
1233+
X509_free(cert);
1234+
EVP_PKEY_free(pkey);
1235+
goto err_ssl_context;
1236+
}
1237+
1238+
if (!SSL_CTX_check_private_key(tunnel->ssl_context)) {
1239+
log_error("PKCS11 SSL_CTX_check_private_key: %s\n",
1240+
ERR_error_string(ERR_peek_last_error(), NULL));
1241+
X509_free(cert);
1242+
EVP_PKEY_free(pkey);
1243+
goto err_ssl_context;
1244+
}
1245+
1246+
// Clean up
1247+
X509_free(cert);
1248+
EVP_PKEY_free(pkey);
1249+
} else { /* end PKCS11 engine */
1250+
#endif // OPENSSL_VERSION_NUMBER >= 0x30000000L
1251+
#endif // OPENSSL_NO_ENGINE
11531252
if (tunnel->config->user_cert) {
11541253
if (!SSL_CTX_use_certificate_chain_file(
11551254
tunnel->ssl_context, tunnel->config->user_cert)) {

0 commit comments

Comments
 (0)