From: Joe Orton Date: Tue, 5 Dec 2023 15:26:22 +0000 (+0000) Subject: mod_ssl: Add support for loading keys from OpenSSL 3.x providers via X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cc796e269d7c4f8d105fa46b590c9301c2a55329;p=thirdparty%2Fapache%2Fhttpd.git mod_ssl: Add support for loading keys from OpenSSL 3.x providers via the STORE API. Separates compile-time support for the STORE API (supported in 3.x) from support for the ENGINE API (deprecated in 3.x). * modules/ssl/ssl_private.h: Define MODSSL_HAVE_OPENSSL_STORE for OpenSSL 3.0+. * modules/ssl/ssl_engine_pphrase.c (modssl_load_store_uri, modssl_load_keypair_store): New functions. (modssl_load_keypair_engine): Renamed from modssl_load_keypair_engine. (modssl_load_engine_keypair): Reimplement to use new STORE-based functions if SSLCryptoDevice was not configured, or else old ENGINE implementation. * modules/ssl/ssl_util.c (modssl_is_engine_id): Match pkcs11: URIs also for the OpenSSL 3.x STORE API. * modules/ssl/ssl_engine_init.c (ssl_init_server_certs): Tweak log message on error paths for the provider/STORE case. Signed-off-by: Ingo Franzki Submitted by: Ingo Franzki Github: closes #397, closes #398 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1914365 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/changes-entries/ssl-providers.txt b/changes-entries/ssl-providers.txt new file mode 100644 index 00000000000..65b5655afa9 --- /dev/null +++ b/changes-entries/ssl-providers.txt @@ -0,0 +1,2 @@ + *) mod_ssl: Add support for loading certs/keys from pkcs11: URIs + via OpenSSL 3.x providers. [Ingo Franzki ] diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index 6069f974f8d..489281b2dd1 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -10491 +10496 diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml index 248fe752477..ac35560f208 100644 --- a/docs/manual/mod/mod_ssl.xml +++ b/docs/manual/mod/mod_ssl.xml @@ -955,7 +955,7 @@ files, a certificate identifier can be used to identify a certificate stored in a token. Currently, only PKCS#11 URIs are recognized as certificate identifiers, and can be used in conjunction -with the OpenSSL pkcs11 engine. If pkcs11 engine or provider. If SSLCertificateKeyFile is omitted, the certificate and private key can be loaded through the single identifier specified with identifier can be used to identify a private key stored in a token. Currently, only PKCS#11 URIs are recognized as private key identifiers, and can be used in conjunction with the OpenSSL -pkcs11 engine.

+pkcs11 engine or provider.

Example @@ -2442,6 +2442,15 @@ separate "-engine" releases of OpenSSL 0.9.6 must be used.

SSLCryptoDevice ubsec
+ +

+With OpenSSL 3.0 or later, if no engine is specified but the key or certificate +is specified using a PKCS#11 URIs +then it is tried to load the key and certificate from an OpenSSL provider. +The OpenSSL provider to use must be defined and configured in the OpenSSL config file, +and it must support the STORE method +for PKCS#11 URIs. +

diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index 56938868b84..30fd6c5e4b5 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -1476,8 +1476,10 @@ static apr_status_t ssl_init_server_certs(server_rec *s, if (cert) { if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) < 1) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10137) - "Failed to configure engine certificate %s, check %s", - key_id, certfile); + "Failed to configure certificate %s from %s, check %s", + key_id, mc->szCryptoDevice ? + mc->szCryptoDevice : "provider", + certfile); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); return APR_EGENERAL; } @@ -1488,8 +1490,9 @@ static apr_status_t ssl_init_server_certs(server_rec *s, if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10130) - "Failed to configure private key %s from engine", - keyfile); + "Failed to configure private key %s from %s", + keyfile, mc->szCryptoDevice ? + mc->szCryptoDevice : "provider"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); return APR_EGENERAL; } diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c index 2a46f26cc3d..dfccf1170a5 100644 --- a/modules/ssl/ssl_engine_pphrase.c +++ b/modules/ssl/ssl_engine_pphrase.c @@ -31,6 +31,9 @@ #include "ssl_private.h" #include +#if MODSSL_HAVE_OPENSSL_STORE +#include +#endif typedef struct { server_rec *s; @@ -576,7 +579,7 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) return (len); } -#if MODSSL_HAVE_ENGINE_API +#if MODSSL_HAVE_ENGINE_API || MODSSL_HAVE_OPENSSL_STORE /* OpenSSL UI implementation for passphrase entry; largely duplicated * from ssl_pphrase_Handle_CB but adjusted for UI API. TODO: Might be @@ -793,13 +796,14 @@ static UI_METHOD *get_passphrase_ui(apr_pool_t *p) } #endif - -apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p, - const char *vhostid, - const char *certid, const char *keyid, - X509 **pubkey, EVP_PKEY **privkey) -{ #if MODSSL_HAVE_ENGINE_API +static apr_status_t modssl_load_keypair_engine(server_rec *s, apr_pool_t *p, + const char *vhostid, + const char *certid, + const char *keyid, + X509 **pubkey, + EVP_PKEY **privkey) +{ const char *c, *scheme; ENGINE *e; UI_METHOD *ui_method = get_passphrase_ui(p); @@ -873,6 +877,118 @@ apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p, ENGINE_free(e); return APR_SUCCESS; +} +#endif + +#if MODSSL_HAVE_OPENSSL_STORE +static OSSL_STORE_INFO *modssl_load_store_uri(server_rec *s, apr_pool_t *p, + const char *vhostid, + const char *uri, int info_type) +{ + OSSL_STORE_CTX *sctx; + UI_METHOD *ui_method = get_passphrase_ui(p); + pphrase_cb_arg_t ppcb; + OSSL_STORE_INFO *info = NULL; + + memset(&ppcb, 0, sizeof ppcb); + ppcb.s = s; + ppcb.p = p; + ppcb.bPassPhraseDialogOnce = TRUE; + ppcb.key_id = vhostid; + ppcb.pkey_file = uri; + + sctx = OSSL_STORE_open(uri, ui_method, &ppcb, NULL, NULL); + if (!sctx) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(10491) + "Init: OSSL_STORE_open failed for PKCS#11 URI `%s'", + uri); + return NULL; + } + + while (!OSSL_STORE_eof(sctx)) { + info = OSSL_STORE_load(sctx); + if (!info) + break; + + if (OSSL_STORE_INFO_get_type(info) == info_type) + break; + + OSSL_STORE_INFO_free(info); + info = NULL; + } + + OSSL_STORE_close(sctx); + + return info; +} + +static apr_status_t modssl_load_keypair_store(server_rec *s, apr_pool_t *p, + const char *vhostid, + const char *certid, + const char *keyid, + X509 **pubkey, + EVP_PKEY **privkey) +{ + OSSL_STORE_INFO *info = NULL; + + *privkey = NULL; + *pubkey = NULL; + + info = modssl_load_store_uri(s, p, vhostid, keyid, OSSL_STORE_INFO_PKEY); + if (!info) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10492) + "Init: OSSL_STORE_INFO_PKEY lookup failed for private key identifier `%s'", + keyid); + return ssl_die(s); + } + + *privkey = OSSL_STORE_INFO_get1_PKEY(info); + OSSL_STORE_INFO_free(info); + if (!*privkey) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10493) + "Init: OSSL_STORE_INFO_PKEY lookup failed for private key identifier `%s'", + keyid); + return ssl_die(s); + } + + if (certid) { + info = modssl_load_store_uri(s, p, vhostid, certid, OSSL_STORE_INFO_CERT); + if (!info) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10494) + "Init: OSSL_STORE_INFO_CERT lookup failed for certificate identifier `%s'", + keyid); + return ssl_die(s); + } + + *pubkey = OSSL_STORE_INFO_get1_CERT(info); + OSSL_STORE_INFO_free(info); + if (!*pubkey) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10495) + "Init: OSSL_STORE_INFO_CERT lookup failed for certificate identifier `%s'", + certid); + return ssl_die(s); + } + } + + return APR_SUCCESS; +} +#endif + +apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p, + const char *vhostid, + const char *certid, const char *keyid, + X509 **pubkey, EVP_PKEY **privkey) +{ +#if MODSSL_HAVE_OPENSSL_STORE + SSLModConfigRec *mc = myModConfig(s); + + if (!mc->szCryptoDevice) + return modssl_load_keypair_store(s, p, vhostid, certid, keyid, + pubkey, privkey); +#endif +#if MODSSL_HAVE_ENGINE_API + return modssl_load_keypair_engine(s, p, vhostid, certid, keyid, + pubkey, privkey); #else return APR_ENOTIMPL; #endif diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index 40510f688d9..d6673ee9762 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -118,6 +118,15 @@ #define MODSSL_HAVE_ENGINE_API 0 #endif +/* Use OpenSSL 3.x STORE for loading URI keys and certificates starting with + * OpenSSL 3.0 + */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000 +#define MODSSL_HAVE_OPENSSL_STORE 1 +#else +#define MODSSL_HAVE_OPENSSL_STORE 0 +#endif + #if (OPENSSL_VERSION_NUMBER < 0x0090801f) #error mod_ssl requires OpenSSL 0.9.8a or later #endif diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c index 0c9bb5acc3c..12ffff511e2 100644 --- a/modules/ssl/ssl_util.c +++ b/modules/ssl/ssl_util.c @@ -500,7 +500,7 @@ void ssl_util_thread_setup(apr_pool_t *p) int modssl_is_engine_id(const char *name) { -#if MODSSL_HAVE_ENGINE_API +#if MODSSL_HAVE_ENGINE_API || MODSSL_HAVE_OPENSSL_STORE /* ### Can handle any other special ENGINE key names here? */ return strncmp(name, "pkcs11:", 7) == 0; #else