</usage>
</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>
<name>SSLProxyVerify</name>
<description>Type of remote server Certificate verification</description>
SSL_CMD_SRV(ProxyMachineCertificatePath, TAKE1,
"SSL Proxy: directory containing client 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 Proxy: check the peers certificate expiration date")
SSL_CMD_SRV(ProxyCheckPeerCN, FLAG,
mctx->pkp->cert_file = NULL;
mctx->pkp->cert_path = NULL;
+ mctx->pkp->ca_cert_file = NULL
mctx->pkp->certs = NULL;
+ mctx->pkp->ca_certs = NULL;
}
static void modssl_ctx_init_server(SSLSrvConfigRec *sc,
cfgMergeString(pkp->cert_file);
cfgMergeString(pkp->cert_path);
+ cfgMergeString(pkp->ca_cert_file);
}
static void modssl_ctx_cfg_merge_server(modssl_ctx_t *base,
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 *arg)
int n, ncerts = 0;
STACK_OF(X509_INFO) *sk;
modssl_pk_proxy_t *pkp = mctx->pkp;
+ STACK_OF(X509_INFO) *chain;
SSL_CTX_set_client_cert_cb(mctx->ssl_ctx,
ssl_callback_proxy_cert);
"loaded %d client certs for SSL proxy",
ncerts);
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,
conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
server_rec *s = mySrvFromConn(c);
SSLSrvConfigRec *sc = mySrvConfig(s);
- X509_NAME *ca_name, *issuer;
- X509_INFO *info;
+ X509_NAME *ca_name, *issuer, *ca_issuer;
+ X509_INFO *info, *ca_info;
STACK_OF(X509_NAME) *ca_list;
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,
SSLPROXY_CERT_CB_LOG_FMT "entered",
info = sk_X509_INFO_value(certs, j);
issuer = X509_get_issuer_name(info->x509);
+ /* Search certs (by issuer name) one by one*/
if (X509_NAME_cmp(issuer, ca_name) == 0) {
modssl_proxy_info_log(s, info, "found acceptable cert");
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,
/** proxy can have any number of cert/key pairs */
const char *cert_file;
const char *cert_path;
+ const char *ca_cert_file;
STACK_OF(X509_INFO) *certs;
+ STACK_OF(X509_INFO) **ca_certs; /* ptr to array of ptrs */
} modssl_pk_proxy_t;
/** stuff related to authentication that can also be per-dir */
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
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 *);
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__ */
/** @} */