/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/
/* * Grab well-defined DH parameters from OpenSSL, see the BN_get_rfc* * functions in <openssl/bn.h> for all available primes.
*/ static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *))
{
DH *dh = DH_new();
BIGNUM *p, *g;
if (!dh) { return NULL;
}
p = prime(NULL);
g = BN_new(); if (g != NULL) {
BN_set_word(g, 2);
} if (!p || !g || !DH_set0_pqg(dh, p, NULL, g)) {
DH_free(dh);
BN_free(p);
BN_free(g); return NULL;
} return dh;
}
for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++)
dhparams[n].dh = make_dh_params(dhparams[n].prime);
}
staticvoid free_dh_params(void)
{ unsigned n;
/* DH_free() is a noop for a NULL parameter, so these are harmless * in the (unexpected) case where these variables are already
* NULL. */ for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) {
DH_free(dhparams[n].dh);
dhparams[n].dh = NULL;
}
}
/* Hand out the same DH structure though once generated as we leak * memory otherwise and freeing the structure up after use would be * hard to track and in fact is not needed at all as it is safe to * use the same parameters over and over again security wise (in * contrast to the keys itself) and code safe as the returned structure * is duplicated by OpenSSL anyway. Hence no modification happens
* to our copy. */
DH *modssl_get_dh_params(unsigned keylen)
{ unsigned n;
for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) if (keylen >= dhparams[n].min) return dhparams[n].dh;
/* _________________________________________________________________ ** ** Let other answer special connection attempts. ** Used in ACME challenge handling by mod_md. ** _________________________________________________________________
*/
if (runtime_lib_version < MODSSL_LIBRARY_VERSION) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(01882) "Init: this version of mod_ssl was compiled against " "a newer library (%s (%s), version currently loaded is 0x%lX)" " - may result in undefined or erroneous behavior",
MODSSL_LIBRARY_TEXT, MODSSL_LIBRARY_DYNTEXT,
runtime_lib_version);
}
/* We initialize mc->pid per-process in the child init, * but it should be initialized for startup before we * call ssl_rand_seed() below.
*/
mc->pid = getpid();
/* * Let us cleanup on restarts and exits
*/
apr_pool_cleanup_register(p, base_server,
ssl_init_ModuleKill,
apr_pool_cleanup_null);
/* * Any init round fixes the global config
*/
ssl_config_global_create(base_server); /* just to avoid problems */
ssl_config_global_fix(mc);
/* * try to fix the configuration and open the dedicated SSL * logfile as early as possible
*/ for (s = base_server; s; s = s->next) {
sc = mySrvConfig(s);
if (sc->server) {
sc->server->sc = sc;
}
/* * Create the server host:port string because we need it a lot
*/ if (sc->vhost_id) { /* already set. This should only happen if this config rec is
* shared with another server. Argh! */
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10104) "%s, SSLSrvConfigRec shared from %s",
ssl_util_vhostid(p, s), sc->vhost_id);
}
sc->vhost_id = ssl_util_vhostid(p, s);
sc->vhost_id_len = strlen(sc->vhost_id);
/* Default to enabled if SSLEngine is not set explicitly, and
* the protocol is https. */ if (ap_get_server_protocol(s)
&& strcmp("https", ap_get_server_protocol(s)) == 0
&& sc->enabled == SSL_ENABLED_UNSET
&& (!apr_is_empty_array(sc->server->pks->cert_files))) {
sc->enabled = SSL_ENABLED_TRUE;
}
/* Fix up stuff that may not have been set. If sc->enabled is
* UNSET, then SSL is disabled on this vhost. */ if (sc->enabled == SSL_ENABLED_UNSET) {
sc->enabled = SSL_ENABLED_FALSE;
}
if (sc->session_cache_timeout == UNSET) {
sc->session_cache_timeout = SSL_SESSION_CACHE_TIMEOUT;
}
/* * Seed the Pseudo Random Number Generator (PRNG) * only need ptemp here; nothing inside allocated from the pool * needs to live once we return from ssl_rand_seed().
*/
ssl_rand_seed(base_server, ptemp, SSL_RSCTX_STARTUP, "Init: ");
#ifdef HAVE_FIPS if (!modssl_fips_is_enabled() && mc->fips == TRUE) { if (!modssl_fips_enable(1)) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, base_server, APLOGNO(01885) "Could not enable FIPS mode");
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, base_server); return ssl_die(base_server);
}
/* Log actual FIPS mode which the SSL library is operating under, * which may have been set outside of the mod_ssl
* configuration. */ if (modssl_fips_is_enabled()) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, base_server, APLOGNO(01884)
MODSSL_LIBRARY_NAME " has FIPS mode enabled");
} else {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(01886)
MODSSL_LIBRARY_NAME " has FIPS mode disabled");
} #endif
/* * initialize the mutex handling
*/ if (!ssl_mutex_init(base_server, p)) { return HTTP_INTERNAL_SERVER_ERROR;
} #ifdef HAVE_OCSP_STAPLING
ssl_stapling_certinfo_hash_init(p); #endif
for (s = base_server; s; s = s->next) {
sc = mySrvConfig(s); /* * Either now skip this server when SSL is disabled for * it or give out some information about what we're * configuring.
*/
/* * Read the server certificate and key
*/ if ((rv = ssl_init_ConfigureServer(s, p, ptemp, sc, pphrases))
!= APR_SUCCESS) { return rv;
}
}
if (pphrases->nelts > 0) {
memset(pphrases->elts, 0, pphrases->elt_size * pphrases->nelts);
pphrases->nelts = 0;
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02560) "Init: Wiped out the queried pass phrases from memory");
}
/* * The Server Name Indication (SNI) provided by the ClientHello can be * used to select the right (name-based-)vhost and its SSL configuration * before the handshake takes place.
*/ if (!SSL_CTX_set_tlsext_servername_callback(mctx->ssl_ctx,
ssl_callback_ServerNameIndication) ||
!SSL_CTX_set_tlsext_servername_arg(mctx->ssl_ctx, mctx)) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01894) "Unable to initialize TLS servername extension " "callback (incompatible OpenSSL version?)");
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); return ssl_die(s);
}
#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) /* * The ClientHello callback also allows to retrieve the SNI, but since it * runs at the earliest possible connection stage we can even set the TLS * protocol version(s) according to the selected (name-based-)vhost, which * is not possible at the SNI callback stage (due to OpenSSL internals).
*/
SSL_CTX_set_client_hello_cb(mctx->ssl_ctx, ssl_callback_ClientHello, NULL); #endif
#else/* #if OPENSSL_VERSION_NUMBER < 0x10100000L */ /* We first determine the maximum protocol version we should provide */ #if SSL_HAVE_PROTOCOL_TLSV1_3 if (protocol & SSL_PROTOCOL_TLSV1_3) {
prot = TLS1_3_VERSION;
} else #endif if (protocol & SSL_PROTOCOL_TLSV1_2) {
prot = TLS1_2_VERSION;
} elseif (protocol & SSL_PROTOCOL_TLSV1_1) {
prot = TLS1_1_VERSION;
} elseif (protocol & SSL_PROTOCOL_TLSV1) {
prot = TLS1_VERSION; #ifndef OPENSSL_NO_SSL3
} elseif (protocol & SSL_PROTOCOL_SSLV3) {
prot = SSL3_VERSION; #endif
} else {
SSL_CTX_free(ctx);
mctx->ssl_ctx = NULL;
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(03378) "No SSL protocols available [hint: SSLProtocol]"); return ssl_die(s);
}
SSL_CTX_set_max_proto_version(ctx, prot);
/* Next we scan for the minimal protocol version we should provide,
* but we do not allow holes between max and min */ #if SSL_HAVE_PROTOCOL_TLSV1_3 if (prot == TLS1_3_VERSION && protocol & SSL_PROTOCOL_TLSV1_2) {
prot = TLS1_2_VERSION;
} #endif if (prot == TLS1_2_VERSION && protocol & SSL_PROTOCOL_TLSV1_1) {
prot = TLS1_1_VERSION;
} if (prot == TLS1_1_VERSION && protocol & SSL_PROTOCOL_TLSV1) {
prot = TLS1_VERSION;
} #ifndef OPENSSL_NO_SSL3 if (prot == TLS1_VERSION && protocol & SSL_PROTOCOL_SSLV3) {
prot = SSL3_VERSION;
} #endif
SSL_CTX_set_min_proto_version(ctx, prot); #endif/* if OPENSSL_VERSION_NUMBER < 0x10100000L */
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION /* * Disallow a session from being resumed during a renegotiation, * so that an acceptable cipher suite can be negotiated.
*/
SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif
#ifdef SSL_MODE_RELEASE_BUFFERS /* If httpd is configured to reduce mem usage, ask openssl to do so, too */ if (ap_max_mem_free != APR_ALLOCATOR_MAX_FREE_UNLIMITED)
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); #endif
#if OPENSSL_VERSION_NUMBER >= 0x1010100fL /* For OpenSSL >=1.1.1, disable auto-retry mode so it's possible * to consume handshake records without blocking for app-data.
* https://github.com/openssl/openssl/issues/7178 */
SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY); #endif
#ifdef HAVE_OPENSSL_KEYLOG if (mctx->sc->mc->keylog_file) {
SSL_CTX_set_keylog_callback(ctx, modssl_callback_keylog);
} #endif
#ifdef SSL_OP_NO_RENEGOTIATION /* For server-side SSL_CTX, disable renegotiation by default.. */ if (!mctx->pkp) {
SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION);
} #endif
#if MODSSL_USE_OPENSSL_PRE_1_1_API /* Note that for OpenSSL>=1.1, auto selection is enabled via
* SSL_CTX_set_dh_auto(,1) if no parameter is configured. */
SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); #endif
/* The info callback is used for debug-level tracing. For OpenSSL * versions where SSL_OP_NO_RENEGOTIATION is not available, the * callback is also used to prevent use of client-initiated
* renegotiation. Enable it in either case. */ if (APLOGdebug(s) || MODSSL_BLOCKS_RENEG) {
SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
}
if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path)) {
ca_list = ssl_init_FindCAList(s, ptemp,
mctx->pks->ca_name_file,
mctx->pks->ca_name_path);
} else
ca_list = ssl_init_FindCAList(s, ptemp,
mctx->auth.ca_cert_file,
mctx->auth.ca_cert_path); 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"); return ssl_die(s);
}
SSL_CTX_set_client_CA_list(ctx, ca_list);
}
/* * Give a warning when no CAs were configured but client authentication * should take place. This cannot work.
*/ if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) {
ca_list = SSL_CTX_get_client_CA_list(ctx);
if (sk_X509_NAME_num(ca_list) == 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01897) "Init: Oops, you want to request client " "authentication, but no CAs are known for " "verification!? [Hint: SSLCACertificate*]");
}
}
/* * Configure SSL Cipher Suite. Always disable NULL and export ciphers, * see also ssl_engine_config.c:ssl_cmd_SSLCipherSuite(). * OpenSSL's SSL_DEFAULT_CIPHER_LIST includes !aNULL:!eNULL from 0.9.8f, * and !EXP from 0.9.8zf/1.0.1m/1.0.2a, so append them while we support * earlier versions.
*/
suite = mctx->auth.cipher_suite ? mctx->auth.cipher_suite :
apr_pstrcat(ptemp, SSL_DEFAULT_CIPHER_LIST, ":!aNULL:!eNULL:!EXP",
NULL);
/* * Read a file that optionally contains the server certificate in PEM * format, possibly followed by a sequence of CA certificates that * should be sent to the peer in the SSL Certificate message.
*/ staticint use_certificate_chain(
SSL_CTX *ctx, char *file, int skipfirst, pem_password_cb *cb)
{
BIO *bio;
X509 *x509; unsignedlong err; int n;
if ((bio = BIO_new(BIO_s_file())) == NULL) return -1; if (BIO_read_filename(bio, file) <= 0) {
BIO_free(bio); return -1;
} /* optionally skip a leading server certificate */ if (skipfirst) { if ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) == NULL) {
BIO_free(bio); return -1;
}
X509_free(x509);
} /* free a perhaps already configured extra chain */ #ifdef OPENSSL_NO_SSL_INTERN
SSL_CTX_clear_extra_chain_certs(ctx); #else if (ctx->extra_certs != NULL) {
sk_X509_pop_free((STACK_OF(X509) *)ctx->extra_certs, X509_free);
ctx->extra_certs = NULL;
} #endif
/* create new extra chain by loading the certs */
n = 0;
ERR_clear_error(); while ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) != NULL) { if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) {
X509_free(x509);
BIO_free(bio); return -1;
}
n++;
} /* Make sure that only the error is just an EOF */ if ((err = ERR_peek_error()) > 0) { if (!( ERR_GET_LIB(err) == ERR_LIB_PEM
&& ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
BIO_free(bio); return -1;
} while (ERR_get_error() > 0) ;
}
BIO_free(bio); return n;
}
/* * Optionally configure extra server certificate chain certificates. * This is usually done by OpenSSL automatically when one of the * server cert issuers are found under SSLCACertificatePath or in * SSLCACertificateFile. But because these are intended for client * authentication it can conflict. For instance when you use a * Global ID server certificate you've to send out the intermediate * CA certificate, too. When you would just configure this with * SSLCACertificateFile and also use client authentication mod_ssl * would accept all clients also issued by this CA. Obviously this * isn't what we want in this situation. So this feature here exists * to allow one to explicitly configure CA certificates which are * used only for the server certificate chain.
*/ if (!chain) { return APR_SUCCESS;
}
for (i = 0; (i < mctx->pks->cert_files->nelts) &&
APR_ARRAY_IDX(mctx->pks->cert_files, i, constchar *); i++) { if (strEQ(APR_ARRAY_IDX(mctx->pks->cert_files, i, constchar *), chain)) {
skip_first = TRUE; break;
}
}
n = use_certificate_chain(mctx->ssl_ctx, (char *)chain, skip_first, NULL); if (n < 0) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01903) "Failed to configure CA certificate chain!"); return ssl_die(s);
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01904) "Configuring server certificate chain " "(%d CA certificate%s)",
n, n == 1 ? "" : "s");
if (modssl_X509_getBC(cert, &is_ca, &pathlen)) { if (is_ca) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01906) "%s server certificate is a CA certificate " "(BasicConstraints: CA == TRUE !?)", key_id);
}
if (pathlen > 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01907) "%s server certificate is not a leaf certificate " "(BasicConstraints: pathlen == %d > 0 !?)",
key_id, pathlen);
}
}
if (modssl_X509_match_name(ptemp, cert, (constchar *)s->server_hostname, TRUE, s) == FALSE) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01909) "%s server certificate does NOT include an ID " "which matches the server name", key_id);
}
}
/* prevent OpenSSL from showing its "Enter PEM pass phrase:" prompt */ staticint ssl_no_passwd_prompt_cb(char *buf, int size, int rwflag, void *userdata) { return 0;
}
/* 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 * X509_check_private_key(). This macro is passed the last error code * off the OpenSSL stack and evaluates to true only for the first * case. With OpenSSL < 3 the second case is identifiable by the
* function code, but function codes are not used from 3.0. */ #if OPENSSL_VERSION_NUMBER < 0x30000000L #define CHECK_PRIVKEY_ERROR(ec) (ERR_GET_FUNC(ec) != X509_F_X509_CHECK_PRIVATE_KEY) #else #define CHECK_PRIVKEY_ERROR(ec) (ERR_GET_LIB(ec) != ERR_LIB_X509 \
|| (ERR_GET_REASON(ec) != X509_R_KEY_TYPE_MISMATCH \
&& ERR_GET_REASON(ec) != X509_R_KEY_VALUES_MISMATCH \
&& ERR_GET_REASON(ec) != X509_R_UNKNOWN_KEY_TYPE)) #endif
/* and second, the private key */ if (i < mctx->pks->key_files->nelts) {
keyfile = APR_ARRAY_IDX(mctx->pks->key_files, i, constchar *);
} else {
keyfile = certfile;
}
ERR_clear_error();
if (modssl_is_engine_id(keyfile)) {
apr_status_t rv;
if (SSL_CTX_check_private_key(mctx->ssl_ctx) < 1) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02565) "Certificate and private key %s from %s and %s " "do not match", key_id, certfile, keyfile); return APR_EGENERAL;
}
#ifdef HAVE_SSL_CONF_CMD /* * workaround for those OpenSSL versions where SSL_CTX_get0_certificate * is not yet available: create an SSL struct which we dispose of * as soon as we no longer need access to the cert. (Strictly speaking, * SSL_CTX_get0_certificate does not depend on the SSL_CONF stuff, * but there's no reliable way to check for its existence, so we * assume that if SSL_CONF is available, it's OpenSSL 1.0.2 or later, * and SSL_CTX_get0_certificate is implemented.)
*/
cert = SSL_CTX_get0_certificate(mctx->ssl_ctx); #else
{
SSL *ssl = SSL_new(mctx->ssl_ctx); if (ssl) { /* Workaround bug in SSL_get_certificate in OpenSSL 0.9.8y */
SSL_set_connect_state(ssl);
cert = SSL_get_certificate(ssl);
SSL_free(ssl);
}
} #endif if (!cert) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02566) "Unable to retrieve certificate %s", key_id); return APR_EGENERAL;
}
#ifdefined(HAVE_OCSP_STAPLING) && !defined(SSL_CTRL_SET_CURRENT_CERT) /* * OpenSSL up to 1.0.1: configure stapling as we go. In 1.0.2 * and later, there's SSL_CTX_set_current_cert, which allows * iterating over all certs in an SSL_CTX (including those possibly * loaded via SSLOpenSSLConfCmd Certificate), so for 1.0.2 and * later, we defer to the code in ssl_init_server_ctx.
*/ if (!ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02567) "Unable to configure certificate %s for stapling",
key_id);
} #endif
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02568) "Certificate and private key %s configured from %s and %s",
key_id, certfile, keyfile);
}
/* * Try to read DH parameters from the (first) SSLCertificateFile
*/
certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, constchar *); if (certfile && !modssl_is_engine_id(certfile)) { int num_bits = 0; #if OPENSSL_VERSION_NUMBER < 0x30000000L
DH *dh = modssl_dh_from_file(certfile); if (dh) {
num_bits = DH_bits(dh);
SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dh);
DH_free(dh);
custom_dh_done = 1;
} #else
pkey = modssl_dh_pkey_from_file(certfile); if (pkey) {
num_bits = EVP_PKEY_get_bits(pkey); if (!SSL_CTX_set0_tmp_dh_pkey(mctx->ssl_ctx, pkey)) {
EVP_PKEY_free(pkey);
} else {
custom_dh_done = 1;
}
} #endif if (custom_dh_done) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540) "Custom DH parameters (%d bits) for %s loaded from %s",
num_bits, vhost_id, certfile);
}
} #if !MODSSL_USE_OPENSSL_PRE_1_1_API if (!custom_dh_done) { /* If no parameter is manually configured, enable auto
* selection. */
SSL_CTX_set_dh_auto(mctx->ssl_ctx, 1);
} #endif
#ifdef HAVE_ECC /* * Similarly, try to read the ECDH curve name from SSLCertificateFile...
*/ if (certfile && !modssl_is_engine_id(certfile)
&& (ecgroup = modssl_ec_group_from_file(certfile))
&& (curve_nid = EC_GROUP_get_curve_name(ecgroup))) { #if OPENSSL_VERSION_NUMBER < 0x30000000L
EC_KEY *eckey = EC_KEY_new_by_curve_name(curve_nid); if (eckey) {
SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey);
EC_KEY_free(eckey);
} else {
curve_nid = 0;
} #else 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);
}
} /* * ...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) { #ifdefined(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
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
staticBOOL load_x509_info(apr_pool_t *ptemp,
STACK_OF(X509_INFO) *sk, constchar *filename)
{
BIO *in;
if (!(in = BIO_new(BIO_s_file()))) { returnFALSE;
}
if (BIO_read_filename(in, filename) <= 0) {
BIO_free(in); returnFALSE;
}
ERR_clear_error();
PEM_X509_INFO_read_bio(in, sk, NULL, NULL);
BIO_free(in);
returnTRUE;
}
static apr_status_t ssl_init_proxy_certs(server_rec *s,
apr_pool_t *p,
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 */
ap_assert(store != NULL); /* safe to assume always non-NULL? */
#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(LIBRESSL_VERSION_NUMBER) /* For OpenSSL >=1.1.1, turn on client cert support which is * otherwise turned off by default (by design).
* https://github.com/openssl/openssl/issues/6933 */
SSL_CTX_set_post_handshake_auth(mctx->ssl_ctx, 1); #endif
if (!(pkp->cert_file || pkp->cert_path)) { return APR_SUCCESS;
}
sk = sk_X509_INFO_new_null();
if (pkp->cert_file) {
load_x509_info(ptemp, sk, pkp->cert_file);
}
if (pkp->cert_path) {
ssl_init_ca_cert_path(s, ptemp, pkp->cert_path, NULL, sk);
}
/* Check that all client certs have got certificates and private * keys. Note the number of certs in the stack may decrease
* during the loop. */ for (n = 0; n < sk_X509_INFO_num(sk); n++) {
X509_INFO *inf = sk_X509_INFO_value(sk, n); int has_privkey = inf->x_pkey && inf->x_pkey->dec_pkey;
/* For a lone certificate in the file, trust it as a
* CA/intermediate certificate. */ if (inf->x509 && !has_privkey && !inf->enc_data) {
ssl_log_xerror(SSLLOG_MARK, APLOG_DEBUG, 0, ptemp, s, inf->x509,
APLOGNO(10261) "Trusting non-leaf certificate");
X509_STORE_add_cert(store, inf->x509); /* increments inf->x509 */ /* Delete from the stack and iterate again. */
X509_INFO_free(inf);
sk_X509_INFO_delete(sk, n);
n--;
addl_chain = 1; continue;
}
if (!has_privkey || inf->enc_data) {
sk_X509_INFO_free(sk);
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, APLOGNO(02252) "incomplete client cert configured for SSL proxy " "(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 " "private key do not match");
ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); return ssl_die(s);
}
}
if ((ncerts = sk_X509_INFO_num(sk)) <= 0) {
sk_X509_INFO_free(sk);
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02206) "no client certs found for SSL proxy"); return APR_SUCCESS;
}
/* 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 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
* names in the certificate request from the server. */
pkp->ca_certs = (STACK_OF(X509) **) apr_pcalloc(p, ncerts * sizeof(sk));
sctx = X509_STORE_CTX_new();
/* Obtain a copy of the verified chain */
chain = X509_STORE_CTX_get1_chain(sctx);
if (chain != NULL) { /* Discard end entity cert from the chain */
X509_free(sk_X509_shift(chain));
if ((i = sk_X509_num(chain)) > 0) { /* Store the chain for later use */
pkp->ca_certs[n] = chain;
} else { /* Discard empty chain */
sk_X509_pop_free(chain, X509_free);
pkp->ca_certs[n] = NULL;
}
ssl_log_xerror(SSLLOG_MARK, APLOG_DEBUG, 0, ptemp, s, inf->x509,
APLOGNO(02271) "loaded %i intermediate CA%s for cert %i: ",
i, i == 1 ? "" : "s", n); if (i > 0) { int j; for (j = 0; j < i; j++) {
ssl_log_xerror(SSLLOG_MARK, APLOG_DEBUG, 0, ptemp, s,
sk_X509_value(chain, j), APLOGNO(03039) "%i:", j);
}
}
}
/* get ready for next X509_STORE_CTX_init */
X509_STORE_CTX_cleanup(sctx);
}
--> --------------------
--> maximum size reached
--> --------------------
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.19Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.