]>
Commit | Line | Data |
---|---|---|
a804b6fe AR |
1 | /* |
2 | * Copyright (C) 1996-2016 The Squid Software Foundation and contributors | |
3 | * | |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
9 | /* DEBUG: section 83 SSL-Bump Server/Peer negotiation */ | |
10 | ||
9210f5ec | 11 | #include "squid.h" |
9210f5ec CT |
12 | #include "security/Handshake.h" |
13 | #if USE_OPENSSL | |
14 | #include "ssl/support.h" | |
15 | #endif | |
16 | ||
c05c0c94 AR |
17 | #include <unordered_set> |
18 | ||
a804b6fe | 19 | namespace Security { |
fde0b2ca | 20 | /* |
a804b6fe AR |
21 | * The types below represent various SSL and TLS protocol elements. Most names |
22 | * are based on RFC 5264 and RFC 6066 terminology. Objects of these explicit | |
23 | * types are stored or passed around. Other protocol elements are simply parsed | |
24 | * in-place, without declaring a corresponding explicit class. | |
25 | */ | |
26 | ||
27 | /// TLS Record Layer's content types from RFC 5246 Section 6.2.1 | |
28 | enum ContentType { | |
29 | ctChangeCipherSpec = 20, | |
30 | ctAlert = 21, | |
31 | ctHandshake = 22, | |
32 | ctApplicationData = 23 | |
33 | }; | |
34 | ||
35 | /// TLS Record Layer's frame from RFC 5246 Section 6.2.1. | |
36 | class TLSPlaintext | |
37 | { | |
38 | public: | |
67c99fc6 | 39 | explicit TLSPlaintext(Parser::BinaryTokenizer &tk); |
a804b6fe AR |
40 | |
41 | uint8_t type; ///< see ContentType | |
67c99fc6 | 42 | AnyP::ProtocolVersion version; ///< Record Layer, not necessarily the negotiated TLS version; |
a804b6fe AR |
43 | SBuf fragment; ///< possibly partial content |
44 | }; | |
45 | ||
46 | /// draft-hickman-netscape-ssl-00. Section 4.1. SSL Record Header Format | |
47 | class Sslv2Record | |
48 | { | |
49 | public: | |
67c99fc6 | 50 | explicit Sslv2Record(Parser::BinaryTokenizer &tk); |
a804b6fe AR |
51 | |
52 | SBuf fragment; | |
53 | }; | |
54 | ||
55 | /// TLS Handshake protocol's handshake types from RFC 5246 Section 7.4 | |
56 | enum HandshakeType { | |
57 | hskClientHello = 1, | |
58 | hskServerHello = 2, | |
59 | hskCertificate = 11, | |
60 | hskServerHelloDone = 14 | |
61 | }; | |
62 | ||
63 | /// TLS Handshake Protocol frame from RFC 5246 Section 7.4. | |
64 | class Handshake | |
65 | { | |
66 | public: | |
67c99fc6 | 67 | explicit Handshake(Parser::BinaryTokenizer &tk); |
a804b6fe AR |
68 | |
69 | uint8_t msg_type; ///< see HandshakeType | |
70 | SBuf msg_body; ///< Handshake Protocol message | |
71 | }; | |
72 | ||
73 | /// TLS Alert protocol frame from RFC 5246 Section 7.2. | |
74 | class Alert | |
75 | { | |
76 | public: | |
67c99fc6 | 77 | explicit Alert(Parser::BinaryTokenizer &tk); |
a804b6fe AR |
78 | |
79 | bool fatal() const { return level == 2; } | |
80 | ||
81 | uint8_t level; ///< warning or fatal | |
82 | uint8_t description; ///< close_notify, unexpected_message, etc. | |
83 | }; | |
84 | ||
85 | /// The size of the TLS Random structure from RFC 5246 Section 7.4.1.2. | |
86 | static const uint64_t HelloRandomSize = 32; | |
87 | ||
88 | /// TLS Hello Extension from RFC 5246 Section 7.4.1.4. | |
89 | class Extension | |
90 | { | |
91 | public: | |
c05c0c94 | 92 | typedef uint16_t Type; |
67c99fc6 | 93 | explicit Extension(Parser::BinaryTokenizer &tk); |
a804b6fe | 94 | |
c05c0c94 AR |
95 | /// whether this extension is supported by Squid and, hence, may be bumped |
96 | /// after peeking or spliced after staring (subject to other restrictions) | |
97 | bool supported() const; | |
98 | ||
99 | Type type; | |
a804b6fe AR |
100 | SBuf data; |
101 | }; | |
102 | ||
c05c0c94 AR |
103 | /// Extension types optimized for fast lookups. |
104 | typedef std::unordered_set<Extension::Type> Extensions; | |
105 | static Extensions SupportedExtensions(); | |
106 | ||
a804b6fe AR |
107 | } // namespace Security |
108 | ||
109 | /// Convenience helper: We parse ProtocolVersion but store "int". | |
67c99fc6 CT |
110 | static AnyP::ProtocolVersion |
111 | ParseProtocolVersion(Parser::BinaryTokenizer &tk) | |
a804b6fe | 112 | { |
67c99fc6 CT |
113 | Parser::BinaryTokenizerContext context(tk, ".version"); |
114 | uint8_t vMajor = tk.uint8(".major"); | |
115 | uint8_t vMinor = tk.uint8(".minor"); | |
116 | if (vMajor == 0 && vMinor == 2) | |
117 | return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 2, 0); | |
6821c276 | 118 | |
67c99fc6 CT |
119 | Must(vMajor == 3); |
120 | if (vMinor == 0) | |
121 | return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0); | |
a804b6fe | 122 | |
67c99fc6 | 123 | return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, (vMinor - 1)); |
9210f5ec CT |
124 | } |
125 | ||
67c99fc6 | 126 | Security::TLSPlaintext::TLSPlaintext(Parser::BinaryTokenizer &tk) |
6821c276 | 127 | { |
67c99fc6 | 128 | Parser::BinaryTokenizerContext context(tk, "TLSPlaintext"); |
a804b6fe | 129 | type = tk.uint8(".type"); |
21530947 | 130 | Must(type >= ctChangeCipherSpec && type <= ctApplicationData); |
a804b6fe AR |
131 | version = ParseProtocolVersion(tk); |
132 | // TODO: Must(version.major == 3); | |
133 | fragment = tk.pstring16(".fragment"); | |
c3149111 | 134 | context.success(); |
9210f5ec CT |
135 | } |
136 | ||
67c99fc6 | 137 | Security::Handshake::Handshake(Parser::BinaryTokenizer &tk) |
9210f5ec | 138 | { |
67c99fc6 | 139 | Parser::BinaryTokenizerContext context(tk, "Handshake"); |
a804b6fe AR |
140 | msg_type = tk.uint8(".msg_type"); |
141 | msg_body = tk.pstring24(".msg_body"); | |
c3149111 | 142 | context.success(); |
9210f5ec CT |
143 | } |
144 | ||
67c99fc6 | 145 | Security::Alert::Alert(Parser::BinaryTokenizer &tk) |
9210f5ec | 146 | { |
67c99fc6 | 147 | Parser::BinaryTokenizerContext context(tk, "Alert"); |
a804b6fe AR |
148 | level = tk.uint8(".level"); |
149 | description = tk.uint8(".description"); | |
c3149111 | 150 | context.success(); |
9210f5ec CT |
151 | } |
152 | ||
67c99fc6 | 153 | Security::Extension::Extension(Parser::BinaryTokenizer &tk) |
9210f5ec | 154 | { |
67c99fc6 | 155 | Parser::BinaryTokenizerContext context(tk, "Extension"); |
a804b6fe AR |
156 | type = tk.uint16(".type"); |
157 | data = tk.pstring16(".data"); | |
c3149111 | 158 | context.success(); |
9210f5ec CT |
159 | } |
160 | ||
c05c0c94 AR |
161 | bool |
162 | Security::Extension::supported() const | |
9210f5ec | 163 | { |
c05c0c94 AR |
164 | static const Extensions supportedExtensions = SupportedExtensions(); |
165 | return supportedExtensions.find(type) != supportedExtensions.end(); | |
9210f5ec CT |
166 | } |
167 | ||
67c99fc6 | 168 | Security::Sslv2Record::Sslv2Record(Parser::BinaryTokenizer &tk) |
9210f5ec | 169 | { |
67c99fc6 | 170 | Parser::BinaryTokenizerContext context(tk, "Sslv2Record"); |
c3149111 | 171 | const uint16_t head = tk.uint16(".head"); |
a804b6fe | 172 | const uint16_t length = head & 0x7FFF; |
79d1813c | 173 | Must((head & 0x8000) && length); // SSLv2 message [without padding] |
8abcff99 | 174 | fragment = tk.area(length, ".fragment"); |
c3149111 | 175 | context.success(); |
9210f5ec CT |
176 | } |
177 | ||
f0f2a850 | 178 | Security::TlsDetails::TlsDetails(): |
67c99fc6 | 179 | compressionSupported(false), |
3ee91b7b | 180 | doHeartBeats(false), |
f0f2a850 CT |
181 | tlsTicketsExtension(false), |
182 | hasTlsTicket(false), | |
c05c0c94 AR |
183 | tlsStatusRequest(false), |
184 | unsupportedExtensions(false) | |
9210f5ec | 185 | { |
6821c276 | 186 | } |
9210f5ec | 187 | |
015cf86c | 188 | /* Security::HandshakeParser */ |
9210f5ec | 189 | |
015cf86c | 190 | Security::HandshakeParser::HandshakeParser(): |
67c99fc6 | 191 | details(new TlsDetails), |
015cf86c | 192 | state(atHelloNone), |
d9219c2b | 193 | resumingSession(false), |
015cf86c | 194 | currentContentType(0), |
d20cf186 | 195 | done(nullptr), |
015cf86c | 196 | expectingModernRecords(false) |
9210f5ec | 197 | { |
9210f5ec CT |
198 | } |
199 | ||
8abcff99 CT |
200 | void |
201 | Security::HandshakeParser::parseVersion2Record() | |
202 | { | |
203 | const Sslv2Record record(tkRecords); | |
c3149111 | 204 | tkRecords.commit(); |
67c99fc6 | 205 | details->tlsVersion = AnyP::ProtocolVersion(AnyP::PROTO_SSL, 2, 0); |
8abcff99 CT |
206 | parseVersion2HandshakeMessage(record.fragment); |
207 | state = atHelloReceived; | |
c3149111 | 208 | done = "SSLv2"; |
8abcff99 CT |
209 | } |
210 | ||
5ea53436 | 211 | /// RFC 5246. Appendix E.2. Compatibility with SSL 2.0 |
c3149111 | 212 | /// And draft-hickman-netscape-ssl-00. Section 4.1. SSL Record Header Format |
21530947 | 213 | bool |
5ea53436 | 214 | Security::HandshakeParser::isSslv2Record(const SBuf &raw) const |
21530947 | 215 | { |
67c99fc6 | 216 | Parser::BinaryTokenizer tk(raw, true); |
c3149111 AR |
217 | const uint16_t head = tk.uint16("?v2Hello.msg_head"); |
218 | const uint8_t type = tk.uint8("?v2Hello.msg_type"); | |
5ea53436 AR |
219 | const uint16_t length = head & 0x7FFF; |
220 | return (head & 0x8000) && length && type == 1; | |
21530947 CT |
221 | } |
222 | ||
9210f5ec CT |
223 | void |
224 | Security::HandshakeParser::parseRecord() | |
6821c276 | 225 | { |
8abcff99 CT |
226 | if (expectingModernRecords) |
227 | parseModernRecord(); | |
228 | else | |
229 | parseVersion2Record(); | |
230 | } | |
21530947 | 231 | |
8abcff99 CT |
232 | /// parses a single TLS Record Layer frame |
233 | void | |
234 | Security::HandshakeParser::parseModernRecord() | |
9210f5ec CT |
235 | { |
236 | const TLSPlaintext record(tkRecords); | |
c3149111 | 237 | tkRecords.commit(); |
9210f5ec | 238 | |
a804b6fe | 239 | details->tlsVersion = record.version; |
9210f5ec | 240 | |
a804b6fe AR |
241 | // RFC 5246: length MUST NOT exceed 2^14 |
242 | Must(record.fragment.length() <= (1 << 14)); | |
9210f5ec | 243 | // RFC 5246: MUST NOT send zero-length [non-application] fragments |
a804b6fe | 244 | Must(record.fragment.length() || record.type == ContentType::ctApplicationData); |
9210f5ec CT |
245 | |
246 | if (currentContentType != record.type) { | |
247 | Must(tkMessages.atEnd()); // no currentContentType leftovers | |
248 | fragments = record.fragment; | |
19928af1 | 249 | tkMessages.reset(fragments, true); // true because more fragments may come |
9210f5ec CT |
250 | currentContentType = record.type; |
251 | } else { | |
252 | fragments.append(record.fragment); | |
19928af1 | 253 | tkMessages.reinput(fragments, true); // true because more fragments may come |
9210f5ec CT |
254 | tkMessages.rollback(); |
255 | } | |
256 | parseMessages(); | |
257 | } | |
258 | ||
259 | /// parses one or more "higher-level protocol" frames of currentContentType | |
260 | void | |
261 | Security::HandshakeParser::parseMessages() | |
262 | { | |
c3149111 | 263 | for (; !tkMessages.atEnd(); tkMessages.commit()) { |
9210f5ec CT |
264 | switch (currentContentType) { |
265 | case ContentType::ctChangeCipherSpec: | |
266 | parseChangeCipherCpecMessage(); | |
267 | continue; | |
268 | case ContentType::ctAlert: | |
269 | parseAlertMessage(); | |
270 | continue; | |
271 | case ContentType::ctHandshake: | |
272 | parseHandshakeMessage(); | |
273 | continue; | |
274 | case ContentType::ctApplicationData: | |
275 | parseApplicationDataMessage(); | |
276 | continue; | |
277 | } | |
d9219c2b | 278 | skipMessage("unknown ContentType msg [fragment]"); |
9210f5ec CT |
279 | } |
280 | } | |
281 | ||
282 | void | |
283 | Security::HandshakeParser::parseChangeCipherCpecMessage() | |
284 | { | |
285 | Must(currentContentType == ContentType::ctChangeCipherSpec); | |
d20cf186 | 286 | // We are currently ignoring Change Cipher Spec Protocol messages. |
d9219c2b | 287 | skipMessage("ChangeCipherCpec msg [fragment]"); |
fde0b2ca | 288 | |
d20cf186 AR |
289 | // Everything after the ChangeCipherCpec message may be encrypted. |
290 | // Continuing parsing is pointless. Stop here. | |
d9219c2b | 291 | resumingSession = true; |
d20cf186 | 292 | done = "ChangeCipherCpec"; |
9210f5ec CT |
293 | } |
294 | ||
295 | void | |
296 | Security::HandshakeParser::parseAlertMessage() | |
297 | { | |
298 | Must(currentContentType == ContentType::ctAlert); | |
299 | const Alert alert(tkMessages); | |
c3149111 AR |
300 | debugs(83, (alert.fatal() ? 2:3), |
301 | "level " << static_cast<int>(alert.level) << | |
302 | " description " << static_cast<int>(alert.description)); | |
793b1bfb AR |
303 | if (alert.fatal()) |
304 | done = "fatal Alert"; | |
305 | // else ignore the warning (at least for now) | |
9210f5ec CT |
306 | } |
307 | ||
308 | void | |
309 | Security::HandshakeParser::parseHandshakeMessage() | |
310 | { | |
311 | Must(currentContentType == ContentType::ctHandshake); | |
312 | ||
313 | const Handshake message(tkMessages); | |
314 | ||
315 | switch (message.msg_type) { | |
fde0b2ca CT |
316 | case HandshakeType::hskClientHello: |
317 | Must(state < atHelloReceived); | |
318 | Security::HandshakeParser::parseClientHelloHandshakeMessage(message.msg_body); | |
319 | state = atHelloReceived; | |
320 | done = "ClientHello"; | |
321 | return; | |
322 | case HandshakeType::hskServerHello: | |
323 | Must(state < atHelloReceived); | |
324 | parseServerHelloHandshakeMessage(message.msg_body); | |
325 | state = atHelloReceived; | |
326 | return; | |
327 | case HandshakeType::hskCertificate: | |
328 | Must(state < atCertificatesReceived); | |
0bffe3ce | 329 | parseServerCertificates(message.msg_body); |
fde0b2ca CT |
330 | state = atCertificatesReceived; |
331 | return; | |
332 | case HandshakeType::hskServerHelloDone: | |
333 | Must(state < atHelloDoneReceived); | |
334 | // zero-length | |
335 | state = atHelloDoneReceived; | |
336 | done = "ServerHelloDone"; | |
337 | return; | |
9210f5ec | 338 | } |
c05c0c94 | 339 | debugs(83, 5, "ignoring " << message.msg_body.length() << "-byte type-" << |
38eba0f7 | 340 | static_cast<unsigned int>(message.msg_type) << " handshake message"); |
9210f5ec CT |
341 | } |
342 | ||
343 | void | |
344 | Security::HandshakeParser::parseApplicationDataMessage() | |
345 | { | |
346 | Must(currentContentType == ContentType::ctApplicationData); | |
d9219c2b | 347 | skipMessage("app data [fragment]"); |
6821c276 CT |
348 | } |
349 | ||
f0f2a850 CT |
350 | void |
351 | Security::HandshakeParser::parseVersion2HandshakeMessage(const SBuf &raw) | |
352 | { | |
67c99fc6 CT |
353 | Parser::BinaryTokenizer tk(raw); |
354 | Parser::BinaryTokenizerContext hello(tk, "V2ClientHello"); | |
c3149111 | 355 | Must(tk.uint8(".type") == hskClientHello); // Only client hello supported. |
a804b6fe | 356 | details->tlsSupportedVersion = ParseProtocolVersion(tk); |
c3149111 AR |
357 | const uint16_t ciphersLen = tk.uint16(".cipher_specs.length"); |
358 | const uint16_t sessionIdLen = tk.uint16(".session_id.length"); | |
359 | const uint16_t challengeLen = tk.uint16(".challenge.length"); | |
360 | parseV23Ciphers(tk.area(ciphersLen, ".cipher_specs.body")); | |
361 | details->sessionId = tk.area(sessionIdLen, ".session_id.body"); | |
362 | tk.skip(challengeLen, ".challenge.body"); | |
363 | hello.success(); | |
f0f2a850 CT |
364 | } |
365 | ||
366 | void | |
367 | Security::HandshakeParser::parseClientHelloHandshakeMessage(const SBuf &raw) | |
368 | { | |
67c99fc6 CT |
369 | Parser::BinaryTokenizer tk(raw); |
370 | Parser::BinaryTokenizerContext hello(tk, "ClientHello"); | |
a804b6fe AR |
371 | details->tlsSupportedVersion = ParseProtocolVersion(tk); |
372 | details->clientRandom = tk.area(HelloRandomSize, ".random"); | |
373 | details->sessionId = tk.pstring8(".session_id"); | |
374 | parseCiphers(tk.pstring16(".cipher_suites")); | |
67c99fc6 | 375 | details->compressionSupported = parseCompressionMethods(tk.pstring8(".compression_methods")); |
c3149111 | 376 | if (!tk.atEnd()) // extension-free message ends here |
a804b6fe | 377 | parseExtensions(tk.pstring16(".extensions")); |
c3149111 | 378 | hello.success(); |
f0f2a850 CT |
379 | } |
380 | ||
67c99fc6 CT |
381 | bool |
382 | Security::HandshakeParser::parseCompressionMethods(const SBuf &raw) | |
383 | { | |
384 | if (raw.length() == 0) | |
385 | return false; | |
386 | Parser::BinaryTokenizer tk(raw); | |
387 | while (!tk.atEnd()) { | |
388 | // Probably here we should check for DEFLATE(1) compression method | |
389 | // which is the only supported by openSSL subsystem. | |
390 | if (tk.uint8("compression_method") != 0) | |
391 | return true; | |
392 | } | |
393 | return false; | |
394 | } | |
395 | ||
f0f2a850 CT |
396 | void |
397 | Security::HandshakeParser::parseExtensions(const SBuf &raw) | |
398 | { | |
67c99fc6 | 399 | Parser::BinaryTokenizer tk(raw); |
f0f2a850 CT |
400 | while (!tk.atEnd()) { |
401 | Extension extension(tk); | |
c05c0c94 AR |
402 | |
403 | if (!details->unsupportedExtensions && !extension.supported()) { | |
404 | debugs(83, 5, "first unsupported extension: " << extension.type); | |
405 | details->unsupportedExtensions = true; | |
406 | } | |
f0f2a850 CT |
407 | |
408 | switch(extension.type) { | |
21f081e2 | 409 | case 0: // The SNI extension; RFC 6066, Section 3 |
a804b6fe | 410 | details->serverName = parseSniExtension(extension.data); |
f0f2a850 | 411 | break; |
79d1813c | 412 | case 5: // Certificate Status Request; RFC 6066, Section 8 |
f0f2a850 CT |
413 | details->tlsStatusRequest = true; |
414 | break; | |
79d1813c | 415 | case 15: // The heartBeats, RFC 6520 |
f0f2a850 CT |
416 | details->doHeartBeats = true; |
417 | break; | |
79d1813c | 418 | case 16: { // Application-Layer Protocol Negotiation Extension, RFC 7301 |
67c99fc6 | 419 | Parser::BinaryTokenizer tkAPN(extension.data); |
a804b6fe | 420 | details->tlsAppLayerProtoNeg = tkAPN.pstring16("APN"); |
f0f2a850 | 421 | break; |
79d1813c AR |
422 | } |
423 | case 35: // SessionTicket TLS Extension; RFC 5077 | |
f0f2a850 | 424 | details->tlsTicketsExtension = true; |
a804b6fe | 425 | details->hasTlsTicket = !extension.data.isEmpty(); |
79d1813c | 426 | case 13172: // Next Protocol Negotiation Extension (expired draft?) |
f0f2a850 CT |
427 | default: |
428 | break; | |
429 | } | |
430 | } | |
431 | } | |
432 | ||
433 | void | |
434 | Security::HandshakeParser::parseCiphers(const SBuf &raw) | |
435 | { | |
c05c0c94 | 436 | details->ciphers.reserve(raw.length() / sizeof(uint16_t)); |
67c99fc6 | 437 | Parser::BinaryTokenizer tk(raw); |
f0f2a850 CT |
438 | while (!tk.atEnd()) { |
439 | const uint16_t cipher = tk.uint16("cipher"); | |
c05c0c94 | 440 | details->ciphers.insert(cipher); |
f0f2a850 CT |
441 | } |
442 | } | |
443 | ||
444 | void | |
445 | Security::HandshakeParser::parseV23Ciphers(const SBuf &raw) | |
446 | { | |
67c99fc6 | 447 | Parser::BinaryTokenizer tk(raw); |
f0f2a850 | 448 | while (!tk.atEnd()) { |
28c02f90 | 449 | // RFC 6101 Appendix E, RFC 5246 Appendix E2 |
fde0b2ca | 450 | // Unlike TLS, ciphers in SSLv23 Hellos are 3 bytes long and come in |
28c02f90 CT |
451 | // two versions: v2 and v3. The two versions may co-exist in a single |
452 | // SSLv23 Hello. Only v3 ciphers have a first byte value of zero. | |
fde0b2ca | 453 | // The ciphers are needed for our peeking/staring code that |
28c02f90 | 454 | // does not support SSLv2, so we ignore v2 ciphers. |
f0f2a850 CT |
455 | const uint8_t prefix = tk.uint8("prefix"); |
456 | const uint16_t cipher = tk.uint16("cipher"); | |
67c99fc6 | 457 | if (prefix == 0) |
c05c0c94 | 458 | details->ciphers.insert(cipher); |
f0f2a850 CT |
459 | } |
460 | } | |
461 | ||
c3149111 | 462 | /// RFC 5246 Section 7.4.1.3. Server Hello |
f0f2a850 CT |
463 | void |
464 | Security::HandshakeParser::parseServerHelloHandshakeMessage(const SBuf &raw) | |
465 | { | |
67c99fc6 CT |
466 | Parser::BinaryTokenizer tk(raw); |
467 | Parser::BinaryTokenizerContext hello(tk, "ServerHello"); | |
a804b6fe AR |
468 | details->tlsSupportedVersion = ParseProtocolVersion(tk); |
469 | tk.skip(HelloRandomSize, ".random"); | |
470 | details->sessionId = tk.pstring8(".session_id"); | |
c05c0c94 | 471 | details->ciphers.insert(tk.uint16(".cipher_suite")); |
67c99fc6 | 472 | details->compressionSupported = tk.uint8(".compression_method") != 0; // not null |
c3149111 | 473 | if (!tk.atEnd()) // extensions present |
a804b6fe AR |
474 | parseExtensions(tk.pstring16(".extensions")); |
475 | hello.success(); | |
f0f2a850 CT |
476 | } |
477 | ||
21f081e2 AR |
478 | // RFC 6066 Section 3: ServerNameList (may be sent by both clients and servers) |
479 | SBuf | |
480 | Security::HandshakeParser::parseSniExtension(const SBuf &extensionData) const | |
481 | { | |
fc34b43d AR |
482 | // Servers SHOULD send an empty SNI extension, not an empty ServerNameList! |
483 | if (extensionData.isEmpty()) | |
484 | return SBuf(); | |
485 | ||
21f081e2 AR |
486 | // SNI MUST NOT contain more than one name of the same name_type but |
487 | // we ignore violations and simply return the first host name found. | |
67c99fc6 CT |
488 | Parser::BinaryTokenizer tkList(extensionData); |
489 | Parser::BinaryTokenizer tkNames(tkList.pstring16("ServerNameList")); | |
21f081e2 | 490 | while (!tkNames.atEnd()) { |
67c99fc6 | 491 | Parser::BinaryTokenizerContext serverName(tkNames, "ServerName"); |
c3149111 | 492 | const uint8_t nameType = tkNames.uint8(".name_type"); |
a804b6fe | 493 | const SBuf name = tkNames.pstring16(".name"); |
c3149111 AR |
494 | serverName.success(); |
495 | ||
21f081e2 | 496 | if (nameType == 0) { |
aa6896b4 AR |
497 | debugs(83, 3, "host_name=" << name); |
498 | return name; // it may be empty | |
21f081e2 | 499 | } |
aa6896b4 | 500 | // else we just parsed a new/unsupported NameType which, |
21f081e2 AR |
501 | // according to RFC 6066, MUST begin with a 16-bit length field |
502 | } | |
c3149111 | 503 | return SBuf(); // SNI extension lacks host_name |
9210f5ec CT |
504 | } |
505 | ||
506 | void | |
507 | Security::HandshakeParser::skipMessage(const char *description) | |
508 | { | |
509 | // tkMessages/fragments can only contain messages of the same ContentType. | |
510 | // To skip a message, we can and should skip everything we have [left]. If | |
511 | // we have partial messages, debugging will mislead about their boundaries. | |
512 | tkMessages.skip(tkMessages.leftovers().length(), description); | |
9210f5ec CT |
513 | } |
514 | ||
9210f5ec | 515 | bool |
7706b2ef | 516 | Security::HandshakeParser::parseHello(const SBuf &data) |
9210f5ec CT |
517 | { |
518 | try { | |
67c99fc6 CT |
519 | if (!expectingModernRecords.configured()) |
520 | expectingModernRecords.configure(!isSslv2Record(data)); | |
5ea53436 | 521 | |
19928af1 AR |
522 | // data contains everything read so far, but we may read more later |
523 | tkRecords.reinput(data, true); | |
9210f5ec | 524 | tkRecords.rollback(); |
d20cf186 | 525 | while (!done) |
9210f5ec | 526 | parseRecord(); |
d20cf186 AR |
527 | debugs(83, 7, "success; got: " << done); |
528 | // we are done; tkRecords may have leftovers we are not interested in | |
529 | return true; | |
9210f5ec | 530 | } |
67c99fc6 | 531 | catch (const Parser::BinaryTokenizer::InsufficientInput &) { |
9210f5ec | 532 | debugs(83, 5, "need more data"); |
d20cf186 | 533 | return false; |
9210f5ec | 534 | } |
d20cf186 | 535 | return false; // unreached |
9210f5ec CT |
536 | } |
537 | ||
a34d1d2d CT |
538 | void |
539 | Security::HandshakeParser::ParseCertificate(const SBuf &raw, Security::CertPointer &pCert) | |
9210f5ec | 540 | { |
a34d1d2d | 541 | #if USE_OPENSSL |
4b5ea8a6 CT |
542 | auto x509Start = reinterpret_cast<const unsigned char *>(raw.rawContent()); |
543 | auto x509Pos = x509Start; | |
9210f5ec CT |
544 | X509 *x509 = d2i_X509(nullptr, &x509Pos, raw.length()); |
545 | Must(x509); // successfully parsed | |
546 | Must(x509Pos == x509Start + raw.length()); // no leftovers | |
a34d1d2d | 547 | pCert.resetAndLock(x509); |
a34d1d2d | 548 | #endif |
9210f5ec CT |
549 | } |
550 | ||
551 | void | |
552 | Security::HandshakeParser::parseServerCertificates(const SBuf &raw) | |
553 | { | |
0bffe3ce CT |
554 | Parser::BinaryTokenizer tkList(raw); |
555 | const SBuf clist = tkList.pstring24("CertificateList"); | |
9210f5ec CT |
556 | Must(tkList.atEnd()); // no leftovers after all certificates |
557 | ||
0bffe3ce | 558 | Parser::BinaryTokenizer tkItems(clist); |
9210f5ec | 559 | while (!tkItems.atEnd()) { |
a34d1d2d CT |
560 | Security::CertPointer cert; |
561 | ParseCertificate(tkItems.pstring24("Certificate"), cert); | |
562 | serverCertificates.push_back(cert); | |
563 | debugs(83, 7, "parsed " << serverCertificates.size() << " certificates so far"); | |
9210f5ec CT |
564 | } |
565 | ||
566 | } | |
c05c0c94 AR |
567 | |
568 | /// A helper function to create a set of all supported TLS extensions | |
569 | static | |
570 | Security::Extensions | |
571 | Security::SupportedExtensions() | |
572 | { | |
a34d1d2d CT |
573 | #if USE_OPENSSL |
574 | ||
c05c0c94 AR |
575 | // optimize lookup speed by reserving the number of values x3, approximately |
576 | Security::Extensions extensions(64); | |
577 | ||
578 | // Keep this list ordered and up to date by running something like | |
579 | // egrep '# *define TLSEXT_TYPE_' /usr/include/openssl/tls1.h | |
580 | // TODO: Teach OpenSSL to return the list of extensions it supports. | |
581 | #if defined(TLSEXT_TYPE_server_name) // 0 | |
582 | extensions.insert(TLSEXT_TYPE_server_name); | |
583 | #endif | |
584 | #if defined(TLSEXT_TYPE_max_fragment_length) // 1 | |
585 | extensions.insert(TLSEXT_TYPE_max_fragment_length); | |
586 | #endif | |
587 | #if defined(TLSEXT_TYPE_client_certificate_url) // 2 | |
588 | extensions.insert(TLSEXT_TYPE_client_certificate_url); | |
589 | #endif | |
590 | #if defined(TLSEXT_TYPE_trusted_ca_keys) // 3 | |
591 | extensions.insert(TLSEXT_TYPE_trusted_ca_keys); | |
592 | #endif | |
593 | #if defined(TLSEXT_TYPE_truncated_hmac) // 4 | |
594 | extensions.insert(TLSEXT_TYPE_truncated_hmac); | |
595 | #endif | |
596 | #if defined(TLSEXT_TYPE_status_request) // 5 | |
597 | extensions.insert(TLSEXT_TYPE_status_request); | |
598 | #endif | |
599 | #if defined(TLSEXT_TYPE_user_mapping) // 6 | |
600 | extensions.insert(TLSEXT_TYPE_user_mapping); | |
601 | #endif | |
602 | #if defined(TLSEXT_TYPE_client_authz) // 7 | |
603 | extensions.insert(TLSEXT_TYPE_client_authz); | |
604 | #endif | |
605 | #if defined(TLSEXT_TYPE_server_authz) // 8 | |
606 | extensions.insert(TLSEXT_TYPE_server_authz); | |
607 | #endif | |
608 | #if defined(TLSEXT_TYPE_cert_type) // 9 | |
609 | extensions.insert(TLSEXT_TYPE_cert_type); | |
610 | #endif | |
611 | #if defined(TLSEXT_TYPE_elliptic_curves) // 10 | |
612 | extensions.insert(TLSEXT_TYPE_elliptic_curves); | |
613 | #endif | |
614 | #if defined(TLSEXT_TYPE_ec_point_formats) // 11 | |
615 | extensions.insert(TLSEXT_TYPE_ec_point_formats); | |
616 | #endif | |
617 | #if defined(TLSEXT_TYPE_srp) // 12 | |
618 | extensions.insert(TLSEXT_TYPE_srp); | |
619 | #endif | |
620 | #if defined(TLSEXT_TYPE_signature_algorithms) // 13 | |
621 | extensions.insert(TLSEXT_TYPE_signature_algorithms); | |
622 | #endif | |
623 | #if defined(TLSEXT_TYPE_use_srtp) // 14 | |
624 | extensions.insert(TLSEXT_TYPE_use_srtp); | |
625 | #endif | |
626 | #if defined(TLSEXT_TYPE_heartbeat) // 15 | |
627 | extensions.insert(TLSEXT_TYPE_heartbeat); | |
628 | #endif | |
629 | #if defined(TLSEXT_TYPE_session_ticket) // 35 | |
630 | extensions.insert(TLSEXT_TYPE_session_ticket); | |
631 | #endif | |
632 | #if defined(TLSEXT_TYPE_renegotiate) // 0xff01 | |
633 | extensions.insert(TLSEXT_TYPE_renegotiate); | |
634 | #endif | |
635 | #if defined(TLSEXT_TYPE_next_proto_neg) // 13172 | |
636 | extensions.insert(TLSEXT_TYPE_next_proto_neg); | |
637 | #endif | |
638 | ||
639 | /* | |
640 | * OpenSSL does not support these last extensions by default, but those | |
641 | * building the OpenSSL libraries and/or Squid might define them. | |
642 | */ | |
643 | ||
644 | // OpenSSL may be built to support draft-rescorla-tls-opaque-prf-input-00, | |
645 | // with the extension type value configured at build time. OpenSSL, Squid, | |
646 | // and TLS agents must all be built with the same extension type value. | |
647 | #if defined(TLSEXT_TYPE_opaque_prf_input) | |
648 | extensions.insert(TLSEXT_TYPE_opaque_prf_input); | |
649 | #endif | |
650 | ||
651 | // Define this to add extensions supported by your OpenSSL but unknown to | |
652 | // your Squid version. Use {list-initialization} to add multiple extensions. | |
653 | #if defined(TLSEXT_TYPE_SUPPORTED_BY_MY_SQUID) | |
654 | extensions.insert(TLSEXT_TYPE_SUPPORTED_BY_MY_SQUID); | |
655 | #endif | |
656 | ||
657 | return extensions; // might be empty | |
f0f2a850 | 658 | #else |
c05c0c94 | 659 | |
c05c0c94 | 660 | return Extensions(); // no extensions are supported without OpenSSL |
9210f5ec | 661 | #endif |
a34d1d2d | 662 | } |
fde0b2ca | 663 |