 Chromium Code Reviews
 Chromium Code Reviews| OLD | NEW | 
|---|---|
| (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 | |
| OLD | NEW |