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