2 * Copyright 2016 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/portability/Unistd.h>
21 #include <folly/ssl/SSLSession.h>
24 using namespace testing;
25 using folly::ssl::SSLSession;
29 const char* testCert = "folly/io/async/test/certs/tests-cert.pem";
30 const char* testKey = "folly/io/async/test/certs/tests-key.pem";
31 const char* testCA = "folly/io/async/test/certs/ca-cert.pem";
33 void getfds(int fds[2]) {
34 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
35 LOG(ERROR) << "failed to create socketpair: " << strerror(errno);
37 for (int idx = 0; idx < 2; ++idx) {
38 int flags = fcntl(fds[idx], F_GETFL, 0);
40 LOG(ERROR) << "failed to get flags for socket " << idx << ": "
43 if (fcntl(fds[idx], F_SETFL, flags | O_NONBLOCK) != 0) {
44 LOG(ERROR) << "failed to put socket " << idx
45 << " in non-blocking mode: " << strerror(errno);
51 std::shared_ptr<folly::SSLContext> clientCtx,
52 std::shared_ptr<folly::SSLContext> serverCtx) {
53 clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
55 serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
56 serverCtx->loadCertificate(testCert);
57 serverCtx->loadPrivateKey(testKey);
60 class SSLSessionTest : public testing::Test {
62 void SetUp() override {
63 clientCtx.reset(new folly::SSLContext());
64 dfServerCtx.reset(new folly::SSLContext());
65 hskServerCtx.reset(new folly::SSLContext());
66 serverName = "xyz.newdev.facebook.com";
67 getctx(clientCtx, dfServerCtx);
70 void TearDown() override {}
72 folly::EventBase eventBase;
73 std::shared_ptr<SSLContext> clientCtx;
74 std::shared_ptr<SSLContext> dfServerCtx;
75 // Use the same SSLContext to continue the handshake after
76 // tlsext_hostname match.
77 std::shared_ptr<SSLContext> hskServerCtx;
78 std::string serverName;
82 * 1. Client sends TLSEXT_HOSTNAME in client hello.
83 * 2. Server found a match SSL_CTX and use this SSL_CTX to
84 * continue the SSL handshake.
85 * 3. Server sends back TLSEXT_HOSTNAME in server hello.
87 TEST_F(SSLSessionTest, BasicTest) {
88 std::unique_ptr<SSLSession> sess;
93 AsyncSSLSocket::UniquePtr clientSock(
94 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
95 auto clientPtr = clientSock.get();
96 AsyncSSLSocket::UniquePtr serverSock(
97 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
98 SSLHandshakeClient client(std::move(clientSock), false, false);
99 SSLHandshakeServerParseClientHello server(
100 std::move(serverSock), false, false);
103 ASSERT_TRUE(client.handshakeSuccess_);
105 sess.reset(new SSLSession(clientPtr->getSSLSession()));
106 ASSERT_NE(sess.get(), nullptr);
112 AsyncSSLSocket::UniquePtr clientSock(
113 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
114 auto clientPtr = clientSock.get();
115 clientSock->setSSLSession(sess->getRawSSLSessionDangerous(), true);
116 AsyncSSLSocket::UniquePtr serverSock(
117 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
118 SSLHandshakeClient client(std::move(clientSock), false, false);
119 SSLHandshakeServerParseClientHello server(
120 std::move(serverSock), false, false);
123 ASSERT_TRUE(client.handshakeSuccess_);
124 ASSERT_TRUE(clientPtr->getSSLSessionReused());
127 TEST_F(SSLSessionTest, SerializeDeserializeTest) {
128 std::string sessiondata;
133 AsyncSSLSocket::UniquePtr clientSock(
134 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
135 auto clientPtr = clientSock.get();
136 AsyncSSLSocket::UniquePtr serverSock(
137 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
138 SSLHandshakeClient client(std::move(clientSock), false, false);
139 SSLHandshakeServerParseClientHello server(
140 std::move(serverSock), false, false);
143 ASSERT_TRUE(client.handshakeSuccess_);
145 std::unique_ptr<SSLSession> sess =
146 folly::make_unique<SSLSession>(clientPtr->getSSLSession());
147 sessiondata = sess->serialize();
148 ASSERT_TRUE(!sessiondata.empty());
154 AsyncSSLSocket::UniquePtr clientSock(
155 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
156 auto clientPtr = clientSock.get();
157 std::unique_ptr<SSLSession> sess =
158 folly::make_unique<SSLSession>(sessiondata);
159 ASSERT_NE(sess.get(), nullptr);
160 clientSock->setSSLSession(sess->getRawSSLSessionDangerous(), true);
161 AsyncSSLSocket::UniquePtr serverSock(
162 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
163 SSLHandshakeClient client(std::move(clientSock), false, false);
164 SSLHandshakeServerParseClientHello server(
165 std::move(serverSock), false, false);
168 ASSERT_TRUE(client.handshakeSuccess_);
169 ASSERT_TRUE(clientPtr->getSSLSessionReused());
173 TEST_F(SSLSessionTest, GetSessionID) {
176 AsyncSSLSocket::UniquePtr clientSock(
177 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
178 auto clientPtr = clientSock.get();
179 AsyncSSLSocket::UniquePtr serverSock(
180 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
181 SSLHandshakeClient client(std::move(clientSock), false, false);
182 SSLHandshakeServerParseClientHello server(
183 std::move(serverSock), false, false);
186 ASSERT_TRUE(client.handshakeSuccess_);
188 std::unique_ptr<SSLSession> sess =
189 folly::make_unique<SSLSession>(clientPtr->getSSLSession());
190 ASSERT_NE(sess, nullptr);
191 auto sessID = sess->getSessionID();
192 ASSERT_GE(sessID.length(), 0);