Chromium Code Reviews

Side by Side Diff: net/socket/ssl_client_socket_snapstart_unittest.cc

Issue 4524003: net: add Snap Start tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ... Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "build/build_config.h"
Mike Belshe 2010/11/08 16:41:10 q: is this intentional?
6
7 #include <arpa/inet.h>
8 #include <netinet/tcp.h>
9 #include <stdarg.h>
10 #include <sys/socket.h>
11 #include <sys/types.h>
12
13 #include <sslt.h>
14
15 #include <vector>
16 #include <string>
17
18 #include "base/eintr_wrapper.h"
19 #include "base/base64.h"
20 #include "base/file_path.h"
21 #include "base/file_util.h"
22 #include "base/path_service.h"
23 #include "base/process_util.h"
24 #include "base/string_util.h"
25 #include "base/values.h"
26 #include "net/base/io_buffer.h"
27 #include "net/base/net_errors.h"
28 #include "net/base/net_log.h"
29 #include "net/base/net_log_unittest.h"
30 #include "net/base/ssl_config_service.h"
31 #include "net/base/test_completion_callback.h"
32 #include "net/socket/client_socket_factory.h"
33 #include "net/socket/ssl_client_socket.h"
34 #include "net/socket/ssl_client_socket_nss.h"
35 #include "net/socket/ssl_host_info.h"
36 #include "net/socket/tcp_client_socket.h"
37 #include "testing/gtest/include/gtest/gtest.h"
38 #include "testing/platform_test.h"
39
40 namespace net {
41
42 // TestSSLHostInfo is an SSLHostInfo which stores a single state in memory and
43 // pretends that certificate verification always succeeds.
44 class TestSSLHostInfo : public SSLHostInfo {
45 public:
46 TestSSLHostInfo()
47 : SSLHostInfo("example.com", kDefaultSSLConfig) {
48 if (!saved_.empty())
49 Parse(saved_);
50 cert_verification_complete_ = true;
51 cert_verification_result_ = OK;
52 }
53
54 virtual void Start() {
55 NOTREACHED();
Paweł Hajdan Jr. 2010/11/08 16:55:33 Please read http://www.chromium.org/developers/cod
56 }
57
58 virtual int WaitForDataReady(CompletionCallback*) { return OK; }
59
60 virtual void Persist() {
61 saved_ = Serialize();
62 }
63
64 static void Reset() {
65 saved_.clear();
66 }
67
68 private:
69 static SSLConfig kDefaultSSLConfig;
70 static std::string saved_;
71 };
72
73 std::string TestSSLHostInfo::saved_;
74
75 SSLConfig TestSSLHostInfo::kDefaultSSLConfig;
76
77 class SSLClientSocketSnapStartTest : public PlatformTest {
78 public:
79 SSLClientSocketSnapStartTest()
80 : child_(base::kNullProcessHandle),
81 socket_factory_(ClientSocketFactory::GetDefaultFactory()),
82 log_(CapturingNetLog::kUnbounded) {
83 TestSSLHostInfo::Reset();
84 ssl_config_.snap_start_enabled = true;
85 }
86
87 virtual void TearDown() {
88 if (child_ != base::kNullProcessHandle) {
89 int exit_code;
90 EXPECT_TRUE(base::WaitForExitCode(child_, &exit_code));
91 EXPECT_EQ(0, exit_code);
92 }
93 }
94
95 protected:
96 void StartSnapStartServer(const char* arg, ...) {
97 FilePath dir_exe;
98 if (!PathService::Get(base::DIR_EXE, &dir_exe))
99 LOG(FATAL) << "Failed to get DIR_EXE";
Paweł Hajdan Jr. 2010/11/08 16:55:33 Same here, and all other similar places.
100 FilePath helper_binary = dir_exe.Append("openssl_helper");
101
102 std::vector<std::string> args;
103 args.push_back(helper_binary.value());
104
105 va_list ap;
106 va_start(ap, arg);
107 while (arg) {
108 args.push_back(arg);
109 arg = va_arg(ap, const char*);
110 }
111 va_end(ap);
112
113 const int listener = socket(AF_INET, SOCK_STREAM, 0);
114 ASSERT_GE(listener, 0);
115 struct sockaddr_in sin;
116 memset(&sin, 0, sizeof(sin));
117 sin.sin_family = PF_INET;
118 ASSERT_EQ(0, bind(listener, (struct sockaddr*) &sin, sizeof(sin)));
119 socklen_t socklen = sizeof(remote_);
120 ASSERT_EQ(0, getsockname(listener, (struct sockaddr*) &remote_, &socklen));
121 ASSERT_EQ(sizeof(remote_), socklen);
122 ASSERT_EQ(0, listen(listener, 1));
123
124 base::file_handle_mapping_vector mapping;
125 // The listening socket is installed as the child's fd 3.
126 mapping.push_back(std::make_pair(listener, 3));
127 base::LaunchApp(args, mapping, false /* don't wait */, &child_);
128 HANDLE_EINTR(close(listener));
129 }
130
131 // LoadDefaultCert returns the DER encoded default certificate.
132 std::string LoadDefaultCert() {
133 FilePath path;
134 if (!PathService::Get(base::DIR_SOURCE_ROOT, &path))
135 LOG(FATAL) << "Failed to get DIR_SOURCE_ROOT";
136 path = path.Append("net");
137 path = path.Append("data");
138 path = path.Append("ssl");
139 path = path.Append("certificates");
140 path = path.Append("ok_cert.pem");
141
142 std::string pem;
143 bool r = file_util::ReadFileToString(path, &pem);
144 CHECK(r) << "failed to read " << path.value();
Paweł Hajdan Jr. 2010/11/08 16:55:33 CHECK is bad too.
145
146 static const char kStartMarker[] = "-----BEGIN CERTIFICATE-----\n";
147 static const char kEndMarker[] = "-----END CERTIFICATE-----\n";
148
149 std::string::size_type i = pem.find(kStartMarker);
150 std::string::size_type j = pem.find(kEndMarker);
151 CHECK(i != std::string::npos);
152 CHECK(j != std::string::npos);
153 CHECK_GT(j, i);
154 i += sizeof(kStartMarker) - 1;
155
156 std::string b64data = pem.substr(i, j - i);
157 ReplaceSubstringsAfterOffset(&b64data, 0 /* start offset */, "\n", "");
158
159 std::string der;
160 base::Base64Decode(b64data, &der);
161 return der;
162 }
163
164 void SetupSSLConfig() {
165 if (ssl_config_.allowed_bad_certs.size())
166 return;
167 const std::string der = LoadDefaultCert();
168 SSLConfig::CertAndStatus cert_and_status;
169 cert_and_status.cert =
170 X509Certificate::CreateFromBytes(der.data(), der.size());
171 cert_and_status.cert_status = ERR_CERT_AUTHORITY_INVALID;
172
173 ssl_config_.allowed_bad_certs.push_back(cert_and_status);
174 }
175
176 // PerformConnection makes an SSL connection to the openssl_helper binary and
177 // does a ping-pong test to check the the SSL socket is working correctly.
178 void PerformConnection() {
179 client_ = socket(AF_INET, SOCK_STREAM, 0);
180 ASSERT_LE(0, client_);
181 ASSERT_EQ(
182 0, connect(client_, (struct sockaddr*) &remote_, sizeof(remote_)));
183 int on = 1;
184 setsockopt(client_, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
185
186 SetupSSLConfig();
187 log_.Clear();
188
189 std::vector<uint8> localhost;
190 localhost.push_back(127);
191 localhost.push_back(0);
192 localhost.push_back(0);
193 localhost.push_back(1);
194 AddressList addr_list(localhost, 443, false);
195 TCPClientSocket* transport = new TCPClientSocket(
196 addr_list, &log_, NetLog::Source());
197
198 transport->AdoptSocket(client_);
199 scoped_ptr<SSLClientSocket> sock(
200 socket_factory_->CreateSSLClientSocket(transport,
201 "example.com", ssl_config_, new TestSSLHostInfo()));
202
203 TestCompletionCallback callback;
204 int rv = sock->Connect(&callback);
205 if (rv != OK) {
206 ASSERT_EQ(ERR_IO_PENDING, rv);
207 EXPECT_FALSE(sock->IsConnected());
208 rv = callback.WaitForResult();
209 EXPECT_EQ(OK, rv);
210 }
211 EXPECT_TRUE(sock->IsConnected());
212
213 static const char request_text[] = "hello!";
214 scoped_refptr<IOBuffer> request_buffer =
215 new IOBuffer(arraysize(request_text) - 1);
216 memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
217 rv = sock->Write(request_buffer, arraysize(request_text), &callback);
218 if (rv < 0) {
219 ASSERT_EQ(ERR_IO_PENDING, rv);
220 rv = callback.WaitForResult();
221 }
222 EXPECT_EQ(7, rv);
223
224 scoped_refptr<IOBuffer> reply_buffer = new IOBuffer(8);
225 rv = sock->Read(reply_buffer, 8, &callback);
226 if (rv < 0) {
227 ASSERT_EQ(ERR_IO_PENDING, rv);
228 rv = callback.WaitForResult();
229 }
230 EXPECT_EQ(8, rv);
231 EXPECT_TRUE(memcmp(reply_buffer->data(), "goodbye!", 8) == 0);
232
233 sock->Disconnect();
234 }
235
236 // SnapStartEventType extracts the type of Snap Start from the NetLog. See
237 // the SSL_SNAP_START_* defines in sslt.h
238 int SnapStartEventType() {
239 const std::vector<CapturingNetLog::Entry>& entries = log_.entries();
240 for (std::vector<CapturingNetLog::Entry>::const_iterator
241 i = entries.begin(); i != entries.end(); i++) {
242 if (i->type == NetLog::TYPE_SSL_SNAP_START) {
243 scoped_ptr<Value> value(i->extra_parameters->ToValue());
244 CHECK(value->GetType() == Value::TYPE_DICTIONARY);
245 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(value.get());
246 int ret;
247 CHECK(dict->GetInteger("type", &ret));
248 return ret;
249 }
250 }
251
252 NOTREACHED();
253 return -1;
254 }
255
256 // DidMerge returns true if the NetLog suggests the the SSL connection
257 // merge it's certificate validation with the optimistic validation from
Mike Belshe 2010/11/08 16:41:10 nit: /merge/merged
258 // the SSLHostInfo.
259 bool DidMerge() {
260 const std::vector<CapturingNetLog::Entry>& entries = log_.entries();
261 for (std::vector<CapturingNetLog::Entry>::const_iterator
262 i = entries.begin(); i != entries.end(); i++) {
263 if (i->type == NetLog::TYPE_SSL_VERIFICATION_MERGED)
264 return true;
265 }
266 return false;
267 }
268
269 base::ProcessHandle child_;
270 ClientSocketFactory* const socket_factory_;
271 struct sockaddr_in remote_;
272 int client_;
273 SSLConfig ssl_config_;
274 CapturingNetLog log_;
275 };
276
277 TEST_F(SSLClientSocketSnapStartTest, Basic) {
278 // Not a Snap Start connection.
279 StartSnapStartServer(NULL);
280 PerformConnection();
281 EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType());
282 EXPECT_FALSE(DidMerge());
283 }
284
285 TEST_F(SSLClientSocketSnapStartTest, SnapStart) {
286 StartSnapStartServer("snap-start", NULL);
287 PerformConnection();
288 EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType());
289 EXPECT_FALSE(DidMerge());
290 SSLClientSocketNSS::DropSessionCache();
291 PerformConnection();
292 EXPECT_EQ(SSL_SNAP_START_FULL, SnapStartEventType());
293 EXPECT_TRUE(DidMerge());
294 }
295
296 TEST_F(SSLClientSocketSnapStartTest, SnapStartResume) {
297 StartSnapStartServer("snap-start", NULL);
298 PerformConnection();
299 EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType());
300 EXPECT_FALSE(DidMerge());
301 PerformConnection();
302 EXPECT_EQ(SSL_SNAP_START_RESUME, SnapStartEventType());
303 EXPECT_TRUE(DidMerge());
304 }
305
306 TEST_F(SSLClientSocketSnapStartTest, SnapStartRecovery) {
307 StartSnapStartServer("snap-start-recovery", NULL);
308 PerformConnection();
309 EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType());
310 EXPECT_FALSE(DidMerge());
311 SSLClientSocketNSS::DropSessionCache();
312 PerformConnection();
313 EXPECT_EQ(SSL_SNAP_START_RECOVERY, SnapStartEventType());
314 EXPECT_TRUE(DidMerge());
315 }
316
317 TEST_F(SSLClientSocketSnapStartTest, SnapStartResumeRecovery) {
318 StartSnapStartServer("snap-start-recovery", NULL);
319 PerformConnection();
320 EXPECT_EQ(SSL_SNAP_START_NONE, SnapStartEventType());
321 EXPECT_FALSE(DidMerge());
322 PerformConnection();
323 EXPECT_EQ(SSL_SNAP_START_RESUME_RECOVERY, SnapStartEventType());
324 EXPECT_TRUE(DidMerge());
325 }
326
327 } // namespace net
OLDNEW
« no previous file with comments | « net/net.gyp ('k') | net/test/openssl_helper.cc » ('j') | net/test/openssl_helper.cc » ('J')

Powered by Google App Engine