You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Bruno Harbulot <Br...@manchester.ac.uk> on 2008/09/30 13:22:57 UTC
mod_ssl, SSL_CLIENT_CERT_CHAIN, mod_proxy_ajp and full chain of client
certificates
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.
Re: mod_ssl, SSL_CLIENT_CERT_CHAIN, mod_proxy_ajp and full chain
of client certificates
Posted by Bruno Harbulot <Br...@manchester.ac.uk>.
Hello,
I thought that Tomcat (at least recent versions) was able to get the
full chain, but I guess I was wrong.
I'm in fact using Jetty behind mod_jk, and it exposes the full chain of
certificates in the "javax.servlet.request.X509Certificate" request
attribute, as expected (I am using "JkOptions +ForwardSSLCertChain").
The version of mod_jk I'm using is that shipped with Ubuntu 8.04, so
it's mod_jk 1.2.25. As far as I can tell, it hasn't been patched for
this. I've also tried it successfully with the version shipped with CentOS.
I was getting the impression that mod_jk was being deprecated in favour
of mod_proxy_ajp. I've also experienced intermittent connection problems
between Apache Httpd and the Jetty-based application I'm using. These
problems could be due to many things, including the way I've deployed
the system, so I've tried to investigate it by using mod_proxy_ajp
instead of mod_jk.
Best wishes,
Bruno.
Bill Barker wrote:
> 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" <Br...@manchester.ac.uk> wrote in message
> news:gbt26i$9p2$1@ger.gmane.org...
>> 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.
Re: mod_ssl, SSL_CLIENT_CERT_CHAIN, mod_proxy_ajp and full chain
of client certificates
Posted by Bruno Harbulot <Br...@manchester.ac.uk>.
Mladen Turk wrote:
> Bill Barker wrote:
>>
>> 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 :).
>>
>
> Right, I'll prepare something for mod_proxy as well.
> It is on my TODO list for a long time.
Thank you. As I was saying in my previous message on this list [*], I've
been able to get the full chain of certificates with mod_jk successfully
with Jetty. One of the reasons I wanted to change is that the Jetty team
now recommends using mod_proxy.
In fact, they also suggest using mod_proxy_http rather than mod_proxy_ajp.
For this, I think getting the full chain of certificate would require a
variable in mod_ssl (for example SSL_CLIENT_CERT_CHAIN as it's done
using my patch, or something else and/or a better patch), combined with
a custom header via mod_headers. Of course, this would also require the
reverse proxy to clear such a user-provided request header, if present,
to avoid spoofing. I suppose this could be useful for other containers
behind a reverse proxy, even if they don't support AJP.
Best wishes,
Bruno.
[*]
http://mail-archives.apache.org/mod_mbox/httpd-dev/200810.mbox/%3Cgcd6qb$9hg$1@ger.gmane.org%3E
Re: mod_ssl, SSL_CLIENT_CERT_CHAIN, mod_proxy_ajp and full chain
of client certificates
Posted by Mladen Turk <mt...@apache.org>.
Bill Barker wrote:
>
> 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 :).
>
Right, I'll prepare something for mod_proxy as well.
It is on my TODO list for a long time.
Regards
--
^(TM)
Re: mod_ssl, SSL_CLIENT_CERT_CHAIN, mod_proxy_ajp and full chain of client certificates
Posted by Bill Barker <wb...@wilshire.com>.
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" <Br...@manchester.ac.uk> wrote in message
news:gbt26i$9p2$1@ger.gmane.org...
> 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);
>