]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/bio.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ssl / bio.cc
CommitLineData
b3a8ae1b 1/*
bde978a6 2 * Copyright (C) 1996-2015 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
AR
16
17#include "comm.h"
d620ae0e
CT
18#include "fde.h"
19#include "globals.h"
40f1e76d 20#include "ip/Address.h"
b3a8ae1b 21#include "ssl/bio.h"
8693472e 22
b3a8ae1b
AR
23#if HAVE_OPENSSL_SSL_H
24#include <openssl/ssl.h>
25#endif
26
d620ae0e
CT
27#undef DO_SSLV23
28
b3a8ae1b
AR
29#if _SQUID_WINDOWS_
30extern int socket_read_method(int, char *, int);
31extern int socket_write_method(int, const char *, int);
32#endif
33
34/* BIO callbacks */
35static int squid_bio_write(BIO *h, const char *buf, int num);
36static int squid_bio_read(BIO *h, char *buf, int size);
37static int squid_bio_puts(BIO *h, const char *str);
38//static int squid_bio_gets(BIO *h, char *str, int size);
39static long squid_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
40static int squid_bio_create(BIO *h);
41static int squid_bio_destroy(BIO *data);
42/* SSL callbacks */
43static void squid_ssl_info(const SSL *ssl, int where, int ret);
44
45/// Initialization structure for the BIO table with
46/// Squid-specific methods and BIO method wrappers.
47static 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};
59
60BIO *
d620ae0e 61Ssl::Bio::Create(const int fd, Ssl::Bio::Type type)
b3a8ae1b
AR
62{
63 if (BIO *bio = BIO_new(&SquidMethods)) {
d620ae0e 64 BIO_int_ctrl(bio, BIO_C_SET_FD, type, fd);
b3a8ae1b
AR
65 return bio;
66 }
67 return NULL;
68}
69
70void
71Ssl::Bio::Link(SSL *ssl, BIO *bio)
72{
73 SSL_set_bio(ssl, bio, bio); // cannot fail
74 SSL_set_info_callback(ssl, &squid_ssl_info); // does not provide diagnostic
75}
76
b3a8ae1b
AR
77Ssl::Bio::Bio(const int anFd): fd_(anFd)
78{
79 debugs(83, 7, "Bio constructed, this=" << this << " FD " << fd_);
80}
81
82Ssl::Bio::~Bio()
83{
84 debugs(83, 7, "Bio destructing, this=" << this << " FD " << fd_);
b3a8ae1b
AR
85}
86
87int Ssl::Bio::write(const char *buf, int size, BIO *table)
88{
89 errno = 0;
90#if _SQUID_WINDOWS_
91 const int result = socket_write_method(fd_, buf, size);
92#else
93 const int result = default_write_method(fd_, buf, size);
94#endif
95 const int xerrno = errno;
96 debugs(83, 5, "FD " << fd_ << " wrote " << result << " <= " << size);
97
98 BIO_clear_retry_flags(table);
99 if (result < 0) {
100 const bool ignoreError = ignoreErrno(xerrno) != 0;
101 debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError);
102 if (ignoreError)
103 BIO_set_retry_write(table);
104 }
105
106 return result;
107}
108
109int
110Ssl::Bio::read(char *buf, int size, BIO *table)
111{
112 errno = 0;
113#if _SQUID_WINDOWS_
114 const int result = socket_read_method(fd_, buf, size);
115#else
116 const int result = default_read_method(fd_, buf, size);
117#endif
118 const int xerrno = errno;
119 debugs(83, 5, "FD " << fd_ << " read " << result << " <= " << size);
120
121 BIO_clear_retry_flags(table);
122 if (result < 0) {
123 const bool ignoreError = ignoreErrno(xerrno) != 0;
124 debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError);
125 if (ignoreError)
126 BIO_set_retry_read(table);
127 }
128
129 return result;
130}
131
132/// Called whenever the SSL connection state changes, an alert appears, or an
133/// error occurs. See SSL_set_info_callback().
134void
135Ssl::Bio::stateChanged(const SSL *ssl, int where, int ret)
136{
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.
140 // For example:
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");
145
d620ae0e 146 debugs(83, 7, "FD " << fd_ << " now: 0x" << std::hex << where << std::dec << ' ' <<
b3a8ae1b
AR
147 SSL_state_string(ssl) << " (" << SSL_state_string_long(ssl) << ")");
148}
149
d620ae0e
CT
150bool
151Ssl::ClientBio::isClientHello(int state)
152{
d85aad1b 153 return (
c05a5e2d
SM
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
e1f72a8b 159 );
d620ae0e
CT
160}
161
e1f72a8b 162void
d620ae0e
CT
163Ssl::ClientBio::stateChanged(const SSL *ssl, int where, int ret)
164{
165 Ssl::Bio::stateChanged(ssl, where, ret);
166}
167
168int
169Ssl::ClientBio::write(const char *buf, int size, BIO *table)
170{
171 if (holdWrite_) {
172 BIO_set_retry_write(table);
173 return 0;
174 }
175
176 return Ssl::Bio::write(buf, size, table);
177}
178
179const char *objToString(unsigned char const *bytes, int len)
180{
181 static std::string buf;
182 buf.clear();
e1f72a8b 183 for (int i = 0; i < len; i++ ) {
d620ae0e
CT
184 char tmp[3];
185 snprintf(tmp, sizeof(tmp), "%.2x", bytes[i]);
186 buf.append(tmp);
187 }
188 return buf.c_str();
189}
190
191int
192Ssl::ClientBio::read(char *buf, int size, BIO *table)
193{
a95989ed 194 if (helloState < atHelloReceived) {
d620ae0e
CT
195
196 if (rbuf.isNull())
7f4e9b73 197 rbuf.init(1024, 16384);
d620ae0e
CT
198
199 size = rbuf.spaceSize() > size ? size : rbuf.spaceSize();
200
201 if (!size)
202 return 0;
203
204 int bytes = Ssl::Bio::read(buf, size, table);
869b4328
CT
205 if (bytes <= 0)
206 return bytes;
d620ae0e
CT
207 rbuf.append(buf, bytes);
208 debugs(83, 7, "rbuf size: " << rbuf.contentSize());
209 }
210
a95989ed 211 if (helloState == atHelloNone) {
d620ae0e
CT
212
213 const unsigned char *head = (const unsigned char *)rbuf.content();
214 const char *s = objToString(head, rbuf.contentSize());
215 debugs(83, 7, "SSL Header: " << s);
216 if (rbuf.contentSize() < 5) {
217 BIO_set_retry_read(table);
218 return 0;
219 }
220
221 if (head[0] == 0x16) {
222 debugs(83, 7, "SSL version 3 handshake message");
a95989ed
CT
223 helloSize = (head[3] << 8) + head[4];
224 debugs(83, 7, "SSL Header Size: " << helloSize);
225 helloSize +=5;
8693472e 226#if defined(DO_SSLV23)
e1f72a8b 227 } else if ((head[0] & 0x80) && head[2] == 0x01 && head[3] == 0x03) {
d620ae0e 228 debugs(83, 7, "SSL version 2 handshake message with v3 support");
a95989ed
CT
229 helloSize = head[1];
230 helloSize +=5;
d620ae0e 231#endif
e1f72a8b 232 } else {
d620ae0e 233 debugs(83, 7, "Not an SSL acceptable handshake message (SSLv2 message?)");
3248e962 234 wrongProtocol = true;
d620ae0e
CT
235 return -1;
236 }
237
a95989ed 238 helloState = atHelloStarted; //Next state
d620ae0e
CT
239 }
240
a95989ed 241 if (helloState == atHelloStarted) {
d620ae0e
CT
242 const unsigned char *head = (const unsigned char *)rbuf.content();
243 const char *s = objToString(head, rbuf.contentSize());
244 debugs(83, 7, "SSL Header: " << s);
245
a95989ed 246 if (helloSize > rbuf.contentSize()) {
d620ae0e
CT
247 BIO_set_retry_read(table);
248 return -1;
249 }
250 features.get((const unsigned char *)rbuf.content());
a95989ed 251 helloState = atHelloReceived;
d620ae0e
CT
252 }
253
254 if (holdRead_) {
255 debugs(83, 7, "Hold flag is set, retry latter. (Hold " << size << "bytes)");
256 BIO_set_retry_read(table);
257 return -1;
258 }
259
a95989ed 260 if (helloState == atHelloReceived) {
d620ae0e
CT
261 if (rbuf.hasContent()) {
262 int bytes = (size <= rbuf.contentSize() ? size : rbuf.contentSize());
263 memcpy(buf, rbuf.content(), bytes);
264 rbuf.consume(bytes);
265 return bytes;
266 } else
267 return Ssl::Bio::read(buf, size, table);
268 }
269
270 return -1;
271}
272
273void
274Ssl::ServerBio::stateChanged(const SSL *ssl, int where, int ret)
275{
276 Ssl::Bio::stateChanged(ssl, where, ret);
277}
278
279void
7f4e9b73 280Ssl::ServerBio::setClientFeatures(const Ssl::Bio::sslFeatures &features)
d620ae0e 281{
7f4e9b73
CT
282 clientFeatures.sslVersion = features.sslVersion;
283 clientFeatures.compressMethod = features.compressMethod;
284 clientFeatures.serverName = features.serverName;
285 clientFeatures.clientRequestedCiphers = features.clientRequestedCiphers;
286 clientFeatures.unknownCiphers = features.unknownCiphers;
287 memcpy(clientFeatures.client_random, features.client_random, SSL3_RANDOM_SIZE);
8693472e
CT
288 clientFeatures.helloMessage.clear();
289 clientFeatures.helloMessage.append(features.helloMessage.rawContent(), features.helloMessage.length());
7f4e9b73
CT
290 clientFeatures.doHeartBeats = features.doHeartBeats;
291 clientFeatures.extensions = features.extensions;
292 featuresSet = true;
d620ae0e
CT
293};
294
295int
296Ssl::ServerBio::read(char *buf, int size, BIO *table)
297{
298 int bytes = Ssl::Bio::read(buf, size, table);
299
300 if (bytes > 0 && record_) {
301 if (rbuf.isNull())
7f4e9b73 302 rbuf.init(1024, 16384);
d620ae0e 303 rbuf.append(buf, bytes);
7f4e9b73 304 debugs(83, 5, "Record is enabled store " << bytes << " bytes");
d620ae0e 305 }
7f4e9b73 306 debugs(83, 5, "Read " << bytes << " from " << size << " bytes");
d620ae0e
CT
307 return bytes;
308}
309
1110989a
CT
310// This function makes the required checks to examine if the client hello
311// message is compatible with the features provided by OpenSSL toolkit.
a95989ed 312// If the features are compatible and can be supported it tries to rewrite SSL
1110989a 313// structure members, to replace the hello message created by openSSL, with the
a95989ed 314// web client SSL hello message.
1110989a
CT
315// This is mostly possible in the cases where the web client uses openSSL
316// library similar with this one used by squid.
a95989ed
CT
317static bool
318adjustSSL(SSL *ssl, Ssl::Bio::sslFeatures &features)
7f4e9b73 319{
a95989ed
CT
320#if SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK
321 if (!ssl->s3) {
322 debugs(83, 5, "No SSLv3 data found!");
323 return false;
324 }
325
7f4e9b73
CT
326 // If the client supports compression but our context does not support
327 // we can not adjust.
a36e9cb2
SH
328#if defined(OPENSSL_NO_COMP)
329 const bool requireCompression = (features.compressMethod && ssl->ctx->comp_methods == NULL);
330#else
331 const bool requireCompression = features.compressMethod;
332#endif
333 if (requireCompression) {
7f4e9b73 334 debugs(83, 5, "Client Hello Data supports compression, but we do not!");
a95989ed 335 return false;
7f4e9b73
CT
336 }
337
a95989ed 338 // Check ciphers list
7f4e9b73
CT
339 size_t token = 0;
340 size_t end = 0;
341 while (token != std::string::npos) {
e1f72a8b
CT
342 end = features.clientRequestedCiphers.find(':',token);
343 std::string cipher;
344 cipher.assign(features.clientRequestedCiphers, token, end - token);
345 token = (end != std::string::npos ? end + 1 : std::string::npos);
346 bool found = false;
347 STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl);
348 for (int i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
349 SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
350 const char *cname = SSL_CIPHER_get_name(c);
351 if (cipher.compare(cname)) {
352 found = true;
353 break;
354 }
355 }
356 if (!found) {
357 debugs(83, 5, "Client Hello Data supports cipher '"<< cipher <<"' but we do not support it!");
358 return false;
359 }
7f4e9b73
CT
360 }
361
362#if !defined(SSL_TLSEXT_HB_ENABLED)
363 if (features.doHeartBeats) {
364 debugs(83, 5, "Client Hello Data supports HeartBeats but we do not support!");
a95989ed 365 return false;
7f4e9b73
CT
366 }
367#endif
368
369 for (std::list<int>::iterator it = features.extensions.begin(); it != features.extensions.end(); ++it) {
370 static int supportedExtensions[] = {
8693472e 371#if defined(TLSEXT_TYPE_server_name)
7f4e9b73 372 TLSEXT_TYPE_server_name,
4cabb5e5 373#endif
8693472e 374#if defined(TLSEXT_TYPE_opaque_prf_input)
7f4e9b73
CT
375 TLSEXT_TYPE_opaque_prf_input,
376#endif
8693472e 377#if defined(TLSEXT_TYPE_heartbeat)
7f4e9b73
CT
378 TLSEXT_TYPE_heartbeat,
379#endif
8693472e 380#if defined(TLSEXT_TYPE_renegotiate)
7f4e9b73
CT
381 TLSEXT_TYPE_renegotiate,
382#endif
8693472e 383#if defined(TLSEXT_TYPE_ec_point_formats)
7f4e9b73
CT
384 TLSEXT_TYPE_ec_point_formats,
385#endif
8693472e 386#if defined(TLSEXT_TYPE_elliptic_curves)
7f4e9b73
CT
387 TLSEXT_TYPE_elliptic_curves,
388#endif
8693472e 389#if defined(TLSEXT_TYPE_session_ticket)
7f4e9b73
CT
390 TLSEXT_TYPE_session_ticket,
391#endif
8693472e 392#if defined(TLSEXT_TYPE_status_request)
7f4e9b73
CT
393 TLSEXT_TYPE_status_request,
394#endif
8693472e 395#if defined(TLSEXT_TYPE_use_srtp)
7f4e9b73
CT
396 TLSEXT_TYPE_use_srtp,
397#endif
a95989ed 398#if 0 //Allow 13172 Firefox supported extension for testing purposes
7f4e9b73
CT
399 13172,
400#endif
401 -1
402 };
403 bool found = false;
404 for (int i = 0; supportedExtensions[i] != -1; i++) {
405 if (*it == supportedExtensions[i]) {
406 found = true;
407 break;
408 }
409 }
410 if (!found) {
411 debugs(83, 5, "Extension " << *it << " does not supported!");
a95989ed 412 return false;
7f4e9b73
CT
413 }
414 }
415
a95989ed 416 SSL3_BUFFER *wb=&(ssl->s3->wbuf);
8693472e 417 if (wb->len < (size_t)features.helloMessage.length())
5d65362c 418 return false;
7f4e9b73 419
a95989ed 420 debugs(83, 5, "OpenSSL SSL struct will be adjusted to mimic client hello data!");
7f4e9b73
CT
421
422 //Adjust ssl structure data.
7f4e9b73
CT
423 // We need to fix the random in SSL struct:
424 memcpy(ssl->s3->client_random, features.client_random, SSL3_RANDOM_SIZE);
8693472e
CT
425 memcpy(wb->buf, features.helloMessage.rawContent(), features.helloMessage.length());
426 wb->left = features.helloMessage.length();
7f4e9b73 427
8693472e
CT
428 size_t mainHelloSize = features.helloMessage.length() - 5;
429 const char *mainHello = features.helloMessage.rawContent() + 5;
4cabb5e5 430 assert((size_t)ssl->init_buf->max > mainHelloSize);
7f4e9b73
CT
431 memcpy(ssl->init_buf->data, mainHello, mainHelloSize);
432 debugs(83, 5, "Hello Data init and adjustd sizes :" << ssl->init_num << " = "<< mainHelloSize);
433 ssl->init_num = mainHelloSize;
434 ssl->s3->wpend_ret = mainHelloSize;
435 ssl->s3->wpend_tot = mainHelloSize;
a95989ed
CT
436 return true;
437#else
438 return false;
439#endif
7f4e9b73
CT
440}
441
d620ae0e
CT
442int
443Ssl::ServerBio::write(const char *buf, int size, BIO *table)
444{
445
446 if (holdWrite_) {
7f4e9b73 447 debugs(83, 7, "Hold write, for SSL connection on " << fd_ << "will not write bytes of size " << size);
d620ae0e
CT
448 BIO_set_retry_write(table);
449 return -1;
450 }
451
5d65362c 452 if (!helloBuild && (bumpMode_ == Ssl::bumpPeek || bumpMode_ == Ssl::bumpStare)) {
d620ae0e
CT
453 if (
454 buf[1] >= 3 //it is an SSL Version3 message
455 && buf[0] == 0x16 // and it is a Handshake/Hello message
e1f72a8b 456 ) {
d620ae0e
CT
457
458 //Hello message is the first message we write to server
8693472e 459 assert(helloMsg.isEmpty());
d620ae0e
CT
460
461 SSL *ssl = fd_table[fd_].ssl;
a95989ed 462 if (featuresSet && ssl) {
5d65362c 463 if (bumpMode_ == Ssl::bumpPeek) {
a95989ed 464 if (adjustSSL(ssl, clientFeatures))
5d65362c 465 allowBump = true;
7f4e9b73 466 allowSplice = true;
8693472e 467 helloMsg.append(clientFeatures.helloMessage);
35178e02 468 debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted for peek mode");
5d65362c
CT
469 } else { /*Ssl::bumpStare*/
470 allowBump = true;
a95989ed 471 if (adjustSSL(ssl, clientFeatures)) {
5d65362c 472 allowSplice = true;
8693472e 473 helloMsg.append(clientFeatures.helloMessage);
35178e02
CT
474 debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted for stare mode");
475 }
7f4e9b73 476 }
d620ae0e
CT
477 }
478 }
7f4e9b73 479 // If we do not build any hello message, copy the current
8693472e 480 if (helloMsg.isEmpty())
7f4e9b73
CT
481 helloMsg.append(buf, size);
482
d620ae0e 483 helloBuild = true;
8693472e 484 helloMsgSize = helloMsg.length();
5d65362c 485 //allowBump = true;
7f4e9b73
CT
486
487 if (allowSplice) {
e1f72a8b 488 // Do not write yet.....
7f4e9b73
CT
489 BIO_set_retry_write(table);
490 return -1;
491 }
d620ae0e
CT
492 }
493
8693472e 494 if (!helloMsg.isEmpty()) {
d620ae0e 495 debugs(83, 7, "buffered write for FD " << fd_);
8693472e 496 int ret = Ssl::Bio::write(helloMsg.rawContent(), helloMsg.length(), table);
d620ae0e 497 helloMsg.consume(ret);
8693472e 498 if (!helloMsg.isEmpty()) {
d620ae0e
CT
499 // We need to retry sendind data.
500 // Say to openSSL to retry sending hello message
501 BIO_set_retry_write(table);
502 return -1;
503 }
504
505 // Sending hello message complete. Do not send more data for now...
7f4e9b73
CT
506 holdWrite_ = true;
507
a95989ed
CT
508 // spoof openSSL that we write what it ask us to write
509 return size;
d620ae0e
CT
510 } else
511 return Ssl::Bio::write(buf, size, table);
512}
513
514void
515Ssl::ServerBio::flush(BIO *table)
516{
8693472e
CT
517 if (!helloMsg.isEmpty()) {
518 int ret = Ssl::Bio::write(helloMsg.rawContent(), helloMsg.length(), table);
d620ae0e
CT
519 helloMsg.consume(ret);
520 }
521}
522
b3a8ae1b
AR
523/// initializes BIO table after allocation
524static int
525squid_bio_create(BIO *bi)
526{
527 bi->init = 0; // set when we store Bio object and socket fd (BIO_C_SET_FD)
528 bi->num = 0;
529 bi->ptr = NULL;
530 bi->flags = 0;
531 return 1;
532}
533
534/// cleans BIO table before deallocation
535static int
536squid_bio_destroy(BIO *table)
537{
538 delete static_cast<Ssl::Bio*>(table->ptr);
539 table->ptr = NULL;
540 return 1;
541}
542
543/// wrapper for Bio::write()
544static int
545squid_bio_write(BIO *table, const char *buf, int size)
546{
547 Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
548 assert(bio);
549 return bio->write(buf, size, table);
550}
551
552/// wrapper for Bio::read()
553static int
554squid_bio_read(BIO *table, char *buf, int size)
555{
556 Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
557 assert(bio);
558 return bio->read(buf, size, table);
559}
560
561/// implements puts() via write()
562static int
563squid_bio_puts(BIO *table, const char *str)
564{
565 assert(str);
566 return squid_bio_write(table, str, strlen(str));
567}
568
569/// other BIO manipulations (those without dedicated callbacks in BIO table)
570static long
571squid_bio_ctrl(BIO *table, int cmd, long arg1, void *arg2)
572{
573 debugs(83, 5, table << ' ' << cmd << '(' << arg1 << ", " << arg2 << ')');
574
575 switch (cmd) {
576 case BIO_C_SET_FD: {
577 assert(arg2);
578 const int fd = *static_cast<int*>(arg2);
d620ae0e
CT
579 Ssl::Bio *bio;
580 if (arg1 == Ssl::Bio::BIO_TO_SERVER)
581 bio = new Ssl::ServerBio(fd);
582 else
583 bio = new Ssl::ClientBio(fd);
b3a8ae1b
AR
584 assert(!table->ptr);
585 table->ptr = bio;
586 table->init = 1;
587 return 0;
588 }
589
590 case BIO_C_GET_FD:
591 if (table->init) {
592 Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
593 assert(bio);
594 if (arg2)
595 *static_cast<int*>(arg2) = bio->fd();
596 return bio->fd();
597 }
598 return -1;
599
54f3b032 600 case BIO_CTRL_DUP:
e1f72a8b 601 // Should implemented if the SSL_dup openSSL API function
54f3b032
CT
602 // used anywhere in squid.
603 return 0;
604
b3a8ae1b
AR
605 case BIO_CTRL_FLUSH:
606 if (table->init) {
607 Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
608 assert(bio);
d620ae0e 609 bio->flush(table);
b3a8ae1b
AR
610 return 1;
611 }
612 return 0;
613
f53969cc
SM
614 /* we may also need to implement these:
615 case BIO_CTRL_RESET:
616 case BIO_C_FILE_SEEK:
617 case BIO_C_FILE_TELL:
618 case BIO_CTRL_INFO:
619 case BIO_CTRL_GET_CLOSE:
620 case BIO_CTRL_SET_CLOSE:
621 case BIO_CTRL_PENDING:
622 case BIO_CTRL_WPENDING:
623 */
b3a8ae1b
AR
624 default:
625 return 0;
626
627 }
628
629 return 0; /* NOTREACHED */
630}
631
632/// wrapper for Bio::stateChanged()
633static void
634squid_ssl_info(const SSL *ssl, int where, int ret)
635{
636 if (BIO *table = SSL_get_rbio(ssl)) {
637 if (Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr))
638 bio->stateChanged(ssl, where, ret);
639 }
640}
641
7f4e9b73 642Ssl::Bio::sslFeatures::sslFeatures(): sslVersion(-1), compressMethod(-1), unknownCiphers(false), doHeartBeats(true)
d620ae0e
CT
643{
644 memset(client_random, 0, SSL3_RANDOM_SIZE);
645}
646
647int Ssl::Bio::sslFeatures::toSquidSSLVersion() const
648{
e1f72a8b 649 if (sslVersion == SSL2_VERSION)
d620ae0e 650 return 2;
e1f72a8b 651 else if (sslVersion == SSL3_VERSION)
d620ae0e 652 return 3;
e1f72a8b 653 else if (sslVersion == TLS1_VERSION)
d620ae0e
CT
654 return 4;
655#if OPENSSL_VERSION_NUMBER >= 0x10001000L
e1f72a8b 656 else if (sslVersion == TLS1_1_VERSION)
d620ae0e 657 return 5;
e1f72a8b 658 else if (sslVersion == TLS1_2_VERSION)
d620ae0e
CT
659 return 6;
660#endif
661 else
662 return 1;
663}
664
665bool
666Ssl::Bio::sslFeatures::get(const SSL *ssl)
667{
668 sslVersion = SSL_version(ssl);
669 debugs(83, 7, "SSL version: " << SSL_get_version(ssl) << " (" << sslVersion << ")");
670
e1f72a8b
CT
671#if defined(TLSEXT_NAMETYPE_host_name)
672 if (const char *server = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))
d620ae0e
CT
673 serverName = server;
674 debugs(83, 7, "SNI server name: " << serverName);
4cabb5e5 675#endif
d620ae0e 676
a36e9cb2 677#if defined(OPENSSL_NO_COMP)
d620ae0e 678 if (ssl->session->compress_meth)
e1f72a8b
CT
679 compressMethod = ssl->session->compress_meth;
680 else if (sslVersion >= 3) //if it is 3 or newer version then compression is disabled
a36e9cb2 681#endif
d620ae0e
CT
682 compressMethod = 0;
683 debugs(83, 7, "SSL compression: " << compressMethod);
684
685 STACK_OF(SSL_CIPHER) * ciphers = NULL;
686 if (ssl->server)
687 ciphers = ssl->session->ciphers;
688 else
689 ciphers = ssl->cipher_list;
690 if (ciphers) {
691 for (int i = 0; i < sk_SSL_CIPHER_num(ciphers); ++i) {
692 SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i);
693 if (c != NULL) {
e1f72a8b 694 if (!clientRequestedCiphers.empty())
d620ae0e
CT
695 clientRequestedCiphers.append(":");
696 clientRequestedCiphers.append(c->name);
697 }
698 }
699 }
700 debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers);
701
702 if (sslVersion >=3 && ssl->s3 && ssl->s3->client_random[0]) {
703 memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE);
704 }
705
706#if 0 /* XXX: OpenSSL 0.9.8k lacks at least some of these tlsext_* fields */
707 //The following extracted for logging purpuses:
708 // TLSEXT_TYPE_ec_point_formats
709 unsigned char *p;
710 int len;
711 if (ssl->server) {
712 p = ssl->session->tlsext_ecpointformatlist;
713 len = ssl->session->tlsext_ecpointformatlist_length;
714 } else {
715 p = ssl->tlsext_ecpointformatlist;
716 len = ssl->tlsext_ecpointformatlist_length;
717 }
718 if (p) {
719 ecPointFormatList = objToString(p, len);
720 debugs(83, 7, "tlsExtension ecPointFormatList of length " << len << " :" << ecPointFormatList);
721 }
722
723 // TLSEXT_TYPE_elliptic_curves
724 if (ssl->server) {
725 p = ssl->session->tlsext_ellipticcurvelist;
726 len = ssl->session->tlsext_ellipticcurvelist_length;
727 } else {
728 p = ssl->tlsext_ellipticcurvelist;
729 len = ssl->tlsext_ellipticcurvelist_length;
730 }
731 if (p) {
732 ellipticCurves = objToString(p, len);
733 debugs(83, 7, "tlsExtension ellipticCurveList of length " << len <<" :" << ellipticCurves);
734 }
735 // TLSEXT_TYPE_opaque_prf_input
736 p = NULL;
737 if (ssl->server) {
738 if (ssl->s3 && ssl->s3->client_opaque_prf_input) {
739 p = (unsigned char *)ssl->s3->client_opaque_prf_input;
740 len = ssl->s3->client_opaque_prf_input_len;
741 }
742 } else {
743 p = (unsigned char *)ssl->tlsext_opaque_prf_input;
744 len = ssl->tlsext_opaque_prf_input_len;
745 }
746 if (p) {
747 debugs(83, 7, "tlsExtension client-opaque-prf-input of length " << len);
748 opaquePrf = objToString(p, len);
749 }
750#endif
751 return true;
752}
753
754bool
755Ssl::Bio::sslFeatures::get(const unsigned char *hello)
756{
757 // The SSL handshake message should starts with a 0x16 byte
758 if (hello[0] == 0x16) {
759 return parseV3Hello(hello);
8693472e 760#if defined(DO_SSLV23)
d620ae0e
CT
761 } else if ((hello[0] & 0x80) && hello[2] == 0x01 && hello[3] == 0x03) {
762 return parseV23Hello(hello);
763#endif
764 }
e1f72a8b 765
d620ae0e
CT
766 debugs(83, 7, "Not a known SSL handshake message");
767 return false;
768}
769
770bool
771Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *hello)
772{
773 debugs(83, 7, "Get fake features from v3 hello message.");
774 // The SSL version exist in the 2nd and 3rd bytes
775 sslVersion = (hello[1] << 8) | hello[2];
776 debugs(83, 7, "Get fake features. Version :" << std::hex << std::setw(8) << std::setfill('0')<< sslVersion);
777
778 // The following hello message size exist in 4th and 5th bytes
779 int helloSize = (hello[3] << 8) | hello[4];
780 helloSize += 5; //Include the 5 header bytes.
8693472e 781 helloMessage.clear();
7f4e9b73 782 helloMessage.append((const char *)hello, helloSize);
d620ae0e
CT
783
784 //For SSLv3 or TLSv1.* protocols we can get some more informations
785 if (hello[1] == 0x3 && hello[5] == 0x1 /*HELLO A message*/) {
786 // Get the correct version of the sub-hello message
787 sslVersion = (hello[9] << 8) | hello[10];
788 //Get Client Random number. It starts on the position 11 of hello message
789 memcpy(client_random, hello + 11, SSL3_RANDOM_SIZE);
790 debugs(83, 7, "Client random: " << objToString(client_random, SSL3_RANDOM_SIZE));
791
792 // At the position 43 (11+SSL3_RANDOM_SIZE)
793 int sessIDLen = (int)hello[43];
794 debugs(83, 7, "Session ID Length: " << sessIDLen);
795
796 //Ciphers list. It is stored after the Session ID.
797 const unsigned char *ciphers = hello + 44 + sessIDLen;
798 int ciphersLen = (ciphers[0] << 8) | ciphers[1];
799 ciphers += 2;
800 if (ciphersLen) {
801 const SSL_METHOD *method = SSLv3_method();
802 int cs = method->put_cipher_by_char(NULL, NULL);
803 assert(cs > 0);
804 for (int i = 0; i < ciphersLen; i += cs) {
805 const SSL_CIPHER *c = method->get_cipher_by_char((ciphers + i));
806 if (c != NULL) {
e1f72a8b 807 if (!clientRequestedCiphers.empty())
d620ae0e
CT
808 clientRequestedCiphers.append(":");
809 clientRequestedCiphers.append(c->name);
7f4e9b73
CT
810 } else
811 unknownCiphers = true;
d620ae0e
CT
812 }
813 }
814 debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers);
815
816 // Compression field: 1 bytes the number of compression methods and
817 // 1 byte for each compression method
818 const unsigned char *compression = ciphers + ciphersLen;
819 if (compression[0] > 1)
820 compressMethod = 1;
821 else
822 compressMethod = 0;
823 debugs(83, 7, "SSL compression methods number: " << (int)compression[0]);
824
7f4e9b73 825 const unsigned char *pToExtensions = compression + 1 + (int)compression[0];
e1f72a8b 826 if (pToExtensions < hello + helloSize) {
7f4e9b73
CT
827 int extensionsLen = (pToExtensions[0] << 8) | pToExtensions[1];
828 const unsigned char *ext = pToExtensions + 2;
e1f72a8b 829 while (ext < pToExtensions + extensionsLen) {
d620ae0e
CT
830 short extType = (ext[0] << 8) | ext[1];
831 ext += 2;
832 short extLen = (ext[0] << 8) | ext[1];
833 ext += 2;
834 debugs(83, 7, "SSL Exntension: " << std::hex << extType << " of size:" << extLen);
835 //The SNI extension has the type 0 (extType == 0)
836 // The two first bytes indicates the length of the SNI data (should be extLen-2)
837 // The next byte is the hostname type, it should be '0' for normal hostname (ext[2] == 0)
838 // The 3rd and 4th bytes are the length of the hostname
839 if (extType == 0 && ext[2] == 0) {
840 int hostLen = (ext[3] << 8) | ext[4];
841 serverName.assign((const char *)(ext+5), hostLen);
842 debugs(83, 7, "Found server name: " << serverName);
7f4e9b73
CT
843 } else if (extType == 15 && ext[0] != 0) {
844 // The heartBeats are the type 15
845 doHeartBeats = true;
846 } else
847 extensions.push_back(extType);
e1f72a8b 848
d620ae0e
CT
849 ext += extLen;
850 }
851 }
852 }
853 return true;
854}
855
856bool
857Ssl::Bio::sslFeatures::parseV23Hello(const unsigned char *hello)
858{
8693472e 859#if defined(DO_SSLV23)
d620ae0e
CT
860 debugs(83, 7, "Get fake features from v23 hello message.");
861 sslVersion = (hello[3] << 8) | hello[4];
862 debugs(83, 7, "Get fake features. Version :" << std::hex << std::setw(8) << std::setfill('0')<< sslVersion);
863
864 // The following hello message size exist in 2nd byte
865 int helloSize = hello[1];
866 helloSize += 2; //Include the 2 header bytes.
8693472e 867 helloMessage.clear();
7f4e9b73 868 helloMessage.append((char *)hello, helloSize);
d620ae0e
CT
869
870 //Ciphers list. It is stored after the Session ID.
871
872 int ciphersLen = (hello[5] << 8) | hello[6];
873 const unsigned char *ciphers = hello + 11;
874 if (ciphersLen) {
875 const SSL_METHOD *method = SSLv23_method();
876 int cs = method->put_cipher_by_char(NULL, NULL);
877 assert(cs > 0);
878 for (int i = 0; i < ciphersLen; i += cs) {
879 // The v2 hello messages cipher has 3 bytes.
880 // The v2 cipher has the first byte not null
e1f72a8b 881 // Because we are going to sent only v3 message we
d620ae0e
CT
882 // are ignoring these ciphers
883 if (ciphers[i] != 0)
884 continue;
885 const SSL_CIPHER *c = method->get_cipher_by_char((ciphers + i + 1));
886 if (c != NULL) {
e1f72a8b 887 if (!clientRequestedCiphers.empty())
d620ae0e
CT
888 clientRequestedCiphers.append(":");
889 clientRequestedCiphers.append(c->name);
890 }
891 }
892 }
e1f72a8b 893 debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers);
d620ae0e
CT
894
895 //Get Client Random number. It starts on the position 11 of hello message
896 memcpy(client_random, ciphers + ciphersLen, SSL3_RANDOM_SIZE);
897 debugs(83, 7, "Client random: " << objToString(client_random, SSL3_RANDOM_SIZE));
898
899 compressMethod = 0;
900 return true;
901#else
902 return false;
903#endif
904}
905
a95989ed
CT
906void
907Ssl::Bio::sslFeatures::applyToSSL(SSL *ssl) const
908{
909 // To increase the possibility for bumping after peek mode selection or
e1f72a8b 910 // splicing after stare mode selection it is good to set the
a95989ed
CT
911 // SSL protocol version.
912 // The SSL_set_ssl_method is not the correct method because it will strict
913 // SSL version which can be used to the SSL version used for client hello message.
e1f72a8b 914 // For example will prevent comunnicating with a tls1.0 server if the
a95989ed
CT
915 // client sent and tlsv1.2 Hello message.
916 //SSL_set_ssl_method(ssl, Ssl::method(features.toSquidSSLVersion()));
8693472e
CT
917#if defined(TLSEXT_NAMETYPE_host_name)
918 if (!serverName.isEmpty()) {
a95989ed 919 SSL_set_tlsext_host_name(ssl, serverName.c_str());
8693472e 920 }
a95989ed
CT
921#endif
922 if (!clientRequestedCiphers.empty())
923 SSL_set_cipher_list(ssl, clientRequestedCiphers.c_str());
8693472e 924#if defined(SSL_OP_NO_COMPRESSION) /* XXX: OpenSSL 0.9.8k lacks SSL_OP_NO_COMPRESSION */
a95989ed
CT
925 if (compressMethod == 0)
926 SSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
927#endif
928
929}
930
d620ae0e
CT
931std::ostream &
932Ssl::Bio::sslFeatures::print(std::ostream &os) const
933{
934 static std::string buf;
e1f72a8b 935 return os << "v" << sslVersion <<
40f1e76d 936 " SNI:" << (serverName.isEmpty() ? SBuf("-") : serverName) <<
e1f72a8b
CT
937 " comp:" << compressMethod <<
938 " Ciphers:" << clientRequestedCiphers <<
939 " Random:" << objToString(client_random, SSL3_RANDOM_SIZE) <<
940 " ecPointFormats:" << ecPointFormatList <<
941 " ec:" << ellipticCurves <<
942 " opaquePrf:" << opaquePrf;
d620ae0e
CT
943}
944
b3a8ae1b 945#endif /* USE_SSL */
f53969cc 946