This directive controls whether the client's SSL certificate chain (the
+client's certificate and all intermediate certificates) or only the client's
+certificate (without any intermediate certificates) will be sent to the AJP
+server when proxying an incoming SSL connection. If on
, the SSL
+certificate chain will be sent.
This is disabled by default because the default AJP message buffers in both +mod_proxy_ajp and Tomcat are not large enough to hold a long certificate chain +(more than 1 or 2 intermediate certificates), so clients having a long chain +will get errors if this is enabled without first adjusting the AJP message +buffer sizes appropriately.
+To adjust the AJP message buffer size in mod_proxy_ajp, use the
+
To adjust the AJP message buffer size in Tomcat, specify the
+packetSize
attribute in the AJP connector declaration. The same
+buffer size should be used for both mod_proxy_ajp and Tomcat.
Note that support for processing of intermediate certificates is only
+available in Tomcat 5.5.28+ and 6.0.21+ (earlier versions will simply ignore
+the intermediate certificates in the AJP request), and the
+packetSize
attribute is only available in Tomcat 5.5.20+ and
+6.0.2+ (earlier versions had a fixed buffer size of 8192 bytes).
The AJP13
protocol is packet-oriented. A binary format
was presumably chosen over the more readable plain text for reasons of
Index: modules/proxy/ajp_config.h
===================================================================
--- modules/proxy/ajp_config.h (revision 0)
+++ modules/proxy/ajp_config.h (revision 0)
@@ -0,0 +1,47 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AJP_CONFIG_H
+#define AJP_CONFIG_H
+
+/**
+ * @file ajp_config.h
+ * @brief AJP internal configuration management.
+ *
+ * @defgroup AJP_config AJP configuration
+ * @ingroup MOD_PROXY
+ * @{
+ */
+
+#ifndef BOOL
+#define BOOL unsigned char
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+typedef struct {
+ BOOL send_cert_chain;
+ BOOL send_cert_chain_set;
+} proxy_ajp_conf;
+
+extern module AP_MODULE_DECLARE_DATA proxy_ajp_module;
+
+#endif /*AJP_CONFIG_H*/
+/** @} */
Index: modules/proxy/ajp.h
===================================================================
--- modules/proxy/ajp.h (revision 943568)
+++ modules/proxy/ajp.h (working copy)
@@ -61,6 +61,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_CHAIN_PREFIX "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"
Index: modules/proxy/mod_proxy_ajp.c
===================================================================
--- modules/proxy/mod_proxy_ajp.c (revision 943568)
+++ modules/proxy/mod_proxy_ajp.c (working copy)
@@ -18,9 +18,47 @@
#include "mod_proxy.h"
#include "ajp.h"
+#include "ajp_config.h"
module AP_MODULE_DECLARE_DATA proxy_ajp_module;
+static void *create_proxy_ajp_config(apr_pool_t *p, server_rec *s)
+{
+ proxy_ajp_conf *c = apr_pcalloc(p, sizeof(proxy_ajp_conf));
+ c->send_cert_chain = FALSE;
+ c->send_cert_chain_set = FALSE;
+ return c;
+}
+
+static void *merge_proxy_ajp_config(apr_pool_t *p, void *basev, void *overridesv)
+{
+ proxy_ajp_conf *c = apr_pcalloc(p, sizeof(proxy_ajp_conf));
+ proxy_ajp_conf *base = (proxy_ajp_conf *) basev;
+ proxy_ajp_conf *overrides = (proxy_ajp_conf *) overridesv;
+ c->send_cert_chain = (overrides->send_cert_chain_set ?
+ overrides->send_cert_chain : base->send_cert_chain);
+ c->send_cert_chain_set = (base->send_cert_chain_set ||
+ overrides->send_cert_chain_set);
+ return c;
+}
+
+static const char *
+ set_forward_cert_chain(cmd_parms *params, void *dummy, const char *arg)
+{
+ proxy_ajp_conf *c =
+ ap_get_module_config(params->server->module_config, &proxy_ajp_module);
+
+ if (strcasecmp(arg, "Off") == 0)
+ c->send_cert_chain = FALSE;
+ else if (strcasecmp(arg, "On") == 0)
+ c->send_cert_chain = TRUE;
+ else
+ return "ProxyAJPForwardSSLCertChain must be one of: On | Off";
+
+ c->send_cert_chain_set = TRUE;
+ return NULL;
+}
+
/*
* Canonicalise http-like URLs.
* scheme is the scheme for the URL
@@ -724,13 +762,21 @@
proxy_hook_canon_handler(proxy_ajp_canon, NULL, NULL, APR_HOOK_FIRST);
}
+static const command_rec proxy_ajp_cmds[] =
+{
+ AP_INIT_TAKE1("ProxyAJPForwardSSLCertChain", set_forward_cert_chain, NULL,
+ RSRC_CONF, "Forward the entire SSL Certificate Chain "
+ "('on', 'off')"),
+ {NULL}
+};
+
module AP_MODULE_DECLARE_DATA proxy_ajp_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
- NULL, /* create per-server config structure */
- NULL, /* merge per-server config structures */
- NULL, /* command apr_table_t */
+ create_proxy_ajp_config, /* create per-server config structure */
+ merge_proxy_ajp_config, /* merge per-server config structures */
+ proxy_ajp_cmds, /* command apr_table_t */
ap_proxy_http_register_hook /* register hooks */
};
Index: modules/proxy/ajp_header.c
===================================================================
--- modules/proxy/ajp_header.c (revision 943568)
+++ modules/proxy/ajp_header.c (working copy)
@@ -16,6 +16,7 @@
#include "ajp_header.h"
#include "ajp.h"
+#include "ajp_config.h"
static const char *response_trans_headers[] = {
"Content-Type",
@@ -200,7 +201,7 @@
?auth_type (byte)(string)
?query_string (byte)(string)
?jvm_route (byte)(string)
- ?ssl_cert (byte)(string)
+ ?ssl_certs (byte)(string)
?ssl_cipher (byte)(string)
?ssl_session (byte)(string)
?ssl_key_size (byte)(int) via JkOptions +ForwardKeySize
@@ -220,6 +221,8 @@
const char *session_route, *envvar;
const apr_array_header_t *arr = apr_table_elts(r->subprocess_env);
const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts;
+ proxy_ajp_conf *sc =
+ ap_get_module_config(r->server->module_config, &proxy_ajp_module);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"Into ajp_marshal_into_msgb");
@@ -356,6 +359,24 @@
if ((envvar = ap_proxy_ssl_val(r->pool, r->server, r->connection, r,
AJP13_SSL_CLIENT_CERT_INDICATOR))
&& envvar[0]) {
+ /* If ProxyAJPForwardSSLCertChain is set, send the entire chain */
+ if (sc->send_cert_chain) {
+ apr_array_header_t *certs = apr_array_make(r->pool, 1, sizeof(char *));
+ int i = 0;
+ char *envvar_name;
+ do {
+ *(const char **)apr_array_push(certs) = envvar;
+ envvar_name = apr_psprintf(r->pool, "%s%d",
+ AJP13_SSL_CLIENT_CHAIN_PREFIX, i);
+ envvar = ap_proxy_ssl_val(r->pool, r->server, r->connection, r,
+ envvar_name);
+ i++;
+ } while (envvar && envvar[0]);
+ envvar = apr_array_pstrcat(r->pool, certs, '\0');
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "ajp_marshal_into_msgb: SSL Client Cert Chain "
+ "(%d certs)", i-1);
+ }
if (ajp_msg_append_uint8(msg, SC_A_SSL_CERT)
|| ajp_msg_append_string(msg, envvar)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
@@ -363,6 +384,8 @@
"Error appending the SSL certificates");
return AJP_EOVERFLOW;
}
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "ajp_marshal_into_msgb: SSL Client Cert");
}
if ((envvar = ap_proxy_ssl_val(r->pool, r->server, r->connection, r,