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 const char* testCert = "folly/io/async/test/certs/tests-cert.pem";
29 const char* testKey = "folly/io/async/test/certs/tests-key.pem";
30 const char* testCA = "folly/io/async/test/certs/ca-cert.pem";
32 void getfds(int fds[2]) {
33 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
34 LOG(ERROR) << "failed to create socketpair: " << strerror(errno);
36 for (int idx = 0; idx < 2; ++idx) {
37 int flags = fcntl(fds[idx], F_GETFL, 0);
39 LOG(ERROR) << "failed to get flags for socket " << idx << ": "
42 if (fcntl(fds[idx], F_SETFL, flags | O_NONBLOCK) != 0) {
43 LOG(ERROR) << "failed to put socket " << idx
44 << " in non-blocking mode: " << strerror(errno);
50 std::shared_ptr<folly::SSLContext> clientCtx,
51 std::shared_ptr<folly::SSLContext> serverCtx) {
52 clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
54 serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
55 serverCtx->loadCertificate(testCert);
56 serverCtx->loadPrivateKey(testKey);
59 class SSLSessionTest : public testing::Test {
61 void SetUp() override {
62 clientCtx.reset(new folly::SSLContext());
63 dfServerCtx.reset(new folly::SSLContext());
64 hskServerCtx.reset(new folly::SSLContext());
65 serverName = "xyz.newdev.facebook.com";
66 getctx(clientCtx, dfServerCtx);
69 void TearDown() override {}
71 folly::EventBase eventBase;
72 std::shared_ptr<SSLContext> clientCtx;
73 std::shared_ptr<SSLContext> dfServerCtx;
74 // Use the same SSLContext to continue the handshake after
75 // tlsext_hostname match.
76 std::shared_ptr<SSLContext> hskServerCtx;
77 std::string serverName;
81 * 1. Client sends TLSEXT_HOSTNAME in client hello.
82 * 2. Server found a match SSL_CTX and use this SSL_CTX to
83 * continue the SSL handshake.
84 * 3. Server sends back TLSEXT_HOSTNAME in server hello.
86 TEST_F(SSLSessionTest, BasicTest) {
87 std::unique_ptr<SSLSession> sess;
92 AsyncSSLSocket::UniquePtr clientSock(
93 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
94 auto clientPtr = clientSock.get();
95 AsyncSSLSocket::UniquePtr serverSock(
96 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
97 SSLHandshakeClient client(std::move(clientSock), false, false);
98 SSLHandshakeServerParseClientHello server(
99 std::move(serverSock), false, false);
102 ASSERT_TRUE(client.handshakeSuccess_);
104 sess.reset(new SSLSession(clientPtr->getSSLSession()));
105 ASSERT_NE(sess.get(), nullptr);
111 AsyncSSLSocket::UniquePtr clientSock(
112 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
113 auto clientPtr = clientSock.get();
114 clientSock->setSSLSession(sess->getRawSSLSessionDangerous(), true);
115 AsyncSSLSocket::UniquePtr serverSock(
116 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
117 SSLHandshakeClient client(std::move(clientSock), false, false);
118 SSLHandshakeServerParseClientHello server(
119 std::move(serverSock), false, false);
122 ASSERT_TRUE(client.handshakeSuccess_);
123 ASSERT_TRUE(clientPtr->getSSLSessionReused());
126 TEST_F(SSLSessionTest, SerializeDeserializeTest) {
127 std::string sessiondata;
132 AsyncSSLSocket::UniquePtr clientSock(
133 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
134 auto clientPtr = clientSock.get();
135 AsyncSSLSocket::UniquePtr serverSock(
136 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
137 SSLHandshakeClient client(std::move(clientSock), false, false);
138 SSLHandshakeServerParseClientHello server(
139 std::move(serverSock), false, false);
142 ASSERT_TRUE(client.handshakeSuccess_);
144 std::unique_ptr<SSLSession> sess =
145 folly::make_unique<SSLSession>(clientPtr->getSSLSession());
146 sessiondata = sess->serialize();
147 ASSERT_TRUE(!sessiondata.empty());
153 AsyncSSLSocket::UniquePtr clientSock(
154 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
155 auto clientPtr = clientSock.get();
156 std::unique_ptr<SSLSession> sess =
157 folly::make_unique<SSLSession>(sessiondata);
158 ASSERT_NE(sess.get(), nullptr);
159 clientSock->setSSLSession(sess->getRawSSLSessionDangerous(), true);
160 AsyncSSLSocket::UniquePtr serverSock(
161 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
162 SSLHandshakeClient client(std::move(clientSock), false, false);
163 SSLHandshakeServerParseClientHello server(
164 std::move(serverSock), false, false);
167 ASSERT_TRUE(client.handshakeSuccess_);
168 ASSERT_TRUE(clientPtr->getSSLSessionReused());
172 TEST_F(SSLSessionTest, GetSessionID) {
175 AsyncSSLSocket::UniquePtr clientSock(
176 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
177 auto clientPtr = clientSock.get();
178 AsyncSSLSocket::UniquePtr serverSock(
179 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
180 SSLHandshakeClient client(std::move(clientSock), false, false);
181 SSLHandshakeServerParseClientHello server(
182 std::move(serverSock), false, false);
185 ASSERT_TRUE(client.handshakeSuccess_);
187 std::unique_ptr<SSLSession> sess =
188 folly::make_unique<SSLSession>(clientPtr->getSSLSession());
189 ASSERT_NE(sess, nullptr);
190 auto sessID = sess->getSessionID();
191 ASSERT_GE(sessID.length(), 0);