]>
Commit | Line | Data |
---|---|---|
b3a8ae1b | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 The Squid Software Foundation and contributors |
b3a8ae1b | 3 | * |
bbc27441 AJ |
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. | |
b3a8ae1b AR |
7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 83 SSL accelerator support */ |
10 | ||
b3a8ae1b | 11 | #include "squid.h" |
d620ae0e | 12 | #include "ssl/support.h" |
b3a8ae1b AR |
13 | |
14 | /* support.cc says this is needed */ | |
31855516 | 15 | #if USE_OPENSSL |
b3a8ae1b | 16 | |
675b8408 | 17 | #include "base/Raw.h" |
b3a8ae1b | 18 | #include "comm.h" |
2e198b84 | 19 | #include "fd.h" |
d620ae0e CT |
20 | #include "fde.h" |
21 | #include "globals.h" | |
40f1e76d | 22 | #include "ip/Address.h" |
7c8ee688 | 23 | #include "parser/BinaryTokenizer.h" |
b3a8ae1b | 24 | #include "ssl/bio.h" |
8693472e | 25 | |
b3a8ae1b AR |
26 | #if _SQUID_WINDOWS_ |
27 | extern int socket_read_method(int, char *, int); | |
28 | extern int socket_write_method(int, const char *, int); | |
29 | #endif | |
30 | ||
31 | /* BIO callbacks */ | |
32 | static int squid_bio_write(BIO *h, const char *buf, int num); | |
33 | static int squid_bio_read(BIO *h, char *buf, int size); | |
34 | static int squid_bio_puts(BIO *h, const char *str); | |
35 | //static int squid_bio_gets(BIO *h, char *str, int size); | |
36 | static long squid_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); | |
37 | static int squid_bio_create(BIO *h); | |
38 | static int squid_bio_destroy(BIO *data); | |
39 | /* SSL callbacks */ | |
40 | static void squid_ssl_info(const SSL *ssl, int where, int ret); | |
41 | ||
17e98f24 AJ |
42 | #if HAVE_LIBCRYPTO_BIO_METH_NEW |
43 | static BIO_METHOD *SquidMethods = nullptr; | |
44 | #else | |
b3a8ae1b AR |
45 | /// Initialization structure for the BIO table with |
46 | /// Squid-specific methods and BIO method wrappers. | |
47 | static BIO_METHOD SquidMethods = { | |
48 | BIO_TYPE_SOCKET, | |
49 | "squid", | |
50 | squid_bio_write, | |
51 | squid_bio_read, | |
52 | squid_bio_puts, | |
53 | NULL, // squid_bio_gets not supported | |
54 | squid_bio_ctrl, | |
55 | squid_bio_create, | |
56 | squid_bio_destroy, | |
57 | NULL // squid_callback_ctrl not supported | |
58 | }; | |
093deea9 | 59 | #endif |
b3a8ae1b AR |
60 | |
61 | BIO * | |
86f77270 | 62 | Ssl::Bio::Create(const int fd, Security::Io::Type type) |
b3a8ae1b | 63 | { |
17e98f24 | 64 | #if HAVE_LIBCRYPTO_BIO_METH_NEW |
093deea9 CT |
65 | if (!SquidMethods) { |
66 | SquidMethods = BIO_meth_new(BIO_TYPE_SOCKET, "squid"); | |
67 | BIO_meth_set_write(SquidMethods, squid_bio_write); | |
68 | BIO_meth_set_read(SquidMethods, squid_bio_read); | |
69 | BIO_meth_set_puts(SquidMethods, squid_bio_puts); | |
aee3523a | 70 | BIO_meth_set_gets(SquidMethods, nullptr); |
093deea9 CT |
71 | BIO_meth_set_ctrl(SquidMethods, squid_bio_ctrl); |
72 | BIO_meth_set_create(SquidMethods, squid_bio_create); | |
73 | BIO_meth_set_destroy(SquidMethods, squid_bio_destroy); | |
74 | } | |
24b30fdc | 75 | BIO_METHOD *useMethod = SquidMethods; |
17e98f24 AJ |
76 | #else |
77 | BIO_METHOD *useMethod = &SquidMethods; | |
093deea9 | 78 | #endif |
ac756c8c | 79 | |
2a268a06 CT |
80 | if (BIO *bio = BIO_new(useMethod)) { |
81 | BIO_int_ctrl(bio, BIO_C_SET_FD, type, fd); | |
82 | return bio; | |
83 | } | |
aee3523a | 84 | return nullptr; |
b3a8ae1b AR |
85 | } |
86 | ||
87 | void | |
88 | Ssl::Bio::Link(SSL *ssl, BIO *bio) | |
89 | { | |
90 | SSL_set_bio(ssl, bio, bio); // cannot fail | |
91 | SSL_set_info_callback(ssl, &squid_ssl_info); // does not provide diagnostic | |
92 | } | |
93 | ||
b3a8ae1b AR |
94 | Ssl::Bio::Bio(const int anFd): fd_(anFd) |
95 | { | |
96 | debugs(83, 7, "Bio constructed, this=" << this << " FD " << fd_); | |
97 | } | |
98 | ||
99 | Ssl::Bio::~Bio() | |
100 | { | |
101 | debugs(83, 7, "Bio destructing, this=" << this << " FD " << fd_); | |
b3a8ae1b AR |
102 | } |
103 | ||
104 | int Ssl::Bio::write(const char *buf, int size, BIO *table) | |
105 | { | |
106 | errno = 0; | |
107 | #if _SQUID_WINDOWS_ | |
108 | const int result = socket_write_method(fd_, buf, size); | |
109 | #else | |
110 | const int result = default_write_method(fd_, buf, size); | |
111 | #endif | |
112 | const int xerrno = errno; | |
113 | debugs(83, 5, "FD " << fd_ << " wrote " << result << " <= " << size); | |
114 | ||
115 | BIO_clear_retry_flags(table); | |
116 | if (result < 0) { | |
117 | const bool ignoreError = ignoreErrno(xerrno) != 0; | |
118 | debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError); | |
119 | if (ignoreError) | |
120 | BIO_set_retry_write(table); | |
121 | } | |
122 | ||
123 | return result; | |
124 | } | |
125 | ||
126 | int | |
127 | Ssl::Bio::read(char *buf, int size, BIO *table) | |
128 | { | |
129 | errno = 0; | |
130 | #if _SQUID_WINDOWS_ | |
131 | const int result = socket_read_method(fd_, buf, size); | |
132 | #else | |
133 | const int result = default_read_method(fd_, buf, size); | |
134 | #endif | |
135 | const int xerrno = errno; | |
136 | debugs(83, 5, "FD " << fd_ << " read " << result << " <= " << size); | |
137 | ||
138 | BIO_clear_retry_flags(table); | |
139 | if (result < 0) { | |
140 | const bool ignoreError = ignoreErrno(xerrno) != 0; | |
141 | debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError); | |
142 | if (ignoreError) | |
143 | BIO_set_retry_read(table); | |
144 | } | |
145 | ||
146 | return result; | |
147 | } | |
148 | ||
149 | /// Called whenever the SSL connection state changes, an alert appears, or an | |
150 | /// error occurs. See SSL_set_info_callback(). | |
151 | void | |
8b082ed9 | 152 | Ssl::Bio::stateChanged(const SSL *ssl, int where, int) |
b3a8ae1b AR |
153 | { |
154 | // Here we can use (where & STATE) to check the current state. | |
155 | // Many STATE values are possible, including: SSL_CB_CONNECT_LOOP, | |
156 | // SSL_CB_ACCEPT_LOOP, SSL_CB_HANDSHAKE_START, and SSL_CB_HANDSHAKE_DONE. | |
157 | // For example: | |
158 | // if (where & SSL_CB_HANDSHAKE_START) | |
159 | // debugs(83, 9, "Trying to establish the SSL connection"); | |
160 | // else if (where & SSL_CB_HANDSHAKE_DONE) | |
161 | // debugs(83, 9, "SSL connection established"); | |
162 | ||
d620ae0e | 163 | debugs(83, 7, "FD " << fd_ << " now: 0x" << std::hex << where << std::dec << ' ' << |
b3a8ae1b AR |
164 | SSL_state_string(ssl) << " (" << SSL_state_string_long(ssl) << ")"); |
165 | } | |
166 | ||
edb876ab CT |
167 | Ssl::ClientBio::ClientBio(const int anFd): |
168 | Bio(anFd), | |
169 | holdRead_(false), | |
170 | holdWrite_(false), | |
edb876ab CT |
171 | abortReason(nullptr) |
172 | { | |
173 | renegotiations.configure(10*1000); | |
174 | } | |
175 | ||
e1f72a8b | 176 | void |
d620ae0e CT |
177 | Ssl::ClientBio::stateChanged(const SSL *ssl, int where, int ret) |
178 | { | |
179 | Ssl::Bio::stateChanged(ssl, where, ret); | |
edb876ab CT |
180 | // detect client-initiated renegotiations DoS (CVE-2011-1473) |
181 | if (where & SSL_CB_HANDSHAKE_START) { | |
182 | const int reneg = renegotiations.count(1); | |
183 | ||
184 | if (abortReason) | |
185 | return; // already decided and informed the admin | |
186 | ||
187 | if (reneg > RenegotiationsLimit) { | |
188 | abortReason = "renegotiate requests flood"; | |
189 | debugs(83, DBG_IMPORTANT, "Terminating TLS connection [from " << fd_table[fd_].ipaddr << "] due to " << abortReason << ". This connection received " << | |
190 | reneg << " renegotiate requests in the last " << | |
191 | RenegotiationsWindow << " seconds (and " << | |
192 | renegotiations.remembered() << " requests total)."); | |
193 | } | |
194 | } | |
d620ae0e CT |
195 | } |
196 | ||
197 | int | |
198 | Ssl::ClientBio::write(const char *buf, int size, BIO *table) | |
199 | { | |
edb876ab CT |
200 | if (abortReason) { |
201 | debugs(83, 3, "BIO on FD " << fd_ << " is aborted"); | |
202 | BIO_clear_retry_flags(table); | |
203 | return -1; | |
204 | } | |
205 | ||
d620ae0e CT |
206 | if (holdWrite_) { |
207 | BIO_set_retry_write(table); | |
208 | return 0; | |
209 | } | |
210 | ||
211 | return Ssl::Bio::write(buf, size, table); | |
212 | } | |
213 | ||
d620ae0e CT |
214 | int |
215 | Ssl::ClientBio::read(char *buf, int size, BIO *table) | |
216 | { | |
edb876ab CT |
217 | if (abortReason) { |
218 | debugs(83, 3, "BIO on FD " << fd_ << " is aborted"); | |
219 | BIO_clear_retry_flags(table); | |
220 | return -1; | |
221 | } | |
222 | ||
d620ae0e CT |
223 | if (holdRead_) { |
224 | debugs(83, 7, "Hold flag is set, retry latter. (Hold " << size << "bytes)"); | |
225 | BIO_set_retry_read(table); | |
226 | return -1; | |
227 | } | |
228 | ||
3cae14a6 CT |
229 | if (!rbuf.isEmpty()) { |
230 | int bytes = (size <= (int)rbuf.length() ? size : rbuf.length()); | |
231 | memcpy(buf, rbuf.rawContent(), bytes); | |
232 | rbuf.consume(bytes); | |
233 | return bytes; | |
234 | } else | |
235 | return Ssl::Bio::read(buf, size, table); | |
d620ae0e CT |
236 | |
237 | return -1; | |
238 | } | |
239 | ||
d20cf186 AR |
240 | Ssl::ServerBio::ServerBio(const int anFd): |
241 | Bio(anFd), | |
242 | helloMsgSize(0), | |
243 | helloBuild(false), | |
244 | allowSplice(false), | |
245 | allowBump(false), | |
246 | holdWrite_(false), | |
247 | record_(false), | |
248 | parsedHandshake(false), | |
0bffe3ce | 249 | parseError(false), |
d20cf186 | 250 | bumpMode_(bumpNone), |
cd29a421 CT |
251 | rbufConsumePos(0), |
252 | parser_(Security::HandshakeParser::fromServer) | |
d20cf186 AR |
253 | { |
254 | } | |
255 | ||
d620ae0e CT |
256 | void |
257 | Ssl::ServerBio::stateChanged(const SSL *ssl, int where, int ret) | |
258 | { | |
259 | Ssl::Bio::stateChanged(ssl, where, ret); | |
260 | } | |
261 | ||
262 | void | |
21530947 | 263 | Ssl::ServerBio::setClientFeatures(Security::TlsDetails::Pointer const &details, SBuf const &aHello) |
d620ae0e | 264 | { |
21530947 | 265 | clientTlsDetails = details; |
6744c1a8 | 266 | clientSentHello = aHello; |
d620ae0e CT |
267 | }; |
268 | ||
55369ae6 | 269 | int |
a465cd53 | 270 | Ssl::ServerBio::read(char *buf, int size, BIO *table) |
55369ae6 | 271 | { |
d20cf186 | 272 | if (parsedHandshake) // done parsing TLS Hello |
a465cd53 | 273 | return readAndGive(buf, size, table); |
d20cf186 AR |
274 | else |
275 | return readAndParse(buf, size, table); | |
a465cd53 | 276 | } |
55369ae6 | 277 | |
a465cd53 AR |
278 | /// Read and give everything to OpenSSL. |
279 | int | |
280 | Ssl::ServerBio::readAndGive(char *buf, const int size, BIO *table) | |
6821c276 | 281 | { |
a465cd53 AR |
282 | // If we have unused buffered bytes, give those bytes to OpenSSL now, |
283 | // before reading more. TODO: Read if we have buffered less than size? | |
284 | if (rbufConsumePos < rbuf.length()) | |
285 | return giveBuffered(buf, size); | |
55369ae6 | 286 | |
a465cd53 AR |
287 | if (record_) { |
288 | const int result = readAndBuffer(table); | |
289 | if (result <= 0) | |
290 | return result; | |
291 | return giveBuffered(buf, size); | |
55369ae6 AR |
292 | } |
293 | ||
a465cd53 | 294 | return Ssl::Bio::read(buf, size, table); |
55369ae6 AR |
295 | } |
296 | ||
a465cd53 | 297 | /// Read and give everything to our parser. |
d20cf186 | 298 | /// When/if parsing is finished (successfully or not), start giving to OpenSSL. |
d620ae0e | 299 | int |
a465cd53 | 300 | Ssl::ServerBio::readAndParse(char *buf, const int size, BIO *table) |
d620ae0e | 301 | { |
a465cd53 AR |
302 | const int result = readAndBuffer(table); |
303 | if (result <= 0) | |
304 | return result; | |
6821c276 | 305 | |
d20cf186 AR |
306 | try { |
307 | if (!parser_.parseHello(rbuf)) { | |
308 | // need more data to finish parsing | |
6821c276 | 309 | BIO_set_retry_read(table); |
a465cd53 AR |
310 | return -1; |
311 | } | |
d20cf186 AR |
312 | parsedHandshake = true; // done parsing (successfully) |
313 | } | |
314 | catch (const std::exception &ex) { | |
315 | debugs(83, 2, "parsing error on FD " << fd_ << ": " << ex.what()); | |
316 | parsedHandshake = true; // done parsing (due to an error) | |
0bffe3ce | 317 | parseError = true; |
55369ae6 AR |
318 | } |
319 | ||
a465cd53 | 320 | return giveBuffered(buf, size); |
6821c276 | 321 | } |
55369ae6 | 322 | |
a465cd53 AR |
323 | /// Reads more data into the read buffer. Returns either the number of bytes |
324 | /// read or, on errors (including "try again" errors), a negative number. | |
d620ae0e | 325 | int |
a465cd53 | 326 | Ssl::ServerBio::readAndBuffer(BIO *table) |
d620ae0e | 327 | { |
672337d1 CT |
328 | char *space = rbuf.rawAppendStart(SQUID_TCP_SO_RCVBUF); |
329 | const int result = Ssl::Bio::read(space, SQUID_TCP_SO_RCVBUF, table); | |
a465cd53 AR |
330 | if (result <= 0) |
331 | return result; | |
6821c276 | 332 | |
672337d1 | 333 | rbuf.rawAppendFinish(space, result); |
a465cd53 AR |
334 | return result; |
335 | } | |
6821c276 | 336 | |
a465cd53 AR |
337 | /// give previously buffered bytes to OpenSSL |
338 | /// returns the number of bytes given | |
339 | int | |
340 | Ssl::ServerBio::giveBuffered(char *buf, const int size) | |
341 | { | |
342 | if (rbuf.length() <= rbufConsumePos) | |
343 | return -1; // buffered nothing yet | |
344 | ||
345 | const int unsent = rbuf.length() - rbufConsumePos; | |
346 | const int bytes = (size <= unsent ? size : unsent); | |
347 | memcpy(buf, rbuf.rawContent() + rbufConsumePos, bytes); | |
348 | rbufConsumePos += bytes; | |
349 | debugs(83, 7, bytes << "<=" << size << " bytes to OpenSSL"); | |
350 | return bytes; | |
d620ae0e CT |
351 | } |
352 | ||
353 | int | |
354 | Ssl::ServerBio::write(const char *buf, int size, BIO *table) | |
355 | { | |
356 | ||
357 | if (holdWrite_) { | |
a465cd53 | 358 | debugs(83, 7, "postpone writing " << size << " bytes to SSL FD " << fd_); |
d620ae0e CT |
359 | BIO_set_retry_write(table); |
360 | return -1; | |
361 | } | |
362 | ||
5d65362c | 363 | if (!helloBuild && (bumpMode_ == Ssl::bumpPeek || bumpMode_ == Ssl::bumpStare)) { |
4ba1501c CT |
364 | // We have not seen any bytes, so the buffer must start with an |
365 | // OpenSSL-generated TLSPlaintext record containing, for example, a | |
366 | // ClientHello or an alert message. We check these assumptions before we | |
367 | // substitute that record/message with clientSentHello. | |
368 | // TODO: Move these checks to where we actually rely on them. | |
369 | debugs(83, 7, "to-server" << Raw("TLSPlaintext", buf, size).hex()); | |
6744c1a8 CT |
370 | Must(size >= 2); // enough for version and content_type checks below |
371 | Must(buf[1] >= 3); // record's version.major; determines buf[0] meaning | |
4ba1501c | 372 | Must(20 <= buf[0] && buf[0] <= 23); // valid TLSPlaintext.content_type |
6744c1a8 CT |
373 | |
374 | //Hello message is the first message we write to server | |
375 | assert(helloMsg.isEmpty()); | |
376 | ||
084fa674 AR |
377 | if (bumpMode_ == Ssl::bumpPeek) { |
378 | // we should not be here if we failed to parse the client-sent ClientHello | |
379 | Must(!clientSentHello.isEmpty()); | |
380 | allowSplice = true; | |
381 | // Replace OpenSSL-generated ClientHello with client-sent one. | |
382 | helloMsg.append(clientSentHello); | |
383 | debugs(83, 7, "FD " << fd_ << ": Using client-sent ClientHello for peek mode"); | |
384 | } else { /*Ssl::bumpStare*/ | |
385 | allowBump = true; | |
d620ae0e | 386 | } |
084fa674 | 387 | |
6744c1a8 | 388 | // if we did not use the client-sent ClientHello, then use the OpenSSL-generated one |
8693472e | 389 | if (helloMsg.isEmpty()) |
7f4e9b73 CT |
390 | helloMsg.append(buf, size); |
391 | ||
d620ae0e | 392 | helloBuild = true; |
8693472e | 393 | helloMsgSize = helloMsg.length(); |
7f4e9b73 CT |
394 | |
395 | if (allowSplice) { | |
e1f72a8b | 396 | // Do not write yet..... |
7f4e9b73 CT |
397 | BIO_set_retry_write(table); |
398 | return -1; | |
399 | } | |
d620ae0e CT |
400 | } |
401 | ||
8693472e | 402 | if (!helloMsg.isEmpty()) { |
d620ae0e | 403 | debugs(83, 7, "buffered write for FD " << fd_); |
8693472e | 404 | int ret = Ssl::Bio::write(helloMsg.rawContent(), helloMsg.length(), table); |
d620ae0e | 405 | helloMsg.consume(ret); |
8693472e | 406 | if (!helloMsg.isEmpty()) { |
d620ae0e CT |
407 | // We need to retry sendind data. |
408 | // Say to openSSL to retry sending hello message | |
409 | BIO_set_retry_write(table); | |
410 | return -1; | |
411 | } | |
412 | ||
413 | // Sending hello message complete. Do not send more data for now... | |
7f4e9b73 CT |
414 | holdWrite_ = true; |
415 | ||
a95989ed CT |
416 | // spoof openSSL that we write what it ask us to write |
417 | return size; | |
d620ae0e CT |
418 | } else |
419 | return Ssl::Bio::write(buf, size, table); | |
420 | } | |
421 | ||
422 | void | |
423 | Ssl::ServerBio::flush(BIO *table) | |
424 | { | |
8693472e CT |
425 | if (!helloMsg.isEmpty()) { |
426 | int ret = Ssl::Bio::write(helloMsg.rawContent(), helloMsg.length(), table); | |
d620ae0e CT |
427 | helloMsg.consume(ret); |
428 | } | |
429 | } | |
430 | ||
89c5ca0f CT |
431 | bool |
432 | Ssl::ServerBio::resumingSession() | |
433 | { | |
d9219c2b | 434 | return parser_.resumingSession; |
55369ae6 | 435 | } |
89c5ca0f | 436 | |
cd29a421 CT |
437 | bool |
438 | Ssl::ServerBio::encryptedCertificates() const | |
439 | { | |
440 | return parser_.details->tlsSupportedVersion && | |
70ac5b29 | 441 | Security::Tls1p3orLater(parser_.details->tlsSupportedVersion); |
cd29a421 CT |
442 | } |
443 | ||
b3a8ae1b AR |
444 | /// initializes BIO table after allocation |
445 | static int | |
446 | squid_bio_create(BIO *bi) | |
447 | { | |
17e98f24 | 448 | #if !HAVE_LIBCRYPTO_BIO_GET_INIT |
b3a8ae1b AR |
449 | bi->init = 0; // set when we store Bio object and socket fd (BIO_C_SET_FD) |
450 | bi->num = 0; | |
b3a8ae1b | 451 | bi->flags = 0; |
093deea9 CT |
452 | #else |
453 | // No need to set more, openSSL initialize BIO memory to zero. | |
454 | #endif | |
455 | ||
aee3523a | 456 | BIO_set_data(bi, nullptr); |
b3a8ae1b AR |
457 | return 1; |
458 | } | |
459 | ||
460 | /// cleans BIO table before deallocation | |
461 | static int | |
462 | squid_bio_destroy(BIO *table) | |
463 | { | |
093deea9 | 464 | delete static_cast<Ssl::Bio*>(BIO_get_data(table)); |
aee3523a | 465 | BIO_set_data(table, nullptr); |
b3a8ae1b AR |
466 | return 1; |
467 | } | |
468 | ||
469 | /// wrapper for Bio::write() | |
470 | static int | |
471 | squid_bio_write(BIO *table, const char *buf, int size) | |
472 | { | |
093deea9 | 473 | Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table)); |
b3a8ae1b AR |
474 | assert(bio); |
475 | return bio->write(buf, size, table); | |
476 | } | |
477 | ||
478 | /// wrapper for Bio::read() | |
479 | static int | |
480 | squid_bio_read(BIO *table, char *buf, int size) | |
481 | { | |
093deea9 | 482 | Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table)); |
b3a8ae1b AR |
483 | assert(bio); |
484 | return bio->read(buf, size, table); | |
485 | } | |
486 | ||
487 | /// implements puts() via write() | |
488 | static int | |
489 | squid_bio_puts(BIO *table, const char *str) | |
490 | { | |
491 | assert(str); | |
492 | return squid_bio_write(table, str, strlen(str)); | |
493 | } | |
494 | ||
495 | /// other BIO manipulations (those without dedicated callbacks in BIO table) | |
496 | static long | |
497 | squid_bio_ctrl(BIO *table, int cmd, long arg1, void *arg2) | |
498 | { | |
499 | debugs(83, 5, table << ' ' << cmd << '(' << arg1 << ", " << arg2 << ')'); | |
500 | ||
501 | switch (cmd) { | |
502 | case BIO_C_SET_FD: { | |
503 | assert(arg2); | |
504 | const int fd = *static_cast<int*>(arg2); | |
d620ae0e | 505 | Ssl::Bio *bio; |
86f77270 | 506 | if (arg1 == Security::Io::BIO_TO_SERVER) |
d620ae0e CT |
507 | bio = new Ssl::ServerBio(fd); |
508 | else | |
509 | bio = new Ssl::ClientBio(fd); | |
093deea9 CT |
510 | assert(!BIO_get_data(table)); |
511 | BIO_set_data(table, bio); | |
512 | BIO_set_init(table, 1); | |
b3a8ae1b AR |
513 | return 0; |
514 | } | |
515 | ||
516 | case BIO_C_GET_FD: | |
093deea9 CT |
517 | if (BIO_get_init(table)) { |
518 | Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table)); | |
b3a8ae1b AR |
519 | assert(bio); |
520 | if (arg2) | |
521 | *static_cast<int*>(arg2) = bio->fd(); | |
522 | return bio->fd(); | |
523 | } | |
524 | return -1; | |
525 | ||
54f3b032 | 526 | case BIO_CTRL_DUP: |
e1f72a8b | 527 | // Should implemented if the SSL_dup openSSL API function |
54f3b032 CT |
528 | // used anywhere in squid. |
529 | return 0; | |
530 | ||
b3a8ae1b | 531 | case BIO_CTRL_FLUSH: |
093deea9 CT |
532 | if (BIO_get_init(table)) { |
533 | Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table)); | |
b3a8ae1b | 534 | assert(bio); |
d620ae0e | 535 | bio->flush(table); |
b3a8ae1b AR |
536 | return 1; |
537 | } | |
538 | return 0; | |
539 | ||
f53969cc SM |
540 | /* we may also need to implement these: |
541 | case BIO_CTRL_RESET: | |
542 | case BIO_C_FILE_SEEK: | |
543 | case BIO_C_FILE_TELL: | |
544 | case BIO_CTRL_INFO: | |
545 | case BIO_CTRL_GET_CLOSE: | |
546 | case BIO_CTRL_SET_CLOSE: | |
547 | case BIO_CTRL_PENDING: | |
548 | case BIO_CTRL_WPENDING: | |
549 | */ | |
b3a8ae1b AR |
550 | default: |
551 | return 0; | |
552 | ||
553 | } | |
554 | ||
555 | return 0; /* NOTREACHED */ | |
556 | } | |
557 | ||
558 | /// wrapper for Bio::stateChanged() | |
559 | static void | |
560 | squid_ssl_info(const SSL *ssl, int where, int ret) | |
561 | { | |
562 | if (BIO *table = SSL_get_rbio(ssl)) { | |
093deea9 | 563 | if (Ssl::Bio *bio = static_cast<Ssl::Bio*>(BIO_get_data(table))) |
b3a8ae1b AR |
564 | bio->stateChanged(ssl, where, ret); |
565 | } | |
566 | } | |
567 | ||
21530947 CT |
568 | void |
569 | applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode) | |
d620ae0e | 570 | { |
21530947 CT |
571 | // To increase the possibility for bumping after peek mode selection or |
572 | // splicing after stare mode selection it is good to set the | |
573 | // SSL protocol version. | |
d9219c2b CT |
574 | // The SSL_set_ssl_method is wrong here because it will restrict the |
575 | // permitted transport version to be identical to the version used in the | |
576 | // ClientHello message. | |
21530947 CT |
577 | // For example will prevent comunnicating with a tls1.0 server if the |
578 | // client sent and tlsv1.2 Hello message. | |
e1f72a8b | 579 | #if defined(TLSEXT_NAMETYPE_host_name) |
21530947 CT |
580 | if (!details->serverName.isEmpty()) { |
581 | SSL_set_tlsext_host_name(ssl, details->serverName.c_str()); | |
458fd470 | 582 | } |
e68e8b9a | 583 | #endif |
2bcab852 | 584 | |
21530947 CT |
585 | if (!details->ciphers.empty()) { |
586 | SBuf strCiphers; | |
587 | for (auto cipherId: details->ciphers) { | |
588 | unsigned char cbytes[3]; | |
589 | cbytes[0] = (cipherId >> 8) & 0xFF; | |
590 | cbytes[1] = cipherId & 0xFF; | |
591 | cbytes[2] = 0; | |
24b30fdc | 592 | if (const auto c = SSL_CIPHER_find(ssl, cbytes)) { |
21530947 CT |
593 | if (!strCiphers.isEmpty()) |
594 | strCiphers.append(":"); | |
093deea9 | 595 | strCiphers.append(SSL_CIPHER_get_name(c)); |
d620ae0e CT |
596 | } |
597 | } | |
21530947 CT |
598 | if (!strCiphers.isEmpty()) |
599 | SSL_set_cipher_list(ssl, strCiphers.c_str()); | |
d620ae0e | 600 | } |
d620ae0e | 601 | |
8693472e | 602 | #if defined(SSL_OP_NO_COMPRESSION) /* XXX: OpenSSL 0.9.8k lacks SSL_OP_NO_COMPRESSION */ |
67c99fc6 | 603 | if (!details->compressionSupported) |
a95989ed CT |
604 | SSL_set_options(ssl, SSL_OP_NO_COMPRESSION); |
605 | #endif | |
606 | ||
cd29a421 CT |
607 | #if defined(SSL_OP_NO_TLSv1_3) |
608 | // avoid "inappropriate fallback" OpenSSL error messages | |
609 | if (details->tlsSupportedVersion && Security::Tls1p2orEarlier(details->tlsSupportedVersion)) | |
610 | SSL_set_options(ssl, SSL_OP_NO_TLSv1_3); | |
611 | #endif | |
612 | ||
89c5ca0f | 613 | #if defined(TLSEXT_STATUSTYPE_ocsp) |
21530947 | 614 | if (details->tlsStatusRequest) |
89c5ca0f CT |
615 | SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp); |
616 | #endif | |
617 | ||
618 | #if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) | |
21530947 | 619 | if (!details->tlsAppLayerProtoNeg.isEmpty()) { |
89c5ca0f | 620 | if (bumpMode == Ssl::bumpPeek) |
3152460d | 621 | SSL_set_alpn_protos(ssl, (const unsigned char*)details->tlsAppLayerProtoNeg.rawContent(), details->tlsAppLayerProtoNeg.length()); |
89c5ca0f CT |
622 | else { |
623 | static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'}; | |
624 | SSL_set_alpn_protos(ssl, supported_protos, sizeof(supported_protos)); | |
625 | } | |
626 | } | |
627 | #endif | |
a95989ed CT |
628 | } |
629 | ||
21530947 | 630 | #endif // USE_OPENSSL |
f53969cc | 631 |