I've noticed that sending CA chains (of potentially untrusted
certificates), with a client certificate on a per-connection basis is
currently impossible, as per the BUGS section of the
SSL_CTX_set_client_cert_cb(3) page and bug #270 in the request tracker.
 This doesn't seem to be a difficult change (but it does change the size
of the SSL structure), and I was wondering if something like the
attached patch could be included in future releases.

Note that this isn't currently tested, but if it looks OK I can check it
actually works properly (and write my code using it :) ).

Thanks

-- 
Andrew Oakley
diff -ur openssl-1.0.0-beta3/include/openssl/ssl.h 
openssl-1.0.0-beta3-extra-certs/include/openssl/ssl.h
--- openssl-1.0.0-beta3/include/openssl/ssl.h   2009-07-15 12:32:57.000000000 
+0100
+++ openssl-1.0.0-beta3-extra-certs/include/openssl/ssl.h       2009-09-03 
16:21:37.000000000 +0100
@@ -1106,6 +1106,8 @@
        /* for server side, keep the list of CA_dn we can use */
        STACK_OF(X509_NAME) *client_CA;
 
+       STACK_OF(X509) *extra_certs;
+
        int references;
        unsigned long options; /* protocol behaviour */
        unsigned long mode; /* API behaviour */
@@ -1426,6 +1428,9 @@
 #define SSL_CTX_add_extra_chain_cert(ctx,x509) \
        SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
 
+#define SSL_add_extra_chain_cert(ctx,x509) \
+       SSL_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
+
 #ifndef OPENSSL_NO_BIO
 BIO_METHOD *BIO_f_ssl(void);
 BIO *BIO_new_ssl(SSL_CTX *ctx,int client);
diff -ur openssl-1.0.0-beta3/ssl/d1_both.c 
openssl-1.0.0-beta3-extra-certs/ssl/d1_both.c
--- openssl-1.0.0-beta3/ssl/d1_both.c   2009-07-15 12:32:57.000000000 +0100
+++ openssl-1.0.0-beta3-extra-certs/ssl/d1_both.c       2009-09-03 
16:25:41.000000000 +0100
@@ -837,6 +837,7 @@
        int i;
        unsigned long l= 3 + DTLS1_HM_HEADER_LENGTH;
        BUF_MEM *buf;
+       STACK_OF(X509) *extras;
 
        /* TLSv1 sends a chain with nothing in it, instead of an alert */
        buf=s->init_buf;
@@ -868,10 +869,14 @@
                        }
                X509_STORE_CTX_cleanup(&xs_ctx);
                }
-       /* Thawte special :-) */
-       for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++)
+
+       if (s->extra_certs)
+               extras = s->extra_certs;
+       else
+               extras = s->ctx->extra_certs;
+       for (i=0; i<sk_X509_num(extras); i++)
                {
-               x=sk_X509_value(s->ctx->extra_certs,i);
+               x=sk_X509_value(extras,i);
                if (!dtls1_add_cert_to_buf(buf, &l, x))
                        return 0;
                }
diff -ur openssl-1.0.0-beta3/ssl/s3_both.c 
openssl-1.0.0-beta3-extra-certs/ssl/s3_both.c
--- openssl-1.0.0-beta3/ssl/s3_both.c   2009-07-15 12:32:57.000000000 +0100
+++ openssl-1.0.0-beta3-extra-certs/ssl/s3_both.c       2009-09-03 
16:00:50.000000000 +0100
@@ -288,8 +288,14 @@
        unsigned long l=7;
        BUF_MEM *buf;
        int no_chain;
+    STACK_OF(X509) *extras;
 
-       if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || s->ctx->extra_certs)
+    if (s->extra_certs)
+        extras = s->extra_certs;
+    else
+        extras = s->ctx->extra_certs;
+
+       if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extras)
                no_chain = 1;
        else
                no_chain = 0;
@@ -332,9 +338,9 @@
                        }
                }
        /* Thawte special :-) */
-       for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++)
+       for (i=0; i<sk_X509_num(extras); i++)
                {
-               x=sk_X509_value(s->ctx->extra_certs,i);
+               x=sk_X509_value(extras,i);
                if (ssl3_add_cert_to_buf(buf, &l, x))
                        return(0);
                }
diff -ur openssl-1.0.0-beta3/ssl/s3_lib.c 
openssl-1.0.0-beta3-extra-certs/ssl/s3_lib.c
--- openssl-1.0.0-beta3/ssl/s3_lib.c    2009-05-28 19:10:47.000000000 +0100
+++ openssl-1.0.0-beta3-extra-certs/ssl/s3_lib.c        2009-09-03 
16:16:29.000000000 +0100
@@ -2477,6 +2477,16 @@
                break;
 
 #endif /* !OPENSSL_NO_TLSEXT */
+
+       case SSL_CTRL_EXTRA_CHAIN_CERT:
+               if (s->extra_certs == NULL)
+                       {
+                       if ((s->extra_certs=sk_X509_new_null()) == NULL)
+                               return(0);
+                       }
+               sk_X509_push(s->extra_certs,(X509 *)parg);
+               break;
+
        default:
                break;
                }
diff -ur openssl-1.0.0-beta3/ssl/ssl.h openssl-1.0.0-beta3-extra-certs/ssl/ssl.h
--- openssl-1.0.0-beta3/ssl/ssl.h       2009-07-15 12:32:57.000000000 +0100
+++ openssl-1.0.0-beta3-extra-certs/ssl/ssl.h   2009-09-03 16:21:37.000000000 
+0100
@@ -1106,6 +1106,8 @@
        /* for server side, keep the list of CA_dn we can use */
        STACK_OF(X509_NAME) *client_CA;
 
+       STACK_OF(X509) *extra_certs;
+
        int references;
        unsigned long options; /* protocol behaviour */
        unsigned long mode; /* API behaviour */
@@ -1426,6 +1428,9 @@
 #define SSL_CTX_add_extra_chain_cert(ctx,x509) \
        SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
 
+#define SSL_add_extra_chain_cert(ctx,x509) \
+       SSL_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
+
 #ifndef OPENSSL_NO_BIO
 BIO_METHOD *BIO_f_ssl(void);
 BIO *BIO_new_ssl(SSL_CTX *ctx,int client);
diff -ur openssl-1.0.0-beta3/ssl/ssl_lib.c 
openssl-1.0.0-beta3-extra-certs/ssl/ssl_lib.c
--- openssl-1.0.0-beta3/ssl/ssl_lib.c   2009-06-30 12:57:24.000000000 +0100
+++ openssl-1.0.0-beta3-extra-certs/ssl/ssl_lib.c       2009-09-03 
16:28:23.000000000 +0100
@@ -357,6 +357,9 @@
 
        s->verify_result=X509_V_OK;
 
+       s->client_CA = NULL;
+       s->extra_certs = NULL;
+
        s->method=ctx->method;
 
        if (!s->method->ssl_new(s))
@@ -577,6 +580,8 @@
 
        if (s->client_CA != NULL)
                sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
+       if (s->extra_certs != NULL)
+               sk_X509_pop_free(s->extra_certs,X509_free);
 
        if (s->method != NULL) s->method->ssl_free(s);
 
@@ -2393,6 +2398,7 @@
        {
        STACK_OF(X509_NAME) *sk;
        X509_NAME *xn;
+       X509 *x;
        SSL *ret;
        int i;
        
@@ -2510,6 +2516,20 @@
                        }
                }
 
+       if (s->extra_certs != NULL)
+               {
+               if ((ret->extra_certs=sk_X509_dup(s->extra_certs)) == NULL) 
goto err;
+               for (i=0; i<sk_X509_num(s->extra_certs); i++)
+                       {
+                       x=sk_X509_value(s->extra_certs,i);
+                       if (sk_X509_set(s->extra_certs,i,X509_dup(x)) == NULL)
+                               {
+                               X509_free(x);
+                               goto err;
+                               }
+                       }
+               }
+
        if (0)
                {
 err:

Reply via email to