From: Christos Tsantilas Date: Mon, 9 May 2016 17:19:42 +0000 (+0300) Subject: Polishing fixes X-Git-Tag: SQUID_4_0_11~29^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=67c99fc6dc9523eb7c1d44a48149a18758f1c439;p=thirdparty%2Fsquid.git Polishing fixes - Replace Handshake::details pointer with an always-available object - Replace Security::ProtocolVersion and its "int" representation in TlsDetails and NegotiationHistory classes with the existing Anyp::ProtocolVersion - Fix TlsDetails::compressMethod. The clients may send a compression methods list with a NULL compression method. Rename to TlsDetails::compressionSupported. - Other minor fixes. --- diff --git a/src/anyp/ProtocolType.h b/src/anyp/ProtocolType.h index 1235521087..c08f84c3b1 100644 --- a/src/anyp/ProtocolType.h +++ b/src/anyp/ProtocolType.h @@ -36,6 +36,8 @@ typedef enum { PROTO_URN, PROTO_WHOIS, PROTO_ICY, + PROTO_SSL, + PROTO_TLS, PROTO_UNKNOWN, PROTO_MAX } ProtocolType; diff --git a/src/parser/BinaryTokenizer.cc b/src/parser/BinaryTokenizer.cc index 94495d6a67..57384a587d 100644 --- a/src/parser/BinaryTokenizer.cc +++ b/src/parser/BinaryTokenizer.cc @@ -11,11 +11,11 @@ #include "squid.h" #include "BinaryTokenizer.h" -BinaryTokenizer::BinaryTokenizer(): BinaryTokenizer(SBuf()) +Parser::BinaryTokenizer::BinaryTokenizer(): BinaryTokenizer(SBuf()) { } -BinaryTokenizer::BinaryTokenizer(const SBuf &data, const bool expectMore): +Parser::BinaryTokenizer::BinaryTokenizer(const SBuf &data, const bool expectMore): context(nullptr), data_(data), parsed_(0), @@ -26,7 +26,7 @@ BinaryTokenizer::BinaryTokenizer(const SBuf &data, const bool expectMore): static inline std::ostream & -operator <<(std::ostream &os, const BinaryTokenizerContext *context) +operator <<(std::ostream &os, const Parser::BinaryTokenizerContext *context) { if (context) os << context->parent << context->name; @@ -40,7 +40,7 @@ operator <<(std::ostream &os, const BinaryTokenizerContext *context) /// logs and throws if fewer than size octets remain; no other side effects void -BinaryTokenizer::want(uint64_t size, const char *description) const +Parser::BinaryTokenizer::want(uint64_t size, const char *description) const { if (parsed_ + size > data_.length()) { debugs(24, 5, (parsed_ + size - data_.length()) << " more bytes for " << @@ -51,7 +51,7 @@ BinaryTokenizer::want(uint64_t size, const char *description) const } void -BinaryTokenizer::got(uint64_t size, const char *description) const +Parser::BinaryTokenizer::got(uint64_t size, const char *description) const { debugs(24, 7, context << description << BinaryTokenizer_tail(size, parsed_ - size)); @@ -59,7 +59,7 @@ BinaryTokenizer::got(uint64_t size, const char *description) const /// debugging helper for parsed number fields void -BinaryTokenizer::got(uint32_t value, uint64_t size, const char *description) const +Parser::BinaryTokenizer::got(uint32_t value, uint64_t size, const char *description) const { debugs(24, 7, context << description << '=' << value << BinaryTokenizer_tail(size, parsed_ - size)); @@ -67,7 +67,7 @@ BinaryTokenizer::got(uint32_t value, uint64_t size, const char *description) con /// debugging helper for parsed areas/blobs void -BinaryTokenizer::got(const SBuf &value, uint64_t size, const char *description) const +Parser::BinaryTokenizer::got(const SBuf &value, uint64_t size, const char *description) const { debugs(24, 7, context << description << '=' << Raw(nullptr, value.rawContent(), value.length()).hex() << @@ -77,7 +77,7 @@ BinaryTokenizer::got(const SBuf &value, uint64_t size, const char *description) /// debugging helper for skipped fields void -BinaryTokenizer::skipped(uint64_t size, const char *description) const +Parser::BinaryTokenizer::skipped(uint64_t size, const char *description) const { debugs(24, 7, context << description << BinaryTokenizer_tail(size, parsed_ - size)); @@ -87,7 +87,7 @@ BinaryTokenizer::skipped(uint64_t size, const char *description) const /// The larger 32-bit return type helps callers shift/merge octets into numbers. /// This internal method does not perform out-of-bounds checks. uint32_t -BinaryTokenizer::octet() +Parser::BinaryTokenizer::octet() { // While char may be signed, we view data characters as unsigned, // which helps to arrive at the right 32-bit return value. @@ -95,31 +95,31 @@ BinaryTokenizer::octet() } void -BinaryTokenizer::reset(const SBuf &data, const bool expectMore) +Parser::BinaryTokenizer::reset(const SBuf &data, const bool expectMore) { *this = BinaryTokenizer(data, expectMore); } void -BinaryTokenizer::rollback() +Parser::BinaryTokenizer::rollback() { parsed_ = syncPoint_; } void -BinaryTokenizer::commit() +Parser::BinaryTokenizer::commit() { syncPoint_ = parsed_; } bool -BinaryTokenizer::atEnd() const +Parser::BinaryTokenizer::atEnd() const { return parsed_ >= data_.length(); } uint8_t -BinaryTokenizer::uint8(const char *description) +Parser::BinaryTokenizer::uint8(const char *description) { want(1, description); const uint8_t result = octet(); @@ -128,7 +128,7 @@ BinaryTokenizer::uint8(const char *description) } uint16_t -BinaryTokenizer::uint16(const char *description) +Parser::BinaryTokenizer::uint16(const char *description) { want(2, description); const uint16_t result = (octet() << 8) | octet(); @@ -137,7 +137,7 @@ BinaryTokenizer::uint16(const char *description) } uint32_t -BinaryTokenizer::uint24(const char *description) +Parser::BinaryTokenizer::uint24(const char *description) { want(3, description); const uint32_t result = (octet() << 16) | (octet() << 8) | octet(); @@ -146,7 +146,7 @@ BinaryTokenizer::uint24(const char *description) } uint32_t -BinaryTokenizer::uint32(const char *description) +Parser::BinaryTokenizer::uint32(const char *description) { want(4, description); const uint32_t result = (octet() << 24) | (octet() << 16) | (octet() << 8) | octet(); @@ -155,7 +155,7 @@ BinaryTokenizer::uint32(const char *description) } SBuf -BinaryTokenizer::area(uint64_t size, const char *description) +Parser::BinaryTokenizer::area(uint64_t size, const char *description) { want(size, description); const SBuf result = data_.substr(parsed_, size); @@ -165,7 +165,7 @@ BinaryTokenizer::area(uint64_t size, const char *description) } void -BinaryTokenizer::skip(uint64_t size, const char *description) +Parser::BinaryTokenizer::skip(uint64_t size, const char *description) { want(size, description); parsed_ += size; @@ -178,7 +178,7 @@ BinaryTokenizer::skip(uint64_t size, const char *description) */ SBuf -BinaryTokenizer::pstring8(const char *description) +Parser::BinaryTokenizer::pstring8(const char *description) { BinaryTokenizerContext pstring(*this, description); if (const uint8_t length = uint8(".length")) @@ -187,7 +187,7 @@ BinaryTokenizer::pstring8(const char *description) } SBuf -BinaryTokenizer::pstring16(const char *description) +Parser::BinaryTokenizer::pstring16(const char *description) { BinaryTokenizerContext pstring(*this, description); if (const uint16_t length = uint16(".length")) @@ -196,7 +196,7 @@ BinaryTokenizer::pstring16(const char *description) } SBuf -BinaryTokenizer::pstring24(const char *description) +Parser::BinaryTokenizer::pstring24(const char *description) { BinaryTokenizerContext pstring(*this, description); if (const uint32_t length = uint24(".length")) diff --git a/src/parser/BinaryTokenizer.h b/src/parser/BinaryTokenizer.h index f065783e1b..c94077f3bb 100644 --- a/src/parser/BinaryTokenizer.h +++ b/src/parser/BinaryTokenizer.h @@ -11,6 +11,9 @@ #include "sbuf/SBuf.h" +namespace Parser +{ + class BinaryTokenizer; /// enables efficient debugging with concise field names: Hello.version.major @@ -139,4 +142,6 @@ BinaryTokenizerContext::success() { close(); } +} /* namespace Parser */ + #endif // SQUID_PARSER_BINARY_TOKENIZER_H diff --git a/src/security/Handshake.cc b/src/security/Handshake.cc index 8eb1ac1176..3a763b3983 100644 --- a/src/security/Handshake.cc +++ b/src/security/Handshake.cc @@ -17,24 +17,6 @@ #include namespace Security { - -// TODO: Replace with Anyp::ProtocolVersion and use for TlsDetails::tls*Version. -/// TLS Record Layer's protocol version from RFC 5246 Section 6.2.1 -class ProtocolVersion -{ -public: - ProtocolVersion() {} - explicit ProtocolVersion(BinaryTokenizer &tk); - - /// XXX: TlsDetails use "int" to manipulate version information. - /// TODO: Use ProtocolVersion in TlsDetails and printTlsVersion(). - int toNumberXXX() const { return (vMajor << 8) | vMinor; } - - // the "v" prefix works around environments that #define major and minor - uint8_t vMajor = 0; - uint8_t vMinor = 0; -}; - /* * The types below represent various SSL and TLS protocol elements. Most names * are based on RFC 5264 and RFC 6066 terminology. Objects of these explicit @@ -54,10 +36,10 @@ enum ContentType { class TLSPlaintext { public: - explicit TLSPlaintext(BinaryTokenizer &tk); + explicit TLSPlaintext(Parser::BinaryTokenizer &tk); uint8_t type; ///< see ContentType - int version; ///< Record Layer, not necessarily the negotiated TLS version; TODO: Replace with Anyp::ProtocolVersion + AnyP::ProtocolVersion version; ///< Record Layer, not necessarily the negotiated TLS version; SBuf fragment; ///< possibly partial content }; @@ -65,7 +47,7 @@ public: class Sslv2Record { public: - explicit Sslv2Record(BinaryTokenizer &tk); + explicit Sslv2Record(Parser::BinaryTokenizer &tk); SBuf fragment; }; @@ -82,7 +64,7 @@ enum HandshakeType { class Handshake { public: - explicit Handshake(BinaryTokenizer &tk); + explicit Handshake(Parser::BinaryTokenizer &tk); uint8_t msg_type; ///< see HandshakeType SBuf msg_body; ///< Handshake Protocol message @@ -92,7 +74,7 @@ public: class Alert { public: - explicit Alert(BinaryTokenizer &tk); + explicit Alert(Parser::BinaryTokenizer &tk); bool fatal() const { return level == 2; } @@ -108,7 +90,7 @@ class Extension { public: typedef uint16_t Type; - explicit Extension(BinaryTokenizer &tk); + explicit Extension(Parser::BinaryTokenizer &tk); /// whether this extension is supported by Squid and, hence, may be bumped /// after peeking or spliced after staring (subject to other restrictions) @@ -125,25 +107,25 @@ static Extensions SupportedExtensions(); } // namespace Security /// Convenience helper: We parse ProtocolVersion but store "int". -static int -ParseProtocolVersion(BinaryTokenizer &tk) +static AnyP::ProtocolVersion +ParseProtocolVersion(Parser::BinaryTokenizer &tk) { - const Security::ProtocolVersion version(tk); - return version.toNumberXXX(); -} + Parser::BinaryTokenizerContext context(tk, ".version"); + uint8_t vMajor = tk.uint8(".major"); + uint8_t vMinor = tk.uint8(".minor"); + if (vMajor == 0 && vMinor == 2) + return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 2, 0); + Must(vMajor == 3); + if (vMinor == 0) + return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0); -Security::ProtocolVersion::ProtocolVersion(BinaryTokenizer &tk) -{ - BinaryTokenizerContext context(tk, ".version"); - vMajor = tk.uint8(".major"); - vMinor = tk.uint8(".minor"); - // do not summarize context.success() to reduce debugging noise + return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, (vMinor - 1)); } -Security::TLSPlaintext::TLSPlaintext(BinaryTokenizer &tk) +Security::TLSPlaintext::TLSPlaintext(Parser::BinaryTokenizer &tk) { - BinaryTokenizerContext context(tk, "TLSPlaintext"); + Parser::BinaryTokenizerContext context(tk, "TLSPlaintext"); type = tk.uint8(".type"); Must(type >= ctChangeCipherSpec && type <= ctApplicationData); version = ParseProtocolVersion(tk); @@ -152,25 +134,25 @@ Security::TLSPlaintext::TLSPlaintext(BinaryTokenizer &tk) context.success(); } -Security::Handshake::Handshake(BinaryTokenizer &tk) +Security::Handshake::Handshake(Parser::BinaryTokenizer &tk) { - BinaryTokenizerContext context(tk, "Handshake"); + Parser::BinaryTokenizerContext context(tk, "Handshake"); msg_type = tk.uint8(".msg_type"); msg_body = tk.pstring24(".msg_body"); context.success(); } -Security::Alert::Alert(BinaryTokenizer &tk) +Security::Alert::Alert(Parser::BinaryTokenizer &tk) { - BinaryTokenizerContext context(tk, "Alert"); + Parser::BinaryTokenizerContext context(tk, "Alert"); level = tk.uint8(".level"); description = tk.uint8(".description"); context.success(); } -Security::Extension::Extension(BinaryTokenizer &tk) +Security::Extension::Extension(Parser::BinaryTokenizer &tk) { - BinaryTokenizerContext context(tk, "Extension"); + Parser::BinaryTokenizerContext context(tk, "Extension"); type = tk.uint16(".type"); data = tk.pstring16(".data"); context.success(); @@ -183,9 +165,9 @@ Security::Extension::supported() const return supportedExtensions.find(type) != supportedExtensions.end(); } -Security::Sslv2Record::Sslv2Record(BinaryTokenizer &tk) +Security::Sslv2Record::Sslv2Record(Parser::BinaryTokenizer &tk) { - BinaryTokenizerContext context(tk, "Sslv2Record"); + Parser::BinaryTokenizerContext context(tk, "Sslv2Record"); const uint16_t head = tk.uint16(".head"); const uint16_t length = head & 0x7FFF; Must((head & 0x8000) && length); // SSLv2 message [without padding] @@ -194,9 +176,7 @@ Security::Sslv2Record::Sslv2Record(BinaryTokenizer &tk) } Security::TlsDetails::TlsDetails(): - tlsVersion(-1), - tlsSupportedVersion(-1), - compressMethod(-1), + compressionSupported(false), doHeartBeats(false), tlsTicketsExtension(false), hasTlsTicket(false), @@ -208,6 +188,7 @@ Security::TlsDetails::TlsDetails(): /* Security::HandshakeParser */ Security::HandshakeParser::HandshakeParser(): + details(new TlsDetails), state(atHelloNone), ressumingSession(false), currentContentType(0), @@ -221,8 +202,7 @@ Security::HandshakeParser::parseVersion2Record() { const Sslv2Record record(tkRecords); tkRecords.commit(); - Must(details); - details->tlsVersion = 0x002; + details->tlsVersion = AnyP::ProtocolVersion(AnyP::PROTO_SSL, 2, 0); parseVersion2HandshakeMessage(record.fragment); state = atHelloReceived; done = "SSLv2"; @@ -233,7 +213,7 @@ Security::HandshakeParser::parseVersion2Record() bool Security::HandshakeParser::isSslv2Record(const SBuf &raw) const { - BinaryTokenizer tk(raw, true); + Parser::BinaryTokenizer tk(raw, true); const uint16_t head = tk.uint16("?v2Hello.msg_head"); const uint8_t type = tk.uint8("?v2Hello.msg_type"); const uint16_t length = head & 0x7FFF; @@ -243,7 +223,6 @@ Security::HandshakeParser::isSslv2Record(const SBuf &raw) const void Security::HandshakeParser::parseRecord() { - Must(details); if (expectingModernRecords) parseModernRecord(); else @@ -371,8 +350,8 @@ Security::HandshakeParser::parseApplicationDataMessage() void Security::HandshakeParser::parseVersion2HandshakeMessage(const SBuf &raw) { - BinaryTokenizer tk(raw); - BinaryTokenizerContext hello(tk, "V2ClientHello"); + Parser::BinaryTokenizer tk(raw); + Parser::BinaryTokenizerContext hello(tk, "V2ClientHello"); Must(tk.uint8(".type") == hskClientHello); // Only client hello supported. details->tlsSupportedVersion = ParseProtocolVersion(tk); const uint16_t ciphersLen = tk.uint16(".cipher_specs.length"); @@ -387,22 +366,37 @@ Security::HandshakeParser::parseVersion2HandshakeMessage(const SBuf &raw) void Security::HandshakeParser::parseClientHelloHandshakeMessage(const SBuf &raw) { - BinaryTokenizer tk(raw); - BinaryTokenizerContext hello(tk, "ClientHello"); + Parser::BinaryTokenizer tk(raw); + Parser::BinaryTokenizerContext hello(tk, "ClientHello"); details->tlsSupportedVersion = ParseProtocolVersion(tk); details->clientRandom = tk.area(HelloRandomSize, ".random"); details->sessionId = tk.pstring8(".session_id"); parseCiphers(tk.pstring16(".cipher_suites")); - details->compressMethod = tk.pstring8(".compression_methods").length() > 0 ? 1 : 0; // Only deflate supported here. + details->compressionSupported = parseCompressionMethods(tk.pstring8(".compression_methods")); if (!tk.atEnd()) // extension-free message ends here parseExtensions(tk.pstring16(".extensions")); hello.success(); } +bool +Security::HandshakeParser::parseCompressionMethods(const SBuf &raw) +{ + if (raw.length() == 0) + return false; + Parser::BinaryTokenizer tk(raw); + while (!tk.atEnd()) { + // Probably here we should check for DEFLATE(1) compression method + // which is the only supported by openSSL subsystem. + if (tk.uint8("compression_method") != 0) + return true; + } + return false; +} + void Security::HandshakeParser::parseExtensions(const SBuf &raw) { - BinaryTokenizer tk(raw); + Parser::BinaryTokenizer tk(raw); while (!tk.atEnd()) { Extension extension(tk); @@ -422,7 +416,7 @@ Security::HandshakeParser::parseExtensions(const SBuf &raw) details->doHeartBeats = true; break; case 16: { // Application-Layer Protocol Negotiation Extension, RFC 7301 - BinaryTokenizer tkAPN(extension.data); + Parser::BinaryTokenizer tkAPN(extension.data); details->tlsAppLayerProtoNeg = tkAPN.pstring16("APN"); break; } @@ -440,7 +434,7 @@ void Security::HandshakeParser::parseCiphers(const SBuf &raw) { details->ciphers.reserve(raw.length() / sizeof(uint16_t)); - BinaryTokenizer tk(raw); + Parser::BinaryTokenizer tk(raw); while (!tk.atEnd()) { const uint16_t cipher = tk.uint16("cipher"); details->ciphers.insert(cipher); @@ -450,15 +444,17 @@ Security::HandshakeParser::parseCiphers(const SBuf &raw) void Security::HandshakeParser::parseV23Ciphers(const SBuf &raw) { - BinaryTokenizer tk(raw); + Parser::BinaryTokenizer tk(raw); while (!tk.atEnd()) { - // The v2 hello messages cipher has 3 bytes. - // The v2 cipher has the first byte not null. - // We support v3 messages only so we are ignoring v2 ciphers. - // XXX: The above line sounds wrong -- we support v2 hello messages. + // The v2 hello messages cipher has 3 bytes. The v2 cipher has the + // first byte not null. In an v23 SSL Hello message both v2 and + // v3/tls ciphers can coexist. + // The supported ciphers list needed for Peek and Stare bumping + // modes where only SSLv3 and TLS protocols are supported so + // we are ignoring the v2 ciphers. const uint8_t prefix = tk.uint8("prefix"); const uint16_t cipher = tk.uint16("cipher"); - if (prefix == 0) // TODO: return immediately if prefix is positive? + if (prefix == 0) details->ciphers.insert(cipher); } } @@ -467,13 +463,13 @@ Security::HandshakeParser::parseV23Ciphers(const SBuf &raw) void Security::HandshakeParser::parseServerHelloHandshakeMessage(const SBuf &raw) { - BinaryTokenizer tk(raw); - BinaryTokenizerContext hello(tk, "ServerHello"); + Parser::BinaryTokenizer tk(raw); + Parser::BinaryTokenizerContext hello(tk, "ServerHello"); details->tlsSupportedVersion = ParseProtocolVersion(tk); tk.skip(HelloRandomSize, ".random"); details->sessionId = tk.pstring8(".session_id"); details->ciphers.insert(tk.uint16(".cipher_suite")); - details->compressMethod = tk.uint8(".compression_method") != 0; // not null + details->compressionSupported = tk.uint8(".compression_method") != 0; // not null if (!tk.atEnd()) // extensions present parseExtensions(tk.pstring16(".extensions")); hello.success(); @@ -489,10 +485,10 @@ Security::HandshakeParser::parseSniExtension(const SBuf &extensionData) const // SNI MUST NOT contain more than one name of the same name_type but // we ignore violations and simply return the first host name found. - BinaryTokenizer tkList(extensionData); - BinaryTokenizer tkNames(tkList.pstring16("ServerNameList")); + Parser::BinaryTokenizer tkList(extensionData); + Parser::BinaryTokenizer tkNames(tkList.pstring16("ServerNameList")); while (!tkNames.atEnd()) { - BinaryTokenizerContext serverName(tkNames, "ServerName"); + Parser::BinaryTokenizerContext serverName(tkNames, "ServerName"); const uint8_t nameType = tkNames.uint8(".name_type"); const SBuf name = tkNames.pstring16(".name"); serverName.success(); @@ -520,10 +516,8 @@ bool Security::HandshakeParser::parseHello(const SBuf &data) { try { - if (!details) { - expectingModernRecords = !isSslv2Record(data); - details = new TlsDetails; // after expectingModernRecords is known - } + if (!expectingModernRecords.configured()) + expectingModernRecords.configure(!isSslv2Record(data)); // data contains everything read so far, but we may read more later tkRecords.reinput(data, true); @@ -534,7 +528,7 @@ Security::HandshakeParser::parseHello(const SBuf &data) // we are done; tkRecords may have leftovers we are not interested in return true; } - catch (const BinaryTokenizer::InsufficientInput &) { + catch (const Parser::BinaryTokenizer::InsufficientInput &) { debugs(83, 5, "need more data"); return false; } @@ -557,11 +551,11 @@ Security::HandshakeParser::ParseCertificate(const SBuf &raw) void Security::HandshakeParser::parseServerCertificates(const SBuf &raw) { - BinaryTokenizer tkList(raw); + Parser::BinaryTokenizer tkList(raw); const SBuf clist = tkList.pstring24("CertificateList"); Must(tkList.atEnd()); // no leftovers after all certificates - BinaryTokenizer tkItems(clist); + Parser::BinaryTokenizer tkItems(clist); while (!tkItems.atEnd()) { X509 *cert = ParseCertificate(tkItems.pstring24("Certificate")); if (!serverCertificates.get()) diff --git a/src/security/Handshake.h b/src/security/Handshake.h index 8726c08ce8..b2a116e343 100644 --- a/src/security/Handshake.h +++ b/src/security/Handshake.h @@ -9,7 +9,9 @@ #ifndef SQUID_SECURITY_HANDSHAKE_H #define SQUID_SECURITY_HANDSHAKE_H +#include "anyp/ProtocolVersion.h" #include "base/RefCount.h" +#include "base/YesNoNone.h" #include "parser/BinaryTokenizer.h" #include "sbuf/SBuf.h" #if USE_OPENSSL @@ -30,9 +32,9 @@ public: /// Prints to os stream a human readable form of TlsDetails object std::ostream & print(std::ostream &os) const; - int tlsVersion; ///< The TLS hello message version - int tlsSupportedVersion; ///< The requested/used TLS version - int compressMethod; ///< The requested/used compressed method + AnyP::ProtocolVersion tlsVersion; ///< The TLS hello message version + AnyP::ProtocolVersion tlsSupportedVersion; ///< The requested/used TLS version + bool compressionSupported; ///< The requested/used compressed method SBuf serverName; ///< The SNI hostname, if any bool doHeartBeats; bool tlsTicketsExtension; ///< whether TLS tickets extension is enabled @@ -96,6 +98,7 @@ private: void parseClientHelloHandshakeMessage(const SBuf &raw); void parseServerHelloHandshakeMessage(const SBuf &raw); + bool parseCompressionMethods(const SBuf &raw); void parseExtensions(const SBuf &raw); SBuf parseSniExtension(const SBuf &extensionData) const; @@ -114,10 +117,10 @@ private: /// concatenated TLSPlaintext.fragments of TLSPlaintext.type SBuf fragments; - BinaryTokenizer tkRecords; // TLS record layer (parsing uninterpreted data) - BinaryTokenizer tkMessages; // TLS message layer (parsing fragments) + Parser::BinaryTokenizer tkRecords; // TLS record layer (parsing uninterpreted data) + Parser::BinaryTokenizer tkMessages; // TLS message layer (parsing fragments) - bool expectingModernRecords; // Whether to use TLS parser or a V2 compatible parser + YesNoNone expectingModernRecords; // Whether to use TLS parser or a V2 compatible parser }; } diff --git a/src/security/NegotiationHistory.cc b/src/security/NegotiationHistory.cc index 4d5b2b16aa..2004f18d91 100644 --- a/src/security/NegotiationHistory.cc +++ b/src/security/NegotiationHistory.cc @@ -15,40 +15,46 @@ #include "ssl/support.h" #endif -Security::NegotiationHistory::NegotiationHistory(): - helloVersion_(-1), - supportedVersion_(-1), - version_(-1) +Security::NegotiationHistory::NegotiationHistory() #if USE_OPENSSL - , cipher(NULL) + : cipher(NULL) #endif { } const char * -Security::NegotiationHistory::printTlsVersion(int v) const +Security::NegotiationHistory::printTlsVersion(AnyP::ProtocolVersion const &v) const { + if (v.protocol != AnyP::PROTO_SSL && v.protocol != AnyP::PROTO_TLS) + return nullptr; + + static char buf[512]; + snprintf(buf, sizeof(buf), "%s/%d.%d", AnyP::ProtocolType_str[v.protocol], v.major, v.minor); + return buf; +} + #if USE_OPENSSL +static AnyP::ProtocolVersion +toProtocolVersion(const int v) +{ switch(v) { #if OPENSSL_VERSION_NUMBER >= 0x10001000L case TLS1_2_VERSION: - return "TLS/1.2"; + return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, 2); case TLS1_1_VERSION: - return "TLS/1.1"; + return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, 1); #endif case TLS1_VERSION: - return "TLS/1.0"; + return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, 0); case SSL3_VERSION: - return "SSL/3.0"; + return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0); case SSL2_VERSION: - return "SSL/2.0"; + return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 2, 0); default: - return nullptr; + return AnyP::ProtocolVersion(); } -#else - return nullptr; -#endif } +#endif void Security::NegotiationHistory::retrieveNegotiatedInfo(Security::SessionPtr ssl) @@ -58,7 +64,7 @@ Security::NegotiationHistory::retrieveNegotiatedInfo(Security::SessionPtr ssl) // Set the negotiated version only if the cipher negotiated // else probably the negotiation is not completed and version // is not the final negotiated version - version_ = ssl->version; + version_ = toProtocolVersion(ssl->version); } if (do_debug(83, 5)) { diff --git a/src/security/NegotiationHistory.h b/src/security/NegotiationHistory.h index 68fb8363fe..65e0490b7e 100644 --- a/src/security/NegotiationHistory.h +++ b/src/security/NegotiationHistory.h @@ -9,6 +9,7 @@ #ifndef SQUID_SRC_SECURITY_NEGOTIATIONHISTORY_H #define SQUID_SRC_SECURITY_NEGOTIATIONHISTORY_H +#include "anyp/ProtocolVersion.h" #include "security/Session.h" #include "security/Handshake.h" @@ -35,10 +36,10 @@ public: const char *supportedVersion() const {return printTlsVersion(supportedVersion_);} private: /// String representation of the TLS version 'v' - const char *printTlsVersion(int v) const; - int helloVersion_; ///< The TLL version of the hello message - int supportedVersion_; ///< The maximum supported TLS version - int version_; ///< The negotiated TLL version + const char *printTlsVersion(AnyP::ProtocolVersion const &v) const; + AnyP::ProtocolVersion helloVersion_; ///< The TLS version of the hello message + AnyP::ProtocolVersion supportedVersion_; ///< The maximum supported TLS version + AnyP::ProtocolVersion version_; ///< The negotiated TLS version #if USE_OPENSSL const SSL_CIPHER *cipher; ///< The negotiated cipher #endif diff --git a/src/ssl/PeekingPeerConnector.cc b/src/ssl/PeekingPeerConnector.cc index f330ae5222..3679bb2fe9 100644 --- a/src/ssl/PeekingPeerConnector.cc +++ b/src/ssl/PeekingPeerConnector.cc @@ -173,10 +173,10 @@ Ssl::PeekingPeerConnector::initializeSsl() BIO *bc = SSL_get_rbio(clientSsl); Ssl::ClientBio *cltBio = static_cast(bc->ptr); Must(cltBio); - if (details && details->tlsVersion != -1) { + if (details && details->tlsVersion.protocol != AnyP::PROTO_NONE) { applyTlsDetailsToSSL(ssl, details, csd->sslBumpMode); // Should we allow it for all protocols? - if (details->tlsVersion >= 3) { + if (details->tlsVersion.protocol == AnyP::PROTO_TLS || details->tlsVersion == AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0)) { BIO *b = SSL_get_rbio(ssl); Ssl::ServerBio *srvBio = static_cast(b->ptr); // Inherite client features, like SSL version, SNI and other diff --git a/src/ssl/bio.cc b/src/ssl/bio.cc index 4142f3d96c..529e91fe80 100644 --- a/src/ssl/bio.cc +++ b/src/ssl/bio.cc @@ -329,9 +329,9 @@ adjustSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, SBuf &helloMes // If the client supports compression but our context does not support // we can not adjust. #if !defined(OPENSSL_NO_COMP) - const bool requireCompression = (details->compressMethod && ssl->ctx->comp_methods == NULL); + const bool requireCompression = (details->compressionSupported && ssl->ctx->comp_methods == NULL); #else - const bool requireCompression = details->compressMethod; + const bool requireCompression = details->compressionSupported; #endif if (requireCompression) { debugs(83, 5, "Client Hello Data supports compression, but we do not!"); @@ -661,7 +661,7 @@ applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl } #if defined(SSL_OP_NO_COMPRESSION) /* XXX: OpenSSL 0.9.8k lacks SSL_OP_NO_COMPRESSION */ - if (details->compressMethod == 0) + if (!details->compressionSupported) SSL_set_options(ssl, SSL_OP_NO_COMPRESSION); #endif diff --git a/src/tests/stub_libsecurity.cc b/src/tests/stub_libsecurity.cc index f3bd39c0a8..8de500bcd9 100644 --- a/src/tests/stub_libsecurity.cc +++ b/src/tests/stub_libsecurity.cc @@ -41,7 +41,7 @@ Security::NegotiationHistory::NegotiationHistory() STUB void Security::NegotiationHistory::retrieveNegotiatedInfo(Security::SessionPtr) STUB void Security::NegotiationHistory::retrieveParsedInfo(Security::TlsDetails::Pointer const &) STUB const char *Security::NegotiationHistory::cipherName() const STUB -const char *Security::NegotiationHistory::printTlsVersion(int) const STUB +const char *Security::NegotiationHistory::printTlsVersion(AnyP::ProtocolVersion const &v) const STUB #include "security/Handshake.h" Security::HandshakeParser::HandshakeParser() STUB