OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "jingle/notifier/base/fake_ssl_client_socket.h" | |
6 | |
7 #include <cstdlib> | |
8 | |
9 #include "base/basictypes.h" | |
10 #include "base/compiler_specific.h" | |
11 #include "base/logging.h" | |
12 #include "net/base/io_buffer.h" | |
13 #include "net/base/net_errors.h" | |
14 | |
15 namespace notifier { | |
16 | |
17 namespace { | |
18 | |
19 // The constants below were taken from libjingle's socketadapters.cc. | |
20 // Basically, we do a "fake" SSL handshake to fool proxies into | |
21 // thinking this is a real SSL connection. | |
22 | |
23 // This is a SSL v2 CLIENT_HELLO message. | |
24 // TODO(juberti): Should this have a session id? The response doesn't have a | |
25 // certificate, so the hello should have a session id. | |
26 static const uint8 kSslClientHello[] = { | |
27 0x80, 0x46, // msg len | |
28 0x01, // CLIENT_HELLO | |
29 0x03, 0x01, // SSL 3.1 | |
30 0x00, 0x2d, // ciphersuite len | |
31 0x00, 0x00, // session id len | |
32 0x00, 0x10, // challenge len | |
33 0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, // ciphersuites | |
34 0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80, // | |
35 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, // | |
36 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, // | |
37 0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, // | |
38 0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc, // challenge | |
39 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea // | |
40 }; | |
41 | |
42 // This is a TLSv1 SERVER_HELLO message. | |
43 static const uint8 kSslServerHello[] = { | |
44 0x16, // handshake message | |
45 0x03, 0x01, // SSL 3.1 | |
46 0x00, 0x4a, // message len | |
47 0x02, // SERVER_HELLO | |
48 0x00, 0x00, 0x46, // handshake len | |
49 0x03, 0x01, // SSL 3.1 | |
50 0x42, 0x85, 0x45, 0xa7, 0x27, 0xa9, 0x5d, 0xa0, // server random | |
51 0xb3, 0xc5, 0xe7, 0x53, 0xda, 0x48, 0x2b, 0x3f, // | |
52 0xc6, 0x5a, 0xca, 0x89, 0xc1, 0x58, 0x52, 0xa1, // | |
53 0x78, 0x3c, 0x5b, 0x17, 0x46, 0x00, 0x85, 0x3f, // | |
54 0x20, // session id len | |
55 0x0e, 0xd3, 0x06, 0x72, 0x5b, 0x5b, 0x1b, 0x5f, // session id | |
56 0x15, 0xac, 0x13, 0xf9, 0x88, 0x53, 0x9d, 0x9b, // | |
57 0xe8, 0x3d, 0x7b, 0x0c, 0x30, 0x32, 0x6e, 0x38, // | |
58 0x4d, 0xa2, 0x75, 0x57, 0x41, 0x6c, 0x34, 0x5c, // | |
59 0x00, 0x04, // RSA/RC4-128/MD5 | |
60 0x00 // null compression | |
61 }; | |
62 | |
63 net::DrainableIOBuffer* NewDrainableIOBufferWithSize(int size) { | |
64 return new net::DrainableIOBuffer(new net::IOBuffer(size), size); | |
65 } | |
66 | |
67 } // namespace | |
68 | |
69 base::StringPiece FakeSSLClientSocket::GetSslClientHello() { | |
70 return base::StringPiece(reinterpret_cast<const char*>(kSslClientHello), | |
71 arraysize(kSslClientHello)); | |
72 } | |
73 | |
74 base::StringPiece FakeSSLClientSocket::GetSslServerHello() { | |
75 return base::StringPiece(reinterpret_cast<const char*>(kSslServerHello), | |
76 arraysize(kSslServerHello)); | |
77 } | |
78 | |
79 FakeSSLClientSocket::FakeSSLClientSocket( | |
80 net::StreamSocket* transport_socket) | |
81 : transport_socket_(transport_socket), | |
82 next_handshake_state_(STATE_NONE), | |
83 handshake_completed_(false), | |
84 write_buf_(NewDrainableIOBufferWithSize(arraysize(kSslClientHello))), | |
85 read_buf_(NewDrainableIOBufferWithSize(arraysize(kSslServerHello))) { | |
86 CHECK(transport_socket_.get()); | |
87 std::memcpy(write_buf_->data(), kSslClientHello, arraysize(kSslClientHello)); | |
88 } | |
89 | |
90 FakeSSLClientSocket::~FakeSSLClientSocket() {} | |
91 | |
92 int FakeSSLClientSocket::Read(net::IOBuffer* buf, int buf_len, | |
93 const net::CompletionCallback& callback) { | |
94 DCHECK_EQ(next_handshake_state_, STATE_NONE); | |
95 DCHECK(handshake_completed_); | |
96 return transport_socket_->Read(buf, buf_len, callback); | |
97 } | |
98 | |
99 int FakeSSLClientSocket::Write(net::IOBuffer* buf, int buf_len, | |
100 const net::CompletionCallback& callback) { | |
101 DCHECK_EQ(next_handshake_state_, STATE_NONE); | |
102 DCHECK(handshake_completed_); | |
103 return transport_socket_->Write(buf, buf_len, callback); | |
104 } | |
105 | |
106 bool FakeSSLClientSocket::SetReceiveBufferSize(int32 size) { | |
107 return transport_socket_->SetReceiveBufferSize(size); | |
108 } | |
109 | |
110 bool FakeSSLClientSocket::SetSendBufferSize(int32 size) { | |
111 return transport_socket_->SetSendBufferSize(size); | |
112 } | |
113 | |
114 int FakeSSLClientSocket::Connect(const net::CompletionCallback& callback) { | |
115 // We don't support synchronous operation, even if | |
116 // |transport_socket_| does. | |
117 DCHECK(!callback.is_null()); | |
118 DCHECK_EQ(next_handshake_state_, STATE_NONE); | |
119 DCHECK(!handshake_completed_); | |
120 DCHECK(user_connect_callback_.is_null()); | |
121 DCHECK_EQ(write_buf_->BytesConsumed(), 0); | |
122 DCHECK_EQ(read_buf_->BytesConsumed(), 0); | |
123 | |
124 next_handshake_state_ = STATE_CONNECT; | |
125 int status = DoHandshakeLoop(); | |
126 if (status == net::ERR_IO_PENDING) | |
127 user_connect_callback_ = callback; | |
128 | |
129 return status; | |
130 } | |
131 | |
132 int FakeSSLClientSocket::DoHandshakeLoop() { | |
133 DCHECK_NE(next_handshake_state_, STATE_NONE); | |
134 int status = net::OK; | |
135 do { | |
136 HandshakeState state = next_handshake_state_; | |
137 next_handshake_state_ = STATE_NONE; | |
138 switch (state) { | |
139 case STATE_CONNECT: | |
140 status = DoConnect(); | |
141 break; | |
142 case STATE_SEND_CLIENT_HELLO: | |
143 status = DoSendClientHello(); | |
144 break; | |
145 case STATE_VERIFY_SERVER_HELLO: | |
146 status = DoVerifyServerHello(); | |
147 break; | |
148 default: | |
149 status = net::ERR_UNEXPECTED; | |
150 LOG(DFATAL) << "unexpected state: " << state; | |
151 break; | |
152 } | |
153 } while ((status != net::ERR_IO_PENDING) && | |
154 (next_handshake_state_ != STATE_NONE)); | |
155 return status; | |
156 } | |
157 | |
158 void FakeSSLClientSocket::RunUserConnectCallback(int status) { | |
159 DCHECK_LE(status, net::OK); | |
160 next_handshake_state_ = STATE_NONE; | |
161 net::CompletionCallback user_connect_callback = user_connect_callback_; | |
162 user_connect_callback_.Reset(); | |
163 user_connect_callback.Run(status); | |
164 } | |
165 | |
166 void FakeSSLClientSocket::DoHandshakeLoopWithUserConnectCallback() { | |
167 int status = DoHandshakeLoop(); | |
168 if (status != net::ERR_IO_PENDING) { | |
169 RunUserConnectCallback(status); | |
170 } | |
171 } | |
172 | |
173 int FakeSSLClientSocket::DoConnect() { | |
174 int status = transport_socket_->Connect( | |
175 base::Bind(&FakeSSLClientSocket::OnConnectDone, base::Unretained(this))); | |
176 if (status != net::OK) { | |
177 return status; | |
178 } | |
179 ProcessConnectDone(); | |
180 return net::OK; | |
181 } | |
182 | |
183 void FakeSSLClientSocket::OnConnectDone(int status) { | |
184 DCHECK_NE(status, net::ERR_IO_PENDING); | |
185 DCHECK_LE(status, net::OK); | |
186 DCHECK(!user_connect_callback_.is_null()); | |
187 if (status != net::OK) { | |
188 RunUserConnectCallback(status); | |
189 return; | |
190 } | |
191 ProcessConnectDone(); | |
192 DoHandshakeLoopWithUserConnectCallback(); | |
193 } | |
194 | |
195 void FakeSSLClientSocket::ProcessConnectDone() { | |
196 DCHECK_EQ(write_buf_->BytesConsumed(), 0); | |
197 DCHECK_EQ(read_buf_->BytesConsumed(), 0); | |
198 next_handshake_state_ = STATE_SEND_CLIENT_HELLO; | |
199 } | |
200 | |
201 int FakeSSLClientSocket::DoSendClientHello() { | |
202 int status = transport_socket_->Write( | |
203 write_buf_, write_buf_->BytesRemaining(), | |
204 base::Bind(&FakeSSLClientSocket::OnSendClientHelloDone, | |
205 base::Unretained(this))); | |
206 if (status < net::OK) { | |
207 return status; | |
208 } | |
209 ProcessSendClientHelloDone(static_cast<size_t>(status)); | |
210 return net::OK; | |
211 } | |
212 | |
213 void FakeSSLClientSocket::OnSendClientHelloDone(int status) { | |
214 DCHECK_NE(status, net::ERR_IO_PENDING); | |
215 DCHECK(!user_connect_callback_.is_null()); | |
216 if (status < net::OK) { | |
217 RunUserConnectCallback(status); | |
218 return; | |
219 } | |
220 ProcessSendClientHelloDone(static_cast<size_t>(status)); | |
221 DoHandshakeLoopWithUserConnectCallback(); | |
222 } | |
223 | |
224 void FakeSSLClientSocket::ProcessSendClientHelloDone(size_t written) { | |
225 DCHECK_LE(written, static_cast<size_t>(write_buf_->BytesRemaining())); | |
226 DCHECK_EQ(read_buf_->BytesConsumed(), 0); | |
227 if (written < static_cast<size_t>(write_buf_->BytesRemaining())) { | |
228 next_handshake_state_ = STATE_SEND_CLIENT_HELLO; | |
229 write_buf_->DidConsume(written); | |
230 } else { | |
231 next_handshake_state_ = STATE_VERIFY_SERVER_HELLO; | |
232 } | |
233 } | |
234 | |
235 int FakeSSLClientSocket::DoVerifyServerHello() { | |
236 int status = transport_socket_->Read( | |
237 read_buf_, read_buf_->BytesRemaining(), | |
238 base::Bind(&FakeSSLClientSocket::OnVerifyServerHelloDone, | |
239 base::Unretained(this))); | |
240 if (status < net::OK) { | |
241 return status; | |
242 } | |
243 size_t read = static_cast<size_t>(status); | |
244 return ProcessVerifyServerHelloDone(read); | |
245 } | |
246 | |
247 void FakeSSLClientSocket::OnVerifyServerHelloDone(int status) { | |
248 DCHECK_NE(status, net::ERR_IO_PENDING); | |
249 DCHECK(!user_connect_callback_.is_null()); | |
250 if (status < net::OK) { | |
251 RunUserConnectCallback(status); | |
252 return; | |
253 } | |
254 size_t read = static_cast<size_t>(status); | |
255 status = ProcessVerifyServerHelloDone(read); | |
256 if (status < net::OK) { | |
257 RunUserConnectCallback(status); | |
258 return; | |
259 } | |
260 if (handshake_completed_) { | |
261 RunUserConnectCallback(net::OK); | |
262 } else { | |
263 DoHandshakeLoopWithUserConnectCallback(); | |
264 } | |
265 } | |
266 | |
267 net::Error FakeSSLClientSocket::ProcessVerifyServerHelloDone(size_t read) { | |
268 DCHECK_LE(read, static_cast<size_t>(read_buf_->BytesRemaining())); | |
269 if (read == 0U) { | |
270 return net::ERR_UNEXPECTED; | |
271 } | |
272 const uint8* expected_data_start = | |
273 &kSslServerHello[arraysize(kSslServerHello) - | |
274 read_buf_->BytesRemaining()]; | |
275 if (std::memcmp(expected_data_start, read_buf_->data(), read) != 0) { | |
276 return net::ERR_UNEXPECTED; | |
277 } | |
278 if (read < static_cast<size_t>(read_buf_->BytesRemaining())) { | |
279 next_handshake_state_ = STATE_VERIFY_SERVER_HELLO; | |
280 read_buf_->DidConsume(read); | |
281 } else { | |
282 next_handshake_state_ = STATE_NONE; | |
283 handshake_completed_ = true; | |
284 } | |
285 return net::OK; | |
286 } | |
287 | |
288 void FakeSSLClientSocket::Disconnect() { | |
289 transport_socket_->Disconnect(); | |
290 next_handshake_state_ = STATE_NONE; | |
291 handshake_completed_ = false; | |
292 user_connect_callback_.Reset(); | |
293 write_buf_->SetOffset(0); | |
294 read_buf_->SetOffset(0); | |
295 } | |
296 | |
297 bool FakeSSLClientSocket::IsConnected() const { | |
298 return handshake_completed_ && transport_socket_->IsConnected(); | |
299 } | |
300 | |
301 bool FakeSSLClientSocket::IsConnectedAndIdle() const { | |
302 return handshake_completed_ && transport_socket_->IsConnectedAndIdle(); | |
303 } | |
304 | |
305 int FakeSSLClientSocket::GetPeerAddress(net::IPEndPoint* address) const { | |
306 return transport_socket_->GetPeerAddress(address); | |
307 } | |
308 | |
309 int FakeSSLClientSocket::GetLocalAddress(net::IPEndPoint* address) const { | |
310 return transport_socket_->GetLocalAddress(address); | |
311 } | |
312 | |
313 const net::BoundNetLog& FakeSSLClientSocket::NetLog() const { | |
314 return transport_socket_->NetLog(); | |
315 } | |
316 | |
317 void FakeSSLClientSocket::SetSubresourceSpeculation() { | |
318 transport_socket_->SetSubresourceSpeculation(); | |
319 } | |
320 | |
321 void FakeSSLClientSocket::SetOmniboxSpeculation() { | |
322 transport_socket_->SetOmniboxSpeculation(); | |
323 } | |
324 | |
325 bool FakeSSLClientSocket::WasEverUsed() const { | |
326 return transport_socket_->WasEverUsed(); | |
327 } | |
328 | |
329 bool FakeSSLClientSocket::UsingTCPFastOpen() const { | |
330 return transport_socket_->UsingTCPFastOpen(); | |
331 } | |
332 | |
333 int64 FakeSSLClientSocket::NumBytesRead() const { | |
334 return transport_socket_->NumBytesRead(); | |
335 } | |
336 | |
337 base::TimeDelta FakeSSLClientSocket::GetConnectTimeMicros() const { | |
338 return transport_socket_->GetConnectTimeMicros(); | |
339 } | |
340 | |
341 bool FakeSSLClientSocket::WasNpnNegotiated() const { | |
342 return transport_socket_->WasNpnNegotiated(); | |
343 } | |
344 | |
345 net::NextProto FakeSSLClientSocket::GetNegotiatedProtocol() const { | |
346 return transport_socket_->GetNegotiatedProtocol(); | |
347 } | |
348 | |
349 bool FakeSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) { | |
350 return transport_socket_->GetSSLInfo(ssl_info); | |
351 } | |
352 | |
353 } // namespace notifier | |
OLD | NEW |