SSLv3 draft (5.6.4) and RFC2246 (7.4.4) describe the capability to provide a list a CA distinguished names for defining a desired authorization space. This is currently not possible with mod_ssl. Even though OpenSSL SSL contexts have both a certificate store for client authentication and a stack of CA names for the CertificateRequest handshake message, they are both created from the same set of certificates. This is ok when the list of trusted roots is also the issuer of the client certificates. PROBLEM ======= When the trusted roots issue subordinate (intermediate) CA certificates which in turn issue end entity certificates, there is the possibility that some and not all of the intermediate CA certificates are acceptable for the trusted root. However, if the trusted root is used for the CertificateRequest handshake message, all of its intermediate CA's are acceptable. Of course, if the trusted root is left out, the certificate chain cannot be verified. FIX === Separate and independent control of the CertificateRequest handshake message. Currently, the SSLCACertificateFile and SSLCACertificatePath are used to both define the trust list for client authentication and create the list of CA distinguished names for the CertificateRequest message. By adding a new directive to mod_ssl (SSLCADNRequestPath, SSLCADNRequestFile) that, only when present, will specifically define the set of certificates to derive the client_CA distinguished names in the exact same way as SSLCACertificate*. In this case SSLCACertificate* will only define the trust list. When not present, SSLCACertificate* does double duty as normal. This makes the fix downwardly compatible with existing SSL configurations. PATCH ===== diff -ru httpd-2.0.52-pristine/modules/ssl/mod_ssl.c httpd-2.0.52-patch3/modules/ssl/mod_ssl.c --- httpd-2.0.52-pristine/modules/ssl/mod_ssl.c Mon Aug 23 10:18:54 2004 +++ httpd-2.0.52-patch3/modules/ssl/mod_ssl.c Tue Dec 14 11:27:21 2004 @@ -111,10 +111,16 @@ "(`/path/to/file' - PEM encoded)") SSL_CMD_ALL(CACertificatePath, TAKE1, "SSL CA Certificate path " - "(`/path/to/dir' - contains PEM encoded files)") + "(`/path/to/dir' - contains PEM encoded files for client authentication)") SSL_CMD_ALL(CACertificateFile, TAKE1, "SSL CA Certificate file " - "(`/path/to/file' - PEM encoded)") + "(`/path/to/file' - PEM encoded for client authentication)") + SSL_CMD_ALL(CADNRequestPath, TAKE1, + "SSL CA Distinguished Name path " + "(`/path/to/dir' - symlink hashes to PEM of acceptable CA names to request)") + SSL_CMD_ALL(CADNRequestFile, TAKE1, + "SSL CA Distinguished Name file " + "(`/path/to/file' - PEM encoded to derive acceptable CA names to request)") SSL_CMD_SRV(CARevocationPath, TAKE1, "SSL CA Certificate Revocation List (CRL) path " "(`/path/to/dir' - contains PEM encoded files)") ================================================================================================ diff -ru httpd-2.0.52-pristine/modules/ssl/mod_ssl.h httpd-2.0.52-patch3/modules/ssl/mod_ssl.h --- httpd-2.0.52-pristine/modules/ssl/mod_ssl.h Fri Aug 27 04:03:24 2004 +++ httpd-2.0.52-patch3/modules/ssl/mod_ssl.h Tue Dec 14 11:27:26 2004 @@ -442,6 +442,20 @@ const char *ca_cert_path; const char *ca_cert_file; + /* + * Acceptable CA names for certificateRequest message. (RFC2246) + * These two were added to support specifying a CA name + * list that may or may not include a self-signed root CA. + * This allows the ability to create a limited authorization + * space given the (possible) growth of complex trust hierarchies. + * + * For backward compatibility, if SSLCADNRequest* is not specified + * the default behavior of using SSLCACertificate* for both trust + * and certificateRequest (client_CA list) will occur. + */ + const char *ca_name_path; + const char *ca_name_file; + const char *cipher_suite; /* for client or downstream server authentication */ @@ -502,6 +516,8 @@ int nVerifyDepth; const char *szCACertificatePath; const char *szCACertificateFile; + const char *szCADNRequestPath; + const char *szCADNRequestFile; const char *szUserName; } SSLDirConfigRec; @@ -534,6 +550,8 @@ const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCACertificatePath(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCACertificateFile(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *, void *, const char *); +const char *ssl_cmd_SSLCADNRequestFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCARevocationPath(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLCARevocationFile(cmd_parms *, void *, const char *); const char *ssl_cmd_SSLVerifyClient(cmd_parms *, void *, const char *); ================================================================================================ diff -ru httpd-2.0.52-pristine/modules/ssl/ssl_engine_config.c httpd-2.0.52-patch3/modules/ssl/ssl_engine_config.c --- httpd-2.0.52-pristine/modules/ssl/ssl_engine_config.c Mon Aug 23 10:18:54 2004 +++ httpd-2.0.52-patch3/modules/ssl/ssl_engine_config.c Tue Dec 14 11:27:47 2004 @@ -122,6 +122,8 @@ mctx->auth.ca_cert_path = NULL; mctx->auth.ca_cert_file = NULL; + mctx->auth.ca_name_path = NULL; /* added to support separate control */ + mctx->auth.ca_name_file = NULL; /* of certificate request message. */ mctx->auth.cipher_suite = NULL; mctx->auth.verify_depth = UNSET; mctx->auth.verify_mode = SSL_CVERIFY_UNSET; @@ -217,6 +219,8 @@ cfgMergeString(auth.ca_cert_path); cfgMergeString(auth.ca_cert_file); + cfgMergeString(auth.ca_name_path); + cfgMergeString(auth.ca_name_file); cfgMergeString(auth.cipher_suite); cfgMergeInt(auth.verify_depth); cfgMerge(auth.verify_mode, SSL_CVERIFY_UNSET); @@ -286,6 +290,8 @@ dc->szCACertificatePath = NULL; dc->szCACertificateFile = NULL; + dc->szCADNRequestPath = NULL; + dc->szCADNRequestFile = NULL; dc->szUserName = NULL; return dc; @@ -323,6 +329,8 @@ cfgMergeString(szCACertificatePath); cfgMergeString(szCACertificateFile); + cfgMergeString(szCADNRequestPath); + cfgMergeString(szCADNRequestFile); cfgMergeString(szUserName); return mrg; @@ -825,6 +833,32 @@ sc->server->auth.ca_cert_file = arg; return NULL; +} + +const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *cmd, void *dcfg, const char *arg) { + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_dir(cmd, &arg))) { + return err; + } + + sc->server->auth.ca_name_path = arg; + + return NULL; +} + +const char *ssl_cmd_SSLCADNRequestFile(cmd_parms *cmd, void *dcfg, const char *arg) { + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + + if ((err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + + sc->server->auth.ca_name_file = arg; + + return NULL; } const char *ssl_cmd_SSLCARevocationPath(cmd_parms *cmd, ================================================================================================ diff -ru httpd-2.0.52-pristine/modules/ssl/ssl_engine_init.c httpd-2.0.52-patch3/modules/ssl/ssl_engine_init.c --- httpd-2.0.52-pristine/modules/ssl/ssl_engine_init.c Mon Jun 7 05:18:37 2004 +++ httpd-2.0.52-patch3/modules/ssl/ssl_engine_init.c Thu Dec 9 19:04:04 2004 @@ -532,12 +532,20 @@ ssl_die(); } - ca_list = ssl_init_FindCAList(s, ptemp, + if (mctx->auth.ca_name_file || mctx->auth.ca_name_path) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Configuring certificateRequest message"); + + ca_list = ssl_init_FindCAList(s, ptemp, + mctx->auth.ca_name_file, + mctx->auth.ca_name_path); + } else + ca_list = ssl_init_FindCAList(s, ptemp, mctx->auth.ca_cert_file, mctx->auth.ca_cert_path); if (!ca_list) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Unable to determine list of available " + "Unable to determine list of acceptable " "CA certificates for client authentication"); ssl_die(); } @@ -556,7 +564,7 @@ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Init: Oops, you want to request client " "authentication, but no CAs are known for " - "verification!? [Hint: SSLCACertificate*]"); + "verification!? [Hint: SSLCACertificate*, SSLCADNRequest*]"); } } } @@ -1123,7 +1131,7 @@ if ((rv = apr_dir_open(&dir, ca_path, ptemp)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, - "Failed to open SSLCACertificatePath `%s'", + "Failed to open Certificate Path `%s'", ca_path); ssl_die(); } ================================================================================================ diff -ru httpd-2.0.52-pristine/modules/ssl/ssl_engine_kernel.c httpd-2.0.52-patch3/modules/ssl/ssl_engine_kernel.c --- httpd-2.0.52-pristine/modules/ssl/ssl_engine_kernel.c Mon Aug 23 10:18:55 2004 +++ httpd-2.0.52-patch3/modules/ssl/ssl_engine_kernel.c Thu Dec 9 19:04:04 2004 @@ -470,11 +470,22 @@ /* SSL_free will free cert_store */ SSL_set_cert_store(ssl, cert_store); - if (!(ca_list = ssl_init_FindCAList(r->server, r->pool, - ca_file, ca_path))) + /* + * If no per-dir CADNRequest* is defined, the per-dir + * CACertificate* takes on its default double-duty. + */ + if (MODSSL_CFG_NE(szCADNRequestFile) || + MODSSL_CFG_NE(szCADNRequestPath)) { + ca_file = MODSSL_CFG_CA(szCADNRequestFile); + ca_path = MODSSL_CFG_CA(szCADNRequestPath); + } + + if (!(ca_list = ssl_init_FindCAList(r->server, r->pool, + ca_file, ca_path))) + { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "Unable to determine list of available " + "Unable to determine list of acceptable " "CA certificates for client authentication"); return HTTP_FORBIDDEN;
Thanks for the submission. A trimmed-down version of this patch has been committed to the trunk for future httpd 2.1/2.2 releases. http://svn.apache.org/viewcvs?view=rev&rev=125165 [viewcvs currently accessible] Did you have a docs update for this too, BTW?
I had not done the doc but I can certainly do so. I assume that when I am done, that I should attach here as was done with the code.
That or just send it to docs@httpd.apache.org; ideally as a diff against the XML source. If it's hassle then just sending in some unformatted text would be great.
Created attachment 14160 [details] documentation patch to mod_ssl.xml