2 * Copyright (C) 1996-2016 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
13 #include "sbuf/SBuf.h"
17 #if HAVE_OPENSSL_BIO_H
18 #include <openssl/bio.h>
25 /// BIO source and sink node, handling socket I/O and monitoring SSL state
34 /// Class to store SSL connection features
39 bool get(const SSL
*ssl
); ///< Retrieves the features from SSL object
40 /// Retrieves features from raw SSL Hello message.
41 /// \param record whether to store Message to the helloMessage member
42 bool get(const MemBuf
&, bool record
= true);
43 /// Parses a v3 ClientHello message
44 bool parseV3Hello(const unsigned char *hello
, size_t helloSize
);
45 /// Parses a v23 ClientHello message
46 bool parseV23Hello(const unsigned char *hello
, size_t helloSize
);
47 /// Parses a v3 ServerHello message.
48 bool parseV3ServerHello(const unsigned char *hello
, size_t helloSize
);
49 /// Prints to os stream a human readable form of sslFeatures object
50 std::ostream
& print(std::ostream
&os
) const;
51 /// Converts to the internal squid SSL version form the sslVersion
52 int toSquidSSLVersion() const;
53 /// Configure the SSL object with the SSL features of the sslFeatures object
54 void applyToSSL(SSL
*ssl
, Ssl::BumpMode bumpMode
) const;
55 /// Parses an SSL Message header. It returns the ssl Message size.
56 /// \retval >0 if the hello size is retrieved
57 /// \retval 0 if the contents of the buffer are not enough
58 /// \retval <0 if the contents of buf are not SSLv3 or TLS hello message
59 int parseMsgHead(const MemBuf
&);
60 /// Parses msg buffer and return true if one of the Change Cipher Spec
61 /// or New Session Ticket messages found
62 bool checkForCcsOrNst(const unsigned char *msg
, size_t size
);
64 int sslHelloVersion
; ///< The SSL hello message version
65 int sslVersion
; ///< The requested/used SSL version
66 int compressMethod
; ///< The requested/used compressed method
67 int helloMsgSize
; ///< the hello message size
68 mutable SBuf serverName
; ///< The SNI hostname, if any
69 std::string clientRequestedCiphers
; ///< The client requested ciphers
70 bool unknownCiphers
; ///< True if one or more ciphers are unknown
71 std::string ecPointFormatList
;///< tlsExtension ecPointFormatList
72 std::string ellipticCurves
; ///< tlsExtension ellipticCurveList
73 std::string opaquePrf
; ///< tlsExtension opaquePrf
75 bool tlsTicketsExtension
; ///< whether TLS tickets extension is enabled
76 bool hasTlsTicket
; ///< whether a TLS ticket is included
77 bool tlsStatusRequest
; ///< whether the TLS status request extension is set
78 SBuf tlsAppLayerProtoNeg
; ///< The value of the TLS application layer protocol extension if it is enabled
79 /// whether Change Cipher Spec message included in ServerHello
82 /// The client random number
83 unsigned char client_random
[SSL3_RANDOM_SIZE
];
85 std::list
<int> extensions
;
89 explicit Bio(const int anFd
);
92 /// Writes the given data to socket
93 virtual int write(const char *buf
, int size
, BIO
*table
);
95 /// Reads data from socket
96 virtual int read(char *buf
, int size
, BIO
*table
);
98 /// Flushes any buffered data to socket.
99 /// The Ssl::Bio does not buffer any data, so this method has nothing to do
100 virtual void flush(BIO
*table
) {}
102 int fd() const { return fd_
; } ///< The SSL socket descriptor
104 /// Called by linked SSL connection whenever state changes, an alert
105 /// appears, or an error occurs. See SSL_set_info_callback().
106 virtual void stateChanged(const SSL
*ssl
, int where
, int ret
);
108 /// Creates a low-level BIO table, creates a high-level Ssl::Bio object
109 /// for a given socket, and then links the two together via BIO_C_SET_FD.
110 static BIO
*Create(const int fd
, Type type
);
111 /// Tells ssl connection to use BIO and monitor state via stateChanged()
112 static void Link(SSL
*ssl
, BIO
*bio
);
114 /// Prepare the rbuf buffer to accept hello data
117 /// Reads data from socket and record them to a buffer
118 int readAndBuffer(char *buf
, int size
, BIO
*table
, const char *description
);
120 /// Return the TLS features requested by TLS client
121 const Bio::sslFeatures
&receivedHelloFeatures() const {return receivedHelloFeatures_
;}
123 const MemBuf
&rBufData() {return rbuf
;}
125 const int fd_
; ///< the SSL socket we are reading and writing
126 MemBuf rbuf
; ///< Used to buffer input data.
127 /// The features retrieved from client or Server TLS hello message
128 Bio::sslFeatures receivedHelloFeatures_
;
131 /// BIO node to handle socket IO for squid client side
132 /// If bumping is enabled this Bio detects and analyses client hello message
133 /// to retrieve the SSL features supported by the client
134 class ClientBio
: public Bio
137 /// The ssl hello message read states
138 typedef enum {atHelloNone
= 0, atHelloStarted
, atHelloReceived
} HelloReadState
;
139 explicit ClientBio(const int anFd
): Bio(anFd
), holdRead_(false), holdWrite_(false), helloState(atHelloNone
), helloSize(0), wrongProtocol(false) {}
141 /// The ClientBio version of the Ssl::Bio::stateChanged method
142 /// When the client hello message retrieved, fill the
143 /// "features" member with the client provided informations.
144 virtual void stateChanged(const SSL
*ssl
, int where
, int ret
);
145 /// The ClientBio version of the Ssl::Bio::write method
146 virtual int write(const char *buf
, int size
, BIO
*table
);
147 /// The ClientBio version of the Ssl::Bio::read method
148 /// If the holdRead flag is true then it does not write any data
149 /// to socket and sets the "read retry" flag of the BIO to true
150 virtual int read(char *buf
, int size
, BIO
*table
);
151 /// Return true if the client hello message received and analized
152 bool gotHello() { return (helloState
== atHelloReceived
); }
153 /// Prevents or allow writting on socket.
154 void hold(bool h
) {holdRead_
= holdWrite_
= h
;}
155 /// True if client does not looks like an SSL client
156 bool noSslClient() {return wrongProtocol
;}
158 /// True if the SSL state corresponds to a hello message
159 bool isClientHello(int state
);
160 bool holdRead_
; ///< The read hold state of the bio.
161 bool holdWrite_
; ///< The write hold state of the bio.
162 HelloReadState helloState
; ///< The SSL hello read state
163 int helloSize
; ///< The SSL hello message sent by client size
164 bool wrongProtocol
; ///< true if client SSL hello parsing failed
167 /// BIO node to handle socket IO for squid server side
168 /// If bumping is enabled, analyses the SSL hello message sent by squid OpenSSL
169 /// subsystem (step3 bumping step) against bumping mode:
170 /// * Peek mode: Send client hello message instead of the openSSL generated
171 /// hello message and normaly denies bumping and allow only
172 /// splice or terminate the SSL connection
173 /// * Stare mode: Sends the openSSL generated hello message and normaly
174 /// denies splicing and allow bump or terminate the SSL
176 /// If SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK is enabled also checks if the
177 /// openSSL library features are compatible with the features reported in
178 /// web client SSL hello message and if it is, overwrites the openSSL SSL
179 /// object members to replace hello message with web client hello message.
180 /// This is may allow bumping in peek mode and splicing in stare mode after
181 /// the server hello message received.
182 class ServerBio
: public Bio
185 explicit ServerBio(const int anFd
): Bio(anFd
), helloMsgSize(0), helloBuild(false), allowSplice(false), allowBump(false), holdWrite_(false), record_(false), bumpMode_(bumpNone
) {}
186 /// The ServerBio version of the Ssl::Bio::stateChanged method
187 virtual void stateChanged(const SSL
*ssl
, int where
, int ret
);
188 /// The ServerBio version of the Ssl::Bio::write method
189 /// If a clientRandom number is set then rewrites the raw hello message
190 /// "client random" field with the provided random number.
191 /// It may buffer the output packets.
192 virtual int write(const char *buf
, int size
, BIO
*table
);
193 /// The ServerBio version of the Ssl::Bio::read method
194 /// If the record flag is set then append the data to the rbuf member
195 virtual int read(char *buf
, int size
, BIO
*table
);
196 /// The ServerBio version of the Ssl::Bio::flush method.
197 /// Flushes any buffered data
198 virtual void flush(BIO
*table
);
199 /// Sets the random number to use in client SSL HELLO message
200 void setClientFeatures(const sslFeatures
&features
);
202 /// Parses server Hello message if it is recorded and extracts
203 /// server-supported features.
204 void extractHelloFeatures();
206 bool resumingSession();
207 /// The write hold state
208 bool holdWrite() const {return holdWrite_
;}
209 /// Enables or disables the write hold state
210 void holdWrite(bool h
) {holdWrite_
= h
;}
211 /// Enables or disables the input data recording, for internal analysis.
212 void recordInput(bool r
) {record_
= r
;}
213 /// Whether we can splice or not the SSL stream
214 bool canSplice() {return allowSplice
;}
215 /// Whether we can bump or not the SSL stream
216 bool canBump() {return allowBump
;}
218 void mode(Ssl::BumpMode m
) {bumpMode_
= m
;}
219 Ssl::BumpMode
bumpMode() {return bumpMode_
;} ///< return the bumping mode
221 sslFeatures clientFeatures
; ///< SSL client features extracted from ClientHello message or SSL object
222 SBuf helloMsg
; ///< Used to buffer output data.
223 mb_size_t helloMsgSize
;
224 bool helloBuild
; ///< True if the client hello message sent to the server
225 bool allowSplice
; ///< True if the SSL stream can be spliced
226 bool allowBump
; ///< True if the SSL stream can be bumped
227 bool holdWrite_
; ///< The write hold state of the bio.
228 bool record_
; ///< If true the input data recorded to rbuf for internal use
229 Ssl::BumpMode bumpMode_
;
233 std::ostream
&operator <<(std::ostream
&os
, Ssl::Bio::sslFeatures
const &f
)
240 #endif /* SQUID_SSL_BIO_H */