Summary:
Normally clearing out the error before calling into an openssl method
is a bad idea. However there might be other code outside AsyncSSLSocket
calling into openssl in the same thread that doesn't use openssl
correctly. This allows users of AsyncSSLSocket to safeguard themselves
from such code.
Reviewed By: anirudhvr
Differential Revision:
D4389970
fbshipit-source-id:
12da254d6b281c2b9d522ba19999b2489c0083a2
#include <boost/noncopyable.hpp>
#include <errno.h>
#include <fcntl.h>
#include <boost/noncopyable.hpp>
#include <errno.h>
#include <fcntl.h>
-#include <openssl/err.h>
#include <openssl/asn1.h>
#include <openssl/asn1.h>
+#include <openssl/err.h>
#include <openssl/ssl.h>
#include <sys/types.h>
#include <chrono>
#include <openssl/ssl.h>
#include <sys/types.h>
#include <chrono>
SSL_set_msg_callback_arg(ssl_, this);
}
SSL_set_msg_callback_arg(ssl_, this);
}
int ret = SSL_accept(ssl_);
if (ret <= 0) {
int sslError;
int ret = SSL_accept(ssl_);
if (ret <= 0) {
int sslError;
AsyncSocket::handleInitialReadWrite();
}
AsyncSocket::handleInitialReadWrite();
}
+void AsyncSSLSocket::clearOpenSSLErrors() {
+ // Normally clearing out the error before calling into an openssl method
+ // is a bad idea. However there might be other code that we don't control
+ // calling into openssl in the same thread, which doesn't use openssl
+ // correctly. We want to safe-guard ourselves from that code.
+ // However touching the ERR stack each and every time has a cost of taking
+ // a lock, so we only do this when we've opted in.
+ if (clearOpenSSLErrors_) {
+ ERR_clear_error();
+ }
+}
+
void
AsyncSSLSocket::handleConnect() noexcept {
VLOG(3) << "AsyncSSLSocket::handleConnect() this=" << this
void
AsyncSSLSocket::handleConnect() noexcept {
VLOG(3) << "AsyncSSLSocket::handleConnect() this=" << this
sslState_ == STATE_CONNECTING);
assert(ssl_);
sslState_ == STATE_CONNECTING);
assert(ssl_);
auto originalState = state_;
int ret = SSL_connect(ssl_);
if (ret <= 0) {
auto originalState = state_;
int ret = SSL_connect(ssl_);
if (ret <= 0) {
return AsyncSocket::performRead(buf, buflen, offset);
}
return AsyncSocket::performRead(buf, buflen, offset);
}
int bytes = 0;
if (!isBufferMovable_) {
bytes = SSL_read(ssl_, *buf, int(*buflen));
int bytes = 0;
if (!isBufferMovable_) {
bytes = SSL_read(ssl_, *buf, int(*buflen));
return sessionResumptionAttempted_;
}
return sessionResumptionAttempted_;
}
+ /**
+ * Clears the ERR stack before invoking SSL methods.
+ * This is useful if unrelated code that runs in the same thread
+ * does not properly handle SSL error conditions, in which case
+ * it could cause SSL_* methods to fail with incorrect error codes.
+ */
+ void setClearOpenSSLErrors(bool clearErr) {
+ clearOpenSSLErrors_ = clearErr;
+ }
+
+ void clearOpenSSLErrors();
// This virtual wrapper around SSL_write exists solely for testing/mockability
virtual int sslWriteImpl(SSL *ssl, const void *buf, int n) {
// This virtual wrapper around SSL_write exists solely for testing/mockability
virtual int sslWriteImpl(SSL *ssl, const void *buf, int n) {
return SSL_write(ssl, buf, n);
}
return SSL_write(ssl, buf, n);
}
bool sessionResumptionAttempted_{false};
std::unique_ptr<IOBuf> preReceivedData_;
bool sessionResumptionAttempted_{false};
std::unique_ptr<IOBuf> preReceivedData_;
+ // Whether or not to clear the err stack before invocation of another
+ // SSL method
+ bool clearOpenSSLErrors_{false};