]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/bio.h
Merged from trunk
[thirdparty/squid.git] / src / ssl / bio.h
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 #ifndef SQUID_SSL_BIO_H
10 #define SQUID_SSL_BIO_H
11
12 #include "fd.h"
13 #include "sbuf/SBuf.h"
14
15 #include <iosfwd>
16 #include <list>
17 #if HAVE_OPENSSL_BIO_H
18 #include <openssl/bio.h>
19 #endif
20 #include <string>
21
22 namespace Ssl
23 {
24
25 /// BIO source and sink node, handling socket I/O and monitoring SSL state
26 class Bio
27 {
28 public:
29 enum Type {
30 BIO_TO_CLIENT = 6000,
31 BIO_TO_SERVER
32 };
33
34 /// Class to store SSL connection features
35 class sslFeatures
36 {
37 public:
38 sslFeatures();
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);
63 public:
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
74 bool doHeartBeats;
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
80 /// handshake message
81 bool hasCcsOrNst;
82 /// The client random number
83 unsigned char client_random[SSL3_RANDOM_SIZE];
84 SBuf sessionId;
85 std::list<int> extensions;
86 SBuf helloMessage;
87 bool initialized_;
88 };
89 explicit Bio(const int anFd);
90 virtual ~Bio();
91
92 /// Writes the given data to socket
93 virtual int write(const char *buf, int size, BIO *table);
94
95 /// Reads data from socket
96 virtual int read(char *buf, int size, BIO *table);
97
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) {}
101
102 int fd() const { return fd_; } ///< The SSL socket descriptor
103
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);
107
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);
113
114 /// Prepare the rbuf buffer to accept hello data
115 void prepReadBuf();
116
117 /// Reads data from socket and record them to a buffer
118 int readAndBuffer(char *buf, int size, BIO *table, const char *description);
119
120 /// Return the TLS features requested by TLS client
121 const Bio::sslFeatures &receivedHelloFeatures() const {return receivedHelloFeatures_;}
122
123 const MemBuf &rBufData() {return rbuf;}
124 protected:
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_;
129 };
130
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
135 {
136 public:
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) {}
140
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;}
157 private:
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
165 };
166
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
175 /// connection
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
183 {
184 public:
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);
201
202 /// Parses server Hello message if it is recorded and extracts
203 /// server-supported features.
204 void extractHelloFeatures();
205
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;}
217 /// The bumping mode
218 void mode(Ssl::BumpMode m) {bumpMode_ = m;}
219 Ssl::BumpMode bumpMode() {return bumpMode_;} ///< return the bumping mode
220 private:
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_;
230 };
231
232 inline
233 std::ostream &operator <<(std::ostream &os, Ssl::Bio::sslFeatures const &f)
234 {
235 return f.print(os);
236 }
237
238 } // namespace Ssl
239
240 #endif /* SQUID_SSL_BIO_H */
241