io/async/test/MockTimeoutManager.h \
io/async/test/ScopedBoundPort.h \
io/async/test/SocketPair.h \
+ io/async/test/TestSSLServer.h \
io/async/test/TimeUtil.h \
io/async/test/UndelayedDestruction.h \
io/async/test/Util.h \
*/
#include <folly/io/async/test/AsyncSSLSocketTest.h>
-#include <pthread.h>
#include <signal.h>
#include <folly/SocketAddress.h>
uint32_t TestSSLAsyncCacheServer::asyncLookups_ = 0;
uint32_t TestSSLAsyncCacheServer::lookupDelay_ = 0;
-const char* testCert = "folly/io/async/test/certs/tests-cert.pem";
-const char* testKey = "folly/io/async/test/certs/tests-key.pem";
-const char* testCA = "folly/io/async/test/certs/ca-cert.pem";
-
constexpr size_t SSLClient::kMaxReadBufferSz;
constexpr size_t SSLClient::kMaxReadsPerEvent;
-TestSSLServer::TestSSLServer(SSLServerAcceptCallbackBase* acb, bool enableTFO)
- : ctx_(new folly::SSLContext),
- acb_(acb),
- socket_(folly::AsyncServerSocket::newSocket(&evb_)) {
- // Set up the SSL context
- ctx_->loadCertificate(testCert);
- ctx_->loadPrivateKey(testKey);
- ctx_->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
-
- acb_->ctx_ = ctx_;
- acb_->base_ = &evb_;
-
- // Enable TFO
- if (enableTFO) {
- LOG(INFO) << "server TFO enabled";
- socket_->setTFOEnabled(true, 1000);
- }
-
- // set up the listening socket
- socket_->bind(0);
- socket_->getAddress(&address_);
- socket_->listen(100);
- socket_->addAcceptCallback(acb_, &evb_);
- socket_->startAccepting();
-
- int ret = pthread_create(&thread_, nullptr, Main, this);
- assert(ret == 0);
- (void)ret;
-
- std::cerr << "Accepting connections on " << address_ << std::endl;
-}
-
void getfds(int fds[2]) {
if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
FAIL() << "failed to create socketpair: " << strerror(errno);
clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
- serverCtx->loadCertificate(
- testCert);
- serverCtx->loadPrivateKey(
- testKey);
+ serverCtx->loadCertificate(kTestCert);
+ serverCtx->loadPrivateKey(kTestKey);
}
void sslsocketpair(
auto serverCtx = std::make_shared<SSLContext>();
serverCtx->setVerificationOption(SSLContext::SSLVerifyPeerEnum::VERIFY);
serverCtx->ciphers("ECDHE-RSA-AES128-SHA:AES128-SHA:AES256-SHA");
- serverCtx->loadPrivateKey(testKey);
- serverCtx->loadCertificate(testCert);
- serverCtx->loadTrustedCertificates(testCA);
- serverCtx->loadClientCAList(testCA);
+ serverCtx->loadPrivateKey(kTestKey);
+ serverCtx->loadCertificate(kTestCert);
+ serverCtx->loadTrustedCertificates(kTestCA);
+ serverCtx->loadClientCAList(kTestCA);
clientCtx->setVerificationOption(SSLContext::SSLVerifyPeerEnum::VERIFY);
clientCtx->ciphers("AES256-SHA:AES128-SHA");
- clientCtx->loadPrivateKey(testKey);
- clientCtx->loadCertificate(testCert);
- clientCtx->loadTrustedCertificates(testCA);
+ clientCtx->loadPrivateKey(kTestKey);
+ clientCtx->loadCertificate(kTestCert);
+ clientCtx->loadTrustedCertificates(kTestCA);
int fds[2];
getfds(fds);
new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
SSLHandshakeClient client(std::move(clientSock), true, true);
- clientCtx->loadTrustedCertificates(testCA);
+ clientCtx->loadTrustedCertificates(kTestCA);
SSLHandshakeServer server(std::move(serverSock), true, true);
new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
SSLHandshakeClient client(std::move(clientSock), true, false);
- clientCtx->loadTrustedCertificates(testCA);
+ clientCtx->loadTrustedCertificates(kTestCA);
SSLHandshakeServer server(std::move(serverSock), true, true);
new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
SSLHandshakeClientNoVerify client(std::move(clientSock), false, false);
- clientCtx->loadTrustedCertificates(testCA);
+ clientCtx->loadTrustedCertificates(kTestCA);
SSLHandshakeServerNoVerify server(std::move(serverSock), false, false);
auto serverCtx = std::make_shared<SSLContext>();
serverCtx->setVerificationOption(SSLContext::SSLVerifyPeerEnum::NO_VERIFY);
serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
- serverCtx->loadPrivateKey(testKey);
- serverCtx->loadCertificate(testCert);
- serverCtx->loadTrustedCertificates(testCA);
- serverCtx->loadClientCAList(testCA);
+ serverCtx->loadPrivateKey(kTestKey);
+ serverCtx->loadCertificate(kTestCert);
+ serverCtx->loadTrustedCertificates(kTestCA);
+ serverCtx->loadClientCAList(kTestCA);
clientCtx->setVerificationOption(SSLContext::SSLVerifyPeerEnum::NO_VERIFY);
clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
- clientCtx->loadPrivateKey(testKey);
- clientCtx->loadCertificate(testCert);
- clientCtx->loadTrustedCertificates(testCA);
+ clientCtx->loadPrivateKey(kTestKey);
+ clientCtx->loadCertificate(kTestCert);
+ clientCtx->loadTrustedCertificates(kTestCA);
int fds[2];
getfds(fds);
serverCtx->setVerificationOption(
SSLContext::SSLVerifyPeerEnum::VERIFY_REQ_CLIENT_CERT);
serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
- serverCtx->loadPrivateKey(testKey);
- serverCtx->loadCertificate(testCert);
- serverCtx->loadTrustedCertificates(testCA);
- serverCtx->loadClientCAList(testCA);
+ serverCtx->loadPrivateKey(kTestKey);
+ serverCtx->loadCertificate(kTestCert);
+ serverCtx->loadTrustedCertificates(kTestCA);
+ serverCtx->loadClientCAList(kTestCA);
clientCtx->setVerificationOption(SSLContext::SSLVerifyPeerEnum::VERIFY);
clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
- clientCtx->loadPrivateKey(testKey);
- clientCtx->loadCertificate(testCert);
- clientCtx->loadTrustedCertificates(testCA);
+ clientCtx->loadPrivateKey(kTestKey);
+ clientCtx->loadCertificate(kTestCert);
+ clientCtx->loadTrustedCertificates(kTestCA);
int fds[2];
getfds(fds);
serverCtx->setVerificationOption(
SSLContext::SSLVerifyPeerEnum::VERIFY_REQ_CLIENT_CERT);
serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
- serverCtx->loadPrivateKey(testKey);
- serverCtx->loadCertificate(testCert);
- serverCtx->loadTrustedCertificates(testCA);
- serverCtx->loadClientCAList(testCA);
+ serverCtx->loadPrivateKey(kTestKey);
+ serverCtx->loadCertificate(kTestCert);
+ serverCtx->loadTrustedCertificates(kTestCA);
+ serverCtx->loadClientCAList(kTestCA);
clientCtx->setVerificationOption(SSLContext::SSLVerifyPeerEnum::NO_VERIFY);
clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
}
TEST(AsyncSSLSocketTest, LoadCertFromMemory) {
- auto cert = getFileAsBuf(testCert);
- auto key = getFileAsBuf(testKey);
+ auto cert = getFileAsBuf(kTestCert);
+ auto key = getFileAsBuf(kTestKey);
ssl::BioUniquePtr certBio(BIO_new(BIO_s_mem()));
BIO_write(certBio.get(), cert.data(), cert.size());
auto ctx = std::make_shared<SSLContext>();
ctx->loadPrivateKeyFromBufferPEM(key);
ctx->loadCertificateFromBufferPEM(cert);
- ctx->loadTrustedCertificates(testCA);
+ ctx->loadTrustedCertificates(kTestCA);
ssl::SSLUniquePtr ssl(ctx->createSSL());
#include <folly/io/async/AsyncTransport.h>
#include <folly/io/async/EventBase.h>
#include <folly/io/async/ssl/SSLErrors.h>
+#include <folly/io/async/test/TestSSLServer.h>
#include <folly/portability/GTest.h>
#include <folly/portability/Sockets.h>
#include <folly/portability/Unistd.h>
namespace folly {
-enum StateEnum {
- STATE_WAITING,
- STATE_SUCCEEDED,
- STATE_FAILED
-};
-
// The destructors of all callback classes assert that the state is
// STATE_SUCCEEDED, for both possitive and negative tests. The tests
// are responsible for setting the succeeded state properly before the
std::string errorString_;
};
-class SSLServerAcceptCallbackBase:
-public folly::AsyncServerSocket::AcceptCallback {
-public:
- explicit SSLServerAcceptCallbackBase(HandshakeCallback *hcb):
- state(STATE_WAITING), hcb_(hcb) {}
-
- ~SSLServerAcceptCallbackBase() {
- EXPECT_EQ(STATE_SUCCEEDED, state);
- }
-
- void acceptError(const std::exception& ex) noexcept override {
- std::cerr << "SSLServerAcceptCallbackBase::acceptError "
- << ex.what() << std::endl;
- state = STATE_FAILED;
- }
-
- void connectionAccepted(
- int fd, const folly::SocketAddress& /* clientAddr */) noexcept override {
- if (socket_) {
- socket_->detachEventBase();
- }
- printf("Connection accepted\n");
- try {
- // Create a AsyncSSLSocket object with the fd. The socket should be
- // added to the event base and in the state of accepting SSL connection.
- socket_ = AsyncSSLSocket::newSocket(ctx_, base_, fd);
- } catch (const std::exception &e) {
- LOG(ERROR) << "Exception %s caught while creating a AsyncSSLSocket "
- "object with socket " << e.what() << fd;
- ::close(fd);
- acceptError(e);
- return;
- }
-
- connAccepted(socket_);
- }
-
- virtual void connAccepted(
- const std::shared_ptr<folly::AsyncSSLSocket> &s) = 0;
-
- void detach() {
- socket_->detachEventBase();
- }
-
- StateEnum state;
- HandshakeCallback *hcb_;
- std::shared_ptr<folly::SSLContext> ctx_;
- std::shared_ptr<AsyncSSLSocket> socket_;
- folly::EventBase* base_;
-};
-
class SSLServerAcceptCallback: public SSLServerAcceptCallbackBase {
public:
uint32_t timeout_;
}
};
-class TestSSLServer {
- protected:
- EventBase evb_;
- std::shared_ptr<folly::SSLContext> ctx_;
- SSLServerAcceptCallbackBase *acb_;
- std::shared_ptr<folly::AsyncServerSocket> socket_;
- folly::SocketAddress address_;
- pthread_t thread_;
-
- static void *Main(void *ctx) {
- TestSSLServer *self = static_cast<TestSSLServer*>(ctx);
- self->evb_.loop();
- self->acb_->detach();
- std::cerr << "Server thread exited event loop" << std::endl;
- return nullptr;
- }
-
- public:
- // Create a TestSSLServer.
- // This immediately starts listening on the given port.
- explicit TestSSLServer(
- SSLServerAcceptCallbackBase* acb,
- bool enableTFO = false);
-
- // Kill the thread.
- ~TestSSLServer() {
- evb_.runInEventBaseThread([&](){
- socket_->stopAccepting();
- });
- std::cerr << "Waiting for server thread to exit" << std::endl;
- pthread_join(thread_, nullptr);
- }
-
- EventBase &getEventBase() { return evb_; }
-
- const folly::SocketAddress& getAddress() const {
- return address_;
- }
-};
-
class TestSSLAsyncCacheServer : public TestSSLServer {
public:
explicit TestSSLAsyncCacheServer(SSLServerAcceptCallbackBase *acb,
namespace folly {
-const char* testCert = "folly/io/async/test/certs/tests-cert.pem";
-const char* testKey = "folly/io/async/test/certs/tests-key.pem";
-const char* testCA = "folly/io/async/test/certs/ca-cert.pem";
-
void getfds(int fds[2]) {
if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
LOG(ERROR) << "failed to create socketpair: " << strerror(errno);
clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
- serverCtx->loadCertificate(testCert);
- serverCtx->loadPrivateKey(testKey);
+ serverCtx->loadCertificate(kTestCert);
+ serverCtx->loadPrivateKey(kTestKey);
}
class SSLSessionTest : public testing::Test {
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <folly/io/async/test/TestSSLServer.h>
+
+namespace folly {
+
+const char* kTestCert = "folly/io/async/test/certs/tests-cert.pem";
+const char* kTestKey = "folly/io/async/test/certs/tests-key.pem";
+const char* kTestCA = "folly/io/async/test/certs/ca-cert.pem";
+
+TestSSLServer::TestSSLServer(SSLServerAcceptCallbackBase* acb, bool enableTFO)
+ : ctx_(new SSLContext),
+ acb_(acb),
+ socket_(AsyncServerSocket::newSocket(&evb_)) {
+ // Set up the SSL context
+ ctx_->loadCertificate(kTestCert);
+ ctx_->loadPrivateKey(kTestKey);
+ ctx_->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
+
+ acb_->ctx_ = ctx_;
+ acb_->base_ = &evb_;
+
+ // Enable TFO
+ if (enableTFO) {
+ LOG(INFO) << "server TFO enabled";
+ socket_->setTFOEnabled(true, 1000);
+ }
+
+ // set up the listening socket
+ socket_->bind(0);
+ socket_->getAddress(&address_);
+ socket_->listen(100);
+ socket_->addAcceptCallback(acb_, &evb_);
+ socket_->startAccepting();
+
+ thread_ = std::thread([&] { Main(); });
+ LOG(INFO) << "Accepting connections on " << address_;
+}
+
+TestSSLServer::~TestSSLServer() {
+ if (thread_.joinable()) {
+ evb_.runInEventBaseThread([&]() { socket_->stopAccepting(); });
+ LOG(INFO) << "Waiting for server thread to exit";
+ thread_.join();
+ }
+}
+}
--- /dev/null
+/*
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <folly/SocketAddress.h>
+#include <folly/experimental/TestUtil.h>
+#include <folly/io/async/AsyncSSLSocket.h>
+#include <folly/io/async/AsyncServerSocket.h>
+#include <folly/io/async/AsyncSocket.h>
+#include <folly/io/async/AsyncTimeout.h>
+#include <folly/io/async/AsyncTransport.h>
+#include <folly/io/async/EventBase.h>
+#include <folly/io/async/ssl/SSLErrors.h>
+#include <folly/portability/GTest.h>
+#include <folly/portability/Sockets.h>
+#include <folly/portability/Unistd.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <list>
+
+namespace folly {
+
+extern const char* kTestCert;
+extern const char* kTestKey;
+extern const char* kTestCA;
+
+enum StateEnum { STATE_WAITING, STATE_SUCCEEDED, STATE_FAILED };
+
+class HandshakeCallback;
+
+class SSLServerAcceptCallbackBase : public AsyncServerSocket::AcceptCallback {
+ public:
+ explicit SSLServerAcceptCallbackBase(HandshakeCallback* hcb)
+ : state(STATE_WAITING), hcb_(hcb) {}
+
+ ~SSLServerAcceptCallbackBase() {
+ EXPECT_EQ(STATE_SUCCEEDED, state);
+ }
+
+ void acceptError(const std::exception& ex) noexcept override {
+ LOG(WARNING) << "SSLServerAcceptCallbackBase::acceptError " << ex.what();
+ state = STATE_FAILED;
+ }
+
+ void connectionAccepted(
+ int fd,
+ const SocketAddress& /* clientAddr */) noexcept override {
+ if (socket_) {
+ socket_->detachEventBase();
+ }
+ LOG(INFO) << "Connection accepted";
+ try {
+ // Create a AsyncSSLSocket object with the fd. The socket should be
+ // added to the event base and in the state of accepting SSL connection.
+ socket_ = AsyncSSLSocket::newSocket(ctx_, base_, fd);
+ } catch (const std::exception& e) {
+ LOG(ERROR) << "Exception %s caught while creating a AsyncSSLSocket "
+ "object with socket "
+ << e.what() << fd;
+ ::close(fd);
+ acceptError(e);
+ return;
+ }
+
+ connAccepted(socket_);
+ }
+
+ virtual void connAccepted(const std::shared_ptr<AsyncSSLSocket>& s) = 0;
+
+ void detach() {
+ socket_->detachEventBase();
+ }
+
+ StateEnum state;
+ HandshakeCallback* hcb_;
+ std::shared_ptr<SSLContext> ctx_;
+ std::shared_ptr<AsyncSSLSocket> socket_;
+ EventBase* base_;
+};
+
+class TestSSLServer {
+ public:
+ // Create a TestSSLServer.
+ // This immediately starts listening on the given port.
+ explicit TestSSLServer(
+ SSLServerAcceptCallbackBase* acb,
+ bool enableTFO = false);
+
+ // Kills the thread.
+ virtual ~TestSSLServer();
+
+ EventBase& getEventBase() {
+ return evb_;
+ }
+
+ const SocketAddress& getAddress() const {
+ return address_;
+ }
+
+ protected:
+ void Main() {
+ evb_.loop();
+ acb_->detach();
+ LOG(INFO) << "Server thread exited event loop";
+ }
+
+ EventBase evb_;
+ std::shared_ptr<SSLContext> ctx_;
+ SSLServerAcceptCallbackBase* acb_;
+ std::shared_ptr<AsyncServerSocket> socket_;
+ SocketAddress address_;
+ std::thread thread_;
+};
+}