2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 83 SSL accelerator support */
12 #include "ssl/support.h"
14 /* support.cc says this is needed */
21 #include "ip/Address.h"
24 #if HAVE_OPENSSL_SSL_H
25 #include <openssl/ssl.h>
29 extern int socket_read_method(int, char *, int);
30 extern int socket_write_method(int, const char *, int);
34 static int squid_bio_write(BIO
*h
, const char *buf
, int num
);
35 static int squid_bio_read(BIO
*h
, char *buf
, int size
);
36 static int squid_bio_puts(BIO
*h
, const char *str
);
37 //static int squid_bio_gets(BIO *h, char *str, int size);
38 static long squid_bio_ctrl(BIO
*h
, int cmd
, long arg1
, void *arg2
);
39 static int squid_bio_create(BIO
*h
);
40 static int squid_bio_destroy(BIO
*data
);
42 static void squid_ssl_info(const SSL
*ssl
, int where
, int ret
);
44 /// Initialization structure for the BIO table with
45 /// Squid-specific methods and BIO method wrappers.
46 static BIO_METHOD SquidMethods
= {
52 NULL
, // squid_bio_gets not supported
56 NULL
// squid_callback_ctrl not supported
62 BinaryTokenizer::BinaryTokenizer(): BinaryTokenizer(SBuf())
66 BinaryTokenizer::BinaryTokenizer(const SBuf
&data
):
74 /// debugging helper that prints a "standard" debugs() trailer
75 #define BinaryTokenizer_tail(size, start) \
76 " occupying " << (size) << " bytes @" << (start) << " in " << this;
78 /// logs and throws if fewer than size octets remain; no other side effects
80 BinaryTokenizer::want(uint64_t size
, const char *description
) const
82 if (parsed_
+ size
> data_
.length()) {
83 debugs(83, 5, (parsed_
+ size
- data_
.length()) << " more bytes for " <<
84 context
<< description
<< BinaryTokenizer_tail(size
, parsed_
));
85 throw InsufficientInput();
89 /// debugging helper for parsed number fields
91 BinaryTokenizer::got(uint32_t value
, uint64_t size
, const char *description
) const
93 debugs(83, 7, context
<< description
<< '=' << value
<<
94 BinaryTokenizer_tail(size
, parsed_
- size
));
97 /// debugging helper for parsed areas/blobs
99 BinaryTokenizer::got(const SBuf
&value
, uint64_t size
, const char *description
) const
101 debugs(83, 7, context
<< description
<< '=' <<
102 Raw(nullptr, value
.rawContent(), value
.length()).hex() <<
103 BinaryTokenizer_tail(size
, parsed_
- size
));
107 /// debugging helper for skipped fields
109 BinaryTokenizer::skipped(uint64_t size
, const char *description
) const
111 debugs(83, 7, context
<< description
<< BinaryTokenizer_tail(size
, parsed_
- size
));
115 /// Returns the next ready-for-shift byte, adjusting the number of parsed bytes.
116 /// The larger 32-bit return type helps callers shift/merge octets into numbers.
117 /// This internal method does not perform out-of-bounds checks.
119 BinaryTokenizer::octet()
121 // While char may be signed, we view data characters as unsigned,
122 // which helps to arrive at the right 32-bit return value.
123 return static_cast<uint8_t>(data_
[parsed_
++]);
127 BinaryTokenizer::reset(const SBuf
&data
)
129 *this = BinaryTokenizer(data
);
133 BinaryTokenizer::rollback()
135 parsed_
= syncPoint_
;
139 BinaryTokenizer::commit()
141 if (context
&& *context
)
142 debugs(83, 6, context
<< BinaryTokenizer_tail(parsed_
- syncPoint_
, syncPoint_
));
143 syncPoint_
= parsed_
;
147 BinaryTokenizer::atEnd() const
149 return parsed_
>= data_
.length();
153 BinaryTokenizer::uint8(const char *description
)
155 want(1, description
);
156 const uint8_t result
= octet();
157 got(result
, 1, description
);
162 BinaryTokenizer::uint16(const char *description
)
164 want(2, description
);
165 const uint16_t result
= (octet() << 8) | octet();
166 got(result
, 2, description
);
171 BinaryTokenizer::uint24(const char *description
)
173 want(3, description
);
174 const uint32_t result
= (octet() << 16) | (octet() << 8) | octet();
175 got(result
, 3, description
);
180 BinaryTokenizer::uint32(const char *description
)
182 want(4, description
);
183 const uint32_t result
= (octet() << 24) | (octet() << 16) | (octet() << 8) | octet();
184 got(result
, 4, description
);
189 BinaryTokenizer::area(uint64_t size
, const char *description
)
191 want(size
, description
);
192 const SBuf result
= data_
.substr(parsed_
, size
);
194 got(result
, size
, description
);
199 BinaryTokenizer::skip(uint64_t size
, const char *description
)
201 want(size
, description
);
203 skipped(size
, description
);
209 Ssl::Rfc5246::FieldGroup::FieldGroup(BinaryTokenizer
&tk
, const char *description
) {
210 tk
.context
= description
;
214 Ssl::Rfc5246::FieldGroup::commit(BinaryTokenizer
&tk
) {
220 Ssl::Rfc5246::ProtocolVersion::ProtocolVersion(BinaryTokenizer
&tk
):
221 vMajor(tk
.uint8(".vMajor")),
222 vMinor(tk
.uint8(".vMinor"))
226 Ssl::Rfc5246::TLSPlaintext::TLSPlaintext(BinaryTokenizer
&tk
):
227 FieldGroup(tk
, "TLSPlaintext"),
228 type(tk
.uint8(".type")),
230 length(tk
.uint16(".length")),
231 fragment(tk
.area(length
, ".fragment"))
236 Ssl::Rfc5246::Handshake::Handshake(BinaryTokenizer
&tk
):
237 FieldGroup(tk
, "Handshake"),
238 msg_type(tk
.uint8(".msg_type")),
239 length(tk
.uint24(".length")),
240 body(tk
.area(length
, ".body"))
245 Ssl::Rfc5246::Alert::Alert(BinaryTokenizer
&tk
):
246 FieldGroup(tk
, "Alert"),
247 level(tk
.uint8(".level")),
248 description(tk
.uint8(".description"))
253 Ssl::Rfc5246::P24String::P24String(BinaryTokenizer
&tk
, const char *description
):
254 FieldGroup(tk
, description
),
255 length(tk
.uint24(".length")),
256 body(tk
.area(length
, ".body"))
264 /// debugging helper to print various parsed records and messages
268 DebugFrame(const char *aName
, uint64_t aType
, uint64_t aSize
):
269 name(aName
), type(aType
), size(aSize
) {}
276 inline std::ostream
&
277 operator <<(std::ostream
&os
, const DebugFrame
&frame
)
279 return os
<< frame
.size
<< "-byte type-" << frame
.type
<< ' ' << frame
.name
;
283 Ssl::Bio::Create(const int fd
, Ssl::Bio::Type type
)
285 if (BIO
*bio
= BIO_new(&SquidMethods
)) {
286 BIO_int_ctrl(bio
, BIO_C_SET_FD
, type
, fd
);
293 Ssl::Bio::Link(SSL
*ssl
, BIO
*bio
)
295 SSL_set_bio(ssl
, bio
, bio
); // cannot fail
296 SSL_set_info_callback(ssl
, &squid_ssl_info
); // does not provide diagnostic
299 Ssl::Bio::Bio(const int anFd
): fd_(anFd
)
301 debugs(83, 7, "Bio constructed, this=" << this << " FD " << fd_
);
306 debugs(83, 7, "Bio destructing, this=" << this << " FD " << fd_
);
309 int Ssl::Bio::write(const char *buf
, int size
, BIO
*table
)
313 const int result
= socket_write_method(fd_
, buf
, size
);
315 const int result
= default_write_method(fd_
, buf
, size
);
317 const int xerrno
= errno
;
318 debugs(83, 5, "FD " << fd_
<< " wrote " << result
<< " <= " << size
);
320 BIO_clear_retry_flags(table
);
322 const bool ignoreError
= ignoreErrno(xerrno
) != 0;
323 debugs(83, 5, "error: " << xerrno
<< " ignored: " << ignoreError
);
325 BIO_set_retry_write(table
);
332 Ssl::Bio::read(char *buf
, int size
, BIO
*table
)
336 const int result
= socket_read_method(fd_
, buf
, size
);
338 const int result
= default_read_method(fd_
, buf
, size
);
340 const int xerrno
= errno
;
341 debugs(83, 5, "FD " << fd_
<< " read " << result
<< " <= " << size
);
343 BIO_clear_retry_flags(table
);
345 const bool ignoreError
= ignoreErrno(xerrno
) != 0;
346 debugs(83, 5, "error: " << xerrno
<< " ignored: " << ignoreError
);
348 BIO_set_retry_read(table
);
355 Ssl::Bio::readAndBuffer(BIO
*table
, const char *description
)
357 char buf
[SQUID_TCP_SO_RCVBUF
];
358 const int bytes
= Ssl::Bio::read(buf
, sizeof(buf
), table
);
359 debugs(83, 5, "read " << bytes
<< " bytes"); // move to Ssl::Bio::read()
362 rbuf
.append(buf
, bytes
);
363 debugs(83, 5, "recorded " << bytes
<< " bytes of " << description
);
368 /// Called whenever the SSL connection state changes, an alert appears, or an
369 /// error occurs. See SSL_set_info_callback().
371 Ssl::Bio::stateChanged(const SSL
*ssl
, int where
, int ret
)
373 // Here we can use (where & STATE) to check the current state.
374 // Many STATE values are possible, including: SSL_CB_CONNECT_LOOP,
375 // SSL_CB_ACCEPT_LOOP, SSL_CB_HANDSHAKE_START, and SSL_CB_HANDSHAKE_DONE.
377 // if (where & SSL_CB_HANDSHAKE_START)
378 // debugs(83, 9, "Trying to establish the SSL connection");
379 // else if (where & SSL_CB_HANDSHAKE_DONE)
380 // debugs(83, 9, "SSL connection established");
382 debugs(83, 7, "FD " << fd_
<< " now: 0x" << std::hex
<< where
<< std::dec
<< ' ' <<
383 SSL_state_string(ssl
) << " (" << SSL_state_string_long(ssl
) << ")");
387 Ssl::ClientBio::isClientHello(int state
)
390 state
== SSL3_ST_SR_CLNT_HELLO_A
||
391 state
== SSL23_ST_SR_CLNT_HELLO_A
||
392 state
== SSL23_ST_SR_CLNT_HELLO_B
||
393 state
== SSL3_ST_SR_CLNT_HELLO_B
||
394 state
== SSL3_ST_SR_CLNT_HELLO_C
399 Ssl::ClientBio::stateChanged(const SSL
*ssl
, int where
, int ret
)
401 Ssl::Bio::stateChanged(ssl
, where
, ret
);
405 Ssl::ClientBio::write(const char *buf
, int size
, BIO
*table
)
408 BIO_set_retry_write(table
);
412 return Ssl::Bio::write(buf
, size
, table
);
416 Ssl::ClientBio::read(char *buf
, int size
, BIO
*table
)
418 if (helloState
< atHelloReceived
) {
419 int bytes
= readAndBuffer(table
, "TLS client Hello");
424 if (helloState
== atHelloNone
) {
425 helloSize
= receivedHelloFeatures_
.parseMsgHead(rbuf
);
426 if (helloSize
== 0) {
427 // Not enough bytes to get hello message size
428 BIO_set_retry_read(table
);
430 } else if (helloSize
< 0) {
431 wrongProtocol
= true;
435 helloState
= atHelloStarted
; //Next state
438 if (helloState
== atHelloStarted
) {
439 debugs(83, 7, "SSL Header: " << Raw(nullptr, rbuf
.rawContent(), rbuf
.length()).hex());
441 if (helloSize
> (int)rbuf
.length()) {
442 BIO_set_retry_read(table
);
445 receivedHelloFeatures_
.get(rbuf
);
446 helloState
= atHelloReceived
;
450 debugs(83, 7, "Hold flag is set, retry latter. (Hold " << size
<< "bytes)");
451 BIO_set_retry_read(table
);
455 if (helloState
== atHelloReceived
) {
456 if (!rbuf
.isEmpty()) {
457 int bytes
= (size
<= (int)rbuf
.length() ? size
: rbuf
.length());
458 memcpy(buf
, rbuf
.rawContent(), bytes
);
462 return Ssl::Bio::read(buf
, size
, table
);
469 Ssl::ServerBio::stateChanged(const SSL
*ssl
, int where
, int ret
)
471 Ssl::Bio::stateChanged(ssl
, where
, ret
);
475 Ssl::ServerBio::setClientFeatures(const Ssl::Bio::sslFeatures
&features
)
477 clientFeatures
= features
;
481 Ssl::ServerBio::readAndBufferServerHelloMsg(BIO
*table
, const char *description
)
484 int ret
= readAndBuffer(table
, description
);
488 if (!parser_
.parseServerHello(rbuf
)) {
489 if (!parser_
.parseError
)
490 BIO_set_retry_read(table
);
498 Ssl::ServerBio::read(char *buf
, int size
, BIO
*table
)
500 if (!parser_
.parseDone
|| record_
) {
501 int ret
= readAndBufferServerHelloMsg(table
, "TLS server Hello");
502 if (!rbuf
.length() && parser_
.parseDone
&& ret
<= 0)
507 debugs(83, 7, "Hold flag is set on ServerBio, retry latter. (Hold " << size
<< "bytes)");
508 BIO_set_retry_read(table
);
512 if (parser_
.parseDone
&& !parser_
.parseError
) {
513 int unsent
= rbuf
.length() - rbufConsumePos
;
515 int bytes
= (size
<= unsent
? size
: unsent
);
516 memcpy(buf
, rbuf
.rawContent() + rbufConsumePos
, bytes
);
517 rbufConsumePos
+= bytes
;
518 debugs(83, 7, "Pass " << bytes
<< " bytes to openSSL as read");
521 return Ssl::Bio::read(buf
, size
, table
);
527 // This function makes the required checks to examine if the client hello
528 // message is compatible with the features provided by OpenSSL toolkit.
529 // If the features are compatible and can be supported it tries to rewrite SSL
530 // structure members, to replace the hello message created by openSSL, with the
531 // web client SSL hello message.
532 // This is mostly possible in the cases where the web client uses openSSL
533 // library similar with this one used by squid.
535 adjustSSL(SSL
*ssl
, Ssl::Bio::sslFeatures
&features
)
537 #if SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK
539 debugs(83, 5, "No SSLv3 data found!");
543 // If the client supports compression but our context does not support
544 // we can not adjust.
545 #if !defined(OPENSSL_NO_COMP)
546 const bool requireCompression
= (features
.compressMethod
&& ssl
->ctx
->comp_methods
== NULL
);
548 const bool requireCompression
= features
.compressMethod
;
550 if (requireCompression
) {
551 debugs(83, 5, "Client Hello Data supports compression, but we do not!");
555 // Check ciphers list
558 while (token
!= std::string::npos
) {
559 end
= features
.clientRequestedCiphers
.find(':',token
);
561 cipher
.assign(features
.clientRequestedCiphers
, token
, end
- token
);
562 token
= (end
!= std::string::npos
? end
+ 1 : std::string::npos
);
564 STACK_OF(SSL_CIPHER
) *cipher_stack
= SSL_get_ciphers(ssl
);
565 for (int i
= 0; i
< sk_SSL_CIPHER_num(cipher_stack
); i
++) {
566 SSL_CIPHER
*c
= sk_SSL_CIPHER_value(cipher_stack
, i
);
567 const char *cname
= SSL_CIPHER_get_name(c
);
568 if (cipher
.compare(cname
)) {
574 debugs(83, 5, "Client Hello Data supports cipher '"<< cipher
<<"' but we do not support it!");
579 #if !defined(SSL_TLSEXT_HB_ENABLED)
580 if (features
.doHeartBeats
) {
581 debugs(83, 5, "Client Hello Data supports HeartBeats but we do not support!");
586 for (std::list
<int>::iterator it
= features
.extensions
.begin(); it
!= features
.extensions
.end(); ++it
) {
587 static int supportedExtensions
[] = {
588 #if defined(TLSEXT_TYPE_server_name)
589 TLSEXT_TYPE_server_name
,
591 #if defined(TLSEXT_TYPE_opaque_prf_input)
592 TLSEXT_TYPE_opaque_prf_input
,
594 #if defined(TLSEXT_TYPE_heartbeat)
595 TLSEXT_TYPE_heartbeat
,
597 #if defined(TLSEXT_TYPE_renegotiate)
598 TLSEXT_TYPE_renegotiate
,
600 #if defined(TLSEXT_TYPE_ec_point_formats)
601 TLSEXT_TYPE_ec_point_formats
,
603 #if defined(TLSEXT_TYPE_elliptic_curves)
604 TLSEXT_TYPE_elliptic_curves
,
606 #if defined(TLSEXT_TYPE_session_ticket)
607 TLSEXT_TYPE_session_ticket
,
609 #if defined(TLSEXT_TYPE_status_request)
610 TLSEXT_TYPE_status_request
,
612 #if defined(TLSEXT_TYPE_use_srtp)
613 TLSEXT_TYPE_use_srtp
,
615 #if 0 //Allow 13172 Firefox supported extension for testing purposes
621 for (int i
= 0; supportedExtensions
[i
] != -1; i
++) {
622 if (*it
== supportedExtensions
[i
]) {
628 debugs(83, 5, "Extension " << *it
<< " does not supported!");
633 SSL3_BUFFER
*wb
=&(ssl
->s3
->wbuf
);
634 if (wb
->len
< (size_t)features
.helloMessage
.length())
637 debugs(83, 5, "OpenSSL SSL struct will be adjusted to mimic client hello data!");
639 //Adjust ssl structure data.
640 // We need to fix the random in SSL struct:
641 memcpy(ssl
->s3
->client_random
, features
.client_random
, SSL3_RANDOM_SIZE
);
642 memcpy(wb
->buf
, features
.helloMessage
.rawContent(), features
.helloMessage
.length());
643 wb
->left
= features
.helloMessage
.length();
645 size_t mainHelloSize
= features
.helloMessage
.length() - 5;
646 const char *mainHello
= features
.helloMessage
.rawContent() + 5;
647 assert((size_t)ssl
->init_buf
->max
> mainHelloSize
);
648 memcpy(ssl
->init_buf
->data
, mainHello
, mainHelloSize
);
649 debugs(83, 5, "Hello Data init and adjustd sizes :" << ssl
->init_num
<< " = "<< mainHelloSize
);
650 ssl
->init_num
= mainHelloSize
;
651 ssl
->s3
->wpend_ret
= mainHelloSize
;
652 ssl
->s3
->wpend_tot
= mainHelloSize
;
660 Ssl::ServerBio::write(const char *buf
, int size
, BIO
*table
)
664 debugs(83, 7, "Hold write, for SSL connection on " << fd_
<< "will not write bytes of size " << size
);
665 BIO_set_retry_write(table
);
669 if (!helloBuild
&& (bumpMode_
== Ssl::bumpPeek
|| bumpMode_
== Ssl::bumpStare
)) {
671 buf
[1] >= 3 //it is an SSL Version3 message
672 && buf
[0] == 0x16 // and it is a Handshake/Hello message
675 //Hello message is the first message we write to server
676 assert(helloMsg
.isEmpty());
678 auto ssl
= fd_table
[fd_
].ssl
.get();
679 if (clientFeatures
.initialized_
&& ssl
) {
680 if (bumpMode_
== Ssl::bumpPeek
) {
681 if (adjustSSL(ssl
, clientFeatures
))
684 helloMsg
.append(clientFeatures
.helloMessage
);
685 debugs(83, 7, "SSL HELLO message for FD " << fd_
<< ": Random number is adjusted for peek mode");
686 } else { /*Ssl::bumpStare*/
688 if (adjustSSL(ssl
, clientFeatures
)) {
690 helloMsg
.append(clientFeatures
.helloMessage
);
691 debugs(83, 7, "SSL HELLO message for FD " << fd_
<< ": Random number is adjusted for stare mode");
696 // If we do not build any hello message, copy the current
697 if (helloMsg
.isEmpty())
698 helloMsg
.append(buf
, size
);
701 helloMsgSize
= helloMsg
.length();
705 // Do not write yet.....
706 BIO_set_retry_write(table
);
711 if (!helloMsg
.isEmpty()) {
712 debugs(83, 7, "buffered write for FD " << fd_
);
713 int ret
= Ssl::Bio::write(helloMsg
.rawContent(), helloMsg
.length(), table
);
714 helloMsg
.consume(ret
);
715 if (!helloMsg
.isEmpty()) {
716 // We need to retry sendind data.
717 // Say to openSSL to retry sending hello message
718 BIO_set_retry_write(table
);
722 // Sending hello message complete. Do not send more data for now...
725 // spoof openSSL that we write what it ask us to write
728 return Ssl::Bio::write(buf
, size
, table
);
732 Ssl::ServerBio::flush(BIO
*table
)
734 if (!helloMsg
.isEmpty()) {
735 int ret
= Ssl::Bio::write(helloMsg
.rawContent(), helloMsg
.length(), table
);
736 helloMsg
.consume(ret
);
741 Ssl::ServerBio::extractHelloFeatures()
743 if (!receivedHelloFeatures_
.initialized_
)
744 receivedHelloFeatures_
.get(rbuf
, false);
748 Ssl::ServerBio::resumingSession()
750 return parser_
.ressumingSession
;
754 /// initializes BIO table after allocation
756 squid_bio_create(BIO
*bi
)
758 bi
->init
= 0; // set when we store Bio object and socket fd (BIO_C_SET_FD)
765 /// cleans BIO table before deallocation
767 squid_bio_destroy(BIO
*table
)
769 delete static_cast<Ssl::Bio
*>(table
->ptr
);
774 /// wrapper for Bio::write()
776 squid_bio_write(BIO
*table
, const char *buf
, int size
)
778 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
);
780 return bio
->write(buf
, size
, table
);
783 /// wrapper for Bio::read()
785 squid_bio_read(BIO
*table
, char *buf
, int size
)
787 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
);
789 return bio
->read(buf
, size
, table
);
792 /// implements puts() via write()
794 squid_bio_puts(BIO
*table
, const char *str
)
797 return squid_bio_write(table
, str
, strlen(str
));
800 /// other BIO manipulations (those without dedicated callbacks in BIO table)
802 squid_bio_ctrl(BIO
*table
, int cmd
, long arg1
, void *arg2
)
804 debugs(83, 5, table
<< ' ' << cmd
<< '(' << arg1
<< ", " << arg2
<< ')');
809 const int fd
= *static_cast<int*>(arg2
);
811 if (arg1
== Ssl::Bio::BIO_TO_SERVER
)
812 bio
= new Ssl::ServerBio(fd
);
814 bio
= new Ssl::ClientBio(fd
);
823 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
);
826 *static_cast<int*>(arg2
) = bio
->fd();
832 // Should implemented if the SSL_dup openSSL API function
833 // used anywhere in squid.
838 Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
);
845 /* we may also need to implement these:
847 case BIO_C_FILE_SEEK:
848 case BIO_C_FILE_TELL:
850 case BIO_CTRL_GET_CLOSE:
851 case BIO_CTRL_SET_CLOSE:
852 case BIO_CTRL_PENDING:
853 case BIO_CTRL_WPENDING:
860 return 0; /* NOTREACHED */
863 /// wrapper for Bio::stateChanged()
865 squid_ssl_info(const SSL
*ssl
, int where
, int ret
)
867 if (BIO
*table
= SSL_get_rbio(ssl
)) {
868 if (Ssl::Bio
*bio
= static_cast<Ssl::Bio
*>(table
->ptr
))
869 bio
->stateChanged(ssl
, where
, ret
);
873 Ssl::Bio::sslFeatures::sslFeatures():
878 unknownCiphers(false),
880 tlsTicketsExtension(false),
882 tlsStatusRequest(false),
885 memset(client_random
, 0, SSL3_RANDOM_SIZE
);
888 int Ssl::Bio::sslFeatures::toSquidSSLVersion() const
890 if (sslVersion
== SSL2_VERSION
)
892 else if (sslVersion
== SSL3_VERSION
)
894 else if (sslVersion
== TLS1_VERSION
)
896 #if OPENSSL_VERSION_NUMBER >= 0x10001000L
897 else if (sslVersion
== TLS1_1_VERSION
)
899 else if (sslVersion
== TLS1_2_VERSION
)
907 Ssl::Bio::sslFeatures::get(const SSL
*ssl
)
909 sslVersion
= SSL_version(ssl
);
910 debugs(83, 7, "SSL version: " << SSL_get_version(ssl
) << " (" << sslVersion
<< ")");
912 #if defined(TLSEXT_NAMETYPE_host_name)
913 if (const char *server
= SSL_get_servername(ssl
, TLSEXT_NAMETYPE_host_name
))
915 debugs(83, 7, "SNI server name: " << serverName
);
918 #if !defined(OPENSSL_NO_COMP)
919 if (ssl
->session
->compress_meth
)
920 compressMethod
= ssl
->session
->compress_meth
;
921 else if (sslVersion
>= 3) //if it is 3 or newer version then compression is disabled
924 debugs(83, 7, "SSL compression: " << compressMethod
);
926 STACK_OF(SSL_CIPHER
) * ciphers
= NULL
;
928 ciphers
= ssl
->session
->ciphers
;
930 ciphers
= ssl
->cipher_list
;
932 for (int i
= 0; i
< sk_SSL_CIPHER_num(ciphers
); ++i
) {
933 SSL_CIPHER
*c
= sk_SSL_CIPHER_value(ciphers
, i
);
935 if (!clientRequestedCiphers
.empty())
936 clientRequestedCiphers
.append(":");
937 clientRequestedCiphers
.append(c
->name
);
941 debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers
);
943 if (sslVersion
>=3 && ssl
->s3
&& ssl
->s3
->client_random
[0]) {
944 memcpy(client_random
, ssl
->s3
->client_random
, SSL3_RANDOM_SIZE
);
952 Ssl::Bio::sslFeatures::parseMsgHead(const SBuf
&buf
)
954 debugs(83, 7, "SSL Header: " << Raw(nullptr, buf
.rawContent(), buf
.length()).hex());
956 if (buf
.length() < 5)
959 if (helloMsgSize
> 0)
962 const unsigned char *head
= (const unsigned char *)buf
.rawContent();
963 // Check for SSLPlaintext/TLSPlaintext record
964 // RFC6101 section 5.2.1
965 // RFC5246 section 6.2.1
966 if (head
[0] == 0x16) {
967 debugs(83, 7, "SSL version 3 handshake message");
968 // The SSL version exist in the 2nd and 3rd bytes
969 sslHelloVersion
= (head
[1] << 8) | head
[2];
970 debugs(83, 7, "SSL Version :" << std::hex
<< std::setw(8) << std::setfill('0') << sslVersion
);
971 // The hello message size exist in 4th and 5th bytes
972 helloMsgSize
= (head
[3] << 8) + head
[4];
973 debugs(83, 7, "SSL Header Size: " << helloMsgSize
);
975 } else if ((head
[0] & 0x80) && head
[2] == 0x01 && head
[3] == 0x03) {
976 debugs(83, 7, "SSL version 2 handshake message with v3 support");
977 sslHelloVersion
= 0x0002;
978 debugs(83, 7, "SSL Version :" << std::hex
<< std::setw(8) << std::setfill('0') << sslVersion
);
979 // The hello message size exist in 2nd byte
980 helloMsgSize
= head
[1];
983 debugs(83, 7, "Not an SSL acceptable handshake message (SSLv2 message?)");
984 return (helloMsgSize
= -1);
987 // Set object as initialized. Even if we did not full parsing yet
988 // The basic features, like the SSL version is set
994 Ssl::Bio::sslFeatures::get(const SBuf
&buf
, bool record
)
997 if ((msgSize
= parseMsgHead(buf
)) <= 0) {
998 debugs(83, 7, "Not a known SSL handshake message");
1002 if (msgSize
> (int)buf
.length()) {
1003 debugs(83, 2, "Partial SSL handshake message, can not parse!");
1010 const unsigned char *msg
= (const unsigned char *)buf
.rawContent();
1012 return parseV23Hello(msg
, (size_t)msgSize
);
1014 // Hello messages require 5 bytes header + 1 byte Msg type + 3 bytes for Msg size
1015 if (buf
.length() < 9)
1018 // Check for the Handshake/Message type
1019 // The type 2 is a ServerHello, the type 1 is a ClientHello
1020 // RFC5246 section 7.4
1021 if (msg
[5] == 0x2) { // ServerHello message
1022 return parseV3ServerHello(msg
, (size_t)msgSize
);
1023 } else if (msg
[5] == 0x1) // ClientHello message,
1024 return parseV3Hello(msg
, (size_t)msgSize
);
1031 Ssl::Bio::sslFeatures::parseV3ServerHello(const unsigned char *messageContainer
, size_t messageContainerSize
)
1033 // Parse a ServerHello Handshake message
1034 // RFC5246 section 7.4, 7.4.1.3
1035 // The ServerHello starts at messageContainer + 5
1036 const unsigned char *serverHello
= messageContainer
+ 5;
1038 // The Length field (bytes 1-3) plus 4 bytes of the serverHello message header (1 handshake type + 3 hello length)
1039 const size_t helloSize
= ((serverHello
[1] << 16) | (serverHello
[2] << 8) | serverHello
[3]) + 4;
1040 debugs(83, 7, "ServerHello message size: " << helloSize
);
1041 if (helloSize
> messageContainerSize
) {
1042 debugs(83, 2, "ServerHello parse error");
1046 // helloSize should be at least 38 bytes long:
1047 // (SSL Version + Random + SessionId Length + Cipher Suite + Compression Method)
1048 if (helloSize
< 38) {
1049 debugs(83, 2, "Too short ServerHello message");
1053 debugs(83, 7, "Get fake features from v3 ServerHello message.");
1054 // Get the correct version of the sub-hello message
1055 sslVersion
= (serverHello
[4] << 8) | serverHello
[5];
1056 // At the position 38 (HelloHeader (6bytes) + SSL3_RANDOM_SIZE (32bytes))
1057 const size_t sessIdLen
= static_cast<size_t>(serverHello
[38]);
1058 debugs(83, 7, "Session ID Length: " << sessIdLen
);
1060 // The size should be enough to hold at least the following
1062 // + 2 (SSL Version) + 32 (random) + 1 (sessionId length)
1063 // + sessIdLength + 2 (cipher suite) + 1 (compression method)
1064 // = 42 + sessIdLength
1065 if (42 + sessIdLen
> helloSize
) {
1066 debugs(83, 2, "ciphers length parse error");
1070 // The sessionID stored at 39 position, after sessionID length field
1071 sessionId
.assign(reinterpret_cast<const char *>(serverHello
+ 39), sessIdLen
);
1073 // Check if there are extensions in hello message
1074 // RFC5246 section 7.4.1.4
1075 if (helloSize
> 42 + sessIdLen
+ 2) {
1077 const unsigned char *pToExtensions
= serverHello
+ 42 + sessIdLen
;
1078 const size_t extensionsLen
= (pToExtensions
[0] << 8) | pToExtensions
[1];
1079 // Check if the hello size can hold extensions
1080 if (42 + 2 + sessIdLen
+ extensionsLen
> helloSize
) {
1081 debugs(83, 2, "Extensions length parse error");
1086 const unsigned char *ext
= pToExtensions
;
1087 while (ext
+ 4 <= pToExtensions
+ extensionsLen
) {
1088 const size_t extType
= (ext
[0] << 8) | ext
[1];
1090 const size_t extLen
= (ext
[0] << 8) | ext
[1];
1092 debugs(83, 7, "TLS Extension: " << std::hex
<< extType
<< " of size:" << extLen
);
1093 // SessionTicket TLS Extension, RFC5077 section 3.2
1094 if (extType
== 0x23) {
1095 tlsTicketsExtension
= true;
1104 Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *messageContainer
, size_t messageContainerSize
)
1106 // Parse a ClientHello Handshake message
1107 // RFC5246 section 7.4, 7.4.1.2
1108 // The ClientHello starts at messageContainer + 5
1109 const unsigned char * clientHello
= messageContainer
+ 5;
1111 debugs(83, 7, "Get fake features from v3 ClientHello message.");
1112 // The Length field (bytes 1-3) plus 4 bytes of the clientHello message header (1 handshake type + 3 hello length)
1113 const size_t helloSize
= ((clientHello
[1] << 16) | (clientHello
[2] << 8) | clientHello
[3]) + 4;
1114 debugs(83, 7, "ClientHello message size: " << helloSize
);
1115 if (helloSize
> messageContainerSize
) {
1116 debugs(83, 2, "ClientHello parse error");
1120 // helloSize should be at least 38 bytes long:
1121 // (SSL Version(2) + Random(32) + SessionId Length(1) + Cipher Suite Length(2) + Compression Method Length(1))
1122 if (helloSize
< 38) {
1123 debugs(83, 2, "Too short ClientHello message");
1127 //For SSLv3 or TLSv1.* protocols we can get some more informations
1128 if (messageContainer
[1] != 0x3 || clientHello
[0] != 0x1 /*HELLO A message*/) {
1129 debugs(83, 2, "Not an SSLv3/TLSv1.x client hello message, stop parsing here");
1133 // Get the correct version of the sub-hello message
1134 sslVersion
= (clientHello
[4] << 8) | clientHello
[5];
1135 //Get Client Random number. It starts on the position 6 of clientHello message
1136 memcpy(client_random
, clientHello
+ 6, SSL3_RANDOM_SIZE
);
1137 debugs(83, 7, "Client random: " << Raw(nullptr, (char *)client_random
, SSL3_RANDOM_SIZE
).hex());
1139 // At the position 38 (6+SSL3_RANDOM_SIZE)
1140 const size_t sessIDLen
= static_cast<size_t>(clientHello
[38]);
1141 debugs(83, 7, "Session ID Length: " << sessIDLen
);
1143 // The helloSize should be enough to hold at least the following
1144 // 1 handshake type + 3 hello Length
1145 // + 2 (SSL Version) + 32 (random) + 1 (sessionId length)
1146 // + sessIdLength + 2 (cipher suite length) + 1 (compression method length)
1147 // = 42 + sessIdLength
1148 if (42 + sessIDLen
> helloSize
) {
1149 debugs(83, 2, "Session ID length parse error");
1153 // The sessionID stored art 39 position, after sessionID length field
1154 sessionId
.assign(reinterpret_cast<const char *>(clientHello
+ 39), sessIDLen
);
1156 //Ciphers list. It is stored after the Session ID.
1157 // It is a variable-length vector(RFC5246 section 4.3)
1158 const unsigned char *ciphers
= clientHello
+ 39 + sessIDLen
;
1159 const size_t ciphersLen
= (ciphers
[0] << 8) | ciphers
[1];
1160 if (42 + sessIDLen
+ ciphersLen
> helloSize
) {
1161 debugs(83, 2, "ciphers length parse error");
1167 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1168 const SSL_METHOD
*method
= TLS_method();
1170 const SSL_METHOD
*method
= SSLv23_method();
1172 for (size_t i
= 0; i
< ciphersLen
; i
+= 2) {
1173 // each cipher in v3/tls HELLO message is of size 2
1174 const SSL_CIPHER
*c
= method
->get_cipher_by_char((ciphers
+ i
));
1176 if (!clientRequestedCiphers
.empty())
1177 clientRequestedCiphers
.append(":");
1178 clientRequestedCiphers
.append(c
->name
);
1180 unknownCiphers
= true;
1183 debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers
);
1185 // Compression field: 1 bytes the number of compression methods and
1186 // 1 byte for each compression method
1187 const unsigned char *compression
= ciphers
+ ciphersLen
;
1188 if (compression
[0] > 1)
1192 debugs(83, 7, "SSL compression methods number: " << static_cast<int>(compression
[0]));
1194 // Parse Extensions, RFC5246 section 7.4.1.4
1195 const unsigned char *pToExtensions
= compression
+ 1 + static_cast<int>(compression
[0]);
1196 if ((size_t)((pToExtensions
- clientHello
) + 2) < helloSize
) {
1197 const size_t extensionsLen
= (pToExtensions
[0] << 8) | pToExtensions
[1];
1198 if ((pToExtensions
- clientHello
) + 2 + extensionsLen
> helloSize
) {
1199 debugs(83, 2, "Extensions length parse error");
1204 const unsigned char *ext
= pToExtensions
;
1205 while (ext
+ 4 <= pToExtensions
+ extensionsLen
) {
1206 const size_t extType
= (ext
[0] << 8) | ext
[1];
1208 const size_t extLen
= (ext
[0] << 8) | ext
[1];
1210 debugs(83, 7, "TLS Extension: " << std::hex
<< extType
<< " of size:" << extLen
);
1212 if (ext
+ extLen
> pToExtensions
+ extensionsLen
) {
1213 debugs(83, 2, "Extension " << std::hex
<< extType
<< " length parser error");
1217 //The SNI extension has the type 0 (extType == 0)
1218 // RFC6066 sections 3, 10.2
1219 // The two first bytes indicates the length of the SNI data (should be extLen-2)
1220 // The next byte is the hostname type, it should be '0' for normal hostname (ext[2] == 0)
1221 // The 3rd and 4th bytes are the length of the hostname
1222 if (extType
== 0 && ext
[2] == 0) {
1223 const size_t hostLen
= (ext
[3] << 8) | ext
[4];
1224 if (hostLen
< extLen
)
1225 serverName
.assign(reinterpret_cast<const char *>(ext
+5), hostLen
);
1226 debugs(83, 7, "Found server name: " << serverName
);
1227 } else if (extType
== 15 && ext
[0] != 0) {
1228 // The heartBeats are the type 15, RFC6520
1229 doHeartBeats
= true;
1230 } else if (extType
== 0x23) {
1231 //SessionTicket TLS Extension RFC5077
1232 tlsTicketsExtension
= true;
1234 hasTlsTicket
= true;
1235 } else if (extType
== 0x05) {
1236 // RFC6066 sections 8, 10.2
1237 tlsStatusRequest
= true;
1238 } else if (extType
== 0x3374) {
1239 // detected TLS next protocol negotiate extension
1240 } else if (extType
== 0x10) {
1241 // Application-Layer Protocol Negotiation Extension, RFC7301
1242 const size_t listLen
= (ext
[0] << 8) | ext
[1];
1243 if (listLen
< extLen
)
1244 tlsAppLayerProtoNeg
.assign(reinterpret_cast<const char *>(ext
+5), listLen
);
1246 extensions
.push_back(extType
);
1255 Ssl::Bio::sslFeatures::parseV23Hello(const unsigned char *hello
, size_t size
)
1257 debugs(83, 7, "Get fake features from v23 ClientHello message.");
1261 // Get the SSL/TLS version supported by client
1262 sslVersion
= (hello
[3] << 8) | hello
[4];
1264 //Ciphers list. It is stored after the Session ID.
1265 const unsigned int ciphersLen
= (hello
[5] << 8) | hello
[6];
1266 const unsigned char *ciphers
= hello
+ 11;
1268 if (size
< ciphersLen
+ 11)
1272 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1273 const SSL_METHOD
*method
= TLS_method();
1275 const SSL_METHOD
*method
= SSLv23_method();
1277 for (unsigned int i
= 0; i
< ciphersLen
; i
+= 3) {
1278 // The v2 hello messages cipher has 3 bytes.
1279 // The v2 cipher has the first byte not null
1280 // Because we are going to sent only v3 message we
1281 // are ignoring these ciphers
1282 if (ciphers
[i
] != 0)
1284 const SSL_CIPHER
*c
= method
->get_cipher_by_char((ciphers
+ i
+ 1));
1286 if (!clientRequestedCiphers
.empty())
1287 clientRequestedCiphers
.append(":");
1288 clientRequestedCiphers
.append(c
->name
);
1292 debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers
);
1294 const unsigned int sessionIdLength
= (hello
[7] << 8) | hello
[8];
1295 debugs(83, 7, "SessionID length: " << sessionIdLength
);
1296 // SessionID starts at: hello+11+ciphersLen
1297 if (sessionIdLength
)
1298 sessionId
.assign((const char *)(hello
+ 11 + ciphersLen
), sessionIdLength
);
1300 const unsigned int challengeLength
= (hello
[5] << 9) | hello
[10];
1301 debugs(83, 7, "Challenge Length: " << challengeLength
);
1302 //challenge starts at: hello+11+ciphersLen+sessionIdLength
1309 Ssl::Bio::sslFeatures::applyToSSL(SSL
*ssl
, Ssl::BumpMode bumpMode
) const
1311 // To increase the possibility for bumping after peek mode selection or
1312 // splicing after stare mode selection it is good to set the
1313 // SSL protocol version.
1314 // The SSL_set_ssl_method is not the correct method because it will strict
1315 // SSL version which can be used to the SSL version used for client hello message.
1316 // For example will prevent comunnicating with a tls1.0 server if the
1317 // client sent and tlsv1.2 Hello message.
1318 #if defined(TLSEXT_NAMETYPE_host_name)
1319 if (!serverName
.isEmpty()) {
1320 SSL_set_tlsext_host_name(ssl
, serverName
.c_str());
1323 if (!clientRequestedCiphers
.empty())
1324 SSL_set_cipher_list(ssl
, clientRequestedCiphers
.c_str());
1325 #if defined(SSL_OP_NO_COMPRESSION) /* XXX: OpenSSL 0.9.8k lacks SSL_OP_NO_COMPRESSION */
1326 if (compressMethod
== 0)
1327 SSL_set_options(ssl
, SSL_OP_NO_COMPRESSION
);
1330 #if defined(TLSEXT_STATUSTYPE_ocsp)
1331 if (tlsStatusRequest
)
1332 SSL_set_tlsext_status_type(ssl
, TLSEXT_STATUSTYPE_ocsp
);
1335 #if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
1336 if (!tlsAppLayerProtoNeg
.isEmpty()) {
1337 if (bumpMode
== Ssl::bumpPeek
)
1338 SSL_set_alpn_protos(ssl
, (const unsigned char*)tlsAppLayerProtoNeg
.rawContent(), tlsAppLayerProtoNeg
.length());
1340 static const unsigned char supported_protos
[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
1341 SSL_set_alpn_protos(ssl
, supported_protos
, sizeof(supported_protos
));
1348 Ssl::Bio::sslFeatures::print(std::ostream
&os
) const
1350 static std::string buf
;
1351 // TODO: Also print missing features like the HeartBeats and AppLayerProtoNeg
1352 return os
<< "v" << sslVersion
<<
1353 " SNI:" << (serverName
.isEmpty() ? SBuf("-") : serverName
) <<
1354 " comp:" << compressMethod
<<
1355 " Ciphers:" << clientRequestedCiphers
<<
1356 " Random:" << Raw(nullptr, (char *)client_random
, SSL3_RANDOM_SIZE
).hex();
1359 /// parses a single TLS Record Layer frame
1361 Ssl::HandshakeParser::parseRecord()
1363 const Rfc5246::TLSPlaintext
record(tkRecords
);
1365 Must(record
.length
<= (1 << 14)); // RFC 5246: length MUST NOT exceed 2^14
1367 // RFC 5246: MUST NOT send zero-length [non-application] fragments
1368 Must(record
.length
|| record
.type
== Rfc5246::ContentType::ctApplicationData
);
1370 if (currentContentType
!= record
.type
) {
1371 Must(tkMessages
.atEnd()); // no currentContentType leftovers
1372 fragments
= record
.fragment
;
1373 tkMessages
.reset(fragments
);
1374 currentContentType
= record
.type
;
1376 fragments
.append(record
.fragment
);
1377 tkMessages
.reinput(fragments
);
1378 tkMessages
.rollback();
1383 /// parses one or more "higher-level protocol" frames of currentContentType
1385 Ssl::HandshakeParser::parseMessages()
1387 debugs(83, 7, DebugFrame("fragments", currentContentType
, fragments
.length()));
1388 while (!tkMessages
.atEnd()) {
1389 switch (currentContentType
) {
1390 case Rfc5246::ContentType::ctChangeCipherSpec
:
1391 parseChangeCipherCpecMessage();
1393 case Rfc5246::ContentType::ctAlert
:
1394 parseAlertMessage();
1396 case Rfc5246::ContentType::ctHandshake
:
1397 parseHandshakeMessage();
1399 case Rfc5246::ContentType::ctApplicationData
:
1400 parseApplicationDataMessage();
1403 skipMessage("unknown ContentType msg");
1408 Ssl::HandshakeParser::parseChangeCipherCpecMessage()
1410 Must(currentContentType
== Rfc5246::ContentType::ctChangeCipherSpec
);
1411 // we are currently ignoring Change Cipher Spec Protocol messages
1412 // Everything after this message may be is encrypted
1413 // The continuing parsing is pointless, abort here and set parseDone
1414 skipMessage("ChangeCipherCpec msg");
1415 ressumingSession
= true;
1420 Ssl::HandshakeParser::parseAlertMessage()
1422 Must(currentContentType
== Rfc5246::ContentType::ctAlert
);
1423 const Rfc5246::Alert
alert(tkMessages
);
1424 debugs(83, 3, "level " << alert
.level
<< " description " << alert
.description
);
1425 // we are currently ignoring Alert Protocol messages
1429 Ssl::HandshakeParser::parseHandshakeMessage()
1431 Must(currentContentType
== Rfc5246::ContentType::ctHandshake
);
1433 const Rfc5246::Handshake
message(tkMessages
);
1435 switch (message
.msg_type
) {
1436 case Rfc5246::HandshakeType::hskServerHello
:
1437 Must(state
< atHelloReceived
);
1438 // TODO: Parse ServerHello in message.body; extract version/session
1439 // If the server is resuming a session, stop parsing w/o certificates
1440 // because all subsequent [Finished] messages will be encrypted, right?
1441 state
= atHelloReceived
;
1443 case Rfc5246::HandshakeType::hskCertificate
:
1444 Must(state
< atCertificatesReceived
);
1445 parseServerCertificates(message
.body
);
1446 state
= atCertificatesReceived
;
1448 case Rfc5246::HandshakeType::hskServerHelloDone
:
1449 Must(state
< atHelloDoneReceived
);
1451 state
= atHelloDoneReceived
;
1455 debugs(83, 5, "ignoring " <<
1456 DebugFrame("handshake msg", message
.msg_type
, message
.length
));
1460 Ssl::HandshakeParser::parseApplicationDataMessage()
1462 Must(currentContentType
== Rfc5246::ContentType::ctApplicationData
);
1463 skipMessage("app data");
1467 Ssl::HandshakeParser::skipMessage(const char *description
)
1469 // tkMessages/fragments can only contain messages of the same ContentType.
1470 // To skip a message, we can and should skip everything we have [left]. If
1471 // we have partial messages, debugging will mislead about their boundaries.
1472 tkMessages
.skip(tkMessages
.leftovers().length(), description
);
1473 tkMessages
.commit();
1476 /// parseServerHelloTry() wrapper that maintains parseDone/parseError state
1478 Ssl::HandshakeParser::parseServerHello(const SBuf
&data
)
1481 tkRecords
.reinput(data
); // data contains _everything_ read so far
1482 tkRecords
.rollback();
1483 while (!tkRecords
.atEnd() && !parseDone
)
1485 debugs(83, 7, "success; done: " << parseDone
);
1488 catch (const BinaryTokenizer::InsufficientInput
&) {
1489 debugs(83, 5, "need more data");
1492 catch (const std::exception
&ex
) {
1493 debugs(83, 2, "parsing error: " << ex
.what());
1500 Ssl::HandshakeParser::ParseCertificate(const SBuf
&raw
)
1502 typedef const unsigned char *x509Data
;
1503 const x509Data x509Start
= reinterpret_cast<x509Data
>(raw
.rawContent());
1504 x509Data x509Pos
= x509Start
;
1505 X509
*x509
= d2i_X509(nullptr, &x509Pos
, raw
.length());
1506 Must(x509
); // successfully parsed
1507 Must(x509Pos
== x509Start
+ raw
.length()); // no leftovers
1512 Ssl::HandshakeParser::parseServerCertificates(const SBuf
&raw
)
1514 BinaryTokenizer
tkList(raw
);
1515 const Rfc5246::P24String
list(tkList
, "CertificateList");
1516 Must(tkList
.atEnd()); // no leftovers after all certificates
1518 BinaryTokenizer
tkItems(list
.body
);
1519 while (!tkItems
.atEnd()) {
1520 const Rfc5246::P24String
item(tkItems
, "Certificate");
1521 X509
*cert
= ParseCertificate(item
.body
);
1522 if (!serverCertificates
.get())
1523 serverCertificates
.reset(sk_X509_new_null());
1524 sk_X509_push(serverCertificates
.get(), cert
);
1525 debugs(83, 7, "parsed " << sk_X509_num(serverCertificates
.get()) << " certificates so far");
1530 #endif /* USE_SSL */