Skip to content

Commit

Permalink
Merge r1884552 from trunk:
Browse files Browse the repository at this point in the history
Treat non-leaf certificates present in SSLProxyMachineCertificateFile
the same was as non-leaf certs are in SSLCertificateFile - use them to
build the trusted cert chain for the end-entity (client) cert.

* modules/ssl/ssl_engine_init.c (ssl_init_proxy_certs):
  For any non-leaf certificate present in the configured, trust as
  if used in SSLProxyMachineCertificateChainFile.

Github: closes #403
Reviewed by: jorton, gbechis, jfclere


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1915679 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
notroj committed Feb 9, 2024
1 parent f96805f commit 4e29445
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 22 deletions.
4 changes: 4 additions & 0 deletions changes-entries/ssl-proxy-chain-certs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*) mod_ssl: SSLProxyMachineCertificateFile/Path may reference files
which include CA certificates; those CA certs are treated as if
configured with SSLProxyMachineCertificateChainFile. [Joe Orton]

17 changes: 8 additions & 9 deletions docs/manual/mod/mod_ssl.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1859,7 +1859,8 @@ SSLProxyMachineCertificatePath "/usr/local/apache2/conf/proxy.crt/"
<syntax>SSLProxyMachineCertificateFile <em>filename</em></syntax>
<contextlist><context>server config</context> <context>virtual host</context>
<context>proxy section</context></contextlist>
<compatibility>The proxy section context is allowed in httpd 2.4.30 and later</compatibility>
<compatibility>The proxy section context is allowed in httpd 2.4.30 and later<br/>
Inclusion of non-leaf (CA) certificates is permitted only in httpd 2.5.1 and later.</compatibility>

<usage>
<p>
Expand All @@ -1869,13 +1870,11 @@ keys used for authentication of the proxy server to remote servers.
<p>
This referenced file is simply the concatenation of the various
PEM-encoded certificate files. Use this directive alternatively or
additionally to <code>SSLProxyMachineCertificatePath</code>. The
referenced file can contain any number of pairs of client certificate
and associated private key. Each pair can be specified in either
(certificate, key) or (key, certificate) order. If the file includes
any non-leaf certificate, or any unmatched key and certificate pair, a
configuration error will be issued at startup.
</p>
additionally to <code>SSLProxyMachineCertificatePath</code>. The referenced file can contain any number of pairs of client
certificate and associated private key. Each pair can be specified in
either (certificate, key) or (key, certificate) order. Non-leaf (CA) certificates can
also be included in the file, and are treated as if configured with <directive
module="mod_ssl">SSLProxyMachineCertificateChainFile</directive>.</p>

<p>When challenged to provide a client certificate by a remote server,
the server should provide a list of <em>acceptable certificate
Expand All @@ -1886,7 +1885,7 @@ client cert/key. If a list of CA names <em>is</em> provided,
to find a configured client cert which was issued either directly by
that CA, or indirectly via any number of intermediary CA certificates.
The chain of intermediate CA certificates can be built from those
configured with <directive
included in the file, or configured with <directive
module="mod_ssl">SSLProxyMachineCertificateChainFile</directive>. The
first configured matching certificate will then be supplied in
response to the challenge.</p>
Expand Down
46 changes: 33 additions & 13 deletions modules/ssl/ssl_engine_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,10 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s,
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
Expand All @@ -1736,20 +1740,28 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s,
ssl_init_ca_cert_path(s, ptemp, pkp->cert_path, NULL, sk);
}

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;
}

/* Check that all client certs have got certificates and private
* keys. */
for (n = 0; n < ncerts; n++) {
* 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;

if (!inf->x509 || !inf->x_pkey || !inf->x_pkey->dec_pkey ||
inf->enc_data) {
/* 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 "
Expand All @@ -1766,13 +1778,21 @@ static apr_status_t ssl_init_proxy_certs(server_rec *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;
}

ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02207)
"loaded %d client certs for SSL proxy",
ncerts);
pkp->certs = sk;


if (!pkp->ca_cert_file || !store) {
/* 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;
}

Expand Down

0 comments on commit 4e29445

Please sign in to comment.