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