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 | |
26 | using namespace std; |
27 | using namespace testing; |
28 | using folly::ssl::SSLSession; |
29 | |
30 | namespace folly { |
31 | |
32 | void 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 | |
44 | void 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 | |
54 | class 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 | */ |
81 | TEST_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 | } |
121 | TEST_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 | |
167 | TEST_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 | |