2 * Copyright 2015 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <arpa/inet.h>
21 #include <openssl/ssl.h>
23 #include <folly/Optional.h>
24 #include <folly/String.h>
25 #include <folly/io/async/AsyncSocket.h>
26 #include <folly/io/async/SSLContext.h>
27 #include <folly/io/async/AsyncTimeout.h>
28 #include <folly/io/async/OpenSSLPtrTypes.h>
29 #include <folly/io/async/TimeoutManager.h>
31 #include <folly/Bits.h>
32 #include <folly/io/IOBuf.h>
33 #include <folly/io/Cursor.h>
37 class SSLException: public folly::AsyncSocketException {
39 SSLException(int sslError, int errno_copy);
41 int getSSLError() const { return error_; }
49 * A class for performing asynchronous I/O on an SSL connection.
51 * AsyncSSLSocket allows users to asynchronously wait for data on an
52 * SSL connection, and to asynchronously send data.
54 * The APIs for reading and writing are intentionally asymmetric.
55 * Waiting for data to read is a persistent API: a callback is
56 * installed, and is notified whenever new data is available. It
57 * continues to be notified of new events until it is uninstalled.
59 * AsyncSSLSocket does not provide read timeout functionality,
60 * because it typically cannot determine when the timeout should be
61 * active. Generally, a timeout should only be enabled when
62 * processing is blocked waiting on data from the remote endpoint.
63 * For server connections, the timeout should not be active if the
64 * server is currently processing one or more outstanding requests for
65 * this connection. For client connections, the timeout should not be
66 * active if there are no requests pending on the connection.
67 * Additionally, if a client has multiple pending requests, it will
68 * ususally want a separate timeout for each request, rather than a
69 * single read timeout.
71 * The write API is fairly intuitive: a user can request to send a
72 * block of data, and a callback will be informed once the entire
73 * block has been transferred to the kernel, or on error.
74 * AsyncSSLSocket does provide a send timeout, since most callers
75 * want to give up if the remote end stops responding and no further
76 * progress can be made sending the data.
78 class AsyncSSLSocket : public virtual AsyncSocket {
80 typedef std::unique_ptr<AsyncSSLSocket, Destructor> UniquePtr;
81 using X509_deleter = folly::static_function_deleter<X509, &X509_free>;
85 virtual ~HandshakeCB() = default;
88 * handshakeVer() is invoked during handshaking to give the
89 * application chance to validate it's peer's certificate.
91 * Note that OpenSSL performs only rudimentary internal
92 * consistency verification checks by itself. Any other validation
93 * like whether or not the certificate was issued by a trusted CA.
94 * The default implementation of this callback mimics what what
95 * OpenSSL does internally if SSL_VERIFY_PEER is set with no
96 * verification callback.
98 * See the passages on verify_callback in SSL_CTX_set_verify(3)
101 virtual bool handshakeVer(AsyncSSLSocket* /*sock*/,
103 X509_STORE_CTX* /*ctx*/) noexcept {
108 * handshakeSuc() is called when a new SSL connection is
109 * established, i.e., after SSL_accept/connect() returns successfully.
111 * The HandshakeCB will be uninstalled before handshakeSuc()
114 * @param sock SSL socket on which the handshake was initiated
116 virtual void handshakeSuc(AsyncSSLSocket *sock) noexcept = 0;
119 * handshakeErr() is called if an error occurs while
120 * establishing the SSL connection.
122 * The HandshakeCB will be uninstalled before handshakeErr()
125 * @param sock SSL socket on which the handshake was initiated
126 * @param ex An exception representing the error.
128 virtual void handshakeErr(
129 AsyncSSLSocket *sock,
130 const AsyncSocketException& ex)
134 class HandshakeTimeout : public AsyncTimeout {
136 HandshakeTimeout(AsyncSSLSocket* sslSocket, EventBase* eventBase)
137 : AsyncTimeout(eventBase)
138 , sslSocket_(sslSocket) {}
140 virtual void timeoutExpired() noexcept {
141 sslSocket_->timeoutExpired();
145 AsyncSSLSocket* sslSocket_;
150 * These are passed to the application via errno, packed in an SSL err which
151 * are outside the valid errno range. The values are chosen to be unique
152 * against values in ssl.h
155 SSL_CLIENT_RENEGOTIATION_ATTEMPT = 900,
156 SSL_INVALID_RENEGOTIATION = 901,
157 SSL_EARLY_WRITE = 902
161 * Create a client AsyncSSLSocket
163 AsyncSSLSocket(const std::shared_ptr<folly::SSLContext> &ctx,
164 EventBase* evb, bool deferSecurityNegotiation = false);
167 * Create a server/client AsyncSSLSocket from an already connected
168 * socket file descriptor.
170 * Note that while AsyncSSLSocket enables TCP_NODELAY for sockets it creates
171 * when connecting, it does not change the socket options when given an
172 * existing file descriptor. If callers want TCP_NODELAY enabled when using
173 * this version of the constructor, they need to explicitly call
174 * setNoDelay(true) after the constructor returns.
176 * @param ctx SSL context for this connection.
177 * @param evb EventBase that will manage this socket.
178 * @param fd File descriptor to take over (should be a connected socket).
179 * @param server Is socket in server mode?
180 * @param deferSecurityNegotiation
181 * unencrypted data can be sent before sslConn/Accept
183 AsyncSSLSocket(const std::shared_ptr<folly::SSLContext>& ctx,
184 EventBase* evb, int fd,
185 bool server = true, bool deferSecurityNegotiation = false);
189 * Helper function to create a server/client shared_ptr<AsyncSSLSocket>.
191 static std::shared_ptr<AsyncSSLSocket> newSocket(
192 const std::shared_ptr<folly::SSLContext>& ctx,
193 EventBase* evb, int fd, bool server=true,
194 bool deferSecurityNegotiation = false) {
195 return std::shared_ptr<AsyncSSLSocket>(
196 new AsyncSSLSocket(ctx, evb, fd, server, deferSecurityNegotiation),
201 * Helper function to create a client shared_ptr<AsyncSSLSocket>.
203 static std::shared_ptr<AsyncSSLSocket> newSocket(
204 const std::shared_ptr<folly::SSLContext>& ctx,
205 EventBase* evb, bool deferSecurityNegotiation = false) {
206 return std::shared_ptr<AsyncSSLSocket>(
207 new AsyncSSLSocket(ctx, evb, deferSecurityNegotiation),
212 #if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT)
214 * Create a client AsyncSSLSocket with tlsext_servername in
215 * the Client Hello message.
217 AsyncSSLSocket(const std::shared_ptr<folly::SSLContext> &ctx,
219 const std::string& serverName,
220 bool deferSecurityNegotiation = false);
223 * Create a client AsyncSSLSocket from an already connected
224 * socket file descriptor.
226 * Note that while AsyncSSLSocket enables TCP_NODELAY for sockets it creates
227 * when connecting, it does not change the socket options when given an
228 * existing file descriptor. If callers want TCP_NODELAY enabled when using
229 * this version of the constructor, they need to explicitly call
230 * setNoDelay(true) after the constructor returns.
232 * @param ctx SSL context for this connection.
233 * @param evb EventBase that will manage this socket.
234 * @param fd File descriptor to take over (should be a connected socket).
235 * @param serverName tlsext_hostname that will be sent in ClientHello.
237 AsyncSSLSocket(const std::shared_ptr<folly::SSLContext>& ctx,
240 const std::string& serverName,
241 bool deferSecurityNegotiation = false);
243 static std::shared_ptr<AsyncSSLSocket> newSocket(
244 const std::shared_ptr<folly::SSLContext>& ctx,
246 const std::string& serverName,
247 bool deferSecurityNegotiation = false) {
248 return std::shared_ptr<AsyncSSLSocket>(
249 new AsyncSSLSocket(ctx, evb, serverName, deferSecurityNegotiation),
255 * TODO: implement support for SSL renegotiation.
257 * This involves proper handling of the SSL_ERROR_WANT_READ/WRITE
258 * code as a result of SSL_write/read(), instead of returning an
259 * error. In that case, the READ/WRITE event should be registered,
260 * and a flag (e.g., writeBlockedOnRead) should be set to indiciate
261 * the condition. In the next invocation of read/write callback, if
262 * the flag is on, performWrite()/performRead() should be called in
263 * addition to the normal call to performRead()/performWrite(), and
264 * the flag should be reset.
267 // Inherit TAsyncTransport methods from AsyncSocket except the
269 // See the documentation in TAsyncTransport.h
270 // TODO: implement graceful shutdown in close()
271 // TODO: implement detachSSL() that returns the SSL connection
272 virtual void closeNow() override;
273 virtual void shutdownWrite() override;
274 virtual void shutdownWriteNow() override;
275 virtual bool good() const override;
276 virtual bool connecting() const override;
277 virtual std::string getApplicationProtocol() noexcept override;
279 virtual std::string getSecurityProtocol() const override { return "TLS"; }
281 bool isEorTrackingEnabled() const override;
282 virtual void setEorTracking(bool track) override;
283 virtual size_t getRawBytesWritten() const override;
284 virtual size_t getRawBytesReceived() const override;
285 void enableClientHelloParsing();
288 * Accept an SSL connection on the socket.
290 * The callback will be invoked and uninstalled when an SSL
291 * connection has been established on the underlying socket.
292 * The value of verifyPeer determines the client verification method.
293 * By default, its set to use the value in the underlying context
295 * @param callback callback object to invoke on success/failure
296 * @param timeout timeout for this function in milliseconds, or 0 for no
298 * @param verifyPeer SSLVerifyPeerEnum uses the options specified in the
299 * context by default, can be set explcitly to override the
300 * method in the context
302 virtual void sslAccept(HandshakeCB* callback, uint32_t timeout = 0,
303 const folly::SSLContext::SSLVerifyPeerEnum& verifyPeer =
304 folly::SSLContext::SSLVerifyPeerEnum::USE_CTX);
307 * Invoke SSL accept following an asynchronous session cache lookup
309 void restartSSLAccept();
312 * Connect to the given address, invoking callback when complete or on error
314 * Note timeout applies to TCP + SSL connection time
316 void connect(ConnectCallback* callback,
317 const folly::SocketAddress& address,
319 const OptionMap &options = emptyOptionMap,
320 const folly::SocketAddress& bindAddr = anyAddress())
323 using AsyncSocket::connect;
326 * Initiate an SSL connection on the socket
327 * The callback will be invoked and uninstalled when an SSL connection
328 * has been establshed on the underlying socket.
329 * The verification option verifyPeer is applied if it's passed explicitly.
330 * If it's not, the options in SSLContext set on the underlying SSLContext
333 * @param callback callback object to invoke on success/failure
334 * @param timeout timeout for this function in milliseconds, or 0 for no
336 * @param verifyPeer SSLVerifyPeerEnum uses the options specified in the
337 * context by default, can be set explcitly to override the
338 * method in the context. If verification is turned on sets
339 * SSL_VERIFY_PEER and invokes
340 * HandshakeCB::handshakeVer().
342 virtual void sslConn(HandshakeCB *callback, uint64_t timeout = 0,
343 const folly::SSLContext::SSLVerifyPeerEnum& verifyPeer =
344 folly::SSLContext::SSLVerifyPeerEnum::USE_CTX);
351 STATE_RSA_ASYNC_PENDING,
354 STATE_REMOTE_CLOSED, /// remote end closed; we can still write
355 STATE_CLOSING, ///< close() called, but waiting on writes to complete
356 /// close() called with pending writes, before connect() has completed
357 STATE_CONNECTING_CLOSING,
362 SSLStateEnum getSSLState() const { return sslState_;}
365 * Get a handle to the negotiated SSL session. This increments the session
366 * refcount and must be deallocated by the caller.
368 SSL_SESSION *getSSLSession();
371 * Set the SSL session to be used during sslConn. AsyncSSLSocket will
372 * hold a reference to the session until it is destroyed or released by the
373 * underlying SSL structure.
375 * @param takeOwnership if true, AsyncSSLSocket will assume the caller's
376 * reference count to session.
378 void setSSLSession(SSL_SESSION *session, bool takeOwnership = false);
381 * Get the name of the protocol selected by the client during
382 * Next Protocol Negotiation (NPN) or Application Layer Protocol Negotiation
385 * Throw an exception if openssl does not support NPN
387 * @param protoName Name of the protocol (not guaranteed to be
388 * null terminated); will be set to nullptr if
389 * the client did not negotiate a protocol.
390 * Note: the AsyncSSLSocket retains ownership
392 * @param protoNameLen Length of the name.
393 * @param protoType Whether this was an NPN or ALPN negotiation
395 virtual void getSelectedNextProtocol(
396 const unsigned char** protoName,
398 SSLContext::NextProtocolType* protoType = nullptr) const;
401 * Get the name of the protocol selected by the client during
402 * Next Protocol Negotiation (NPN) or Application Layer Protocol Negotiation
405 * @param protoName Name of the protocol (not guaranteed to be
406 * null terminated); will be set to nullptr if
407 * the client did not negotiate a protocol.
408 * Note: the AsyncSSLSocket retains ownership
410 * @param protoNameLen Length of the name.
411 * @param protoType Whether this was an NPN or ALPN negotiation
412 * @return false if openssl does not support NPN
414 virtual bool getSelectedNextProtocolNoThrow(
415 const unsigned char** protoName,
417 SSLContext::NextProtocolType* protoType = nullptr) const;
420 * Determine if the session specified during setSSLSession was reused
421 * or if the server rejected it and issued a new session.
423 virtual bool getSSLSessionReused() const;
426 * true if the session was resumed using session ID
428 bool sessionIDResumed() const { return sessionIDResumed_; }
430 void setSessionIDResumed(bool resumed) {
431 sessionIDResumed_ = resumed;
435 * Get the negociated cipher name for this SSL connection.
436 * Returns the cipher used or the constant value "NONE" when no SSL session
437 * has been established.
439 virtual const char* getNegotiatedCipherName() const;
442 * Get the server name for this SSL connection.
443 * Returns the server name used or the constant value "NONE" when no SSL
444 * session has been established.
445 * If openssl has no SNI support, throw TTransportException.
447 const char *getSSLServerName() const;
450 * Get the server name for this SSL connection.
451 * Returns the server name used or the constant value "NONE" when no SSL
452 * session has been established.
453 * If openssl has no SNI support, return "NONE"
455 const char *getSSLServerNameNoThrow() const;
458 * Get the SSL version for this connection.
459 * Possible return values are SSL2_VERSION, SSL3_VERSION, TLS1_VERSION,
460 * with hexa representations 0x200, 0x300, 0x301,
461 * or 0 if no SSL session has been established.
463 int getSSLVersion() const;
466 * Get the signature algorithm used in the cert that is used for this
469 const char *getSSLCertSigAlgName() const;
472 * Get the certificate size used for this SSL connection.
474 int getSSLCertSize() const;
476 virtual void attachEventBase(EventBase* eventBase) override {
477 AsyncSocket::attachEventBase(eventBase);
478 handshakeTimeout_.attachEventBase(eventBase);
481 virtual void detachEventBase() override {
482 AsyncSocket::detachEventBase();
483 handshakeTimeout_.detachEventBase();
486 virtual bool isDetachable() const override {
487 return AsyncSocket::isDetachable() && !handshakeTimeout_.isScheduled();
490 virtual void attachTimeoutManager(TimeoutManager* manager) {
491 handshakeTimeout_.attachTimeoutManager(manager);
494 virtual void detachTimeoutManager() {
495 handshakeTimeout_.detachTimeoutManager();
498 #if OPENSSL_VERSION_NUMBER >= 0x009080bfL
500 * This function will set the SSL context for this socket to the
501 * argument. This should only be used on client SSL Sockets that have
502 * already called detachSSLContext();
504 void attachSSLContext(const std::shared_ptr<folly::SSLContext>& ctx);
507 * Detaches the SSL context for this socket.
509 void detachSSLContext();
512 #if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT)
514 * Switch the SSLContext to continue the SSL handshake.
515 * It can only be used in server mode.
517 void switchServerSSLContext(
518 const std::shared_ptr<folly::SSLContext>& handshakeCtx);
521 * Did server recognize/support the tlsext_hostname in Client Hello?
522 * It can only be used in client mode.
524 * @return true - tlsext_hostname is matched by the server
525 * false - tlsext_hostname is not matched or
526 * is not supported by server
528 bool isServerNameMatch() const;
531 * Set the SNI hostname that we'll advertise to the server in the
532 * ClientHello message.
534 void setServerName(std::string serverName) noexcept;
537 void timeoutExpired() noexcept;
540 * Get the list of supported ciphers sent by the client in the client's
543 void getSSLClientCiphers(std::string& clientCiphers) const {
544 std::stringstream ciphersStream;
545 std::string cipherName;
547 if (parseClientHello_ == false
548 || clientHelloInfo_->clientHelloCipherSuites_.empty()) {
553 for (auto originalCipherCode : clientHelloInfo_->clientHelloCipherSuites_)
555 // OpenSSL expects code as a big endian char array
556 auto cipherCode = htons(originalCipherCode);
558 #if defined(SSL_OP_NO_TLSv1_2)
559 const SSL_CIPHER* cipher =
560 TLSv1_2_method()->get_cipher_by_char((unsigned char*)&cipherCode);
561 #elif defined(SSL_OP_NO_TLSv1_1)
562 const SSL_CIPHER* cipher =
563 TLSv1_1_method()->get_cipher_by_char((unsigned char*)&cipherCode);
564 #elif defined(SSL_OP_NO_TLSv1)
565 const SSL_CIPHER* cipher =
566 TLSv1_method()->get_cipher_by_char((unsigned char*)&cipherCode);
568 const SSL_CIPHER* cipher =
569 SSLv3_method()->get_cipher_by_char((unsigned char*)&cipherCode);
572 if (cipher == nullptr) {
573 ciphersStream << std::setfill('0') << std::setw(4) << std::hex
574 << originalCipherCode << ":";
576 ciphersStream << SSL_CIPHER_get_name(cipher) << ":";
580 clientCiphers = ciphersStream.str();
581 clientCiphers.erase(clientCiphers.end() - 1);
585 * Get the list of compression methods sent by the client in TLS Hello.
587 std::string getSSLClientComprMethods() const {
588 if (!parseClientHello_) {
591 return folly::join(":", clientHelloInfo_->clientHelloCompressionMethods_);
595 * Get the list of TLS extensions sent by the client in the TLS Hello.
597 std::string getSSLClientExts() const {
598 if (!parseClientHello_) {
601 return folly::join(":", clientHelloInfo_->clientHelloExtensions_);
604 std::string getSSLClientSigAlgs() const {
605 if (!parseClientHello_) {
610 sigAlgs.reserve(clientHelloInfo_->clientHelloSigAlgs_.size() * 4);
611 for (size_t i = 0; i < clientHelloInfo_->clientHelloSigAlgs_.size(); i++) {
613 sigAlgs.push_back(':');
615 sigAlgs.append(folly::to<std::string>(
616 clientHelloInfo_->clientHelloSigAlgs_[i].first));
617 sigAlgs.push_back(',');
618 sigAlgs.append(folly::to<std::string>(
619 clientHelloInfo_->clientHelloSigAlgs_[i].second));
626 * Get the list of shared ciphers between the server and the client.
627 * Works well for only SSLv2, not so good for SSLv3 or TLSv1.
629 void getSSLSharedCiphers(std::string& sharedCiphers) const {
630 char ciphersBuffer[1024];
631 ciphersBuffer[0] = '\0';
632 SSL_get_shared_ciphers(ssl_, ciphersBuffer, sizeof(ciphersBuffer) - 1);
633 sharedCiphers = ciphersBuffer;
637 * Get the list of ciphers supported by the server in the server's
640 void getSSLServerCiphers(std::string& serverCiphers) const {
641 serverCiphers = SSL_get_cipher_list(ssl_, 0);
644 while ((cipher = SSL_get_cipher_list(ssl_, i)) != nullptr) {
645 serverCiphers.append(":");
646 serverCiphers.append(cipher);
651 static int getSSLExDataIndex();
652 static AsyncSSLSocket* getFromSSL(const SSL *ssl);
653 static int eorAwareBioWrite(BIO *b, const char *in, int inl);
654 void resetClientHelloParsing(SSL *ssl);
655 static void clientHelloParsingCallback(int write_p, int version,
656 int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
658 // http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
659 enum class TLSExtension: uint16_t {
661 MAX_FRAGMENT_LENGTH = 1,
662 CLIENT_CERTIFICATE_URL = 2,
670 SUPPORTED_GROUPS = 10,
671 EC_POINT_FORMATS = 11,
673 SIGNATURE_ALGORITHMS = 13,
676 APPLICATION_LAYER_PROTOCOL_NEGOTIATION = 16,
677 STATUS_REQUEST_V2 = 17,
678 SIGNED_CERTIFICATE_TIMESTAMP = 18,
679 CLIENT_CERTIFICATE_TYPE = 19,
680 SERVER_CERTIFICATE_TYPE = 20,
682 ENCRYPT_THEN_MAC = 22,
683 EXTENDED_MASTER_SECRET = 23,
685 RENEGOTIATION_INFO = 65281
688 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-18
689 enum class HashAlgorithm: uint8_t {
699 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16
700 enum class SignatureAlgorithm: uint8_t {
707 struct ClientHelloInfo {
708 folly::IOBufQueue clientHelloBuf_;
709 uint8_t clientHelloMajorVersion_;
710 uint8_t clientHelloMinorVersion_;
711 std::vector<uint16_t> clientHelloCipherSuites_;
712 std::vector<uint8_t> clientHelloCompressionMethods_;
713 std::vector<TLSExtension> clientHelloExtensions_;
715 std::pair<HashAlgorithm, SignatureAlgorithm>> clientHelloSigAlgs_;
719 ClientHelloInfo* getClientHelloInfo() const {
720 return clientHelloInfo_.get();
724 * Returns the time taken to complete a handshake.
726 virtual std::chrono::nanoseconds getHandshakeTime() const {
727 return handshakeEndTime_ - handshakeStartTime_;
730 void setMinWriteSize(size_t minWriteSize) {
731 minWriteSize_ = minWriteSize;
734 size_t getMinWriteSize() const {
735 return minWriteSize_;
738 void setReadCB(ReadCallback* callback) override;
741 * Returns the peer certificate, or nullptr if no peer certificate received.
743 virtual X509_UniquePtr getPeerCert() const override {
748 X509* cert = SSL_get_peer_certificate(ssl_);
749 return X509_UniquePtr(cert);
759 * Protected destructor.
761 * Users of AsyncSSLSocket must never delete it directly. Instead, invoke
762 * destroy() instead. (See the documentation in DelayedDestruction.h for
767 // Inherit event notification methods from AsyncSocket except
769 void prepareReadBuffer(void** buf, size_t* buflen) noexcept override;
770 void handleRead() noexcept override;
771 void handleWrite() noexcept override;
772 void handleAccept() noexcept;
773 void handleConnect() noexcept override;
775 void invalidState(HandshakeCB* callback);
776 bool willBlock(int ret, int *errorOut) noexcept;
778 virtual void checkForImmediateRead() noexcept override;
779 // AsyncSocket calls this at the wrong time for SSL
780 void handleInitialReadWrite() noexcept override {}
782 int interpretSSLError(int rc, int error);
783 ssize_t performRead(void** buf, size_t* buflen, size_t* offset) override;
784 ssize_t performWrite(const iovec* vec, uint32_t count, WriteFlags flags,
785 uint32_t* countWritten, uint32_t* partialWritten)
788 ssize_t performWriteIovec(const iovec* vec, uint32_t count,
789 WriteFlags flags, uint32_t* countWritten,
790 uint32_t* partialWritten);
792 // This virtual wrapper around SSL_write exists solely for testing/mockability
793 virtual int sslWriteImpl(SSL *ssl, const void *buf, int n) {
794 return SSL_write(ssl, buf, n);
798 * Apply verification options passed to sslConn/sslAccept or those set
799 * in the underlying SSLContext object.
801 * @param ssl pointer to the SSL object on which verification options will be
802 * applied. If verifyPeer_ was explicitly set either via sslConn/sslAccept,
803 * those options override the settings in the underlying SSLContext.
805 void applyVerificationOptions(SSL * ssl);
808 * A SSL_write wrapper that understand EOR
810 * @param ssl: SSL* object
811 * @param buf: Buffer to be written
812 * @param n: Number of bytes to be written
813 * @param eor: Does the last byte (buf[n-1]) have the app-last-byte?
814 * @return: The number of app bytes successfully written to the socket
816 int eorAwareSSLWrite(SSL *ssl, const void *buf, int n, bool eor);
818 // Inherit error handling methods from AsyncSocket, plus the following.
819 void failHandshake(const char* fn, const AsyncSocketException& ex);
821 void invokeHandshakeErr(const AsyncSocketException& ex);
822 void invokeHandshakeCB();
824 static void sslInfoCallback(const SSL *ssl, int type, int val);
826 // SSL related members.
828 // Used to prevent client-initiated renegotiation. Note that AsyncSSLSocket
829 // doesn't fully support renegotiation, so we could just fail all attempts
830 // to enforce this. Once it is supported, we should make it an option
831 // to disable client-initiated renegotiation.
832 bool handshakeComplete_{false};
833 bool renegotiateAttempted_{false};
834 SSLStateEnum sslState_{STATE_UNINIT};
835 std::shared_ptr<folly::SSLContext> ctx_;
836 // Callback for SSL_accept() or SSL_connect()
837 HandshakeCB* handshakeCallback_{nullptr};
839 SSL_SESSION *sslSession_{nullptr};
840 HandshakeTimeout handshakeTimeout_;
841 // whether the SSL session was resumed using session ID or not
842 bool sessionIDResumed_{false};
844 // The app byte num that we are tracking for the MSG_EOR
845 // Only one app EOR byte can be tracked.
846 size_t appEorByteNo_{0};
848 // Try to avoid calling SSL_write() for buffers smaller than this.
849 // It doesn't take effect when it is 0.
850 size_t minWriteSize_{1500};
852 // When openssl is about to sendmsg() across the minEorRawBytesNo_,
853 // it will pass MSG_EOR to sendmsg().
854 size_t minEorRawByteNo_{0};
855 #if OPENSSL_VERSION_NUMBER >= 0x1000105fL && !defined(OPENSSL_NO_TLSEXT)
856 std::shared_ptr<folly::SSLContext> handshakeCtx_;
857 std::string tlsextHostname_;
859 folly::SSLContext::SSLVerifyPeerEnum
860 verifyPeer_{folly::SSLContext::SSLVerifyPeerEnum::USE_CTX};
862 // Callback for SSL_CTX_set_verify()
863 static int sslVerifyCallback(int preverifyOk, X509_STORE_CTX* ctx);
865 bool parseClientHello_{false};
866 std::unique_ptr<ClientHelloInfo> clientHelloInfo_;
868 // Time taken to complete the ssl handshake.
869 std::chrono::steady_clock::time_point handshakeStartTime_;
870 std::chrono::steady_clock::time_point handshakeEndTime_;