#if USE_OPENSSL
/// SSL [certificate validation] errors, in undefined order
- Ssl::CertErrors *sslErrors;
+ const Ssl::CertErrors *sslErrors;
/// The peer certificate
Security::CertPointer serverCert;
#endif
ACLFilledChecklist checklist(NULL, sslServerBump->request.getRaw(),
clientConnection != NULL ? clientConnection->rfc931 : dash_str);
- checklist.sslErrors = cbdataReference(sslServerBump->sslErrors);
+ checklist.sslErrors = cbdataReference(sslServerBump->sslErrors());
for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != NULL; ca = ca->next) {
// If the algorithm already set, then ignore it.
if (al->request && al->request->clientConnectionManager.valid()) {
if (Ssl::ServerBump * srvBump = al->request->clientConnectionManager->serverBump()) {
const char *separator = fmt->data.string ? fmt->data.string : ":";
- for (Ssl::CertErrors *sslError = srvBump->sslErrors; sslError != NULL; sslError = sslError->next) {
+ for (Ssl::CertErrors const *sslError = srvBump->sslErrors(); sslError != NULL; sslError = sslError->next) {
if (sb.size())
sb.append(separator);
if (const char *errorName = Ssl::GetErrorName(sslError->element.code))
#endif
#endif
-/*
- * NOTE: we use TidyPointer for sessions. OpenSSL provides explicit reference
- * locking mechanisms, but GnuTLS only provides init/deinit. To ensure matching
- * behaviour we cannot use LockingPointer (yet) and must ensure that there is
- * no possibility of double-free being used on the raw pointers. That is
- * currently done by using a TidyPointer in the global fde table so its
- * lifetime matched the connection.
- */
-
namespace Security {
#if USE_OPENSSL
typedef SSL* SessionPtr;
CtoCpp1(SSL_free, SSL *);
-typedef TidyPointer<SSL, Security::SSL_free_cpp> SessionPointer;
+typedef LockingPointer<SSL, Security::SSL_free_cpp, CRYPTO_LOCK_SSL> SessionPointer;
#elif USE_GNUTLS
typedef gnutls_session_t SessionPtr;
CtoCpp1(gnutls_deinit, gnutls_session_t);
+// TODO: Convert to Locking pointer.
+// Locks can be implemented attaching locks counter to gnutls_session_t
+// objects using the gnutls_session_set_ptr()/gnutls_session_get_ptr ()
+// library functions
typedef TidyPointer<struct gnutls_session_int, Security::gnutls_deinit_cpp> SessionPointer;
#else
Ssl::setClientSNI(ssl, sniServer);
}
- // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
- X509 *peeked_cert;
- if (csd->serverBump() &&
- (peeked_cert = csd->serverBump()->serverCert.get())) {
- CRYPTO_add(&(peeked_cert->references),1,CRYPTO_LOCK_X509);
- SSL_set_ex_data(ssl, ssl_ex_index_ssl_peeked_cert, peeked_cert);
+ if (Ssl::ServerBump *serverBump = csd->serverBump()) {
+ serverBump->attachServerSSL(ssl);
+ // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
+ if (X509 *peeked_cert = serverBump->serverCert.get()) {
+ CRYPTO_add(&(peeked_cert->references),1,CRYPTO_LOCK_X509);
+ SSL_set_ex_data(ssl, ssl_ex_index_ssl_peeked_cert, peeked_cert);
+ }
}
}
// remember the server certificate from the ErrorDetail object
if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
- // remember validation errors, if any
- if (certErrors) {
- if (serverBump->sslErrors)
- cbdataReferenceDone(serverBump->sslErrors);
- serverBump->sslErrors = cbdataReference(certErrors);
- }
-
if (!serverBump->serverCert.get()) {
// remember the server certificate from the ErrorDetail object
if (error && error->detail && error->detail->peerCert())
Ssl::PeerConnector::PeerConnector(const Comm::ConnectionPointer &aServerConn, AsyncCall::Pointer &aCallback, const AccessLogEntryPointer &alp, const time_t timeout) :
AsyncJob("Ssl::PeerConnector"),
serverConn(aServerConn),
- certErrors(NULL),
al(alp),
callback(aCallback),
negotiationTimeout(timeout),
Ssl::PeerConnector::~PeerConnector()
{
- cbdataReferenceDone(certErrors);
debugs(83, 5, "Peer connector " << this << " gone");
}
{
Must(validationResponse != NULL);
- Ssl::CertErrors *errs = NULL;
Ssl::ErrorDetail *errDetails = NULL;
bool validatorFailed = false;
if (!Comm::IsConnOpen(serverConnection())) {
debugs(83,5, request->url.host() << " cert validation result: " << validationResponse->resultCode);
- if (validationResponse->resultCode == ::Helper::Error)
- errs = sslCrtvdCheckForErrors(*validationResponse, errDetails);
- else if (validationResponse->resultCode != ::Helper::Okay)
+ if (validationResponse->resultCode == ::Helper::Error) {
+ if (Ssl::CertErrors *errs = sslCrtvdCheckForErrors(*validationResponse, errDetails)) {
+ Security::SessionPtr ssl = fd_table[serverConnection()->fd].ssl.get();
+ Ssl::CertErrors *oldErrs = static_cast<Ssl::CertErrors*>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors));
+ SSL_set_ex_data(ssl, ssl_ex_index_ssl_errors, (void *)errs);
+ delete oldErrs;
+ }
+ } else if (validationResponse->resultCode != ::Helper::Okay)
validatorFailed = true;
if (!errDetails && !validatorFailed) {
return;
}
- if (errs) {
- if (certErrors)
- cbdataReferenceDone(certErrors);
- certErrors = cbdataReference(errs);
- }
-
ErrorState *anErr = NULL;
if (validatorFailed) {
anErr = new ErrorState(ERR_GATEWAY_FAILURE, Http::scInternalServerError, request.getRaw());
if (ssl_lib_error != SSL_ERROR_NONE)
anErr->detail->setLibError(ssl_lib_error);
- assert(certErrors == NULL);
- // remember validation errors, if any
- if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors*>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
- certErrors = cbdataReference(errs);
-
noteNegotiationDone(anErr);
bail(anErr);
}
HttpRequestPointer request; ///< peer connection trigger or cause
Comm::ConnectionPointer serverConn; ///< TCP connection to the peer
- /// Certificate errors found from SSL validation procedure or from cert
- /// validator
- Ssl::CertErrors *certErrors;
AccessLogEntryPointer al; ///< info for the future access.log entry
AsyncCall::Pointer callback; ///< we call this with the results
private:
Ssl::ServerBump::ServerBump(HttpRequest *fakeRequest, StoreEntry *e, Ssl::BumpMode md):
request(fakeRequest),
- sslErrors(NULL),
step(bumpStep1)
{
debugs(33, 4, "will peek at " << request->url.authority(true));
storeUnregister(sc, entry, this);
entry->unlock("Ssl::ServerBump");
}
- cbdataReferenceDone(sslErrors);
}
+void
+Ssl::ServerBump::attachServerSSL(SSL *ssl)
+{
+ if (serverSSL.get())
+ return;
+
+ serverSSL.resetAndLock(ssl);
+}
+
+const Ssl::CertErrors *
+Ssl::ServerBump::sslErrors() const
+{
+ if (!serverSSL.get())
+ return NULL;
+
+ const Ssl::CertErrors *errs = static_cast<const Ssl::CertErrors*>(SSL_get_ex_data(serverSSL.get(), ssl_ex_index_ssl_errors));
+ return errs;
+}
public:
explicit ServerBump(HttpRequest *fakeRequest, StoreEntry *e = NULL, Ssl::BumpMode mode = Ssl::bumpServerFirst);
~ServerBump();
+ void attachServerSSL(SSL *); ///< Sets the server SSL object
+ const Ssl::CertErrors *sslErrors() const; ///< SSL [certificate validation] errors
/// faked, minimal request; required by Client API
HttpRequest::Pointer request;
StoreEntry *entry; ///< for receiving Squid-generated error messages
- Security::CertPointer serverCert; ///< HTTPS server certificate
- Ssl::CertErrors *sslErrors; ///< SSL [certificate validation] errors
+ /// HTTPS server certificate. Maybe it is different than the one
+ /// it is stored in serverSSL object (error SQUID_X509_V_ERR_CERT_CHANGE)
+ Security::CertPointer serverCert;
struct {
Ssl::BumpMode step1; ///< The SSL bump mode at step1
Ssl::BumpMode step2; ///< The SSL bump mode at step2
} act; ///< bumping actions at various bumping steps
Ssl::BumpStep step; ///< The SSL bumping step
SBuf clientSni; ///< the SSL client SNI name
+ Security::SessionPointer serverSSL; ///< The SSL object on server side.
private:
store_client *sc; ///< dummy client to prevent entry trimming