]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/bio.h
SSL Peek and Splice
[thirdparty/squid.git] / src / ssl / bio.h
1 #ifndef SQUID_SSL_BIO_H
2 #define SQUID_SSL_BIO_H
3
4 #include "fd.h"
5 #include "SBuf.h"
6
7 #include <iosfwd>
8 #include <list>
9 #if HAVE_OPENSSL_BIO_H
10 #include <openssl/bio.h>
11 #endif
12 #include <string>
13
14 namespace Ssl
15 {
16
17 /// BIO source and sink node, handling socket I/O and monitoring SSL state
18 class Bio
19 {
20 public:
21 enum Type {
22 BIO_TO_CLIENT = 6000,
23 BIO_TO_SERVER
24 };
25
26 /// Class to store SSL connection features
27 class sslFeatures
28 {
29 public:
30 sslFeatures();
31 bool get(const SSL *ssl); ///< Retrieves the features from SSL object
32 bool get(const unsigned char *hello); ///< Retrieves the features from raw SSL hello message
33 bool parseV3Hello(const unsigned char *hello);
34 bool parseV23Hello(const unsigned char *hello);
35 /// Prints to os stream a human readable form of sslFeatures object
36 std::ostream & print(std::ostream &os) const;
37 /// Converts to the internal squid SSL version form the sslVersion
38 int toSquidSSLVersion() const;
39 /// Configure the SSL object with the SSL features of the sslFeatures object
40 void applyToSSL(SSL *ssl) const;
41 public:
42 int sslVersion; ///< The requested/used SSL version
43 int compressMethod; ///< The requested/used compressed method
44 mutable SBuf serverName; ///< The SNI hostname, if any
45 std::string clientRequestedCiphers; ///< The client requested ciphers
46 bool unknownCiphers; ///< True if one or more ciphers are unknown
47 std::string ecPointFormatList;///< tlsExtension ecPointFormatList
48 std::string ellipticCurves; ///< tlsExtension ellipticCurveList
49 std::string opaquePrf; ///< tlsExtension opaquePrf
50 bool doHeartBeats;
51 /// The client random number
52 unsigned char client_random[SSL3_RANDOM_SIZE];
53 std::list<int> extensions;
54 SBuf helloMessage;
55 };
56 explicit Bio(const int anFd);
57 virtual ~Bio();
58
59 /// Writes the given data to socket
60 virtual int write(const char *buf, int size, BIO *table);
61
62 /// Reads data from socket
63 virtual int read(char *buf, int size, BIO *table);
64
65 /// Flushes any buffered data to socket.
66 /// The Ssl::Bio does not buffer any data, so this method has nothing to do
67 virtual void flush(BIO *table) {}
68
69 int fd() const { return fd_; } ///< The SSL socket descriptor
70
71 /// Called by linked SSL connection whenever state changes, an alert
72 /// appears, or an error occurs. See SSL_set_info_callback().
73 virtual void stateChanged(const SSL *ssl, int where, int ret);
74
75 /// Creates a low-level BIO table, creates a high-level Ssl::Bio object
76 /// for a given socket, and then links the two together via BIO_C_SET_FD.
77 static BIO *Create(const int fd, Type type);
78 /// Tells ssl connection to use BIO and monitor state via stateChanged()
79 static void Link(SSL *ssl, BIO *bio);
80
81 const MemBuf &rBufData() {return rbuf;}
82 protected:
83 const int fd_; ///< the SSL socket we are reading and writing
84 MemBuf rbuf; ///< Used to buffer input data.
85 };
86
87 /// BIO node to handle socket IO for squid client side
88 /// If bumping is enabled this Bio detects and analyses client hello message
89 /// to retrieve the SSL features supported by the client
90 class ClientBio: public Bio
91 {
92 public:
93 /// The ssl hello message read states
94 typedef enum {atHelloNone = 0, atHelloStarted, atHelloReceived} HelloReadState;
95 explicit ClientBio(const int anFd): Bio(anFd), holdRead_(false), holdWrite_(false), helloState(atHelloNone), helloSize(0) {}
96
97 /// The ClientBio version of the Ssl::Bio::stateChanged method
98 /// When the client hello message retrieved, fill the
99 /// "features" member with the client provided informations.
100 virtual void stateChanged(const SSL *ssl, int where, int ret);
101 /// The ClientBio version of the Ssl::Bio::write method
102 virtual int write(const char *buf, int size, BIO *table);
103 /// The ClientBio version of the Ssl::Bio::read method
104 /// If the holdRead flag is true then it does not write any data
105 /// to socket and sets the "read retry" flag of the BIO to true
106 virtual int read(char *buf, int size, BIO *table);
107 /// Return true if the client hello message received and analized
108 bool gotHello() {return features.sslVersion != -1;}
109 /// Return the SSL features requested by SSL client
110 const Bio::sslFeatures &getFeatures() const {return features;}
111 /// Prevents or allow writting on socket.
112 void hold(bool h) {holdRead_ = holdWrite_ = h;}
113
114 private:
115 /// True if the SSL state corresponds to a hello message
116 bool isClientHello(int state);
117 /// The futures retrieved from client SSL hello message
118 Bio::sslFeatures features;
119 bool holdRead_; ///< The read hold state of the bio.
120 bool holdWrite_; ///< The write hold state of the bio.
121 HelloReadState helloState; ///< The SSL hello read state
122 int helloSize; ///< The SSL hello message sent by client size
123 };
124
125 /// BIO node to handle socket IO for squid server side
126 /// If bumping is enabled, analyses the SSL hello message sent by squid OpenSSL
127 /// subsystem (step3 bumping step) against bumping mode:
128 /// * Peek mode: Send client hello message instead of the openSSL generated
129 /// hello message and normaly denies bumping and allow only
130 /// splice or terminate the SSL connection
131 /// * Stare mode: Sends the openSSL generated hello message and normaly
132 /// denies splicing and allow bump or terminate the SSL
133 /// connection
134 /// If SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK is enabled also checks if the
135 /// openSSL library features are compatible with the features reported in
136 /// web client SSL hello message and if it is, overwrites the openSSL SSL
137 /// object members to replace hello message with web client hello message.
138 /// This is may allow bumping in peek mode and splicing in stare mode after
139 /// the server hello message received.
140 class ServerBio: public Bio
141 {
142 public:
143 explicit ServerBio(const int anFd): Bio(anFd), featuresSet(false), helloMsgSize(0), helloBuild(false), allowSplice(false), allowBump(false), holdWrite_(false), record_(false), bumpMode_(bumpNone) {}
144 /// The ServerBio version of the Ssl::Bio::stateChanged method
145 virtual void stateChanged(const SSL *ssl, int where, int ret);
146 /// The ServerBio version of the Ssl::Bio::write method
147 /// If a clientRandom number is set then rewrites the raw hello message
148 /// "client random" field with the provided random number.
149 /// It may buffer the output packets.
150 virtual int write(const char *buf, int size, BIO *table);
151 /// The ServerBio version of the Ssl::Bio::read method
152 /// If the record flag is set then append the data to the rbuf member
153 virtual int read(char *buf, int size, BIO *table);
154 /// The ServerBio version of the Ssl::Bio::flush method.
155 /// Flushes any buffered data
156 virtual void flush(BIO *table);
157 /// Sets the random number to use in client SSL HELLO message
158 void setClientFeatures(const sslFeatures &features);
159
160 /// The write hold state
161 bool holdWrite() const {return holdWrite_;}
162 /// Enables or disables the write hold state
163 void holdWrite(bool h) {holdWrite_ = h;}
164 /// Enables or disables the input data recording, for internal analysis.
165 void recordInput(bool r) {record_ = r;}
166 /// Whether we can splice or not the SSL stream
167 bool canSplice() {return allowSplice;}
168 /// Whether we can bump or not the SSL stream
169 bool canBump() {return allowBump;}
170 /// The bumping mode
171 void mode(Ssl::BumpMode m) {bumpMode_ = m;}
172 private:
173 /// A random number to use as "client random" in client hello message
174 sslFeatures clientFeatures;
175 bool featuresSet; ///< True if the clientFeatures member is set and can be used
176 SBuf helloMsg; ///< Used to buffer output data.
177 mb_size_t helloMsgSize;
178 bool helloBuild; ///< True if the client hello message sent to the server
179 bool allowSplice; ///< True if the SSL stream can be spliced
180 bool allowBump; ///< True if the SSL stream can be bumped
181 bool holdWrite_; ///< The write hold state of the bio.
182 bool record_; ///< If true the input data recorded to rbuf for internal use
183 Ssl::BumpMode bumpMode_;
184 };
185
186 inline
187 std::ostream &operator <<(std::ostream &os, Ssl::Bio::sslFeatures const &f)
188 {
189 return f.print(os);
190 }
191
192 } // namespace Ssl
193
194 #endif /* SQUID_SSL_BIO_H */