1/*
2 * Copyright 2016-present Facebook, Inc.
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include <folly/ssl/SSLSession.h>
18#include <folly/io/async/test/AsyncSSLSocketTest.h>
19#include <folly/net/NetOps.h>
20#include <folly/net/NetworkSocket.h>
21#include <folly/portability/GTest.h>
22#include <folly/portability/Sockets.h>
23
24#include <memory>
25
26using namespace std;
27using namespace testing;
28using folly::ssl::SSLSession;
29
30namespace folly {
31
32void getfds(NetworkSocket fds[2]) {
33 if (netops::socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
34 FAIL() << "failed to create socketpair: " << errnoStr(errno);
35 }
36 for (int idx = 0; idx < 2; ++idx) {
37 if (netops::set_socket_non_blocking(fds[idx]) != 0) {
38 FAIL() << "failed to put socket " << idx
39 << " in non-blocking mode: " << errnoStr(errno);
40 }
41 }
42}
43
44void getctx(
45 std::shared_ptr<folly::SSLContext> clientCtx,
46 std::shared_ptr<folly::SSLContext> serverCtx) {
47 clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
48
49 serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
50 serverCtx->loadCertificate(kTestCert);
51 serverCtx->loadPrivateKey(kTestKey);
52}
53
54class SSLSessionTest : public testing::Test {
55 public:
56 void SetUp() override {
57 clientCtx.reset(new folly::SSLContext());
58 dfServerCtx.reset(new folly::SSLContext());
59 hskServerCtx.reset(new folly::SSLContext());
60 serverName = "xyz.newdev.facebook.com";
61 getctx(clientCtx, dfServerCtx);
62 }
63
64 void TearDown() override {}
65
66 folly::EventBase eventBase;
67 std::shared_ptr<SSLContext> clientCtx;
68 std::shared_ptr<SSLContext> dfServerCtx;
69 // Use the same SSLContext to continue the handshake after
70 // tlsext_hostname match.
71 std::shared_ptr<SSLContext> hskServerCtx;
72 std::string serverName;
73};
74
75/**
76 * 1. Client sends TLSEXT_HOSTNAME in client hello.
77 * 2. Server found a match SSL_CTX and use this SSL_CTX to
78 * continue the SSL handshake.
79 * 3. Server sends back TLSEXT_HOSTNAME in server hello.
80 */
81TEST_F(SSLSessionTest, BasicTest) {
82 std::unique_ptr<SSLSession> sess;
83
84 {
85 NetworkSocket fds[2];
86 getfds(fds);
87 AsyncSSLSocket::UniquePtr clientSock(
88 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
89 auto clientPtr = clientSock.get();
90 AsyncSSLSocket::UniquePtr serverSock(
91 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
92 SSLHandshakeClient client(std::move(clientSock), false, false);
93 SSLHandshakeServerParseClientHello server(
94 std::move(serverSock), false, false);
95
96 eventBase.loop();
97 ASSERT_TRUE(client.handshakeSuccess_);
98
99 sess = std::make_unique<SSLSession>(clientPtr->getSSLSession());
100 ASSERT_NE(sess.get(), nullptr);
101 }
102
103 {
104 NetworkSocket fds[2];
105 getfds(fds);
106 AsyncSSLSocket::UniquePtr clientSock(
107 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
108 auto clientPtr = clientSock.get();
109 clientSock->setSSLSession(sess->getRawSSLSessionDangerous(), true);
110 AsyncSSLSocket::UniquePtr serverSock(
111 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
112 SSLHandshakeClient client(std::move(clientSock), false, false);
113 SSLHandshakeServerParseClientHello server(
114 std::move(serverSock), false, false);
115
116 eventBase.loop();
117 ASSERT_TRUE(client.handshakeSuccess_);
118 ASSERT_TRUE(clientPtr->getSSLSessionReused());
119 }
120}
121TEST_F(SSLSessionTest, SerializeDeserializeTest) {
122 std::string sessiondata;
123
124 {
125 NetworkSocket fds[2];
126 getfds(fds);
127 AsyncSSLSocket::UniquePtr clientSock(
128 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
129 auto clientPtr = clientSock.get();
130 AsyncSSLSocket::UniquePtr serverSock(
131 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
132 SSLHandshakeClient client(std::move(clientSock), false, false);
133 SSLHandshakeServerParseClientHello server(
134 std::move(serverSock), false, false);
135
136 eventBase.loop();
137 ASSERT_TRUE(client.handshakeSuccess_);
138
139 std::unique_ptr<SSLSession> sess =
140 std::make_unique<SSLSession>(clientPtr->getSSLSession());
141 sessiondata = sess->serialize();
142 ASSERT_TRUE(!sessiondata.empty());
143 }
144
145 {
146 NetworkSocket fds[2];
147 getfds(fds);
148 AsyncSSLSocket::UniquePtr clientSock(
149 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
150 auto clientPtr = clientSock.get();
151 std::unique_ptr<SSLSession> sess =
152 std::make_unique<SSLSession>(sessiondata);
153 ASSERT_NE(sess.get(), nullptr);
154 clientSock->setSSLSession(sess->getRawSSLSessionDangerous(), true);
155 AsyncSSLSocket::UniquePtr serverSock(
156 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
157 SSLHandshakeClient client(std::move(clientSock), false, false);
158 SSLHandshakeServerParseClientHello server(
159 std::move(serverSock), false, false);
160
161 eventBase.loop();
162 ASSERT_TRUE(client.handshakeSuccess_);
163 ASSERT_TRUE(clientPtr->getSSLSessionReused());
164 }
165}
166
167TEST_F(SSLSessionTest, GetSessionID) {
168 NetworkSocket fds[2];
169 getfds(fds);
170 AsyncSSLSocket::UniquePtr clientSock(
171 new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
172 auto clientPtr = clientSock.get();
173 AsyncSSLSocket::UniquePtr serverSock(
174 new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
175 SSLHandshakeClient client(std::move(clientSock), false, false);
176 SSLHandshakeServerParseClientHello server(
177 std::move(serverSock), false, false);
178
179 eventBase.loop();
180 ASSERT_TRUE(client.handshakeSuccess_);
181
182 std::unique_ptr<SSLSession> sess =
183 std::make_unique<SSLSession>(clientPtr->getSSLSession());
184 ASSERT_NE(sess, nullptr);
185 auto sessID = sess->getSessionID();
186 ASSERT_GE(sessID.length(), 0);
187}
188} // namespace folly
189