mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
Revamp CRL checking for client and remote servers:
- completely delegate CRL processing to OpenSSL - introduce a new [Proxy]CARevocationCheck directive - drop ssl_callback_SSLVerify_CRL from ssl_engine_kernel.c - remove X509_STORE from modssl_ctx_t - drop CRL store helper functions from ssl_util_ssl.c - avoid sending "certificate_expired" SSL alerts to peers when the nextUpdate field of a CRL is in the past git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1165056 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
5
CHANGES
5
CHANGES
@@ -1,6 +1,11 @@
|
|||||||
-*- coding: utf-8 -*-
|
-*- coding: utf-8 -*-
|
||||||
Changes with Apache 2.3.15
|
Changes with Apache 2.3.15
|
||||||
|
|
||||||
|
*) mod_ssl: revamp CRL-based revocation checking when validating
|
||||||
|
certificates of clients or proxied servers. Completely delegate
|
||||||
|
CRL processing to OpenSSL, and add a new [Proxy]CARevocationCheck
|
||||||
|
directive for controlling the revocation checking mode. [Kaspar Brand]
|
||||||
|
|
||||||
*) Fix a regression in the CVE-2011-3192 byterange fix.
|
*) Fix a regression in the CVE-2011-3192 byterange fix.
|
||||||
PR 51748. [low_priority <lowprio20 gmail.com>]
|
PR 51748. [low_priority <lowprio20 gmail.com>]
|
||||||
|
|
||||||
|
@@ -1033,6 +1033,43 @@ SSLCARevocationFile /usr/local/apache2/conf/ssl.crl/ca-bundle-client.crl
|
|||||||
</usage>
|
</usage>
|
||||||
</directivesynopsis>
|
</directivesynopsis>
|
||||||
|
|
||||||
|
<directivesynopsis>
|
||||||
|
<name>SSLCARevocationCheck</name>
|
||||||
|
<description>Enable CRL-based revocation checking</description>
|
||||||
|
<syntax>SSLCARevocationCheck chain|leaf|none</syntax>
|
||||||
|
<default>SSLCARevocationCheck none</default>
|
||||||
|
<contextlist><context>server config</context>
|
||||||
|
<context>virtual host</context></contextlist>
|
||||||
|
|
||||||
|
<usage>
|
||||||
|
<p>
|
||||||
|
Enables certificate revocation list (CRL) checking. At least one of
|
||||||
|
<directive module="mod_ssl">SSLCARevocationFile</directive>
|
||||||
|
or <directive module="mod_ssl">SSLCARevocationPath</directive> must be
|
||||||
|
configured. When set to <code>chain</code> (recommended setting),
|
||||||
|
CRL checks are applied to all certificates in the chain, while setting it to
|
||||||
|
<code>leaf</code> limits the checks to the end-entity cert.
|
||||||
|
</p>
|
||||||
|
<note>
|
||||||
|
<title>When set to <code>chain</code> or <code>leaf</code>,
|
||||||
|
CRLs <em>must</em> be available for successful validation</title>
|
||||||
|
<p>
|
||||||
|
Prior to version 2.3.15, CRL checking in mod_ssl also succeeded when
|
||||||
|
no CRL(s) were found in any of the locations configured with
|
||||||
|
<directive module="mod_ssl">SSLCARevocationFile</directive>
|
||||||
|
or <directive module="mod_ssl">SSLCARevocationPath</directive>.
|
||||||
|
With the introduction of this directive, the behavior has been changed:
|
||||||
|
when checking is enabled, CRLs <em>must</em> be present for the validation
|
||||||
|
to succeed - otherwise it will fail with an
|
||||||
|
<code>"unable to get certificate CRL"</code> error.
|
||||||
|
</p>
|
||||||
|
</note>
|
||||||
|
<example><title>Example</title>
|
||||||
|
SSLCARevocationCheck chain
|
||||||
|
</example>
|
||||||
|
</usage>
|
||||||
|
</directivesynopsis>
|
||||||
|
|
||||||
<directivesynopsis>
|
<directivesynopsis>
|
||||||
<name>SSLVerifyClient</name>
|
<name>SSLVerifyClient</name>
|
||||||
<description>Type of Client Certificate verification</description>
|
<description>Type of Client Certificate verification</description>
|
||||||
@@ -1784,6 +1821,44 @@ SSLProxyCARevocationFile /usr/local/apache2/conf/ssl.crl/ca-bundle-remote-server
|
|||||||
</usage>
|
</usage>
|
||||||
</directivesynopsis>
|
</directivesynopsis>
|
||||||
|
|
||||||
|
<directivesynopsis>
|
||||||
|
<name>SSLProxyCARevocationCheck</name>
|
||||||
|
<description>Enable CRL-based revocation checking for Remote Server Auth</description>
|
||||||
|
<syntax>SSLProxyCARevocationCheck chain|leaf|none</syntax>
|
||||||
|
<default>SSLProxyCARevocationCheck none</default>
|
||||||
|
<contextlist><context>server config</context>
|
||||||
|
<context>virtual host</context></contextlist>
|
||||||
|
|
||||||
|
<usage>
|
||||||
|
<p>
|
||||||
|
Enables certificate revocation list (CRL) checking for the
|
||||||
|
<em>remote servers</em> you deal with. At least one of
|
||||||
|
<directive module="mod_ssl">SSLProxyCARevocationFile</directive>
|
||||||
|
or <directive module="mod_ssl">SSLProxyCARevocationPath</directive> must be
|
||||||
|
configured. When set to <code>chain</code> (recommended setting),
|
||||||
|
CRL checks are applied to all certificates in the chain, while setting it to
|
||||||
|
<code>leaf</code> limits the checks to the end-entity cert.
|
||||||
|
</p>
|
||||||
|
<note>
|
||||||
|
<title>When set to <code>chain</code> or <code>leaf</code>,
|
||||||
|
CRLs <em>must</em> be available for successful validation</title>
|
||||||
|
<p>
|
||||||
|
Prior to version 2.3.15, CRL checking in mod_ssl also succeeded when
|
||||||
|
no CRL(s) were found in any of the locations configured with
|
||||||
|
<directive module="mod_ssl">SSLProxyCARevocationFile</directive>
|
||||||
|
or <directive module="mod_ssl">SSLProxyCARevocationPath</directive>.
|
||||||
|
With the introduction of this directive, the behavior has been changed:
|
||||||
|
when checking is enabled, CRLs <em>must</em> be present for the validation
|
||||||
|
to succeed - otherwise it will fail with an
|
||||||
|
<code>"unable to get certificate CRL"</code> error.
|
||||||
|
</p>
|
||||||
|
</note>
|
||||||
|
<example><title>Example</title>
|
||||||
|
SSLProxyCARevocationCheck chain
|
||||||
|
</example>
|
||||||
|
</usage>
|
||||||
|
</directivesynopsis>
|
||||||
|
|
||||||
<directivesynopsis>
|
<directivesynopsis>
|
||||||
<name>SSLUserName</name>
|
<name>SSLUserName</name>
|
||||||
<description>Variable name to determine user name</description>
|
<description>Variable name to determine user name</description>
|
||||||
|
@@ -112,6 +112,8 @@ static const command_rec ssl_config_cmds[] = {
|
|||||||
SSL_CMD_SRV(CARevocationFile, TAKE1,
|
SSL_CMD_SRV(CARevocationFile, TAKE1,
|
||||||
"SSL CA Certificate Revocation List (CRL) file "
|
"SSL CA Certificate Revocation List (CRL) file "
|
||||||
"('/path/to/file' - PEM encoded)")
|
"('/path/to/file' - PEM encoded)")
|
||||||
|
SSL_CMD_SRV(CARevocationCheck, TAKE1,
|
||||||
|
"SSL CA Certificate Revocation List (CRL) checking mode")
|
||||||
SSL_CMD_ALL(VerifyClient, TAKE1,
|
SSL_CMD_ALL(VerifyClient, TAKE1,
|
||||||
"SSL Client verify type "
|
"SSL Client verify type "
|
||||||
"('none', 'optional', 'require', 'optional_no_ca')")
|
"('none', 'optional', 'require', 'optional_no_ca')")
|
||||||
@@ -163,6 +165,8 @@ static const command_rec ssl_config_cmds[] = {
|
|||||||
SSL_CMD_SRV(ProxyCARevocationFile, TAKE1,
|
SSL_CMD_SRV(ProxyCARevocationFile, TAKE1,
|
||||||
"SSL Proxy: CA Certificate Revocation List (CRL) file "
|
"SSL Proxy: CA Certificate Revocation List (CRL) file "
|
||||||
"('/path/to/file' - PEM encoded)")
|
"('/path/to/file' - PEM encoded)")
|
||||||
|
SSL_CMD_SRV(ProxyCARevocationCheck, TAKE1,
|
||||||
|
"SSL Proxy: CA Certificate Revocation List (CRL) checking mode")
|
||||||
SSL_CMD_SRV(ProxyMachineCertificateFile, TAKE1,
|
SSL_CMD_SRV(ProxyMachineCertificateFile, TAKE1,
|
||||||
"SSL Proxy: file containing client certificates "
|
"SSL Proxy: file containing client certificates "
|
||||||
"('/path/to/file' - PEM encoded certificates)")
|
"('/path/to/file' - PEM encoded certificates)")
|
||||||
|
@@ -119,7 +119,7 @@ static void modssl_ctx_init(modssl_ctx_t *mctx)
|
|||||||
|
|
||||||
mctx->crl_path = NULL;
|
mctx->crl_path = NULL;
|
||||||
mctx->crl_file = NULL;
|
mctx->crl_file = NULL;
|
||||||
mctx->crl = NULL; /* set during module init */
|
mctx->crl_check_mode = SSL_CRLCHECK_UNSET;
|
||||||
|
|
||||||
mctx->auth.ca_cert_path = NULL;
|
mctx->auth.ca_cert_path = NULL;
|
||||||
mctx->auth.ca_cert_file = NULL;
|
mctx->auth.ca_cert_file = NULL;
|
||||||
@@ -238,6 +238,7 @@ static void modssl_ctx_cfg_merge(modssl_ctx_t *base,
|
|||||||
|
|
||||||
cfgMerge(crl_path, NULL);
|
cfgMerge(crl_path, NULL);
|
||||||
cfgMerge(crl_file, NULL);
|
cfgMerge(crl_file, NULL);
|
||||||
|
cfgMerge(crl_check_mode, SSL_CRLCHECK_UNSET);
|
||||||
|
|
||||||
cfgMergeString(auth.ca_cert_path);
|
cfgMergeString(auth.ca_cert_path);
|
||||||
cfgMergeString(auth.ca_cert_file);
|
cfgMergeString(auth.ca_cert_file);
|
||||||
@@ -902,6 +903,39 @@ const char *ssl_cmd_SSLCARevocationFile(cmd_parms *cmd,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *ssl_cmd_crlcheck_parse(cmd_parms *parms,
|
||||||
|
const char *arg,
|
||||||
|
ssl_crlcheck_t *mode)
|
||||||
|
{
|
||||||
|
if (strcEQ(arg, "none")) {
|
||||||
|
*mode = SSL_CRLCHECK_NONE;
|
||||||
|
}
|
||||||
|
else if (strcEQ(arg, "leaf")) {
|
||||||
|
*mode = SSL_CRLCHECK_LEAF;
|
||||||
|
}
|
||||||
|
else if (strcEQ(arg, "chain")) {
|
||||||
|
*mode = SSL_CRLCHECK_CHAIN;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return apr_pstrcat(parms->temp_pool, parms->cmd->name,
|
||||||
|
": Invalid argument '", arg, "'",
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ssl_cmd_SSLCARevocationCheck(cmd_parms *cmd,
|
||||||
|
void *dcfg,
|
||||||
|
const char *arg)
|
||||||
|
{
|
||||||
|
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
|
||||||
|
|
||||||
|
const char *err;
|
||||||
|
|
||||||
|
return ssl_cmd_crlcheck_parse(cmd, arg, &sc->server->crl_check_mode);
|
||||||
|
}
|
||||||
|
|
||||||
static const char *ssl_cmd_verify_parse(cmd_parms *parms,
|
static const char *ssl_cmd_verify_parse(cmd_parms *parms,
|
||||||
const char *arg,
|
const char *arg,
|
||||||
ssl_verify_t *id)
|
ssl_verify_t *id)
|
||||||
@@ -1379,6 +1413,15 @@ const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *cmd,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *ssl_cmd_SSLProxyCARevocationCheck(cmd_parms *cmd,
|
||||||
|
void *dcfg,
|
||||||
|
const char *arg)
|
||||||
|
{
|
||||||
|
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
|
||||||
|
|
||||||
|
return ssl_cmd_crlcheck_parse(cmd, arg, &sc->proxy->crl_check_mode);
|
||||||
|
}
|
||||||
|
|
||||||
const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *cmd,
|
const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *cmd,
|
||||||
void *dcfg,
|
void *dcfg,
|
||||||
const char *arg)
|
const char *arg)
|
||||||
|
@@ -726,28 +726,55 @@ static void ssl_init_ctx_crl(server_rec *s,
|
|||||||
apr_pool_t *ptemp,
|
apr_pool_t *ptemp,
|
||||||
modssl_ctx_t *mctx)
|
modssl_ctx_t *mctx)
|
||||||
{
|
{
|
||||||
|
X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx);
|
||||||
|
unsigned long crlflags = 0;
|
||||||
|
char *cfgp = mctx->pkp ? "SSLProxy" : "SSL";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure Certificate Revocation List (CRL) Details
|
* Configure Certificate Revocation List (CRL) Details
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!(mctx->crl_file || mctx->crl_path)) {
|
if (!(mctx->crl_file || mctx->crl_path)) {
|
||||||
|
if (mctx->crl_check_mode == SSL_CRLCHECK_LEAF ||
|
||||||
|
mctx->crl_check_mode == SSL_CRLCHECK_CHAIN) {
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
|
||||||
|
"Host %s: CRL checking has been enabled, but "
|
||||||
|
"neither %sCARevocationFile nor %sCARevocationPath "
|
||||||
|
"is configured", mctx->sc->vhost_id, cfgp, cfgp);
|
||||||
|
ssl_die();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
||||||
"Configuring certificate revocation facility");
|
"Configuring certificate revocation facility");
|
||||||
|
|
||||||
mctx->crl =
|
if (!store || !X509_STORE_load_locations(store, mctx->crl_file,
|
||||||
SSL_X509_STORE_create((char *)mctx->crl_file,
|
mctx->crl_path)) {
|
||||||
(char *)mctx->crl_path);
|
|
||||||
|
|
||||||
if (!mctx->crl) {
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
|
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
|
||||||
"Unable to configure X.509 CRL storage "
|
"Host %s: unable to configure X.509 CRL storage "
|
||||||
"for certificate revocation");
|
"for certificate revocation", mctx->sc->vhost_id);
|
||||||
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
|
||||||
ssl_die();
|
ssl_die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (mctx->crl_check_mode) {
|
||||||
|
case SSL_CRLCHECK_LEAF:
|
||||||
|
crlflags = X509_V_FLAG_CRL_CHECK;
|
||||||
|
break;
|
||||||
|
case SSL_CRLCHECK_CHAIN:
|
||||||
|
crlflags = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crlflags) {
|
||||||
|
X509_STORE_set_flags(store, crlflags);
|
||||||
|
} else {
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
|
||||||
|
"Host %s: X.509 CRL storage locations configured, "
|
||||||
|
"but CRL checking (%sCARevocationCheck) is not "
|
||||||
|
"enabled", mctx->sc->vhost_id, cfgp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ssl_init_ctx_pkcs7_cert_chain(server_rec *s, modssl_ctx_t *mctx)
|
static void ssl_init_ctx_pkcs7_cert_chain(server_rec *s, modssl_ctx_t *mctx)
|
||||||
@@ -1432,8 +1459,6 @@ void ssl_init_Child(apr_pool_t *p, server_rec *s)
|
|||||||
|
|
||||||
static void ssl_init_ctx_cleanup(modssl_ctx_t *mctx)
|
static void ssl_init_ctx_cleanup(modssl_ctx_t *mctx)
|
||||||
{
|
{
|
||||||
MODSSL_CFG_ITEM_FREE(X509_STORE_free, mctx->crl);
|
|
||||||
|
|
||||||
MODSSL_CFG_ITEM_FREE(SSL_CTX_free, mctx->ssl_ctx);
|
MODSSL_CFG_ITEM_FREE(SSL_CTX_free, mctx->ssl_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1429,8 +1429,11 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
|
|||||||
*/
|
*/
|
||||||
ssl_log_cxerror(SSLLOG_MARK, APLOG_DEBUG, 0, conn,
|
ssl_log_cxerror(SSLLOG_MARK, APLOG_DEBUG, 0, conn,
|
||||||
X509_STORE_CTX_get_current_cert(ctx),
|
X509_STORE_CTX_get_current_cert(ctx),
|
||||||
"Certificate Verification, depth %d",
|
"Certificate Verification, depth %d, "
|
||||||
errdepth);
|
"CRL checking mode: %s", errdepth,
|
||||||
|
mctx->crl_check_mode == SSL_CRLCHECK_CHAIN ?
|
||||||
|
"chain" : (mctx->crl_check_mode == SSL_CRLCHECK_LEAF ?
|
||||||
|
"leaf" : "none"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for optionally acceptable non-verifiable issuer situation
|
* Check for optionally acceptable non-verifiable issuer situation
|
||||||
@@ -1464,19 +1467,30 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform OCSP/CRL-based revocation checks
|
* Expired certificates vs. "expired" CRLs: by default, OpenSSL
|
||||||
|
* turns X509_V_ERR_CRL_HAS_EXPIRED into a "certificate_expired(45)"
|
||||||
|
* SSL alert, but that's not really the message we should convey to the
|
||||||
|
* peer (at the very least, it's confusing, and in many cases, it's also
|
||||||
|
* inaccurate, as the certificate itself may very well not have expired
|
||||||
|
* yet). We set the X509_STORE_CTX error to something which OpenSSL's
|
||||||
|
* s3_both.c:ssl_verify_alarm_type() maps to SSL_AD_CERTIFICATE_UNKNOWN,
|
||||||
|
* i.e. the peer will receive a "certificate_unknown(46)" alert.
|
||||||
|
* We do not touch errnum, though, so that later on we will still log
|
||||||
|
* the "real" error, as returned by OpenSSL.
|
||||||
*/
|
*/
|
||||||
if (ok) {
|
if (!ok && errnum == X509_V_ERR_CRL_HAS_EXPIRED) {
|
||||||
if (!(ok = ssl_callback_SSLVerify_CRL(ok, ctx, conn))) {
|
X509_STORE_CTX_set_error(ctx, -1);
|
||||||
errnum = X509_STORE_CTX_get_error(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_OCSP
|
#ifndef OPENSSL_NO_OCSP
|
||||||
|
/*
|
||||||
|
* Perform OCSP-based revocation checks
|
||||||
|
*/
|
||||||
|
if (ok && sc->server->ocsp_enabled) {
|
||||||
/* If there was an optional verification error, it's not
|
/* If there was an optional verification error, it's not
|
||||||
* possible to perform OCSP validation since the issuer may be
|
* possible to perform OCSP validation since the issuer may be
|
||||||
* missing/untrusted. Fail in that case. */
|
* missing/untrusted. Fail in that case. */
|
||||||
if (ok && ssl_verify_error_is_optional(errnum)
|
if (ssl_verify_error_is_optional(errnum)) {
|
||||||
&& sc->server->ocsp_enabled) {
|
|
||||||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION);
|
X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION);
|
||||||
errnum = X509_V_ERR_APPLICATION_VERIFICATION;
|
errnum = X509_V_ERR_APPLICATION_VERIFICATION;
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn,
|
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn,
|
||||||
@@ -1484,52 +1498,28 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
|
|||||||
"if issuer has not been verified "
|
"if issuer has not been verified "
|
||||||
"(optional_no_ca configured)");
|
"(optional_no_ca configured)");
|
||||||
ok = FALSE;
|
ok = FALSE;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if (ok && sc->server->ocsp_enabled) {
|
|
||||||
ok = modssl_verify_ocsp(ctx, sc, s, conn, conn->pool);
|
ok = modssl_verify_ocsp(ctx, sc, s, conn, conn->pool);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
errnum = X509_STORE_CTX_get_error(ctx);
|
errnum = X509_STORE_CTX_get_error(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we already know it's not ok, log the real reason
|
* If we already know it's not ok, log the real reason
|
||||||
*/
|
*/
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
if (APLOGcinfo(conn)) {
|
||||||
|
ssl_log_cxerror(SSLLOG_MARK, APLOG_INFO, 0, conn,
|
||||||
|
X509_STORE_CTX_get_current_cert(ctx),
|
||||||
|
"Certificate Verification: Error (%d): %s",
|
||||||
|
errnum, X509_verify_cert_error_string(errnum));
|
||||||
|
} else {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn,
|
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn,
|
||||||
"Certificate Verification: Error (%d): %s",
|
"Certificate Verification: Error (%d): %s",
|
||||||
errnum, X509_verify_cert_error_string(errnum));
|
errnum, X509_verify_cert_error_string(errnum));
|
||||||
if (APLOGcinfo(conn)) {
|
|
||||||
X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
|
|
||||||
BIO *bio = BIO_new(BIO_s_mem());
|
|
||||||
char buff[512]; /* should be plenty */
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (bio) {
|
|
||||||
BIO_puts(bio, "Failed certificate: subject: '");
|
|
||||||
X509_NAME_print_ex(bio, X509_get_subject_name(cert), 0,
|
|
||||||
XN_FLAG_ONELINE);
|
|
||||||
|
|
||||||
BIO_puts(bio, "', issuer: '");
|
|
||||||
X509_NAME_print_ex(bio, X509_get_issuer_name(cert), 0,
|
|
||||||
XN_FLAG_ONELINE);
|
|
||||||
|
|
||||||
BIO_puts(bio, "', notbefore: ");
|
|
||||||
ASN1_UTCTIME_print(bio, X509_get_notBefore(cert));
|
|
||||||
|
|
||||||
BIO_puts(bio, ", notafter: ");
|
|
||||||
ASN1_UTCTIME_print(bio, X509_get_notAfter(cert));
|
|
||||||
|
|
||||||
n = BIO_read(bio, buff, sizeof(buff) - 1);
|
|
||||||
BIO_free(bio);
|
|
||||||
if (n > 0) {
|
|
||||||
buff[n] = '\0';
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, conn, "%s", buff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sslconn->client_cert) {
|
if (sslconn->client_cert) {
|
||||||
@@ -1569,195 +1559,6 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssl_callback_SSLVerify_CRL(int ok, X509_STORE_CTX *ctx, conn_rec *c)
|
|
||||||
{
|
|
||||||
SSL *ssl = X509_STORE_CTX_get_ex_data(ctx,
|
|
||||||
SSL_get_ex_data_X509_STORE_CTX_idx());
|
|
||||||
request_rec *r = (request_rec *)SSL_get_app_data2(ssl);
|
|
||||||
server_rec *s = r ? r->server : mySrvFromConn(c);
|
|
||||||
SSLSrvConfigRec *sc = mySrvConfig(s);
|
|
||||||
SSLConnRec *sslconn = myConnConfig(c);
|
|
||||||
modssl_ctx_t *mctx = myCtxConfig(sslconn, sc);
|
|
||||||
X509_OBJECT obj;
|
|
||||||
X509_NAME *subject, *issuer;
|
|
||||||
X509 *cert;
|
|
||||||
X509_CRL *crl;
|
|
||||||
EVP_PKEY *pubkey;
|
|
||||||
int i, n, rc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Unless a revocation store for CRLs was created we
|
|
||||||
* cannot do any CRL-based verification, of course.
|
|
||||||
*/
|
|
||||||
if (!mctx->crl) {
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine certificate ingredients in advance
|
|
||||||
*/
|
|
||||||
cert = X509_STORE_CTX_get_current_cert(ctx);
|
|
||||||
subject = X509_get_subject_name(cert);
|
|
||||||
issuer = X509_get_issuer_name(cert);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* OpenSSL provides the general mechanism to deal with CRLs but does not
|
|
||||||
* use them automatically when verifying certificates, so we do it
|
|
||||||
* explicitly here. We will check the CRL for the currently checked
|
|
||||||
* certificate, if there is such a CRL in the store.
|
|
||||||
*
|
|
||||||
* We come through this procedure for each certificate in the certificate
|
|
||||||
* chain, starting with the root-CA's certificate. At each step we've to
|
|
||||||
* both verify the signature on the CRL (to make sure it's a valid CRL)
|
|
||||||
* and its revocation list (to make sure the current certificate isn't
|
|
||||||
* revoked). But because to check the signature on the CRL we need the
|
|
||||||
* public key of the issuing CA certificate (which was already processed
|
|
||||||
* one round before), we've a little problem. But we can both solve it and
|
|
||||||
* at the same time optimize the processing by using the following
|
|
||||||
* verification scheme (idea and code snippets borrowed from the GLOBUS
|
|
||||||
* project):
|
|
||||||
*
|
|
||||||
* 1. We'll check the signature of a CRL in each step when we find a CRL
|
|
||||||
* through the _subject_ name of the current certificate. This CRL
|
|
||||||
* itself will be needed the first time in the next round, of course.
|
|
||||||
* But we do the signature processing one round before this where the
|
|
||||||
* public key of the CA is available.
|
|
||||||
*
|
|
||||||
* 2. We'll check the revocation list of a CRL in each step when
|
|
||||||
* we find a CRL through the _issuer_ name of the current certificate.
|
|
||||||
* This CRLs signature was then already verified one round before.
|
|
||||||
*
|
|
||||||
* This verification scheme allows a CA to revoke its own certificate as
|
|
||||||
* well, of course.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to retrieve a CRL corresponding to the _subject_ of
|
|
||||||
* the current certificate in order to verify its integrity.
|
|
||||||
*/
|
|
||||||
memset((char *)&obj, 0, sizeof(obj));
|
|
||||||
rc = SSL_X509_STORE_lookup(mctx->crl,
|
|
||||||
X509_LU_CRL, subject, &obj);
|
|
||||||
crl = obj.data.crl;
|
|
||||||
|
|
||||||
if ((rc > 0) && crl) {
|
|
||||||
/*
|
|
||||||
* Log information about CRL
|
|
||||||
* (A little bit complicated because of ASN.1 and BIOs...)
|
|
||||||
*/
|
|
||||||
if (APLOGtrace1(s)) {
|
|
||||||
char buff[512]; /* should be plenty */
|
|
||||||
BIO *bio = BIO_new(BIO_s_mem());
|
|
||||||
|
|
||||||
BIO_printf(bio, "CA CRL: Issuer: ");
|
|
||||||
X509_NAME_print(bio, issuer, 0);
|
|
||||||
|
|
||||||
BIO_printf(bio, ", lastUpdate: ");
|
|
||||||
ASN1_UTCTIME_print(bio, X509_CRL_get_lastUpdate(crl));
|
|
||||||
|
|
||||||
BIO_printf(bio, ", nextUpdate: ");
|
|
||||||
ASN1_UTCTIME_print(bio, X509_CRL_get_nextUpdate(crl));
|
|
||||||
|
|
||||||
n = BIO_read(bio, buff, sizeof(buff) - 1);
|
|
||||||
buff[n] = '\0';
|
|
||||||
|
|
||||||
BIO_free(bio);
|
|
||||||
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "%s", buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Verify the signature on this CRL
|
|
||||||
*/
|
|
||||||
pubkey = X509_get_pubkey(cert);
|
|
||||||
rc = X509_CRL_verify(crl, pubkey);
|
|
||||||
if (pubkey)
|
|
||||||
EVP_PKEY_free(pubkey);
|
|
||||||
if (rc <= 0) {
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
|
|
||||||
"Invalid signature on CRL");
|
|
||||||
|
|
||||||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
|
|
||||||
X509_OBJECT_free_contents(&obj);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check date of CRL to make sure it's not expired
|
|
||||||
*/
|
|
||||||
i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
|
|
||||||
"Found CRL has invalid nextUpdate field");
|
|
||||||
|
|
||||||
X509_STORE_CTX_set_error(ctx,
|
|
||||||
X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
|
|
||||||
X509_OBJECT_free_contents(&obj);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < 0) {
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
|
|
||||||
"Found CRL is expired - "
|
|
||||||
"revoking all certificates until you get updated CRL");
|
|
||||||
|
|
||||||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED);
|
|
||||||
X509_OBJECT_free_contents(&obj);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
X509_OBJECT_free_contents(&obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to retrieve a CRL corresponding to the _issuer_ of
|
|
||||||
* the current certificate in order to check for revocation.
|
|
||||||
*/
|
|
||||||
memset((char *)&obj, 0, sizeof(obj));
|
|
||||||
rc = SSL_X509_STORE_lookup(mctx->crl,
|
|
||||||
X509_LU_CRL, issuer, &obj);
|
|
||||||
|
|
||||||
crl = obj.data.crl;
|
|
||||||
if ((rc > 0) && crl) {
|
|
||||||
/*
|
|
||||||
* Check if the current certificate is revoked by this CRL
|
|
||||||
*/
|
|
||||||
n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
X509_REVOKED *revoked =
|
|
||||||
sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
|
|
||||||
|
|
||||||
ASN1_INTEGER *sn = revoked->serialNumber;
|
|
||||||
|
|
||||||
if (!ASN1_INTEGER_cmp(sn, X509_get_serialNumber(cert))) {
|
|
||||||
if (APLOGdebug(s)) {
|
|
||||||
char *cp = X509_NAME_oneline(issuer, NULL, 0);
|
|
||||||
long serial = ASN1_INTEGER_get(sn);
|
|
||||||
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
|
|
||||||
"Certificate with serial %ld (0x%lX) "
|
|
||||||
"revoked per CRL from issuer %s",
|
|
||||||
serial, serial, cp);
|
|
||||||
OPENSSL_free(cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
|
|
||||||
X509_OBJECT_free_contents(&obj);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
X509_OBJECT_free_contents(&obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SSLPROXY_CERT_CB_LOG_FMT \
|
#define SSLPROXY_CERT_CB_LOG_FMT \
|
||||||
"Proxy client certificate callback: (%s) "
|
"Proxy client certificate callback: (%s) "
|
||||||
|
|
||||||
|
@@ -325,6 +325,16 @@ typedef enum {
|
|||||||
|| (errnum == X509_V_ERR_CERT_UNTRUSTED) \
|
|| (errnum == X509_V_ERR_CERT_UNTRUSTED) \
|
||||||
|| (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))
|
|| (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CRL checking modes
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
SSL_CRLCHECK_UNSET = UNSET,
|
||||||
|
SSL_CRLCHECK_NONE = 0,
|
||||||
|
SSL_CRLCHECK_LEAF = 1,
|
||||||
|
SSL_CRLCHECK_CHAIN = 2
|
||||||
|
} ssl_crlcheck_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the SSL pass phrase dialog types
|
* Define the SSL pass phrase dialog types
|
||||||
*/
|
*/
|
||||||
@@ -567,7 +577,7 @@ typedef struct {
|
|||||||
/** certificate revocation list */
|
/** certificate revocation list */
|
||||||
const char *crl_path;
|
const char *crl_path;
|
||||||
const char *crl_file;
|
const char *crl_file;
|
||||||
X509_STORE *crl;
|
ssl_crlcheck_t crl_check_mode;
|
||||||
|
|
||||||
#ifdef HAVE_OCSP_STAPLING
|
#ifdef HAVE_OCSP_STAPLING
|
||||||
/** OCSP stapling options */
|
/** OCSP stapling options */
|
||||||
@@ -665,6 +675,7 @@ const char *ssl_cmd_SSLCADNRequestPath(cmd_parms *, void *, const char *);
|
|||||||
const char *ssl_cmd_SSLCADNRequestFile(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_SSLCARevocationPath(cmd_parms *, void *, const char *);
|
||||||
const char *ssl_cmd_SSLCARevocationFile(cmd_parms *, void *, const char *);
|
const char *ssl_cmd_SSLCARevocationFile(cmd_parms *, void *, const char *);
|
||||||
|
const char *ssl_cmd_SSLCARevocationCheck(cmd_parms *, void *, const char *);
|
||||||
const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag);
|
const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag);
|
||||||
const char *ssl_cmd_SSLVerifyClient(cmd_parms *, void *, const char *);
|
const char *ssl_cmd_SSLVerifyClient(cmd_parms *, void *, const char *);
|
||||||
const char *ssl_cmd_SSLVerifyDepth(cmd_parms *, void *, const char *);
|
const char *ssl_cmd_SSLVerifyDepth(cmd_parms *, void *, const char *);
|
||||||
@@ -688,6 +699,7 @@ const char *ssl_cmd_SSLProxyCACertificatePath(cmd_parms *, void *, const char *
|
|||||||
const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *, void *, const char *);
|
const char *ssl_cmd_SSLProxyCACertificateFile(cmd_parms *, void *, const char *);
|
||||||
const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *, void *, const char *);
|
const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *, void *, const char *);
|
||||||
const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *, void *, const char *);
|
const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *, void *, const char *);
|
||||||
|
const char *ssl_cmd_SSLProxyCARevocationCheck(cmd_parms *, void *, const char *);
|
||||||
const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, void *, const char *);
|
const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, void *, const char *);
|
||||||
const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, void *, const char *);
|
const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, void *, const char *);
|
||||||
const char *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *, void *, const char *);
|
const char *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *, void *, const char *);
|
||||||
|
@@ -182,55 +182,6 @@ int SSL_smart_shutdown(SSL *ssl)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _________________________________________________________________
|
|
||||||
**
|
|
||||||
** Certificate Revocation List (CRL) Storage
|
|
||||||
** _________________________________________________________________
|
|
||||||
*/
|
|
||||||
|
|
||||||
X509_STORE *SSL_X509_STORE_create(char *cpFile, char *cpPath)
|
|
||||||
{
|
|
||||||
X509_STORE *pStore;
|
|
||||||
X509_LOOKUP *pLookup;
|
|
||||||
int rv = 1;
|
|
||||||
|
|
||||||
ERR_clear_error();
|
|
||||||
|
|
||||||
if (cpFile == NULL && cpPath == NULL)
|
|
||||||
return NULL;
|
|
||||||
if ((pStore = X509_STORE_new()) == NULL)
|
|
||||||
return NULL;
|
|
||||||
if (cpFile != NULL) {
|
|
||||||
pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_file());
|
|
||||||
if (pLookup == NULL) {
|
|
||||||
X509_STORE_free(pStore);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
rv = X509_LOOKUP_load_file(pLookup, cpFile, X509_FILETYPE_PEM);
|
|
||||||
}
|
|
||||||
if (cpPath != NULL && rv == 1) {
|
|
||||||
pLookup = X509_STORE_add_lookup(pStore, X509_LOOKUP_hash_dir());
|
|
||||||
if (pLookup == NULL) {
|
|
||||||
X509_STORE_free(pStore);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
rv = X509_LOOKUP_add_dir(pLookup, cpPath, X509_FILETYPE_PEM);
|
|
||||||
}
|
|
||||||
return rv == 1 ? pStore : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SSL_X509_STORE_lookup(X509_STORE *pStore, int nType,
|
|
||||||
X509_NAME *pName, X509_OBJECT *pObj)
|
|
||||||
{
|
|
||||||
X509_STORE_CTX pStoreCtx;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
X509_STORE_CTX_init(&pStoreCtx, pStore, NULL, NULL);
|
|
||||||
rc = X509_STORE_get_by_subject(&pStoreCtx, nType, pName, pObj);
|
|
||||||
X509_STORE_CTX_cleanup(&pStoreCtx);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* _________________________________________________________________
|
/* _________________________________________________________________
|
||||||
**
|
**
|
||||||
** Cipher Suite Spec String Creation
|
** Cipher Suite Spec String Creation
|
||||||
|
@@ -63,8 +63,6 @@ void SSL_set_app_data2(SSL *, void *);
|
|||||||
X509 *SSL_read_X509(char *, X509 **, pem_password_cb *);
|
X509 *SSL_read_X509(char *, X509 **, pem_password_cb *);
|
||||||
EVP_PKEY *SSL_read_PrivateKey(char *, EVP_PKEY **, pem_password_cb *, void *);
|
EVP_PKEY *SSL_read_PrivateKey(char *, EVP_PKEY **, pem_password_cb *, void *);
|
||||||
int SSL_smart_shutdown(SSL *ssl);
|
int SSL_smart_shutdown(SSL *ssl);
|
||||||
X509_STORE *SSL_X509_STORE_create(char *, char *);
|
|
||||||
int SSL_X509_STORE_lookup(X509_STORE *, int, X509_NAME *, X509_OBJECT *);
|
|
||||||
char *SSL_make_ciphersuite(apr_pool_t *, SSL *);
|
char *SSL_make_ciphersuite(apr_pool_t *, SSL *);
|
||||||
BOOL SSL_X509_isSGC(X509 *);
|
BOOL SSL_X509_isSGC(X509 *);
|
||||||
BOOL SSL_X509_getBC(X509 *, int *, int *);
|
BOOL SSL_X509_getBC(X509 *, int *, int *);
|
||||||
|
Reference in New Issue
Block a user