2 * Copyright (C) 1996-2017 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
14 #include "FadingCounter.h"
16 #include "security/Handshake.h"
20 #if HAVE_OPENSSL_BIO_H
21 #include <openssl/bio.h>
24 #include <type_traits>
29 /// BIO source and sink node, handling socket I/O and monitoring SSL state
33 explicit Bio(const int anFd
);
36 /// Writes the given data to socket
37 virtual int write(const char *buf
, int size
, BIO
*table
);
39 /// Reads data from socket
40 virtual int read(char *buf
, int size
, BIO
*table
);
42 /// Flushes any buffered data to socket.
43 /// The Ssl::Bio does not buffer any data, so this method has nothing to do
44 virtual void flush(BIO
*table
) {}
46 int fd() const { return fd_
; } ///< The SSL socket descriptor
48 /// Called by linked SSL connection whenever state changes, an alert
49 /// appears, or an error occurs. See SSL_set_info_callback().
50 virtual void stateChanged(const SSL
*ssl
, int where
, int ret
);
52 /// Creates a low-level BIO table, creates a high-level Ssl::Bio object
53 /// for a given socket, and then links the two together via BIO_C_SET_FD.
54 static BIO
*Create(const int fd
, Security::Io::Type type
);
55 /// Tells ssl connection to use BIO and monitor state via stateChanged()
56 static void Link(SSL
*ssl
, BIO
*bio
);
58 const SBuf
&rBufData() {return rbuf
;} ///< The buffered input data
60 const int fd_
; ///< the SSL socket we are reading and writing
61 SBuf rbuf
; ///< Used to buffer input data.
64 /// BIO node to handle socket IO for squid client side
65 /// If bumping is enabled this Bio detects and analyses client hello message
66 /// to retrieve the SSL features supported by the client
67 class ClientBio
: public Bio
70 explicit ClientBio(const int anFd
);
72 /// The ClientBio version of the Ssl::Bio::stateChanged method
73 /// When the client hello message retrieved, fill the
74 /// "features" member with the client provided informations.
75 virtual void stateChanged(const SSL
*ssl
, int where
, int ret
);
76 /// The ClientBio version of the Ssl::Bio::write method
77 virtual int write(const char *buf
, int size
, BIO
*table
);
78 /// The ClientBio version of the Ssl::Bio::read method
79 /// If the holdRead flag is true then it does not write any data
80 /// to socket and sets the "read retry" flag of the BIO to true
81 virtual int read(char *buf
, int size
, BIO
*table
);
82 /// Prevents or allow writting on socket.
83 void hold(bool h
) {holdRead_
= holdWrite_
= h
;}
85 /// Sets the buffered input data (Bio::rbuf).
86 /// Used to pass payload data (normally client HELLO data) retrieved
88 void setReadBufData(SBuf
&data
) {rbuf
= data
;}
90 /// approximate size of a time window for computing client-initiated renegotiation rate (in seconds)
91 static const time_t RenegotiationsWindow
= 10;
93 /// the maximum tolerated number of client-initiated renegotiations in RenegotiationsWindow
94 static const int RenegotiationsLimit
= 5;
96 bool holdRead_
; ///< The read hold state of the bio.
97 bool holdWrite_
; ///< The write hold state of the bio.
98 int helloSize
; ///< The SSL hello message sent by client size
99 FadingCounter renegotiations
; ///< client requested renegotiations limit control
101 /// why we should terminate the connection during next TLS operation (or nil)
102 const char *abortReason
;
105 /// BIO node to handle socket IO for squid server side
106 /// If bumping is enabled, analyses the SSL hello message sent by squid OpenSSL
107 /// subsystem (step3 bumping step) against bumping mode:
108 /// * Peek mode: Send client hello message instead of the openSSL generated
109 /// hello message and normaly denies bumping and allow only
110 /// splice or terminate the SSL connection
111 /// * Stare mode: Sends the openSSL generated hello message and normaly
112 /// denies splicing and allow bump or terminate the SSL
114 /// If SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK is enabled also checks if the
115 /// openSSL library features are compatible with the features reported in
116 /// web client SSL hello message and if it is, overwrites the openSSL SSL
117 /// object members to replace hello message with web client hello message.
118 /// This is may allow bumping in peek mode and splicing in stare mode after
119 /// the server hello message received.
120 class ServerBio
: public Bio
123 explicit ServerBio(const int anFd
);
125 /// The ServerBio version of the Ssl::Bio::stateChanged method
126 virtual void stateChanged(const SSL
*ssl
, int where
, int ret
);
127 /// The ServerBio version of the Ssl::Bio::write method
128 /// If a clientRandom number is set then rewrites the raw hello message
129 /// "client random" field with the provided random number.
130 /// It may buffer the output packets.
131 virtual int write(const char *buf
, int size
, BIO
*table
);
132 /// The ServerBio version of the Ssl::Bio::read method
133 /// If the record flag is set then append the data to the rbuf member
134 virtual int read(char *buf
, int size
, BIO
*table
);
135 /// The ServerBio version of the Ssl::Bio::flush method.
136 /// Flushes any buffered data
137 virtual void flush(BIO
*table
);
138 /// Sets the random number to use in client SSL HELLO message
139 void setClientFeatures(Security::TlsDetails::Pointer
const &details
, SBuf
const &hello
);
141 bool resumingSession();
143 /// The write hold state
144 bool holdWrite() const {return holdWrite_
;}
145 /// Enables or disables the write hold state
146 void holdWrite(bool h
) {holdWrite_
= h
;}
147 /// The read hold state
148 bool holdRead() const {return holdRead_
;}
149 /// Enables or disables the read hold state
150 void holdRead(bool h
) {holdRead_
= h
;}
151 /// Enables or disables the input data recording, for internal analysis.
152 void recordInput(bool r
) {record_
= r
;}
153 /// Whether we can splice or not the SSL stream
154 bool canSplice() {return allowSplice
;}
155 /// Whether we can bump or not the SSL stream
156 bool canBump() {return allowBump
;}
158 void mode(Ssl::BumpMode m
) {bumpMode_
= m
;}
159 Ssl::BumpMode
bumpMode() {return bumpMode_
;} ///< return the bumping mode
161 /// \retval true if the Server hello message received
162 bool gotHello() const { return (parsedHandshake
&& !parseError
); }
164 /// Return true if the Server Hello parsing failed
165 bool gotHelloFailed() const { return (parsedHandshake
&& parseError
); }
167 /// \return the server certificates list if received and parsed correctly
168 const Security::CertList
&serverCertificatesIfAny() { return parser_
.serverCertificates
; }
170 /// \return the TLS Details advertised by TLS server.
171 const Security::TlsDetails::Pointer
&receivedHelloDetails() const {return parser_
.details
;}
174 int readAndGive(char *buf
, const int size
, BIO
*table
);
175 int readAndParse(char *buf
, const int size
, BIO
*table
);
176 int readAndBuffer(BIO
*table
);
177 int giveBuffered(char *buf
, const int size
);
179 /// SSL client features extracted from ClientHello message or SSL object
180 Security::TlsDetails::Pointer clientTlsDetails
;
181 /// TLS client hello message, used to adapt our tls Hello message to the server
182 SBuf clientSentHello
;
183 SBuf helloMsg
; ///< Used to buffer output data.
184 mb_size_t helloMsgSize
;
185 bool helloBuild
; ///< True if the client hello message sent to the server
186 bool allowSplice
; ///< True if the SSL stream can be spliced
187 bool allowBump
; ///< True if the SSL stream can be bumped
188 bool holdWrite_
; ///< The write hold state of the bio.
189 bool holdRead_
; ///< The read hold state of the bio.
190 bool record_
; ///< If true the input data recorded to rbuf for internal use
191 bool parsedHandshake
; ///< whether we are done parsing TLS Hello
192 bool parseError
; ///< error while parsing server hello message
193 Ssl::BumpMode bumpMode_
;
195 /// The size of data stored in rbuf which passed to the openSSL
196 size_t rbufConsumePos
;
197 Security::HandshakeParser parser_
; ///< The TLS/SSL messages parser.
203 applyTlsDetailsToSSL(SSL
*ssl
, Security::TlsDetails::Pointer
const &details
, Ssl::BumpMode bumpMode
);
205 #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
206 // OpenSSL v1.0 bio compatibility functions
207 inline void *BIO_get_data(BIO
*table
) { return table
->ptr
; }
208 inline void BIO_set_data(BIO
*table
, void *data
) { table
->ptr
= data
; }
209 inline int BIO_get_init(BIO
*table
) { return table
->init
; }
210 inline void BIO_set_init(BIO
*table
, int init
) { table
->init
= init
; }
213 #endif /* USE_OPENSSL */
214 #endif /* SQUID_SSL_BIO_H */