Hello,
When an _intermediate_ SSL server certificate fails validation, we
should report errors using information in that certificate and not in
the top-level "peer" certificate. Otherwise, our details may make no
sense. For example, we could say that the validation failed due to the
expired certificate and show an expiration date in the future (because
the top-level certificate did not expire but the intermediate
certificate did).
OpenSSL X509_STORE_CTX_get_current_cert() returns the certificate that
was being tested when our certificate validation callback was called.
Thank you,
Alex.
Use the right certificate when detailing SSL certificate validation errors.
When an _intermediate_ SSL server certificate fails validation, we should
report errors using information in that certificate and not in the top-level
"peer" certificate. Otherwise, our details may make no sense. For example, we
could say that the validation failed due to the expired certificate and show
an expiration date in the future (because the top-level certificate did not
expire but the intermediate certificate did).
OpenSSL X509_STORE_CTX_get_current_cert() returns the certificate that was
being tested when our certificate validation callback was called.
=== modified file 'src/ssl/support.cc'
--- src/ssl/support.cc 2011-10-28 00:19:03 +0000
+++ src/ssl/support.cc 2011-11-15 16:47:37 +0000
@@ -235,41 +235,52 @@
if (!ok) {
if (const char *err_descr = Ssl::GetErrorDescr(error_no))
debugs(83, 5, err_descr << ": " << buffer);
else
debugs(83, DBG_IMPORTANT, "SSL unknown certificate error " << error_no << " in " << buffer);
if (check) {
Filled(check)->ssl_error = error_no;
if (check->fastCheck() == ACCESS_ALLOWED) {
debugs(83, 3, "bypassing SSL error " << error_no << " in " << buffer);
ok = 1;
} else {
debugs(83, 5, "confirming SSL error " << error_no);
}
}
}
if (!dont_verify_domain && server) {}
if (!ok && !SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) ) {
- Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail(error_no, peer_cert);
+
+ // Find the broken certificate. It may be intermediate.
+ X509 *broken_cert = peer_cert; // reasonable default if search fails
+ // Our SQUID_X509_V_ERR_DOMAIN_MISMATCH implies peer_cert is at fault.
+ if (error_no != SQUID_X509_V_ERR_DOMAIN_MISMATCH) {
+ if (X509 *last_used_cert = X509_STORE_CTX_get_current_cert(ctx))
+ broken_cert = last_used_cert;
+ }
+
+ Ssl::ErrorDetail *errDetail =
+ new Ssl::ErrorDetail(error_no, broken_cert);
+
if (!SSL_set_ex_data(ssl, ssl_ex_index_ssl_error_detail, errDetail)) {
debugs(83, 2, "Failed to set Ssl::ErrorDetail in ssl_verify_cb: Certificate " << buffer);
delete errDetail;
}
}
return ok;
}
/// \ingroup ServerProtocolSSLInternal
static struct ssl_option {
const char *name;
long value;
}
ssl_options[] = {
#if SSL_OP_MICROSOFT_SESS_ID_BUG
{
"MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG