diff --git a/CHANGES b/CHANGES index 1b7ada49993..93cde76456a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.1 + *) mod_ssl: Add support for OpenSSL providers across all certificates, + CA certificates, CRLs and keys. [Graham Leggett] + *) mod_proxy_beacon: Back-end reverse proxy servers can announce themselves and be auto-added to their front-end proxy balancer. [Jim Jagielski] diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number index f847eee1e1f..77ed9b0d16d 100644 --- a/docs/log-message-tags/next-number +++ b/docs/log-message-tags/next-number @@ -1 +1 @@ -10599 +10617 diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index 8f79d0a8bc0..20d3db1a0d5 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -110,6 +110,9 @@ static const command_rec ssl_config_cmds[] = { SSL_CMD_ALL(CipherSuite, TAKE12, "Colon-delimited list of permitted SSL Ciphers, optional preceded " "by protocol identifier ('XXX:...:XXX' - see manual)") + SSL_CMD_SRV(CertificateURI, TAKE1, + "SSL Server Certificate/Key uri " + "('file:', 'pkcs11:' - URI of certificate or key)") SSL_CMD_SRV(CertificateFile, TAKE1, "SSL Server Certificate file " "('/path/to/file' - PEM or DER encoded)") @@ -129,6 +132,9 @@ static const command_rec ssl_config_cmds[] = { "TLS ECH Key Directory" "('/path/to/dir' - directory with ECH key pairs)") #endif + SSL_CMD_SRV(CACertificateURI, TAKE1, + "SSL CA Certificate uri " + "('file:', 'pkcs11:' - URI of CA certificates)") SSL_CMD_ALL(CACertificatePath, TAKE1, "SSL CA Certificate path " "('/path/to/dir' - contains PEM encoded files)") @@ -141,6 +147,9 @@ static const command_rec ssl_config_cmds[] = { SSL_CMD_SRV(CADNRequestFile, TAKE1, "SSL CA Distinguished Name file " "('/path/to/file' - PEM encoded to derive acceptable CA names to request)") + SSL_CMD_SRV(CARevocationURI, TAKE1, + "SSL CA Certificate Revocation List (CRL) uri " + "('file:', 'pkcs11:' - URI of CRLs)") SSL_CMD_SRV(CARevocationPath, TAKE1, "SSL CA Certificate Revocation List (CRL) path " "('/path/to/dir' - contains PEM encoded files)") @@ -216,12 +225,18 @@ static const command_rec ssl_config_cmds[] = { SSL_CMD_PXY(ProxyVerifyDepth, TAKE1, "SSL Proxy: maximum certificate verification depth " "('N' - number of intermediate certificates)") + SSL_CMD_PXY(ProxyCACertificateURI, TAKE1, + "SSL Proxy: uri referring to server certificates " + "('file:', 'pkcs11:' - URI of CA certificates)") SSL_CMD_PXY(ProxyCACertificateFile, TAKE1, "SSL Proxy: file containing server certificates " "('/path/to/file' - PEM encoded certificates)") SSL_CMD_PXY(ProxyCACertificatePath, TAKE1, "SSL Proxy: directory containing server certificates " "('/path/to/dir' - contains PEM encoded certificates)") + SSL_CMD_PXY(ProxyCARevocationURI, TAKE1, + "SSL Proxy: CA Certificate Revocation List (CRL) uri " + "('file:', 'pkcs11:' - URI of CRLs)") SSL_CMD_PXY(ProxyCARevocationPath, TAKE1, "SSL Proxy: CA Certificate Revocation List (CRL) path " "('/path/to/dir' - contains PEM encoded files)") @@ -230,6 +245,9 @@ static const command_rec ssl_config_cmds[] = { "('/path/to/file' - PEM encoded)") SSL_CMD_PXY(ProxyCARevocationCheck, RAW_ARGS, "SSL Proxy: CA Certificate Revocation List (CRL) checking mode") + SSL_CMD_PXY(ProxyMachineCertificateURI, TAKE1, + "SSL Proxy: uri referring to client certificates " + "('file:', 'pkcs11:' - URI of certificate or key)") SSL_CMD_PXY(ProxyMachineCertificateFile, TAKE1, "SSL Proxy: file containing client certificates " "('/path/to/file' - PEM encoded certificates)") diff --git a/modules/ssl/mod_ssl_openssl.h b/modules/ssl/mod_ssl_openssl.h index e251bd9b77a..fa345b4069e 100644 --- a/modules/ssl/mod_ssl_openssl.h +++ b/modules/ssl/mod_ssl_openssl.h @@ -33,6 +33,8 @@ #include #if OPENSSL_VERSION_NUMBER >= 0x30000000 #include /* for OPENSSL_API_LEVEL */ +#include /* for OSSL_STORE_open_ex */ +#include /* for UI_null */ #endif #if OPENSSL_VERSION_NUMBER >= 0x10001000 /* must be defined before including ssl.h */ diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index a38dd943e4c..af09a12b561 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -113,6 +113,7 @@ static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p) mctx->sc = NULL; /* set during module init */ mctx->ssl_ctx = NULL; /* set during module init */ + mctx->libctx = NULL; /* set during module init */ mctx->pks = NULL; mctx->pkp = NULL; @@ -131,8 +132,10 @@ static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p) mctx->crl_path = NULL; mctx->crl_file = NULL; + mctx->crl_uri = NULL; mctx->crl_check_mask = UNSET; + mctx->auth.ca_cert_uri = NULL; mctx->auth.ca_cert_path = NULL; mctx->auth.ca_cert_file = NULL; mctx->auth.cipher_suite = NULL; @@ -200,6 +203,7 @@ static void modssl_ctx_init_server(SSLSrvConfigRec *sc, mctx->pks = apr_pcalloc(p, sizeof(*mctx->pks)); + mctx->pks->uris = apr_array_make(p, 3, sizeof(char *)); mctx->pks->cert_files = apr_array_make(p, 3, sizeof(char *)); mctx->pks->key_files = apr_array_make(p, 3, sizeof(char *)); @@ -279,6 +283,7 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p, cfgMerge(crl_file, NULL); cfgMergeInt(crl_check_mask); + cfgMergeString(auth.ca_cert_uri); cfgMergeString(auth.ca_cert_path); cfgMergeString(auth.ca_cert_file); cfgMergeString(auth.cipher_suite); @@ -333,9 +338,11 @@ static void modssl_ctx_cfg_merge_server(apr_pool_t *p, { modssl_ctx_cfg_merge(p, base, add, mrg); + cfgMergeArray(pks->uris); cfgMergeArray(pks->cert_files); cfgMergeArray(pks->key_files); + cfgMergeString(pks->ca_name_uri); cfgMergeString(pks->ca_name_path); cfgMergeString(pks->ca_name_file); @@ -386,6 +393,7 @@ static void modssl_ctx_init_proxy(SSLDirConfigRec *dc, mctx->pkp = apr_palloc(p, sizeof(*mctx->pkp)); + mctx->pkp->uris = apr_array_make(p, 3, sizeof(char *)); mctx->pkp->cert_file = NULL; mctx->pkp->cert_path = NULL; mctx->pkp->ca_cert_file = NULL; @@ -429,6 +437,7 @@ static void modssl_ctx_cfg_merge_proxy(apr_pool_t *p, { modssl_ctx_cfg_merge(p, base, add, mrg); + cfgMergeArray(pkp->uris); cfgMergeString(pkp->cert_file); cfgMergeString(pkp->cert_path); cfgMergeString(pkp->ca_cert_file); @@ -962,6 +971,44 @@ static const char *ssl_cmd_check_file(cmd_parms *parms, } +static const char *ssl_cmd_check_uri(cmd_parms *parms, + const char *uri) +{ + OSSL_STORE_CTX *ctx; + unsigned long err; + int reason; + + /* If only dumping the config, don't verify the paths */ + if (ap_state_query(AP_SQ_RUN_MODE) == AP_SQ_RM_CONFIG_DUMP) { + return NULL; + } + + ctx = OSSL_STORE_open_ex(uri, NULL, NULL, UI_null(), + NULL, NULL, NULL, NULL); + + if (ctx) { + OSSL_STORE_close(ctx); + return NULL; + } + + err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_OSSL_STORE) { + reason = ERR_GET_REASON(err); + + if (reason == OSSL_STORE_R_UNREGISTERED_SCHEME) { + + return apr_pstrcat(parms->pool, parms->cmd->name, + ": uri '", uri, + "' is not recognised", NULL); + + } + } + + ERR_clear_error(); + + return NULL; +} + const char *ssl_cmd_SSLCompression(cmd_parms *cmd, void *dcfg, int flag) { #if !defined(OPENSSL_NO_COMP) @@ -1048,6 +1095,22 @@ static const char *ssl_cmd_check_dir(cmd_parms *parms, } +const char *ssl_cmd_SSLCertificateURI(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_uri(cmd, arg))) { + return err; + } + + *(const char **)apr_array_push(sc->server->pks->uris) = arg; + + return NULL; +} + const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) @@ -1121,6 +1184,28 @@ const char *ssl_cmd_SSLSessionTicketKeyFile(cmd_parms *cmd, #define NO_PER_DIR_SSL_CA \ "Your SSL library does not have support for per-directory CA" +const char *ssl_cmd_SSLCACertificateURI(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + /*SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg;*/ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_uri(cmd, arg))) { + return err; + } + + if (cmd->path) { + return NO_PER_DIR_SSL_CA; + } + + /* XXX: bring back per-dir */ + sc->server->auth.ca_cert_uri = arg; + + return NULL; +} + const char *ssl_cmd_SSLCACertificatePath(cmd_parms *cmd, void *dcfg, const char *arg) @@ -1165,6 +1250,21 @@ const char *ssl_cmd_SSLCACertificateFile(cmd_parms *cmd, return NULL; } +const char *ssl_cmd_SSLCADNRequestURI(cmd_parms *cmd, void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_uri(cmd, arg))) { + return err; + } + + sc->server->pks->ca_name_uri = arg; + + return NULL; +} + const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *cmd, void *dcfg, const char *arg) { @@ -1195,6 +1295,22 @@ const char *ssl_cmd_SSLCADNRequestFile(cmd_parms *cmd, void *dcfg, return NULL; } +const char *ssl_cmd_SSLCARevocationURI(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_uri(cmd, arg))) { + return err; + } + + sc->server->crl_uri = arg; + + return NULL; +} + const char *ssl_cmd_SSLCARevocationPath(cmd_parms *cmd, void *dcfg, const char *arg) @@ -1740,6 +1856,22 @@ const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *cmd, return NULL; } +const char *ssl_cmd_SSLProxyCACertificateURI(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + const char *err; + + if ((err = ssl_cmd_check_uri(cmd, arg))) { + return err; + } + + dc->proxy->auth.ca_cert_uri = arg; + + return NULL; +} + const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) @@ -1772,6 +1904,22 @@ const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *cmd, return NULL; } +const char *ssl_cmd_SSLProxyCARevocationURI(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + const char *err; + + if ((err = ssl_cmd_check_uri(cmd, arg))) { + return err; + } + + dc->proxy->crl_uri = arg; + + return NULL; +} + const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *cmd, void *dcfg, const char *arg) @@ -1813,6 +1961,22 @@ const char *ssl_cmd_SSLProxyCARevocationCheck(cmd_parms *cmd, return ssl_cmd_crlcheck_parse(cmd, arg, &dc->proxy->crl_check_mask); } +const char *ssl_cmd_SSLProxyMachineCertificateURI(cmd_parms *cmd, + void *dcfg, + const char *arg) +{ + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + const char *err; + + if ((err = ssl_cmd_check_uri(cmd, arg))) { + return err; + } + + *(const char **)apr_array_push(dc->proxy->pkp->uris) = arg; + + return NULL; +} + const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *cmd, void *dcfg, const char *arg) @@ -2293,7 +2457,7 @@ const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, /* OCSP Responder File Function to read in value */ const char *ssl_cmd_SSLOCSPResponderCertificateFile(cmd_parms *cmd, void *dcfg, - const char *arg) + const char *arg) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); const char *err; @@ -2332,6 +2496,14 @@ void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s) modssl_pk_server_t *const pks = sc->server->pks; int i; + for (i = 0; (i < pks->uris->nelts) && + APR_ARRAY_IDX(pks->uris, i, const char *); + i++) { + apr_file_printf(out, " %s\n", + APR_ARRAY_IDX(pks->uris, + i, const char *)); + } + for (i = 0; (i < pks->cert_files->nelts) && APR_ARRAY_IDX(pks->cert_files, i, const char *); i++) { @@ -2356,6 +2528,10 @@ void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s) SSLSrvConfigRec *sc = mySrvConfig(s); if (sc && sc->server) { + if (sc->server->auth.ca_cert_uri) { + apr_file_printf(out, " %s\n", + sc->server->auth.ca_cert_uri); + } if (sc->server->auth.ca_cert_path) { apr_file_printf(out, " %s\n", sc->server->auth.ca_cert_path); @@ -2623,6 +2799,7 @@ static void modssl_auth_ctx_dump(modssl_auth_ctx_t *auth, apr_pool_t *p, int pro #endif DMP_VERIFY(proxy? "SSLProxyVerify" : "SSLVerifyClient", auth->verify_mode); DMP_LONG( proxy? "SSLProxyVerify" : "SSLVerifyDepth", auth->verify_depth); + DMP_STRING(proxy? "SSLProxyCACertificateURI" : "SSLCACertificateURI", auth->ca_cert_uri); DMP_STRING(proxy? "SSLProxyCACertificateFile" : "SSLCACertificateFile", auth->ca_cert_file); DMP_STRING(proxy? "SSLProxyCACertificatePath" : "SSLCACertificatePath", auth->ca_cert_path); } @@ -2640,14 +2817,17 @@ static void modssl_ctx_dump(modssl_ctx_t *ctx, apr_pool_t *p, int proxy, modssl_auth_ctx_dump(&ctx->auth, p, proxy, out, indent, psep); + DMP_STRING(proxy? "SSLProxyCARevocationURI" : "SSLCARevocationURI", ctx->crl_uri); DMP_STRING(proxy? "SSLProxyCARevocationFile" : "SSLCARevocationFile", ctx->crl_file); DMP_STRING(proxy? "SSLProxyCARevocationPath" : "SSLCARevocationPath", ctx->crl_path); DMP_CRLCHK(proxy? "SSLProxyCARevocationCheck" : "SSLCARevocationCheck", ctx->crl_check_mask); if (!proxy) { DMP_PHRASE("SSLPassPhraseDialog", ctx->pphrase_dialog_type, ctx->pphrase_dialog_path); if (ctx->pks) { + DMP_STRING("SSLCADNRequestURI", ctx->pks->ca_name_uri); DMP_STRING("SSLCADNRequestFile", ctx->pks->ca_name_file); DMP_STRING("SSLCADNRequestPath", ctx->pks->ca_name_path); + DMP_STRARR("SSLCertificateURI", ctx->pks->uris); DMP_STRARR("SSLCertificateFile", ctx->pks->cert_files); DMP_STRARR("SSLCertificateKeyFile", ctx->pks->key_files); } @@ -2698,6 +2878,7 @@ static void modssl_ctx_dump(modssl_ctx_t *ctx, apr_pool_t *p, int proxy, } else { /* proxy */ if (ctx->pkp) { + DMP_STRARR("SSLProxyMachineCertificateURI", ctx->pkp->uris); DMP_STRING("SSLProxyMachineCertificateFile", ctx->pkp->cert_file); DMP_STRING("SSLProxyMachineCertificatePath", ctx->pkp->cert_path); DMP_STRING("SSLProxyMachineCertificateChainFile", ctx->pkp->ca_cert_file); diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index a557e940dd4..3fb308e234b 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -334,6 +334,7 @@ static void hash_sni_policy_pk(apr_pool_t *ptemp, apr_md5_ctx_t *hash, modssl_ct md5_ifstr_update(hash, "ciphers:", ctx->auth.cipher_suite); md5_ifstr_update(hash, "tls13_ciphers:", ctx->auth.tls13_ciphers); + md5_strarray_hash(ptemp, hash, "uris:", ctx->pks->uris); md5_strarray_hash(ptemp, hash, "cert_files:", ctx->pks->cert_files); md5_strarray_hash(ptemp, hash, "key_files:", ctx->pks->key_files); } @@ -346,10 +347,13 @@ static void hash_sni_policy_auth(apr_md5_ctx_t *hash, modssl_ctx_t *ctx) md5_fmt_update(hash, "verify_depth:%d", a->verify_depth); md5_fmt_update(hash, "verify_mode:%d", a->verify_mode); + md5_ifstr_update(hash, "ca_name_uri:", pks->ca_name_uri); md5_ifstr_update(hash, "ca_name_path:", pks->ca_name_path); md5_ifstr_update(hash, "ca_name_file:", pks->ca_name_file); + md5_ifstr_update(hash, "ca_cert_uri:", a->ca_cert_uri); md5_ifstr_update(hash, "ca_cert_path:", a->ca_cert_path); md5_ifstr_update(hash, "ca_cert_file:", a->ca_cert_file); + md5_ifstr_update(hash, "crl_uri:", ctx->crl_uri); md5_ifstr_update(hash, "crl_path:", ctx->crl_path); md5_ifstr_update(hash, "crl_file:", ctx->crl_file); md5_fmt_update(hash, "crl_check_mask:%d", ctx->crl_check_mask); @@ -848,7 +852,7 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s, #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20800000L) + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20800000L) /* * Enable/disable SSLProtocol. If the mod_ssl enables protocol * which is disabled by default by OpenSSL, show a warning. @@ -887,7 +891,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, int protocol = mctx->protocol; SSLSrvConfigRec *sc = mySrvConfig(s); #if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x20800000L) + (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x20800000L) /* default is highest supported version, will be overridden below */ #if SSL_HAVE_PROTOCOL_TLSV1_3 int prot = TLS1_3_VERSION; @@ -978,7 +982,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, SSL_CTX_set_options(ctx, SSL_OP_ALL); #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20800000L) + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20800000L) /* always disable SSLv2, as per RFC 6176 */ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); @@ -1222,6 +1226,103 @@ int modssl_CTX_load_verify_locations(SSL_CTX *ctx, return 1; } +/* + * OpenSSL has a SSL_CTX_load_verify_store() function, but + * this function loads both leaf certs and CA certs. + * + * An end user reasonably wants to configure a URI pointing at + * CA certs and not have any surprises if the scope of the URI + * included leaf certificates. + * + * As a result we consider CA certs exclusively below. + */ + +static APR_INLINE +apr_status_t modssl_CTX_load_verify_store(server_rec *s, + apr_pool_t *ptemp, + const char *uri, + int depth, + modssl_ctx_t *mctx) +{ +#if MODSSL_HAVE_OPENSSL_STORE + OSSL_STORE_CTX *sctx; + OSSL_STORE_INFO *info; + + apr_status_t rv = APR_SUCCESS; + + X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx); + + ap_assert(store != NULL); /* safe to assume always non-NULL? */ + + if (!uri) { + return APR_SUCCESS; + } + + if ((!(sctx = OSSL_STORE_open_ex(uri, mctx->libctx, NULL, NULL, NULL, + NULL, NULL, NULL)))) { + return APR_EGENERAL; + } + + while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) { + + if (!(info = OSSL_STORE_load(sctx))) { + continue; + } + + switch(OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_NAME: { + + if (depth > 0) { + rv = modssl_CTX_load_verify_store(s, ptemp, + OSSL_STORE_INFO_get0_NAME(info), + depth - 1, mctx); + if (APR_SUCCESS != rv) { + OSSL_STORE_close(sctx); + return rv; + } + } + + break; + } + case OSSL_STORE_INFO_CERT: { + + X509 *cert; + + if (!(cert = OSSL_STORE_INFO_get0_CERT(info))) { + return APR_EGENERAL; + } + else if (!X509_check_ca(cert)) { + /* ignore leaf certificates */ + continue; + } + if (X509_STORE_add_cert(store, cert)) { + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10599) + "Host %s: Trusted certificate from URI: %s", + mctx->sc->vhost_id, + modssl_X509_NAME_to_string(ptemp, + X509_get_subject_name(cert), 0)); + + } + + break; + } + } + } + + OSSL_STORE_close(sctx); + + return rv; +#else + if (!uri) { + return APR_SUCCESS; + } + + return APR_ENOTIMPL; +#endif +} + + static apr_status_t ssl_init_ctx_verify(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, @@ -1258,10 +1359,24 @@ static apr_status_t ssl_init_ctx_verify(server_rec *s, /* * Configure Client Authentication details */ - if (mctx->auth.ca_cert_file || mctx->auth.ca_cert_path) { + + if (mctx->auth.ca_cert_file || mctx->auth.ca_cert_path || + mctx->auth.ca_cert_uri) { + + apr_status_t rv; + ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "Configuring client authentication"); + if ((rv = modssl_CTX_load_verify_store(s, ptemp, + mctx->auth.ca_cert_uri, 1, mctx)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(10600) + "Unable to configure verify store " + "for client authentication"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return ssl_die(s); + } + if (!modssl_CTX_load_verify_locations(ctx, mctx->auth.ca_cert_file, mctx->auth.ca_cert_path)) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01895) @@ -1271,22 +1386,32 @@ static apr_status_t ssl_init_ctx_verify(server_rec *s, return ssl_die(s); } - if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path)) { + if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path || + mctx->pks->ca_name_uri)) { ca_list = ssl_init_FindCAList(s, ptemp, - mctx->pks->ca_name_file, - mctx->pks->ca_name_path); - } else + mctx->pks->ca_name_file, + mctx->pks->ca_name_path, + mctx->pks->ca_name_uri, + mctx); + + } else { ca_list = ssl_init_FindCAList(s, ptemp, - mctx->auth.ca_cert_file, - mctx->auth.ca_cert_path); + mctx->auth.ca_cert_file, + mctx->auth.ca_cert_path, + mctx->auth.ca_cert_uri, + mctx); + } + if (sk_X509_NAME_num(ca_list) <= 0) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01896) "Unable to determine list of acceptable " "CA certificates for client authentication"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); return ssl_die(s); } SSL_CTX_set_client_CA_list(ctx, ca_list); + } /* @@ -1354,17 +1479,113 @@ int modssl_X509_STORE_load_locations(X509_STORE *store, const char *path) { #if OPENSSL_VERSION_NUMBER < 0x30000000L - if (!X509_STORE_load_locations(store, file, path)) + if (!X509_STORE_load_locations(store, file, path)) { return 0; + } #else - if (file && !X509_STORE_load_file(store, file)) + if (file && !X509_STORE_load_file(store, file)) { return 0; - if (path && !X509_STORE_load_path(store, path)) + } + if (path && !X509_STORE_load_path(store, path)) { return 0; + } #endif return 1; } +/* + * OpenSSL has a X509_STORE_load_store() function, but this + * function has side effects - it loads both CRLs and trusted + * CA certificates. + * + * An end user reasonably wants to configure a URI pointing at + * CRLs and not have any surprises if the scope of the URI + * included trusted CA certificates for whatever reason. + * + * As a result we consider CRLs exclusively below. + */ + +static APR_INLINE +apr_status_t modssl_X509_STORE_load_crl(server_rec *s, + apr_pool_t *ptemp, + const char *uri, + int depth, + modssl_ctx_t *mctx) +{ +#if MODSSL_HAVE_OPENSSL_STORE + OSSL_STORE_CTX *sctx; + OSSL_STORE_INFO *info; + + apr_status_t rv = APR_SUCCESS; + + X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx); + + ap_assert(store != NULL); /* safe to assume always non-NULL? */ + + if (!uri) { + return APR_SUCCESS; + } + + if ((!(sctx = OSSL_STORE_open_ex(uri, mctx->libctx, NULL, NULL, NULL, + NULL, NULL, NULL)))) { + return APR_EGENERAL; + } + + while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) { + + if (!(info = OSSL_STORE_load(sctx))) { + continue; + } + + switch(OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_NAME: { + + if (depth > 0) { + rv = modssl_X509_STORE_load_crl(s, ptemp, + OSSL_STORE_INFO_get0_NAME(info), + depth - 1, mctx); + if (APR_SUCCESS != rv) { + OSSL_STORE_close(sctx); + return rv; + } + } + + break; + } + case OSSL_STORE_INFO_CRL: { + + X509_CRL *crl; + + if (!(crl = OSSL_STORE_INFO_get0_CRL(info))) { + return APR_EGENERAL; + } + if (X509_STORE_add_crl(store, crl)) { + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10601) + "Host %s: Certificate revocation list from URI: %s", + mctx->sc->vhost_id, + modssl_X509_NAME_to_string(ptemp, + X509_CRL_get_issuer(crl), 0)); + + } + + break; + } + } + } + + OSSL_STORE_close(sctx); + + return rv; +#else + if (!uri) { + return APR_SUCCESS; + } + + return APR_ENOTIMPL; +#endif +} + static apr_status_t ssl_init_ctx_crl(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, @@ -1374,6 +1595,9 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s, unsigned long crlflags = 0; char *cfgp = mctx->pkp ? "SSLProxy" : "SSL"; int crl_check_mode; + apr_status_t rv; + + ap_assert(store != NULL); /* safe to assume always non-NULL? */ if (mctx->ocsp_mask == UNSET) { mctx->ocsp_mask = SSL_OCSPCHECK_NONE; @@ -1388,13 +1612,13 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s, * Configure Certificate Revocation List (CRL) Details */ - if (!(mctx->crl_file || mctx->crl_path)) { + if (!(mctx->crl_uri || mctx->crl_file || mctx->crl_path)) { if (crl_check_mode == SSL_CRLCHECK_LEAF || crl_check_mode == SSL_CRLCHECK_CHAIN) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01899) "Host %s: CRL checking has been enabled, but " - "neither %sCARevocationFile nor %sCARevocationPath " - "is configured", mctx->sc->vhost_id, cfgp, cfgp); + "neither %sCARevocationURI, %sCARevocationFile nor %sCARevocationPath " + "is configured", mctx->sc->vhost_id, cfgp, cfgp, cfgp); return ssl_die(s); } return APR_SUCCESS; @@ -1403,8 +1627,16 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01900) "Configuring certificate revocation facility"); - if (!store || !modssl_X509_STORE_load_locations(store, mctx->crl_file, - mctx->crl_path)) { + if ((rv = modssl_X509_STORE_load_crl(s, ptemp, mctx->crl_uri, 1, mctx)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(10602) + "Host %s: unable to configure X.509 CRL uri " + "for certificate revocation", mctx->sc->vhost_id); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return ssl_die(s); + } + + if (!modssl_X509_STORE_load_locations(store, + mctx->crl_file, mctx->crl_path)) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01901) "Host %s: unable to configure X.509 CRL storage " "for certificate revocation", mctx->sc->vhost_id); @@ -1636,6 +1868,386 @@ static int ssl_no_passwd_prompt_cb(char *buf, int size, int rwflag, return 0; } + +#ifndef DEFINE_STACK_OF_EVP_PKEY +DEFINE_STACK_OF(EVP_PKEY) +#endif + +#if MODSSL_HAVE_OPENSSL_STORE + +static apr_status_t ssl_init_uri_cleanup(void *data) +{ + modssl_ctx_uri_t *uctx = (modssl_ctx_uri_t *)data; + + sk_X509_pop_free(uctx->cert_list, X509_free); + sk_EVP_PKEY_pop_free(uctx->key_list, EVP_PKEY_free); + sk_X509_pop_free(uctx->ca_list, X509_free); + + return APR_SUCCESS; +} + +/* + * Sort certificates oldest to newest (last one wins). + */ +static int compare_certs_asc(const X509 *const *a, const X509 *const *b) +{ + const ASN1_TIME *time_a = X509_get0_notBefore(*a); + const ASN1_TIME *time_b = X509_get0_notBefore(*b); + + /* ASN1_TIME_compare returns: + * -1 if time_a is earlier than time_b + * 0 if they are identical + * 1 if time_a is later than time_b + */ + return ASN1_TIME_compare(time_a, time_b); +} + +static int cert_match(apr_pool_t *p, X509 *cert, char *id) +{ + if (id[0] == '[') { + const char *end = strchr(id, ']'); + if (end && X509_check_ip_asc(cert, + apr_pstrndup(p, id + 1, end - id - 1), 0) == 1) { + return 1; + } + return 0; + } + if (X509_check_ip_asc(cert, id, 0) == 1) { + return 1; + } + if (X509_check_host(cert, id, 0, 0, NULL) == 1) { + return 1; + } + return 0; +} + +static apr_status_t ssl_init_uri(server_rec *s, + apr_pool_t *ptemp, + const char *uri, + int depth, + modssl_ctx_uri_t *uctx) +{ + OSSL_STORE_CTX *sctx; + OSSL_STORE_INFO *info; + + apr_status_t rv = APR_SUCCESS; + + if (!uri) { + return rv; + } + + if ((!(sctx = OSSL_STORE_open_ex(uri, uctx->mctx->libctx, NULL, + modssl_get_passphrase_ui(ptemp), + modssl_get_passphrase_cb(s, ptemp, + uctx->mctx->sc->vhost_id, uri), + NULL, NULL, NULL)))) { + return APR_EGENERAL; + } + + while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) { + + if (!(info = OSSL_STORE_load(sctx))) { + continue; + } + + switch(OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_NAME: { + + if (depth > 0) { + rv = ssl_init_uri(s, ptemp, + OSSL_STORE_INFO_get0_NAME(info), + depth - 1, uctx); + if (APR_SUCCESS != rv) { + OSSL_STORE_close(sctx); + return rv; + } + } + + break; + } + case OSSL_STORE_INFO_CERT: { + + X509 *cert; + + if (!(cert = OSSL_STORE_INFO_get1_CERT(info))) { + return APR_EGENERAL; + } + else if (X509_check_ca(cert)) { + + if (X509_self_signed(cert, 1)) { + + uctx->num_ca_certs++; + + /* ignore root certificates */ + X509_free(cert); + continue; + } + + if (sk_X509_push(uctx->ca_list, cert) <= 0) { + X509_free(cert); + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + + uctx->num_intermediate_certs++; + + } + else { + + uctx->num_leaf_certs++; + + if (!X509_check_purpose(cert, X509_PURPOSE_SSL_SERVER, 0)) { + /* ignore non server certs */ + X509_free(cert); + continue; + } + + /* check for a match on server name */ + if (s->server_hostname) { + if (!cert_match(ptemp, cert, s->server_hostname)) { + X509_free(cert); + continue; + } + } + + /* check for a match on all server aliases */ + if (s->names && !apr_is_empty_array(s->names)) { + char **aliases = (char **)s->names->elts; + int i; + for (i = 0; i < s->names->nelts; i++) { + if (!cert_match(ptemp, cert, aliases[i])) { + X509_free(cert); + continue; + } + } + } + + /* If we get here and a server name or server alias was + * not specified, we use the most recently issued leaf + * certificate in scope and assume the admin knows what + * they are doing. + */ + + if (sk_X509_push(uctx->cert_list, cert) <= 0) { + X509_free(cert); + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + + uctx->num_server_certs++; + + } + + uctx->num_certs++; + + break; + } + case OSSL_STORE_INFO_PKEY: { + + EVP_PKEY *key; + + if (!(key = OSSL_STORE_INFO_get1_PKEY(info))) { + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + if (sk_EVP_PKEY_push(uctx->key_list, key) <= 0) { + EVP_PKEY_free(key); + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + + uctx->num_keys++; + + break; + } + } + } + + OSSL_STORE_close(sctx); + + return rv; +} + + +/* + * Load certs from all URIs. + * + * The end user might point their URI at a single set of + * PEM encoded certs using the file: scheme, or might point + * the URI at pkcs11: or the whole MacOS keychain and + * expect us to figure it out for them. Lets help as much + * as possible. + * + * - Load all certs across all uris. + * - Consider intermediate certs, add them to the store + * - Consider leaf certs that match the ServerName and + * ServerAliases and drop if no match. + * - Sort certs by start date, oldest to newest + * - Load all keys across all uris. + * - Consider certs with a private key, drop the rest. + * - Pass each cert and key, in order, using + * SSL_CTX_use_certificate and SSL_CTX_use_PrivateKey. + * - End result, the most recent cert for each type (RSA, + * ECDSA, etc) wins. + * + */ + +static apr_status_t ssl_init_server_uris(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx, + apr_array_header_t *pphrases) +{ + const char *uri; + int i, k; + int found = 0; + apr_status_t rv = APR_SUCCESS; + + modssl_ctx_uri_t *uctx = apr_pcalloc(ptemp, sizeof(modssl_ctx_uri_t)); + + uctx->mctx = mctx; + + uctx->cert_list = sk_X509_new_null(); + uctx->key_list = sk_EVP_PKEY_new_null(); + uctx->ca_list = sk_X509_new_null(); + + apr_pool_cleanup_register(ptemp, uctx, + ssl_init_uri_cleanup, + apr_pool_cleanup_null); + + sk_X509_set_cmp_func(uctx->cert_list, compare_certs_asc); + + /* no OpenSSL default prompts for any of the SSL_CTX_use_* calls, please */ + SSL_CTX_set_default_passwd_cb(mctx->ssl_ctx, ssl_no_passwd_prompt_cb); + + /* Iterate over the SSLCertificateURI array */ + for (i = 0; (i < mctx->pks->uris->nelts) && + (uri = APR_ARRAY_IDX(mctx->pks->uris, i, + const char *)); + i++) { + + if (ssl_init_uri(s, ptemp, uri, 1, uctx) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10603) + "Host %s: Failed to open URI `%s'", + mctx->sc->vhost_id, uri); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return APR_EGENERAL; + } + + } + + /* oldest to newest, last one wins */ + sk_X509_sort(uctx->cert_list); + + /* Match certs to keys */ + for (i = sk_X509_num(uctx->cert_list) - 1; i >= 0; i--) { + X509 *cert = sk_X509_value(uctx->cert_list, i); + + for (k = 0; k < sk_EVP_PKEY_num(uctx->key_list); k++) { + EVP_PKEY *pkey = sk_EVP_PKEY_value(uctx->key_list, k); + + if (X509_check_private_key(cert, pkey) == 1) { + + if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) < 1) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10604) + "Host %s: Failed to use certificate: %s", + mctx->sc->vhost_id, + modssl_X509_NAME_to_string(ptemp, + X509_get_subject_name(cert), 0)); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return APR_EGENERAL; + } + + if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10605) + "Host %s: Failed to use private key: %s", + mctx->sc->vhost_id, + modssl_X509_NAME_to_string(ptemp, + X509_get_subject_name(cert), 0)); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return APR_EGENERAL; + } + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10606) + "Host %s: Server certificate from URI: %s", + mctx->sc->vhost_id, + modssl_X509_NAME_to_string(ptemp, + X509_get_subject_name(cert), 0)); + + found = 1; + break; + } + + } + } + + if (!found) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10607) + "Host %s: No matching certificate/key pairs found among " + "%d certs, %d CA certs, %d intermediate certs, " + "%d leaf certs, %d server certs, %d keys.", + mctx->sc->vhost_id, + uctx->num_certs, uctx->num_ca_certs, uctx->num_intermediate_certs, + uctx->num_leaf_certs, + uctx->num_server_certs, uctx->num_keys); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return APR_EGENERAL; + } + + /* Handle intermediates, must happen after cert handling */ + for (i = sk_X509_num(uctx->ca_list) - 1; i >= 0; i--) { + X509 *cert = sk_X509_value(uctx->ca_list, i); + if (!SSL_CTX_add1_chain_cert(mctx->ssl_ctx, cert)) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10608) + "Host %s: Failed to add intermediate certificate: %s", + mctx->sc->vhost_id, + modssl_X509_NAME_to_string(ptemp, + X509_get_subject_name(cert), 0)); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return APR_EGENERAL; + } + } + + /* + * Do our best to build as much of the chain as possible with + * the certs we were provided. + */ + + if (!SSL_CTX_build_cert_chain(mctx->ssl_ctx, SSL_BUILD_CHAIN_FLAG_NO_ROOT | + SSL_BUILD_CHAIN_FLAG_UNTRUSTED | + SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR | + SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR)) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10609) + "Host %s: Could not build the certificate chain from " + "%d certs, %d CA certs, %d intermediate certs, " + "%d leaf certs, %d server certs, %d keys.", + mctx->sc->vhost_id, + uctx->num_certs, uctx->num_ca_certs, uctx->num_intermediate_certs, + uctx->num_leaf_certs, + uctx->num_server_certs, uctx->num_keys); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return APR_EGENERAL; + } + + return rv; +} +#else +static apr_status_t ssl_init_server_uris(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx, + apr_array_header_t *pphrases) +{ + const char *vhost_id = mctx->sc->vhost_id; + + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10610) + "Host %s: Server certificate URIs are not supported on this platform.", + mctx->sc->vhost_id); + + return APR_ENOTIMPL; +} +#endif + /* SSL_CTX_use_PrivateKey_file() can fail either because the private * key was encrypted, or due to a mismatch between an already-loaded * cert and the key - a common misconfiguration - from calling @@ -1896,106 +2508,395 @@ static apr_status_t ssl_init_server_certs(server_rec *s, if (!SSL_CTX_set1_curves(mctx->ssl_ctx, &curve_nid, 1)) { curve_nid = 0; } -#endif - if (curve_nid) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541) - "ECDH curve %s for %s specified in %s", - OBJ_nid2sn(curve_nid), vhost_id, certfile); +#endif + if (curve_nid) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541) + "ECDH curve %s for %s specified in %s", + OBJ_nid2sn(curve_nid), vhost_id, certfile); + } + } + /* + * ...otherwise, enable auto curve selection (OpenSSL 1.0.2) + * or configure NIST P-256 (required to enable ECDHE for earlier versions) + * ECDH is always enabled in 1.1.0 unless excluded from SSLCipherList + */ +#if MODSSL_USE_OPENSSL_PRE_1_1_API + if (!curve_nid) { +#if defined(SSL_CTX_set_ecdh_auto) + SSL_CTX_set_ecdh_auto(mctx->ssl_ctx, 1); +#else + EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (eckey) { + SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey); + EC_KEY_free(eckey); + } +#endif + } +#endif + /* OpenSSL assures us that _free() is NULL-safe */ + EC_GROUP_free(ecgroup); +#endif + + return APR_SUCCESS; +} + +#ifdef HAVE_TLS_SESSION_TICKETS +static apr_status_t ssl_init_ticket_key(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + apr_status_t rv; + apr_file_t *fp; + apr_size_t len; + char buf[TLSEXT_TICKET_KEY_LEN]; + char *path; + modssl_ticket_key_t *ticket_key = mctx->ticket_key; + int res; + + if (!ticket_key->file_path) { + return APR_SUCCESS; + } + + path = ap_server_root_relative(p, ticket_key->file_path); + + rv = apr_file_open(&fp, path, APR_READ|APR_BINARY, + APR_OS_DEFAULT, ptemp); + + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02286) + "Failed to open ticket key file %s: (%d) %pm", + path, rv, &rv); + return ssl_die(s); + } + + rv = apr_file_read_full(fp, &buf[0], TLSEXT_TICKET_KEY_LEN, &len); + + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02287) + "Failed to read %d bytes from %s: (%d) %pm", + TLSEXT_TICKET_KEY_LEN, path, rv, &rv); + return ssl_die(s); + } + + memcpy(ticket_key->key_name, buf, 16); + memcpy(ticket_key->aes_key, buf + 32, 16); +#if OPENSSL_VERSION_NUMBER < 0x30000000L + memcpy(ticket_key->hmac_secret, buf + 16, 16); + res = SSL_CTX_set_tlsext_ticket_key_cb(mctx->ssl_ctx, + ssl_callback_SessionTicket); +#else + ticket_key->mac_params[0] = + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, + apr_pmemdup(p, buf + 16, 16), 16); + ticket_key->mac_params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, "sha256", 0); + ticket_key->mac_params[2] = + OSSL_PARAM_construct_end(); + res = SSL_CTX_set_tlsext_ticket_key_evp_cb(mctx->ssl_ctx, + ssl_callback_SessionTicket); +#endif + OPENSSL_cleanse(buf, sizeof(buf)); + if (!res) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01913) + "Unable to initialize TLS session ticket key callback " + "(incompatible OpenSSL version?)"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return ssl_die(s); + } + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02288) + "TLS session ticket key for %s successfully loaded from %s", + (mySrvConfig(s))->vhost_id, path); + + return APR_SUCCESS; +} +#endif + +#if MODSSL_HAVE_OPENSSL_STORE + +/* + * Sort certificates newest to oldest (first one wins). + */ +static int compare_certs_desc(const X509 *const *a, const X509 *const *b) +{ + const ASN1_TIME *time_a = X509_get0_notBefore(*a); + const ASN1_TIME *time_b = X509_get0_notBefore(*b); + + /* ASN1_TIME_compare returns: + * -1 if time_a is earlier than time_b + * 0 if they are identical + * 1 if time_a is later than time_b + */ + return -ASN1_TIME_compare(time_a, time_b); +} + +static apr_status_t ssl_init_proxy_uri(server_rec *s, + apr_pool_t *ptemp, + const char *uri, + int depth, + modssl_ctx_uri_t *uctx) +{ + OSSL_STORE_CTX *sctx; + OSSL_STORE_INFO *info; + + apr_status_t rv = APR_SUCCESS; + + if (!uri) { + return rv; + } + + if ((!(sctx = OSSL_STORE_open_ex(uri, uctx->mctx->libctx, NULL, + modssl_get_passphrase_ui(ptemp), + modssl_get_passphrase_cb(s, ptemp, + uctx->mctx->sc->vhost_id, uri), + NULL, NULL, NULL)))) { + return APR_EGENERAL; + } + + while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) { + + if (!(info = OSSL_STORE_load(sctx))) { + continue; + } + + switch(OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_NAME: { + + if (depth > 0) { + rv = ssl_init_uri(s, ptemp, + OSSL_STORE_INFO_get0_NAME(info), + depth - 1, uctx); + if (APR_SUCCESS != rv) { + OSSL_STORE_close(sctx); + return rv; + } + } + + break; + } + case OSSL_STORE_INFO_CERT: { + + X509 *cert; + + if (!(cert = OSSL_STORE_INFO_get1_CERT(info))) { + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + else if (X509_check_ca(cert)) { + + if (X509_self_signed(cert, 1)) { + + uctx->num_ca_certs++; + + /* ignore root certificates */ + X509_free(cert); + break; + } + + if (sk_X509_push(uctx->ca_list, cert) <= 0) { + X509_free(cert); + return APR_EGENERAL; + } + + uctx->num_intermediate_certs++; + + } + else { + + uctx->num_leaf_certs++; + + if (!X509_check_purpose(cert, X509_PURPOSE_SSL_CLIENT, 0)) { + /* ignore non client certs */ + X509_free(cert); + break; + } + + if (sk_X509_push(uctx->cert_list, cert) <= 0) { + X509_free(cert); + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + + uctx->num_client_certs++; + + } + + uctx->num_certs++; + + break; + } + case OSSL_STORE_INFO_PKEY: { + + EVP_PKEY *key; + + if (!(key = OSSL_STORE_INFO_get1_PKEY(info))) { + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + if (sk_EVP_PKEY_push(uctx->key_list, key) <= 0) { + EVP_PKEY_free(key); + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + + uctx->num_keys++; + + break; } - } - /* - * ...otherwise, enable auto curve selection (OpenSSL 1.0.2) - * or configure NIST P-256 (required to enable ECDHE for earlier versions) - * ECDH is always enabled in 1.1.0 unless excluded from SSLCipherList - */ -#if MODSSL_USE_OPENSSL_PRE_1_1_API - if (!curve_nid) { -#if defined(SSL_CTX_set_ecdh_auto) - SSL_CTX_set_ecdh_auto(mctx->ssl_ctx, 1); -#else - EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - if (eckey) { - SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey); - EC_KEY_free(eckey); } -#endif } -#endif - /* OpenSSL assures us that _free() is NULL-safe */ - EC_GROUP_free(ecgroup); -#endif - return APR_SUCCESS; + OSSL_STORE_close(sctx); + + return rv; } -#ifdef HAVE_TLS_SESSION_TICKETS -static apr_status_t ssl_init_ticket_key(server_rec *s, +static apr_status_t ssl_init_proxy_uris(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, modssl_ctx_t *mctx) { - apr_status_t rv; - apr_file_t *fp; - apr_size_t len; - char buf[TLSEXT_TICKET_KEY_LEN]; - char *path; - modssl_ticket_key_t *ticket_key = mctx->ticket_key; - int res; + const char *uri; + modssl_pk_proxy_t *pkp = mctx->pkp; + modssl_ctx_uri_t *uctx; + STACK_OF(X509_INFO) *sk; - if (!ticket_key->file_path) { + int i, k; + int found = 0; + apr_status_t rv = APR_SUCCESS; + + X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx); + + ap_assert(store != NULL); /* safe to assume always non-NULL? */ + + if (!pkp->uris->nelts) { return APR_SUCCESS; } - path = ap_server_root_relative(p, ticket_key->file_path); + SSL_CTX_set_post_handshake_auth(mctx->ssl_ctx, 1); - rv = apr_file_open(&fp, path, APR_READ|APR_BINARY, - APR_OS_DEFAULT, ptemp); + SSL_CTX_set_client_cert_cb(mctx->ssl_ctx, + ssl_callback_proxy_cert); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02286) - "Failed to open ticket key file %s: (%d) %pm", - path, rv, &rv); - return ssl_die(s); + sk = pkp->certs; + if (!sk) { + pkp->certs = sk = sk_X509_INFO_new_null(); } - rv = apr_file_read_full(fp, &buf[0], TLSEXT_TICKET_KEY_LEN, &len); + uctx = apr_pcalloc(ptemp, sizeof(modssl_ctx_uri_t)); + + uctx->mctx = mctx; + + uctx->cert_list = sk_X509_new_null(); + uctx->key_list = sk_EVP_PKEY_new_null(); + uctx->ca_list = sk_X509_new_null(); + + apr_pool_cleanup_register(ptemp, uctx, + ssl_init_uri_cleanup, + apr_pool_cleanup_null); + + sk_X509_set_cmp_func(uctx->cert_list, compare_certs_desc); + + /* Iterate over the SSLProxyCertificateURI array */ + for (i = 0; (i < mctx->pkp->uris->nelts) && + (uri = APR_ARRAY_IDX(mctx->pkp->uris, i, + const char *)); + i++) { + + if (uri && + ssl_init_proxy_uri(s, ptemp, uri, 1, uctx) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10611) + "Host %s: Failed to open proxy URI `%s'", + mctx->sc->vhost_id, uri); + return APR_EGENERAL; + } - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02287) - "Failed to read %d bytes from %s: (%d) %pm", - TLSEXT_TICKET_KEY_LEN, path, rv, &rv); - return ssl_die(s); } - memcpy(ticket_key->key_name, buf, 16); - memcpy(ticket_key->aes_key, buf + 32, 16); -#if OPENSSL_VERSION_NUMBER < 0x30000000L - memcpy(ticket_key->hmac_secret, buf + 16, 16); - res = SSL_CTX_set_tlsext_ticket_key_cb(mctx->ssl_ctx, - ssl_callback_SessionTicket); -#else - ticket_key->mac_params[0] = - OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, - apr_pmemdup(p, buf + 16, 16), 16); - ticket_key->mac_params[1] = - OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, "sha256", 0); - ticket_key->mac_params[2] = - OSSL_PARAM_construct_end(); - res = SSL_CTX_set_tlsext_ticket_key_evp_cb(mctx->ssl_ctx, - ssl_callback_SessionTicket); -#endif - OPENSSL_cleanse(buf, sizeof(buf)); - if (!res) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01913) - "Unable to initialize TLS session ticket key callback " - "(incompatible OpenSSL version?)"); + /* newest to oldest, first one wins */ + sk_X509_sort(uctx->cert_list); + + /* Match certs to keys */ + for (i = sk_X509_num(uctx->cert_list) - 1; i >= 0; i--) { + X509 *cert = sk_X509_value(uctx->cert_list, i); + + for (k = 0; k < sk_EVP_PKEY_num(uctx->key_list); k++) { + EVP_PKEY *pkey = sk_EVP_PKEY_value(uctx->key_list, k); + + if (X509_check_private_key(cert, pkey) == 1) { + + X509_INFO *info = X509_INFO_new(); + info->x_pkey = X509_PKEY_new(); + + X509_up_ref(cert); + info->x509 = cert; + + EVP_PKEY_up_ref(pkey); + info->x_pkey->dec_pkey = pkey; + + sk_X509_INFO_push(sk, info); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10612) + "Host %s: Proxy certificate from URI: %s", + mctx->sc->vhost_id, + modssl_X509_NAME_to_string(ptemp, + X509_get_subject_name(cert), 0)); + + found = 1; + break; + } + + } + } + + if (!found) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10613) + "Host %s: No matching proxy certificate/key pairs found among " + "%d certs, %d CA certs, %d intermediate certs, " + "%d leaf certs, %d client certs, %d keys.", + mctx->sc->vhost_id, + uctx->num_certs, uctx->num_ca_certs, uctx->num_intermediate_certs, + uctx->num_leaf_certs, + uctx->num_client_certs, uctx->num_keys); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - return ssl_die(s); + sk_X509_INFO_free(sk); + return APR_EGENERAL; } - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02288) - "TLS session ticket key for %s successfully loaded from %s", - (mySrvConfig(s))->vhost_id, path); + /* Handle intermediates, must happen after cert handling */ + for (i = sk_X509_num(uctx->ca_list) - 1; i >= 0; i--) { + X509 *cert = sk_X509_value(uctx->ca_list, i); + X509_STORE_add_cert(store, cert); /* increments cert */ + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10614) + "Host %s: loaded %d client certs for SSL proxy among " + "%d certs, %d CA certs, %d intermediate certs, " + "%d leaf certs, %d client certs, %d keys.", + mctx->sc->vhost_id, + sk_X509_INFO_num(sk), + uctx->num_certs, uctx->num_ca_certs, uctx->num_intermediate_certs, + uctx->num_leaf_certs, + uctx->num_client_certs, uctx->num_keys); + + return rv; +} +#else +static apr_status_t ssl_init_proxy_uris(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + if (pkp->uris->nelts) { + const char *vhost_id = mctx->sc->vhost_id; + + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10615) + "Host %s: Proxy certificate URIs are not supported on this platform.", + mctx->sc->vhost_id); + + return APR_ENOTIMPL; + } return APR_SUCCESS; } @@ -2030,14 +2931,10 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, apr_pool_t *ptemp, modssl_ctx_t *mctx) { - int n, ncerts = 0; STACK_OF(X509_INFO) *sk; modssl_pk_proxy_t *pkp = mctx->pkp; - STACK_OF(X509) *chain; - X509_STORE_CTX *sctx; X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx); - int addl_chain = 0; /* non-zero if additional chain certs were - * added to store */ + int n, ncerts = 0; ap_assert(store != NULL); /* safe to assume always non-NULL? */ @@ -2047,7 +2944,7 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, * https://github.com/openssl/openssl/issues/6933 */ SSL_CTX_set_post_handshake_auth(mctx->ssl_ctx, 1); #endif - + SSL_CTX_set_client_cert_cb(mctx->ssl_ctx, ssl_callback_proxy_cert); @@ -2082,7 +2979,6 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, X509_INFO_free(inf); sk_X509_INFO_delete(sk, n); n--; - addl_chain = 1; continue; } @@ -2093,7 +2989,7 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, "(missing or encrypted private key?)"); return ssl_die(s); } - + if (X509_check_private_key(inf->x509, inf->x_pkey->dec_pkey) != 1) { ssl_log_xerror(SSLLOG_MARK, APLOG_STARTUP, 0, ptemp, s, inf->x509, APLOGNO(02326) "proxy client certificate and " @@ -2115,36 +3011,51 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, ncerts); pkp->certs = sk; - /* If any chain certs are configured, build the ->ca_certs chains - * corresponding to the loaded keypairs. */ - if (!pkp->ca_cert_file && !addl_chain) { - return APR_SUCCESS; + if (pkp->ca_cert_file) { + modssl_X509_STORE_load_locations(store, pkp->ca_cert_file, NULL); } - /* If SSLProxyMachineCertificateChainFile is configured, load all - * the CA certs and have OpenSSL attempt to construct a full chain - * from each configured end-entity cert up to a root. This will - * allow selection of the correct cert given a list of root CA + return APR_SUCCESS; +} + +static apr_status_t ssl_init_proxy_ca_certs(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, + modssl_ctx_t *mctx) +{ + modssl_pk_proxy_t *pkp = mctx->pkp; + + X509_STORE_CTX *sctx; + X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx); + STACK_OF(X509) *chain; + + int n, ncerts = 0; + + ap_assert(store != NULL); /* safe to assume always non-NULL? */ + + ncerts = pkp->certs ? sk_X509_INFO_num(pkp->certs) : 0; + + /* If intermediate certificates have been configured, have + * OpenSSL attempt to construct a full chain from each + * configured end-entity cert up to a root. This will allow + * selection of the correct cert given a list of root CA * names in the certificate request from the server. */ - pkp->ca_certs = (STACK_OF(X509) **) apr_pcalloc(p, ncerts * sizeof(sk)); + + pkp->ca_certs = (STACK_OF(X509) **) apr_pcalloc(p, ncerts * sizeof(STACK_OF(X509_INFO) *)); sctx = X509_STORE_CTX_new(); if (!sctx) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02208) "SSL proxy client cert initialization failed"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - sk_X509_INFO_free(sk); return ssl_die(s); } - modssl_X509_STORE_load_locations(store, pkp->ca_cert_file, NULL); - for (n = 0; n < ncerts; n++) { int i; X509_INFO *inf = sk_X509_INFO_value(pkp->certs, n); if (!X509_STORE_CTX_init(sctx, store, inf->x509, NULL)) { - sk_X509_INFO_free(sk); X509_STORE_CTX_free(sctx); return ssl_die(s); } @@ -2268,6 +3179,14 @@ static apr_status_t ssl_init_proxy_ctx(server_rec *s, return rv; } + if ((rv = ssl_init_proxy_uris(s, p, ptemp, proxy)) != APR_SUCCESS) { + return rv; + } + + if ((rv = ssl_init_proxy_ca_certs(s, p, ptemp, proxy)) != APR_SUCCESS) { + return rv; + } + return APR_SUCCESS; } @@ -2319,16 +3238,30 @@ static apr_status_t ssl_init_server_ctx(server_rec *s, /* additionally installed certs overrides any old chain configuration */ sc->server->cert_chain = NULL; } - + if ((rv = ssl_init_ctx(s, p, ptemp, sc->server)) != APR_SUCCESS) { return rv; } - if ((rv = ssl_init_server_certs(s, p, ptemp, sc->server, pphrases)) - != APR_SUCCESS) { - return rv; + if (pks->cert_files->nelts) { + + if ((rv = ssl_init_server_certs(s, p, ptemp, sc->server, pphrases)) + != APR_SUCCESS) { + return rv; + } + } + if (pks->uris->nelts) { + + if ((rv = ssl_init_server_uris(s, p, ptemp, sc->server, pphrases)) + != APR_SUCCESS) { + return rv; + } + + } + + #ifdef HAVE_SSL_CONF_CMD SSL_CONF_CTX_set_ssl_ctx(cctx, sc->server->ssl_ctx); for (i = 0; i < sc->server->ssl_ctx_param->nelts; i++, param++) { @@ -2425,10 +3358,10 @@ apr_status_t ssl_init_ConfigureServer(server_rec *s, return rv; } - /* Initialize OCSP Responder certificate if OCSP enabled */ - #ifndef OPENSSL_NO_OCSP - ssl_init_ocsp_certificates(s, sc->server); - #endif + /* Initialize OCSP Responder certificate if OCSP enabled */ + #ifndef OPENSSL_NO_OCSP + ssl_init_ocsp_certificates(s, sc->server); + #endif } @@ -2566,6 +3499,101 @@ int ssl_proxy_section_post_config(apr_pool_t *p, apr_pool_t *plog, return OK; } +static int ssl_init_x509_name_cmp(const X509_NAME *const *a, const X509_NAME *const *b) +{ + return X509_NAME_cmp(*a, *b); +} + +static apr_status_t ssl_init_ca_cert_uri(server_rec *s, + apr_pool_t *ptemp, + const char *uri, + STACK_OF(X509_NAME) *ca_list, + int depth, + modssl_ctx_t *mctx) +{ +#if MODSSL_HAVE_OPENSSL_STORE + OSSL_STORE_CTX *sctx; + OSSL_STORE_INFO *info; + + apr_status_t rv = APR_SUCCESS; + + sk_X509_NAME_set_cmp_func(ca_list, ssl_init_x509_name_cmp); + + if (!uri) { + return rv; + } + + if ((!(sctx = OSSL_STORE_open_ex(uri, mctx->libctx, NULL, NULL, NULL, + NULL, NULL, NULL)))) { + return APR_EGENERAL; + } + + while (!OSSL_STORE_eof(sctx) && !OSSL_STORE_error(sctx)) { + + if (!(info = OSSL_STORE_load(sctx))) { + continue; + } + + switch(OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_NAME: { + + if (depth > 0) { + rv = ssl_init_ca_cert_uri(s, ptemp, + OSSL_STORE_INFO_get0_NAME(info), + ca_list, depth - 1, mctx); + if (APR_SUCCESS != rv) { + OSSL_STORE_close(sctx); + return rv; + } + } + + break; + } + case OSSL_STORE_INFO_CERT: { + + X509 *cert; + const X509_NAME *name; + X509_NAME *xname; + + if (!(cert = OSSL_STORE_INFO_get0_CERT(info))) { + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + else if (!X509_check_ca(cert)) { + /* ignore leaf certificates */ + continue; + } + else if (!(name = X509_get_subject_name(cert)) || + !(xname = X509_NAME_dup(name))) { + return APR_EGENERAL; + } + if (sk_X509_NAME_find(ca_list, xname) >= 0) { + /* duplicate */ + X509_NAME_free(xname); + } + else if (!sk_X509_NAME_push(ca_list, xname)) { + X509_NAME_free(xname); + OSSL_STORE_close(sctx); + return APR_EGENERAL; + } + + break; + } + } + } + + OSSL_STORE_close(sctx); + + return rv; +#else + if (!uri) { + return APR_SUCCESS; + } + + return APR_ENOTIMPL; +#endif +} + static apr_status_t ssl_init_ca_cert_path(server_rec *s, apr_pool_t *ptemp, const char *path, @@ -2603,24 +3631,34 @@ static apr_status_t ssl_init_ca_cert_path(server_rec *s, STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, apr_pool_t *ptemp, const char *ca_file, - const char *ca_path) + const char *ca_path, + const char *ca_uri, + modssl_ctx_t *mctx) { STACK_OF(X509_NAME) *ca_list = sk_X509_NAME_new_null();; + /* + * Process CA certificate store uri + */ + if (ca_uri && + ssl_init_ca_cert_uri(s, ptemp, + ca_uri, ca_list, 1, mctx) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10616) + "Failed to open Certificate URI `%s'", ca_uri); + sk_X509_NAME_pop_free(ca_list, X509_NAME_free); + return NULL; + } + /* * Process CA certificate bundle file */ - if (ca_file) { - SSL_add_file_cert_subjects_to_stack(ca_list, ca_file); - /* - * If ca_list is still empty after trying to load ca_file - * then the file failed to load, and users should hear about that. - */ - if (sk_X509_NAME_num(ca_list) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02210) + if (ca_file && + !SSL_add_file_cert_subjects_to_stack(ca_list, ca_file)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02210) "Failed to load SSLCACertificateFile: %s", ca_file); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); - } + ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); + sk_X509_NAME_pop_free(ca_list, X509_NAME_free); + return NULL; } /* @@ -2675,10 +3713,10 @@ apr_status_t ssl_init_ModuleKill(void *data) ssl_init_ctx_cleanup(sc->server); - /* Not Sure but possibly clear X509 trusted cert file */ - #ifndef OPENSSL_NO_OCSP - sk_X509_pop_free(sc->server->ocsp_certs, X509_free); - #endif + /* Not Sure but possibly clear X509 trusted cert file */ + #ifndef OPENSSL_NO_OCSP + sk_X509_pop_free(sc->server->ocsp_certs, X509_free); + #endif } diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index 3e96f9efdac..85118b7a9d0 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -29,6 +29,7 @@ time I was too famous.'' -- Unknown */ #include "ssl_private.h" +#include "httpd.h" #include "mod_ssl.h" #include "util_md5.h" #include "scoreboard.h" diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c index 773c4660eb8..900b91a472a 100644 --- a/modules/ssl/ssl_engine_pphrase.c +++ b/modules/ssl/ssl_engine_pphrase.c @@ -780,7 +780,7 @@ static apr_status_t pp_ui_method_cleanup(void *uip) return APR_SUCCESS; } -static UI_METHOD *get_passphrase_ui(apr_pool_t *p) +UI_METHOD *modssl_get_passphrase_ui(apr_pool_t *p) { UI_METHOD *ui_method = UI_create_method("Passphrase UI"); @@ -794,6 +794,21 @@ static UI_METHOD *get_passphrase_ui(apr_pool_t *p) return ui_method; } + +void *modssl_get_passphrase_cb(server_rec *s, apr_pool_t *p, + const char *vhostid, + const char *uri) +{ + pphrase_cb_arg_t *ppcb = apr_pcalloc(p, sizeof(pphrase_cb_arg_t)); + + ppcb->s = s; + ppcb->p = p; + ppcb->bPassPhraseDialogOnce = TRUE; + ppcb->key_id = vhostid; + ppcb->pkey_file = uri; + + return ppcb; +} #endif #if MODSSL_HAVE_ENGINE_API @@ -819,7 +834,7 @@ static apr_status_t modssl_load_keypair_engine(server_rec *s, apr_pool_t *pconf, { const char *c, *scheme; ENGINE *e; - UI_METHOD *ui_method = get_passphrase_ui(ptemp); + UI_METHOD *ui_method = modssl_get_passphrase_ui(ptemp); pphrase_cb_arg_t ppcb; memset(&ppcb, 0, sizeof ppcb); @@ -904,7 +919,7 @@ static OSSL_STORE_INFO *modssl_load_store_uri(server_rec *s, apr_pool_t *p, const char *uri, int info_type) { OSSL_STORE_CTX *sctx; - UI_METHOD *ui_method = get_passphrase_ui(p); + UI_METHOD *ui_method = modssl_get_passphrase_ui(p); pphrase_cb_arg_t ppcb; OSSL_STORE_INFO *info = NULL; diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index a34b034f265..8814f276e05 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -755,19 +755,23 @@ typedef struct { * a given vhost */ typedef struct { /* Lists of configured certs and keys for this server */ + apr_array_header_t *uris; apr_array_header_t *cert_files; apr_array_header_t *key_files; /** Certificates which specify the set of CA names which should be * sent in the CertificateRequest message: */ + const char *ca_name_uri; const char *ca_name_path; const char *ca_name_file; - + /* TLS service for this server is suspended */ int service_unavailable; } modssl_pk_server_t; typedef struct { + /* Lists of configured certs and keys for this proxy */ + apr_array_header_t *uris; /** proxy can have any number of cert/key pairs */ const char *cert_file; const char *cert_path; @@ -784,6 +788,7 @@ typedef struct { /** stuff related to authentication that can also be per-dir */ typedef struct { /** known/trusted CAs */ + const char *ca_cert_uri; const char *ca_cert_path; const char *ca_cert_file; @@ -822,6 +827,9 @@ typedef struct { typedef struct { SSLSrvConfigRec *sc; /** pointer back to server config */ SSL_CTX *ssl_ctx; +#if MODSSL_HAVE_OPENSSL_STORE + OSSL_LIB_CTX *libctx; +#endif /** we are one or the other */ modssl_pk_server_t *pks; @@ -841,6 +849,7 @@ typedef struct { const char *cert_chain; /** certificate revocation list */ + const char *crl_uri; const char *crl_path; const char *crl_file; int crl_check_mask; @@ -892,6 +901,24 @@ typedef struct { BOOL ssl_check_peer_expire; } modssl_ctx_t; + +typedef struct { + modssl_ctx_t* mctx; + + STACK_OF(X509) *cert_list; + STACK_OF(EVP_PKEY) *key_list; + STACK_OF(X509) *ca_list; + + int num_certs; + int num_ca_certs; + int num_intermediate_certs; + int num_leaf_certs; + int num_server_certs; + int num_client_certs; + int num_keys; + +} modssl_ctx_uri_t; + struct SSLSrvConfigRec { SSLModConfigRec *mc; ssl_enabled_t enabled; @@ -963,13 +990,17 @@ const char *ssl_cmd_SSLEngine(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLECHKeyDir(cmd_parms *cmd, void *dcfg, const char *arg); #endif const char *ssl_cmd_SSLCipherSuite(cmd_parms *, void *, const char *, const char *); +const char *ssl_cmd_SSLCertificateURI(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCertificateFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCACertificateURI(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCACertificatePath(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCACertificateFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCADNRequestURI(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCADNRequestFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCARevocationURI(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCARevocationPath(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCARevocationFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCARevocationCheck(cmd_parms *, void *, const char *); @@ -996,11 +1027,14 @@ const char *ssl_cmd_SSLProxyProtocol(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *, void *, const char *, const char *); const char *ssl_cmd_SSLProxyVerify(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyVerifyDepth(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyCACertificateURI(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyCARevocationURI(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyCARevocationCheck(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLProxyMachineCertificateURI(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *, void *, const char *); @@ -1046,7 +1080,7 @@ int ssl_proxy_section_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s, ap_conf_vector_t *section_config); STACK_OF(X509_NAME) - *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *); + *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *, const char *, modssl_ctx_t *); void ssl_init_Child(apr_pool_t *, server_rec *); apr_status_t ssl_init_ModuleKill(void *data); @@ -1181,6 +1215,12 @@ apr_status_t modssl_load_engine_keypair(server_rec *s, const char *certid, const char *keyid, X509 **pubkey, EVP_PKEY **privkey); +UI_METHOD *modssl_get_passphrase_ui(apr_pool_t *p); +void *modssl_get_passphrase_cb(server_rec *s, apr_pool_t *p, + const char *vhostid, + const char *uri); + + /** Diffie-Hellman Parameter Support */ #if OPENSSL_VERSION_NUMBER < 0x30000000L DH *modssl_dh_from_file(const char *);