SQUID_STATE_ROLLBACK(check_TXTDB)
])
-dnl Check if we can rewrite the hello message stored in an SSL object.
-dnl The tests are very basic, just check if the required members exist in
-dnl SSL structure.
-AC_DEFUN([SQUID_CHECK_OPENSSL_HELLO_OVERWRITE_HACK],[
- AH_TEMPLATE(SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK, "Define to 1 if hello message can be overwritten in SSL struct")
- SQUID_STATE_SAVE(check_openSSL_overwrite_hack)
- AC_MSG_CHECKING(whether hello message can be overwritten in SSL struct)
-
- AC_COMPILE_IFELSE([
- AC_LANG_PROGRAM(
- [
- #include <openssl/ssl.h>
- #include <openssl/err.h>
- #include <assert.h>
- ],
- [
- SSL *ssl;
- char *random, *msg;
- memcpy(ssl->s3->client_random, random, SSL3_RANDOM_SIZE);
- SSL3_BUFFER *wb=&(ssl->s3->wbuf);
- assert(wb->len == 0);
- memcpy(wb->buf, msg, 0);
- assert(wb->left == 0);
- memcpy(ssl->init_buf->data, msg, 0);
- ssl->init_num = 0;
- ssl->s3->wpend_ret = 0;
- ssl->s3->wpend_tot = 0;
- SSL_CIPHER *cipher = 0;
- assert(SSL_CIPHER_get_id(cipher));
- ])
- ],
- [
- AC_MSG_RESULT([possibly; to try, set SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK macro value to 1])
- ],
- [
- AC_MSG_RESULT([no])
- ],
- [])
-
-SQUID_STATE_ROLLBACK(check_openSSL_overwrite_hack)
-]
-)
return bytes;
}
-// This function makes the required checks to examine if the client hello
-// message is compatible with the features provided by OpenSSL toolkit.
-// If the features are compatible and can be supported it tries to rewrite SSL
-// structure members, to replace the hello message created by openSSL, with the
-// web client SSL hello message.
-// This is mostly possible in the cases where the web client uses openSSL
-// library similar with this one used by squid.
-static bool
-adjustSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, SBuf &helloMessage)
-{
-#if SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK
- if (!details)
- return false;
-
- if (!ssl->s3) {
- debugs(83, 5, "No SSLv3 data found!");
- return false;
- }
-
- // If the client supports compression but our context does not support
- // we can not adjust.
-#if !defined(OPENSSL_NO_COMP)
- const bool requireCompression = (details->compressionSupported && ssl->ctx->comp_methods == nullptr);
-#else
- const bool requireCompression = details->compressionSupported;
-#endif
- if (requireCompression) {
- debugs(83, 5, "Client Hello Data supports compression, but we do not!");
- return false;
- }
-
-#if !defined(SSL_TLSEXT_HB_ENABLED)
- if (details->doHeartBeats) {
- debugs(83, 5, "Client Hello Data supports HeartBeats but we do not support!");
- return false;
- }
-#endif
-
- if (details->unsupportedExtensions) {
- debugs(83, 5, "Client Hello contains extensions that we do not support!");
- return false;
- }
-
- SSL3_BUFFER *wb=&(ssl->s3->wbuf);
- if (wb->len < (size_t)helloMessage.length()) {
- debugs(83, 5, "Client Hello exceeds OpenSSL buffer: " << helloMessage.length() << " >= " << wb->len);
- return false;
- }
-
- /* Check whether all on-the-wire ciphers are supported by OpenSSL. */
-
- const auto &wireCiphers = details->ciphers;
- Security::TlsDetails::Ciphers::size_type ciphersToFind = wireCiphers.size();
-
- // RFC 5746: "TLS_EMPTY_RENEGOTIATION_INFO_SCSV is not a true cipher suite".
- // It is commonly seen on the wire, including in from-OpenSSL traffic, but
- // SSL_get_ciphers() does not return this _pseudo_ cipher suite in my tests.
- // If OpenSSL supports scsvCipher, we count it (at most once) further below.
-#if defined(TLSEXT_TYPE_renegotiate)
- // the 0x00FFFF mask converts 3-byte OpenSSL cipher to our 2-byte cipher
- const uint16_t scsvCipher = SSL3_CK_SCSV & 0x00FFFF;
-#else
- const uint16_t scsvCipher = 0;
-#endif
-
- STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl);
- const int supportedCipherCount = sk_SSL_CIPHER_num(cipher_stack);
- for (int idx = 0; idx < supportedCipherCount && ciphersToFind > 0; ++idx) {
- const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(cipher_stack, idx);
- const auto id = SSL_CIPHER_get_id(cipher) & 0x00FFFF;
- if (wireCiphers.find(id) != wireCiphers.end() && (!scsvCipher || id != scsvCipher))
- --ciphersToFind;
- }
-
- if (ciphersToFind > 0 && scsvCipher && wireCiphers.find(scsvCipher) != wireCiphers.end())
- --ciphersToFind;
-
- if (ciphersToFind > 0) {
- // TODO: Add slowlyReportUnsupportedCiphers() to slowly find and report each of them
- debugs(83, 5, "Client Hello Data has " << ciphersToFind << " ciphers that we do not support!");
- return false;
- }
-
- debugs(83, 5, "OpenSSL SSL struct will be adjusted to mimic client hello data!");
-
- //Adjust ssl structure data.
- // We need to fix the random in SSL struct:
- if (details->clientRandom.length() == SSL3_RANDOM_SIZE)
- memcpy(ssl->s3->client_random, details->clientRandom.c_str(), SSL3_RANDOM_SIZE);
- memcpy(wb->buf, helloMessage.rawContent(), helloMessage.length());
- wb->left = helloMessage.length();
-
- size_t mainHelloSize = helloMessage.length() - 5;
- const char *mainHello = helloMessage.rawContent() + 5;
- assert((size_t)ssl->init_buf->max > mainHelloSize);
- memcpy(ssl->init_buf->data, mainHello, mainHelloSize);
- debugs(83, 5, "Hello Data init and adjustd sizes :" << ssl->init_num << " = "<< mainHelloSize);
- ssl->init_num = mainHelloSize;
- ssl->s3->wpend_ret = mainHelloSize;
- ssl->s3->wpend_tot = mainHelloSize;
- return true;
-#else
- (void)ssl;
- (void)details;
- (void)helloMessage;
- return false;
-#endif
-}
-
int
Ssl::ServerBio::write(const char *buf, int size, BIO *table)
{
if (bumpMode_ == Ssl::bumpPeek) {
// we should not be here if we failed to parse the client-sent ClientHello
Must(!clientSentHello.isEmpty());
- if (adjustSSL(ssl, clientTlsDetails, clientSentHello))
- allowBump = true;
allowSplice = true;
// Replace OpenSSL-generated ClientHello with client-sent one.
helloMsg.append(clientSentHello);
debugs(83, 7, "FD " << fd_ << ": Using client-sent ClientHello for peek mode");
} else { /*Ssl::bumpStare*/
allowBump = true;
- if (!clientSentHello.isEmpty() && adjustSSL(ssl, clientTlsDetails, clientSentHello)) {
- allowSplice = true;
- helloMsg.append(clientSentHello);
- debugs(83, 7, "FD " << fd_ << ": Using client-sent ClientHello for stare mode");
- }
}
}
// if we did not use the client-sent ClientHello, then use the OpenSSL-generated one