2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
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.
9 #ifndef SQUID_SSL_BIO_H
10 #define SQUID_SSL_BIO_H
17 #if HAVE_OPENSSL_BIO_H
18 #include <openssl/bio.h>
24 class HandshakeParser
{
26 /// The parsing states
27 typedef enum {atHelloNone
= 0, atHelloStarted
, atHelloReceived
, atCertificatesReceived
, atHelloDoneReceived
, atNstReceived
, atCcsReceived
, atFinishReceived
} ParserState
;
29 /// TLS record protocol, content types, RFC5246 section 6.2.1
30 typedef enum {ctNone
= 0, ctChangeCipherSpec
= 20, ctAlert
= 21, ctHandshake
= 22, ctApplicationData
} ContentType
;
31 /// TLS Handshake protocol, handshake types, RFC5246 section 7.4
32 typedef enum {hskNone
= 0, hskServerHello
= 2, shkNewSessionTicket
= 4, hskCertificate
= 11, hskServerHelloDone
= 14, hskFinished
= 20} HandshakeType
;
34 HandshakeParser(): state(atHelloNone
), currentContentType(ctNone
), unParsedContent(0), parsingPos(0), currentMsg(0), currentMsgSize(0), certificatesMsgPos(0), certificatesMsgSize(0), ressumingSession(false), parseDone(false), parseError(false) {}
36 /// Parses the SSL Server Hello records stored in data.
37 /// Return false if the hello messages are not complete (HelloDone
38 /// or Finished handshake messages are not received)
39 /// On parse error, return false and sets the parseError member to true.
40 bool parseServerHello(const unsigned char *data
, size_t dataSize
);
42 /// Parse server certificates message and store the certificate to serverCertificates list
43 bool parseServerCertificates(Ssl::X509_STACK_Pointer
&serverCertificates
, const unsigned char *msg
, size_t size
);
45 ParserState state
; ///< current parsing state.
47 ContentType currentContentType
; ///< The current SSL record content type
48 size_t unParsedContent
; ///< The size of current SSL record, which is not parsed yet
49 size_t parsingPos
; ///< The parsing position from the beginning of parsed data
50 size_t currentMsg
; ///< The current handshake message possition from the beginning of parsed data
51 size_t currentMsgSize
; ///< The current handshake message size.
53 size_t certificatesMsgPos
; ///< The possition of certificates message from the beggining of parsed data
54 size_t certificatesMsgSize
; ///< The size of certificates message
55 bool ressumingSession
; ///< True if this is a resumming session
57 bool parseDone
; ///< The parser finishes its job
58 bool parseError
; ///< Set to tru by parse on parse error.
61 /// Do nothing if there are unparsed data from existing SSL record
62 /// else parses the next SSL record.
63 /// Return false if the next SSL record is not complete.
64 bool parseNextContentRecord(const unsigned char *msg
, size_t size
);
65 /// Consumes the current SSL record and set the parsingPos to the next
66 bool skipContentDataRecord(const unsigned char *msg
, size_t size
);
67 /// Parses the next handshake message in current SSL record
68 HandshakeType
parseNextHandshakeMessage(const unsigned char *msg
, size_t size
);
71 /// BIO source and sink node, handling socket I/O and monitoring SSL state
80 /// Class to store SSL connection features
85 bool get(const SSL
*ssl
); ///< Retrieves the features from SSL object
86 /// Retrieves features from raw SSL Hello message.
87 /// \param record whether to store Message to the helloMessage member
88 bool get(const MemBuf
&, bool record
= true);
89 /// Parses a v3 ClientHello message
90 bool parseV3Hello(const unsigned char *hello
, size_t helloSize
);
91 /// Parses a v23 ClientHello message
92 bool parseV23Hello(const unsigned char *hello
, size_t helloSize
);
93 /// Parses a v3 ServerHello message.
94 bool parseV3ServerHello(const unsigned char *hello
, size_t helloSize
);
95 /// Prints to os stream a human readable form of sslFeatures object
96 std::ostream
& print(std::ostream
&os
) const;
97 /// Converts to the internal squid SSL version form the sslVersion
98 int toSquidSSLVersion() const;
99 /// Configure the SSL object with the SSL features of the sslFeatures object
100 void applyToSSL(SSL
*ssl
, Ssl::BumpMode bumpMode
) const;
101 /// Parses an SSL Message header. It returns the ssl Message size.
102 /// \retval >0 if the hello size is retrieved
103 /// \retval 0 if the contents of the buffer are not enough
104 /// \retval <0 if the contents of buf are not SSLv3 or TLS hello message
105 int parseMsgHead(const MemBuf
&);
107 int sslVersion
; ///< The requested/used SSL version
108 int compressMethod
; ///< The requested/used compressed method
109 int helloMsgSize
; ///< the hello message size
110 mutable SBuf serverName
; ///< The SNI hostname, if any
111 std::string clientRequestedCiphers
; ///< The client requested ciphers
112 bool unknownCiphers
; ///< True if one or more ciphers are unknown
113 std::string ecPointFormatList
;///< tlsExtension ecPointFormatList
114 std::string ellipticCurves
; ///< tlsExtension ellipticCurveList
115 std::string opaquePrf
; ///< tlsExtension opaquePrf
117 bool tlsTicketsExtension
; ///< whether TLS tickets extension is enabled
118 bool hasTlsTicket
; ///< whether a TLS ticket is included
119 bool tlsStatusRequest
; ///< whether the TLS status request extension is set
120 SBuf tlsAppLayerProtoNeg
; ///< The value of the TLS application layer protocol extension if it is enabled
121 /// The client random number
122 unsigned char client_random
[SSL3_RANDOM_SIZE
];
124 std::list
<int> extensions
;
128 explicit Bio(const int anFd
);
131 /// Writes the given data to socket
132 virtual int write(const char *buf
, int size
, BIO
*table
);
134 /// Reads data from socket
135 virtual int read(char *buf
, int size
, BIO
*table
);
137 /// Flushes any buffered data to socket.
138 /// The Ssl::Bio does not buffer any data, so this method has nothing to do
139 virtual void flush(BIO
*table
) {}
141 int fd() const { return fd_
; } ///< The SSL socket descriptor
143 /// Called by linked SSL connection whenever state changes, an alert
144 /// appears, or an error occurs. See SSL_set_info_callback().
145 virtual void stateChanged(const SSL
*ssl
, int where
, int ret
);
147 /// Creates a low-level BIO table, creates a high-level Ssl::Bio object
148 /// for a given socket, and then links the two together via BIO_C_SET_FD.
149 static BIO
*Create(const int fd
, Type type
);
150 /// Tells ssl connection to use BIO and monitor state via stateChanged()
151 static void Link(SSL
*ssl
, BIO
*bio
);
153 /// Prepare the rbuf buffer to accept hello data
156 /// Reads data from socket and record them to a buffer
157 int readAndBuffer(BIO
*table
, const char *description
);
159 const MemBuf
&rBufData() {return rbuf
;}
161 const int fd_
; ///< the SSL socket we are reading and writing
162 MemBuf rbuf
; ///< Used to buffer input data.
165 /// BIO node to handle socket IO for squid client side
166 /// If bumping is enabled this Bio detects and analyses client hello message
167 /// to retrieve the SSL features supported by the client
168 class ClientBio
: public Bio
171 /// The ssl hello message read states
172 typedef enum {atHelloNone
= 0, atHelloStarted
, atHelloReceived
} HelloReadState
;
173 explicit ClientBio(const int anFd
): Bio(anFd
), holdRead_(false), holdWrite_(false), helloState(atHelloNone
), helloSize(0), wrongProtocol(false) {}
175 /// The ClientBio version of the Ssl::Bio::stateChanged method
176 /// When the client hello message retrieved, fill the
177 /// "features" member with the client provided informations.
178 virtual void stateChanged(const SSL
*ssl
, int where
, int ret
);
179 /// The ClientBio version of the Ssl::Bio::write method
180 virtual int write(const char *buf
, int size
, BIO
*table
);
181 /// The ClientBio version of the Ssl::Bio::read method
182 /// If the holdRead flag is true then it does not write any data
183 /// to socket and sets the "read retry" flag of the BIO to true
184 virtual int read(char *buf
, int size
, BIO
*table
);
185 /// Return true if the client hello message received and analized
186 bool gotHello() { return (helloState
== atHelloReceived
); }
187 /// Return the SSL features requested by SSL client
188 const Bio::sslFeatures
&getFeatures() const {return features
;}
189 /// Prevents or allow writting on socket.
190 void hold(bool h
) {holdRead_
= holdWrite_
= h
;}
191 /// True if client does not looks like an SSL client
192 bool noSslClient() {return wrongProtocol
;}
194 /// True if the SSL state corresponds to a hello message
195 bool isClientHello(int state
);
196 /// The futures retrieved from client SSL hello message
197 Bio::sslFeatures features
;
198 bool holdRead_
; ///< The read hold state of the bio.
199 bool holdWrite_
; ///< The write hold state of the bio.
200 HelloReadState helloState
; ///< The SSL hello read state
201 int helloSize
; ///< The SSL hello message sent by client size
202 bool wrongProtocol
; ///< true if client SSL hello parsing failed
205 /// BIO node to handle socket IO for squid server side
206 /// If bumping is enabled, analyses the SSL hello message sent by squid OpenSSL
207 /// subsystem (step3 bumping step) against bumping mode:
208 /// * Peek mode: Send client hello message instead of the openSSL generated
209 /// hello message and normaly denies bumping and allow only
210 /// splice or terminate the SSL connection
211 /// * Stare mode: Sends the openSSL generated hello message and normaly
212 /// denies splicing and allow bump or terminate the SSL
214 /// If SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK is enabled also checks if the
215 /// openSSL library features are compatible with the features reported in
216 /// web client SSL hello message and if it is, overwrites the openSSL SSL
217 /// object members to replace hello message with web client hello message.
218 /// This is may allow bumping in peek mode and splicing in stare mode after
219 /// the server hello message received.
220 class ServerBio
: public Bio
223 explicit ServerBio(const int anFd
): Bio(anFd
), helloMsgSize(0), helloBuild(false), allowSplice(false), allowBump(false), holdWrite_(false), holdRead_(true), bumpMode_(bumpNone
), rbufConsumePos(0) {}
224 /// The ServerBio version of the Ssl::Bio::stateChanged method
225 virtual void stateChanged(const SSL
*ssl
, int where
, int ret
);
226 /// The ServerBio version of the Ssl::Bio::write method
227 /// If a clientRandom number is set then rewrites the raw hello message
228 /// "client random" field with the provided random number.
229 /// It may buffer the output packets.
230 virtual int write(const char *buf
, int size
, BIO
*table
);
231 /// The ServerBio version of the Ssl::Bio::read method
232 /// If the record flag is set then append the data to the rbuf member
233 virtual int read(char *buf
, int size
, BIO
*table
);
234 /// The ServerBio version of the Ssl::Bio::flush method.
235 /// Flushes any buffered data
236 virtual void flush(BIO
*table
);
237 /// Sets the random number to use in client SSL HELLO message
238 void setClientFeatures(const sslFeatures
&features
);
240 bool resumingSession();
242 /// Reads Server hello message+certificates+ServerHelloDone message sent
243 /// by server and buffer it to rbuf member
244 int readAndBufferServerHelloMsg(BIO
*table
, const char *description
);
246 /// The write hold state
247 bool holdWrite() const {return holdWrite_
;}
248 /// Enables or disables the write hold state
249 void holdWrite(bool h
) {holdWrite_
= h
;}
250 /// The read hold state
251 bool holdRead() const {return holdRead_
;}
252 /// Enables or disables the read hold state
253 void holdRead(bool h
) {holdRead_
= h
;}
254 /// Whether we can splice or not the SSL stream
255 bool canSplice() {return allowSplice
;}
256 /// Whether we can bump or not the SSL stream
257 bool canBump() {return allowBump
;}
259 void mode(Ssl::BumpMode m
) {bumpMode_
= m
;}
260 Ssl::BumpMode
bumpMode() {return bumpMode_
;} ///< return the bumping mode
262 /// Return true if the Server hello message received
263 bool gotHello() const { return (parser_
.parseDone
&& !parser_
.parseError
); }
265 /// Return true if the Server Hello parsing failed
266 bool gotHelloFailed() const { return (parser_
.parseDone
&& parser_
.parseError
); }
268 const Ssl::X509_STACK_Pointer
&serverCertificates();
270 sslFeatures clientFeatures
; ///< SSL client features extracted from ClientHello message or SSL object
271 SBuf helloMsg
; ///< Used to buffer output data.
272 mb_size_t helloMsgSize
;
273 bool helloBuild
; ///< True if the client hello message sent to the server
274 bool allowSplice
; ///< True if the SSL stream can be spliced
275 bool allowBump
; ///< True if the SSL stream can be bumped
276 bool holdWrite_
; ///< The write hold state of the bio.
277 bool holdRead_
; ///< The read hold state of the bio.
278 Ssl::BumpMode bumpMode_
;
280 ///< The size of data stored in rbuf which passed to the openSSL
281 size_t rbufConsumePos
;
282 HandshakeParser parser_
; ///< The SSL messages parser.
283 Ssl::X509_STACK_Pointer serverCertificates_
; ///< The certificates chain sent by the SSL server
287 std::ostream
&operator <<(std::ostream
&os
, Ssl::Bio::sslFeatures
const &f
)
294 #endif /* SQUID_SSL_BIO_H */