]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/bio.cc
2 * Copyright (C) 1996-2016 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 "ssl/support.h"
14 /* support.cc says this is needed */
21 #include "ip/Address.h"
22 #include "parser/BinaryTokenizer.h"
25 #if HAVE_OPENSSL_SSL_H
26 #include <openssl/ssl.h>
30 extern int socket_read_method(int, char *, int);
31 extern int socket_write_method(int, const char *, int);
35 static int squid_bio_write(BIO
*h
, const char *buf
, int num
);
36 static int squid_bio_read(BIO
*h
, char *buf
, int size
);
37 static int squid_bio_puts(BIO
*h
, const char *str
);
38 //static int squid_bio_gets(BIO *h, char *str, int size);
39 static long squid_bio_ctrl(BIO
*h
, int cmd
, long arg1
, void *arg2
);
40 static int squid_bio_create(BIO
*h
);
41 static int squid_bio_destroy(BIO
*data
);
43 static void squid_ssl_info(const SSL
*ssl
, int where
, int ret
);
45 /// Initialization structure for the BIO table with
46 /// Squid-specific methods and BIO method wrappers.
47 static BIO_METHOD SquidMethods
= {
53 NULL
, // squid_bio_gets not supported
57 NULL
// squid_callback_ctrl not supported
61 Ssl::Bio::Create(const int fd
, Ssl::Bio::Type type
)
63 if (BIO
*bio
= BIO_new(&SquidMethods
)) {
64 BIO_int_ctrl(bio
, BIO_C_SET_FD
, type
, fd
);
71 Ssl::Bio::Link(SSL
*ssl
, BIO
*bio
)
73 SSL_set_bio(ssl
, bio
, bio
); // cannot fail
74 SSL_set_info_callback(ssl
, &squid_ssl_info
); // does not provide diagnostic
77 Ssl::Bio::Bio(const int anFd
): fd_(anFd
)
79 debugs(83, 7, "Bio constructed, this=" << this << " FD " << fd_
);
84 debugs(83, 7, "Bio destructing, this=" << this << " FD " << fd_
);
87 int Ssl::Bio::write(const char *buf
, int size
, BIO
*table
)
91 const int result
= socket_write_method(fd_
, buf
, size
);
93 const int result
= default_write_method(fd_
, buf
, size
);
95 const int xerrno
= errno
;
96 debugs(83, 5, "FD " << fd_
<< " wrote " << result
<< " <= " << size
);
98 BIO_clear_retry_flags(table
);
100 const bool ignoreError
= ignoreErrno(xerrno
) != 0;
101 debugs(83, 5, "error: " << xerrno
<< " ignored: " << ignoreError
);
103 BIO_set_retry_write(table
);
110 Ssl::Bio::read(char *buf
, int size
, BIO
*table
)
114 const int result
= socket_read_method(fd_
, buf
, size
);
116 const int result
= default_read_method(fd_
, buf
, size
);
118 const int xerrno
= errno
;
119 debugs(83, 5, "FD " << fd_
<< " read " << result
<< " <= " << size
);
121 BIO_clear_retry_flags(table
);
123 const bool ignoreError
= ignoreErrno(xerrno
) != 0;
124 debugs(83, 5, "error: " << xerrno
<< " ignored: " << ignoreError
);
126 BIO_set_retry_read(table
);
132 /// Called whenever the SSL connection state changes, an alert appears, or an
133 /// error occurs. See SSL_set_info_callback().
135 Ssl::Bio::stateChanged(const SSL
*ssl
, int where
, int ret
)
137 // Here we can use (where & STATE) to check the current state.
138 // Many STATE values are possible, including: SSL_CB_CONNECT_LOOP,
139 // SSL_CB_ACCEPT_LOOP, SSL_CB_HANDSHAKE_START, and SSL_CB_HANDSHAKE_DONE.
141 // if (where & SSL_CB_HANDSHAKE_START)
142 // debugs(83, 9, "Trying to establish the SSL connection");
143 // else if (where & SSL_CB_HANDSHAKE_DONE)
144 // debugs(83, 9, "SSL connection established");
146 debugs(83, 7, "FD " << fd_
<< " now: 0x" << std::hex
<< where
<< std::dec
<< ' ' <<
147 SSL_state_string(ssl
) << " (" << SSL_state_string_long(ssl
) << ")");
151 Ssl::ClientBio::isClientHello(int state
)
154 state
== SSL3_ST_SR_CLNT_HELLO_A
||
155 state
== SSL23_ST_SR_CLNT_HELLO_A
||
156 state
== SSL23_ST_SR_CLNT_HELLO_B
||
157 state
== SSL3_ST_SR_CLNT_HELLO_B
||
158 state
== SSL3_ST_SR_CLNT_HELLO_C
163 Ssl::ClientBio::stateChanged(const SSL
*ssl
, int where
, int ret
)
165 Ssl::Bio::stateChanged(ssl
, where
, ret
);
169 Ssl::ClientBio::write(const char *buf
, int size
, BIO
*table
)
172 BIO_set_retry_write(table
);
176 return Ssl::Bio::write(buf
, size
, table
);
180 Ssl::ClientBio::read(char *buf
, int size
, BIO
*table
)
183 debugs(83, 7, "Hold flag is set, retry latter. (Hold " << size
<< "bytes)");
184 BIO_set_retry_read(table
);
188 if (!rbuf
.isEmpty()) {
189 int bytes
= (size
<= (int)rbuf
.length() ? size
: rbuf
.length());
190 memcpy(buf
, rbuf
.rawContent(), bytes
);
194 return Ssl::Bio::read(buf
, size
, table
);
199 Ssl::ServerBio::ServerBio(const int anFd
):
208 parsedHandshake(false),
216 Ssl::ServerBio::stateChanged(const SSL
*ssl
, int where
, int ret
)
218 Ssl::Bio::stateChanged(ssl
, where
, ret
);
222 Ssl::ServerBio::setClientFeatures(Security::TlsDetails::Pointer
const &details
, SBuf
const &aHello
)
224 clientTlsDetails
= details
;
225 clientHelloMessage
= aHello
;
229 Ssl::ServerBio::read(char *buf
, int size
, BIO
*table
)
231 if (parsedHandshake
) // done parsing TLS Hello
232 return readAndGive(buf
, size
, table
);
234 return readAndParse(buf
, size
, table
);
237 /// Read and give everything to OpenSSL.
239 Ssl::ServerBio::readAndGive(char *buf
, const int size
, BIO
*table
)
241 // If we have unused buffered bytes, give those bytes to OpenSSL now,
242 // before reading more. TODO: Read if we have buffered less than size?
243 if (rbufConsumePos
< rbuf
.length())
244 return giveBuffered(buf
, size
);
247 const int result
= readAndBuffer(table
);
250 return giveBuffered(buf
, size
);
253 return Ssl::Bio::read(buf
, size
, table
);
256 /// Read and give everything to our parser.
257 /// When/if parsing is finished (successfully or not), start giving to OpenSSL.
259 Ssl::ServerBio::readAndParse(char *buf
, const int size
, BIO
*table
)
261 const int result
= readAndBuffer(table
);
266 if (!parser_
.parseHello(rbuf
)) {
267 // need more data to finish parsing
268 BIO_set_retry_read(table
);
271 parsedHandshake
= true; // done parsing (successfully)
273 catch (const std::exception
&ex
) {
274 debugs(83, 2, "parsing error on FD " << fd_
<< ": " << ex
.what());
275 parsedHandshake
= true; // done parsing (due to an error)
280 debugs(83, 7, "Hold flag is set, retry latter. (Hold " << size
<< "bytes)");
281 BIO_set_retry_read(table
);
285 return giveBuffered(buf
, size
);
288 /// Reads more data into the read buffer. Returns either the number of bytes
289 /// read or, on errors (including "try again" errors), a negative number.
291 Ssl::ServerBio::readAndBuffer(BIO
*table
)
293 char *space
= rbuf
.rawSpace(SQUID_TCP_SO_RCVBUF
);
294 const int result
= Ssl::Bio::read(space
, rbuf
.spaceSize(), table
);
298 rbuf
.forceSize(rbuf
.length() + result
);
302 /// give previously buffered bytes to OpenSSL
303 /// returns the number of bytes given
305 Ssl::ServerBio::giveBuffered(char *buf
, const int size
)
307 if (rbuf
.length() <= rbufConsumePos
)
308 return -1; // buffered nothing yet
310 const int unsent
= rbuf
.length() - rbufConsumePos
;
311 const int bytes
= (size
<= unsent
? size
: unsent
);
312 memcpy(buf
, rbuf
.rawContent() + rbufConsumePos
, bytes
);
313 rbufConsumePos
+= bytes
;
314 debugs(83, 7, bytes
<< "<=" << size
<< " bytes to OpenSSL");
318 // This function makes the required checks to examine if the client hello
319 // message is compatible with the features provided by OpenSSL toolkit.
320 // If the features are compatible and can be supported it tries to rewrite SSL
321 // structure members, to replace the hello message created by openSSL, with the
322 // web client SSL hello message.
323 // This is mostly possible in the cases where the web client uses openSSL
324 // library similar with this one used by squid.
326 adjustSSL(SSL
*ssl
, Security::TlsDetails::Pointer
const &details
, SBuf
&helloMessage
)
328 #if SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK
330 debugs(83, 5, "No SSLv3 data found!");
334 // If the client supports compression but our context does not support
335 // we can not adjust.
336 #if !defined(OPENSSL_NO_COMP)
337 const bool requireCompression
= (details
->compressionSupported
&& ssl
->ctx
->comp_methods
== nullptr);
339 const bool requireCompression
= details
->compressionSupported
;
341 if (requireCompression
) {
342 debugs(83, 5, "Client Hello Data supports compression, but we do not!");
346 #if !defined(SSL_TLSEXT_HB_ENABLED)
347 if (details
->doHeartBeats
) {
348 debugs(83, 5, "Client Hello Data supports HeartBeats but we do not support!");
353 if (details
->unsupportedExtensions
) {
354 debugs(83, 5, "Client Hello contains extensions that we do not support!");
358 SSL3_BUFFER
*wb
=&(ssl
->s3
->wbuf
);
359 if (wb
->len
< (size_t)helloMessage
.length()) {
360 debugs(83, 5, "Client Hello exceeds OpenSSL buffer: " << helloMessage
.length() << " >= " << wb
->len
);
364 /* Check whether all on-the-wire ciphers are supported by OpenSSL. */
366 const auto &wireCiphers
= details
->ciphers
;
367 Security::TlsDetails::Ciphers::size_type ciphersToFind
= wireCiphers
.size();
369 // RFC 5746: "TLS_EMPTY_RENEGOTIATION_INFO_SCSV is not a true cipher suite".
370 // It is commonly seen on the wire, including in from-OpenSSL traffic, but
371 // SSL_get_ciphers() does not return this _pseudo_ cipher suite in my tests.
372 // If OpenSSL supports scsvCipher, we count it (at most once) further below.
373 #if defined(TLSEXT_TYPE_renegotiate)
374 // the 0x00FFFF mask converts 3-byte OpenSSL cipher to our 2-byte cipher
375 const uint16_t scsvCipher
= SSL3_CK_SCSV
& 0x00FFFF;
377 const uint16_t scsvCipher
= 0;
380 STACK_OF(SSL_CIPHER
) *cipher_stack
= SSL_get_ciphers(ssl
);
381 const int supportedCipherCount
= sk_SSL_CIPHER_num(cipher_stack
);
382 for (int idx
= 0; idx
< supportedCipherCount
&& ciphersToFind
> 0; ++idx
) {
383 const SSL_CIPHER
*cipher
= sk_SSL_CIPHER_value(cipher_stack
, idx
);
384 const auto id
= SSL_CIPHER_get_id(cipher
) & 0x00FFFF;
385 if (wireCiphers
.find(id
) != wireCiphers
.end() && (!scsvCipher
|| id
!= scsvCipher
))
389 if (ciphersToFind
> 0 && scsvCipher
&& wireCiphers
.find(scsvCipher
) != wireCiphers
.end())
392 if (ciphersToFind
> 0) {
393 // TODO: Add slowlyReportUnsupportedCiphers() to slowly find and report each of them
394 debugs(83, 5, "Client Hello Data has " << ciphersToFind
<< " ciphers that we do not support!");
398 debugs(83, 5, "OpenSSL SSL struct will be adjusted to mimic client hello data!");
400 //Adjust ssl structure data.
401 // We need to fix the random in SSL struct:
402 if (details
->clientRandom
.length() == SSL3_RANDOM_SIZE
)
403 memcpy(ssl
->s3
->client_random
, details
->clientRandom
.c_str(), SSL3_RANDOM_SIZE
);
404 memcpy(wb
->buf
, helloMessage
.rawContent(), helloMessage
.length());
405 wb
->left
= helloMessage
.length();
407 size_t mainHelloSize
= helloMessage
.length() - 5;
408 const char *mainHello
= helloMessage
.rawContent() + 5;
409 assert((size_t)ssl
->init_buf
->max
> mainHelloSize
);
410 memcpy(ssl
->init_buf
->data
, mainHello
, mainHelloSize
);
411 debugs(83, 5, "Hello Data init and adjustd sizes :" << ssl
->init_num
<< " = "<< mainHelloSize
);
412 ssl
->init_num
= mainHelloSize
;
413 ssl
->s3
->wpend_ret
= mainHelloSize
;
414 ssl
->s3
->wpend_tot
= mainHelloSize
;
422 Ssl::ServerBio::write(const char *buf
, int size
, BIO
*table
)
426 debugs(83, 7, "postpone writing " << size
<< " bytes to SSL FD " << fd_
);
427 BIO_set_retry_write(table
);
431 if (!helloBuild
&& (bumpMode_
== Ssl::bumpPeek
|| bumpMode_
== Ssl::bumpStare
)) {
433 buf
[1] >= 3 //it is an SSL Version3 message
434 && buf
[0] == 0x16 // and it is a Handshake/Hello message
437 //Hello message is the first message we write to server
438 assert(helloMsg
.isEmpty());
440 auto ssl
= fd_table
[fd_
].ssl
.get();
442 if (bumpMode_
== Ssl::bumpPeek
) {
443 if (adjustSSL(ssl
, clientTlsDetails
, clientHelloMessage
))
446 helloMsg
.append(clientHelloMessage
);
447 debugs(83, 7, "SSL HELLO message for FD " << fd_
<< ": Random number is adjusted for peek mode");
448 } else { /*Ssl::bumpStare*/
450 if (adjustSSL(ssl
, clientTlsDetails
, clientHelloMessage
)) {
452 helloMsg
.append(clientHelloMessage
);
453 debugs(83, 7, "SSL HELLO message for FD " << fd_
<< ": Random number is adjusted for stare mode");
458 // If we do not build any hello message, copy the current
459 if (helloMsg
.isEmpty())
460 helloMsg
.append(buf
, size
);
463 helloMsgSize
= helloMsg
.length();
467 // Do not write yet.....
468 BIO_set_retry_write(table
);
473 if (!helloMsg
.isEmpty()) {
474 debugs(83, 7, "buffered write for FD " << fd_
);
475 int ret
= Ssl::Bio::write(helloMsg
.rawContent(), helloMsg
.length(), table
);
476 helloMsg
.consume(ret
);
477 if (!helloMsg
.isEmpty()) {
478 // We need to retry sendind data.
479 // Say to openSSL to retry sending hello message
480 BIO_set_retry_write(table
);
484 // Sending hello message complete. Do not send more data for now...
487 // spoof openSSL that we write what it ask us to write
490 return Ssl::Bio::write(buf
, size
, table
);
494 Ssl::ServerBio::flush(BIO
*table
)
496 if (!helloMsg
.isEmpty()) {
497 int ret
= Ssl::Bio::write(helloMsg
.rawContent(), helloMsg
.length(), table
);
498 helloMsg
.consume(ret
);
503 Ssl::ServerBio::resumingSession()
505 return parser_
.resumingSession
;
508 /// initializes BIO table after allocation
510 squid_bio_create(BIO
*bi
)
512 bi
->init
= 0; // set when we store Bio object and socket fd (BIO_C_SET_FD)
519 /// cleans BIO table before deallocation
521 squid_bio_destroy(BIO
*table
)
523 delete static_cast<Ssl::Bio
*>(table
->ptr
);
528 /// wrapper for Bio::write()
530 squid_bio_write(BIO
*table
, const char *buf
, int size
)
532 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
);
534 return bio
->write(buf
, size
, table
);
537 /// wrapper for Bio::read()
539 squid_bio_read(BIO
*table
, char *buf
, int size
)
541 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
);
543 return bio
->read(buf
, size
, table
);
546 /// implements puts() via write()
548 squid_bio_puts(BIO
*table
, const char *str
)
551 return squid_bio_write(table
, str
, strlen(str
));
554 /// other BIO manipulations (those without dedicated callbacks in BIO table)
556 squid_bio_ctrl(BIO
*table
, int cmd
, long arg1
, void *arg2
)
558 debugs(83, 5, table
<< ' ' << cmd
<< '(' << arg1
<< ", " << arg2
<< ')');
563 const int fd
= *static_cast<int*>(arg2
);
565 if (arg1
== Ssl::Bio::BIO_TO_SERVER
)
566 bio
= new Ssl::ServerBio(fd
);
568 bio
= new Ssl::ClientBio(fd
);
577 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
);
580 *static_cast<int*>(arg2
) = bio
->fd();
586 // Should implemented if the SSL_dup openSSL API function
587 // used anywhere in squid.
592 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
);
599 /* we may also need to implement these:
601 case BIO_C_FILE_SEEK:
602 case BIO_C_FILE_TELL:
604 case BIO_CTRL_GET_CLOSE:
605 case BIO_CTRL_SET_CLOSE:
606 case BIO_CTRL_PENDING:
607 case BIO_CTRL_WPENDING:
614 return 0; /* NOTREACHED */
617 /// wrapper for Bio::stateChanged()
619 squid_ssl_info(const SSL
*ssl
, int where
, int ret
)
621 if (BIO
*table
= SSL_get_rbio(ssl
)) {
622 if (Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
))
623 bio
->stateChanged(ssl
, where
, ret
);
628 applyTlsDetailsToSSL(SSL
*ssl
, Security::TlsDetails::Pointer
const &details
, Ssl::BumpMode bumpMode
)
630 // To increase the possibility for bumping after peek mode selection or
631 // splicing after stare mode selection it is good to set the
632 // SSL protocol version.
633 // The SSL_set_ssl_method is wrong here because it will restrict the
634 // permitted transport version to be identical to the version used in the
635 // ClientHello message.
636 // For example will prevent comunnicating with a tls1.0 server if the
637 // client sent and tlsv1.2 Hello message.
638 #if defined(TLSEXT_NAMETYPE_host_name)
639 if (!details
->serverName
.isEmpty()) {
640 SSL_set_tlsext_host_name(ssl
, details
->serverName
.c_str());
644 if (!details
->ciphers
.empty()) {
646 for (auto cipherId
: details
->ciphers
) {
647 unsigned char cbytes
[3];
648 cbytes
[0] = (cipherId
>> 8) & 0xFF;
649 cbytes
[1] = cipherId
& 0xFF;
651 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
652 const SSL_METHOD
*method
= TLS_method();
654 const SSL_METHOD
*method
= SSLv23_method();
656 const SSL_CIPHER
*c
= method
->get_cipher_by_char(cbytes
);
658 if (!strCiphers
.isEmpty())
659 strCiphers
.append(":");
660 strCiphers
.append(c
->name
);
663 if (!strCiphers
.isEmpty())
664 SSL_set_cipher_list(ssl
, strCiphers
.c_str());
667 #if defined(SSL_OP_NO_COMPRESSION) /* XXX: OpenSSL 0.9.8k lacks SSL_OP_NO_COMPRESSION */
668 if (!details
->compressionSupported
)
669 SSL_set_options(ssl
, SSL_OP_NO_COMPRESSION
);
672 #if defined(TLSEXT_STATUSTYPE_ocsp)
673 if (details
->tlsStatusRequest
)
674 SSL_set_tlsext_status_type(ssl
, TLSEXT_STATUSTYPE_ocsp
);
677 #if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
678 if (!details
->tlsAppLayerProtoNeg
.isEmpty()) {
679 if (bumpMode
== Ssl::bumpPeek
)
680 SSL_set_alpn_protos(ssl
, (const unsigned char*)details
->tlsAppLayerProtoNeg
.rawContent(), details
->tlsAppLayerProtoNeg
.length());
682 static const unsigned char supported_protos
[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
683 SSL_set_alpn_protos(ssl
, supported_protos
, sizeof(supported_protos
));
689 #endif // USE_OPENSSL