mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
Add SSLProxyMachineCertificateChainFile directive and documentation for bug 50812
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1160863 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -1493,6 +1493,31 @@ SSLProxyMachineCertificateFile /usr/local/apache2/conf/ssl.crt/proxy.pem
|
|||||||
</usage>
|
</usage>
|
||||||
</directivesynopsis>
|
</directivesynopsis>
|
||||||
|
|
||||||
|
<directivesynopsis>
|
||||||
|
<name>SSLProxyMachineCertificateChainFile</name>
|
||||||
|
<description>File of concatenated PEM-encoded CA certificates to be used by the proxy for choosing a certificate</description>
|
||||||
|
<syntax>SSLProxyMachineCertificateChainFile <em>filename</em></syntax>
|
||||||
|
<contextlist><context>server config</context></contextlist>
|
||||||
|
<override>Not applicable</override>
|
||||||
|
|
||||||
|
<usage>
|
||||||
|
<p>
|
||||||
|
This directive sets the all-in-one file where you keep the certificate chain
|
||||||
|
for all of the client certs in use. This directive will be needed if the
|
||||||
|
remote server presents a list of CA certificates that are not direct signers
|
||||||
|
of one of the configured client certificates.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This referenced file is simply the concatenation of the various PEM-encoded
|
||||||
|
certificate files. Upon startup, each client certificate configured will
|
||||||
|
be examined and a chain of trust will be constructed.
|
||||||
|
</p>
|
||||||
|
<example><title>Example</title>
|
||||||
|
SSLProxyMachineCertificateChainFile /usr/local/apache2/conf/ssl.crt/proxyCA.pem
|
||||||
|
</example>
|
||||||
|
</usage>
|
||||||
|
</directivesynopsis>
|
||||||
|
|
||||||
<directivesynopsis>
|
<directivesynopsis>
|
||||||
<name>SSLProxyVerify</name>
|
<name>SSLProxyVerify</name>
|
||||||
<description>Type of remote server Certificate verification</description>
|
<description>Type of remote server Certificate verification</description>
|
||||||
|
@@ -169,6 +169,10 @@ static const command_rec ssl_config_cmds[] = {
|
|||||||
SSL_CMD_SRV(ProxyMachineCertificatePath, TAKE1,
|
SSL_CMD_SRV(ProxyMachineCertificatePath, TAKE1,
|
||||||
"SSL Proxy: directory containing client certificates "
|
"SSL Proxy: directory containing client certificates "
|
||||||
"('/path/to/dir' - contains PEM encoded certificates)")
|
"('/path/to/dir' - contains PEM encoded certificates)")
|
||||||
|
SSL_CMD_SRV(ProxyMachineCertificateChainFile, TAKE1,
|
||||||
|
"SSL Proxy: file containing issuing certificates "
|
||||||
|
"of the client certificate "
|
||||||
|
"(`/path/to/file' - PEM encoded certificates)")
|
||||||
SSL_CMD_SRV(ProxyCheckPeerExpire, FLAG,
|
SSL_CMD_SRV(ProxyCheckPeerExpire, FLAG,
|
||||||
"SSL Proxy: check the peers certificate expiration date")
|
"SSL Proxy: check the peers certificate expiration date")
|
||||||
SSL_CMD_SRV(ProxyCheckPeerCN, FLAG,
|
SSL_CMD_SRV(ProxyCheckPeerCN, FLAG,
|
||||||
|
@@ -160,7 +160,9 @@ static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc,
|
|||||||
|
|
||||||
mctx->pkp->cert_file = NULL;
|
mctx->pkp->cert_file = NULL;
|
||||||
mctx->pkp->cert_path = NULL;
|
mctx->pkp->cert_path = NULL;
|
||||||
|
mctx->pkp->ca_cert_file = NULL
|
||||||
mctx->pkp->certs = NULL;
|
mctx->pkp->certs = NULL;
|
||||||
|
mctx->pkp->ca_certs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void modssl_ctx_init_server(SSLSrvConfigRec *sc,
|
static void modssl_ctx_init_server(SSLSrvConfigRec *sc,
|
||||||
@@ -270,6 +272,7 @@ static void modssl_ctx_cfg_merge_proxy(modssl_ctx_t *base,
|
|||||||
|
|
||||||
cfgMergeString(pkp->cert_file);
|
cfgMergeString(pkp->cert_file);
|
||||||
cfgMergeString(pkp->cert_path);
|
cfgMergeString(pkp->cert_path);
|
||||||
|
cfgMergeString(pkp->ca_cert_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void modssl_ctx_cfg_merge_server(modssl_ctx_t *base,
|
static void modssl_ctx_cfg_merge_server(modssl_ctx_t *base,
|
||||||
@@ -1408,6 +1411,21 @@ const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *cmd,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *cmd,
|
||||||
|
void *dcfg,
|
||||||
|
const char *arg)
|
||||||
|
{
|
||||||
|
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
|
||||||
|
const char *err;
|
||||||
|
|
||||||
|
if ((err = ssl_cmd_check_file(cmd, &arg))) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->proxy->pkp->ca_cert_file = arg;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const char *ssl_cmd_SSLUserName(cmd_parms *cmd, void *dcfg,
|
const char *ssl_cmd_SSLUserName(cmd_parms *cmd, void *dcfg,
|
||||||
const char *arg)
|
const char *arg)
|
||||||
|
@@ -1086,6 +1086,7 @@ static void ssl_init_proxy_certs(server_rec *s,
|
|||||||
int n, ncerts = 0;
|
int n, ncerts = 0;
|
||||||
STACK_OF(X509_INFO) *sk;
|
STACK_OF(X509_INFO) *sk;
|
||||||
modssl_pk_proxy_t *pkp = mctx->pkp;
|
modssl_pk_proxy_t *pkp = mctx->pkp;
|
||||||
|
STACK_OF(X509_INFO) *chain;
|
||||||
|
|
||||||
SSL_CTX_set_client_cert_cb(mctx->ssl_ctx,
|
SSL_CTX_set_client_cert_cb(mctx->ssl_ctx,
|
||||||
ssl_callback_proxy_cert);
|
ssl_callback_proxy_cert);
|
||||||
@@ -1130,6 +1131,30 @@ static void ssl_init_proxy_certs(server_rec *s,
|
|||||||
"loaded %d client certs for SSL proxy",
|
"loaded %d client certs for SSL proxy",
|
||||||
ncerts);
|
ncerts);
|
||||||
pkp->certs = sk;
|
pkp->certs = sk;
|
||||||
|
|
||||||
|
if (!pkp->ca_cert_file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load all of the CA certs and construct a chain */
|
||||||
|
sk = sk_X509_INFO_new_null();
|
||||||
|
|
||||||
|
SSL_X509_INFO_load_file(ptemp, sk, pkp->ca_cert_file);
|
||||||
|
pkp->ca_certs = (STACK_OF(X509_INFO) **) apr_pcalloc(p, ncerts * sizeof(sk));
|
||||||
|
|
||||||
|
for (n = 0; n < ncerts; n++) {
|
||||||
|
int len;
|
||||||
|
X509_INFO *inf = sk_X509_INFO_value(pkp->certs, n);
|
||||||
|
chain = sk_X509_INFO_new_null();
|
||||||
|
len = SSL_X509_INFO_create_chain(inf->x509, sk, chain);
|
||||||
|
pkp->ca_certs[n] = chain;
|
||||||
|
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
||||||
|
"client certificate %i has loaded %i "
|
||||||
|
"intermediary signers ", n, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
sk_X509_INFO_free(sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ssl_init_proxy_ctx(server_rec *s,
|
static void ssl_init_proxy_ctx(server_rec *s,
|
||||||
|
@@ -1798,11 +1798,12 @@ int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
|
|||||||
conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
|
conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
|
||||||
server_rec *s = mySrvFromConn(c);
|
server_rec *s = mySrvFromConn(c);
|
||||||
SSLSrvConfigRec *sc = mySrvConfig(s);
|
SSLSrvConfigRec *sc = mySrvConfig(s);
|
||||||
X509_NAME *ca_name, *issuer;
|
X509_NAME *ca_name, *issuer, *ca_issuer;
|
||||||
X509_INFO *info;
|
X509_INFO *info, *ca_info;
|
||||||
STACK_OF(X509_NAME) *ca_list;
|
STACK_OF(X509_NAME) *ca_list;
|
||||||
STACK_OF(X509_INFO) *certs = sc->proxy->pkp->certs;
|
STACK_OF(X509_INFO) *certs = sc->proxy->pkp->certs;
|
||||||
int i, j;
|
STACK_OF(X509_INFO) *ca_certs;
|
||||||
|
int i, j, k;
|
||||||
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
||||||
SSLPROXY_CERT_CB_LOG_FMT "entered",
|
SSLPROXY_CERT_CB_LOG_FMT "entered",
|
||||||
@@ -1839,6 +1840,7 @@ int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
|
|||||||
info = sk_X509_INFO_value(certs, j);
|
info = sk_X509_INFO_value(certs, j);
|
||||||
issuer = X509_get_issuer_name(info->x509);
|
issuer = X509_get_issuer_name(info->x509);
|
||||||
|
|
||||||
|
/* Search certs (by issuer name) one by one*/
|
||||||
if (X509_NAME_cmp(issuer, ca_name) == 0) {
|
if (X509_NAME_cmp(issuer, ca_name) == 0) {
|
||||||
modssl_proxy_info_log(s, info, "found acceptable cert");
|
modssl_proxy_info_log(s, info, "found acceptable cert");
|
||||||
|
|
||||||
@@ -1846,7 +1848,22 @@ int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
|
|||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Failed to find direct issuer - search intermediaries (by issuer name) */
|
||||||
|
ca_certs = sc->proxy->pkp->ca_certs[j];
|
||||||
|
for (k = 0; k < sk_X509_INFO_num(ca_certs); k++) {
|
||||||
|
ca_info = sk_X509_INFO_value(ca_certs, k);
|
||||||
|
ca_issuer = X509_get_issuer_name(ca_info->x509);
|
||||||
|
|
||||||
|
if(X509_NAME_cmp(ca_issuer, ca_name) == 0 ) {
|
||||||
|
modssl_proxy_info_log(s, info, "found acceptable cert by intermediary");
|
||||||
|
|
||||||
|
modssl_set_cert_info(info, x509, pkey);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
} /* end loop through chained certs */
|
||||||
|
} /* end loop through available certs */
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
||||||
|
@@ -527,7 +527,9 @@ typedef struct {
|
|||||||
/** proxy can have any number of cert/key pairs */
|
/** proxy can have any number of cert/key pairs */
|
||||||
const char *cert_file;
|
const char *cert_file;
|
||||||
const char *cert_path;
|
const char *cert_path;
|
||||||
|
const char *ca_cert_file;
|
||||||
STACK_OF(X509_INFO) *certs;
|
STACK_OF(X509_INFO) *certs;
|
||||||
|
STACK_OF(X509_INFO) **ca_certs; /* ptr to array of ptrs */
|
||||||
} modssl_pk_proxy_t;
|
} modssl_pk_proxy_t;
|
||||||
|
|
||||||
/** stuff related to authentication that can also be per-dir */
|
/** stuff related to authentication that can also be per-dir */
|
||||||
|
@@ -434,6 +434,45 @@ BOOL SSL_X509_INFO_load_path(apr_pool_t *ptemp,
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct a stack of X509_INFO containing only certificates
|
||||||
|
* that have signed the provided certificate or are an intermediary
|
||||||
|
* signer of the certificate
|
||||||
|
*/
|
||||||
|
int SSL_X509_INFO_create_chain(const X509 *x509,
|
||||||
|
STACK_OF(X509_INFO) *ca_certs,
|
||||||
|
STACK_OF(X509_INFO) *chain)
|
||||||
|
{
|
||||||
|
int can_proceed=1;
|
||||||
|
int len=0;
|
||||||
|
int i;
|
||||||
|
X509 *certificate = (X509 *)x509;
|
||||||
|
X509_INFO *info;
|
||||||
|
X509_NAME *cert_issuer_name, *ca_name, *ca_issuer_name;
|
||||||
|
|
||||||
|
while (can_proceed) {
|
||||||
|
can_proceed = 0;
|
||||||
|
cert_issuer_name = X509_get_issuer_name(certificate);
|
||||||
|
|
||||||
|
for (i = 0; i < sk_X509_INFO_num(ca_certs); i++) {
|
||||||
|
info = sk_X509_INFO_value(ca_certs, i);
|
||||||
|
ca_name = X509_get_subject_name(info->x509);
|
||||||
|
ca_issuer_name = X509_get_issuer_name(info->x509);
|
||||||
|
|
||||||
|
if (X509_NAME_cmp(cert_issuer_name, ca_name) == 0) {
|
||||||
|
/* Check for a self-signed cert (no issuer) */
|
||||||
|
can_proceed=X509_NAME_cmp(ca_name, ca_issuer_name) == 0 ? 0 : 1;
|
||||||
|
len++;
|
||||||
|
certificate = info->x509;
|
||||||
|
sk_X509_INFO_unshift(chain, info);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
/* _________________________________________________________________
|
/* _________________________________________________________________
|
||||||
**
|
**
|
||||||
** Extra Server Certificate Chain Support
|
** Extra Server Certificate Chain Support
|
||||||
|
@@ -74,6 +74,7 @@ BOOL SSL_X509_INFO_load_file(apr_pool_t *, STACK_OF(X509_INFO) *, const c
|
|||||||
BOOL SSL_X509_INFO_load_path(apr_pool_t *, STACK_OF(X509_INFO) *, const char *);
|
BOOL SSL_X509_INFO_load_path(apr_pool_t *, STACK_OF(X509_INFO) *, const char *);
|
||||||
int SSL_CTX_use_certificate_chain(SSL_CTX *, char *, int, pem_password_cb *);
|
int SSL_CTX_use_certificate_chain(SSL_CTX *, char *, int, pem_password_cb *);
|
||||||
char *SSL_SESSION_id2sz(unsigned char *, int, char *, int);
|
char *SSL_SESSION_id2sz(unsigned char *, int, char *, int);
|
||||||
|
int SSL_X509_INFO_create_chain(const X509 *, STACK_OF(X509_INFO) *, STACK_OF(X509_INFO) *);
|
||||||
|
|
||||||
#endif /* __SSL_UTIL_SSL_H__ */
|
#endif /* __SSL_UTIL_SSL_H__ */
|
||||||
/** @} */
|
/** @} */
|
||||||
|
Reference in New Issue
Block a user