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