1
0
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:
Daniel Ruggeri
2011-08-23 19:35:07 +00:00
parent 840f787b31
commit e5df36d18a
8 changed files with 135 additions and 4 deletions

View File

@@ -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>

View File

@@ -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,

View File

@@ -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)

View File

@@ -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,

View File

@@ -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,

View File

@@ -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 */

View File

@@ -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

View File

@@ -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__ */
/** @} */ /** @} */