Yes, while mod_jk has an option to send the cert chain (added a little over 18 months ago by mturk), no Tomcat connector has an option to read it. As a result, Tomcat will read the end certificate and ignore the rest of the chain.
This is because the AJP/1.3 protocol was created back in the days of Servlet-2.2 (corresponding to Tomcat 3.x) and back then only the end certificate was exposed by the Servlet-API. Mladen's patch to mod_jk is simplier than this one, so I would prefer it to this one. But I have no voting rights on this list :). "Bruno Harbulot" <[EMAIL PROTECTED]> wrote in message news:[EMAIL PROTECTED] > Hello, > > I'm trying to use mod_proxy_ajp instead of mod_jk, but I'd like to be > able to pass the whole client certificate chain, instead of only the end > certificate. The servlet specification allows for a chain of > certificates to be presented and this is indeed possible with mod_jk, > using "JkOptions +ForwardSSLCertChain". > > This doesn't seem to be possible using mod_proxy_ajp, which uses the > content of the SSL_CLIENT_CERT variable only. > > I thought I would be able to pass the chain using mod_headers. > Unfortunately, there doesn't seem to be a mod_ssl variable that > represents the whole chain. There is a set of variables called > SSL_CLIENT_CERT_CHAIN_n (where n is an integer), but they have to be > named individually. > > I'm attaching the patch I've written to provide a variable called > SSL_CLIENT_CERT_CHAIN, which is the concatenation of all the > certificates in the chain, in PEM format. (It also sets > SSL_CLIENT_CERT_CHAIN_0 when there's no chain available but just one > certificate.) > > A few tests with mod_headers "RequestHeader set X-ClientCertChain > %{SSL_CLIENT_CERT_CHAIN}s" seem to indicate that it works. > > However, I've also tried to modify mod_proxy_ajp to send the whole > chain, but this doesn't work: > > --- a/modules/proxy/ajp.h > +++ b/modules/proxy/ajp.h > @@ -60,7 +60,7 @@ > > /* The following environment variables match mod_ssl! */ > #define AJP13_HTTPS_INDICATOR "HTTPS" > -#define AJP13_SSL_CLIENT_CERT_INDICATOR "SSL_CLIENT_CERT" > +#define AJP13_SSL_CLIENT_CERT_INDICATOR "SSL_CLIENT_CERT_CHAIN" > #define AJP13_SSL_CIPHER_INDICATOR "SSL_CIPHER" > #define AJP13_SSL_SESSION_INDICATOR "SSL_SESSION_ID" > #define AJP13_SSL_KEY_SIZE_INDICATOR "SSL_CIPHER_USEKEYSIZE" > > This patch has been made against the svn trunk, rev 695234. > > > I'm aware that my knowledge of the Apache Httpd code is limited, so this > patch is likely to need improvements (there's obviously something wrong > since my modification to mod_proxy_ajp doesn't work). > I'd appreciate any comments and suggestions. > > > Best wishes, > > Bruno. > -------------------------------------------------------------------------------- > diff --git a/modules/ssl/ssl_engine_kernel.c > b/modules/ssl/ssl_engine_kernel.c > index e938d05..894bef8 100644 > --- a/modules/ssl/ssl_engine_kernel.c > +++ b/modules/ssl/ssl_engine_kernel.c > @@ -1157,6 +1157,11 @@ int ssl_hook_Fixup(request_rec *r) > apr_table_setn(env, var, val); > } > } > + } else { > + val = ssl_var_lookup(r->pool, r->server, r->connection, > + r, "SSL_CLIENT_CERT"); > + > + apr_table_setn(env, "SSL_CLIENT_CERT_CHAIN_0", val); > } > } > > diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c > index 3d688cd..e191ddd 100644 > --- a/modules/ssl/ssl_engine_vars.c > +++ b/modules/ssl/ssl_engine_vars.c > @@ -46,6 +46,7 @@ static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t > *p, ASN1_UTCTIME *tm); > static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs); > static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) > *sk, char *var); > static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs); > +static char *ssl_var_lookup_ssl_cert_chain_PEM(apr_pool_t *p, > STACK_OF(X509) *sk); > static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c); > static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, conn_rec *c, char > *var); > static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int > *algkeysize); > @@ -300,6 +301,10 @@ static char *ssl_var_lookup_ssl(apr_pool_t *p, > conn_rec *c, char *var) > else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) > { > result = ssl_var_lookup_ssl_cipher(p, c, var+6); > } > + else if (ssl != NULL && strcEQ(var, "CLIENT_CERT_CHAIN")) { > + sk = SSL_get_peer_cert_chain(ssl); > + result = ssl_var_lookup_ssl_cert_chain(p, sk, NULL); > + } > else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, > "CLIENT_CERT_CHAIN_", 18)) { > sk = SSL_get_peer_cert_chain(ssl); > result = ssl_var_lookup_ssl_cert_chain(p, sk, var+18); > @@ -550,13 +555,18 @@ static char > *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, ch > > result = NULL; > > - if (strspn(var, "0123456789") == strlen(var)) { > - n = atoi(var); > - if (n < sk_X509_num(sk)) { > - xs = sk_X509_value(sk, n); > - result = ssl_var_lookup_ssl_cert_PEM(p, xs); > + if (var != NULL) { > + if (strspn(var, "0123456789") == strlen(var)) { > + n = atoi(var); > + if (n < sk_X509_num(sk)) { > + xs = sk_X509_value(sk, n); > + result = ssl_var_lookup_ssl_cert_PEM(p, xs); > + } > } > } > + else { > + result = ssl_var_lookup_ssl_cert_chain_PEM(p, sk); > + } > > return result; > } > @@ -578,6 +588,28 @@ static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t > *p, X509 *xs) > return result; > } > > +static char *ssl_var_lookup_ssl_cert_chain_PEM(apr_pool_t *p, > STACK_OF(X509) *sk) > +{ > + char *result; > + BIO *bio; > + X509 *xs; > + int n; > + int i; > + > + if ((bio = BIO_new(BIO_s_mem())) == NULL) > + return NULL; > + for (i=0; i < sk_X509_num(sk); i++) { > + xs = sk_X509_value(sk, i); > + PEM_write_bio_X509(bio, xs); > + } > + n = BIO_pending(bio); > + result = apr_pcalloc(p, n+1); > + n = BIO_read(bio, result, n); > + result[n] = NUL; > + BIO_free(bio); > + return result; > +} > + > static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c) > { > SSLConnRec *sslconn = myConnConfig(c); >