/*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
#if USE_OPENSSL
#include "comm.h"
+#include "fd.h"
#include "fde.h"
#include "globals.h"
#include "ip/Address.h"
+#include "parser/BinaryTokenizer.h"
+#include "SquidTime.h"
#include "ssl/bio.h"
-#if HAVE_OPENSSL_SSL_H
-#include <openssl/ssl.h>
-#endif
-
#if _SQUID_WINDOWS_
extern int socket_read_method(int, char *, int);
extern int socket_write_method(int, const char *, int);
/* SSL callbacks */
static void squid_ssl_info(const SSL *ssl, int where, int ret);
+#if HAVE_LIBCRYPTO_BIO_METH_NEW
+static BIO_METHOD *SquidMethods = nullptr;
+#else
/// Initialization structure for the BIO table with
/// Squid-specific methods and BIO method wrappers.
static BIO_METHOD SquidMethods = {
squid_bio_destroy,
NULL // squid_callback_ctrl not supported
};
+#endif
BIO *
-Ssl::Bio::Create(const int fd, Ssl::Bio::Type type)
-{
- if (BIO *bio = BIO_new(&SquidMethods)) {
+Ssl::Bio::Create(const int fd, Security::Io::Type type)
+{
+#if HAVE_LIBCRYPTO_BIO_METH_NEW
+ if (!SquidMethods) {
+ SquidMethods = BIO_meth_new(BIO_TYPE_SOCKET, "squid");
+ BIO_meth_set_write(SquidMethods, squid_bio_write);
+ BIO_meth_set_read(SquidMethods, squid_bio_read);
+ BIO_meth_set_puts(SquidMethods, squid_bio_puts);
+ BIO_meth_set_gets(SquidMethods, NULL);
+ BIO_meth_set_ctrl(SquidMethods, squid_bio_ctrl);
+ BIO_meth_set_create(SquidMethods, squid_bio_create);
+ BIO_meth_set_destroy(SquidMethods, squid_bio_destroy);
+ }
+ BIO_METHOD *useMethod = SquidMethods;
+#else
+ BIO_METHOD *useMethod = &SquidMethods;
+#endif
+
+ if (BIO *bio = BIO_new(useMethod)) {
BIO_int_ctrl(bio, BIO_C_SET_FD, type, fd);
return bio;
}
return result;
}
-int
-Ssl::Bio::readAndBuffer(char *buf, int size, BIO *table, const char *description)
-{
- prepReadBuf();
-
- size = min((int)rbuf.potentialSpaceSize(), size);
- if (size <= 0) {
- debugs(83, DBG_IMPORTANT, "Not enough space to hold " <<
- rbuf.contentSize() << "+ byte " << description);
- return -1;
- }
-
- const int bytes = Ssl::Bio::read(buf, size, table);
- debugs(83, 5, "read " << bytes << " out of " << size << " bytes"); // move to Ssl::Bio::read()
-
- if (bytes > 0) {
- rbuf.append(buf, bytes);
- debugs(83, 5, "recorded " << bytes << " bytes of " << description);
- }
- return bytes;
-}
-
/// Called whenever the SSL connection state changes, an alert appears, or an
/// error occurs. See SSL_set_info_callback().
void
SSL_state_string(ssl) << " (" << SSL_state_string_long(ssl) << ")");
}
-void
-Ssl::Bio::prepReadBuf()
+Ssl::ClientBio::ClientBio(const int anFd):
+ Bio(anFd),
+ holdRead_(false),
+ holdWrite_(false),
+ helloSize(0),
+ abortReason(nullptr)
{
- if (rbuf.isNull())
- rbuf.init(4096, 65536);
-}
-
-bool
-Ssl::ClientBio::isClientHello(int state)
-{
- return (
- state == SSL3_ST_SR_CLNT_HELLO_A ||
- state == SSL23_ST_SR_CLNT_HELLO_A ||
- state == SSL23_ST_SR_CLNT_HELLO_B ||
- state == SSL3_ST_SR_CLNT_HELLO_B ||
- state == SSL3_ST_SR_CLNT_HELLO_C
- );
+ renegotiations.configure(10*1000);
}
void
Ssl::ClientBio::stateChanged(const SSL *ssl, int where, int ret)
{
Ssl::Bio::stateChanged(ssl, where, ret);
+ // detect client-initiated renegotiations DoS (CVE-2011-1473)
+ if (where & SSL_CB_HANDSHAKE_START) {
+ const int reneg = renegotiations.count(1);
+
+ if (abortReason)
+ return; // already decided and informed the admin
+
+ if (reneg > RenegotiationsLimit) {
+ abortReason = "renegotiate requests flood";
+ debugs(83, DBG_IMPORTANT, "Terminating TLS connection [from " << fd_table[fd_].ipaddr << "] due to " << abortReason << ". This connection received " <<
+ reneg << " renegotiate requests in the last " <<
+ RenegotiationsWindow << " seconds (and " <<
+ renegotiations.remembered() << " requests total).");
+ }
+ }
}
int
Ssl::ClientBio::write(const char *buf, int size, BIO *table)
{
+ if (abortReason) {
+ debugs(83, 3, "BIO on FD " << fd_ << " is aborted");
+ BIO_clear_retry_flags(table);
+ return -1;
+ }
+
if (holdWrite_) {
BIO_set_retry_write(table);
return 0;
return Ssl::Bio::write(buf, size, table);
}
-const char *objToString(unsigned char const *bytes, int len)
-{
- static std::string buf;
- buf.clear();
- for (int i = 0; i < len; i++ ) {
- char tmp[3];
- snprintf(tmp, sizeof(tmp), "%.2x", bytes[i]);
- buf.append(tmp);
- }
- return buf.c_str();
-}
-
int
Ssl::ClientBio::read(char *buf, int size, BIO *table)
{
- if (helloState < atHelloReceived) {
- int bytes = readAndBuffer(buf, size, table, "TLS client Hello");
- if (bytes <= 0)
- return bytes;
- }
-
- if (helloState == atHelloNone) {
- helloSize = features.parseMsgHead(rbuf);
- if (helloSize == 0) {
- // Not enough bytes to get hello message size
- BIO_set_retry_read(table);
- return -1;
- } else if (helloSize < 0) {
- wrongProtocol = true;
- return -1;
- }
-
- helloState = atHelloStarted; //Next state
- }
-
- if (helloState == atHelloStarted) {
- const unsigned char *head = (const unsigned char *)rbuf.content();
- const char *s = objToString(head, rbuf.contentSize());
- debugs(83, 7, "SSL Header: " << s);
-
- if (helloSize > rbuf.contentSize()) {
- BIO_set_retry_read(table);
- return -1;
- }
- features.get(rbuf);
- helloState = atHelloReceived;
+ if (abortReason) {
+ debugs(83, 3, "BIO on FD " << fd_ << " is aborted");
+ BIO_clear_retry_flags(table);
+ return -1;
}
if (holdRead_) {
return -1;
}
- if (helloState == atHelloReceived) {
- if (rbuf.hasContent()) {
- int bytes = (size <= rbuf.contentSize() ? size : rbuf.contentSize());
- memcpy(buf, rbuf.content(), bytes);
- rbuf.consume(bytes);
- return bytes;
- } else
- return Ssl::Bio::read(buf, size, table);
- }
+ if (!rbuf.isEmpty()) {
+ int bytes = (size <= (int)rbuf.length() ? size : rbuf.length());
+ memcpy(buf, rbuf.rawContent(), bytes);
+ rbuf.consume(bytes);
+ return bytes;
+ } else
+ return Ssl::Bio::read(buf, size, table);
return -1;
}
+Ssl::ServerBio::ServerBio(const int anFd):
+ Bio(anFd),
+ helloMsgSize(0),
+ helloBuild(false),
+ allowSplice(false),
+ allowBump(false),
+ holdWrite_(false),
+ record_(false),
+ parsedHandshake(false),
+ parseError(false),
+ bumpMode_(bumpNone),
+ rbufConsumePos(0),
+ parser_(Security::HandshakeParser::fromServer)
+{
+}
+
void
Ssl::ServerBio::stateChanged(const SSL *ssl, int where, int ret)
{
}
void
-Ssl::ServerBio::setClientFeatures(const Ssl::Bio::sslFeatures &features)
+Ssl::ServerBio::setClientFeatures(Security::TlsDetails::Pointer const &details, SBuf const &aHello)
{
- clientFeatures = features;
+ clientTlsDetails = details;
+ clientSentHello = aHello;
};
int
Ssl::ServerBio::read(char *buf, int size, BIO *table)
{
- return record_ ?
- readAndBuffer(buf, size, table, "TLS server Hello") : Ssl::Bio::read(buf, size, table);
+ if (parsedHandshake) // done parsing TLS Hello
+ return readAndGive(buf, size, table);
+ else
+ return readAndParse(buf, size, table);
+}
+
+/// Read and give everything to OpenSSL.
+int
+Ssl::ServerBio::readAndGive(char *buf, const int size, BIO *table)
+{
+ // If we have unused buffered bytes, give those bytes to OpenSSL now,
+ // before reading more. TODO: Read if we have buffered less than size?
+ if (rbufConsumePos < rbuf.length())
+ return giveBuffered(buf, size);
+
+ if (record_) {
+ const int result = readAndBuffer(table);
+ if (result <= 0)
+ return result;
+ return giveBuffered(buf, size);
+ }
+
+ return Ssl::Bio::read(buf, size, table);
+}
+
+/// Read and give everything to our parser.
+/// When/if parsing is finished (successfully or not), start giving to OpenSSL.
+int
+Ssl::ServerBio::readAndParse(char *buf, const int size, BIO *table)
+{
+ const int result = readAndBuffer(table);
+ if (result <= 0)
+ return result;
+
+ try {
+ if (!parser_.parseHello(rbuf)) {
+ // need more data to finish parsing
+ BIO_set_retry_read(table);
+ return -1;
+ }
+ parsedHandshake = true; // done parsing (successfully)
+ }
+ catch (const std::exception &ex) {
+ debugs(83, 2, "parsing error on FD " << fd_ << ": " << ex.what());
+ parsedHandshake = true; // done parsing (due to an error)
+ parseError = true;
+ }
+
+ return giveBuffered(buf, size);
+}
+
+/// Reads more data into the read buffer. Returns either the number of bytes
+/// read or, on errors (including "try again" errors), a negative number.
+int
+Ssl::ServerBio::readAndBuffer(BIO *table)
+{
+ char *space = rbuf.rawAppendStart(SQUID_TCP_SO_RCVBUF);
+ const int result = Ssl::Bio::read(space, SQUID_TCP_SO_RCVBUF, table);
+ if (result <= 0)
+ return result;
+
+ rbuf.rawAppendFinish(space, result);
+ return result;
+}
+
+/// give previously buffered bytes to OpenSSL
+/// returns the number of bytes given
+int
+Ssl::ServerBio::giveBuffered(char *buf, const int size)
+{
+ if (rbuf.length() <= rbufConsumePos)
+ return -1; // buffered nothing yet
+
+ const int unsent = rbuf.length() - rbufConsumePos;
+ const int bytes = (size <= unsent ? size : unsent);
+ memcpy(buf, rbuf.rawContent() + rbufConsumePos, bytes);
+ rbufConsumePos += bytes;
+ debugs(83, 7, bytes << "<=" << size << " bytes to OpenSSL");
+ return bytes;
}
// This function makes the required checks to examine if the client hello
// 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, Ssl::Bio::sslFeatures &features)
+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 = (features.compressMethod && ssl->ctx->comp_methods == NULL);
+ const bool requireCompression = (details->compressionSupported && ssl->ctx->comp_methods == nullptr);
#else
- const bool requireCompression = features.compressMethod;
+ const bool requireCompression = details->compressionSupported;
#endif
if (requireCompression) {
debugs(83, 5, "Client Hello Data supports compression, but we do not!");
return false;
}
- // Check ciphers list
- size_t token = 0;
- size_t end = 0;
- while (token != std::string::npos) {
- end = features.clientRequestedCiphers.find(':',token);
- std::string cipher;
- cipher.assign(features.clientRequestedCiphers, token, end - token);
- token = (end != std::string::npos ? end + 1 : std::string::npos);
- bool found = false;
- STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl);
- for (int i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
- SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
- const char *cname = SSL_CIPHER_get_name(c);
- if (cipher.compare(cname)) {
- found = true;
- break;
- }
- }
- if (!found) {
- debugs(83, 5, "Client Hello Data supports cipher '"<< cipher <<"' but we do not support it!");
- return false;
- }
- }
-
#if !defined(SSL_TLSEXT_HB_ENABLED)
- if (features.doHeartBeats) {
+ if (details->doHeartBeats) {
debugs(83, 5, "Client Hello Data supports HeartBeats but we do not support!");
return false;
}
#endif
- for (std::list<int>::iterator it = features.extensions.begin(); it != features.extensions.end(); ++it) {
- static int supportedExtensions[] = {
-#if defined(TLSEXT_TYPE_server_name)
- TLSEXT_TYPE_server_name,
-#endif
-#if defined(TLSEXT_TYPE_opaque_prf_input)
- TLSEXT_TYPE_opaque_prf_input,
-#endif
-#if defined(TLSEXT_TYPE_heartbeat)
- TLSEXT_TYPE_heartbeat,
-#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)
- TLSEXT_TYPE_renegotiate,
-#endif
-#if defined(TLSEXT_TYPE_ec_point_formats)
- TLSEXT_TYPE_ec_point_formats,
-#endif
-#if defined(TLSEXT_TYPE_elliptic_curves)
- TLSEXT_TYPE_elliptic_curves,
-#endif
-#if defined(TLSEXT_TYPE_session_ticket)
- TLSEXT_TYPE_session_ticket,
-#endif
-#if defined(TLSEXT_TYPE_status_request)
- TLSEXT_TYPE_status_request,
-#endif
-#if defined(TLSEXT_TYPE_use_srtp)
- TLSEXT_TYPE_use_srtp,
-#endif
-#if 0 //Allow 13172 Firefox supported extension for testing purposes
- 13172,
+ // 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
- -1
- };
- bool found = false;
- for (int i = 0; supportedExtensions[i] != -1; i++) {
- if (*it == supportedExtensions[i]) {
- found = true;
- break;
- }
- }
- if (!found) {
- debugs(83, 5, "Extension " << *it << " does not supported!");
- return false;
- }
+
+ 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;
}
- SSL3_BUFFER *wb=&(ssl->s3->wbuf);
- if (wb->len < (size_t)features.helloMessage.length())
+ 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:
- memcpy(ssl->s3->client_random, features.client_random, SSL3_RANDOM_SIZE);
- memcpy(wb->buf, features.helloMessage.rawContent(), features.helloMessage.length());
- wb->left = features.helloMessage.length();
+ 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 = features.helloMessage.length() - 5;
- const char *mainHello = features.helloMessage.rawContent() + 5;
+ 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);
{
if (holdWrite_) {
- debugs(83, 7, "Hold write, for SSL connection on " << fd_ << "will not write bytes of size " << size);
+ debugs(83, 7, "postpone writing " << size << " bytes to SSL FD " << fd_);
BIO_set_retry_write(table);
return -1;
}
if (!helloBuild && (bumpMode_ == Ssl::bumpPeek || bumpMode_ == Ssl::bumpStare)) {
- if (
- buf[1] >= 3 //it is an SSL Version3 message
- && buf[0] == 0x16 // and it is a Handshake/Hello message
- ) {
-
- //Hello message is the first message we write to server
- assert(helloMsg.isEmpty());
-
- SSL *ssl = fd_table[fd_].ssl;
- if (clientFeatures.initialized_ && ssl) {
- if (bumpMode_ == Ssl::bumpPeek) {
- if (adjustSSL(ssl, clientFeatures))
- allowBump = true;
- allowSplice = true;
- helloMsg.append(clientFeatures.helloMessage);
- debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted for peek mode");
- } else { /*Ssl::bumpStare*/
+ // buf contains OpenSSL-generated ClientHello. We assume it has a
+ // complete ClientHello and nothing else, but cannot fully verify
+ // that quickly. We only verify that buf starts with a v3+ record
+ // containing ClientHello.
+ Must(size >= 2); // enough for version and content_type checks below
+ Must(buf[1] >= 3); // record's version.major; determines buf[0] meaning
+ Must(buf[0] == 22); // TLSPlaintext.content_type == handshake in v3+
+
+ //Hello message is the first message we write to server
+ assert(helloMsg.isEmpty());
+
+ if (auto ssl = fd_table[fd_].ssl.get()) {
+ 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;
- if (adjustSSL(ssl, clientFeatures)) {
- allowSplice = true;
- helloMsg.append(clientFeatures.helloMessage);
- debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted for stare mode");
- }
+ 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 do not build any hello message, copy the current
+ // if we did not use the client-sent ClientHello, then use the OpenSSL-generated one
if (helloMsg.isEmpty())
helloMsg.append(buf, size);
bool
Ssl::ServerBio::resumingSession()
{
- if (!serverFeatures.initialized_)
- serverFeatures.get(rbuf, false);
-
- if (!clientFeatures.sessionId.isEmpty() && !serverFeatures.sessionId.isEmpty())
- return clientFeatures.sessionId == serverFeatures.sessionId;
-
- // is this a session resuming attempt using TLS tickets?
- if (clientFeatures.hasTlsTicket &&
- serverFeatures.tlsTicketsExtension &&
- serverFeatures.hasCcsOrNst)
- return true;
+ return parser_.resumingSession;
+}
- return false;
+bool
+Ssl::ServerBio::encryptedCertificates() const
+{
+ return parser_.details->tlsSupportedVersion &&
+ Security::Tls1p3orLater(parser_.details->tlsSupportedVersion);
}
/// initializes BIO table after allocation
static int
squid_bio_create(BIO *bi)
{
+#if !HAVE_LIBCRYPTO_BIO_GET_INIT
bi->init = 0; // set when we store Bio object and socket fd (BIO_C_SET_FD)
bi->num = 0;
- bi->ptr = NULL;
bi->flags = 0;
+#else
+ // No need to set more, openSSL initialize BIO memory to zero.
+#endif
+
+ BIO_set_data(bi, NULL);
return 1;
}
static int
squid_bio_destroy(BIO *table)
{
- delete static_cast<Ssl::Bio*>(table->ptr);
- table->ptr = NULL;
+ delete static_cast<Ssl::Bio*>(BIO_get_data(table));
+ BIO_set_data(table, NULL);
return 1;
}
static int
squid_bio_write(BIO *table, const char *buf, int size)
{
- Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
+ Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table));
assert(bio);
return bio->write(buf, size, table);
}
static int
squid_bio_read(BIO *table, char *buf, int size)
{
- Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
+ Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table));
assert(bio);
return bio->read(buf, size, table);
}
assert(arg2);
const int fd = *static_cast<int*>(arg2);
Ssl::Bio *bio;
- if (arg1 == Ssl::Bio::BIO_TO_SERVER)
+ if (arg1 == Security::Io::BIO_TO_SERVER)
bio = new Ssl::ServerBio(fd);
else
bio = new Ssl::ClientBio(fd);
- assert(!table->ptr);
- table->ptr = bio;
- table->init = 1;
+ assert(!BIO_get_data(table));
+ BIO_set_data(table, bio);
+ BIO_set_init(table, 1);
return 0;
}
case BIO_C_GET_FD:
- if (table->init) {
- Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
+ if (BIO_get_init(table)) {
+ Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table));
assert(bio);
if (arg2)
*static_cast<int*>(arg2) = bio->fd();
return 0;
case BIO_CTRL_FLUSH:
- if (table->init) {
- Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
+ if (BIO_get_init(table)) {
+ Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table));
assert(bio);
bio->flush(table);
return 1;
squid_ssl_info(const SSL *ssl, int where, int ret)
{
if (BIO *table = SSL_get_rbio(ssl)) {
- if (Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr))
+ if (Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table)))
bio->stateChanged(ssl, where, ret);
}
}
-Ssl::Bio::sslFeatures::sslFeatures(): sslVersion(-1), compressMethod(-1), helloMsgSize(0), unknownCiphers(false), doHeartBeats(true), tlsTicketsExtension(false), hasTlsTicket(false), tlsStatusRequest(false), hasCcsOrNst(false), initialized_(false)
-{
- memset(client_random, 0, SSL3_RANDOM_SIZE);
-}
-
-int Ssl::Bio::sslFeatures::toSquidSSLVersion() const
-{
- if (sslVersion == SSL2_VERSION)
- return 2;
- else if (sslVersion == SSL3_VERSION)
- return 3;
- else if (sslVersion == TLS1_VERSION)
- return 4;
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- else if (sslVersion == TLS1_1_VERSION)
- return 5;
- else if (sslVersion == TLS1_2_VERSION)
- return 6;
-#endif
- else
- return 1;
-}
-
-bool
-Ssl::Bio::sslFeatures::get(const SSL *ssl)
-{
- sslVersion = SSL_version(ssl);
- debugs(83, 7, "SSL version: " << SSL_get_version(ssl) << " (" << sslVersion << ")");
-
-#if defined(TLSEXT_NAMETYPE_host_name)
- if (const char *server = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))
- serverName = server;
- debugs(83, 7, "SNI server name: " << serverName);
-#endif
-
-#if !defined(OPENSSL_NO_COMP)
- if (ssl->session->compress_meth)
- compressMethod = ssl->session->compress_meth;
- else if (sslVersion >= 3) //if it is 3 or newer version then compression is disabled
-#endif
- compressMethod = 0;
- debugs(83, 7, "SSL compression: " << compressMethod);
-
- STACK_OF(SSL_CIPHER) * ciphers = NULL;
- if (ssl->server)
- ciphers = ssl->session->ciphers;
- else
- ciphers = ssl->cipher_list;
- if (ciphers) {
- for (int i = 0; i < sk_SSL_CIPHER_num(ciphers); ++i) {
- SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i);
- if (c != NULL) {
- if (!clientRequestedCiphers.empty())
- clientRequestedCiphers.append(":");
- clientRequestedCiphers.append(c->name);
- }
- }
- }
- debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers);
-
- if (sslVersion >=3 && ssl->s3 && ssl->s3->client_random[0]) {
- memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE);
- }
-
-#if 0 /* XXX: OpenSSL 0.9.8k lacks at least some of these tlsext_* fields */
- //The following extracted for logging purpuses:
- // TLSEXT_TYPE_ec_point_formats
- unsigned char *p;
- int len;
- if (ssl->server) {
- p = ssl->session->tlsext_ecpointformatlist;
- len = ssl->session->tlsext_ecpointformatlist_length;
- } else {
- p = ssl->tlsext_ecpointformatlist;
- len = ssl->tlsext_ecpointformatlist_length;
- }
- if (p) {
- ecPointFormatList = objToString(p, len);
- debugs(83, 7, "tlsExtension ecPointFormatList of length " << len << " :" << ecPointFormatList);
- }
-
- // TLSEXT_TYPE_elliptic_curves
- if (ssl->server) {
- p = ssl->session->tlsext_ellipticcurvelist;
- len = ssl->session->tlsext_ellipticcurvelist_length;
- } else {
- p = ssl->tlsext_ellipticcurvelist;
- len = ssl->tlsext_ellipticcurvelist_length;
- }
- if (p) {
- ellipticCurves = objToString(p, len);
- debugs(83, 7, "tlsExtension ellipticCurveList of length " << len <<" :" << ellipticCurves);
- }
- // TLSEXT_TYPE_opaque_prf_input
- p = NULL;
- if (ssl->server) {
- if (ssl->s3 && ssl->s3->client_opaque_prf_input) {
- p = (unsigned char *)ssl->s3->client_opaque_prf_input;
- len = ssl->s3->client_opaque_prf_input_len;
- }
- } else {
- p = (unsigned char *)ssl->tlsext_opaque_prf_input;
- len = ssl->tlsext_opaque_prf_input_len;
- }
- if (p) {
- debugs(83, 7, "tlsExtension client-opaque-prf-input of length " << len);
- opaquePrf = objToString(p, len);
- }
-#endif
- initialized_ = true;
- return true;
-}
-
-int
-Ssl::Bio::sslFeatures::parseMsgHead(const MemBuf &buf)
-{
- const unsigned char *head = (const unsigned char *)buf.content();
- const char *s = objToString(head, buf.contentSize());
- debugs(83, 7, "SSL Header: " << s);
- if (buf.contentSize() < 5)
- return 0;
-
- if (helloMsgSize > 0)
- return helloMsgSize;
-
- // Check for SSLPlaintext/TLSPlaintext record
- // RFC6101 section 5.2.1
- // RFC5246 section 6.2.1
- if (head[0] == 0x16) {
- debugs(83, 7, "SSL version 3 handshake message");
- // The SSL version exist in the 2nd and 3rd bytes
- sslVersion = (head[1] << 8) | head[2];
- debugs(83, 7, "SSL Version :" << std::hex << std::setw(8) << std::setfill('0') << sslVersion);
- // The hello message size exist in 4th and 5th bytes
- helloMsgSize = (head[3] << 8) + head[4];
- debugs(83, 7, "SSL Header Size: " << helloMsgSize);
- helloMsgSize +=5;
- } else if ((head[0] & 0x80) && head[2] == 0x01 && head[3] == 0x03) {
- debugs(83, 7, "SSL version 2 handshake message with v3 support");
- sslVersion = (head[3] << 8) | head[4];
- debugs(83, 7, "SSL Version :" << std::hex << std::setw(8) << std::setfill('0') << sslVersion);
- // The hello message size exist in 2nd byte
- helloMsgSize = head[1];
- helloMsgSize +=2;
- } else {
- debugs(83, 7, "Not an SSL acceptable handshake message (SSLv2 message?)");
- return (helloMsgSize = -1);
- }
-
- // Set object as initialized. Even if we did not full parsing yet
- // The basic features, like the SSL version is set
- initialized_ = true;
- return helloMsgSize;
-}
-
-bool
-Ssl::Bio::sslFeatures::checkForCcsOrNst(const unsigned char *msg, size_t size)
-{
- while (size > 5) {
- const int msgType = msg[0];
- const int msgSslVersion = (msg[1] << 8) | msg[2];
- debugs(83, 7, "SSL Message Version :" << std::hex << std::setw(8) << std::setfill('0') << msgSslVersion);
- // Check for Change Cipher Spec message
- // RFC5246 section 6.2.1
- if (msgType == 0x14) {// Change Cipher Spec message found
- debugs(83, 7, "SSL Change Cipher Spec message found");
- return true;
- }
- // Check for New Session Ticket message
- // RFC5077 section 3.3
- if (msgType == 0x04) {// New Session Ticket message found
- debugs(83, 7, "TLS New Session Ticket message found");
- return true;
- }
- // The hello message size exist in 4th and 5th bytes
- size_t msgLength = (msg[3] << 8) + msg[4];
- debugs(83, 7, "SSL Message Size: " << msgLength);
- msgLength += 5;
-
- if (msgLength <= size) {
- msg += msgLength;
- size -= msgLength;
- } else
- size = 0;
- }
- return false;
-}
-
-bool
-Ssl::Bio::sslFeatures::get(const MemBuf &buf, bool record)
-{
- int msgSize;
- if ((msgSize = parseMsgHead(buf)) <= 0) {
- debugs(83, 7, "Not a known SSL handshake message");
- return false;
- }
-
- if (msgSize > buf.contentSize()) {
- debugs(83, 2, "Partial SSL handshake message, can not parse!");
- return false;
- }
-
- if (record) {
- helloMessage.clear();
- helloMessage.append(buf.content(), buf.contentSize());
- }
-
- const unsigned char *msg = (const unsigned char *)buf.content();
- if (msg[0] & 0x80)
- return parseV23Hello(msg, (size_t)msgSize);
- else {
- // Hello messages require 5 bytes header + 1 byte Msg type + 3 bytes for Msg size
- if (buf.contentSize() < 9)
- return false;
-
- // Check for the Handshake/Message type
- // The type 2 is a ServerHello, the type 1 is a ClientHello
- // RFC5246 section 7.4
- if (msg[5] == 0x2) { // ServerHello message
- if (parseV3ServerHello(msg, (size_t)msgSize)) {
- hasCcsOrNst = checkForCcsOrNst(msg + msgSize, buf.contentSize() - msgSize);
- return true;
- }
- } else if (msg[5] == 0x1) // ClientHello message,
- return parseV3Hello(msg, (size_t)msgSize);
- }
-
- return false;
-}
-
-bool
-Ssl::Bio::sslFeatures::parseV3ServerHello(const unsigned char *messageContainer, size_t messageContainerSize)
-{
- // Parse a ServerHello Handshake message
- // RFC5246 section 7.4, 7.4.1.3
- // The ServerHello starts at messageContainer + 5
- const unsigned char *serverHello = messageContainer + 5;
-
- // The Length field (bytes 1-3) plus 4 bytes of the serverHello message header (1 handshake type + 3 hello length)
- const size_t helloSize = ((serverHello[1] << 16) | (serverHello[2] << 8) | serverHello[3]) + 4;
- debugs(83, 7, "ServerHello message size: " << helloSize);
- if (helloSize > messageContainerSize) {
- debugs(83, 2, "ServerHello parse error");
- return false;
- }
-
- // helloSize should be at least 38 bytes long:
- // (SSL Version + Random + SessionId Length + Cipher Suite + Compression Method)
- if (helloSize < 38) {
- debugs(83, 2, "Too short ServerHello message");
- return false;
- }
-
- debugs(83, 7, "Get fake features from v3 ServerHello message.");
- // Get the correct version of the sub-hello message
- sslVersion = (serverHello[4] << 8) | serverHello[5];
- // At the position 38 (HelloHeader (6bytes) + SSL3_RANDOM_SIZE (32bytes))
- const size_t sessIdLen = static_cast<size_t>(serverHello[38]);
- debugs(83, 7, "Session ID Length: " << sessIdLen);
-
- // The size should be enough to hold at least the following
- // 4 (hello header)
- // + 2 (SSL Version) + 32 (random) + 1 (sessionId length)
- // + sessIdLength + 2 (cipher suite) + 1 (compression method)
- // = 42 + sessIdLength
- if (42 + sessIdLen > helloSize) {
- debugs(83, 2, "ciphers length parse error");
- return false;
- }
-
- // The sessionID stored at 39 position, after sessionID length field
- sessionId.assign(reinterpret_cast<const char *>(serverHello + 39), sessIdLen);
-
- // Check if there are extensions in hello message
- // RFC5246 section 7.4.1.4
- if (helloSize > 42 + sessIdLen + 2) {
- // 42 + sessIdLen
- const unsigned char *pToExtensions = serverHello + 42 + sessIdLen;
- const size_t extensionsLen = (pToExtensions[0] << 8) | pToExtensions[1];
- // Check if the hello size can hold extensions
- if (42 + 2 + sessIdLen + extensionsLen > helloSize ) {
- debugs(83, 2, "Extensions length parse error");
- return false;
- }
-
- pToExtensions += 2;
- const unsigned char *ext = pToExtensions;
- while (ext + 4 <= pToExtensions + extensionsLen) {
- const size_t extType = (ext[0] << 8) | ext[1];
- ext += 2;
- const size_t extLen = (ext[0] << 8) | ext[1];
- ext += 2;
- debugs(83, 7, "TLS Extension: " << std::hex << extType << " of size:" << extLen);
- // SessionTicket TLS Extension, RFC5077 section 3.2
- if (extType == 0x23) {
- tlsTicketsExtension = true;
- }
- ext += extLen;
- }
- }
- return true;
-}
-
-bool
-Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *messageContainer, size_t messageContainerSize)
-{
- // Parse a ClientHello Handshake message
- // RFC5246 section 7.4, 7.4.1.2
- // The ClientHello starts at messageContainer + 5
- const unsigned char * clientHello = messageContainer + 5;
-
- debugs(83, 7, "Get fake features from v3 ClientHello message.");
- // The Length field (bytes 1-3) plus 4 bytes of the clientHello message header (1 handshake type + 3 hello length)
- const size_t helloSize = ((clientHello[1] << 16) | (clientHello[2] << 8) | clientHello[3]) + 4;
- debugs(83, 7, "ClientHello message size: " << helloSize);
- if (helloSize > messageContainerSize) {
- debugs(83, 2, "ClientHello parse error");
- return false;
- }
-
- // helloSize should be at least 38 bytes long:
- // (SSL Version(2) + Random(32) + SessionId Length(1) + Cipher Suite Length(2) + Compression Method Length(1))
- if (helloSize < 38) {
- debugs(83, 2, "Too short ClientHello message");
- return false;
- }
-
- //For SSLv3 or TLSv1.* protocols we can get some more informations
- if (messageContainer[1] != 0x3 || clientHello[0] != 0x1 /*HELLO A message*/) {
- debugs(83, 2, "Not an SSLv3/TLSv1.x client hello message, stop parsing here");
- return true;
- }
-
- // Get the correct version of the sub-hello message
- sslVersion = (clientHello[4] << 8) | clientHello[5];
- //Get Client Random number. It starts on the position 6 of clientHello message
- memcpy(client_random, clientHello + 6, SSL3_RANDOM_SIZE);
- debugs(83, 7, "Client random: " << objToString(client_random, SSL3_RANDOM_SIZE));
-
- // At the position 38 (6+SSL3_RANDOM_SIZE)
- const size_t sessIDLen = static_cast<size_t>(clientHello[38]);
- debugs(83, 7, "Session ID Length: " << sessIDLen);
-
- // The helloSize should be enough to hold at least the following
- // 1 handshake type + 3 hello Length
- // + 2 (SSL Version) + 32 (random) + 1 (sessionId length)
- // + sessIdLength + 2 (cipher suite length) + 1 (compression method length)
- // = 42 + sessIdLength
- if (42 + sessIDLen > helloSize) {
- debugs(83, 2, "Session ID length parse error");
- return false;
- }
-
- // The sessionID stored art 39 position, after sessionID length field
- sessionId.assign(reinterpret_cast<const char *>(clientHello + 39), sessIDLen);
-
- //Ciphers list. It is stored after the Session ID.
- // It is a variable-length vector(RFC5246 section 4.3)
- const unsigned char *ciphers = clientHello + 39 + sessIDLen;
- const size_t ciphersLen = (ciphers[0] << 8) | ciphers[1];
- if (42 + sessIDLen + ciphersLen > helloSize) {
- debugs(83, 2, "ciphers length parse error");
- return false;
- }
-
- ciphers += 2;
- if (ciphersLen) {
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- const SSL_METHOD *method = TLS_method();
-#else
- const SSL_METHOD *method = SSLv23_method();
-#endif
- for (size_t i = 0; i < ciphersLen; i += 2) {
- // each cipher in v3/tls HELLO message is of size 2
- const SSL_CIPHER *c = method->get_cipher_by_char((ciphers + i));
- if (c != NULL) {
- if (!clientRequestedCiphers.empty())
- clientRequestedCiphers.append(":");
- clientRequestedCiphers.append(c->name);
- } else
- unknownCiphers = true;
- }
- }
- debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers);
-
- // Compression field: 1 bytes the number of compression methods and
- // 1 byte for each compression method
- const unsigned char *compression = ciphers + ciphersLen;
- if (compression[0] > 1)
- compressMethod = 1;
- else
- compressMethod = 0;
- debugs(83, 7, "SSL compression methods number: " << static_cast<int>(compression[0]));
-
- // Parse Extensions, RFC5246 section 7.4.1.4
- const unsigned char *pToExtensions = compression + 1 + static_cast<int>(compression[0]);
- if ((size_t)((pToExtensions - clientHello) + 2) < helloSize) {
- const size_t extensionsLen = (pToExtensions[0] << 8) | pToExtensions[1];
- if ((pToExtensions - clientHello) + 2 + extensionsLen > helloSize) {
- debugs(83, 2, "Extensions length parse error");
- return false;
- }
-
- pToExtensions += 2;
- const unsigned char *ext = pToExtensions;
- while (ext + 4 <= pToExtensions + extensionsLen) {
- const size_t extType = (ext[0] << 8) | ext[1];
- ext += 2;
- const size_t extLen = (ext[0] << 8) | ext[1];
- ext += 2;
- debugs(83, 7, "TLS Extension: " << std::hex << extType << " of size:" << extLen);
-
- if (ext + extLen > pToExtensions + extensionsLen) {
- debugs(83, 2, "Extension " << std::hex << extType << " length parser error");
- return false;
- }
-
- //The SNI extension has the type 0 (extType == 0)
- // RFC6066 sections 3, 10.2
- // The two first bytes indicates the length of the SNI data (should be extLen-2)
- // The next byte is the hostname type, it should be '0' for normal hostname (ext[2] == 0)
- // The 3rd and 4th bytes are the length of the hostname
- if (extType == 0 && ext[2] == 0) {
- const size_t hostLen = (ext[3] << 8) | ext[4];
- if (hostLen < extLen)
- serverName.assign(reinterpret_cast<const char *>(ext+5), hostLen);
- debugs(83, 7, "Found server name: " << serverName);
- } else if (extType == 15 && ext[0] != 0) {
- // The heartBeats are the type 15, RFC6520
- doHeartBeats = true;
- } else if (extType == 0x23) {
- //SessionTicket TLS Extension RFC5077
- tlsTicketsExtension = true;
- if (extLen != 0)
- hasTlsTicket = true;
- } else if (extType == 0x05) {
- // RFC6066 sections 8, 10.2
- tlsStatusRequest = true;
- } else if (extType == 0x3374) {
- // detected TLS next protocol negotiate extension
- } else if (extType == 0x10) {
- // Application-Layer Protocol Negotiation Extension, RFC7301
- const size_t listLen = (ext[0] << 8) | ext[1];
- if (listLen < extLen)
- tlsAppLayerProtoNeg.assign(reinterpret_cast<const char *>(ext+5), listLen);
- } else
- extensions.push_back(extType);
-
- ext += extLen;
- }
- }
- return true;
-}
-
-bool
-Ssl::Bio::sslFeatures::parseV23Hello(const unsigned char *hello, size_t size)
-{
- debugs(83, 7, "Get fake features from v23 ClientHello message.");
- if (size < 7)
- return false;
- //Ciphers list. It is stored after the Session ID.
- const unsigned int ciphersLen = (hello[5] << 8) | hello[6];
- const unsigned char *ciphers = hello + 11;
-
- if (size < ciphersLen + 11)
- return false;
-
- if (ciphersLen) {
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- const SSL_METHOD *method = TLS_method();
-#else
- const SSL_METHOD *method = SSLv23_method();
-#endif
- for (unsigned int i = 0; i < ciphersLen; i += 3) {
- // The v2 hello messages cipher has 3 bytes.
- // The v2 cipher has the first byte not null
- // Because we are going to sent only v3 message we
- // are ignoring these ciphers
- if (ciphers[i] != 0)
- continue;
- const SSL_CIPHER *c = method->get_cipher_by_char((ciphers + i + 1));
- if (c != NULL) {
- if (!clientRequestedCiphers.empty())
- clientRequestedCiphers.append(":");
- clientRequestedCiphers.append(c->name);
- }
- }
- }
- debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers);
-
- const unsigned int sessionIdLength = (hello[7] << 8) | hello[8];
- debugs(83, 7, "SessionID length: " << sessionIdLength);
- // SessionID starts at: hello+11+ciphersLen
- if (sessionIdLength)
- sessionId.assign((const char *)(hello + 11 + ciphersLen), sessionIdLength);
-
- const unsigned int challengeLength = (hello[5] << 9) | hello[10];
- debugs(83, 7, "Challenge Length: " << challengeLength);
- //challenge starts at: hello+11+ciphersLen+sessionIdLength
-
- compressMethod = 0;
- return true;
-}
-
void
-Ssl::Bio::sslFeatures::applyToSSL(SSL *ssl, Ssl::BumpMode bumpMode) const
+applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode)
{
// To increase the possibility for bumping after peek mode selection or
// splicing after stare mode selection it is good to set the
// SSL protocol version.
- // The SSL_set_ssl_method is not the correct method because it will strict
- // SSL version which can be used to the SSL version used for client hello message.
+ // The SSL_set_ssl_method is wrong here because it will restrict the
+ // permitted transport version to be identical to the version used in the
+ // ClientHello message.
// For example will prevent comunnicating with a tls1.0 server if the
// client sent and tlsv1.2 Hello message.
#if defined(TLSEXT_NAMETYPE_host_name)
- if (!serverName.isEmpty()) {
- SSL_set_tlsext_host_name(ssl, serverName.c_str());
+ if (!details->serverName.isEmpty()) {
+ SSL_set_tlsext_host_name(ssl, details->serverName.c_str());
}
#endif
- if (!clientRequestedCiphers.empty())
- SSL_set_cipher_list(ssl, clientRequestedCiphers.c_str());
+
+ if (!details->ciphers.empty()) {
+ SBuf strCiphers;
+ for (auto cipherId: details->ciphers) {
+ unsigned char cbytes[3];
+ cbytes[0] = (cipherId >> 8) & 0xFF;
+ cbytes[1] = cipherId & 0xFF;
+ cbytes[2] = 0;
+ if (const auto c = SSL_CIPHER_find(ssl, cbytes)) {
+ if (!strCiphers.isEmpty())
+ strCiphers.append(":");
+ strCiphers.append(SSL_CIPHER_get_name(c));
+ }
+ }
+ if (!strCiphers.isEmpty())
+ SSL_set_cipher_list(ssl, strCiphers.c_str());
+ }
+
#if defined(SSL_OP_NO_COMPRESSION) /* XXX: OpenSSL 0.9.8k lacks SSL_OP_NO_COMPRESSION */
- if (compressMethod == 0)
+ if (!details->compressionSupported)
SSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
#endif
+#if defined(SSL_OP_NO_TLSv1_3)
+ // avoid "inappropriate fallback" OpenSSL error messages
+ if (details->tlsSupportedVersion && Security::Tls1p2orEarlier(details->tlsSupportedVersion))
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
+#endif
+
#if defined(TLSEXT_STATUSTYPE_ocsp)
- if (tlsStatusRequest)
+ if (details->tlsStatusRequest)
SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
#endif
#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
- if (!tlsAppLayerProtoNeg.isEmpty()) {
+ if (!details->tlsAppLayerProtoNeg.isEmpty()) {
if (bumpMode == Ssl::bumpPeek)
- SSL_set_alpn_protos(ssl, (const unsigned char*)tlsAppLayerProtoNeg.rawContent(), tlsAppLayerProtoNeg.length());
+ SSL_set_alpn_protos(ssl, (const unsigned char*)details->tlsAppLayerProtoNeg.rawContent(), details->tlsAppLayerProtoNeg.length());
else {
static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
SSL_set_alpn_protos(ssl, supported_protos, sizeof(supported_protos));
#endif
}
-std::ostream &
-Ssl::Bio::sslFeatures::print(std::ostream &os) const
-{
- static std::string buf;
- // TODO: Also print missing features like the HeartBeats and AppLayerProtoNeg
- return os << "v" << sslVersion <<
- " SNI:" << (serverName.isEmpty() ? SBuf("-") : serverName) <<
- " comp:" << compressMethod <<
- " Ciphers:" << clientRequestedCiphers <<
- " Random:" << objToString(client_random, SSL3_RANDOM_SIZE) <<
- " ecPointFormats:" << ecPointFormatList <<
- " ec:" << ellipticCurves <<
- " opaquePrf:" << opaquePrf;
-}
-
-#endif /* USE_SSL */
+#endif // USE_OPENSSL