httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wr...@apache.org
Subject svn commit: r1374374 - in /httpd/httpd/branches/2.2.x: ./ docs/manual/mod/ modules/ssl/
Date Fri, 17 Aug 2012 17:30:47 GMT
Author: wrowe
Date: Fri Aug 17 17:30:46 2012
New Revision: 1374374

URL: http://svn.apache.org/viewvc?rev=1374374&view=rev
Log:
mod_ssl: Add SSLProxyMachineCertificateChainFile directive uses openssl 
to construct a chain for each proxy cert. When a remote server requests
a client certificate that is NOT the direct issuer of any available client
certificate, the chain for that certificate will be used to trace it to a
known CA and that client certificate will be used. 

Submitted by: druggeri
Reviewed by: kbrand, rpluem
Backports: 1160863,1162103,1170833,1172010,1175946,1242089


Modified:
    httpd/httpd/branches/2.2.x/CHANGES
    httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml
    httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.h

Modified: httpd/httpd/branches/2.2.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/CHANGES?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.2.x/CHANGES [utf-8] Fri Aug 17 17:30:46 2012
@@ -5,6 +5,10 @@ Changes with Apache 2.2.23
      envvars: Fix insecure handling of LD_LIBRARY_PATH that could lead to the
      current working directory to be searched for DSOs. [Stefan Fritsch]
 
+  *) Added SSLProxyMachineCertificateChainFile directive so the proxy client
+     can select the proper client certificate when using a chain and the
+     remote server only lists the root CA as allowed.
+
   *) mpm_event, mpm_worker: Remain active amidst prevalent child process
      resource shortages.  [Jeff Trawick]
 

Modified: httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml (original)
+++ httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml Fri Aug 17 17:30:46 2012
@@ -1458,6 +1458,37 @@ SSLProxyMachineCertificateFile /usr/loca
 </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>
+<compatibility>Available in Apache 2.2.22 and later</compatibility>
+
+<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>
+<note type="warning"><title>Security warning</title>
+<p>If this directive is enabled, all of the certificates in the file will be
+trusted as if they were also in <directive module="mod_ssl">
+SSLProxyCACertificateFile</directive>.</p>
+</note>
+<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>
 <syntax>SSLProxyVerify <em>level</em></syntax>

Modified: httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c Fri Aug 17 17:30:46 2012
@@ -189,6 +189,10 @@ static const command_rec ssl_config_cmds
     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,

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c Fri Aug 17 17:30:46 2012
@@ -141,7 +141,9 @@ static void modssl_ctx_init_proxy(SSLSrv
 
     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,
@@ -233,6 +235,7 @@ static void modssl_ctx_cfg_merge_proxy(m
 
     cfgMergeString(pkp->cert_file);
     cfgMergeString(pkp->cert_path);
+    cfgMergeString(pkp->ca_cert_file);
 }
 
 static void modssl_ctx_cfg_merge_server(modssl_ctx_t *base,
@@ -1478,6 +1481,21 @@ const char *ssl_cmd_SSLProxyMachineCerti
     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)

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c Fri Aug 17 17:30:46 2012
@@ -975,6 +975,9 @@ static void ssl_init_proxy_certs(server_
 {
     int n, ncerts = 0;
     STACK_OF(X509_INFO) *sk;
+    STACK_OF(X509) *chain;
+    X509_STORE_CTX *sctx;
+    X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
     modssl_pk_proxy_t *pkp = mctx->pkp;
 
     SSL_CTX_set_client_cert_cb(mctx->ssl_ctx,
@@ -1020,6 +1023,78 @@ static void ssl_init_proxy_certs(server_
                  "loaded %d client certs for SSL proxy",
                  ncerts);
     pkp->certs = sk;
+
+    if (!pkp->ca_cert_file || !store) {
+        return;
+    }
+
+    /* Load all of the CA certs and construct a chain */
+    pkp->ca_certs = (STACK_OF(X509) **) apr_pcalloc(p, ncerts * sizeof(sk));
+    sctx = X509_STORE_CTX_new();
+
+    if (!sctx) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
+                     "SSL proxy client cert initialization failed");
+        ssl_log_ssl_error(APLOG_MARK, APLOG_EMERG, s);
+        ssl_die();
+    }
+
+    X509_STORE_load_locations(store, pkp->ca_cert_file, NULL);
+
+    for (n = 0; n < ncerts; n++) {
+        int i;
+
+        X509_INFO *inf = sk_X509_INFO_value(pkp->certs, n);
+        X509_NAME *name = X509_get_subject_name(inf->x509);
+        char *cert_dn = SSL_X509_NAME_to_string(ptemp, name, 0);
+        X509_STORE_CTX_init(sctx, store, inf->x509, NULL);
+
+        /* Attempt to verify the client cert */
+        if (X509_verify_cert(sctx) != 1) {
+            int err = X509_STORE_CTX_get_error(sctx);
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
+                         "SSL proxy client cert chain verification failed for %s: %s",
+                         cert_dn, X509_verify_cert_error_string(err));
+        }
+
+        /* Clear X509_verify_cert errors */
+        ERR_clear_error();
+
+        /* 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;
+            }
+
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                         "loaded %i intermediate CA%s for cert %i (%s)",
+                         i, i == 1 ? "" : "s", n, cert_dn);
+            if (i > 0) {
+                int j;
+                for (j = 0; j < i; j++) {
+                    X509_NAME *ca_name = X509_get_subject_name(sk_X509_value(chain, j));
+                    char *ca_dn = SSL_X509_NAME_to_string(ptemp, ca_name, 0);
+                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%i: %s", j, ca_dn);
+                }
+            }
+        }
+
+        /* get ready for next X509_STORE_CTX_init */
+        X509_STORE_CTX_cleanup(sctx);
+    }
+
+    X509_STORE_CTX_free(sctx);
 }
 
 static void ssl_init_proxy_ctx(server_rec *s,
@@ -1302,6 +1377,17 @@ static void ssl_init_ctx_cleanup_proxy(m
     ssl_init_ctx_cleanup(mctx);
 
     if (mctx->pkp->certs) {
+        int i = 0;
+        int ncerts = sk_X509_INFO_num(mctx->pkp->certs);
+
+        if (mctx->pkp->ca_certs) {
+            for (i = 0; i < ncerts; i++) {
+                if (mctx->pkp->ca_certs[i] != NULL) {
+                    sk_X509_pop_free(mctx->pkp->ca_certs[i], X509_free);
+                }
+            }
+        }
+
         sk_X509_INFO_pop_free(mctx->pkp->certs, X509_INFO_free);
         mctx->pkp->certs = NULL;
     }

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c Fri Aug 17 17:30:46 2012
@@ -1651,11 +1651,14 @@ int ssl_callback_proxy_cert(SSL *ssl, MO
     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_NAME *ca_name, *issuer, *ca_issuer;
     X509_INFO *info;
+    X509 *ca_cert;
     STACK_OF(X509_NAME) *ca_list;
     STACK_OF(X509_INFO) *certs = sc->proxy->pkp->certs;
-    int i, j;
+    STACK_OF(X509) *ca_certs;
+    STACK_OF(X509) **ca_cert_chains;
+    int i, j, k;
 
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                  SSLPROXY_CERT_CB_LOG_FMT "entered",
@@ -1685,6 +1688,7 @@ int ssl_callback_proxy_cert(SSL *ssl, MO
         return TRUE;
     }
 
+    ca_cert_chains = sc->proxy->pkp->ca_certs;
     for (i = 0; i < sk_X509_NAME_num(ca_list); i++) {
         ca_name = sk_X509_NAME_value(ca_list, i);
 
@@ -1692,6 +1696,7 @@ int ssl_callback_proxy_cert(SSL *ssl, MO
             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");
 
@@ -1699,7 +1704,27 @@ int ssl_callback_proxy_cert(SSL *ssl, MO
 
                 return TRUE;
             }
-        }
+
+            if (ca_cert_chains) {
+                /*
+                 * Failed to find direct issuer - search intermediates
+                 * (by issuer name), if provided.
+                 */
+                ca_certs = ca_cert_chains[j];
+                for (k = 0; k < sk_X509_num(ca_certs); k++) {
+                    ca_cert = sk_X509_value(ca_certs, k);
+                    ca_issuer = X509_get_issuer_name(ca_cert);
+
+                    if(X509_NAME_cmp(ca_issuer, ca_name) == 0 ) {
+                        modssl_proxy_info_log(s, info, "found acceptable cert by intermediate
CA");
+
+                        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,

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h Fri Aug 17 17:30:46 2012
@@ -425,7 +425,11 @@ typedef struct {
     /** proxy can have any number of cert/key pairs */
     const char  *cert_file;
     const char  *cert_path;
-    STACK_OF(X509_INFO) *certs;
+    const char  *ca_cert_file;
+    STACK_OF(X509_INFO) *certs; /* Contains End Entity certs */
+    STACK_OF(X509) **ca_certs; /* Contains ONLY chain certs for
+                                * each item in certs.
+                                * (ptr to array of ptrs) */
 } modssl_pk_proxy_t;
 
 /** stuff related to authentication that can also be per-dir */
@@ -566,6 +570,7 @@ const char  *ssl_cmd_SSLProxyCARevocatio
 const char  *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, void *, const char *);
+const char  *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *, void *, const char
*);
 const char  *ssl_cmd_SSLProxyCheckPeerExpire(cmd_parms *cmd, void *dcfg, int flag);
 const char  *ssl_cmd_SSLProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag);
 

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h Fri Aug 17 17:30:46 2012
@@ -238,6 +238,7 @@ typedef void (*modssl_popfree_fn)(char *
 #define sk_X509_push sk_push
 #define sk_X509_pop_free(st, free) sk_pop_free((STACK*)(st), (modssl_popfree_fn)(free))
 #define sk_X509_value (X509 *)sk_value
+#define sk_X509_shift (X509 *)sk_shift
 #define sk_X509_INFO_free sk_free
 #define sk_X509_INFO_pop_free(st, free) sk_pop_free((STACK*)(st), (modssl_popfree_fn)(free))
 #define sk_X509_INFO_num sk_num

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.c?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.c Fri Aug 17 17:30:46 2012
@@ -382,6 +382,38 @@ BOOL SSL_X509_getCN(apr_pool_t *p, X509 
     return FALSE;
 }
 
+/*
+ * convert an X509_NAME to an RFC 2253 formatted string, optionally truncated
+ * to maxlen characters (specify a maxlen of 0 for no length limit)
+ */
+char *SSL_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, unsigned int maxlen)
+{
+    char *result = NULL;
+    BIO *bio;
+    int len;
+
+    if ((bio = BIO_new(BIO_s_mem())) == NULL)
+        return NULL;
+    X509_NAME_print_ex(bio, dn, 0, XN_FLAG_RFC2253);
+    len = BIO_pending(bio);
+    if (len > 0) {
+        result = apr_palloc(p, maxlen ? maxlen+1 : len+1);
+        if (maxlen && maxlen < len) {
+            len = BIO_read(bio, result, maxlen);
+            if (maxlen > 2) {
+                /* insert trailing ellipsis if there's enough space */
+                apr_snprintf(result + maxlen - 3, 4, "...");
+            }
+        } else {
+            len = BIO_read(bio, result, len);
+        }
+        result[len] = NUL;
+    }
+    BIO_free(bio);
+
+    return result;
+}
+
 /*  _________________________________________________________________
 **
 **  Low-Level CA Certificate Loading

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.h?rev=1374374&r1=1374373&r2=1374374&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.h (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_util_ssl.h Fri Aug 17 17:30:46 2012
@@ -85,6 +85,7 @@ int         SSL_X509_STORE_lookup(X509_S
 char       *SSL_make_ciphersuite(apr_pool_t *, SSL *);
 BOOL        SSL_X509_isSGC(X509 *);
 BOOL        SSL_X509_getBC(X509 *, int *, int *);
+char       *SSL_X509_NAME_to_string(apr_pool_t *, X509_NAME *, unsigned int);
 BOOL        SSL_X509_getCN(apr_pool_t *, X509 *, char **);
 BOOL        SSL_X509_INFO_load_file(apr_pool_t *, STACK_OF(X509_INFO) *, const char *);
 BOOL        SSL_X509_INFO_load_path(apr_pool_t *, STACK_OF(X509_INFO) *, const char *);



Mime
View raw message