OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // OpenSSL binding for SSLClientSocket. The class layout and general principle | 5 // OpenSSL binding for SSLClientSocket. The class layout and general principle |
6 // of operation is derived from SSLClientSocketNSS. | 6 // of operation is derived from SSLClientSocketNSS. |
7 | 7 |
8 #include "net/socket/ssl_client_socket_openssl.h" | 8 #include "net/socket/ssl_client_socket_openssl.h" |
9 | 9 |
10 #include <openssl/ssl.h> | 10 #include <openssl/ssl.h> |
11 #include <openssl/err.h> | 11 #include <openssl/err.h> |
12 | 12 |
13 #include "net/base/cert_verifier.h" | |
13 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
14 #include "net/base/ssl_connection_status_flags.h" | 15 #include "net/base/ssl_connection_status_flags.h" |
15 #include "net/base/ssl_info.h" | 16 #include "net/base/ssl_info.h" |
16 #include "net/base/test_certificate_data.h" // TODO(joth): Remove!! | 17 #include "net/base/test_certificate_data.h" // TODO(joth): Remove!! |
17 | 18 |
18 namespace net { | 19 namespace net { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 // Enable this to see logging for state machine state transitions. | 23 // Enable this to see logging for state machine state transitions. |
(...skipping 16 matching lines...) Expand all Loading... | |
39 ERR_error_string_n(error_num, buf, arraysize(buf)); | 40 ERR_error_string_n(error_num, buf, arraysize(buf)); |
40 DVLOG(1) << "SSL error " << error_num << ": " << buf; | 41 DVLOG(1) << "SSL error " << error_num << ": " << buf; |
41 } | 42 } |
42 } | 43 } |
43 | 44 |
44 int MapOpenSSLError(int err) { | 45 int MapOpenSSLError(int err) { |
45 switch (err) { | 46 switch (err) { |
46 case SSL_ERROR_WANT_READ: | 47 case SSL_ERROR_WANT_READ: |
47 case SSL_ERROR_WANT_WRITE: | 48 case SSL_ERROR_WANT_WRITE: |
48 return ERR_IO_PENDING; | 49 return ERR_IO_PENDING; |
50 case SSL_ERROR_SYSCALL: | |
51 DVLOG(1) << "OpenSSL SYSVCALL error, errno " << errno; | |
wtc
2010/10/04 23:13:53
Typo: SYSVCALL => SYSCALL
Should this really be m
| |
52 MaybeLogSSLError(); | |
53 return ERR_SSL_PROTOCOL_ERROR; | |
49 default: | 54 default: |
50 // TODO(joth): Implement full mapping. | 55 // TODO(joth): Implement full mapping. |
51 LOG(WARNING) << "Unknown OpenSSL error " << err; | 56 LOG(WARNING) << "Unknown OpenSSL error " << err; |
52 MaybeLogSSLError(); | 57 MaybeLogSSLError(); |
53 return ERR_SSL_PROTOCOL_ERROR; | 58 return ERR_SSL_PROTOCOL_ERROR; |
54 } | 59 } |
55 } | 60 } |
56 | 61 |
57 // Registered with |g_ctx| as global verify callback handler; we unpack the | 62 // Registered with |g_ctx| as global verify callback handler; we unpack the |
58 // SSLClientSocketOpenSSL instance associated with this callback and delegate | 63 // SSLClientSocketOpenSSL instance associated with this callback and delegate |
(...skipping 20 matching lines...) Expand all Loading... | |
79 : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_( | 84 : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_( |
80 this, &SSLClientSocketOpenSSL::BufferSendComplete)), | 85 this, &SSLClientSocketOpenSSL::BufferSendComplete)), |
81 ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_( | 86 ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_( |
82 this, &SSLClientSocketOpenSSL::BufferRecvComplete)), | 87 this, &SSLClientSocketOpenSSL::BufferRecvComplete)), |
83 transport_send_busy_(false), | 88 transport_send_busy_(false), |
84 transport_recv_busy_(false), | 89 transport_recv_busy_(false), |
85 user_connect_callback_(NULL), | 90 user_connect_callback_(NULL), |
86 user_read_callback_(NULL), | 91 user_read_callback_(NULL), |
87 user_write_callback_(NULL), | 92 user_write_callback_(NULL), |
88 client_auth_cert_needed_(false), | 93 client_auth_cert_needed_(false), |
94 ALLOW_THIS_IN_INITIALIZER_LIST(handshake_io_callback_( | |
95 this, &SSLClientSocketOpenSSL::OnHandshakeIOComplete)), | |
89 ssl_(NULL), | 96 ssl_(NULL), |
90 transport_bio_(NULL), | 97 transport_bio_(NULL), |
91 transport_(transport_socket), | 98 transport_(transport_socket), |
92 hostname_(hostname), | 99 hostname_(hostname), |
93 ssl_config_(ssl_config), | 100 ssl_config_(ssl_config), |
94 completed_handshake_(false), | 101 completed_handshake_(false), |
95 net_log_(transport_socket->socket()->NetLog()) { | 102 net_log_(transport_socket->socket()->NetLog()) { |
96 } | 103 } |
97 | 104 |
98 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { | 105 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
158 | 165 |
159 SSL_set_bio(ssl_, ssl_bio, ssl_bio); | 166 SSL_set_bio(ssl_, ssl_bio, ssl_bio); |
160 | 167 |
161 return true; | 168 return true; |
162 } | 169 } |
163 | 170 |
164 int SSLClientSocketOpenSSL::SSLVerifyCallback(int preverify_ok, | 171 int SSLClientSocketOpenSSL::SSLVerifyCallback(int preverify_ok, |
165 SSL* ssl, | 172 SSL* ssl, |
166 X509_STORE_CTX* x509_ctx) { | 173 X509_STORE_CTX* x509_ctx) { |
167 DCHECK_EQ(ssl_, ssl); | 174 DCHECK_EQ(ssl_, ssl); |
168 if (!preverify_ok) { | 175 int depth = X509_STORE_CTX_get_error_depth(x509_ctx); |
169 int depth = X509_STORE_CTX_get_error_depth(x509_ctx); | 176 DVLOG(preverify_ok ? 3 : 1) << "SSLVerifyCallback " << preverify_ok |
170 DVLOG(2) << "SSLVerifyCallback " << preverify_ok << " depth " << depth; | 177 << " depth " << depth; |
171 MaybeLogSSLError(); | 178 MaybeLogSSLError(); |
172 } | |
173 return preverify_ok; | 179 return preverify_ok; |
174 } | 180 } |
175 | 181 |
176 // SSLClientSocket methods | 182 // SSLClientSocket methods |
177 | 183 |
178 void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) { | 184 void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) { |
185 ssl_info->Reset(); | |
186 if (!server_cert_) | |
187 return; | |
188 | |
179 // Chrome DCHECKs that https pages provide a valid cert. For now (whilst in | 189 // Chrome DCHECKs that https pages provide a valid cert. For now (whilst in |
180 // early dev) we just create a spoof cert. | 190 // early dev) we just create a spoof cert. |
181 // TODO(joth): implement X509Certificate for OpenSSL and remove this hack. | 191 // TODO(joth): implement X509Certificate for OpenSSL and remove this hack. |
182 LOG(WARNING) << "Filling in certificate with bogus content"; | 192 LOG(WARNING) << "Filling in certificate with bogus content"; |
183 ssl_info->Reset(); | 193 ssl_info->cert = server_cert_; |
184 ssl_info->cert = X509Certificate::CreateFromBytes( | 194 ssl_info->cert_status = server_cert_verify_result_.cert_status; |
185 reinterpret_cast<const char*>(google_der), sizeof(google_der)); | |
186 DCHECK(ssl_info->cert); | |
187 ssl_info->cert_status = 0; | |
188 ssl_info->security_bits = 56; | 195 ssl_info->security_bits = 56; |
189 ssl_info->connection_status = | 196 ssl_info->connection_status = |
190 ((TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA) & | 197 ((TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA) & |
191 SSL_CONNECTION_CIPHERSUITE_MASK) << SSL_CONNECTION_CIPHERSUITE_SHIFT; | 198 SSL_CONNECTION_CIPHERSUITE_MASK) << SSL_CONNECTION_CIPHERSUITE_SHIFT; |
192 | |
193 // Silence compiler about unused vars. | |
194 (void)google_der; | |
195 (void)webkit_der; | |
196 (void)thawte_der; | |
197 (void)paypal_null_der; | |
198 } | 199 } |
199 | 200 |
200 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( | 201 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( |
201 SSLCertRequestInfo* cert_request_info) { | 202 SSLCertRequestInfo* cert_request_info) { |
202 NOTREACHED(); | 203 NOTREACHED(); |
203 } | 204 } |
204 | 205 |
205 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( | 206 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( |
206 std::string* proto) { | 207 std::string* proto) { |
207 proto->clear(); | 208 proto->clear(); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
252 if (rv == ERR_IO_PENDING) { | 253 if (rv == ERR_IO_PENDING) { |
253 user_connect_callback_ = callback; | 254 user_connect_callback_ = callback; |
254 } else { | 255 } else { |
255 net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL); | 256 net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL); |
256 } | 257 } |
257 | 258 |
258 return rv > OK ? OK : rv; | 259 return rv > OK ? OK : rv; |
259 } | 260 } |
260 | 261 |
261 void SSLClientSocketOpenSSL::Disconnect() { | 262 void SSLClientSocketOpenSSL::Disconnect() { |
263 if (ssl_) { | |
264 SSL_free(ssl_); | |
265 ssl_ = NULL; | |
266 } | |
267 if (transport_bio_) { | |
268 BIO_free_all(transport_bio_); | |
269 transport_bio_ = NULL; | |
270 } | |
271 | |
272 // Shut down anything that may call us back (through buffer_send_callback_, | |
273 // buffer_recv_callback, or handshake_io_callback_). | |
274 verifier_.reset(); | |
275 transport_->socket()->Disconnect(); | |
276 | |
262 // Null all callbacks, delete all buffers. | 277 // Null all callbacks, delete all buffers. |
263 transport_send_busy_ = false; | 278 transport_send_busy_ = false; |
264 send_buffer_ = NULL; | 279 send_buffer_ = NULL; |
265 transport_recv_busy_ = false; | 280 transport_recv_busy_ = false; |
266 recv_buffer_ = NULL; | 281 recv_buffer_ = NULL; |
267 | 282 |
268 user_connect_callback_ = NULL; | 283 user_connect_callback_ = NULL; |
269 user_read_callback_ = NULL; | 284 user_read_callback_ = NULL; |
270 user_write_callback_ = NULL; | 285 user_write_callback_ = NULL; |
271 user_read_buf_ = NULL; | 286 user_read_buf_ = NULL; |
272 user_read_buf_len_ = 0; | 287 user_read_buf_len_ = 0; |
273 user_write_buf_ = NULL; | 288 user_write_buf_ = NULL; |
274 user_write_buf_len_ = 0; | 289 user_write_buf_len_ = 0; |
275 | 290 |
276 client_certs_.clear(); | 291 client_certs_.clear(); |
277 client_auth_cert_needed_ = false; | 292 client_auth_cert_needed_ = false; |
278 | 293 |
279 if (ssl_) { | 294 server_cert_verify_result_.Reset(); |
280 SSL_free(ssl_); | |
281 ssl_ = NULL; | |
282 } | |
283 if (transport_bio_) { | |
284 BIO_free(transport_bio_); | |
285 transport_bio_ = NULL; | |
286 } | |
287 | |
288 completed_handshake_ = false; | 295 completed_handshake_ = false; |
289 transport_->socket()->Disconnect(); | |
290 } | 296 } |
291 | 297 |
292 int SSLClientSocketOpenSSL::DoHandshakeLoop(int last_io_result) { | 298 int SSLClientSocketOpenSSL::DoHandshakeLoop(int last_io_result) { |
293 bool network_moved; | 299 bool network_moved; |
294 int rv = last_io_result; | 300 int rv = last_io_result; |
295 do { | 301 do { |
296 // Default to STATE_NONE for next state. | 302 // Default to STATE_NONE for next state. |
297 // (This is a quirk carried over from the windows | 303 // (This is a quirk carried over from the windows |
298 // implementation. It makes reading the logs a bit harder.) | 304 // implementation. It makes reading the logs a bit harder.) |
299 // State handlers can and often do call GotoState just | 305 // State handlers can and often do call GotoState just |
300 // to stay in the current state. | 306 // to stay in the current state. |
301 State state = next_handshake_state_; | 307 State state = next_handshake_state_; |
302 GotoState(STATE_NONE); | 308 GotoState(STATE_NONE); |
303 switch (state) { | 309 switch (state) { |
304 case STATE_NONE: | 310 case STATE_NONE: |
305 // we're just pumping data between the buffer and the network | 311 // we're just pumping data between the buffer and the network |
306 break; | 312 break; |
307 case STATE_HANDSHAKE: | 313 case STATE_HANDSHAKE: |
308 rv = DoHandshake(); | 314 rv = DoHandshake(); |
309 break; | 315 break; |
310 #if 0 // TODO(joth): Implement cert verification. | |
311 case STATE_VERIFY_CERT: | 316 case STATE_VERIFY_CERT: |
312 DCHECK(rv == OK); | 317 DCHECK(rv == OK); |
313 rv = DoVerifyCert(rv); | 318 rv = DoVerifyCert(rv); |
314 break; | 319 break; |
315 case STATE_VERIFY_CERT_COMPLETE: | 320 case STATE_VERIFY_CERT_COMPLETE: |
316 rv = DoVerifyCertComplete(rv); | 321 rv = DoVerifyCertComplete(rv); |
317 break; | 322 break; |
318 #endif | |
319 default: | 323 default: |
320 rv = ERR_UNEXPECTED; | 324 rv = ERR_UNEXPECTED; |
321 NOTREACHED() << "unexpected state" << state; | 325 NOTREACHED() << "unexpected state" << state; |
322 break; | 326 break; |
323 } | 327 } |
324 | 328 |
325 // To avoid getting an ERR_IO_PENDING here after handshake complete. | 329 // To avoid getting an ERR_IO_PENDING here after handshake complete. |
326 if (next_handshake_state_ == STATE_NONE) | 330 if (next_handshake_state_ == STATE_NONE) |
327 break; | 331 break; |
328 | 332 |
329 // Do the actual network I/O. | 333 // Do the actual network I/O. |
330 network_moved = DoTransportIO(); | 334 network_moved = DoTransportIO(); |
331 } while ((rv != ERR_IO_PENDING || network_moved) && | 335 } while ((rv != ERR_IO_PENDING || network_moved) && |
332 next_handshake_state_ != STATE_NONE); | 336 next_handshake_state_ != STATE_NONE); |
333 return rv; | 337 return rv; |
334 } | 338 } |
335 | 339 |
336 int SSLClientSocketOpenSSL::DoHandshake() { | 340 int SSLClientSocketOpenSSL::DoHandshake() { |
337 int net_error = net::OK; | 341 int net_error = net::OK; |
338 int rv = SSL_do_handshake(ssl_); | 342 int rv = SSL_do_handshake(ssl_); |
339 | 343 |
340 if (rv == 1) { | 344 if (rv == 1) { |
341 // SSL handshake is completed. Let's verify the certificate. | 345 // SSL handshake is completed. Let's verify the certificate. |
342 // For now we are done, certificates not implemented yet. | 346 if (UpdateServerCert() == NULL) { |
343 // TODO(joth): Implement certificates | 347 net_error = ERR_SSL_PROTOCOL_ERROR; |
344 GotoState(STATE_NONE); | 348 } else { |
345 completed_handshake_ = true; | 349 GotoState(STATE_VERIFY_CERT); |
350 | |
351 // TODO(joth): Remove this check when X509Certificate::Verify is | |
352 // implemented for OpenSSL | |
353 long verify_result = SSL_get_verify_result(ssl_); | |
354 LOG_IF(WARNING, verify_result != X509_V_OK) | |
355 << "Built in verify failed: " << verify_result; | |
356 } | |
346 } else { | 357 } else { |
347 int ssl_error = SSL_get_error(ssl_, rv); | 358 int ssl_error = SSL_get_error(ssl_, rv); |
359 net_error = MapOpenSSLError(ssl_error); | |
348 | 360 |
349 // If not done, stay in this state | 361 // If not done, stay in this state |
350 GotoState(STATE_HANDSHAKE); | 362 if (net_error == ERR_IO_PENDING) { |
351 net_error = MapOpenSSLError(ssl_error); | 363 GotoState(STATE_HANDSHAKE); |
364 } else { | |
365 LOG(ERROR) << "handshake failed; returned " << rv | |
366 << ", SSL error code " << ssl_error | |
367 << ", net_error " << net_error; | |
368 MaybeLogSSLError(); | |
369 } | |
370 } | |
371 return net_error; | |
372 } | |
373 | |
374 int SSLClientSocketOpenSSL::DoVerifyCert(int result) { | |
375 DCHECK(server_cert_); | |
376 GotoState(STATE_VERIFY_CERT_COMPLETE); | |
377 int flags = 0; | |
378 | |
379 if (ssl_config_.rev_checking_enabled) | |
380 flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED; | |
381 if (ssl_config_.verify_ev_cert) | |
382 flags |= X509Certificate::VERIFY_EV_CERT; | |
383 verifier_.reset(new CertVerifier); | |
384 return verifier_->Verify(server_cert_, hostname_, flags, | |
385 &server_cert_verify_result_, | |
386 &handshake_io_callback_); | |
387 } | |
388 | |
389 int SSLClientSocketOpenSSL::DoVerifyCertComplete(int result) { | |
390 verifier_.reset(); | |
391 | |
392 if (result == OK) { | |
393 // TODO(joth): Work out if we need to remember the intermediate CA certs | |
394 // when the server sends them to us, and do so here. | |
352 } | 395 } |
353 | 396 |
354 return net_error; | 397 // If we have been explicitly told to accept this certificate, override the |
398 // result of verifier_.Verify. | |
399 // Eventually, we should cache the cert verification results so that we don't | |
400 // need to call verifier_.Verify repeatedly. But for now we need to do this. | |
401 // Alternatively, we could use the cert's status that we stored along with | |
402 // the cert in the allowed_bad_certs vector. | |
403 if (IsCertificateError(result) && | |
404 ssl_config_.IsAllowedBadCert(server_cert_)) { | |
405 LOG(INFO) << "accepting bad SSL certificate, as user told us to"; | |
406 result = OK; | |
407 } | |
408 | |
409 completed_handshake_ = true; | |
410 // The NSS version has a comment that we may not need this call because it is | |
411 // now harmless to have a session with a bad cert. | |
412 // This may or may not apply here, but let's invalidate it anyway. | |
413 InvalidateSessionIfBadCertificate(); | |
414 // Exit DoHandshakeLoop and return the result to the caller to Connect. | |
415 DCHECK_EQ(STATE_NONE, next_handshake_state_); | |
416 return result; | |
417 } | |
418 | |
419 void SSLClientSocketOpenSSL::InvalidateSessionIfBadCertificate() { | |
420 if (UpdateServerCert() != NULL && | |
421 ssl_config_.IsAllowedBadCert(server_cert_)) { | |
422 // Remove from session cache but don't clear this connection. | |
423 // TODO(joth): This should be a no-op until we enable session caching, | |
424 // see SSL_CTX_set_session_cache_mode(SSL_SESS_CACHE_CLIENT). | |
425 SSL_SESSION* session = SSL_get_session(ssl_); | |
426 LOG_IF(ERROR, session) << "Connection has a session?? " << session; | |
427 int rv = SSL_CTX_remove_session(g_ctx, session); | |
428 LOG_IF(ERROR, rv) << "Session was cached?? " << rv; | |
429 } | |
430 } | |
431 | |
432 X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() { | |
433 if (server_cert_) | |
434 return server_cert_; | |
435 | |
436 X509* cert = SSL_get_peer_certificate(ssl_); | |
437 if (cert == NULL) { | |
438 LOG(WARNING) << "SSL_get_peer_certificate returned NULL"; | |
439 return NULL; | |
440 } | |
441 | |
442 // TODO(joth): Get |server_cert_| from |cert|. | |
443 server_cert_ = X509Certificate::CreateFromBytes( | |
444 reinterpret_cast<const char*>(google_der), sizeof(google_der)); | |
445 X509_free(cert); | |
446 DCHECK(server_cert_); | |
447 // Silence compiler about unused vars. | |
448 (void)google_der; (void)webkit_der; (void)thawte_der; (void)paypal_null_der; | |
449 | |
450 return server_cert_; | |
355 } | 451 } |
356 | 452 |
357 bool SSLClientSocketOpenSSL::DoTransportIO() { | 453 bool SSLClientSocketOpenSSL::DoTransportIO() { |
358 bool network_moved = false; | 454 bool network_moved = false; |
359 int nsent = BufferSend(); | 455 int nsent = BufferSend(); |
360 int nreceived = BufferRecv(); | 456 int nreceived = BufferRecv(); |
361 network_moved = (nsent > 0 || nreceived >= 0); | 457 network_moved = (nsent > 0 || nreceived >= 0); |
362 return network_moved; | 458 return network_moved; |
363 } | 459 } |
364 | 460 |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
645 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); | 741 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); |
646 | 742 |
647 if (rv >= 0) | 743 if (rv >= 0) |
648 return rv; | 744 return rv; |
649 | 745 |
650 int err = SSL_get_error(ssl_, rv); | 746 int err = SSL_get_error(ssl_, rv); |
651 return MapOpenSSLError(err); | 747 return MapOpenSSLError(err); |
652 } | 748 } |
653 | 749 |
654 } // namespace net | 750 } // namespace net |
OLD | NEW |