diff options
Diffstat (limited to 'modules/ssl')
-rw-r--r-- | modules/ssl/ssl_engine_init.c | 13 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_io.c | 82 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_kernel.c | 4 | ||||
-rw-r--r-- | modules/ssl/ssl_engine_pphrase.c | 159 | ||||
-rw-r--r-- | modules/ssl/ssl_private.h | 14 | ||||
-rw-r--r-- | modules/ssl/ssl_util.c | 2 |
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 |