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