]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Polishing fixes
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Mon, 9 May 2016 17:19:42 +0000 (20:19 +0300)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Mon, 9 May 2016 17:19:42 +0000 (20:19 +0300)
 - 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.

src/anyp/ProtocolType.h
src/parser/BinaryTokenizer.cc
src/parser/BinaryTokenizer.h
src/security/Handshake.cc
src/security/Handshake.h
src/security/NegotiationHistory.cc
src/security/NegotiationHistory.h
src/ssl/PeekingPeerConnector.cc
src/ssl/bio.cc
src/tests/stub_libsecurity.cc

index 12355210874548cee8fbb9f750e91612a6f5aa79..c08f84c3b1e2c874f990e4d01ca71c5a600625f2 100644 (file)
@@ -36,6 +36,8 @@ typedef enum {
     PROTO_URN,
     PROTO_WHOIS,
     PROTO_ICY,
+    PROTO_SSL,
+    PROTO_TLS,
     PROTO_UNKNOWN,
     PROTO_MAX
 } ProtocolType;
index 94495d6a67a9e7e5ee197a715c4299b28c4010cc..57384a587d553b734e82b762d50b00ea53a7eb00 100644 (file)
 #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"))
index f065783e1bfd33445d78c5679ee6a92b3afaf9fc..c94077f3bbafc72f19a19bffe8419dbada245c5d 100644 (file)
@@ -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
index 8eb1ac1176922f3daec3ae045aa11e9a37674eae..3a763b3983f1035aaa7c7cd8ba76ccb801dafd1a 100644 (file)
 #include <unordered_set>
 
 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())
index 8726c08ce8547a6a285fdca75d1a71291171d255..b2a116e343626b18f645c966d95d36acc45d66a7 100644 (file)
@@ -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
 };
 
 }
index 4d5b2b16aab4682a6e53a874a50aa80efdb50fa3..2004f18d91f48eb1a87db0f31c4947e8303b4898 100644 (file)
 #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)) {
index 68fb8363fe153140a22fff7562ec76d0db0137b6..65e0490b7ee1ac8eb0f2c325f9b4899f258679dc 100644 (file)
@@ -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
index f330ae5222398c9d209fee62c4eb2bd7b2f52de5..3679bb2fe95771601164a7017f30b2383a8e2e0b 100644 (file)
@@ -173,10 +173,10 @@ Ssl::PeekingPeerConnector::initializeSsl()
             BIO *bc = SSL_get_rbio(clientSsl);
             Ssl::ClientBio *cltBio = static_cast<Ssl::ClientBio *>(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<Ssl::ServerBio *>(b->ptr);
                     // Inherite client features, like SSL version, SNI and other
index 4142f3d96c826ec4627cd5fe7921a107809462d8..529e91fe80ebb1f89f91435a3e8f283a15047a3b 100644 (file)
@@ -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
 
index f3bd39c0a8e52109036225b07683752b966157be..8de500bcd961b7e58d2256b747b7ee139ac73435 100644 (file)
@@ -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