diff options
author | Joe Orton <jorton@apache.org> | 2023-12-05 16:26:22 +0100 |
---|---|---|
committer | Joe Orton <jorton@apache.org> | 2023-12-05 16:26:22 +0100 |
commit | cc796e269d7c4f8d105fa46b590c9301c2a55329 (patch) | |
tree | 7b7b44eb2e557b7e97e8c610324ed0c1e4b685b7 | |
parent | mod_ssl: Follow up to r1908537: Fix typo s/MODSSL_USE_ENGINE_API/MODSSL_HAVE_... (diff) | |
download | apache2-cc796e269d7c4f8d105fa46b590c9301c2a55329.tar.xz apache2-cc796e269d7c4f8d105fa46b590c9301c2a55329.zip |
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 <ifranzki linux.ibm.com>
Submitted by: Ingo Franzki <ifranzki linux.ibm.com>
Github: closes #397, closes #398
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1914365 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | changes-entries/ssl-providers.txt | 2 | ||||
-rw-r--r-- | docs/log-message-tags/next-number | 2 | ||||
-rw-r--r-- | docs/manual/mod/mod_ssl.xml | 13 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_init.c | 11 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_pphrase.c | 130 | ||||
-rw-r--r-- | modules/ssl/ssl_private.h | 9 | ||||
-rw-r--r-- | modules/ssl/ssl_util.c | 2 |
7 files changed, 154 insertions, 15 deletions
diff --git a/changes-entries/ssl-providers.txt b/changes-entries/ssl-providers.txt new file mode 100644 index 0000000000..65b5655afa --- /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 <ifranzki linux.ibm.com>] diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index 6069f974f8..489281b2dd 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 248fe75247..ac35560f20 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 <a href="https://tools.ietf.org/html/rfc7512">PKCS#11 URIs</a> are recognized as certificate identifiers, and can be used in conjunction -with the OpenSSL <code>pkcs11</code> engine. If <directive +with the OpenSSL <code>pkcs11</code> engine or provider. If <directive module="mod_ssl">SSLCertificateKeyFile</directive> is omitted, the certificate and private key can be loaded through the single identifier specified with <directive @@ -1048,7 +1048,7 @@ key file.</p> identifier can be used to identify a private key stored in a token. Currently, only <a href="https://tools.ietf.org/html/rfc7512">PKCS#11 URIs</a> are recognized as private key identifiers, and can be used in conjunction with the OpenSSL -<code>pkcs11</code> engine.</p> +<code>pkcs11</code> engine or provider.</p> <example><title>Example</title> <highlight language="config"> @@ -2442,6 +2442,15 @@ separate "-engine" releases of OpenSSL 0.9.6 must be used.</p> SSLCryptoDevice ubsec </highlight> </example> + +<p> +With OpenSSL 3.0 or later, if no engine is specified but the key or certificate +is specified using a <a href="https://tools.ietf.org/html/rfc7512">PKCS#11 URIs</a> +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 <a href="https://www.openssl.org/docs/man3.0/man7/provider-storemgmt.html">STORE method</a> +for <a href="https://tools.ietf.org/html/rfc7512">PKCS#11 URIs</a>. +</p> </usage> </directivesynopsis> diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index 56938868b8..30fd6c5e4b 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 2a46f26cc3..dfccf1170a 100644 --- a/modules/ssl/ssl_engine_pphrase.c +++ b/modules/ssl/ssl_engine_pphrase.c @@ -31,6 +31,9 @@ #include "ssl_private.h" #include <openssl/ui.h> +#if MODSSL_HAVE_OPENSSL_STORE +#include <openssl/store.h> +#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 40510f688d..d6673ee976 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 0c9bb5acc3..12ffff511e 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 |