On 02.12.2023 11:20, Graham Leggett via dev wrote: > On 27 Nov 2023, at 15:02, Ingo Franzki <ifran...@linux.ibm.com> wrote: > >> The mod_ssl module has support for loading keys and certificates from >> OpenSSL engines via PKCS#11 URIs at SSLCertificateFile and >> SSLCertificateKeyFile, e.g. using the PKCS#11 engine part of libp11 >> (https://github.com/OpenSC/libp11). >> >> This works fine, but with OpenSSL 3.0 engines got deprecated, and a new >> provider concept is used. >> OpenSSL 1.1.1 is no longer supported by the OpenSSL organization >> (https://www.openssl.org/blog/blog/2023/09/11/eol-111/), >> and newer distributions all have OpenSSL 3.x included. >> Currently, engines do still work, bit since they are deprecated, they will >> at some point in time no longer be working. >> >> With OpenSSL 3.x providers one can implements loading of keys and >> certificates by implementing a STORE method. >> With this, keys and certificates can be loaded for example from PKCS#11 >> modules via PKCS#11 URIs, just like it was possible with an PKCS#11 engine. >> >> Please find below some code changes required to support loading the server >> private key and certificates from a PKCS#11 provider using OpenSSL STORE >> providers. > > Definite +1 in principle. > >> Index: docs/manual/mod/mod_ssl.html.en.utf8 >> =================================================================== >> --- docs/manual/mod/mod_ssl.html.en.utf8 (revision 1914150) >> +++ docs/manual/mod/mod_ssl.html.en.utf8 (working copy) >> @@ -666,7 +666,7 @@ > > Would it be possible to patch mod_ssl.xml instead of the html file, the html > is autogenerated. Sure, see updated patch attached. > >> Index: modules/ssl/ssl_engine_config.c >> =================================================================== >> --- modules/ssl/ssl_engine_config.c (revision 1914150) >> +++ modules/ssl/ssl_engine_config.c (working copy) >> @@ -689,6 +689,11 @@ >> if (strcEQ(arg, "builtin")) { >> mc->szCryptoDevice = NULL; >> } >> +#if MODSSL_USE_OPENSSL_STORE >> + else if (strcEQ(arg, "provider")) { >> + mc->szCryptoDevice = arg; >> + } >> +#endif >> #if MODSSL_HAVE_ENGINE_API > > This patch isn’t applying for me, looks like the leading spaces have been > lost. Would it be possible to try attach it as a file? Please see the patch file attached. I also fixed to minor bugs that I found during testing.
You can also look at the patch here: https://github.com/ifranzki/httpd/commit/4bb3ea191bc2c77608b4811817ad7f63177dd931 If you want, I can even submit a pull request to https://github.com/apache/httpd. Let me know what you prefer. > > Regards, > Graham > — > -- Ingo Franzki eMail: ifran...@linux.ibm.com Tel: ++49 (0)7031-16-4648 Linux on IBM Z Development, Schoenaicher Str. 220, 71032 Boeblingen, Germany IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Gregor Pillen Geschäftsführung: David Faller Sitz der Gesellschaft: Böblingen / Registergericht: Amtsgericht Stuttgart, HRB 243294 IBM DATA Privacy Statement: https://www.ibm.com/privacy/us/en/
Index: docs/manual/mod/mod_ssl.xml =================================================================== --- docs/manual/mod/mod_ssl.xml (revision 1914150) +++ docs/manual/mod/mod_ssl.xml (working copy) @@ -955,7 +955,7 @@ 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 @@ 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,14 @@ SSLCryptoDevice ubsec </highlight> </example> + +<p> +With OpenSSL 3.0 or later, specify <code>provider</code> to load keys and +certificates from a provider using <a href="https://tools.ietf.org/html/rfc7512">PKCS#11 URIs</a>. +The 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> Index: modules/ssl/ssl_engine_config.c =================================================================== --- modules/ssl/ssl_engine_config.c (revision 1914150) +++ modules/ssl/ssl_engine_config.c (working copy) @@ -689,6 +689,11 @@ if (strcEQ(arg, "builtin")) { mc->szCryptoDevice = NULL; } +#if MODSSL_USE_OPENSSL_STORE + else if (strcEQ(arg, "provider")) { + mc->szCryptoDevice = arg; + } +#endif #if MODSSL_HAVE_ENGINE_API else if ((e = ENGINE_by_id(arg))) { mc->szCryptoDevice = arg; @@ -697,7 +702,11 @@ #endif else { err = "SSLCryptoDevice: Invalid argument; must be one of: " +#if MODSSL_USE_OPENSSL_STORE + "'builtin' (none), 'provider' (use OpenSSL >= 3.0 provider STORE)"; +#else "'builtin' (none)"; +#endif #if MODSSL_HAVE_ENGINE_API e = ENGINE_get_first(); while (e) { Index: modules/ssl/ssl_engine_init.c =================================================================== --- modules/ssl/ssl_engine_init.c (revision 1914150) +++ modules/ssl/ssl_engine_init.c (working copy) @@ -506,7 +506,11 @@ SSLModConfigRec *mc = myModConfig(s); ENGINE *e; +#if MODSSL_USE_OPENSSL_STORE + if (mc->szCryptoDevice && !strcEQ(mc->szCryptoDevice, "provider")) { +#else if (mc->szCryptoDevice) { +#endif if (!(e = ENGINE_by_id(mc->szCryptoDevice))) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01888) "Init: Failed to load Crypto Device API `%s'", @@ -1476,7 +1480,11 @@ if (cert) { if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) < 1) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10137) +#if MODSSL_USE_OPENSSL_STORE + "Failed to configure engine/provider certificate %s, check %s", +#else "Failed to configure engine certificate %s, check %s", +#endif key_id, certfile); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); return APR_EGENERAL; @@ -1488,7 +1496,11 @@ if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10130) +#if MODSSL_USE_OPENSSL_STORE + "Failed to configure private key %s from engine/provider", +#else "Failed to configure private key %s from engine", +#endif keyfile); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); return APR_EGENERAL; Index: modules/ssl/ssl_engine_pphrase.c =================================================================== --- modules/ssl/ssl_engine_pphrase.c (revision 1914150) +++ modules/ssl/ssl_engine_pphrase.c (working copy) @@ -31,6 +31,9 @@ #include "ssl_private.h" #include <openssl/ui.h> +#if MODSSL_USE_OPENSSL_STORE +#include <openssl/store.h> +#endif typedef struct { server_rec *s; @@ -576,7 +579,7 @@ return (len); } -#if MODSSL_HAVE_ENGINE_API +#if MODSSL_HAVE_ENGINE_API || MODSSL_USE_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 @@ } #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,133 @@ ENGINE_free(e); return APR_SUCCESS; +} +#endif + +#if MODSSL_USE_OPENSSL_STORE +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_CTX *sctx; + UI_METHOD *ui_method = get_passphrase_ui(p); + pphrase_cb_arg_t ppcb; + + memset(&ppcb, 0, sizeof ppcb); + ppcb.s = s; + ppcb.p = p; + ppcb.bPassPhraseDialogOnce = TRUE; + ppcb.key_id = vhostid; + ppcb.pkey_file = keyid; + + *privkey = NULL; + sctx = OSSL_STORE_open(keyid, ui_method, &ppcb, NULL, NULL); + if (!sctx) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) + "Init: OSSL_STORE_open failed for private key identifier `%s'", + keyid); + return ssl_die(s); + } + + while (!OSSL_STORE_eof(sctx)) { + OSSL_STORE_INFO *info = OSSL_STORE_load(sctx); + if (!info) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) + "Init: OSSL_STORE_load failed for private key identifier `%s'", + keyid); + OSSL_STORE_close(sctx); + return ssl_die(s); + } + + switch (OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_PKEY: + *privkey = OSSL_STORE_INFO_get1_PKEY(info); + break; + default: + OSSL_STORE_INFO_free(info); + continue; + } + + OSSL_STORE_INFO_free(info); + break; + } + + OSSL_STORE_close(sctx); + + if (!*privkey) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) + "Init: OSSL_STORE_INFO_PKEY lookup failed for private key identifier `%s'", + keyid); + OSSL_STORE_close(sctx); + return ssl_die(s); + } + + if (certid) { + *pubkey = NULL; + + sctx = OSSL_STORE_open(certid, ui_method, &ppcb, NULL, NULL); + if (!sctx) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) + "Init: OSSL_STORE_open failed for certificate identifier `%s'", + certid); + return ssl_die(s); + } + + while (!OSSL_STORE_eof(sctx)) { + OSSL_STORE_INFO *info = OSSL_STORE_load(sctx); + if (!info) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) + "Init: OSSL_STORE_load failed for certificate identifier `%s'", + certid); + OSSL_STORE_close(sctx); + return ssl_die(s); + } + + switch (OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_CERT: + *pubkey = OSSL_STORE_INFO_get1_CERT(info); + break; + default: + OSSL_STORE_INFO_free(info); + continue; + } + + OSSL_STORE_INFO_free(info); + break; + } + + OSSL_STORE_close(sctx); + + if (!*pubkey) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) + "Init: OSSL_STORE_INFO_PKEY 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_USE_OPENSSL_STORE + SSLModConfigRec *mc = myModConfig(s); + + if (strcEQ(mc->szCryptoDevice, "provider")) + 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 Index: modules/ssl/ssl_private.h =================================================================== --- modules/ssl/ssl_private.h (revision 1914150) +++ modules/ssl/ssl_private.h (working copy) @@ -118,6 +118,13 @@ #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_USE_OPENSSL_STORE 1 +#endif + #if (OPENSSL_VERSION_NUMBER < 0x0090801f) #error mod_ssl requires OpenSSL 0.9.8a or later #endif Index: modules/ssl/ssl_util.c =================================================================== --- modules/ssl/ssl_util.c (revision 1914150) +++ modules/ssl/ssl_util.c (working copy) @@ -500,7 +500,7 @@ int modssl_is_engine_id(const char *name) { -#if MODSSL_USE_ENGINE_API +#if MODSSL_USE_ENGINE_API || MODSSL_USE_OPENSSL_STORE /* ### Can handle any other special ENGINE key names here? */ return strncmp(name, "pkcs11:", 7) == 0; #else