#else
err->xerrno = EACCES;
#endif
- Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail( SQUID_X509_V_ERR_DOMAIN_MISMATCH, server_cert);
+ Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail( SQUID_X509_V_ERR_DOMAIN_MISMATCH, server_cert, NULL);
err->detail = errDetail;
repContext->setReplyToError(request->method, err);
assert(context->http->out.offset == 0);
} else {
// server_cert can be be NULL
X509 *server_cert = SSL_get_peer_certificate(ssl);
- errDetails = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, server_cert);
+ errDetails = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, server_cert, NULL);
X509_free(server_cert);
}
if (ssl_lib_error != SSL_ERROR_NONE)
errDetails->setLibError(ssl_lib_error);
- X509 *srvX509 = errDetails->peerCert();
if (request->clientConnectionManager.valid()) {
// Get the server certificate from ErrorDetail object and store it
// to connection manager
- request->clientConnectionManager->setBumpServerCert(X509_dup(srvX509));
+ request->clientConnectionManager->setBumpServerCert(X509_dup(errDetails->peerCert()));
// if there is a list of ssl errors, pass it to connection manager
if (Ssl::Errors *errNoList = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_sslerrno)))
if (request->flags.sslPeek) {
// If possible, set host name to server certificate CN.
- if (srvX509) {
+ if (X509 *srvX509 = errDetails->brokenCert()) {
if (const char *name = Ssl::CommonHostName(srvX509)) {
request->SetHost(name);
debugs(83, 3, HERE << "reset request host: " << name);
return errDetailStr;
}
-/* We may do not want to use X509_dup but instead
- internal SSL locking:
- CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509);
- peer_cert.reset(cert);
-*/
-Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert): error_no (err_no), lib_error_no(SSL_ERROR_NONE)
+Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert, X509 *broken): error_no (err_no), lib_error_no(SSL_ERROR_NONE)
{
if (cert)
- peer_cert.reset(X509_dup(cert));
+ peer_cert.resetAndLock(cert);
+
+ if (broken)
+ broken_cert.resetAndLock(broken);
+ else
+ broken_cert.resetAndLock(cert);
detailEntry.error_no = SSL_ERROR_NONE;
}
request = anErrDetail.request;
if (anErrDetail.peer_cert.get()) {
- peer_cert.reset(X509_dup(anErrDetail.peer_cert.get()));
+ peer_cert.resetAndLock(anErrDetail.peer_cert.get());
+ }
+
+ if (anErrDetail.broken_cert.get()) {
+ broken_cert.resetAndLock(anErrDetail.broken_cert.get());
}
detailEntry = anErrDetail.detailEntry;
class ErrorDetail
{
public:
- ErrorDetail(ssl_error_t err_no, X509 *cert);
+ // if broken certificate is nil, the peer certificate is broken
+ ErrorDetail(ssl_error_t err_no, X509 *peer, X509 *broken);
ErrorDetail(ErrorDetail const &);
const String &toString() const; ///< An error detail string to embed in squid error pages
void useRequest(HttpRequest *aRequest) { if (aRequest != NULL) request = aRequest;}
void setLibError(unsigned long lib_err_no) {lib_error_no = lib_err_no;}
///The peer certificate
X509 *peerCert() { return peer_cert.get(); }
+ /// peer or intermediate certificate that failed validation
+ X509 *brokenCert() {return broken_cert.get(); }
private:
typedef const char * (ErrorDetail::*fmt_action_t)() const;
/**
ssl_error_t error_no; ///< The error code
unsigned long lib_error_no; ///< low-level error returned by OpenSSL ERR_get_error(3SSL)
X509_Pointer peer_cert; ///< A pointer to the peer certificate
+ X509_Pointer broken_cert; ///< A pointer to the broken certificate (peer or intermediate)
mutable ErrorDetailEntry detailEntry;
HttpRequest::Pointer request;
};
}
Ssl::ErrorDetail *errDetail =
- new Ssl::ErrorDetail(error_no, broken_cert);
+ new Ssl::ErrorDetail(error_no, peer_cert, 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);