]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/bio.cc
074ad014d5e0031fdd25997979b517965e7a5b9f
[thirdparty/squid.git] / src / ssl / bio.cc
1 /*
2 * Copyright (C) 1996-2025 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 /* DEBUG: section 83 SSL accelerator support */
10
11 #include "squid.h"
12 #include "base/IoManip.h"
13 #include "ssl/support.h"
14
15 /* support.cc says this is needed */
16 #if USE_OPENSSL
17
18 #include "base/Raw.h"
19 #include "comm.h"
20 #include "fd.h"
21 #include "fde.h"
22 #include "globals.h"
23 #include "ip/Address.h"
24 #include "parser/BinaryTokenizer.h"
25 #include "ssl/bio.h"
26
27 #if _SQUID_WINDOWS_
28 extern int socket_read_method(int, char *, int);
29 extern int socket_write_method(int, const char *, int);
30 #endif
31
32 /* BIO callbacks */
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);
40 /* SSL callbacks */
41 static void squid_ssl_info(const SSL *ssl, int where, int ret);
42
43 #if HAVE_LIBCRYPTO_BIO_METH_NEW
44 static BIO_METHOD *SquidMethods = nullptr;
45 #else
46 /// Initialization structure for the BIO table with
47 /// Squid-specific methods and BIO method wrappers.
48 static BIO_METHOD SquidMethods = {
49 BIO_TYPE_SOCKET,
50 "squid",
51 squid_bio_write,
52 squid_bio_read,
53 squid_bio_puts,
54 nullptr, // squid_bio_gets not supported
55 squid_bio_ctrl,
56 squid_bio_create,
57 squid_bio_destroy,
58 NULL // squid_callback_ctrl not supported
59 };
60 #endif
61
62 BIO *
63 Ssl::Bio::Create(const int fd, Security::Io::Type type)
64 {
65 #if HAVE_LIBCRYPTO_BIO_METH_NEW
66 if (!SquidMethods) {
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);
75 }
76 BIO_METHOD *useMethod = SquidMethods;
77 #else
78 BIO_METHOD *useMethod = &SquidMethods;
79 #endif
80
81 if (BIO *bio = BIO_new(useMethod)) {
82 BIO_int_ctrl(bio, BIO_C_SET_FD, type, fd);
83 return bio;
84 }
85 return nullptr;
86 }
87
88 void
89 Ssl::Bio::Link(SSL *ssl, BIO *bio)
90 {
91 SSL_set_bio(ssl, bio, bio); // cannot fail
92 SSL_set_info_callback(ssl, &squid_ssl_info); // does not provide diagnostic
93 }
94
95 Ssl::Bio::Bio(const int anFd): fd_(anFd)
96 {
97 debugs(83, 7, "Bio constructed, this=" << this << " FD " << fd_);
98 }
99
100 Ssl::Bio::~Bio()
101 {
102 debugs(83, 7, "Bio destructing, this=" << this << " FD " << fd_);
103 }
104
105 int Ssl::Bio::write(const char *buf, int size, BIO *table)
106 {
107 errno = 0;
108 #if _SQUID_WINDOWS_
109 const int result = socket_write_method(fd_, buf, size);
110 #else
111 const int result = default_write_method(fd_, buf, size);
112 #endif
113 const int xerrno = errno;
114 debugs(83, 5, "FD " << fd_ << " wrote " << result << " <= " << size);
115
116 BIO_clear_retry_flags(table);
117 if (result < 0) {
118 const bool ignoreError = ignoreErrno(xerrno) != 0;
119 debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError);
120 if (ignoreError)
121 BIO_set_retry_write(table);
122 }
123
124 return result;
125 }
126
127 int
128 Ssl::Bio::read(char *buf, int size, BIO *table)
129 {
130 errno = 0;
131 #if _SQUID_WINDOWS_
132 const int result = socket_read_method(fd_, buf, size);
133 #else
134 const int result = default_read_method(fd_, buf, size);
135 #endif
136 const int xerrno = errno;
137 debugs(83, 5, "FD " << fd_ << " read " << result << " <= " << size);
138
139 BIO_clear_retry_flags(table);
140 if (result < 0) {
141 const bool ignoreError = ignoreErrno(xerrno) != 0;
142 debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError);
143 if (ignoreError)
144 BIO_set_retry_read(table);
145 }
146
147 return result;
148 }
149
150 /// Called whenever the SSL connection state changes, an alert appears, or an
151 /// error occurs. See SSL_set_info_callback().
152 void
153 Ssl::Bio::stateChanged(const SSL *ssl, int where, int)
154 {
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.
158 // For example:
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");
163
164 debugs(83, 7, "FD " << fd_ << " now: 0x" << asHex(where) << ' ' <<
165 SSL_state_string(ssl) << " (" << SSL_state_string_long(ssl) << ")");
166 }
167
168 Ssl::ClientBio::ClientBio(const int anFd):
169 Bio(anFd),
170 holdRead_(false),
171 holdWrite_(false),
172 abortReason(nullptr)
173 {
174 renegotiations.configure(10*1000);
175 }
176
177 void
178 Ssl::ClientBio::stateChanged(const SSL *ssl, int where, int ret)
179 {
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);
184
185 if (abortReason)
186 return; // already decided and informed the admin
187
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).");
194 }
195 }
196 }
197
198 int
199 Ssl::ClientBio::write(const char *buf, int size, BIO *table)
200 {
201 if (abortReason) {
202 debugs(83, 3, "BIO on FD " << fd_ << " is aborted");
203 BIO_clear_retry_flags(table);
204 return -1;
205 }
206
207 if (holdWrite_) {
208 BIO_set_retry_write(table);
209 return 0;
210 }
211
212 return Ssl::Bio::write(buf, size, table);
213 }
214
215 int
216 Ssl::ClientBio::read(char *buf, int size, BIO *table)
217 {
218 if (abortReason) {
219 debugs(83, 3, "BIO on FD " << fd_ << " is aborted");
220 BIO_clear_retry_flags(table);
221 return -1;
222 }
223
224 if (holdRead_) {
225 debugs(83, 7, "Hold flag is set, retry latter. (Hold " << size << "bytes)");
226 BIO_set_retry_read(table);
227 return -1;
228 }
229
230 if (!rbuf.isEmpty()) {
231 int bytes = (size <= (int)rbuf.length() ? size : rbuf.length());
232 memcpy(buf, rbuf.rawContent(), bytes);
233 rbuf.consume(bytes);
234 return bytes;
235 } else
236 return Ssl::Bio::read(buf, size, table);
237
238 return -1;
239 }
240
241 Ssl::ServerBio::ServerBio(const int anFd):
242 Bio(anFd),
243 helloMsgSize(0),
244 helloBuild(false),
245 allowSplice(false),
246 allowBump(false),
247 holdWrite_(false),
248 record_(false),
249 parsedHandshake(false),
250 parseError(false),
251 bumpMode_(bumpNone),
252 rbufConsumePos(0),
253 parser_(Security::HandshakeParser::fromServer)
254 {
255 }
256
257 void
258 Ssl::ServerBio::stateChanged(const SSL *ssl, int where, int ret)
259 {
260 Ssl::Bio::stateChanged(ssl, where, ret);
261 }
262
263 void
264 Ssl::ServerBio::setClientFeatures(Security::TlsDetails::Pointer const &details, SBuf const &aHello)
265 {
266 clientTlsDetails = details;
267 clientSentHello = aHello;
268 };
269
270 int
271 Ssl::ServerBio::read(char *buf, int size, BIO *table)
272 {
273 if (parsedHandshake) // done parsing TLS Hello
274 return readAndGive(buf, size, table);
275 else
276 return readAndParse(buf, size, table);
277 }
278
279 /// Read and give everything to OpenSSL.
280 int
281 Ssl::ServerBio::readAndGive(char *buf, const int size, BIO *table)
282 {
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);
287
288 if (record_) {
289 const int result = readAndBuffer(table);
290 if (result <= 0)
291 return result;
292 return giveBuffered(buf, size);
293 }
294
295 return Ssl::Bio::read(buf, size, table);
296 }
297
298 /// Read and give everything to our parser.
299 /// When/if parsing is finished (successfully or not), start giving to OpenSSL.
300 int
301 Ssl::ServerBio::readAndParse(char *buf, const int size, BIO *table)
302 {
303 const int result = readAndBuffer(table);
304 if (result <= 0)
305 return result;
306
307 try {
308 if (!parser_.parseHello(rbuf)) {
309 // need more data to finish parsing
310 BIO_set_retry_read(table);
311 return -1;
312 }
313 parsedHandshake = true; // done parsing (successfully)
314 }
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)
318 parseError = true;
319 }
320
321 return giveBuffered(buf, size);
322 }
323
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.
326 int
327 Ssl::ServerBio::readAndBuffer(BIO *table)
328 {
329 char *space = rbuf.rawAppendStart(SQUID_TCP_SO_RCVBUF);
330 const int result = Ssl::Bio::read(space, SQUID_TCP_SO_RCVBUF, table);
331 if (result <= 0)
332 return result;
333
334 rbuf.rawAppendFinish(space, result);
335 return result;
336 }
337
338 /// give previously buffered bytes to OpenSSL
339 /// returns the number of bytes given
340 int
341 Ssl::ServerBio::giveBuffered(char *buf, const int size)
342 {
343 if (rbuf.length() <= rbufConsumePos)
344 return -1; // buffered nothing yet
345
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");
351 return bytes;
352 }
353
354 int
355 Ssl::ServerBio::write(const char *buf, int size, BIO *table)
356 {
357
358 if (holdWrite_) {
359 debugs(83, 7, "postpone writing " << size << " bytes to SSL FD " << fd_);
360 BIO_set_retry_write(table);
361 return -1;
362 }
363
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
374
375 //Hello message is the first message we write to server
376 assert(helloMsg.isEmpty());
377
378 if (bumpMode_ == Ssl::bumpPeek) {
379 // we should not be here if we failed to parse the client-sent ClientHello
380 Must(!clientSentHello.isEmpty());
381 allowSplice = true;
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*/
386 allowBump = true;
387 }
388
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);
392
393 helloBuild = true;
394 helloMsgSize = helloMsg.length();
395
396 if (allowSplice) {
397 // Do not write yet.....
398 BIO_set_retry_write(table);
399 return -1;
400 }
401 }
402
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);
411 return -1;
412 }
413
414 // Sending hello message complete. Do not send more data for now...
415 holdWrite_ = true;
416
417 // spoof openSSL that we write what it ask us to write
418 return size;
419 } else
420 return Ssl::Bio::write(buf, size, table);
421 }
422
423 void
424 Ssl::ServerBio::flush(BIO *table)
425 {
426 if (!helloMsg.isEmpty()) {
427 int ret = Ssl::Bio::write(helloMsg.rawContent(), helloMsg.length(), table);
428 helloMsg.consume(ret);
429 }
430 }
431
432 bool
433 Ssl::ServerBio::resumingSession()
434 {
435 return parser_.resumingSession;
436 }
437
438 bool
439 Ssl::ServerBio::encryptedCertificates() const
440 {
441 return parser_.details->tlsSupportedVersion &&
442 Security::Tls1p3orLater(parser_.details->tlsSupportedVersion);
443 }
444
445 /// initializes BIO table after allocation
446 static int
447 squid_bio_create(BIO *bi)
448 {
449 #if !HAVE_LIBCRYPTO_BIO_GET_INIT
450 bi->init = 0; // set when we store Bio object and socket fd (BIO_C_SET_FD)
451 bi->num = 0;
452 bi->flags = 0;
453 #else
454 // No need to set more, openSSL initialize BIO memory to zero.
455 #endif
456
457 BIO_set_data(bi, nullptr);
458 return 1;
459 }
460
461 /// cleans BIO table before deallocation
462 static int
463 squid_bio_destroy(BIO *table)
464 {
465 delete static_cast<Ssl::Bio*>(BIO_get_data(table));
466 BIO_set_data(table, nullptr);
467 return 1;
468 }
469
470 /// wrapper for Bio::write()
471 static int
472 squid_bio_write(BIO *table, const char *buf, int size)
473 {
474 Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table));
475 assert(bio);
476 return bio->write(buf, size, table);
477 }
478
479 /// wrapper for Bio::read()
480 static int
481 squid_bio_read(BIO *table, char *buf, int size)
482 {
483 Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table));
484 assert(bio);
485 return bio->read(buf, size, table);
486 }
487
488 /// implements puts() via write()
489 static int
490 squid_bio_puts(BIO *table, const char *str)
491 {
492 assert(str);
493 return squid_bio_write(table, str, strlen(str));
494 }
495
496 /// other BIO manipulations (those without dedicated callbacks in BIO table)
497 static long
498 squid_bio_ctrl(BIO *table, int cmd, long arg1, void *arg2)
499 {
500 debugs(83, 5, table << ' ' << cmd << '(' << arg1 << ", " << arg2 << ')');
501
502 switch (cmd) {
503 case BIO_C_SET_FD: {
504 assert(arg2);
505 const int fd = *static_cast<int*>(arg2);
506 Ssl::Bio *bio;
507 if (arg1 == Security::Io::BIO_TO_SERVER)
508 bio = new Ssl::ServerBio(fd);
509 else
510 bio = new Ssl::ClientBio(fd);
511 assert(!BIO_get_data(table));
512 BIO_set_data(table, bio);
513 BIO_set_init(table, 1);
514 return 0;
515 }
516
517 case BIO_C_GET_FD:
518 if (BIO_get_init(table)) {
519 Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table));
520 assert(bio);
521 if (arg2)
522 *static_cast<int*>(arg2) = bio->fd();
523 return bio->fd();
524 }
525 return -1;
526
527 case BIO_CTRL_DUP:
528 // Should implemented if the SSL_dup openSSL API function
529 // used anywhere in squid.
530 return 0;
531
532 case BIO_CTRL_FLUSH:
533 if (BIO_get_init(table)) {
534 Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table));
535 assert(bio);
536 bio->flush(table);
537 return 1;
538 }
539 return 0;
540
541 /* we may also need to implement these:
542 case BIO_CTRL_RESET:
543 case BIO_C_FILE_SEEK:
544 case BIO_C_FILE_TELL:
545 case BIO_CTRL_INFO:
546 case BIO_CTRL_GET_CLOSE:
547 case BIO_CTRL_SET_CLOSE:
548 case BIO_CTRL_PENDING:
549 case BIO_CTRL_WPENDING:
550 */
551 default:
552 return 0;
553
554 }
555
556 return 0; /* NOTREACHED */
557 }
558
559 /// wrapper for Bio::stateChanged()
560 static void
561 squid_ssl_info(const SSL *ssl, int where, int ret)
562 {
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);
566 }
567 }
568
569 void
570 applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode)
571 {
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());
583 }
584 #endif
585
586 if (!details->ciphers.empty()) {
587 SBuf strCiphers;
588 for (auto cipherId: details->ciphers) {
589 unsigned char cbytes[3];
590 cbytes[0] = (cipherId >> 8) & 0xFF;
591 cbytes[1] = cipherId & 0xFF;
592 cbytes[2] = 0;
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));
597 }
598 }
599 if (!strCiphers.isEmpty())
600 SSL_set_cipher_list(ssl, strCiphers.c_str());
601 }
602
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);
606 #endif
607
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);
612 #endif
613
614 #if defined(TLSEXT_STATUSTYPE_ocsp)
615 if (details->tlsStatusRequest)
616 SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
617 #endif
618
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());
623 else {
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));
626 }
627 }
628 #endif
629 }
630
631 #endif // USE_OPENSSL
632