1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

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
This commit is contained in:
Joe Orton
2023-12-05 15:26:22 +00:00
parent 0123a2b0ed
commit cc796e269d
7 changed files with 154 additions and 15 deletions

View File

@@ -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>]

View File

@@ -1 +1 @@
10491 10496

View File

@@ -955,7 +955,7 @@ files, a certificate identifier can be used to identify a certificate
stored in a token. Currently, only <a stored in a token. Currently, only <a
href="https://tools.ietf.org/html/rfc7512">PKCS#11 URIs</a> are href="https://tools.ietf.org/html/rfc7512">PKCS#11 URIs</a> are
recognized as certificate identifiers, and can be used in conjunction 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 module="mod_ssl">SSLCertificateKeyFile</directive> is omitted, the
certificate and private key can be loaded through the single certificate and private key can be loaded through the single
identifier specified with <directive identifier specified with <directive
@@ -1048,7 +1048,7 @@ key file.</p>
identifier can be used to identify a private key stored in a 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 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 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> <example><title>Example</title>
<highlight language="config"> <highlight language="config">
@@ -2442,6 +2442,15 @@ separate "-engine" releases of OpenSSL 0.9.6 must be used.</p>
SSLCryptoDevice ubsec SSLCryptoDevice ubsec
</highlight> </highlight>
</example> </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> </usage>
</directivesynopsis> </directivesynopsis>

View File

@@ -1476,8 +1476,10 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
if (cert) { if (cert) {
if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) < 1) { if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) < 1) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10137) ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10137)
"Failed to configure engine certificate %s, check %s", "Failed to configure certificate %s from %s, check %s",
key_id, certfile); key_id, mc->szCryptoDevice ?
mc->szCryptoDevice : "provider",
certfile);
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
return APR_EGENERAL; 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) { if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10130) ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10130)
"Failed to configure private key %s from engine", "Failed to configure private key %s from %s",
keyfile); keyfile, mc->szCryptoDevice ?
mc->szCryptoDevice : "provider");
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
return APR_EGENERAL; return APR_EGENERAL;
} }

View File

@@ -31,6 +31,9 @@
#include "ssl_private.h" #include "ssl_private.h"
#include <openssl/ui.h> #include <openssl/ui.h>
#if MODSSL_HAVE_OPENSSL_STORE
#include <openssl/store.h>
#endif
typedef struct { typedef struct {
server_rec *s; server_rec *s;
@@ -576,7 +579,7 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
return (len); return (len);
} }
#if MODSSL_HAVE_ENGINE_API #if MODSSL_HAVE_ENGINE_API || MODSSL_HAVE_OPENSSL_STORE
/* OpenSSL UI implementation for passphrase entry; largely duplicated /* OpenSSL UI implementation for passphrase entry; largely duplicated
* from ssl_pphrase_Handle_CB but adjusted for UI API. TODO: Might be * 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 #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 #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; const char *c, *scheme;
ENGINE *e; ENGINE *e;
UI_METHOD *ui_method = get_passphrase_ui(p); 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); ENGINE_free(e);
return APR_SUCCESS; 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 #else
return APR_ENOTIMPL; return APR_ENOTIMPL;
#endif #endif

View File

@@ -118,6 +118,15 @@
#define MODSSL_HAVE_ENGINE_API 0 #define MODSSL_HAVE_ENGINE_API 0
#endif #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) #if (OPENSSL_VERSION_NUMBER < 0x0090801f)
#error mod_ssl requires OpenSSL 0.9.8a or later #error mod_ssl requires OpenSSL 0.9.8a or later
#endif #endif

View File

@@ -500,7 +500,7 @@ void ssl_util_thread_setup(apr_pool_t *p)
int modssl_is_engine_id(const char *name) 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? */ /* ### Can handle any other special ENGINE key names here? */
return strncmp(name, "pkcs11:", 7) == 0; return strncmp(name, "pkcs11:", 7) == 0;
#else #else