On 03.09.2011 22:39, Daniel Ruggeri wrote:
> updated method I'm using. Rather than storing the chain as
> STACK_OF(X509_INFO) I have switched to STACK_OF(X509) and am using the
> following function to build the chain.
> Comments are definitely appreciated as I don't have a very good frame of
> reference for using X509_verify_cert().

Switching to STACK_OF(X509) is the right thing, yes (you don't need
X509_INFO and its additional fields for the CA certs). After having
looked at ssl_init_proxy_certs() and ssl_callback_proxy_cert() a bit
more closely, I think some additional changes might be needed.

Thanks to your patch, ssl_callback_proxy_cert() will now pick the proper
cert even if the ca_list does not include the DN of the CA which signed
the cert, which is definitely an improvement. There's still one
drawback, though, IINM: for proxy connections, mod_ssl currently won't
include the intermediate CA certs of its client cert(s) in outgoing
connections.

As SSL_CTX_set_client_cert_cb(3) states:

       The client_cert_cb() cannot return a complete certificate
       chain, it can only return one client certificate. If the
       chain only has a length of 2, the root CA certificate may
       be omitted according to the TLS standard and thus a stan-
       dard conforming answer can be sent to the server. For a
       longer chain, the client must send the complete chain
       (with the option to leave out the root CA certificate).
       This can only be accomplished by either adding the inter-
       mediate CA certificates into the trusted certificate
       store for the SSL_CTX object (resulting in having to add
       CA certificates that otherwise maybe would not be
       trusted), or by adding the chain certificates using the
       SSL_CTX_add_extra_chain_cert(3) function, which is only
       available for the SSL_CTX object as a whole and that
       therefore probably can only apply for one client certifi-
       cate, making the concept of the callback function (to
       allow the choice from several certificates) questionable.

SSL_CTX_add_extra_chain_cert() isn't an option for us, I assume, so the
best we can probably do in ssl_init_proxy_certs()) is to load the certs
specified via ProxyMachineCertificateChainFile with
X509_STORE_load_locations and rely on OpenSSL's "auto chain building"
afterwards.

Populating the mctx->pkp->ca_certs stacks is still required, however,
since these are needed in the callback to figure out the correct client
cert.

Attached is an *untested* patch which hopefully gives you an idea of the
approach I'm suggesting (you might still want to separate the chain
building into a function of its own, I simply left t inline in
ssl_init_proxy_certs for easier editing). Not sure if it works, but
would appreciate if you could give it a try.

Kaspar
Index: ssl_engine_init.c
===================================================================
--- ssl_engine_init.c   (revision 1165347)
+++ ssl_engine_init.c   (working copy)
@@ -1115,7 +1115,9 @@ static void ssl_init_proxy_certs(server_rec *s,
     int n, ncerts = 0;
     STACK_OF(X509_INFO) *sk;
     modssl_pk_proxy_t *pkp = mctx->pkp;
-    STACK_OF(X509_INFO) *chain;
+    STACK_OF(X509) *chain;
+    X509_STORE_CTX *sctx;
+    X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
 
     SSL_CTX_set_client_cert_cb(mctx->ssl_ctx,
                                ssl_callback_proxy_cert);
@@ -1161,29 +1163,41 @@ static void ssl_init_proxy_certs(server_rec *s,
                  ncerts);
     pkp->certs = sk;
 
-    if (!pkp->ca_cert_file) {
+    if (!pkp->ca_cert_file || !store) {
         return;
     }
 
-    /* Load all of the CA certs and construct a chain */
-    sk = sk_X509_INFO_new_null();
+    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(SSLLOG_MARK, APLOG_EMERG, s);
+        ssl_die();
+    }
 
-    SSL_X509_INFO_load_file(ptemp, sk, pkp->ca_cert_file);
-    pkp->ca_certs = (STACK_OF(X509_INFO) **) apr_pcalloc(p, ncerts * 
sizeof(sk));
-
+    X509_STORE_load_locations(store, pkp->ca_cert_file, NULL);
+    
     for (n = 0; n < ncerts; n++) {
-        int len;
+        int i, 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);
+
+        X509_STORE_CTX_init(sctx, store, inf->x509, NULL);
+        X509_verify_cert(sctx);
+        ERR_clear_error();
+       
+        chain = sk_X509_new_null();
+        for (i = 0; i < sk_X509_num(sctx->chain); i++) {
+           sk_X509_push(chain, sk_X509_value(sctx->chain, i));
+        }
         pkp->ca_certs[n] = chain;
 
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                      "client certificate %i has loaded %i "
-                     "intermediary signers ", n, len);
+                     "intermediate CAs", n, i);
     }
 
     sk_X509_INFO_free(sk);
+    X509_STORE_CTX_free(sctx);
 }
 
 static void ssl_init_proxy_ctx(server_rec *s,

Reply via email to