Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

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

Issue 6804032: Add TLS-SRP (RFC 5054) support Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: remove "httpsv" scheme, minor NSS/OpenSSL changes Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/socket/ssl_client_socket_nss.cc ('k') | net/socket/ssl_client_socket_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <arpa/inet.h>
6 #include <netinet/tcp.h>
7 #include <stdarg.h>
8 #include <sys/socket.h>
9 #include <sys/types.h>
10
11 #include <sslt.h>
12
13 #include <vector>
14 #include <string>
15
16 #include "base/eintr_wrapper.h"
17 #include "base/base64.h"
18 #include "base/file_path.h"
19 #include "base/file_util.h"
20 #include "base/path_service.h"
21 #include "base/process_util.h"
22 #include "base/string_util.h"
23 #include "base/values.h"
24 #include "net/base/io_buffer.h"
25 #include "net/base/net_errors.h"
26 #include "net/base/net_log.h"
27 #include "net/base/net_log_unittest.h"
28 #include "net/base/ssl_config_service.h"
29 #include "net/base/test_completion_callback.h"
30 #include "net/socket/client_socket_factory.h"
31 #include "net/socket/ssl_client_socket.h"
32 #include "net/socket/ssl_client_socket_nss.h"
33 #include "net/socket/ssl_host_info.h"
34 #include "net/socket/tcp_client_socket.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "testing/gtest/include/gtest/gtest-spi.h"
37 #include "testing/platform_test.h"
38
39 namespace net {
40
41 // TestSSLHostInfo is an SSLHostInfo which stores a single state in memory and
42 // pretends that certificate verification always succeeds.
43 class TestSSLHostInfo : public SSLHostInfo {
44 public:
45 explicit TestSSLHostInfo(CertVerifier* cert_verifier)
46 : SSLHostInfo("example.com", kDefaultSSLConfig, cert_verifier) {
47 if (!saved_.empty())
48 Parse(saved_);
49 cert_verification_complete_ = true;
50 cert_verification_error_ = OK;
51 }
52
53 virtual void Start() {
54 }
55
56 virtual int WaitForDataReady(CompletionCallback*) { return OK; }
57
58 virtual void Persist() {
59 saved_ = Serialize();
60 }
61
62 static void Reset() {
63 saved_.clear();
64 }
65
66 private:
67 static SSLConfig kDefaultSSLConfig;
68 static std::string saved_;
69 };
70
71 std::string TestSSLHostInfo::saved_;
72
73 SSLConfig TestSSLHostInfo::kDefaultSSLConfig;
74
75 class SSLClientSocketTLSSRPTest : public PlatformTest {
76 public:
77 SSLClientSocketTLSSRPTest()
78 : child_(base::kNullProcessHandle),
79 socket_factory_(ClientSocketFactory::GetDefaultFactory()),
80 log_(CapturingNetLog::kUnbounded),
81 expected_exit_code_(0)
82 {
83 TestSSLHostInfo::Reset();
84 }
85
86 virtual void TearDown() {
87 if (child_ != base::kNullProcessHandle) {
88 int exit_code;
89 EXPECT_TRUE(base::WaitForExitCode(child_, &exit_code));
90 EXPECT_EQ(expected_exit_code_, exit_code);
91 }
92 }
93
94 protected:
95 void StartTLSSRPServer(const char* arg, ...) {
96 FilePath dir_exe;
97 PathService::Get(base::DIR_EXE, &dir_exe);
98 FilePath helper_binary = dir_exe.Append("openssl_helper");
99
100 std::vector<std::string> args;
101 args.push_back(helper_binary.value());
102
103 args.push_back("tls-srp");
104 args.push_back("--srpv-file");
105 args.push_back(GetDefaultSRPVFilePath());
106
107 // Additional arguments can override the --srpv-file set above.
108 va_list ap;
109 va_start(ap, arg);
110 while (arg) {
111 args.push_back(arg);
112 arg = va_arg(ap, const char*);
113 }
114 va_end(ap);
115
116 const int listener = socket(AF_INET, SOCK_STREAM, 0);
117 ASSERT_GE(listener, 0);
118 struct sockaddr_in sin;
119 memset(&sin, 0, sizeof(sin));
120 sin.sin_family = PF_INET;
121 ASSERT_EQ(0, bind(listener, (struct sockaddr*) &sin, sizeof(sin)));
122 socklen_t socklen = sizeof(remote_);
123 ASSERT_EQ(0, getsockname(listener, (struct sockaddr*) &remote_, &socklen));
124 ASSERT_EQ(sizeof(remote_), socklen);
125 ASSERT_EQ(0, listen(listener, 1));
126
127 base::file_handle_mapping_vector mapping;
128 // The listening socket is installed as the child's fd 3.
129 mapping.push_back(std::make_pair(listener, 3));
130 base::LaunchApp(args, mapping, false /* don't wait */, &child_);
131 ASSERT_EQ(0, HANDLE_EINTR(close(listener)));
132 }
133
134 // GetDefaultSRPVFilePath returns the path to the default test SRPV file,
135 // ok.srpv
136 std::string GetDefaultSRPVFilePath() {
137 FilePath path;
138 PathService::Get(base::DIR_SOURCE_ROOT, &path);
139 path = path.Append("net");
140 path = path.Append("data");
141 path = path.Append("ssl");
142 path = path.Append("certificates");
143 path = path.Append("ok.srpv");
144 return path.value();
145 }
146
147 // LoadDefaultCert returns the DER encoded default certificate.
148 std::string LoadDefaultCert() {
149 FilePath path;
150 PathService::Get(base::DIR_SOURCE_ROOT, &path);
151 path = path.Append("net");
152 path = path.Append("data");
153 path = path.Append("ssl");
154 path = path.Append("certificates");
155 path = path.Append("ok_cert.pem");
156
157 std::string pem;
158 bool r = file_util::ReadFileToString(path, &pem);
159 CHECK(r) << "failed to read " << path.value();
160
161 static const char kStartMarker[] = "-----BEGIN CERTIFICATE-----\n";
162 static const char kEndMarker[] = "-----END CERTIFICATE-----\n";
163
164 std::string::size_type i = pem.find(kStartMarker);
165 std::string::size_type j = pem.find(kEndMarker);
166 CHECK(i != std::string::npos);
167 CHECK(j != std::string::npos);
168 CHECK_GT(j, i);
169 i += sizeof(kStartMarker) - 1;
170
171 std::string b64data = pem.substr(i, j - i);
172 ReplaceSubstringsAfterOffset(&b64data, 0 /* start offset */, "\n", "");
173
174 std::string der;
175 base::Base64Decode(b64data, &der);
176 return der;
177 }
178
179 void SetupSSLConfig() {
180 if (ssl_config_.allowed_bad_certs.size())
181 return;
182 const std::string der = LoadDefaultCert();
183 SSLConfig::CertAndStatus cert_and_status;
184 cert_and_status.cert =
185 X509Certificate::CreateFromBytes(der.data(), der.size());
186 cert_and_status.cert_status = ERR_CERT_AUTHORITY_INVALID;
187
188 ssl_config_.allowed_bad_certs.push_back(cert_and_status);
189 }
190
191 // PerformConnection makes an SSL connection to the openssl_helper binary and
192 // does a ping-pong test to check the the SSL socket is working correctly.
193 void PerformConnection(std::string username = "",
194 std::string password = "",
195 bool fail = false,
196 int expected_net_error = OK) {
197 client_ = socket(AF_INET, SOCK_STREAM, 0);
198 ASSERT_LE(0, client_);
199 ASSERT_EQ(
200 0, connect(client_, (struct sockaddr*) &remote_, sizeof(remote_)));
201 int on = 1;
202 setsockopt(client_, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
203
204 SetupSSLConfig();
205 log_.Clear();
206
207 std::vector<uint8> localhost;
208 localhost.push_back(127);
209 localhost.push_back(0);
210 localhost.push_back(0);
211 localhost.push_back(1);
212 AddressList addr_list(localhost, 443, false);
213 TCPClientSocket* transport = new TCPClientSocket(
214 addr_list, &log_, NetLog::Source());
215
216 if (!username.empty()) {
217 ssl_config_.use_tls_auth = true;
218 ssl_config_.tls_username = username;
219 ssl_config_.tls_password = password;
220 ssl_config_.ssl3_enabled = false;
221 ssl_config_.tls1_enabled = true;
222 }
223
224 transport->AdoptSocket(client_);
225 scoped_ptr<SSLClientSocket> sock(
226 socket_factory_->CreateSSLClientSocket(
227 transport, HostPortPair("example.com", 443), ssl_config_,
228 new TestSSLHostInfo(&cert_verifier_), &cert_verifier_));
229
230 TestCompletionCallback callback;
231 int rv = sock->Connect(&callback);
232 if (rv != OK) {
233 ASSERT_EQ(ERR_IO_PENDING, rv);
234 EXPECT_FALSE(sock->IsConnected());
235 rv = callback.WaitForResult();
236 EXPECT_EQ(expected_net_error, rv); // default expected_net_error is OK
237 return;
238 }
239 EXPECT_TRUE(sock->IsConnected());
240
241 static const char request_text[] = "whoami";
242 scoped_refptr<IOBuffer> request_buffer =
243 new IOBuffer(arraysize(request_text) - 1);
244 memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
245 rv = sock->Write(request_buffer, arraysize(request_text), &callback);
246 if (rv < 0) {
247 ASSERT_EQ(ERR_IO_PENDING, rv);
248 rv = callback.WaitForResult();
249 }
250 EXPECT_EQ(7, rv);
251
252 scoped_refptr<IOBuffer> reply_buffer = new IOBuffer(8);
253 rv = sock->Read(reply_buffer, 8, &callback);
254 if (rv < 0) {
255 ASSERT_EQ(ERR_IO_PENDING, rv);
256 rv = callback.WaitForResult();
257 }
258
259 std::string exp_response = (ssl_config_.use_tls_auth) ?
260 ssl_config_.tls_username : "not-using-tls-srp";
261
262 EXPECT_EQ((int)exp_response.size(), rv);
263 EXPECT_TRUE(memcmp(reply_buffer->data(), exp_response.data(),
264 exp_response.size()) == 0);
265
266 next_proto_status_ = sock->GetNextProto(&next_proto_);
267
268 sock->Disconnect();
269 }
270
271 base::ProcessHandle child_;
272 CertVerifier cert_verifier_;
273 ClientSocketFactory* const socket_factory_;
274 struct sockaddr_in remote_;
275 int client_;
276 SSLConfig ssl_config_;
277 CapturingNetLog log_;
278 SSLClientSocket::NextProtoStatus next_proto_status_;
279 std::string next_proto_;
280 int expected_exit_code_;
281 };
282
283 TEST_F(SSLClientSocketTLSSRPTest, NoCredentials) {
284 StartTLSSRPServer(NULL);
285 // Not a TLS-SRP connection.
286 PerformConnection("", "", true, ERR_SSL_UNKNOWN_PSK_IDENTITY_ALERT);
287 expected_exit_code_ = 1;
288 }
289
290 TEST_F(SSLClientSocketTLSSRPTest, GoodCredentials) {
291 StartTLSSRPServer(NULL);
292 PerformConnection("user", "secret");
293 }
294
295 // TODO(sqs): The current openssl_helper terminates the connection upon seeing
296 // a username it doesn't know. It should instead either (1) make up (s,v) and
297 // play along, or (2) send unknown_psk_identity. When it's fixed, the net error
298 // below will need to change.
299 TEST_F(SSLClientSocketTLSSRPTest, BadCredentials) {
300 StartTLSSRPServer(NULL);
301 PerformConnection("baduser", "secret", true,
302 ERR_SSL_UNKNOWN_PSK_IDENTITY_ALERT);
303 expected_exit_code_ = 1;
304 }
305
306 TEST_F(SSLClientSocketTLSSRPTest, GoodUsernameBadPassword) {
307 StartTLSSRPServer(NULL);
308 PerformConnection("user", "badsecret", true, ERR_SSL_BAD_RECORD_MAC_ALERT);
309 expected_exit_code_ = 1;
310 }
311
312 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/ssl_client_socket_nss.cc ('k') | net/socket/ssl_client_socket_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698