Go to the documentation of this file.
28 extern int socket_read_method(
int,
char *,
int);
29 extern int socket_write_method(
int,
const char *,
int);
37 static long squid_bio_ctrl(BIO *h,
int cmd,
long arg1,
void *arg2);
43 #if HAVE_LIBCRYPTO_BIO_METH_NEW
65 #if HAVE_LIBCRYPTO_BIO_METH_NEW
81 if (BIO *bio = BIO_new(useMethod)) {
82 BIO_int_ctrl(bio, BIO_C_SET_FD, type, fd);
91 SSL_set_bio(ssl, bio, bio);
97 debugs(83, 7,
"Bio constructed, this=" <<
this <<
" FD " <<
fd_);
102 debugs(83, 7,
"Bio destructing, this=" <<
this <<
" FD " << fd_);
109 const int result = socket_write_method(fd_, buf,
size);
113 const int xerrno = errno;
114 debugs(83, 5,
"FD " << fd_ <<
" wrote " << result <<
" <= " <<
size);
116 BIO_clear_retry_flags(table);
119 debugs(83, 5,
"error: " << xerrno <<
" ignored: " << ignoreError);
121 BIO_set_retry_write(table);
132 const int result = socket_read_method(fd_, buf,
size);
136 const int xerrno = errno;
137 debugs(83, 5,
"FD " << fd_ <<
" read " << result <<
" <= " <<
size);
139 BIO_clear_retry_flags(table);
142 debugs(83, 5,
"error: " << xerrno <<
" ignored: " << ignoreError);
144 BIO_set_retry_read(table);
164 debugs(83, 7,
"FD " << fd_ <<
" now: 0x" <<
asHex(where) <<
' ' <<
165 SSL_state_string(ssl) <<
" (" << SSL_state_string_long(ssl) <<
")");
182 if (where & SSL_CB_HANDSHAKE_START) {
183 const int reneg = renegotiations.count(1);
188 if (reneg > RenegotiationsLimit) {
189 abortReason =
"renegotiate requests flood";
190 debugs(83,
DBG_IMPORTANT,
"Terminating TLS connection [from " <<
fd_table[fd_].ipaddr <<
"] due to " << abortReason <<
". This connection received " <<
191 reneg <<
" renegotiate requests in the last " <<
192 RenegotiationsWindow <<
" seconds (and " <<
193 renegotiations.remembered() <<
" requests total).");
202 debugs(83, 3,
"BIO on FD " << fd_ <<
" is aborted");
203 BIO_clear_retry_flags(table);
208 BIO_set_retry_write(table);
219 debugs(83, 3,
"BIO on FD " << fd_ <<
" is aborted");
220 BIO_clear_retry_flags(table);
225 debugs(83, 7,
"Hold flag is set, retry latter. (Hold " <<
size <<
"bytes)");
226 BIO_set_retry_read(table);
230 if (!rbuf.isEmpty()) {
231 int bytes = (
size <= (
int)rbuf.length() ?
size : rbuf.length());
232 memcpy(buf, rbuf.rawContent(), bytes);
249 parsedHandshake(false),
253 parser_(
Security::HandshakeParser::fromServer)
266 clientTlsDetails = details;
267 clientSentHello = aHello;
274 return readAndGive(buf,
size, table);
276 return readAndParse(buf,
size, table);
285 if (rbufConsumePos < rbuf.length())
286 return giveBuffered(buf,
size);
289 const int result = readAndBuffer(table);
292 return giveBuffered(buf,
size);
303 const int result = readAndBuffer(table);
308 if (!parser_.parseHello(rbuf)) {
310 BIO_set_retry_read(table);
313 parsedHandshake =
true;
315 catch (
const std::exception &ex) {
316 debugs(83, 2,
"parsing error on FD " << fd_ <<
": " << ex.what());
317 parsedHandshake =
true;
321 return giveBuffered(buf,
size);
329 char *space = rbuf.rawAppendStart(SQUID_TCP_SO_RCVBUF);
330 const int result =
Ssl::Bio::read(space, SQUID_TCP_SO_RCVBUF, table);
334 rbuf.rawAppendFinish(space, result);
343 if (rbuf.length() <= rbufConsumePos)
346 const int unsent = rbuf.length() - rbufConsumePos;
347 const int bytes = (
size <= unsent ?
size : unsent);
348 memcpy(buf, rbuf.rawContent() + rbufConsumePos, bytes);
349 rbufConsumePos += bytes;
350 debugs(83, 7, bytes <<
"<=" <<
size <<
" bytes to OpenSSL");
359 debugs(83, 7,
"postpone writing " <<
size <<
" bytes to SSL FD " << fd_);
360 BIO_set_retry_write(table);
370 debugs(83, 7,
"to-server" <<
Raw(
"TLSPlaintext", buf,
size).hex());
373 Must(20 <= buf[0] && buf[0] <= 23);
376 assert(helloMsg.isEmpty());
380 Must(!clientSentHello.isEmpty());
383 helloMsg.append(clientSentHello);
384 debugs(83, 7,
"FD " << fd_ <<
": Using client-sent ClientHello for peek mode");
390 if (helloMsg.isEmpty())
391 helloMsg.append(buf,
size);
394 helloMsgSize = helloMsg.length();
398 BIO_set_retry_write(table);
403 if (!helloMsg.isEmpty()) {
404 debugs(83, 7,
"buffered write for FD " << fd_);
405 int ret =
Ssl::Bio::write(helloMsg.rawContent(), helloMsg.length(), table);
406 helloMsg.consume(ret);
407 if (!helloMsg.isEmpty()) {
410 BIO_set_retry_write(table);
426 if (!helloMsg.isEmpty()) {
427 int ret =
Ssl::Bio::write(helloMsg.rawContent(), helloMsg.length(), table);
428 helloMsg.consume(ret);
435 return parser_.resumingSession;
441 return parser_.details->tlsSupportedVersion &&
449 #if !HAVE_LIBCRYPTO_BIO_GET_INIT
500 debugs(83, 5, table <<
' ' << cmd <<
'(' << arg1 <<
", " << arg2 <<
')');
505 const int fd = *
static_cast<int*
>(arg2);
522 *
static_cast<int*
>(arg2) = bio->fd();
563 if (BIO *table = SSL_get_rbio(ssl)) {
565 bio->stateChanged(ssl, where, ret);
580 #if defined(TLSEXT_NAMETYPE_host_name)
581 if (!details->serverName.isEmpty()) {
582 SSL_set_tlsext_host_name(ssl, details->serverName.c_str());
586 if (!details->ciphers.empty()) {
588 for (
auto cipherId: details->ciphers) {
589 unsigned char cbytes[3];
590 cbytes[0] = (cipherId >> 8) & 0xFF;
591 cbytes[1] = cipherId & 0xFF;
596 strCiphers.
append(SSL_CIPHER_get_name(c));
600 SSL_set_cipher_list(ssl, strCiphers.
c_str());
603 #if defined(SSL_OP_NO_COMPRESSION)
604 if (!details->compressionSupported)
605 SSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
608 #if defined(SSL_OP_NO_TLSv1_3)
611 SSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
614 #if defined(TLSEXT_STATUSTYPE_ocsp)
615 if (details->tlsStatusRequest)
616 SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
619 #if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
620 if (!details->tlsAppLayerProtoNeg.isEmpty()) {
622 SSL_set_alpn_protos(ssl, (
const unsigned char*)details->tlsAppLayerProtoNeg.rawContent(), details->tlsAppLayerProtoNeg.length());
624 static const unsigned char supported_protos[] = {8,
'h',
't',
't',
'p',
'/',
'1',
'.',
'1'};
625 SSL_set_alpn_protos(ssl, supported_protos,
sizeof(supported_protos));
631 #endif // USE_OPENSSL
static void Link(SSL *ssl, BIO *bio)
Tells ssl connection to use BIO and monitor state via stateChanged()
static int squid_bio_create(BIO *h)
initializes BIO table after allocation
void setClientFeatures(Security::TlsDetails::Pointer const &details, SBuf const &hello)
Sets the random number to use in client SSL HELLO message.
int read(char *buf, int size, BIO *table) override
void configure(double horizonSeconds)
0=remember nothing; -1=forget nothing; new value triggers clear()
void applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode)
const SSL_CIPHER * SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr)
virtual void stateChanged(const SSL *ssl, int where, int ret)
ClientBio(const int anFd)
void stateChanged(const SSL *ssl, int where, int ret) override
int readAndGive(char *buf, const int size, BIO *table)
Read and give everything to OpenSSL.
void * BIO_get_data(BIO *table)
ServerBio(const int anFd)
int BIO_get_init(BIO *table)
static BIO * Create(const int fd, Security::Io::Type type)
void BIO_set_data(BIO *table, void *data)
void flush(BIO *table) override
virtual int read(char *buf, int size, BIO *table)
Reads data from socket.
bool Tls1p2orEarlier(const AnyP::ProtocolVersion &p)
whether the given TLS/SSL protocol is TLS v1.2 or earlier, including SSL
int default_read_method(int, char *, int)
int readAndBuffer(BIO *table)
virtual int write(const char *buf, int size, BIO *table)
Writes the given data to socket.
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
static int squid_bio_puts(BIO *h, const char *str)
implements puts() via write()
static int squid_bio_destroy(BIO *data)
cleans BIO table before deallocation
int default_write_method(int, const char *, int)
SBuf & append(const SBuf &S)
bool Tls1p3orLater(const AnyP::ProtocolVersion &p)
whether the given TLS/SSL protocol is TLS v1.3 or later
int ignoreErrno(int ierrno)
BIO source and sink node, handling socket I/O and monitoring SSL state.
static int squid_bio_read(BIO *h, char *buf, int size)
wrapper for Bio::read()
bool encryptedCertificates() const
const int fd_
the SSL socket we are reading and writing
static long squid_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2)
other BIO manipulations (those without dedicated callbacks in BIO table)
FadingCounter renegotiations
client requested renegotiations limit control
int read(char *buf, int size, BIO *table) override
static int squid_bio_write(BIO *h, const char *buf, int num)
wrapper for Bio::write()
int giveBuffered(char *buf, const int size)
void stateChanged(const SSL *ssl, int where, int ret) override
The ServerBio version of the Ssl::Bio::stateChanged method.
static void squid_ssl_info(const SSL *ssl, int where, int ret)
wrapper for Bio::stateChanged()
int readAndParse(char *buf, const int size, BIO *table)
int write(const char *buf, int size, BIO *table) override
void BIO_set_init(BIO *table, int init)
Network/connection security abstraction layer.
#define debugs(SECTION, LEVEL, CONTENT)
const char * bumpMode(int bm)
static BIO_METHOD SquidMethods
virtual void flush(BIO *)
int write(const char *buf, int size, BIO *table) override
The ClientBio version of the Ssl::Bio::write method.