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

Side by Side Diff: net/base/ssl_client_socket_nss.cc

Issue 11249: Fix several cert problems on Linux (take 2) (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years 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
OLDNEW
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 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424 10 // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
10 // 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.
11 #define Lock FOO_NSS_Lock 12 #define Lock FOO_NSS_Lock
12 #include <ssl.h> 13 #include <ssl.h>
14 #include <sslerr.h>
13 #include <pk11pub.h> 15 #include <pk11pub.h>
14 #undef Lock 16 #undef Lock
15 17
16 #include "base/logging.h" 18 #include "base/logging.h"
17 #include "base/nss_init.h" 19 #include "base/nss_init.h"
18 #include "base/string_util.h" 20 #include "base/string_util.h"
19 #include "net/base/net_errors.h" 21 #include "net/base/net_errors.h"
20 #include "net/base/ssl_info.h" 22 #include "net/base/ssl_info.h"
21 23
22 static const int kRecvBufferSize = 4096; 24 static const int kRecvBufferSize = 4096;
23 25
24 /* 26 // nss calls this if an incoming certificate is invalid.
25 * nss calls this if an incoming certificate is invalid.
26 * TODO(port): expose to app via GetSSLInfo so it can put up
27 * the appropriate GUI and retry with override if desired
28 */
29 static SECStatus 27 static SECStatus
30 ownBadCertHandler(void * arg, PRFileDesc * socket) 28 ownBadCertHandler(void * arg, PRFileDesc * socket)
31 { 29 {
32 PRErrorCode err = PR_GetError(); 30 PRErrorCode err = PR_GetError();
33 LOG(ERROR) << "server certificate is invalid; NSS error code " << err; 31 LOG(INFO) << "server certificate is invalid; NSS error code " << err;
34 // Return SECSuccess to override the problem, SECFailure to let the original function fail 32 // Return SECSuccess to override the problem,
35 return SECSuccess; /* override, say it's OK. */ 33 // or SECFailure to let the original function fail
34 // Chromium wants it to fail here, and may retry it later.
35 return SECFailure;
36 } 36 }
37 37
38 38
39 namespace net { 39 namespace net {
40 40
41 // State machines are easier to debug if you log state transitions. 41 // State machines are easier to debug if you log state transitions.
42 // Enable these if you want to see what's going on. 42 // Enable these if you want to see what's going on.
43 #if 1 43 #if 1
44 #define EnterFunction(x) 44 #define EnterFunction(x)
45 #define LeaveFunction(x) 45 #define LeaveFunction(x)
46 #define GotoState(s) next_state_ = s 46 #define GotoState(s) next_state_ = s
47 #define LogData(s, len)
47 #else 48 #else
48 #define EnterFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ 49 #define EnterFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
49 " enter " << x << "; next_state " << next_state_ 50 " enter " << x << "; next_state " << next_state_
50 #define LeaveFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ 51 #define LeaveFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
51 " leave " << x << "; next_state " << next_state_ 52 " leave " << x << "; next_state " << next_state_
52 #define GotoState(s) do { LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ 53 #define GotoState(s) do { LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
53 " jump to state " << s; next_state_ = s; } while (0) 54 " jump to state " << s; next_state_ = s; } while (0)
55 #define LogData(s, len) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
56 " data [" << std::string(s, len) << "]";
57
54 #endif 58 #endif
55 59
60 namespace {
61
62 int NetErrorFromNSPRError(PRErrorCode err) {
63 // TODO(port): fill this out as we learn what's important
64 switch (err) {
65 case PR_WOULD_BLOCK_ERROR:
66 return ERR_IO_PENDING;
67 case SSL_ERROR_NO_CYPHER_OVERLAP:
68 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
69 case SSL_ERROR_BAD_CERT_DOMAIN:
70 return ERR_CERT_COMMON_NAME_INVALID;
71 case SEC_ERROR_EXPIRED_CERTIFICATE:
72 return ERR_CERT_DATE_INVALID;
73 case SEC_ERROR_BAD_SIGNATURE:
74 return ERR_CERT_INVALID;
75 case SSL_ERROR_REVOKED_CERT_ALERT:
76 case SEC_ERROR_REVOKED_CERTIFICATE:
77 case SEC_ERROR_REVOKED_KEY:
78 return ERR_CERT_REVOKED;
79 case SEC_ERROR_UNKNOWN_ISSUER:
80 return ERR_CERT_AUTHORITY_INVALID;
81
82 default: {
83 if (IS_SSL_ERROR(err)) {
84 LOG(WARNING) << "Unknown SSL error " << err <<
85 " mapped to net::ERR_SSL_PROTOCOL_ERROR";
86 return ERR_SSL_PROTOCOL_ERROR;
87 }
88 if (IS_SEC_ERROR(err)) {
89 // TODO(port): Probably not the best mapping
90 LOG(WARNING) << "Unknown SEC error " << err <<
91 " mapped to net::ERR_CERT_INVALID";
92 return ERR_CERT_INVALID;
93 }
94 LOG(WARNING) << "Unknown error " << err <<
95 " mapped to net::ERR_FAILED";
96 return ERR_FAILED;
97 }
98 }
99 }
100
101 // Shared with the Windows code. TODO(avi): merge to a common place
102 int CertStatusFromNetError(int error) {
103 switch (error) {
104 case ERR_CERT_COMMON_NAME_INVALID:
105 return CERT_STATUS_COMMON_NAME_INVALID;
106 case ERR_CERT_DATE_INVALID:
107 return CERT_STATUS_DATE_INVALID;
108 case ERR_CERT_AUTHORITY_INVALID:
109 return CERT_STATUS_AUTHORITY_INVALID;
110 case ERR_CERT_NO_REVOCATION_MECHANISM:
111 return CERT_STATUS_NO_REVOCATION_MECHANISM;
112 case ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
113 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
114 case ERR_CERT_REVOKED:
115 return CERT_STATUS_REVOKED;
116 case ERR_CERT_CONTAINS_ERRORS:
117 NOTREACHED();
118 // Falls through.
119 case ERR_CERT_INVALID:
120 return CERT_STATUS_INVALID;
121 default:
122 return 0;
123 }
124 }
125
126 } // namespace
127
56 bool SSLClientSocketNSS::nss_options_initialized_ = false; 128 bool SSLClientSocketNSS::nss_options_initialized_ = false;
57 129
58 SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket, 130 SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket,
59 const std::string& hostname, 131 const std::string& hostname,
60 const SSLConfig& ssl_config) 132 const SSLConfig& ssl_config)
61 : 133 :
62 buffer_send_callback_(this, &SSLClientSocketNSS::BufferSendComplete), 134 buffer_send_callback_(this, &SSLClientSocketNSS::BufferSendComplete),
63 buffer_recv_callback_(this, &SSLClientSocketNSS::BufferRecvComplete), 135 buffer_recv_callback_(this, &SSLClientSocketNSS::BufferRecvComplete),
64 transport_send_busy_(false), 136 transport_send_busy_(false),
65 transport_recv_busy_(false), 137 transport_recv_busy_(false),
66 io_callback_(this, &SSLClientSocketNSS::OnIOComplete), 138 io_callback_(this, &SSLClientSocketNSS::OnIOComplete),
67 transport_(transport_socket), 139 transport_(transport_socket),
68 hostname_(hostname), 140 hostname_(hostname),
69 ssl_config_(ssl_config), 141 ssl_config_(ssl_config),
70 user_callback_(NULL), 142 user_callback_(NULL),
71 user_buf_(NULL), 143 user_buf_(NULL),
72 user_buf_len_(0), 144 user_buf_len_(0),
145 server_cert_status_(0),
73 completed_handshake_(false), 146 completed_handshake_(false),
74 next_state_(STATE_NONE), 147 next_state_(STATE_NONE),
75 nss_fd_(NULL), 148 nss_fd_(NULL),
76 nss_bufs_(NULL) { 149 nss_bufs_(NULL) {
77 EnterFunction(""); 150 EnterFunction("");
78 } 151 }
79 152
80 SSLClientSocketNSS::~SSLClientSocketNSS() { 153 SSLClientSocketNSS::~SSLClientSocketNSS() {
81 EnterFunction(""); 154 EnterFunction("");
82 Disconnect(); 155 Disconnect();
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 DCHECK(!user_callback_); 214 DCHECK(!user_callback_);
142 DCHECK(!user_buf_); 215 DCHECK(!user_buf_);
143 216
144 user_buf_ = buf; 217 user_buf_ = buf;
145 user_buf_len_ = buf_len; 218 user_buf_len_ = buf_len;
146 219
147 GotoState(STATE_PAYLOAD_READ); 220 GotoState(STATE_PAYLOAD_READ);
148 int rv = DoLoop(OK); 221 int rv = DoLoop(OK);
149 if (rv == ERR_IO_PENDING) 222 if (rv == ERR_IO_PENDING)
150 user_callback_ = callback; 223 user_callback_ = callback;
151 LeaveFunction(""); 224 LeaveFunction(rv);
152 return rv; 225 return rv;
153 } 226 }
154 227
155 int SSLClientSocketNSS::Write(const char* buf, int buf_len, 228 int SSLClientSocketNSS::Write(const char* buf, int buf_len,
156 CompletionCallback* callback) { 229 CompletionCallback* callback) {
157 EnterFunction(buf_len); 230 EnterFunction(buf_len);
158 DCHECK(completed_handshake_); 231 DCHECK(completed_handshake_);
159 DCHECK(next_state_ == STATE_NONE); 232 DCHECK(next_state_ == STATE_NONE);
160 DCHECK(!user_callback_); 233 DCHECK(!user_callback_);
161 DCHECK(!user_buf_); 234 DCHECK(!user_buf_);
162 235
163 user_buf_ = const_cast<char*>(buf); 236 user_buf_ = const_cast<char*>(buf);
164 user_buf_len_ = buf_len; 237 user_buf_len_ = buf_len;
165 238
166 GotoState(STATE_PAYLOAD_WRITE); 239 GotoState(STATE_PAYLOAD_WRITE);
167 int rv = DoLoop(OK); 240 int rv = DoLoop(OK);
168 if (rv == ERR_IO_PENDING) 241 if (rv == ERR_IO_PENDING)
169 user_callback_ = callback; 242 user_callback_ = callback;
170 LeaveFunction(""); 243 LeaveFunction(rv);
171 return rv; 244 return rv;
172 } 245 }
173 246
174 void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { 247 void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
175 EnterFunction(""); 248 EnterFunction("");
176 // TODO(port): implement!
177 ssl_info->Reset(); 249 ssl_info->Reset();
250 SSLChannelInfo channel_info;
251 SECStatus ok = SSL_GetChannelInfo(nss_fd_,
252 &channel_info, sizeof(channel_info));
253 if (ok == SECSuccess) {
254 SSLCipherSuiteInfo cipher_info;
255 ok = SSL_GetCipherSuiteInfo(channel_info.cipherSuite,
256 &cipher_info, sizeof(cipher_info));
257 if (ok == SECSuccess) {
258 ssl_info->security_bits = cipher_info.effectiveKeyBits;
259 } else {
260 ssl_info->security_bits = -1;
261 NOTREACHED();
262 }
263 }
264 ssl_info->cert_status = server_cert_status_;
265 // TODO(port): implement X509Certificate so we can set the cert field!
266 // CERTCertificate *nssCert = SSL_PeerCertificate(nss_fd_);
178 LeaveFunction(""); 267 LeaveFunction("");
179 } 268 }
180 269
181 void SSLClientSocketNSS::DoCallback(int rv) { 270 void SSLClientSocketNSS::DoCallback(int rv) {
182 EnterFunction(rv); 271 EnterFunction(rv);
183 DCHECK(rv != ERR_IO_PENDING); 272 DCHECK(rv != ERR_IO_PENDING);
184 DCHECK(user_callback_); 273 DCHECK(user_callback_);
185 274
186 // since Run may result in Read being called, clear user_callback_ up front. 275 // since Run may result in Read being called, clear user_callback_ up front.
187 CompletionCallback* c = user_callback_; 276 CompletionCallback* c = user_callback_;
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 int rv; 460 int rv;
372 461
373 rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE); 462 rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE);
374 if (rv != SECSuccess) 463 if (rv != SECSuccess)
375 return ERR_UNEXPECTED; 464 return ERR_UNEXPECTED;
376 465
377 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, ssl_config_.ssl2_enabled); 466 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, ssl_config_.ssl2_enabled);
378 if (rv != SECSuccess) 467 if (rv != SECSuccess)
379 return ERR_UNEXPECTED; 468 return ERR_UNEXPECTED;
380 469
470 // SNI is enabled automatically if TLS is enabled -- as long as
471 // SSL_V2_COMPATIBLE_HELLO isn't.
472 // So don't do V2 compatible hellos unless we're really using SSL2,
473 // to avoid errors like
474 // "common name `mail.google.com' != requested host name `gmail.com'"
475 rv = SSL_OptionSet(nss_fd_, SSL_V2_COMPATIBLE_HELLO,
476 ssl_config_.ssl2_enabled);
477 if (rv != SECSuccess)
478 return ERR_UNEXPECTED;
479
381 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.ssl3_enabled); 480 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.ssl3_enabled);
382 if (rv != SECSuccess) 481 if (rv != SECSuccess)
383 return ERR_UNEXPECTED; 482 return ERR_UNEXPECTED;
384 483
385 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.tls1_enabled); 484 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_TLS, ssl_config_.tls1_enabled);
386 if (rv != SECSuccess) 485 if (rv != SECSuccess)
387 return ERR_UNEXPECTED; 486 return ERR_UNEXPECTED;
388 487
488 #ifdef SSL_ENABLE_SESSION_TICKETS
489 // Support RFC 5077
490 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
491 if (rv != SECSuccess)
492 LOG(INFO) << "SSL_ENABLE_SESSION_TICKETS failed. Old system nss?";
493 #else
494 #error "You need to install NSS-3.12 or later to build chromium"
495 #endif
496
389 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); 497 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
390 if (rv != SECSuccess) 498 if (rv != SECSuccess)
391 return ERR_UNEXPECTED; 499 return ERR_UNEXPECTED;
392 500
393 rv = SSL_BadCertHook(nss_fd_, ownBadCertHandler, NULL); 501 rv = SSL_BadCertHook(nss_fd_, ownBadCertHandler, NULL);
394 if (rv != SECSuccess) 502 if (rv != SECSuccess)
395 return ERR_UNEXPECTED; 503 return ERR_UNEXPECTED;
396 504
397 // Tell SSL the hostname we're trying to connect to. 505 // Tell SSL the hostname we're trying to connect to.
398 SSL_SetURL(nss_fd_, hostname_.c_str()); 506 SSL_SetURL(nss_fd_, hostname_.c_str());
399 507
400 // Tell SSL we're a client; needed if not letting NSPR do socket I/O 508 // Tell SSL we're a client; needed if not letting NSPR do socket I/O
401 SSL_ResetHandshake(nss_fd_, 0); 509 SSL_ResetHandshake(nss_fd_, 0);
402 GotoState(STATE_HANDSHAKE_READ); 510 GotoState(STATE_HANDSHAKE_READ);
403 // Return OK so DoLoop tries handshaking 511 // Return OK so DoLoop tries handshaking
404 LeaveFunction(""); 512 LeaveFunction("");
405 return OK; 513 return OK;
406 } 514 }
407 515
408 int SSLClientSocketNSS::DoHandshakeRead() { 516 int SSLClientSocketNSS::DoHandshakeRead() {
409 EnterFunction(""); 517 EnterFunction("");
518 int net_error;
410 int rv = SSL_ForceHandshake(nss_fd_); 519 int rv = SSL_ForceHandshake(nss_fd_);
520
411 if (rv == SECSuccess) { 521 if (rv == SECSuccess) {
522 net_error = OK;
412 // there's a callback for this, too 523 // there's a callback for this, too
413 completed_handshake_ = true; 524 completed_handshake_ = true;
414 // Indicate we're ready to handle I/O. Badly named? 525 // Indicate we're ready to handle I/O. Badly named?
415 GotoState(STATE_NONE); 526 GotoState(STATE_NONE);
416 LeaveFunction(""); 527 } else {
417 return OK; 528 PRErrorCode prerr = PR_GetError();
529 net_error = NetErrorFromNSPRError(prerr);
530
531 // If not done, stay in this state
532 if (net_error == ERR_IO_PENDING) {
533 GotoState(STATE_HANDSHAKE_READ);
534 } else {
535 server_cert_status_ = CertStatusFromNetError(net_error);
536 LOG(ERROR) << "handshake failed; NSS error code " << prerr
537 << ", net_error " << net_error << ", server_cert_status " << se rver_cert_status_;
538 }
418 } 539 }
419 PRErrorCode prerr = PR_GetError(); 540
420 if (prerr == PR_WOULD_BLOCK_ERROR) {
421 // at this point, it should have tried to send some bytes
422 GotoState(STATE_HANDSHAKE_READ);
423 LeaveFunction("");
424 return ERR_IO_PENDING;
425 }
426 // TODO: map rv to net error code properly
427 LeaveFunction(""); 541 LeaveFunction("");
428 return ERR_SSL_PROTOCOL_ERROR; 542 return net_error;
429 } 543 }
430 544
431 int SSLClientSocketNSS::DoPayloadRead() { 545 int SSLClientSocketNSS::DoPayloadRead() {
432 EnterFunction(user_buf_len_); 546 EnterFunction(user_buf_len_);
433 int rv = PR_Read(nss_fd_, user_buf_, user_buf_len_); 547 int rv = PR_Read(nss_fd_, user_buf_, user_buf_len_);
434 if (rv >= 0) { 548 if (rv >= 0) {
549 LogData(user_buf_, rv);
435 user_buf_ = NULL; 550 user_buf_ = NULL;
436 LeaveFunction(""); 551 LeaveFunction("");
437 return rv; 552 return rv;
438 } 553 }
439 PRErrorCode prerr = PR_GetError(); 554 PRErrorCode prerr = PR_GetError();
440 if (prerr == PR_WOULD_BLOCK_ERROR) { 555 if (prerr == PR_WOULD_BLOCK_ERROR) {
441 GotoState(STATE_PAYLOAD_READ); 556 GotoState(STATE_PAYLOAD_READ);
442 LeaveFunction(""); 557 LeaveFunction("");
443 return ERR_IO_PENDING; 558 return ERR_IO_PENDING;
444 } 559 }
445 user_buf_ = NULL; 560 user_buf_ = NULL;
446 LeaveFunction(""); 561 LeaveFunction("");
447 // TODO: map rv to net error code properly 562 // TODO: map rv to net error code properly
448 return ERR_SSL_PROTOCOL_ERROR; 563 return ERR_SSL_PROTOCOL_ERROR;
449 } 564 }
450 565
451 int SSLClientSocketNSS::DoPayloadWrite() { 566 int SSLClientSocketNSS::DoPayloadWrite() {
452 EnterFunction(user_buf_len_); 567 EnterFunction(user_buf_len_);
453 int rv = PR_Write(nss_fd_, user_buf_, user_buf_len_); 568 int rv = PR_Write(nss_fd_, user_buf_, user_buf_len_);
454 if (rv >= 0) { 569 if (rv >= 0) {
570 LogData(user_buf_, rv);
455 user_buf_ = NULL; 571 user_buf_ = NULL;
456 LeaveFunction(""); 572 LeaveFunction("");
457 return rv; 573 return rv;
458 } 574 }
459 PRErrorCode prerr = PR_GetError(); 575 PRErrorCode prerr = PR_GetError();
460 if (prerr == PR_WOULD_BLOCK_ERROR) { 576 if (prerr == PR_WOULD_BLOCK_ERROR) {
461 GotoState(STATE_PAYLOAD_WRITE); 577 GotoState(STATE_PAYLOAD_WRITE);
462 return ERR_IO_PENDING; 578 return ERR_IO_PENDING;
463 } 579 }
464 user_buf_ = NULL; 580 user_buf_ = NULL;
465 LeaveFunction(""); 581 LeaveFunction("");
466 // TODO: map rv to net error code properly 582 // TODO: map rv to net error code properly
467 return ERR_SSL_PROTOCOL_ERROR; 583 return ERR_SSL_PROTOCOL_ERROR;
468 } 584 }
469 585
470 } // namespace net 586 } // namespace net
471 587
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698