1 /*
2  * Copyright (C) 1996-2021 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 #ifndef SQUID_SECURITY_HANDSHAKE_H
10 #define SQUID_SECURITY_HANDSHAKE_H
11 
12 #include "anyp/ProtocolVersion.h"
13 #include "base/YesNoNone.h"
14 #include "parser/BinaryTokenizer.h"
15 #include "security/forward.h"
16 
17 #include <unordered_set>
18 
19 namespace Security
20 {
21 
22 class TlsDetails: public RefCountable
23 {
24 public:
25     typedef RefCount<TlsDetails> Pointer;
26 
27     TlsDetails();
28     /// Prints to os stream a human readable form of TlsDetails object
29     std::ostream & print(std::ostream &os) const;
30 
31     AnyP::ProtocolVersion tlsVersion; ///< The TLS hello message version
32 
33     /// For most compliant TLS v1.3+ agents, this is supported_versions maximum.
34     /// For others agents, this is the legacy_version field.
35     AnyP::ProtocolVersion tlsSupportedVersion;
36 
37     bool compressionSupported; ///< The requested/used compressed  method
38     SBuf serverName; ///< The SNI hostname, if any
39     bool doHeartBeats;
40     bool tlsTicketsExtension; ///< whether TLS tickets extension is enabled
41     bool hasTlsTicket; ///< whether a TLS ticket is included
42     bool tlsStatusRequest; ///< whether the TLS status request extension is set
43     bool unsupportedExtensions; ///< whether any unsupported by Squid extensions are used
44     SBuf tlsAppLayerProtoNeg; ///< The value of the TLS application layer protocol extension if it is enabled
45     /// The client random number
46     SBuf clientRandom;
47     SBuf sessionId;
48 
49     typedef std::unordered_set<uint16_t> Ciphers;
50     Ciphers ciphers;
51 };
52 
53 inline
54 std::ostream &operator <<(std::ostream &os, Security::TlsDetails const &details)
55 {
56     return details.print(os);
57 }
58 
59 /// Incremental TLS/SSL Handshake parser.
60 class HandshakeParser
61 {
62 public:
63     /// The parsing states
64     typedef enum {atHelloNone = 0, atHelloStarted, atHelloReceived, atCertificatesReceived, atHelloDoneReceived, atNstReceived, atCcsReceived, atFinishReceived} ParserState;
65 
66     /// the originator of the TLS handshake being parsed
67     typedef enum { fromClient = 0, fromServer } MessageSource;
68 
69     explicit HandshakeParser(MessageSource);
70 
71     /// Parses the initial sequence of raw bytes sent by the TLS/SSL agent.
72     /// Returns true upon successful completion (e.g., got HelloDone).
73     /// Returns false if more data is needed.
74     /// Throws on errors.
75     bool parseHello(const SBuf &data);
76 
77     TlsDetails::Pointer details; ///< TLS handshake meta info. Never nil.
78 
79     Security::CertList serverCertificates; ///< parsed certificates chain
80 
81     ParserState state; ///< current parsing state.
82 
83     bool resumingSession; ///< True if this is a resuming session
84 
85     /// whether we are parsing Server or Client TLS handshake messages
86     MessageSource messageSource;
87 
88 private:
89     bool isSslv2Record(const SBuf &raw) const;
90     void parseRecord();
91     void parseModernRecord();
92     void parseVersion2Record();
93     void parseMessages();
94 
95     void parseChangeCipherCpecMessage();
96     void parseAlertMessage();
97     void parseHandshakeMessage();
98     void parseApplicationDataMessage();
99     void skipMessage(const char *msgType);
100 
101     bool parseRecordVersion2Try();
102     void parseVersion2HandshakeMessage(const SBuf &raw);
103     void parseClientHelloHandshakeMessage(const SBuf &raw);
104     void parseServerHelloHandshakeMessage(const SBuf &raw);
105 
106     bool parseCompressionMethods(const SBuf &raw);
107     void parseExtensions(const SBuf &raw);
108     SBuf parseSniExtension(const SBuf &extensionData) const;
109     void parseSupportedVersionsExtension(const SBuf &extensionData) const;
110 
111     void parseCiphers(const SBuf &raw);
112     void parseV23Ciphers(const SBuf &raw);
113 
114     void parseServerCertificates(const SBuf &raw);
115     static CertPointer ParseCertificate(const SBuf &raw);
116 
117     unsigned int currentContentType; ///< The current TLS/SSL record content type
118 
119     const char *done; ///< not nil if we got what we were looking for
120 
121     /// concatenated TLSPlaintext.fragments of TLSPlaintext.type
122     SBuf fragments;
123 
124     /// TLS record layer (parsing uninterpreted data)
125     Parser::BinaryTokenizer tkRecords;
126 
127     /// TLS message layer (parsing fragments)
128     Parser::BinaryTokenizer tkMessages;
129 
130     /// Whether to use TLS parser or a V2 compatible parser
131     YesNoNone expectingModernRecords;
132 };
133 
134 /// whether the given protocol belongs to the TLS/SSL group of protocols
135 inline bool
TlsFamilyProtocol(const AnyP::ProtocolVersion & version)136 TlsFamilyProtocol(const AnyP::ProtocolVersion &version)
137 {
138     return (version.protocol == AnyP::PROTO_TLS || version.protocol == AnyP::PROTO_SSL);
139 }
140 
141 /// whether TLS/SSL protocol `a` precedes TLS/SSL protocol `b`
142 inline bool
TlsVersionEarlierThan(const AnyP::ProtocolVersion & a,const AnyP::ProtocolVersion & b)143 TlsVersionEarlierThan(const AnyP::ProtocolVersion &a, const AnyP::ProtocolVersion &b)
144 {
145     Must(TlsFamilyProtocol(a));
146     Must(TlsFamilyProtocol(b));
147 
148     if (a.protocol == b.protocol)
149         return a < b;
150 
151     return a.protocol == AnyP::PROTO_SSL; // implies that b is TLS
152 }
153 
154 /// whether the given TLS/SSL protocol is TLS v1.2 or earlier, including SSL
155 inline bool
Tls1p2orEarlier(const AnyP::ProtocolVersion & p)156 Tls1p2orEarlier(const AnyP::ProtocolVersion &p)
157 {
158     return TlsVersionEarlierThan(p, AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, 3));
159 }
160 
161 /// whether the given TLS/SSL protocol is TLS v1.3 or later
162 inline bool
Tls1p3orLater(const AnyP::ProtocolVersion & p)163 Tls1p3orLater(const AnyP::ProtocolVersion &p)
164 {
165     return !Tls1p2orEarlier(p);
166 }
167 
168 }
169 
170 #endif // SQUID_SECURITY_HANDSHAKE_H
171 
172