]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/bio.cc
074ad014d5e0031fdd25997979b517965e7a5b9f
2 * Copyright (C) 1996-2025 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 /* DEBUG: section 83 SSL accelerator support */
12 #include "base/IoManip.h"
13 #include "ssl/support.h"
15 /* support.cc says this is needed */
23 #include "ip/Address.h"
24 #include "parser/BinaryTokenizer.h"
28 extern int socket_read_method(int, char *, int);
29 extern int socket_write_method(int, const char *, int);
33 static int squid_bio_write(BIO
*h
, const char *buf
, int num
);
34 static int squid_bio_read(BIO
*h
, char *buf
, int size
);
35 static int squid_bio_puts(BIO
*h
, const char *str
);
36 //static int squid_bio_gets(BIO *h, char *str, int size);
37 static long squid_bio_ctrl(BIO
*h
, int cmd
, long arg1
, void *arg2
);
38 static int squid_bio_create(BIO
*h
);
39 static int squid_bio_destroy(BIO
*data
);
41 static void squid_ssl_info(const SSL
*ssl
, int where
, int ret
);
43 #if HAVE_LIBCRYPTO_BIO_METH_NEW
44 static BIO_METHOD
*SquidMethods
= nullptr;
46 /// Initialization structure for the BIO table with
47 /// Squid-specific methods and BIO method wrappers.
48 static BIO_METHOD SquidMethods
= {
54 nullptr, // squid_bio_gets not supported
58 NULL
// squid_callback_ctrl not supported
63 Ssl::Bio::Create(const int fd
, Security::Io::Type type
)
65 #if HAVE_LIBCRYPTO_BIO_METH_NEW
67 SquidMethods
= BIO_meth_new(BIO_TYPE_SOCKET
, "squid");
68 BIO_meth_set_write(SquidMethods
, squid_bio_write
);
69 BIO_meth_set_read(SquidMethods
, squid_bio_read
);
70 BIO_meth_set_puts(SquidMethods
, squid_bio_puts
);
71 BIO_meth_set_gets(SquidMethods
, nullptr);
72 BIO_meth_set_ctrl(SquidMethods
, squid_bio_ctrl
);
73 BIO_meth_set_create(SquidMethods
, squid_bio_create
);
74 BIO_meth_set_destroy(SquidMethods
, squid_bio_destroy
);
76 BIO_METHOD
*useMethod
= SquidMethods
;
78 BIO_METHOD
*useMethod
= &SquidMethods
;
81 if (BIO
*bio
= BIO_new(useMethod
)) {
82 BIO_int_ctrl(bio
, BIO_C_SET_FD
, type
, fd
);
89 Ssl::Bio::Link(SSL
*ssl
, BIO
*bio
)
91 SSL_set_bio(ssl
, bio
, bio
); // cannot fail
92 SSL_set_info_callback(ssl
, &squid_ssl_info
); // does not provide diagnostic
95 Ssl::Bio::Bio(const int anFd
): fd_(anFd
)
97 debugs(83, 7, "Bio constructed, this=" << this << " FD " << fd_
);
102 debugs(83, 7, "Bio destructing, this=" << this << " FD " << fd_
);
105 int Ssl::Bio::write(const char *buf
, int size
, BIO
*table
)
109 const int result
= socket_write_method(fd_
, buf
, size
);
111 const int result
= default_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
);
118 const bool ignoreError
= ignoreErrno(xerrno
) != 0;
119 debugs(83, 5, "error: " << xerrno
<< " ignored: " << ignoreError
);
121 BIO_set_retry_write(table
);
128 Ssl::Bio::read(char *buf
, int size
, BIO
*table
)
132 const int result
= socket_read_method(fd_
, buf
, size
);
134 const int result
= default_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
);
141 const bool ignoreError
= ignoreErrno(xerrno
) != 0;
142 debugs(83, 5, "error: " << xerrno
<< " ignored: " << ignoreError
);
144 BIO_set_retry_read(table
);
150 /// Called whenever the SSL connection state changes, an alert appears, or an
151 /// error occurs. See SSL_set_info_callback().
153 Ssl::Bio::stateChanged(const SSL
*ssl
, int where
, int)
155 // Here we can use (where & STATE) to check the current state.
156 // Many STATE values are possible, including: SSL_CB_CONNECT_LOOP,
157 // SSL_CB_ACCEPT_LOOP, SSL_CB_HANDSHAKE_START, and SSL_CB_HANDSHAKE_DONE.
159 // if (where & SSL_CB_HANDSHAKE_START)
160 // debugs(83, 9, "Trying to establish the SSL connection");
161 // else if (where & SSL_CB_HANDSHAKE_DONE)
162 // debugs(83, 9, "SSL connection established");
164 debugs(83, 7, "FD " << fd_
<< " now: 0x" << asHex(where
) << ' ' <<
165 SSL_state_string(ssl
) << " (" << SSL_state_string_long(ssl
) << ")");
168 Ssl::ClientBio::ClientBio(const int anFd
):
174 renegotiations
.configure(10*1000);
178 Ssl::ClientBio::stateChanged(const SSL
*ssl
, int where
, int ret
)
180 Ssl::Bio::stateChanged(ssl
, where
, ret
);
181 // detect client-initiated renegotiations DoS (CVE-2011-1473)
182 if (where
& SSL_CB_HANDSHAKE_START
) {
183 const int reneg
= renegotiations
.count(1);
186 return; // already decided and informed the admin
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).");
199 Ssl::ClientBio::write(const char *buf
, int size
, BIO
*table
)
202 debugs(83, 3, "BIO on FD " << fd_
<< " is aborted");
203 BIO_clear_retry_flags(table
);
208 BIO_set_retry_write(table
);
212 return Ssl::Bio::write(buf
, size
, table
);
216 Ssl::ClientBio::read(char *buf
, int size
, BIO
*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
);
236 return Ssl::Bio::read(buf
, size
, table
);
241 Ssl::ServerBio::ServerBio(const int anFd
):
249 parsedHandshake(false),
253 parser_(Security::HandshakeParser::fromServer
)
258 Ssl::ServerBio::stateChanged(const SSL
*ssl
, int where
, int ret
)
260 Ssl::Bio::stateChanged(ssl
, where
, ret
);
264 Ssl::ServerBio::setClientFeatures(Security::TlsDetails::Pointer
const &details
, SBuf
const &aHello
)
266 clientTlsDetails
= details
;
267 clientSentHello
= aHello
;
271 Ssl::ServerBio::read(char *buf
, int size
, BIO
*table
)
273 if (parsedHandshake
) // done parsing TLS Hello
274 return readAndGive(buf
, size
, table
);
276 return readAndParse(buf
, size
, table
);
279 /// Read and give everything to OpenSSL.
281 Ssl::ServerBio::readAndGive(char *buf
, const int size
, BIO
*table
)
283 // If we have unused buffered bytes, give those bytes to OpenSSL now,
284 // before reading more. TODO: Read if we have buffered less than size?
285 if (rbufConsumePos
< rbuf
.length())
286 return giveBuffered(buf
, size
);
289 const int result
= readAndBuffer(table
);
292 return giveBuffered(buf
, size
);
295 return Ssl::Bio::read(buf
, size
, table
);
298 /// Read and give everything to our parser.
299 /// When/if parsing is finished (successfully or not), start giving to OpenSSL.
301 Ssl::ServerBio::readAndParse(char *buf
, const int size
, BIO
*table
)
303 const int result
= readAndBuffer(table
);
308 if (!parser_
.parseHello(rbuf
)) {
309 // need more data to finish parsing
310 BIO_set_retry_read(table
);
313 parsedHandshake
= true; // done parsing (successfully)
315 catch (const std::exception
&ex
) {
316 debugs(83, 2, "parsing error on FD " << fd_
<< ": " << ex
.what());
317 parsedHandshake
= true; // done parsing (due to an error)
321 return giveBuffered(buf
, size
);
324 /// Reads more data into the read buffer. Returns either the number of bytes
325 /// read or, on errors (including "try again" errors), a negative number.
327 Ssl::ServerBio::readAndBuffer(BIO
*table
)
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
);
338 /// give previously buffered bytes to OpenSSL
339 /// returns the number of bytes given
341 Ssl::ServerBio::giveBuffered(char *buf
, const int size
)
343 if (rbuf
.length() <= rbufConsumePos
)
344 return -1; // buffered nothing yet
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");
355 Ssl::ServerBio::write(const char *buf
, int size
, BIO
*table
)
359 debugs(83, 7, "postpone writing " << size
<< " bytes to SSL FD " << fd_
);
360 BIO_set_retry_write(table
);
364 if (!helloBuild
&& (bumpMode_
== Ssl::bumpPeek
|| bumpMode_
== Ssl::bumpStare
)) {
365 // We have not seen any bytes, so the buffer must start with an
366 // OpenSSL-generated TLSPlaintext record containing, for example, a
367 // ClientHello or an alert message. We check these assumptions before we
368 // substitute that record/message with clientSentHello.
369 // TODO: Move these checks to where we actually rely on them.
370 debugs(83, 7, "to-server" << Raw("TLSPlaintext", buf
, size
).hex());
371 Must(size
>= 2); // enough for version and content_type checks below
372 Must(buf
[1] >= 3); // record's version.major; determines buf[0] meaning
373 Must(20 <= buf
[0] && buf
[0] <= 23); // valid TLSPlaintext.content_type
375 //Hello message is the first message we write to server
376 assert(helloMsg
.isEmpty());
378 if (bumpMode_
== Ssl::bumpPeek
) {
379 // we should not be here if we failed to parse the client-sent ClientHello
380 Must(!clientSentHello
.isEmpty());
382 // Replace OpenSSL-generated ClientHello with client-sent one.
383 helloMsg
.append(clientSentHello
);
384 debugs(83, 7, "FD " << fd_
<< ": Using client-sent ClientHello for peek mode");
385 } else { /*Ssl::bumpStare*/
389 // if we did not use the client-sent ClientHello, then use the OpenSSL-generated one
390 if (helloMsg
.isEmpty())
391 helloMsg
.append(buf
, size
);
394 helloMsgSize
= helloMsg
.length();
397 // Do not write yet.....
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()) {
408 // We need to retry sendind data.
409 // Say to openSSL to retry sending hello message
410 BIO_set_retry_write(table
);
414 // Sending hello message complete. Do not send more data for now...
417 // spoof openSSL that we write what it ask us to write
420 return Ssl::Bio::write(buf
, size
, table
);
424 Ssl::ServerBio::flush(BIO
*table
)
426 if (!helloMsg
.isEmpty()) {
427 int ret
= Ssl::Bio::write(helloMsg
.rawContent(), helloMsg
.length(), table
);
428 helloMsg
.consume(ret
);
433 Ssl::ServerBio::resumingSession()
435 return parser_
.resumingSession
;
439 Ssl::ServerBio::encryptedCertificates() const
441 return parser_
.details
->tlsSupportedVersion
&&
442 Security::Tls1p3orLater(parser_
.details
->tlsSupportedVersion
);
445 /// initializes BIO table after allocation
447 squid_bio_create(BIO
*bi
)
449 #if !HAVE_LIBCRYPTO_BIO_GET_INIT
450 bi
->init
= 0; // set when we store Bio object and socket fd (BIO_C_SET_FD)
454 // No need to set more, openSSL initialize BIO memory to zero.
457 BIO_set_data(bi
, nullptr);
461 /// cleans BIO table before deallocation
463 squid_bio_destroy(BIO
*table
)
465 delete static_cast<Ssl::Bio
*>(BIO_get_data(table
));
466 BIO_set_data(table
, nullptr);
470 /// wrapper for Bio::write()
472 squid_bio_write(BIO
*table
, const char *buf
, int size
)
474 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(BIO_get_data(table
));
476 return bio
->write(buf
, size
, table
);
479 /// wrapper for Bio::read()
481 squid_bio_read(BIO
*table
, char *buf
, int size
)
483 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(BIO_get_data(table
));
485 return bio
->read(buf
, size
, table
);
488 /// implements puts() via write()
490 squid_bio_puts(BIO
*table
, const char *str
)
493 return squid_bio_write(table
, str
, strlen(str
));
496 /// other BIO manipulations (those without dedicated callbacks in BIO table)
498 squid_bio_ctrl(BIO
*table
, int cmd
, long arg1
, void *arg2
)
500 debugs(83, 5, table
<< ' ' << cmd
<< '(' << arg1
<< ", " << arg2
<< ')');
505 const int fd
= *static_cast<int*>(arg2
);
507 if (arg1
== Security::Io::BIO_TO_SERVER
)
508 bio
= new Ssl::ServerBio(fd
);
510 bio
= new Ssl::ClientBio(fd
);
511 assert(!BIO_get_data(table
));
512 BIO_set_data(table
, bio
);
513 BIO_set_init(table
, 1);
518 if (BIO_get_init(table
)) {
519 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(BIO_get_data(table
));
522 *static_cast<int*>(arg2
) = bio
->fd();
528 // Should implemented if the SSL_dup openSSL API function
529 // used anywhere in squid.
533 if (BIO_get_init(table
)) {
534 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(BIO_get_data(table
));
541 /* we may also need to implement these:
543 case BIO_C_FILE_SEEK:
544 case BIO_C_FILE_TELL:
546 case BIO_CTRL_GET_CLOSE:
547 case BIO_CTRL_SET_CLOSE:
548 case BIO_CTRL_PENDING:
549 case BIO_CTRL_WPENDING:
556 return 0; /* NOTREACHED */
559 /// wrapper for Bio::stateChanged()
561 squid_ssl_info(const SSL
*ssl
, int where
, int ret
)
563 if (BIO
*table
= SSL_get_rbio(ssl
)) {
564 if (Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(BIO_get_data(table
)))
565 bio
->stateChanged(ssl
, where
, ret
);
570 applyTlsDetailsToSSL(SSL
*ssl
, Security::TlsDetails::Pointer
const &details
, Ssl::BumpMode bumpMode
)
572 // To increase the possibility for bumping after peek mode selection or
573 // splicing after stare mode selection it is good to set the
574 // SSL protocol version.
575 // The SSL_set_ssl_method is wrong here because it will restrict the
576 // permitted transport version to be identical to the version used in the
577 // ClientHello message.
578 // For example will prevent comunnicating with a tls1.0 server if the
579 // client sent and tlsv1.2 Hello message.
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;
593 if (const auto c
= SSL_CIPHER_find(ssl
, cbytes
)) {
594 if (!strCiphers
.isEmpty())
595 strCiphers
.append(":");
596 strCiphers
.append(SSL_CIPHER_get_name(c
));
599 if (!strCiphers
.isEmpty())
600 SSL_set_cipher_list(ssl
, strCiphers
.c_str());
603 #if defined(SSL_OP_NO_COMPRESSION) /* XXX: OpenSSL 0.9.8k lacks 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)
609 // avoid "inappropriate fallback" OpenSSL error messages
610 if (details
->tlsSupportedVersion
&& Security::Tls1p2orEarlier(details
->tlsSupportedVersion
))
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()) {
621 if (bumpMode
== Ssl::bumpPeek
)
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