2 * Copyright 2017 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.
17 #include <folly/io/async/test/AsyncSSLSocketTest.h>
18 #include <folly/portability/GTest.h>
19 #include <folly/portability/Sockets.h>
20 #include <folly/ssl/SSLSession.h>
23 using namespace testing;
24 using folly::ssl::SSLSession;
28 void getfds(int fds[2]) {
29 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
30 LOG(ERROR) << "failed to create socketpair: " << strerror(errno);
32 for (int idx = 0; idx < 2; ++idx) {
33 int flags = fcntl(fds[idx], F_GETFL, 0);
35 LOG(ERROR) << "failed to get flags for socket " << idx << ": "
38 if (fcntl(fds[idx], F_SETFL, flags | O_NONBLOCK) != 0) {
39 LOG(ERROR) << "failed to put socket " << idx
40 << " in non-blocking mode: " << strerror(errno);
46 std::shared_ptr<folly::SSLContext> clientCtx,
47 std::shared_ptr<folly::SSLContext> serverCtx) {
48 clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
50 serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
51 serverCtx->loadCertificate(kTestCert);
52 serverCtx->loadPrivateKey(kTestKey);
55 class SSLSessionTest : public testing::Test {
57 void SetUp() override {
58 clientCtx.reset(new folly::SSLContext());
59 dfServerCtx.reset(new folly::SSLContext());
60 hskServerCtx.reset(new folly::SSLContext());
61 serverName = "xyz.newdev.facebook.com";
62 getctx(clientCtx, dfServerCtx);
65 void TearDown() override {}
67 folly::EventBase eventBase;
68 std::shared_ptr<SSLContext> clientCtx;
69 std::shared_ptr<SSLContext> dfServerCtx;
70 // Use the same SSLContext to continue the handshake after
71 // tlsext_hostname match.
72 std::shared_ptr<SSLContext> hskServerCtx;
73 std::string serverName;
77 * 1. Client sends TLSEXT_HOSTNAME in client hello.
78 * 2. Server found a match SSL_CTX and use this SSL_CTX to
79 * continue the SSL handshake.
80 * 3. Server sends back TLSEXT_HOSTNAME in server hello.
82 TEST_F(SSLSessionTest, BasicTest) {
83 std::unique_ptr<SSLSession> sess;
88 AsyncSSLSocket::UniquePtr clientSock(
89 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
90 auto clientPtr = clientSock.get();
91 AsyncSSLSocket::UniquePtr serverSock(
92 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
93 SSLHandshakeClient client(std::move(clientSock), false, false);
94 SSLHandshakeServerParseClientHello server(
95 std::move(serverSock), false, false);
98 ASSERT_TRUE(client.handshakeSuccess_);
100 sess.reset(new SSLSession(clientPtr->getSSLSession()));
101 ASSERT_NE(sess.get(), nullptr);
107 AsyncSSLSocket::UniquePtr clientSock(
108 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
109 auto clientPtr = clientSock.get();
110 clientSock->setSSLSession(sess->getRawSSLSessionDangerous(), true);
111 AsyncSSLSocket::UniquePtr serverSock(
112 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
113 SSLHandshakeClient client(std::move(clientSock), false, false);
114 SSLHandshakeServerParseClientHello server(
115 std::move(serverSock), false, false);
118 ASSERT_TRUE(client.handshakeSuccess_);
119 ASSERT_TRUE(clientPtr->getSSLSessionReused());
122 TEST_F(SSLSessionTest, SerializeDeserializeTest) {
123 std::string sessiondata;
128 AsyncSSLSocket::UniquePtr clientSock(
129 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
130 auto clientPtr = clientSock.get();
131 AsyncSSLSocket::UniquePtr serverSock(
132 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
133 SSLHandshakeClient client(std::move(clientSock), false, false);
134 SSLHandshakeServerParseClientHello server(
135 std::move(serverSock), false, false);
138 ASSERT_TRUE(client.handshakeSuccess_);
140 std::unique_ptr<SSLSession> sess =
141 folly::make_unique<SSLSession>(clientPtr->getSSLSession());
142 sessiondata = sess->serialize();
143 ASSERT_TRUE(!sessiondata.empty());
149 AsyncSSLSocket::UniquePtr clientSock(
150 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
151 auto clientPtr = clientSock.get();
152 std::unique_ptr<SSLSession> sess =
153 folly::make_unique<SSLSession>(sessiondata);
154 ASSERT_NE(sess.get(), nullptr);
155 clientSock->setSSLSession(sess->getRawSSLSessionDangerous(), true);
156 AsyncSSLSocket::UniquePtr serverSock(
157 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
158 SSLHandshakeClient client(std::move(clientSock), false, false);
159 SSLHandshakeServerParseClientHello server(
160 std::move(serverSock), false, false);
163 ASSERT_TRUE(client.handshakeSuccess_);
164 ASSERT_TRUE(clientPtr->getSSLSessionReused());
168 TEST_F(SSLSessionTest, GetSessionID) {
171 AsyncSSLSocket::UniquePtr clientSock(
172 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
173 auto clientPtr = clientSock.get();
174 AsyncSSLSocket::UniquePtr serverSock(
175 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
176 SSLHandshakeClient client(std::move(clientSock), false, false);
177 SSLHandshakeServerParseClientHello server(
178 std::move(serverSock), false, false);
181 ASSERT_TRUE(client.handshakeSuccess_);
183 std::unique_ptr<SSLSession> sess =
184 folly::make_unique<SSLSession>(clientPtr->getSSLSession());
185 ASSERT_NE(sess, nullptr);
186 auto sessID = sess->getSessionID();
187 ASSERT_GE(sessID.length(), 0);