Skip to content

Commit

Permalink
mod_ssl: Add support for loading keys from OpenSSL 3.x providers via
Browse files Browse the repository at this point in the history
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 apache#397, closes apache#398

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1914365 13f79535-47bb-0310-9956-ffa450edef68
(cherry picked from commit cc796e2)
  • Loading branch information
notroj committed Jun 19, 2024
1 parent 0aa7f14 commit 1135e85
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 14 deletions.
2 changes: 2 additions & 0 deletions changes-entries/ssl-providers.txt
Original file line number Diff line number Diff line change
@@ -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>]
13 changes: 11 additions & 2 deletions docs/manual/mod/mod_ssl.xml
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,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
Expand Down Expand Up @@ -1045,7 +1045,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">
Expand Down Expand Up @@ -2422,6 +2422,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>

Expand Down
11 changes: 7 additions & 4 deletions modules/ssl/ssl_engine_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1411,8 +1411,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;
}
Expand All @@ -1423,8 +1425,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;
}
Expand Down
130 changes: 123 additions & 7 deletions modules/ssl/ssl_engine_pphrase.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -608,7 +611,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
Expand Down Expand Up @@ -826,13 +829,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);
Expand Down Expand Up @@ -906,6 +910,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
Expand Down
9 changes: 9 additions & 0 deletions modules/ssl/ssl_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion modules/ssl/ssl_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ void ssl_util_thread_id_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
Expand Down

0 comments on commit 1135e85

Please sign in to comment.