Hello,

This is a patch (proposal) to include ssl_c_cert keyword to add client
certificate (in pem format) to backend requests. This is useful for
offloading ssl for applications that need access to client certificate
(for example with something like tomcat sslvalve:
http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/valves/SSLValve.html
and
http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina/7.0.0/org/apache/catalina/valves/SSLValve.java
)

This patch should be compatible with apache/mod_ssl
(RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s") 
(newlines in the pem cert are replaced with space chars).

(pound / nginx use different formatting for the cert:
X-SSL-certificate: -----BEGIN CERTIFICATE-----
\t...
\t-----END CERTIFICATE-----).

The code to replace newlines with spaces is not optimized. If there's a
guarantee that openssl PEM_write_bio_X509 will always format the pem
cert in same way(
-----BEGIN CERTIFICATE-----
MIIEoTCCA4mgAwIBAgIQIHCGEzfaVEFkF5d4JxstDTANBgkqhkiG9w0BAQUFADA2
....
r8q5R89n4IPaS0DaE4I+/W15CPs/AUlkUh6vy2v+PY+WRlie6g==
-----END CERTIFICATE-----) --> are the base64 encoded lines always 64chars
(except the last line) ?

--> the loop could be optimized to start from pos 27 (end of BEGIN line)
and jump 65 chars until end of last line.

Is this something that could be included in haproxy ?
(The patch is against haproxy-ss-20140501).

-Jarno
diff -ur haproxy-ss-20140501/src/ssl_sock.c 
haproxy-ss-20140501.new/src/ssl_sock.c
--- haproxy-ss-20140501/src/ssl_sock.c  2014-04-30 23:31:11.000000000 +0300
+++ haproxy-ss-20140501.new/src/ssl_sock.c      2014-05-06 13:29:11.620045574 
+0300
@@ -2387,6 +2387,74 @@
        return 1;
 }
 
+/* str, returns the client certificate in pem format. \n chars are
+   replaced with <SPC> (like apache mod_ssl/mod_header). */
+static int
+smp_fetch_ssl_c_cert(struct proxy *px, struct session *l4, void *l7, unsigned 
int opt,
+                        const struct arg *args, struct sample *smp, const char 
*kw)
+{
+       int ret = 0;
+       int i;
+       X509 *crt;
+       BIO *bio;
+       int len;
+       struct chunk *smp_trash;
+       struct connection *conn;
+
+       if (!l4)
+               return 0;
+
+       conn = objt_conn(l4->si[0].end);
+       if (!conn || conn->xprt != &ssl_sock)
+               return 0;
+
+       if (!(conn->flags & CO_FL_CONNECTED)) {
+               smp->flags |= SMP_F_MAY_CHANGE;
+               return 0;
+       }
+
+       /* SSL_get_peer_certificate increase X509 * ref count  */
+       crt = SSL_get_peer_certificate(conn->xprt_ctx);
+       if (!crt)
+               return 0;
+
+       bio = BIO_new(BIO_s_mem());
+
+       if (bio == NULL) {
+               X509_free(crt);
+               return 0;
+       }
+
+       if (!PEM_write_bio_X509(bio, crt))
+               goto end;
+
+       len = BIO_pending(bio);
+       smp_trash = get_trash_chunk();
+
+       if ((len < 0) || (len >= smp_trash->size))
+               goto end;
+
+       if ((len = BIO_read(bio, smp_trash->str, len)) <= 0)
+               goto end;
+
+       /* Tomcat SSLValve expects spaces instead of newlines. */
+       for (i=0; i < len; i++) {
+               if (smp_trash->str[i] == '\n')
+                       smp_trash->str[i] = ' ';
+       }
+
+       smp->data.str.str = smp_trash->str;
+       smp->type = SMP_T_STR;
+       smp->data.str.len = len;
+       ret = 1;
+
+end:
+       X509_free(crt);
+       BIO_free(bio);
+       return ret;
+}
+
+
 /* boolean, returns true if front conn. transport layer is SSL.
  * This function is also usable on backend conn if the fetch keyword 5th
  * char is 'b'.
@@ -3407,6 +3475,7 @@
        { "ssl_bc_session_id",      smp_fetch_ssl_fc_session_id,  0,            
       NULL,    SMP_T_BIN,  SMP_USE_L5SRV },
        { "ssl_c_ca_err",           smp_fetch_ssl_c_ca_err,       0,            
       NULL,    SMP_T_UINT, SMP_USE_L5CLI },
        { "ssl_c_ca_err_depth",     smp_fetch_ssl_c_ca_err_depth, 0,            
       NULL,    SMP_T_UINT, SMP_USE_L5CLI },
+       { "ssl_c_cert",             smp_fetch_ssl_c_cert,         0,            
       NULL,    SMP_T_STR,  SMP_USE_L5CLI },
        { "ssl_c_err",              smp_fetch_ssl_c_err,          0,            
       NULL,    SMP_T_UINT, SMP_USE_L5CLI },
        { "ssl_c_i_dn",             smp_fetch_ssl_x_i_dn,         
ARG2(0,STR,SINT),    NULL,    SMP_T_STR,  SMP_USE_L5CLI },
        { "ssl_c_key_alg",          smp_fetch_ssl_x_key_alg,      0,            
       NULL,    SMP_T_STR,  SMP_USE_L5CLI },

Reply via email to