summaryrefslogtreecommitdiffstats
path: root/modules/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'modules/ssl')
-rw-r--r--modules/ssl/ssl_engine_init.c13
-rw-r--r--modules/ssl/ssl_engine_io.c82
-rw-r--r--modules/ssl/ssl_engine_kernel.c4
-rw-r--r--modules/ssl/ssl_engine_pphrase.c159
-rw-r--r--modules/ssl/ssl_private.h14
-rw-r--r--modules/ssl/ssl_util.c2
6 files changed, 231 insertions, 43 deletions
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index 443eac4..598e89f 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -1424,7 +1424,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s,
if (modssl_is_engine_id(keyfile)) {
apr_status_t rv;
- if ((rv = modssl_load_engine_keypair(s, ptemp, vhost_id,
+ if ((rv = modssl_load_engine_keypair(s, p, ptemp, vhost_id,
engine_certfile, keyfile,
&cert, &pkey))) {
return rv;
@@ -1433,8 +1433,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;
}
@@ -1445,8 +1447,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_io.c b/modules/ssl/ssl_engine_io.c
index 9c7d216..0be5318 100644
--- a/modules/ssl/ssl_engine_io.c
+++ b/modules/ssl/ssl_engine_io.c
@@ -2285,9 +2285,7 @@ void ssl_io_filter_init(conn_rec *c, request_rec *r, SSL *ssl)
apr_pool_cleanup_register(c->pool, (void*)filter_ctx,
ssl_io_filter_cleanup, apr_pool_cleanup_null);
- if (APLOG_CS_IS_LEVEL(c, mySrvFromConn(c), APLOG_TRACE4)) {
- modssl_set_io_callbacks(ssl);
- }
+ modssl_set_io_callbacks(ssl, c, mySrvFromConn(c));
return;
}
@@ -2312,7 +2310,7 @@ void ssl_io_filter_register(apr_pool_t *p)
#define DUMP_WIDTH 16
static void ssl_io_data_dump(conn_rec *c, server_rec *s,
- const char *b, long len)
+ const char *b, int len)
{
char buf[256];
int i, j, rows, trunc, pos;
@@ -2365,11 +2363,13 @@ static void ssl_io_data_dump(conn_rec *c, server_rec *s,
}
if (trunc > 0)
ap_log_cserror(APLOG_MARK, APLOG_TRACE7, 0, c, s,
- "| %04ld - <SPACES/NULS>", len + trunc);
+ "| %04d - <SPACES/NULS>", len + trunc);
ap_log_cserror(APLOG_MARK, APLOG_TRACE7, 0, c, s,
"+-------------------------------------------------------------------------+");
}
+#define MODSSL_IO_DUMP_MAX APR_UINT16_MAX
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
static long modssl_io_cb(BIO *bio, int cmd, const char *argp,
size_t len, int argi, long argl, int rc,
@@ -2382,10 +2382,12 @@ static long modssl_io_cb(BIO *bio, int cmd, const char *argp,
SSL *ssl;
conn_rec *c;
server_rec *s;
+
+ /* unused */
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- (void)len;
- (void)processed;
+ (void)argi;
#endif
+ (void)argl;
if ((ssl = (SSL *)BIO_get_callback_arg(bio)) == NULL)
return rc;
@@ -2395,28 +2397,59 @@ static long modssl_io_cb(BIO *bio, int cmd, const char *argp,
if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN)
|| cmd == (BIO_CB_READ |BIO_CB_RETURN) ) {
- if (rc >= 0) {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ apr_size_t requested_len = len;
+ /*
+ * On OpenSSL >= 3 rc uses the meaning of the BIO_read_ex and
+ * BIO_write_ex functions return value and not the one of
+ * BIO_read and BIO_write. Hence 0 indicates an error.
+ */
+ int ok = (rc > 0);
+#else
+ apr_size_t requested_len = (apr_size_t)argi;
+ int ok = (rc >= 0);
+#endif
+ if (ok) {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ apr_size_t actual_len = *processed;
+#else
+ apr_size_t actual_len = (apr_size_t)rc;
+#endif
const char *dump = "";
if (APLOG_CS_IS_LEVEL(c, s, APLOG_TRACE7)) {
- if (argp != NULL)
- dump = "(BIO dump follows)";
- else
+ if (argp == NULL)
dump = "(Oops, no memory buffer?)";
+ else if (actual_len > MODSSL_IO_DUMP_MAX)
+ dump = "(BIO dump follows, truncated to "
+ APR_STRINGIFY(MODSSL_IO_DUMP_MAX) ")";
+ else
+ dump = "(BIO dump follows)";
}
ap_log_cserror(APLOG_MARK, APLOG_TRACE4, 0, c, s,
- "%s: %s %ld/%d bytes %s BIO#%pp [mem: %pp] %s",
+ "%s: %s %" APR_SIZE_T_FMT "/%" APR_SIZE_T_FMT
+ " bytes %s BIO#%pp [mem: %pp] %s",
MODSSL_LIBRARY_NAME,
- (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
- (long)rc, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "to" : "from"),
+ (cmd & BIO_CB_WRITE) ? "write" : "read",
+ actual_len, requested_len,
+ (cmd & BIO_CB_WRITE) ? "to" : "from",
bio, argp, dump);
- if (*dump != '\0' && argp != NULL)
- ssl_io_data_dump(c, s, argp, rc);
+ /*
+ * *dump will only be != '\0' if
+ * APLOG_CS_IS_LEVEL(c, s, APLOG_TRACE7)
+ */
+ if (*dump != '\0' && argp != NULL) {
+ int dump_len = (actual_len >= MODSSL_IO_DUMP_MAX
+ ? MODSSL_IO_DUMP_MAX
+ : actual_len);
+ ssl_io_data_dump(c, s, argp, dump_len);
+ }
}
else {
ap_log_cserror(APLOG_MARK, APLOG_TRACE4, 0, c, s,
- "%s: I/O error, %d bytes expected to %s on BIO#%pp [mem: %pp]",
- MODSSL_LIBRARY_NAME, argi,
- (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
+ "%s: I/O error, %" APR_SIZE_T_FMT
+ " bytes expected to %s on BIO#%pp [mem: %pp]",
+ MODSSL_LIBRARY_NAME, requested_len,
+ (cmd & BIO_CB_WRITE) ? "write" : "read",
bio, argp);
}
}
@@ -2433,10 +2466,15 @@ static APR_INLINE void set_bio_callback(BIO *bio, void *arg)
BIO_set_callback_arg(bio, arg);
}
-void modssl_set_io_callbacks(SSL *ssl)
+void modssl_set_io_callbacks(SSL *ssl, conn_rec *c, server_rec *s)
{
- BIO *rbio = SSL_get_rbio(ssl),
- *wbio = SSL_get_wbio(ssl);
+ BIO *rbio, *wbio;
+
+ if (!APLOG_CS_IS_LEVEL(c, s, APLOG_TRACE4))
+ return;
+
+ rbio = SSL_get_rbio(ssl);
+ wbio = SSL_get_wbio(ssl);
if (rbio) {
set_bio_callback(rbio, ssl);
}
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index fa1b3a8..9c51021 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -2585,9 +2585,7 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s)
* (and the first vhost doesn't use APLOG_TRACE4), then
* we need to set that callback here.
*/
- if (APLOGtrace4(s)) {
- modssl_set_io_callbacks(ssl);
- }
+ modssl_set_io_callbacks(ssl, c, s);
return 1;
}
diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c
index 699019f..8a08ede 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;
@@ -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
@@ -826,21 +829,32 @@ static UI_METHOD *get_passphrase_ui(apr_pool_t *p)
}
#endif
+#if MODSSL_HAVE_ENGINE_API
+static apr_status_t modssl_engine_cleanup(void *engine)
+{
+ ENGINE *e = engine;
-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)
+ ENGINE_finish(e);
+
+ return APR_SUCCESS;
+}
+
+static apr_status_t modssl_load_keypair_engine(server_rec *s, apr_pool_t *pconf,
+ apr_pool_t *ptemp,
+ const char *vhostid,
+ const char *certid,
+ const char *keyid,
+ X509 **pubkey,
+ EVP_PKEY **privkey)
{
-#if MODSSL_HAVE_ENGINE_API
const char *c, *scheme;
ENGINE *e;
- UI_METHOD *ui_method = get_passphrase_ui(p);
+ UI_METHOD *ui_method = get_passphrase_ui(ptemp);
pphrase_cb_arg_t ppcb;
memset(&ppcb, 0, sizeof ppcb);
ppcb.s = s;
- ppcb.p = p;
+ ppcb.p = ptemp;
ppcb.bPassPhraseDialogOnce = TRUE;
ppcb.key_id = vhostid;
ppcb.pkey_file = keyid;
@@ -853,7 +867,7 @@ apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
return ssl_die(s);
}
- scheme = apr_pstrmemdup(p, keyid, c - keyid);
+ scheme = apr_pstrmemdup(ptemp, keyid, c - keyid);
if (!(e = ENGINE_by_id(scheme))) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10132)
"Init: Failed to load engine for private key %s",
@@ -902,11 +916,136 @@ apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
return ssl_die(s);
}
- ENGINE_finish(e);
+ /* Release the functional reference obtained by ENGINE_init() only
+ * when after the ENGINE is no longer used. */
+ apr_pool_cleanup_register(pconf, e, modssl_engine_cleanup, modssl_engine_cleanup);
+
+ /* Release the structural reference obtained by ENGINE_by_id()
+ * immediately. */
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 *pconf, apr_pool_t *ptemp,
+ const char *vhostid,
+ const char *certid, const char *keyid,
+ X509 **pubkey, EVP_PKEY **privkey)
+{
+#if MODSSL_HAVE_ENGINE_API
+ SSLModConfigRec *mc = myModConfig(s);
+
+ /* For OpenSSL 3.x, use the STORE-based API if either ENGINE
+ * support was not present compile-time, or if it's built but
+ * SSLCryptoDevice is not configured. */
+ if (mc->szCryptoDevice)
+ return modssl_load_keypair_engine(s, pconf, ptemp,
+ vhostid, certid, keyid,
+ pubkey, privkey);
+#endif
+#if MODSSL_HAVE_OPENSSL_STORE
+ return modssl_load_keypair_store(s, ptemp, vhostid, certid, keyid,
+ pubkey, privkey);
#else
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10496)
+ "Init: no method for loading keypair for %s (%s | %s)",
+ vhostid, certid ? certid : "no cert", keyid);
return APR_ENOTIMPL;
#endif
}
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index 25d79ce..c517a7b 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
@@ -1049,7 +1058,7 @@ void modssl_callback_keylog(const SSL *ssl, const char *line);
/** I/O */
void ssl_io_filter_init(conn_rec *, request_rec *r, SSL *);
void ssl_io_filter_register(apr_pool_t *);
-void modssl_set_io_callbacks(SSL *ssl);
+void modssl_set_io_callbacks(SSL *ssl, conn_rec *c, server_rec *s);
/* ssl_io_buffer_fill fills the setaside buffering of the HTTP request
* to allow an SSL renegotiation to take place. */
@@ -1081,7 +1090,8 @@ apr_status_t ssl_load_encrypted_pkey(server_rec *, apr_pool_t *, int,
/* Load public and/or private key from the configured ENGINE. Private
* key returned as *pkey. certid can be NULL, in which case *pubkey
* is not altered. Errors logged on failure. */
-apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p,
+apr_status_t modssl_load_engine_keypair(server_rec *s,
+ apr_pool_t *pconf, apr_pool_t *ptemp,
const char *vhostid,
const char *certid, const char *keyid,
X509 **pubkey, EVP_PKEY **privkey);
diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c
index 87ddfa7..7473edb 100644
--- a/modules/ssl/ssl_util.c
+++ b/modules/ssl/ssl_util.c
@@ -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