Lines 1-147
Link Here
|
1 |
--- src/security/Handshake.cc.orig 2020-06-07 15:42:16 UTC |
|
|
2 |
+++ src/security/Handshake.cc |
3 |
@@ -9,6 +9,7 @@ |
4 |
/* DEBUG: section 83 SSL-Bump Server/Peer negotiation */ |
5 |
|
6 |
#include "squid.h" |
7 |
+#include "sbuf/Stream.h" |
8 |
#include "security/Handshake.h" |
9 |
#if USE_OPENSSL |
10 |
#include "ssl/support.h" |
11 |
@@ -104,25 +105,52 @@ class Extension (public) |
12 |
typedef std::unordered_set<Extension::Type> Extensions; |
13 |
static Extensions SupportedExtensions(); |
14 |
|
15 |
-} // namespace Security |
16 |
- |
17 |
/// parse TLS ProtocolVersion (uint16) and convert it to AnyP::ProtocolVersion |
18 |
+/// \retval PROTO_NONE for unsupported values (in relaxed mode) |
19 |
static AnyP::ProtocolVersion |
20 |
-ParseProtocolVersion(Parser::BinaryTokenizer &tk, const char *contextLabel = ".version") |
21 |
+ParseProtocolVersionBase(Parser::BinaryTokenizer &tk, const char *contextLabel, const bool beStrict) |
22 |
{ |
23 |
Parser::BinaryTokenizerContext context(tk, contextLabel); |
24 |
uint8_t vMajor = tk.uint8(".major"); |
25 |
uint8_t vMinor = tk.uint8(".minor"); |
26 |
+ |
27 |
if (vMajor == 0 && vMinor == 2) |
28 |
return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 2, 0); |
29 |
|
30 |
- Must(vMajor == 3); |
31 |
- if (vMinor == 0) |
32 |
- return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0); |
33 |
+ if (vMajor == 3) { |
34 |
+ if (vMinor == 0) |
35 |
+ return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0); |
36 |
+ return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, (vMinor - 1)); |
37 |
+ } |
38 |
|
39 |
- return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, (vMinor - 1)); |
40 |
+ /* handle unsupported versions */ |
41 |
+ |
42 |
+ const uint16_t vRaw = (vMajor << 8) | vMinor; |
43 |
+ debugs(83, 7, "unsupported: " << asHex(vRaw)); |
44 |
+ if (beStrict) |
45 |
+ throw TextException(ToSBuf("unsupported TLS version: ", asHex(vRaw)), Here()); |
46 |
+ // else hide unsupported version details from the caller behind PROTO_NONE |
47 |
+ return AnyP::ProtocolVersion(); |
48 |
} |
49 |
|
50 |
+/// parse a framing-related TLS ProtocolVersion |
51 |
+/// \returns a supported SSL or TLS Anyp::ProtocolVersion, never PROTO_NONE |
52 |
+static AnyP::ProtocolVersion |
53 |
+ParseProtocolVersion(Parser::BinaryTokenizer &tk) |
54 |
+{ |
55 |
+ return ParseProtocolVersionBase(tk, ".version", true); |
56 |
+} |
57 |
+ |
58 |
+/// parse a framing-unrelated TLS ProtocolVersion |
59 |
+/// \retval PROTO_NONE for unsupported values |
60 |
+static AnyP::ProtocolVersion |
61 |
+ParseOptionalProtocolVersion(Parser::BinaryTokenizer &tk, const char *contextLabel) |
62 |
+{ |
63 |
+ return ParseProtocolVersionBase(tk, contextLabel, false); |
64 |
+} |
65 |
+ |
66 |
+} // namespace Security |
67 |
+ |
68 |
Security::TLSPlaintext::TLSPlaintext(Parser::BinaryTokenizer &tk) |
69 |
{ |
70 |
Parser::BinaryTokenizerContext context(tk, "TLSPlaintext"); |
71 |
@@ -431,6 +459,8 @@ Security::HandshakeParser::parseExtensions(const SBuf |
72 |
break; |
73 |
case 16: { // Application-Layer Protocol Negotiation Extension, RFC 7301 |
74 |
Parser::BinaryTokenizer tkAPN(extension.data); |
75 |
+ // Store the entire protocol list, including unsupported-by-Squid |
76 |
+ // values (if any). We have to use all when peeking at the server. |
77 |
details->tlsAppLayerProtoNeg = tkAPN.pstring16("APN"); |
78 |
break; |
79 |
} |
80 |
@@ -441,8 +471,9 @@ Security::HandshakeParser::parseExtensions(const SBuf |
81 |
case 43: // supported_versions extension; RFC 8446 |
82 |
parseSupportedVersionsExtension(extension.data); |
83 |
break; |
84 |
- case 13172: // Next Protocol Negotiation Extension (expired draft?) |
85 |
default: |
86 |
+ // other extensions, including those that Squid does not support, do |
87 |
+ // not require special handling here, but see unsupportedExtensions |
88 |
break; |
89 |
} |
90 |
} |
91 |
@@ -455,7 +486,7 @@ Security::HandshakeParser::parseCiphers(const SBuf &ra |
92 |
Parser::BinaryTokenizer tk(raw); |
93 |
while (!tk.atEnd()) { |
94 |
const uint16_t cipher = tk.uint16("cipher"); |
95 |
- details->ciphers.insert(cipher); |
96 |
+ details->ciphers.insert(cipher); // including Squid-unsupported ones |
97 |
} |
98 |
} |
99 |
|
100 |
@@ -473,7 +504,7 @@ Security::HandshakeParser::parseV23Ciphers(const SBuf |
101 |
const uint8_t prefix = tk.uint8("prefix"); |
102 |
const uint16_t cipher = tk.uint16("cipher"); |
103 |
if (prefix == 0) |
104 |
- details->ciphers.insert(cipher); |
105 |
+ details->ciphers.insert(cipher); // including Squid-unsupported ones |
106 |
} |
107 |
} |
108 |
|
109 |
@@ -486,6 +517,7 @@ Security::HandshakeParser::parseServerHelloHandshakeMe |
110 |
details->tlsSupportedVersion = ParseProtocolVersion(tk); |
111 |
tk.skip(HelloRandomSize, ".random"); |
112 |
details->sessionId = tk.pstring8(".session_id"); |
113 |
+ // cipherSuite may be unsupported by a peeking Squid |
114 |
details->ciphers.insert(tk.uint16(".cipher_suite")); |
115 |
details->compressionSupported = tk.uint8(".compression_method") != 0; // not null |
116 |
if (!tk.atEnd()) // extensions present |
117 |
@@ -554,12 +586,15 @@ Security::HandshakeParser::parseSupportedVersionsExten |
118 |
Parser::BinaryTokenizer tkList(extensionData); |
119 |
Parser::BinaryTokenizer tkVersions(tkList.pstring8("SupportedVersions")); |
120 |
while (!tkVersions.atEnd()) { |
121 |
- const auto version = ParseProtocolVersion(tkVersions, "supported_version"); |
122 |
+ const auto version = ParseOptionalProtocolVersion(tkVersions, "supported_version"); |
123 |
+ // ignore values unsupported by Squid,represented by a falsy version |
124 |
+ if (!version) |
125 |
+ continue; |
126 |
if (!supportedVersionMax || TlsVersionEarlierThan(supportedVersionMax, version)) |
127 |
supportedVersionMax = version; |
128 |
} |
129 |
|
130 |
- // ignore empty supported_versions |
131 |
+ // ignore empty and ignored-values-only supported_versions |
132 |
if (!supportedVersionMax) |
133 |
return; |
134 |
|
135 |
@@ -569,7 +604,11 @@ Security::HandshakeParser::parseSupportedVersionsExten |
136 |
} else { |
137 |
assert(messageSource == fromServer); |
138 |
Parser::BinaryTokenizer tkVersion(extensionData); |
139 |
- const auto version = ParseProtocolVersion(tkVersion, "selected_version"); |
140 |
+ const auto version = ParseOptionalProtocolVersion(tkVersion, "selected_version"); |
141 |
+ // Ignore values unsupported by Squid. There should not be any until we |
142 |
+ // start seeing TLS v2+, but they do not affect TLS framing anyway. |
143 |
+ if (!version) |
144 |
+ return; |
145 |
// RFC 8446 Section 4.2.1: |
146 |
// A server which negotiates a version of TLS prior to TLS 1.3 [...] |
147 |
// MUST NOT send the "supported_versions" extension. |