--- docs/manual/mod/mod_ssl.xml (revision 933708)
+++ docs/manual/mod/mod_ssl.xml (working copy)
@@ -83,7 +83,7 @@
-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:
-- none:
- no client Certificate is required at all
-- optional:
- the client may present a valid Certificate
-- require:
- the client has to present a valid Certificate
-- optional_no_ca:
- the client may present a valid Certificate
- but it need not to be (successfully) verifiable.
+none
+ No client Certificate is requested.
+optional_no_verify
+ The client is asked to present a Certificate signed by one of our
+ trusted CA Certificates, but will be accepted even if no Certificate is
+ provided, if the provided Certificate is not signed by one of our trusted
+ CA Certificates, or if the provided Certificate has been revoked or is
+ otherwise invalid.
+optional_no_ca
+ The client is asked to present a Certificate signed by one of our
+ trusted CA Certificates, and will be accepted even if no Certificate is
+ provided or if the provided Certificate is not signed by one of our trusted
+ CA Certificates, but will be disconnected if the provided Certificate has
+ been revoked or is otherwise invalid.
+optional
+ The client is asked to present a Certificate signed by one of our
+ trusted CA Certificates, and will be accepted even if no Certificate is
+ provided, but will be disconnected if the provided Certificate is not
+ signed by one of our trusted CA Certificates, has been revoked, or is
+ otherwise invalid.
+require
+ The client is asked to present a Certificate signed by one of our
+ trusted CA Certificates, and will be disconnected if no Certificate is
+ provided, if the provided Certificate is not signed by on of our trusted CA
+ Certificates, or if the provided Certificate has been revoked or is
+ otherwise invalid.
-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 SSLCACertificateFile and
+SSLCACertificatePath directives to
+configure the list of trusted CA Certificates.
+If using one of the optional levels, note that if the
+client does not have a suitable Certificate signed by one of the specified
+trusted CAs, most browsers will attempt to continue without providing a
+Certificate, but some browsers may give up and disconnect on their own.
+If using optional_no_ca or
+optional_no_verify, you can request any available Certificate
+(signed by any CA) from most browsers by creating a file containing only a
+single space character, and pointing SSLCACertificateFile at that file.
Example
SSLVerifyClient require
@@ -1428,33 +1455,41 @@
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
+server, this directive can be used to configure verification of the
+remote server's SSL Certificate. 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
+the initial 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.
+is read but before the HTTP response is sent.
The following levels are available for level:
-- none:
- no remote server Certificate is required at all
-- optional:
- the remote server may present a valid Certificate
-- require:
- the remote server has to present a valid Certificate
-- optional_no_ca:
- the remote server may present a valid Certificate
- but it need not to be (successfully) verifiable.
+none
+ No remote server Certificate verification will be performed.
+optional_no_verify
+ If the remote server provides a Certificate, it will be verified, but
+ the result will be ignored.
+optional_no_ca
+ If the remote server provides a Certificate, it will be verified. The
+ connection will be accepted even if the Certificate is not signed by one of
+ the CAs listed in
+ SSLProxyCACertificateFile or
+ SSLProxyCACertificatePath, but will
+ be rejected if verification fails for any other reason.
+optional
+ If the remote server provides a Certificate, it will be verified, and the
+ connection will be rejected if verification fails.
+require
+ The connection will be rejected unless the remote server provides a
+ Certificate and that Certificate is successfully verified.
-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
--- modules/ssl/ssl_private.h (revision 933708)
+++ 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 \
--- modules/ssl/ssl_engine_init.c (revision 933708)
+++ 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;
}
--- modules/ssl/ssl_engine_config.c (revision 933708)
+++ 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, "'",
--- modules/ssl/ssl_engine_io.c (revision 933708)
+++ 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");
--- modules/ssl/ssl_engine_vars.c (revision 933708)
+++ 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);
--- modules/ssl/ssl_engine_kernel.c (revision 933708)
+++ 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;
+ }
}
/*
--- modules/ssl/mod_ssl.c (revision 933708)
+++ 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)")