Index: docs/manual/mod/mod_ssl.xml =================================================================== --- docs/manual/mod/mod_ssl.xml (revision 935069) +++ docs/manual/mod/mod_ssl.xml (working copy) @@ -83,7 +83,7 @@ SSL_CLIENT_A_KEY string Algorithm used for the public key of client's certificate SSL_CLIENT_CERT string PEM-encoded client certificate SSL_CLIENT_CERT_CHAIN_n string PEM-encoded certificates in client certificate chain -SSL_CLIENT_VERIFY string NONE, SUCCESS, GENEROUS or FAILED:reason +SSL_CLIENT_VERIFY string NONE, SUCCESS, GENEROUS:reason or FAILED:reason SSL_SERVER_M_VERSION string The version of the server certificate SSL_SERVER_M_SERIAL string The serial of the server certificate SSL_SERVER_S_DN string Subject DN in server's certificate @@ -869,6 +869,13 @@ specify an all-in-one file containing a concatenation of PEM-encoded CA certificates.

+

For testing purposes, any available certificate (signed by any CA) +may be requested by specifying a file containing only a single space +character. However note that while this trick happens to work with +most browsers, the SSL/TLS standards do not define the appropriate +behavior when the set of acceptable CA names is empty, so this is not +guaranteed to work with all browsers.

+ Example SSLCADNRequestFile /usr/local/apache2/conf/ca-names.crt @@ -966,31 +973,58 @@

-This directive sets the Certificate verification level for the Client +This directive sets the Certificate verification level for Client Certificate Authentication. Notice that this directive can be used both in per-server and per-directory context. In per-server context it applies to the client -authentication process used in the standard SSL handshake when a connection is +authentication process in the initial SSL handshake when a connection is established. In per-directory context it forces a SSL renegotation with the -reconfigured client verification level after the HTTP request was read but +reconfigured client verification level after the HTTP request is read but before the HTTP response is sent.

The following levels are available for level:

-

In practice only levels none and -require are really interesting, because level -optional doesn't work with all browsers and level -optional_no_ca is actually against the idea of -authentication (but can be used to establish SSL test pages, etc.)

+

In practice, most users will want either none or +require, as the other levels allow users to bypass the +authentication mechanism. However, the other levels may be useful for testing, +or if your web application does it's own Certificate verification.

+

See the SSLCADNRequestFile and +SSLCADNRequestPath directives to +configure the list of acceptable CA Certificates, and see the +SSLCACertificateFile and +SSLCACertificatePath directives to +configure the list of trusted CA Certificates.

+

Note that if SSLv2 is used with one of the optional levels +and no Certificate signed by one of the acceptable CA Certificates is available, +the browser may give up and disconnect rather than continuing without providing +a Certificate. If SSLv3 or TLS are used, the browser should always either +provide a Certificate or attempt to continue without a Certificate.

Example SSLVerifyClient require @@ -1420,41 +1454,38 @@ SSLProxyVerify level SSLProxyVerify none server config -virtual host -directory -.htaccess -AuthConfig +virtual host -

When a proxy is configured to forward requests to a remote SSL -server, this directive can be used to configure certificate -verification of the remote server. Notice that this directive can be -used both in per-server and per-directory context. In per-server -context it applies to the remote server authentication process used in -the standard SSL handshake when a connection is established by the -proxy. In per-directory context it forces a SSL renegotation with the -reconfigured remote server verification level after the HTTP request -was read but before the HTTP response is sent.

- +server, this directive can be used to configure verification of the +remote server's SSL Certificate.

The following levels are available for level:

-

In practice only levels none and -require are really interesting, because level -optional doesn't work with all servers and level -optional_no_ca is actually against the idea of -authentication (but can be used to establish SSL test pages, etc.)

+

In practice, most users will want either none or +require, as the other levels allow a remote server to bypass +the authentication mechanism. However, the other levels may be useful for +testing.

Example SSLProxyVerify require @@ -1468,20 +1499,12 @@ SSLProxyVerifyDepth number SSLProxyVerifyDepth 1 server config -virtual host -directory -.htaccess -AuthConfig +virtual host

This directive sets how deeply mod_ssl should verify before deciding that the -remote server does not have a valid certificate. Notice that this directive can be -used both in per-server and per-directory context. In per-server context it -applies to the client authentication process used in the standard SSL -handshake when a connection is established. In per-directory context it forces -a SSL renegotation with the reconfigured remote server verification depth after the -HTTP request was read but before the HTTP response is sent.

+remote server does not have a valid certificate.

The depth actually is the maximum number of intermediate certificate issuers, i.e. the number of CA certificates which are max allowed to be followed while Index: modules/ssl/ssl_private.h =================================================================== --- modules/ssl/ssl_private.h (revision 935069) +++ modules/ssl/ssl_private.h (working copy) @@ -231,7 +231,8 @@ SSL_CVERIFY_NONE = 0, SSL_CVERIFY_OPTIONAL = 1, SSL_CVERIFY_REQUIRE = 2, - SSL_CVERIFY_OPTIONAL_NO_CA = 3 + SSL_CVERIFY_OPTIONAL_NO_CA = 3, + SSL_CVERIFY_OPTIONAL_NO_VERIFY = 4 } ssl_verify_t; #define SSL_VERIFY_PEER_STRICT \ Index: modules/ssl/ssl_engine_init.c =================================================================== --- modules/ssl/ssl_engine_init.c (revision 935069) +++ modules/ssl/ssl_engine_init.c (working copy) @@ -610,7 +610,8 @@ } if ((mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL) || - (mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA)) + (mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA) || + (mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_VERIFY)) { verify |= SSL_VERIFY_PEER; } Index: modules/ssl/ssl_engine_config.c =================================================================== --- modules/ssl/ssl_engine_config.c (revision 935069) +++ modules/ssl/ssl_engine_config.c (working copy) @@ -916,6 +916,9 @@ else if (strcEQ(arg, "optional_no_ca")) { *id = SSL_CVERIFY_OPTIONAL_NO_CA; } + else if (strcEQ(arg, "optional_no_verify")) { + *id = SSL_CVERIFY_OPTIONAL_NO_VERIFY; + } else { return apr_pstrcat(parms->temp_pool, parms->cmd->name, ": Invalid argument '", arg, "'", Index: modules/ssl/ssl_engine_io.c =================================================================== --- modules/ssl/ssl_engine_io.c (revision 935069) +++ modules/ssl/ssl_engine_io.c (working copy) @@ -1200,8 +1200,13 @@ if ((verify_result != X509_V_OK) || sslconn->verify_error) { - if (ssl_verify_error_is_optional(verify_result) && - (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA)) + const char *error = sslconn->verify_error ? + sslconn->verify_error : + X509_verify_cert_error_string(verify_result); + + if ((ssl_verify_error_is_optional(verify_result) && + sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA) || + sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_VERIFY) { /* leaving this log message as an error for the moment, * according to the mod_ssl docs: @@ -1212,17 +1217,14 @@ * in 1.x */ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, - "SSL client authentication failed, " - "accepting certificate based on " - "\"SSLVerifyClient optional_no_ca\" " - "configuration"); + "SSL client authentication failed, accepting " + "certificate based on \"SSLVerifyClient " + "optional_no_ca\" or \"SSLVerifyClient " + "optional_no_verify\" configuration: %s", + error ? error : "unknown"); ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, server); } else { - const char *error = sslconn->verify_error ? - sslconn->verify_error : - X509_verify_cert_error_string(verify_result); - ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, "SSL client authentication failed: %s", error ? error : "unknown"); Index: modules/ssl/ssl_engine_vars.c =================================================================== --- modules/ssl/ssl_engine_vars.c (revision 935069) +++ modules/ssl/ssl_engine_vars.c (working copy) @@ -617,9 +617,12 @@ else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL) /* client verification done successful */ result = "SUCCESS"; - else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS")) + else if (vinfo != NULL && strEQ(vinfo, "GENEROUS")) /* client verification done in generous way */ - result = "GENEROUS"; + if (verr) + result = apr_psprintf(p, "GENEROUS:%s", verr); + else + result = "GENEROUS"; else /* client verification failed */ result = apr_psprintf(p, "FAILED:%s", verr); Index: modules/ssl/ssl_engine_kernel.c =================================================================== --- modules/ssl/ssl_engine_kernel.c (revision 935069) +++ modules/ssl/ssl_engine_kernel.c (working copy) @@ -519,7 +519,7 @@ * We force a renegotiation if the reconfigured/new verify type is * stronger than the currently active verify type. * - * The order is: none << optional_no_ca << optional << require + * The order is: none << optional_no_verify << optional_no_ca << optional << require * * Additionally the following optimization is possible here: When the * currently active verify type is "none" but a client certificate is @@ -541,8 +541,10 @@ if ((dc->nVerifyClient == SSL_CVERIFY_OPTIONAL) || (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA) || + (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_VERIFY) || (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL) || - (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA)) + (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA) || + (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_VERIFY)) { verify |= SSL_VERIFY_PEER; } @@ -1377,14 +1379,17 @@ } if (ssl_verify_error_is_optional(errnum) && - (verify == SSL_CVERIFY_OPTIONAL_NO_CA)) + ((verify == SSL_CVERIFY_OPTIONAL_NO_CA) || + (verify == SSL_CVERIFY_OPTIONAL_NO_VERIFY))) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn, - "Certificate Verification: Verifiable Issuer is " - "configured as optional, therefore we're accepting " - "the certificate"); + "Certificate Verification: Error (%d) but verifiable " + "Issuer is configured as optional, therefore we're " + "accepting the certificate: %s", errnum, + X509_verify_cert_error_string(errnum)); sslconn->verify_info = "GENEROUS"; + sslconn->verify_error = X509_verify_cert_error_string(errnum); ok = TRUE; } @@ -1424,16 +1429,31 @@ * If we already know it's not ok, log the real reason */ if (!ok) { - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn, - "Certificate Verification: Error (%d): %s", - errnum, X509_verify_cert_error_string(errnum)); + if (verify == SSL_CVERIFY_OPTIONAL_NO_VERIFY) { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn, + "Certificate Verification: Error (%d) but " + "verification is configured as optional, therefore " + "we're accepting the certificate: %s", errnum, + X509_verify_cert_error_string(errnum)); - if (sslconn->client_cert) { - X509_free(sslconn->client_cert); - sslconn->client_cert = NULL; + sslconn->verify_info = "GENEROUS"; + if (!sslconn->verify_error) { + sslconn->verify_error = X509_verify_cert_error_string(errnum); + } + ok = TRUE; } - sslconn->client_dn = NULL; - sslconn->verify_error = X509_verify_cert_error_string(errnum); + else { + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn, + "Certificate Verification: Error (%d): %s", + errnum, X509_verify_cert_error_string(errnum)); + + if (sslconn->client_cert) { + X509_free(sslconn->client_cert); + sslconn->client_cert = NULL; + } + sslconn->client_dn = NULL; + sslconn->verify_error = X509_verify_cert_error_string(errnum); + } } /* @@ -1447,16 +1467,32 @@ } if (errdepth > depth) { - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn, - "Certificate Verification: Certificate Chain too long " - "(chain has %d certificates, but maximum allowed are " - "only %d)", - errdepth, depth); + if (verify == SSL_CVERIFY_OPTIONAL_NO_VERIFY) { + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn, + "Certificate Verification: Certificate Chain too long " + "(chain has %d certificates, but maximum allowed are " + "only %d) but verification is configured as optional, " + "therefore we're accepting the certificate", + errdepth, depth); - errnum = X509_V_ERR_CERT_CHAIN_TOO_LONG; - sslconn->verify_error = X509_verify_cert_error_string(errnum); + sslconn->verify_info = "GENEROUS"; + if (!sslconn->verify_error) { + errnum = X509_V_ERR_CERT_CHAIN_TOO_LONG; + sslconn->verify_error = X509_verify_cert_error_string(errnum); + } + } + else { + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn, + "Certificate Verification: Certificate Chain too long " + "(chain has %d certificates, but maximum allowed are " + "only %d)", + errdepth, depth); - ok = FALSE; + errnum = X509_V_ERR_CERT_CHAIN_TOO_LONG; + sslconn->verify_error = X509_verify_cert_error_string(errnum); + + ok = FALSE; + } } /* Index: modules/ssl/mod_ssl.c =================================================================== --- modules/ssl/mod_ssl.c (revision 935069) +++ modules/ssl/mod_ssl.c (working copy) @@ -114,7 +114,7 @@ "('/path/to/file' - PEM encoded)") SSL_CMD_ALL(VerifyClient, TAKE1, "SSL Client verify type " - "('none', 'optional', 'require', 'optional_no_ca')") + "('none', 'optional_no_verify', 'optional_no_ca', 'optional', 'require')") SSL_CMD_ALL(VerifyDepth, TAKE1, "SSL Client verify depth " "('N' - number of intermediate certificates)") @@ -150,7 +150,7 @@ "('XXX:...:XXX' - see manual)") SSL_CMD_SRV(ProxyVerify, TAKE1, "SSL Proxy: whether to verify the remote certificate " - "('on' or 'off')") + "('none', 'optional_no_verify', 'optional_no_ca', 'optional', 'require')") SSL_CMD_SRV(ProxyVerifyDepth, TAKE1, "SSL Proxy: maximum certificate verification depth " "('N' - number of intermediate certificates)")