]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/bio.cc
Refactored and probably sped up ServerBio reading.
[thirdparty/squid.git] / src / ssl / bio.cc
1 /*
2 * Copyright (C) 1996-2016 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 "ssl/support.h"
13
14 /* support.cc says this is needed */
15 #if USE_OPENSSL
16
17 #include "comm.h"
18 #include "fd.h"
19 #include "fde.h"
20 #include "globals.h"
21 #include "ip/Address.h"
22 #include "parser/BinaryTokenizer.h"
23 #include "ssl/bio.h"
24
25 #if HAVE_OPENSSL_SSL_H
26 #include <openssl/ssl.h>
27 #endif
28
29 #if _SQUID_WINDOWS_
30 extern int socket_read_method(int, char *, int);
31 extern int socket_write_method(int, const char *, int);
32 #endif
33
34 /* BIO callbacks */
35 static int squid_bio_write(BIO *h, const char *buf, int num);
36 static int squid_bio_read(BIO *h, char *buf, int size);
37 static int squid_bio_puts(BIO *h, const char *str);
38 //static int squid_bio_gets(BIO *h, char *str, int size);
39 static long squid_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
40 static int squid_bio_create(BIO *h);
41 static int squid_bio_destroy(BIO *data);
42 /* SSL callbacks */
43 static 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.
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 };
59
60 /* Ssl:Bio */
61
62 BIO *
63 Ssl::Bio::Create(const int fd, Ssl::Bio::Type type)
64 {
65 if (BIO *bio = BIO_new(&SquidMethods)) {
66 BIO_int_ctrl(bio, BIO_C_SET_FD, type, fd);
67 return bio;
68 }
69 return NULL;
70 }
71
72 void
73 Ssl::Bio::Link(SSL *ssl, BIO *bio)
74 {
75 SSL_set_bio(ssl, bio, bio); // cannot fail
76 SSL_set_info_callback(ssl, &squid_ssl_info); // does not provide diagnostic
77 }
78
79 Ssl::Bio::Bio(const int anFd): fd_(anFd)
80 {
81 debugs(83, 7, "Bio constructed, this=" << this << " FD " << fd_);
82 }
83
84 Ssl::Bio::~Bio()
85 {
86 debugs(83, 7, "Bio destructing, this=" << this << " FD " << fd_);
87 }
88
89 int Ssl::Bio::write(const char *buf, int size, BIO *table)
90 {
91 errno = 0;
92 #if _SQUID_WINDOWS_
93 const int result = socket_write_method(fd_, buf, size);
94 #else
95 const int result = default_write_method(fd_, buf, size);
96 #endif
97 const int xerrno = errno;
98 debugs(83, 5, "FD " << fd_ << " wrote " << result << " <= " << size);
99
100 BIO_clear_retry_flags(table);
101 if (result < 0) {
102 const bool ignoreError = ignoreErrno(xerrno) != 0;
103 debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError);
104 if (ignoreError)
105 BIO_set_retry_write(table);
106 }
107
108 return result;
109 }
110
111 int
112 Ssl::Bio::read(char *buf, int size, BIO *table)
113 {
114 errno = 0;
115 #if _SQUID_WINDOWS_
116 const int result = socket_read_method(fd_, buf, size);
117 #else
118 const int result = default_read_method(fd_, buf, size);
119 #endif
120 const int xerrno = errno;
121 debugs(83, 5, "FD " << fd_ << " read " << result << " <= " << size);
122
123 BIO_clear_retry_flags(table);
124 if (result < 0) {
125 const bool ignoreError = ignoreErrno(xerrno) != 0;
126 debugs(83, 5, "error: " << xerrno << " ignored: " << ignoreError);
127 if (ignoreError)
128 BIO_set_retry_read(table);
129 }
130
131 return result;
132 }
133
134 /// Called whenever the SSL connection state changes, an alert appears, or an
135 /// error occurs. See SSL_set_info_callback().
136 void
137 Ssl::Bio::stateChanged(const SSL *ssl, int where, int ret)
138 {
139 // Here we can use (where & STATE) to check the current state.
140 // Many STATE values are possible, including: SSL_CB_CONNECT_LOOP,
141 // SSL_CB_ACCEPT_LOOP, SSL_CB_HANDSHAKE_START, and SSL_CB_HANDSHAKE_DONE.
142 // For example:
143 // if (where & SSL_CB_HANDSHAKE_START)
144 // debugs(83, 9, "Trying to establish the SSL connection");
145 // else if (where & SSL_CB_HANDSHAKE_DONE)
146 // debugs(83, 9, "SSL connection established");
147
148 debugs(83, 7, "FD " << fd_ << " now: 0x" << std::hex << where << std::dec << ' ' <<
149 SSL_state_string(ssl) << " (" << SSL_state_string_long(ssl) << ")");
150 }
151
152 bool
153 Ssl::ClientBio::isClientHello(int state)
154 {
155 return (
156 state == SSL3_ST_SR_CLNT_HELLO_A ||
157 state == SSL23_ST_SR_CLNT_HELLO_A ||
158 state == SSL23_ST_SR_CLNT_HELLO_B ||
159 state == SSL3_ST_SR_CLNT_HELLO_B ||
160 state == SSL3_ST_SR_CLNT_HELLO_C
161 );
162 }
163
164 void
165 Ssl::ClientBio::stateChanged(const SSL *ssl, int where, int ret)
166 {
167 Ssl::Bio::stateChanged(ssl, where, ret);
168 }
169
170 int
171 Ssl::ClientBio::write(const char *buf, int size, BIO *table)
172 {
173 if (holdWrite_) {
174 BIO_set_retry_write(table);
175 return 0;
176 }
177
178 return Ssl::Bio::write(buf, size, table);
179 }
180
181 int
182 Ssl::ClientBio::read(char *buf, int size, BIO *table)
183 {
184 if (holdRead_) {
185 debugs(83, 7, "Hold flag is set, retry latter. (Hold " << size << "bytes)");
186 BIO_set_retry_read(table);
187 return -1;
188 }
189
190 if (!rbuf.isEmpty()) {
191 int bytes = (size <= (int)rbuf.length() ? size : rbuf.length());
192 memcpy(buf, rbuf.rawContent(), bytes);
193 rbuf.consume(bytes);
194 return bytes;
195 } else
196 return Ssl::Bio::read(buf, size, table);
197
198 return -1;
199 }
200
201 void
202 Ssl::ServerBio::stateChanged(const SSL *ssl, int where, int ret)
203 {
204 Ssl::Bio::stateChanged(ssl, where, ret);
205 }
206
207 void
208 Ssl::ServerBio::setClientFeatures(Security::TlsDetails::Pointer const &details, SBuf const &aHello)
209 {
210 clientTlsDetails = details;
211 clientHelloMessage = aHello;
212 };
213
214 int
215 Ssl::ServerBio::read(char *buf, int size, BIO *table)
216 {
217 if (!parser_.parseDone && !parser_.parseError) // not done parsing yet
218 return readAndParse(buf, size, table);
219 else
220 return readAndGive(buf, size, table);
221 }
222
223 /// Read and give everything to OpenSSL.
224 int
225 Ssl::ServerBio::readAndGive(char *buf, const int size, BIO *table)
226 {
227 // If we have unused buffered bytes, give those bytes to OpenSSL now,
228 // before reading more. TODO: Read if we have buffered less than size?
229 if (rbufConsumePos < rbuf.length())
230 return giveBuffered(buf, size);
231
232 if (record_) {
233 const int result = readAndBuffer(table);
234 if (result <= 0)
235 return result;
236 return giveBuffered(buf, size);
237 }
238
239 return Ssl::Bio::read(buf, size, table);
240 }
241
242 /// Read and give everything to our parser.
243 /// When/if parsing is done, start giving to OpenSSL.
244 int
245 Ssl::ServerBio::readAndParse(char *buf, const int size, BIO *table)
246 {
247 const int result = readAndBuffer(table);
248 if (result <= 0)
249 return result;
250
251 if (!parser_.parseServerHello(rbuf)) {
252 if (!parser_.parseError) {
253 BIO_set_retry_read(table);
254 return -1;
255 }
256 debugs(83, DBG_IMPORTANT, "ERROR: Failed to parse SSL Server Hello Message"); // XXX: move to catch{}
257 }
258
259 Must(parser_.parseDone || parser_.parseError);
260 return giveBuffered(buf, size);
261 }
262
263 /// Reads more data into the read buffer. Returns either the number of bytes
264 /// read or, on errors (including "try again" errors), a negative number.
265 int
266 Ssl::ServerBio::readAndBuffer(BIO *table)
267 {
268 char *space = rbuf.rawSpace(SQUID_TCP_SO_RCVBUF);
269 const int result = Ssl::Bio::read(space, rbuf.spaceSize(), table);
270 if (result <= 0)
271 return result;
272
273 rbuf.forceSize(rbuf.length() + result);
274 return result;
275 }
276
277 /// give previously buffered bytes to OpenSSL
278 /// returns the number of bytes given
279 int
280 Ssl::ServerBio::giveBuffered(char *buf, const int size)
281 {
282 if (rbuf.length() <= rbufConsumePos)
283 return -1; // buffered nothing yet
284
285 const int unsent = rbuf.length() - rbufConsumePos;
286 const int bytes = (size <= unsent ? size : unsent);
287 memcpy(buf, rbuf.rawContent() + rbufConsumePos, bytes);
288 rbufConsumePos += bytes;
289 debugs(83, 7, bytes << "<=" << size << " bytes to OpenSSL");
290 return bytes;
291 }
292
293 // This function makes the required checks to examine if the client hello
294 // message is compatible with the features provided by OpenSSL toolkit.
295 // If the features are compatible and can be supported it tries to rewrite SSL
296 // structure members, to replace the hello message created by openSSL, with the
297 // web client SSL hello message.
298 // This is mostly possible in the cases where the web client uses openSSL
299 // library similar with this one used by squid.
300 static bool
301 adjustSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, SBuf &helloMessage)
302 {
303 #if SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK
304 if (!ssl->s3) {
305 debugs(83, 5, "No SSLv3 data found!");
306 return false;
307 }
308
309 // If the client supports compression but our context does not support
310 // we can not adjust.
311 #if !defined(OPENSSL_NO_COMP)
312 const bool requireCompression = (details->compressMethod && ssl->ctx->comp_methods == NULL);
313 #else
314 const bool requireCompression = details->compressMethod;
315 #endif
316 if (requireCompression) {
317 debugs(83, 5, "Client Hello Data supports compression, but we do not!");
318 return false;
319 }
320
321 // Check ciphers list
322 for (auto cipherId: details->ciphers) {
323 bool found = false;
324 STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl);
325 for (int i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
326 SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
327 const long cid = SSL_CIPHER_get_id(c);
328 if (cipherId == (0xFFFF & cid)) {
329 found = true;
330 break;
331 }
332 }
333 if (!found) {
334 debugs(83, 5, "Client Hello Data supports cipher '"<< cipherId <<"' but we do not support it!");
335 return false;
336 }
337 }
338
339 #if !defined(SSL_TLSEXT_HB_ENABLED)
340 if (details->doHeartBeats) {
341 debugs(83, 5, "Client Hello Data supports HeartBeats but we do not support!");
342 return false;
343 }
344 #endif
345
346 for (std::list<uint16_t>::iterator it = details->extensions.begin(); it != details->extensions.end(); ++it) {
347 static int supportedExtensions[] = {
348 #if defined(TLSEXT_TYPE_server_name)
349 TLSEXT_TYPE_server_name,
350 #endif
351 #if defined(TLSEXT_TYPE_opaque_prf_input)
352 TLSEXT_TYPE_opaque_prf_input,
353 #endif
354 #if defined(TLSEXT_TYPE_heartbeat)
355 TLSEXT_TYPE_heartbeat,
356 #endif
357 #if defined(TLSEXT_TYPE_renegotiate)
358 TLSEXT_TYPE_renegotiate,
359 #endif
360 #if defined(TLSEXT_TYPE_ec_point_formats)
361 TLSEXT_TYPE_ec_point_formats,
362 #endif
363 #if defined(TLSEXT_TYPE_elliptic_curves)
364 TLSEXT_TYPE_elliptic_curves,
365 #endif
366 #if defined(TLSEXT_TYPE_session_ticket)
367 TLSEXT_TYPE_session_ticket,
368 #endif
369 #if defined(TLSEXT_TYPE_status_request)
370 TLSEXT_TYPE_status_request,
371 #endif
372 #if defined(TLSEXT_TYPE_use_srtp)
373 TLSEXT_TYPE_use_srtp,
374 #endif
375 #if 0 //Allow 13172 Firefox supported extension for testing purposes
376 13172,
377 #endif
378 -1
379 };
380 bool found = false;
381 for (int i = 0; supportedExtensions[i] != -1; i++) {
382 if (*it == supportedExtensions[i]) {
383 found = true;
384 break;
385 }
386 }
387 if (!found) {
388 debugs(83, 5, "Extension " << *it << " does not supported!");
389 return false;
390 }
391 }
392
393 SSL3_BUFFER *wb=&(ssl->s3->wbuf);
394 if (wb->len < (size_t)helloMessage.length())
395 return false;
396
397 debugs(83, 5, "OpenSSL SSL struct will be adjusted to mimic client hello data!");
398
399 //Adjust ssl structure data.
400 // We need to fix the random in SSL struct:
401 if (details->clientRandom.length() == SSL3_RANDOM_SIZE)
402 memcpy(ssl->s3->client_random, details->clientRandom.c_str(), SSL3_RANDOM_SIZE);
403 memcpy(wb->buf, helloMessage.rawContent(), helloMessage.length());
404 wb->left = helloMessage.length();
405
406 size_t mainHelloSize = helloMessage.length() - 5;
407 const char *mainHello = helloMessage.rawContent() + 5;
408 assert((size_t)ssl->init_buf->max > mainHelloSize);
409 memcpy(ssl->init_buf->data, mainHello, mainHelloSize);
410 debugs(83, 5, "Hello Data init and adjustd sizes :" << ssl->init_num << " = "<< mainHelloSize);
411 ssl->init_num = mainHelloSize;
412 ssl->s3->wpend_ret = mainHelloSize;
413 ssl->s3->wpend_tot = mainHelloSize;
414 return true;
415 #else
416 return false;
417 #endif
418 }
419
420 int
421 Ssl::ServerBio::write(const char *buf, int size, BIO *table)
422 {
423
424 if (holdWrite_) {
425 debugs(83, 7, "postpone writing " << size << " bytes to SSL FD " << fd_);
426 BIO_set_retry_write(table);
427 return -1;
428 }
429
430 if (!helloBuild && (bumpMode_ == Ssl::bumpPeek || bumpMode_ == Ssl::bumpStare)) {
431 if (
432 buf[1] >= 3 //it is an SSL Version3 message
433 && buf[0] == 0x16 // and it is a Handshake/Hello message
434 ) {
435
436 //Hello message is the first message we write to server
437 assert(helloMsg.isEmpty());
438
439 auto ssl = fd_table[fd_].ssl.get();
440 if (ssl) {
441 if (bumpMode_ == Ssl::bumpPeek) {
442 if (adjustSSL(ssl, clientTlsDetails, clientHelloMessage))
443 allowBump = true;
444 allowSplice = true;
445 helloMsg.append(clientHelloMessage);
446 debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted for peek mode");
447 } else { /*Ssl::bumpStare*/
448 allowBump = true;
449 if (adjustSSL(ssl, clientTlsDetails, clientHelloMessage)) {
450 allowSplice = true;
451 helloMsg.append(clientHelloMessage);
452 debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted for stare mode");
453 }
454 }
455 }
456 }
457 // If we do not build any hello message, copy the current
458 if (helloMsg.isEmpty())
459 helloMsg.append(buf, size);
460
461 helloBuild = true;
462 helloMsgSize = helloMsg.length();
463 //allowBump = true;
464
465 if (allowSplice) {
466 // Do not write yet.....
467 BIO_set_retry_write(table);
468 return -1;
469 }
470 }
471
472 if (!helloMsg.isEmpty()) {
473 debugs(83, 7, "buffered write for FD " << fd_);
474 int ret = Ssl::Bio::write(helloMsg.rawContent(), helloMsg.length(), table);
475 helloMsg.consume(ret);
476 if (!helloMsg.isEmpty()) {
477 // We need to retry sendind data.
478 // Say to openSSL to retry sending hello message
479 BIO_set_retry_write(table);
480 return -1;
481 }
482
483 // Sending hello message complete. Do not send more data for now...
484 holdWrite_ = true;
485
486 // spoof openSSL that we write what it ask us to write
487 return size;
488 } else
489 return Ssl::Bio::write(buf, size, table);
490 }
491
492 void
493 Ssl::ServerBio::flush(BIO *table)
494 {
495 if (!helloMsg.isEmpty()) {
496 int ret = Ssl::Bio::write(helloMsg.rawContent(), helloMsg.length(), table);
497 helloMsg.consume(ret);
498 }
499 }
500
501 bool
502 Ssl::ServerBio::resumingSession()
503 {
504 return parser_.ressumingSession;
505 }
506
507
508 /// initializes BIO table after allocation
509 static int
510 squid_bio_create(BIO *bi)
511 {
512 bi->init = 0; // set when we store Bio object and socket fd (BIO_C_SET_FD)
513 bi->num = 0;
514 bi->ptr = NULL;
515 bi->flags = 0;
516 return 1;
517 }
518
519 /// cleans BIO table before deallocation
520 static int
521 squid_bio_destroy(BIO *table)
522 {
523 delete static_cast<Ssl::Bio*>(table->ptr);
524 table->ptr = NULL;
525 return 1;
526 }
527
528 /// wrapper for Bio::write()
529 static int
530 squid_bio_write(BIO *table, const char *buf, int size)
531 {
532 Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
533 assert(bio);
534 return bio->write(buf, size, table);
535 }
536
537 /// wrapper for Bio::read()
538 static int
539 squid_bio_read(BIO *table, char *buf, int size)
540 {
541 Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
542 assert(bio);
543 return bio->read(buf, size, table);
544 }
545
546 /// implements puts() via write()
547 static int
548 squid_bio_puts(BIO *table, const char *str)
549 {
550 assert(str);
551 return squid_bio_write(table, str, strlen(str));
552 }
553
554 /// other BIO manipulations (those without dedicated callbacks in BIO table)
555 static long
556 squid_bio_ctrl(BIO *table, int cmd, long arg1, void *arg2)
557 {
558 debugs(83, 5, table << ' ' << cmd << '(' << arg1 << ", " << arg2 << ')');
559
560 switch (cmd) {
561 case BIO_C_SET_FD: {
562 assert(arg2);
563 const int fd = *static_cast<int*>(arg2);
564 Ssl::Bio *bio;
565 if (arg1 == Ssl::Bio::BIO_TO_SERVER)
566 bio = new Ssl::ServerBio(fd);
567 else
568 bio = new Ssl::ClientBio(fd);
569 assert(!table->ptr);
570 table->ptr = bio;
571 table->init = 1;
572 return 0;
573 }
574
575 case BIO_C_GET_FD:
576 if (table->init) {
577 Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
578 assert(bio);
579 if (arg2)
580 *static_cast<int*>(arg2) = bio->fd();
581 return bio->fd();
582 }
583 return -1;
584
585 case BIO_CTRL_DUP:
586 // Should implemented if the SSL_dup openSSL API function
587 // used anywhere in squid.
588 return 0;
589
590 case BIO_CTRL_FLUSH:
591 if (table->init) {
592 Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr);
593 assert(bio);
594 bio->flush(table);
595 return 1;
596 }
597 return 0;
598
599 /* we may also need to implement these:
600 case BIO_CTRL_RESET:
601 case BIO_C_FILE_SEEK:
602 case BIO_C_FILE_TELL:
603 case BIO_CTRL_INFO:
604 case BIO_CTRL_GET_CLOSE:
605 case BIO_CTRL_SET_CLOSE:
606 case BIO_CTRL_PENDING:
607 case BIO_CTRL_WPENDING:
608 */
609 default:
610 return 0;
611
612 }
613
614 return 0; /* NOTREACHED */
615 }
616
617 /// wrapper for Bio::stateChanged()
618 static void
619 squid_ssl_info(const SSL *ssl, int where, int ret)
620 {
621 if (BIO *table = SSL_get_rbio(ssl)) {
622 if (Ssl::Bio *bio = static_cast<Ssl::Bio*>(table->ptr))
623 bio->stateChanged(ssl, where, ret);
624 }
625 }
626
627
628 void
629 applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode)
630 {
631 // To increase the possibility for bumping after peek mode selection or
632 // splicing after stare mode selection it is good to set the
633 // SSL protocol version.
634 // The SSL_set_ssl_method is not the correct method because it will strict
635 // SSL version which can be used to the SSL version used for client hello message.
636 // For example will prevent comunnicating with a tls1.0 server if the
637 // client sent and tlsv1.2 Hello message.
638 #if defined(TLSEXT_NAMETYPE_host_name)
639 if (!details->serverName.isEmpty()) {
640 SSL_set_tlsext_host_name(ssl, details->serverName.c_str());
641 }
642 #endif
643
644 if (!details->ciphers.empty()) {
645 SBuf strCiphers;
646 for (auto cipherId: details->ciphers) {
647 unsigned char cbytes[3];
648 cbytes[0] = (cipherId >> 8) & 0xFF;
649 cbytes[1] = cipherId & 0xFF;
650 cbytes[2] = 0;
651 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
652 const SSL_METHOD *method = TLS_method();
653 #else
654 const SSL_METHOD *method = SSLv23_method();
655 #endif
656 const SSL_CIPHER *c = method->get_cipher_by_char(cbytes);
657 if (c != NULL) {
658 if (!strCiphers.isEmpty())
659 strCiphers.append(":");
660 strCiphers.append(c->name);
661 }
662 }
663 if (!strCiphers.isEmpty())
664 SSL_set_cipher_list(ssl, strCiphers.c_str());
665 }
666
667 #if defined(SSL_OP_NO_COMPRESSION) /* XXX: OpenSSL 0.9.8k lacks SSL_OP_NO_COMPRESSION */
668 if (details->compressMethod == 0)
669 SSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
670 #endif
671
672 #if defined(TLSEXT_STATUSTYPE_ocsp)
673 if (details->tlsStatusRequest)
674 SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
675 #endif
676
677 #if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
678 if (!details->tlsAppLayerProtoNeg.isEmpty()) {
679 if (bumpMode == Ssl::bumpPeek)
680 SSL_set_alpn_protos(ssl, (const unsigned char*)details->tlsAppLayerProtoNeg.rawContent(), tlsAppLayerProtoNeg.length());
681 else {
682 static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
683 SSL_set_alpn_protos(ssl, supported_protos, sizeof(supported_protos));
684 }
685 }
686 #endif
687 }
688
689 #endif // USE_OPENSSL