OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 #include "net/base/ssl_client_socket_nss.h" | 5 #include "net/base/ssl_client_socket_nss.h" |
6 | 6 |
7 #include <nspr.h> | 7 #include <nspr.h> |
8 #include <nss.h> | 8 #include <nss.h> |
9 #include <secerr.h> | 9 #include <secerr.h> |
10 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 | 10 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 |
11 // until NSS 3.12.2 comes out and we update to it. | 11 // until NSS 3.12.2 comes out and we update to it. |
12 #define Lock FOO_NSS_Lock | 12 #define Lock FOO_NSS_Lock |
13 #include <ssl.h> | 13 #include <ssl.h> |
14 #include <sslerr.h> | 14 #include <sslerr.h> |
15 #include <pk11pub.h> | 15 #include <pk11pub.h> |
16 #undef Lock | 16 #undef Lock |
17 | 17 |
| 18 #include "base/compiler_specific.h" |
18 #include "base/logging.h" | 19 #include "base/logging.h" |
19 #include "base/nss_init.h" | 20 #include "base/nss_init.h" |
20 #include "base/string_util.h" | 21 #include "base/string_util.h" |
21 #include "net/base/net_errors.h" | 22 #include "net/base/net_errors.h" |
22 #include "net/base/ssl_info.h" | 23 #include "net/base/ssl_info.h" |
23 | 24 |
24 static const int kRecvBufferSize = 4096; | 25 static const int kRecvBufferSize = 4096; |
25 | 26 |
26 namespace net { | 27 namespace net { |
27 | 28 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 | 123 |
123 int SSLClientSocketNSS::Init() { | 124 int SSLClientSocketNSS::Init() { |
124 EnterFunction(""); | 125 EnterFunction(""); |
125 // Call NSS_NoDB_Init() in a threadsafe way. | 126 // Call NSS_NoDB_Init() in a threadsafe way. |
126 base::EnsureNSSInit(); | 127 base::EnsureNSSInit(); |
127 | 128 |
128 LeaveFunction(""); | 129 LeaveFunction(""); |
129 return OK; | 130 return OK; |
130 } | 131 } |
131 | 132 |
| 133 // As part of Connect(), the SSLClientSocketNSS object performs an SSL |
| 134 // handshake. This requires network IO, which in turn calls |
| 135 // BufferRecvComplete() with a non-zero byte count. This byte count eventually |
| 136 // winds its way through the state machine and ends up being passed to the |
| 137 // callback. For Read() and Write(), that's what we want. But for Connect(), |
| 138 // the caller expects OK (i.e. 0) for success. |
| 139 // |
| 140 // The ConnectCallbackWrapper object changes the argument that gets passed |
| 141 // to the callback function. Any positive value gets turned into OK. |
| 142 class ConnectCallbackWrapper : |
| 143 public CompletionCallbackImpl<ConnectCallbackWrapper> { |
| 144 public: |
| 145 ConnectCallbackWrapper(CompletionCallback* user_callback) |
| 146 : ALLOW_THIS_IN_INITIALIZER_LIST( |
| 147 CompletionCallbackImpl<ConnectCallbackWrapper>(this, |
| 148 &ConnectCallbackWrapper::ReturnValueWrapper)), |
| 149 user_callback_(user_callback) { |
| 150 } |
| 151 |
| 152 private: |
| 153 void ReturnValueWrapper(int rv) { |
| 154 user_callback_->Run(rv > OK ? OK : rv); |
| 155 delete this; |
| 156 } |
| 157 |
| 158 CompletionCallback* user_callback_; |
| 159 }; |
| 160 |
132 int SSLClientSocketNSS::Connect(CompletionCallback* callback) { | 161 int SSLClientSocketNSS::Connect(CompletionCallback* callback) { |
133 EnterFunction(""); | 162 EnterFunction(""); |
134 DCHECK(transport_.get()); | 163 DCHECK(transport_.get()); |
135 DCHECK(next_state_ == STATE_NONE); | 164 DCHECK(next_state_ == STATE_NONE); |
136 DCHECK(!user_callback_); | 165 DCHECK(!user_callback_); |
137 | 166 |
138 GotoState(STATE_CONNECT); | 167 GotoState(STATE_CONNECT); |
139 int rv = DoLoop(OK); | 168 int rv = DoLoop(OK); |
140 if (rv == ERR_IO_PENDING) | 169 if (rv == ERR_IO_PENDING) |
141 user_callback_ = callback; | 170 user_callback_ = new ConnectCallbackWrapper(callback); |
142 | 171 |
143 LeaveFunction(""); | 172 LeaveFunction(""); |
144 return rv; | 173 return rv > OK ? OK : rv; |
145 } | 174 } |
146 | 175 |
147 int SSLClientSocketNSS::ReconnectIgnoringLastError( | 176 void SSLClientSocketNSS::InvalidateSessionIfBadCertificate() { |
148 CompletionCallback* callback) { | 177 if (UpdateServerCert() != NULL && |
149 EnterFunction(""); | 178 ssl_config_.allowed_bad_certs_.count(server_cert_)) { |
150 // TODO(darin): implement me! | 179 SSL_InvalidateSession(nss_fd_); |
151 LeaveFunction(""); | 180 } |
152 return ERR_FAILED; | |
153 } | 181 } |
154 | 182 |
155 void SSLClientSocketNSS::Disconnect() { | 183 void SSLClientSocketNSS::Disconnect() { |
156 EnterFunction(""); | 184 EnterFunction(""); |
| 185 |
| 186 // Reset object state |
| 187 transport_send_busy_ = false; |
| 188 transport_recv_busy_ = false; |
| 189 user_buf_ = NULL; |
| 190 user_buf_len_ = 0; |
| 191 server_cert_error_ = OK; |
| 192 completed_handshake_ = false; |
| 193 nss_bufs_ = NULL; |
| 194 |
157 // TODO(wtc): Send SSL close_notify alert. | 195 // TODO(wtc): Send SSL close_notify alert. |
158 if (nss_fd_ != NULL) { | 196 if (nss_fd_ != NULL) { |
| 197 InvalidateSessionIfBadCertificate(); |
159 PR_Close(nss_fd_); | 198 PR_Close(nss_fd_); |
160 nss_fd_ = NULL; | 199 nss_fd_ = NULL; |
161 } | 200 } |
162 completed_handshake_ = false; | 201 |
163 transport_->Disconnect(); | 202 transport_->Disconnect(); |
164 LeaveFunction(""); | 203 LeaveFunction(""); |
165 } | 204 } |
166 | 205 |
167 bool SSLClientSocketNSS::IsConnected() const { | 206 bool SSLClientSocketNSS::IsConnected() const { |
168 // Ideally, we should also check if we have received the close_notify alert | 207 // Ideally, we should also check if we have received the close_notify alert |
169 // message from the server, and return false in that case. We're not doing | 208 // message from the server, and return false in that case. We're not doing |
170 // that, so this function may return a false positive. Since the upper | 209 // that, so this function may return a false positive. Since the upper |
171 // layer (HttpNetworkTransaction) needs to handle a persistent connection | 210 // layer (HttpNetworkTransaction) needs to handle a persistent connection |
172 // closed by the server when we send a request anyway, a false positive in | 211 // closed by the server when we send a request anyway, a false positive in |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 user_buf_len_ = buf_len; | 261 user_buf_len_ = buf_len; |
223 | 262 |
224 GotoState(STATE_PAYLOAD_WRITE); | 263 GotoState(STATE_PAYLOAD_WRITE); |
225 int rv = DoLoop(OK); | 264 int rv = DoLoop(OK); |
226 if (rv == ERR_IO_PENDING) | 265 if (rv == ERR_IO_PENDING) |
227 user_callback_ = callback; | 266 user_callback_ = callback; |
228 LeaveFunction(rv); | 267 LeaveFunction(rv); |
229 return rv; | 268 return rv; |
230 } | 269 } |
231 | 270 |
| 271 X509Certificate *SSLClientSocketNSS::UpdateServerCert() { |
| 272 // We set the server_cert_ from OwnAuthCertHandler(), but this handler |
| 273 // does not necessarily get called if we are continuing a cached SSL |
| 274 // session. |
| 275 if (server_cert_ == NULL) { |
| 276 X509Certificate::OSCertHandle nss_cert = SSL_PeerCertificate(nss_fd_); |
| 277 if (nss_cert) { |
| 278 server_cert_ = X509Certificate::CreateFromHandle( |
| 279 nss_cert, X509Certificate::SOURCE_FROM_NETWORK); |
| 280 } |
| 281 } |
| 282 return server_cert_; |
| 283 } |
| 284 |
232 void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { | 285 void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { |
233 EnterFunction(""); | 286 EnterFunction(""); |
234 ssl_info->Reset(); | 287 ssl_info->Reset(); |
235 SSLChannelInfo channel_info; | 288 SSLChannelInfo channel_info; |
236 SECStatus ok = SSL_GetChannelInfo(nss_fd_, | 289 SECStatus ok = SSL_GetChannelInfo(nss_fd_, |
237 &channel_info, sizeof(channel_info)); | 290 &channel_info, sizeof(channel_info)); |
238 if (ok == SECSuccess && | 291 if (ok == SECSuccess && |
239 channel_info.length == sizeof(channel_info) && | 292 channel_info.length == sizeof(channel_info) && |
240 channel_info.cipherSuite) { | 293 channel_info.cipherSuite) { |
241 SSLCipherSuiteInfo cipher_info; | 294 SSLCipherSuiteInfo cipher_info; |
242 ok = SSL_GetCipherSuiteInfo(channel_info.cipherSuite, | 295 ok = SSL_GetCipherSuiteInfo(channel_info.cipherSuite, |
243 &cipher_info, sizeof(cipher_info)); | 296 &cipher_info, sizeof(cipher_info)); |
244 if (ok == SECSuccess) { | 297 if (ok == SECSuccess) { |
245 ssl_info->security_bits = cipher_info.effectiveKeyBits; | 298 ssl_info->security_bits = cipher_info.effectiveKeyBits; |
246 } else { | 299 } else { |
247 ssl_info->security_bits = -1; | 300 ssl_info->security_bits = -1; |
248 LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError() | 301 LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError() |
249 << " for cipherSuite " << channel_info.cipherSuite; | 302 << " for cipherSuite " << channel_info.cipherSuite; |
250 } | 303 } |
| 304 UpdateServerCert(); |
251 } | 305 } |
252 if (server_cert_error_ != net::OK) | 306 if (server_cert_error_ != net::OK) |
253 ssl_info->SetCertError(server_cert_error_); | 307 ssl_info->SetCertError(server_cert_error_); |
254 X509Certificate::OSCertHandle nss_cert = SSL_PeerCertificate(nss_fd_); | 308 DCHECK(server_cert_ != NULL); |
255 if (nss_cert) | 309 ssl_info->cert = server_cert_; |
256 ssl_info->cert = X509Certificate::CreateFromHandle(nss_cert, | |
257 X509Certificate::SOURCE_FROM_NETWORK); | |
258 LeaveFunction(""); | 310 LeaveFunction(""); |
259 } | 311 } |
260 | 312 |
261 void SSLClientSocketNSS::DoCallback(int rv) { | 313 void SSLClientSocketNSS::DoCallback(int rv) { |
262 EnterFunction(rv); | 314 EnterFunction(rv); |
263 DCHECK(rv != ERR_IO_PENDING); | 315 DCHECK(rv != ERR_IO_PENDING); |
264 DCHECK(user_callback_); | 316 DCHECK(user_callback_); |
265 | 317 |
266 // since Run may result in Read being called, clear user_callback_ up front. | 318 // since Run may result in Read being called, clear user_callback_ up front. |
267 CompletionCallback* c = user_callback_; | 319 CompletionCallback* c = user_callback_; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 } | 400 } |
349 | 401 |
350 void SSLClientSocketNSS::BufferRecvComplete(int result) { | 402 void SSLClientSocketNSS::BufferRecvComplete(int result) { |
351 EnterFunction(result); | 403 EnterFunction(result); |
352 memio_PutReadResult(nss_bufs_, result); | 404 memio_PutReadResult(nss_bufs_, result); |
353 transport_recv_busy_ = false; | 405 transport_recv_busy_ = false; |
354 OnIOComplete(result); | 406 OnIOComplete(result); |
355 LeaveFunction(""); | 407 LeaveFunction(""); |
356 } | 408 } |
357 | 409 |
358 | |
359 int SSLClientSocketNSS::DoLoop(int last_io_result) { | 410 int SSLClientSocketNSS::DoLoop(int last_io_result) { |
360 EnterFunction(last_io_result); | 411 EnterFunction(last_io_result); |
361 bool network_moved; | 412 bool network_moved; |
362 int rv = last_io_result; | 413 int rv = last_io_result; |
363 do { | 414 do { |
364 network_moved = false; | 415 network_moved = false; |
365 // Default to STATE_NONE for next state. | 416 // Default to STATE_NONE for next state. |
366 // (This is a quirk carried over from the windows | 417 // (This is a quirk carried over from the windows |
367 // implementation. It makes reading the logs a bit harder.) | 418 // implementation. It makes reading the logs a bit harder.) |
368 // State handlers can and often do call GotoState just | 419 // State handlers can and often do call GotoState just |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 } | 453 } |
403 } while ((rv != ERR_IO_PENDING || network_moved) && | 454 } while ((rv != ERR_IO_PENDING || network_moved) && |
404 next_state_ != STATE_NONE); | 455 next_state_ != STATE_NONE); |
405 LeaveFunction(""); | 456 LeaveFunction(""); |
406 return rv; | 457 return rv; |
407 } | 458 } |
408 | 459 |
409 int SSLClientSocketNSS::DoConnect() { | 460 int SSLClientSocketNSS::DoConnect() { |
410 EnterFunction(""); | 461 EnterFunction(""); |
411 GotoState(STATE_CONNECT_COMPLETE); | 462 GotoState(STATE_CONNECT_COMPLETE); |
412 return transport_->Connect(&io_callback_); | 463 |
| 464 // The caller has to make sure that the transport socket is connected. If |
| 465 // it isn't, we will eventually fail when trying to negotiate an SSL session. |
| 466 // But we cannot call transport_->Connect(), as we do not know if there is |
| 467 // any proxy negotiation that needs to be performed prior to establishing |
| 468 // the SSL session. |
| 469 return OK; |
| 470 } |
| 471 |
| 472 // static |
| 473 // NSS calls this if an incoming certificate needs to be verified. |
| 474 SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg, |
| 475 PRFileDesc* socket, |
| 476 PRBool checksig, |
| 477 PRBool is_server) { |
| 478 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); |
| 479 |
| 480 // Remember the certificate as it will no longer be accessible if the |
| 481 // handshake fails. |
| 482 that->UpdateServerCert(); |
| 483 |
| 484 return SSL_AuthCertificate(CERT_GetDefaultCertDB(), socket, checksig, |
| 485 is_server); |
413 } | 486 } |
414 | 487 |
415 // static | 488 // static |
416 // NSS calls this if an incoming certificate is invalid. | 489 // NSS calls this if an incoming certificate is invalid. |
417 SECStatus SSLClientSocketNSS::OwnBadCertHandler(void* arg, PRFileDesc* socket) { | 490 SECStatus SSLClientSocketNSS::OwnBadCertHandler(void* arg, |
| 491 PRFileDesc* socket) { |
418 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); | 492 SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); |
| 493 |
| 494 if (that->server_cert_ && |
| 495 that->ssl_config_.allowed_bad_certs_.count(that->server_cert_)) { |
| 496 LOG(INFO) << "accepting bad SSL certificate, as user told us to"; |
| 497 |
| 498 return SECSuccess; |
| 499 } |
419 PRErrorCode prerr = PR_GetError(); | 500 PRErrorCode prerr = PR_GetError(); |
420 that->server_cert_error_ = NetErrorFromNSPRError(prerr); | 501 that->server_cert_error_ = NetErrorFromNSPRError(prerr); |
421 LOG(INFO) << "server certificate is invalid; NSS error code " << prerr | 502 LOG(INFO) << "server certificate is invalid; NSS error code " << prerr |
422 << ", net error " << that->server_cert_error_; | 503 << ", net error " << that->server_cert_error_; |
423 // Return SECSuccess to override the problem. | 504 |
424 // Chromium wants it to succeed here, and may abort the connection later. | 505 return SECFailure; |
425 return SECSuccess; | |
426 } | 506 } |
427 | 507 |
428 int SSLClientSocketNSS::DoConnectComplete(int result) { | 508 int SSLClientSocketNSS::DoConnectComplete(int result) { |
429 EnterFunction(result); | 509 EnterFunction(result); |
430 if (result < 0) | 510 if (result < 0) |
431 return result; | 511 return result; |
432 | 512 |
433 if (Init() != OK) { | 513 if (Init() != OK) { |
434 NOTREACHED() << "Couldn't initialize nss"; | 514 NOTREACHED() << "Couldn't initialize nss"; |
435 } | 515 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 if (rv != SECSuccess) | 576 if (rv != SECSuccess) |
497 LOG(INFO) << "SSL_ENABLE_SESSION_TICKETS failed. Old system nss?"; | 577 LOG(INFO) << "SSL_ENABLE_SESSION_TICKETS failed. Old system nss?"; |
498 #else | 578 #else |
499 #error "You need to install NSS-3.12 or later to build chromium" | 579 #error "You need to install NSS-3.12 or later to build chromium" |
500 #endif | 580 #endif |
501 | 581 |
502 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); | 582 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); |
503 if (rv != SECSuccess) | 583 if (rv != SECSuccess) |
504 return ERR_UNEXPECTED; | 584 return ERR_UNEXPECTED; |
505 | 585 |
| 586 rv = SSL_AuthCertificateHook(nss_fd_, OwnAuthCertHandler, this); |
| 587 if (rv != SECSuccess) |
| 588 return ERR_UNEXPECTED; |
| 589 |
506 rv = SSL_BadCertHook(nss_fd_, OwnBadCertHandler, this); | 590 rv = SSL_BadCertHook(nss_fd_, OwnBadCertHandler, this); |
507 if (rv != SECSuccess) | 591 if (rv != SECSuccess) |
508 return ERR_UNEXPECTED; | 592 return ERR_UNEXPECTED; |
509 | 593 |
510 // Tell SSL the hostname we're trying to connect to. | 594 // Tell SSL the hostname we're trying to connect to. |
511 SSL_SetURL(nss_fd_, hostname_.c_str()); | 595 SSL_SetURL(nss_fd_, hostname_.c_str()); |
512 | 596 |
513 // Tell SSL we're a client; needed if not letting NSPR do socket I/O | 597 // Tell SSL we're a client; needed if not letting NSPR do socket I/O |
514 SSL_ResetHandshake(nss_fd_, 0); | 598 SSL_ResetHandshake(nss_fd_, 0); |
515 GotoState(STATE_HANDSHAKE_READ); | 599 GotoState(STATE_HANDSHAKE_READ); |
516 // Return OK so DoLoop tries handshaking | 600 // Return OK so DoLoop tries handshaking |
517 LeaveFunction(""); | 601 LeaveFunction(""); |
518 return OK; | 602 return OK; |
519 } | 603 } |
520 | 604 |
521 int SSLClientSocketNSS::DoHandshakeRead() { | 605 int SSLClientSocketNSS::DoHandshakeRead() { |
522 EnterFunction(""); | 606 EnterFunction(""); |
523 int net_error; | 607 int net_error = net::OK; |
524 int rv = SSL_ForceHandshake(nss_fd_); | 608 int rv = SSL_ForceHandshake(nss_fd_); |
525 | 609 |
526 if (rv == SECSuccess) { | 610 if (rv == SECSuccess) { |
527 net_error = server_cert_error_; | 611 DCHECK(server_cert_error_ == net::OK); |
| 612 |
| 613 InvalidateSessionIfBadCertificate(); |
| 614 |
528 // there's a callback for this, too | 615 // there's a callback for this, too |
529 completed_handshake_ = true; | 616 completed_handshake_ = true; |
530 // Done! | 617 // Done! |
531 } else { | 618 } else { |
532 PRErrorCode prerr = PR_GetError(); | 619 PRErrorCode prerr = PR_GetError(); |
533 net_error = NetErrorFromNSPRError(prerr); | 620 net_error = NetErrorFromNSPRError(prerr); |
534 | 621 |
535 // If not done, stay in this state | 622 // If not done, stay in this state |
536 if (net_error == ERR_IO_PENDING) { | 623 if (net_error == ERR_IO_PENDING) { |
537 GotoState(STATE_HANDSHAKE_READ); | 624 GotoState(STATE_HANDSHAKE_READ); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 if (prerr == PR_WOULD_BLOCK_ERROR) { | 666 if (prerr == PR_WOULD_BLOCK_ERROR) { |
580 GotoState(STATE_PAYLOAD_WRITE); | 667 GotoState(STATE_PAYLOAD_WRITE); |
581 return ERR_IO_PENDING; | 668 return ERR_IO_PENDING; |
582 } | 669 } |
583 user_buf_ = NULL; | 670 user_buf_ = NULL; |
584 LeaveFunction(""); | 671 LeaveFunction(""); |
585 return NetErrorFromNSPRError(prerr); | 672 return NetErrorFromNSPRError(prerr); |
586 } | 673 } |
587 | 674 |
588 } // namespace net | 675 } // namespace net |
OLD | NEW |