apply clang-tidy modernize-use-override
[folly.git] / folly / io / async / test / SSLSessionTest.cpp
1 /*
2  * Copyright 2017 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/io/async/test/AsyncSSLSocketTest.h>
18 #include <folly/portability/GTest.h>
19 #include <folly/portability/Sockets.h>
20 #include <folly/ssl/SSLSession.h>
21
22 using namespace std;
23 using namespace testing;
24 using folly::ssl::SSLSession;
25
26 namespace folly {
27
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);
31   }
32   for (int idx = 0; idx < 2; ++idx) {
33     int flags = fcntl(fds[idx], F_GETFL, 0);
34     if (flags == -1) {
35       LOG(ERROR) << "failed to get flags for socket " << idx << ": "
36                  << strerror(errno);
37     }
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);
41     }
42   }
43 }
44
45 void getctx(
46     std::shared_ptr<folly::SSLContext> clientCtx,
47     std::shared_ptr<folly::SSLContext> serverCtx) {
48   clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
49
50   serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
51   serverCtx->loadCertificate(kTestCert);
52   serverCtx->loadPrivateKey(kTestKey);
53 }
54
55 class SSLSessionTest : public testing::Test {
56  public:
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);
63   }
64
65   void TearDown() override {}
66
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;
74 };
75
76 /**
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.
81  */
82 TEST_F(SSLSessionTest, BasicTest) {
83   std::unique_ptr<SSLSession> sess;
84
85   {
86     int fds[2];
87     getfds(fds);
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);
96
97     eventBase.loop();
98     ASSERT_TRUE(client.handshakeSuccess_);
99
100     sess.reset(new SSLSession(clientPtr->getSSLSession()));
101     ASSERT_NE(sess.get(), nullptr);
102   }
103
104   {
105     int fds[2];
106     getfds(fds);
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);
116
117     eventBase.loop();
118     ASSERT_TRUE(client.handshakeSuccess_);
119     ASSERT_TRUE(clientPtr->getSSLSessionReused());
120   }
121 }
122 TEST_F(SSLSessionTest, SerializeDeserializeTest) {
123   std::string sessiondata;
124
125   {
126     int fds[2];
127     getfds(fds);
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);
136
137     eventBase.loop();
138     ASSERT_TRUE(client.handshakeSuccess_);
139
140     std::unique_ptr<SSLSession> sess =
141         std::make_unique<SSLSession>(clientPtr->getSSLSession());
142     sessiondata = sess->serialize();
143     ASSERT_TRUE(!sessiondata.empty());
144   }
145
146   {
147     int fds[2];
148     getfds(fds);
149     AsyncSSLSocket::UniquePtr clientSock(
150         new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
151     auto clientPtr = clientSock.get();
152     std::unique_ptr<SSLSession> sess =
153         std::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);
161
162     eventBase.loop();
163     ASSERT_TRUE(client.handshakeSuccess_);
164     ASSERT_TRUE(clientPtr->getSSLSessionReused());
165   }
166 }
167
168 TEST_F(SSLSessionTest, GetSessionID) {
169   int fds[2];
170   getfds(fds);
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);
179
180   eventBase.loop();
181   ASSERT_TRUE(client.handshakeSuccess_);
182
183   std::unique_ptr<SSLSession> sess =
184       std::make_unique<SSLSession>(clientPtr->getSSLSession());
185   ASSERT_NE(sess, nullptr);
186   auto sessID = sess->getSessionID();
187   ASSERT_GE(sessID.length(), 0);
188 }
189 }