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 // 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. | 27 static SECStatus ownBadCertHandler(void* arg, PRFileDesc* socket) { |
26 * TODO(port): expose to app via GetSSLInfo so it can put up | 28 PRErrorCode err = PR_GetError(); |
27 * the appropriate GUI and retry with override if desired | 29 LOG(INFO) << "server certificate is invalid; NSS error code " << err; |
28 */ | 30 // Return SECSuccess to override the problem, |
29 static SECStatus | 31 // or SECFailure to let the original function fail |
30 ownBadCertHandler(void * arg, PRFileDesc * socket) | 32 // Chromium wants it to fail here, and may retry it later. |
31 { | 33 return SECFailure; |
32 PRErrorCode err = PR_GetError(); | |
33 LOG(ERROR) << "server certificate is invalid; NSS error code " << err; | |
34 // Return SECSuccess to override the problem, SECFailure to let the original
function fail | |
35 return SECSuccess; /* override, say it's OK. */ | |
36 } | 34 } |
37 | 35 |
38 | 36 |
39 namespace net { | 37 namespace net { |
40 | 38 |
41 // State machines are easier to debug if you log state transitions. | 39 // State machines are easier to debug if you log state transitions. |
42 // Enable these if you want to see what's going on. | 40 // Enable these if you want to see what's going on. |
43 #if 1 | 41 #if 1 |
44 #define EnterFunction(x) | 42 #define EnterFunction(x) |
45 #define LeaveFunction(x) | 43 #define LeaveFunction(x) |
46 #define GotoState(s) next_state_ = s | 44 #define GotoState(s) next_state_ = s |
| 45 #define LogData(s, len) |
47 #else | 46 #else |
48 #define EnterFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ | 47 #define EnterFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ |
49 " enter " << x << "; next_state " << next_state_ | 48 " enter " << x << "; next_state " << next_state_ |
50 #define LeaveFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ | 49 #define LeaveFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ |
51 " leave " << x << "; next_state " << next_state_ | 50 " leave " << x << "; next_state " << next_state_ |
52 #define GotoState(s) do { LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ | 51 #define GotoState(s) do { LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ |
53 " jump to state " << s; next_state_ = s; } while (0) | 52 " jump to state " << s; next_state_ = s; } while (0) |
| 53 #define LogData(s, len) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \ |
| 54 " data [" << std::string(s, len) << "]"; |
| 55 |
54 #endif | 56 #endif |
55 | 57 |
| 58 namespace { |
| 59 |
| 60 int NetErrorFromNSPRError(PRErrorCode err) { |
| 61 // TODO(port): fill this out as we learn what's important |
| 62 switch (err) { |
| 63 case PR_WOULD_BLOCK_ERROR: |
| 64 return ERR_IO_PENDING; |
| 65 case SSL_ERROR_NO_CYPHER_OVERLAP: |
| 66 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; |
| 67 case SSL_ERROR_BAD_CERT_DOMAIN: |
| 68 return ERR_CERT_COMMON_NAME_INVALID; |
| 69 case SEC_ERROR_EXPIRED_CERTIFICATE: |
| 70 return ERR_CERT_DATE_INVALID; |
| 71 case SEC_ERROR_BAD_SIGNATURE: |
| 72 return ERR_CERT_INVALID; |
| 73 case SSL_ERROR_REVOKED_CERT_ALERT: |
| 74 case SEC_ERROR_REVOKED_CERTIFICATE: |
| 75 case SEC_ERROR_REVOKED_KEY: |
| 76 return ERR_CERT_REVOKED; |
| 77 case SEC_ERROR_UNKNOWN_ISSUER: |
| 78 return ERR_CERT_AUTHORITY_INVALID; |
| 79 |
| 80 default: { |
| 81 if (IS_SSL_ERROR(err)) { |
| 82 LOG(WARNING) << "Unknown SSL error " << err << |
| 83 " mapped to net::ERR_SSL_PROTOCOL_ERROR"; |
| 84 return ERR_SSL_PROTOCOL_ERROR; |
| 85 } |
| 86 if (IS_SEC_ERROR(err)) { |
| 87 // TODO(port): Probably not the best mapping |
| 88 LOG(WARNING) << "Unknown SEC error " << err << |
| 89 " mapped to net::ERR_CERT_INVALID"; |
| 90 return ERR_CERT_INVALID; |
| 91 } |
| 92 LOG(WARNING) << "Unknown error " << err << |
| 93 " mapped to net::ERR_FAILED"; |
| 94 return ERR_FAILED; |
| 95 } |
| 96 } |
| 97 } |
| 98 |
| 99 // Shared with the Windows code. TODO(avi): merge to a common place |
| 100 int CertStatusFromNetError(int error) { |
| 101 switch (error) { |
| 102 case ERR_CERT_COMMON_NAME_INVALID: |
| 103 return CERT_STATUS_COMMON_NAME_INVALID; |
| 104 case ERR_CERT_DATE_INVALID: |
| 105 return CERT_STATUS_DATE_INVALID; |
| 106 case ERR_CERT_AUTHORITY_INVALID: |
| 107 return CERT_STATUS_AUTHORITY_INVALID; |
| 108 case ERR_CERT_NO_REVOCATION_MECHANISM: |
| 109 return CERT_STATUS_NO_REVOCATION_MECHANISM; |
| 110 case ERR_CERT_UNABLE_TO_CHECK_REVOCATION: |
| 111 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; |
| 112 case ERR_CERT_REVOKED: |
| 113 return CERT_STATUS_REVOKED; |
| 114 case ERR_CERT_CONTAINS_ERRORS: |
| 115 NOTREACHED(); |
| 116 // Falls through. |
| 117 case ERR_CERT_INVALID: |
| 118 return CERT_STATUS_INVALID; |
| 119 default: |
| 120 return 0; |
| 121 } |
| 122 } |
| 123 |
| 124 } // namespace |
| 125 |
56 bool SSLClientSocketNSS::nss_options_initialized_ = false; | 126 bool SSLClientSocketNSS::nss_options_initialized_ = false; |
57 | 127 |
58 SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket, | 128 SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket, |
59 const std::string& hostname, | 129 const std::string& hostname, |
60 const SSLConfig& ssl_config) | 130 const SSLConfig& ssl_config) |
61 : | 131 : |
62 buffer_send_callback_(this, &SSLClientSocketNSS::BufferSendComplete), | 132 buffer_send_callback_(this, &SSLClientSocketNSS::BufferSendComplete), |
63 buffer_recv_callback_(this, &SSLClientSocketNSS::BufferRecvComplete), | 133 buffer_recv_callback_(this, &SSLClientSocketNSS::BufferRecvComplete), |
64 transport_send_busy_(false), | 134 transport_send_busy_(false), |
65 transport_recv_busy_(false), | 135 transport_recv_busy_(false), |
66 io_callback_(this, &SSLClientSocketNSS::OnIOComplete), | 136 io_callback_(this, &SSLClientSocketNSS::OnIOComplete), |
67 transport_(transport_socket), | 137 transport_(transport_socket), |
68 hostname_(hostname), | 138 hostname_(hostname), |
69 ssl_config_(ssl_config), | 139 ssl_config_(ssl_config), |
70 user_callback_(NULL), | 140 user_callback_(NULL), |
71 user_buf_(NULL), | 141 user_buf_(NULL), |
72 user_buf_len_(0), | 142 user_buf_len_(0), |
| 143 server_cert_status_(0), |
73 completed_handshake_(false), | 144 completed_handshake_(false), |
74 next_state_(STATE_NONE), | 145 next_state_(STATE_NONE), |
75 nss_fd_(NULL), | 146 nss_fd_(NULL), |
76 nss_bufs_(NULL) { | 147 nss_bufs_(NULL) { |
77 EnterFunction(""); | 148 EnterFunction(""); |
78 } | 149 } |
79 | 150 |
80 SSLClientSocketNSS::~SSLClientSocketNSS() { | 151 SSLClientSocketNSS::~SSLClientSocketNSS() { |
81 EnterFunction(""); | 152 EnterFunction(""); |
82 Disconnect(); | 153 Disconnect(); |
(...skipping 17 matching lines...) Expand all Loading... |
100 | 171 |
101 GotoState(STATE_CONNECT); | 172 GotoState(STATE_CONNECT); |
102 int rv = DoLoop(OK); | 173 int rv = DoLoop(OK); |
103 if (rv == ERR_IO_PENDING) | 174 if (rv == ERR_IO_PENDING) |
104 user_callback_ = callback; | 175 user_callback_ = callback; |
105 | 176 |
106 LeaveFunction(""); | 177 LeaveFunction(""); |
107 return rv; | 178 return rv; |
108 } | 179 } |
109 | 180 |
110 int SSLClientSocketNSS::ReconnectIgnoringLastError(CompletionCallback* callback)
{ | 181 int SSLClientSocketNSS::ReconnectIgnoringLastError( |
| 182 CompletionCallback* callback) { |
111 EnterFunction(""); | 183 EnterFunction(""); |
112 // TODO(darin): implement me! | 184 // TODO(darin): implement me! |
113 LeaveFunction(""); | 185 LeaveFunction(""); |
114 return ERR_FAILED; | 186 return ERR_FAILED; |
115 } | 187 } |
116 | 188 |
117 void SSLClientSocketNSS::Disconnect() { | 189 void SSLClientSocketNSS::Disconnect() { |
118 EnterFunction(""); | 190 EnterFunction(""); |
119 // TODO(wtc): Send SSL close_notify alert. | 191 // TODO(wtc): Send SSL close_notify alert. |
120 if (nss_fd_ != NULL) { | 192 if (nss_fd_ != NULL) { |
121 PR_Close(nss_fd_); | 193 PR_Close(nss_fd_); |
122 nss_fd_ = NULL; | 194 nss_fd_ = NULL; |
123 } | 195 } |
124 completed_handshake_ = false; | 196 completed_handshake_ = false; |
125 transport_->Disconnect(); | 197 transport_->Disconnect(); |
126 LeaveFunction(""); | 198 LeaveFunction(""); |
127 } | 199 } |
128 | 200 |
129 bool SSLClientSocketNSS::IsConnected() const { | 201 bool SSLClientSocketNSS::IsConnected() const { |
130 EnterFunction(""); | 202 EnterFunction(""); |
131 bool ret = completed_handshake_ && transport_->IsConnected(); | 203 bool ret = completed_handshake_ && transport_->IsConnected(); |
132 LeaveFunction(""); | 204 LeaveFunction(""); |
133 return ret; | 205 return ret; |
134 } | 206 } |
135 | 207 |
136 int SSLClientSocketNSS::Read(char* buf, int buf_len, | 208 int SSLClientSocketNSS::Read(char* buf, int buf_len, |
137 CompletionCallback* callback) { | 209 CompletionCallback* callback) { |
138 EnterFunction(buf_len); | 210 EnterFunction(buf_len); |
139 DCHECK(completed_handshake_); | 211 DCHECK(completed_handshake_); |
140 DCHECK(next_state_ == STATE_NONE); | 212 DCHECK(next_state_ == STATE_NONE); |
141 DCHECK(!user_callback_); | 213 DCHECK(!user_callback_); |
142 DCHECK(!user_buf_); | 214 DCHECK(!user_buf_); |
143 | 215 |
144 user_buf_ = buf; | 216 user_buf_ = buf; |
145 user_buf_len_ = buf_len; | 217 user_buf_len_ = buf_len; |
146 | 218 |
147 GotoState(STATE_PAYLOAD_READ); | 219 GotoState(STATE_PAYLOAD_READ); |
148 int rv = DoLoop(OK); | 220 int rv = DoLoop(OK); |
149 if (rv == ERR_IO_PENDING) | 221 if (rv == ERR_IO_PENDING) |
150 user_callback_ = callback; | 222 user_callback_ = callback; |
151 LeaveFunction(""); | 223 LeaveFunction(rv); |
152 return rv; | 224 return rv; |
153 } | 225 } |
154 | 226 |
155 int SSLClientSocketNSS::Write(const char* buf, int buf_len, | 227 int SSLClientSocketNSS::Write(const char* buf, int buf_len, |
156 CompletionCallback* callback) { | 228 CompletionCallback* callback) { |
157 EnterFunction(buf_len); | 229 EnterFunction(buf_len); |
158 DCHECK(completed_handshake_); | 230 DCHECK(completed_handshake_); |
159 DCHECK(next_state_ == STATE_NONE); | 231 DCHECK(next_state_ == STATE_NONE); |
160 DCHECK(!user_callback_); | 232 DCHECK(!user_callback_); |
161 DCHECK(!user_buf_); | 233 DCHECK(!user_buf_); |
162 | 234 |
163 user_buf_ = const_cast<char*>(buf); | 235 user_buf_ = const_cast<char*>(buf); |
164 user_buf_len_ = buf_len; | 236 user_buf_len_ = buf_len; |
165 | 237 |
166 GotoState(STATE_PAYLOAD_WRITE); | 238 GotoState(STATE_PAYLOAD_WRITE); |
167 int rv = DoLoop(OK); | 239 int rv = DoLoop(OK); |
168 if (rv == ERR_IO_PENDING) | 240 if (rv == ERR_IO_PENDING) |
169 user_callback_ = callback; | 241 user_callback_ = callback; |
170 LeaveFunction(""); | 242 LeaveFunction(rv); |
171 return rv; | 243 return rv; |
172 } | 244 } |
173 | 245 |
174 void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { | 246 void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { |
175 EnterFunction(""); | 247 EnterFunction(""); |
176 // TODO(port): implement! | |
177 ssl_info->Reset(); | 248 ssl_info->Reset(); |
| 249 SSLChannelInfo channel_info; |
| 250 SECStatus ok = SSL_GetChannelInfo(nss_fd_, |
| 251 &channel_info, sizeof(channel_info)); |
| 252 if (ok == SECSuccess) { |
| 253 SSLCipherSuiteInfo cipher_info; |
| 254 ok = SSL_GetCipherSuiteInfo(channel_info.cipherSuite, |
| 255 &cipher_info, sizeof(cipher_info)); |
| 256 if (ok == SECSuccess) { |
| 257 ssl_info->security_bits = cipher_info.effectiveKeyBits; |
| 258 } else { |
| 259 ssl_info->security_bits = -1; |
| 260 NOTREACHED(); |
| 261 } |
| 262 } |
| 263 ssl_info->cert_status = server_cert_status_; |
| 264 // TODO(port): implement X509Certificate so we can set the cert field! |
| 265 // CERTCertificate *nssCert = SSL_PeerCertificate(nss_fd_); |
178 LeaveFunction(""); | 266 LeaveFunction(""); |
179 } | 267 } |
180 | 268 |
181 void SSLClientSocketNSS::DoCallback(int rv) { | 269 void SSLClientSocketNSS::DoCallback(int rv) { |
182 EnterFunction(rv); | 270 EnterFunction(rv); |
183 DCHECK(rv != ERR_IO_PENDING); | 271 DCHECK(rv != ERR_IO_PENDING); |
184 DCHECK(user_callback_); | 272 DCHECK(user_callback_); |
185 | 273 |
186 // since Run may result in Read being called, clear user_callback_ up front. | 274 // since Run may result in Read being called, clear user_callback_ up front. |
187 CompletionCallback* c = user_callback_; | 275 CompletionCallback* c = user_callback_; |
(...skipping 14 matching lines...) Expand all Loading... |
202 // See _MD_unix_map_default_error in the NSS source | 290 // See _MD_unix_map_default_error in the NSS source |
203 // tree for inspiration. | 291 // tree for inspiration. |
204 static PRErrorCode MapErrorToNSS(int result) { | 292 static PRErrorCode MapErrorToNSS(int result) { |
205 if (result >=0) | 293 if (result >=0) |
206 return result; | 294 return result; |
207 // TODO(port): add real table | 295 // TODO(port): add real table |
208 LOG(ERROR) << "MapErrorToNSS " << result; | 296 LOG(ERROR) << "MapErrorToNSS " << result; |
209 return PR_UNKNOWN_ERROR; | 297 return PR_UNKNOWN_ERROR; |
210 } | 298 } |
211 | 299 |
212 /* | 300 /* |
213 * Do network I/O between the given buffer and the given socket. | 301 * Do network I/O between the given buffer and the given socket. |
214 * Return 0 for EOF, | 302 * Return 0 for EOF, |
215 * > 0 for bytes transferred immediately, | 303 * > 0 for bytes transferred immediately, |
216 * < 0 for error (or the non-error ERR_IO_PENDING). | 304 * < 0 for error (or the non-error ERR_IO_PENDING). |
217 */ | 305 */ |
218 int SSLClientSocketNSS::BufferSend(void) { | 306 int SSLClientSocketNSS::BufferSend(void) { |
219 if (transport_send_busy_) return ERR_IO_PENDING; | 307 if (transport_send_busy_) return ERR_IO_PENDING; |
220 | 308 |
221 const char *buf; | 309 const char *buf; |
222 int nb = memio_GetWriteParams(nss_bufs_, &buf); | 310 int nb = memio_GetWriteParams(nss_bufs_, &buf); |
223 EnterFunction(nb); | 311 EnterFunction(nb); |
224 | 312 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 } | 364 } |
277 | 365 |
278 | 366 |
279 int SSLClientSocketNSS::DoLoop(int last_io_result) { | 367 int SSLClientSocketNSS::DoLoop(int last_io_result) { |
280 EnterFunction(last_io_result); | 368 EnterFunction(last_io_result); |
281 bool network_moved; | 369 bool network_moved; |
282 int rv = last_io_result; | 370 int rv = last_io_result; |
283 do { | 371 do { |
284 network_moved = false; | 372 network_moved = false; |
285 // Default to STATE_NONE for next state. | 373 // Default to STATE_NONE for next state. |
286 // (This is a quirk carried over from the windows | 374 // (This is a quirk carried over from the windows |
287 // implementation. It makes reading the logs a bit harder.) | 375 // implementation. It makes reading the logs a bit harder.) |
288 // State handlers can and often do call GotoState just | 376 // State handlers can and often do call GotoState just |
289 // to stay in the current state. | 377 // to stay in the current state. |
290 State state = next_state_; | 378 State state = next_state_; |
291 GotoState(STATE_NONE); | 379 GotoState(STATE_NONE); |
292 switch (state) { | 380 switch (state) { |
293 case STATE_NONE: | 381 case STATE_NONE: |
294 // we're just pumping data between the buffer and the network | 382 // we're just pumping data between the buffer and the network |
295 break; | 383 break; |
296 case STATE_CONNECT: | 384 case STATE_CONNECT: |
297 rv = DoConnect(); | 385 rv = DoConnect(); |
298 break; | 386 break; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 // Tell NSS who we're connected to | 438 // Tell NSS who we're connected to |
351 PRNetAddr peername; | 439 PRNetAddr peername; |
352 socklen_t len = sizeof(PRNetAddr); | 440 socklen_t len = sizeof(PRNetAddr); |
353 int err = transport_->GetPeerName((struct sockaddr *)&peername, &len); | 441 int err = transport_->GetPeerName((struct sockaddr *)&peername, &len); |
354 if (err) { | 442 if (err) { |
355 DLOG(ERROR) << "GetPeerName failed"; | 443 DLOG(ERROR) << "GetPeerName failed"; |
356 return 9999; // TODO(port): real error | 444 return 9999; // TODO(port): real error |
357 } | 445 } |
358 memio_SetPeerName(nss_fd_, &peername); | 446 memio_SetPeerName(nss_fd_, &peername); |
359 | 447 |
360 // Grab pointer to buffers | 448 // Grab pointer to buffers |
361 nss_bufs_ = memio_GetSecret(nss_fd_); | 449 nss_bufs_ = memio_GetSecret(nss_fd_); |
362 | 450 |
363 /* Create SSL state machine */ | 451 /* Create SSL state machine */ |
364 /* Push SSL onto our fake I/O socket */ | 452 /* Push SSL onto our fake I/O socket */ |
365 nss_fd_ = SSL_ImportFD(NULL, nss_fd_); | 453 nss_fd_ = SSL_ImportFD(NULL, nss_fd_); |
366 if (nss_fd_ == NULL) { | 454 if (nss_fd_ == NULL) { |
367 return ERR_SSL_PROTOCOL_ERROR; // TODO(port): real error | 455 return ERR_SSL_PROTOCOL_ERROR; // TODO(port): real error |
368 } | 456 } |
369 // TODO(port): set more ssl options! Check errors! | 457 // TODO(port): set more ssl options! Check errors! |
370 | 458 |
371 int rv; | 459 int rv; |
372 | 460 |
373 rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE); | 461 rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE); |
374 if (rv != SECSuccess) | 462 if (rv != SECSuccess) |
375 return ERR_UNEXPECTED; | 463 return ERR_UNEXPECTED; |
376 | 464 |
377 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, ssl_config_.ssl2_enabled); | 465 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, ssl_config_.ssl2_enabled); |
378 if (rv != SECSuccess) | 466 if (rv != SECSuccess) |
379 return ERR_UNEXPECTED; | 467 return ERR_UNEXPECTED; |
380 | 468 |
| 469 // SNI is enabled automatically if TLS is enabled -- as long as |
| 470 // SSL_V2_COMPATIBLE_HELLO isn't. |
| 471 // So don't do V2 compatible hellos unless we're really using SSL2, |
| 472 // to avoid errors like |
| 473 // "common name `mail.google.com' != requested host name `gmail.com'" |
| 474 rv = SSL_OptionSet(nss_fd_, SSL_V2_COMPATIBLE_HELLO, |
| 475 ssl_config_.ssl2_enabled); |
| 476 if (rv != SECSuccess) |
| 477 return ERR_UNEXPECTED; |
| 478 |
381 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.ssl3_enabled); | 479 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.ssl3_enabled); |
382 if (rv != SECSuccess) | 480 if (rv != SECSuccess) |
383 return ERR_UNEXPECTED; | 481 return ERR_UNEXPECTED; |
384 | 482 |
385 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.tls1_enabled); | 483 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_TLS, ssl_config_.tls1_enabled); |
386 if (rv != SECSuccess) | 484 if (rv != SECSuccess) |
387 return ERR_UNEXPECTED; | 485 return ERR_UNEXPECTED; |
388 | 486 |
| 487 #ifdef SSL_ENABLE_SESSION_TICKETS |
| 488 // Support RFC 5077 |
| 489 rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE); |
| 490 if (rv != SECSuccess) |
| 491 LOG(INFO) << "SSL_ENABLE_SESSION_TICKETS failed. Old system nss?"; |
| 492 #else |
| 493 #error "You need to install NSS-3.12 or later to build chromium" |
| 494 #endif |
| 495 |
389 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); | 496 rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); |
390 if (rv != SECSuccess) | 497 if (rv != SECSuccess) |
391 return ERR_UNEXPECTED; | 498 return ERR_UNEXPECTED; |
392 | 499 |
393 rv = SSL_BadCertHook(nss_fd_, ownBadCertHandler, NULL); | 500 rv = SSL_BadCertHook(nss_fd_, ownBadCertHandler, NULL); |
394 if (rv != SECSuccess) | 501 if (rv != SECSuccess) |
395 return ERR_UNEXPECTED; | 502 return ERR_UNEXPECTED; |
396 | 503 |
397 // Tell SSL the hostname we're trying to connect to. | 504 // Tell SSL the hostname we're trying to connect to. |
398 SSL_SetURL(nss_fd_, hostname_.c_str()); | 505 SSL_SetURL(nss_fd_, hostname_.c_str()); |
399 | 506 |
400 // Tell SSL we're a client; needed if not letting NSPR do socket I/O | 507 // Tell SSL we're a client; needed if not letting NSPR do socket I/O |
401 SSL_ResetHandshake(nss_fd_, 0); | 508 SSL_ResetHandshake(nss_fd_, 0); |
402 GotoState(STATE_HANDSHAKE_READ); | 509 GotoState(STATE_HANDSHAKE_READ); |
403 // Return OK so DoLoop tries handshaking | 510 // Return OK so DoLoop tries handshaking |
404 LeaveFunction(""); | 511 LeaveFunction(""); |
405 return OK; | 512 return OK; |
406 } | 513 } |
407 | 514 |
408 int SSLClientSocketNSS::DoHandshakeRead() { | 515 int SSLClientSocketNSS::DoHandshakeRead() { |
409 EnterFunction(""); | 516 EnterFunction(""); |
| 517 int net_error; |
410 int rv = SSL_ForceHandshake(nss_fd_); | 518 int rv = SSL_ForceHandshake(nss_fd_); |
| 519 |
411 if (rv == SECSuccess) { | 520 if (rv == SECSuccess) { |
| 521 net_error = OK; |
412 // there's a callback for this, too | 522 // there's a callback for this, too |
413 completed_handshake_ = true; | 523 completed_handshake_ = true; |
414 // Indicate we're ready to handle I/O. Badly named? | 524 // Indicate we're ready to handle I/O. Badly named? |
415 GotoState(STATE_NONE); | 525 GotoState(STATE_NONE); |
416 LeaveFunction(""); | 526 } else { |
417 return OK; | 527 PRErrorCode prerr = PR_GetError(); |
| 528 net_error = NetErrorFromNSPRError(prerr); |
| 529 |
| 530 // If not done, stay in this state |
| 531 if (net_error == ERR_IO_PENDING) { |
| 532 GotoState(STATE_HANDSHAKE_READ); |
| 533 } else { |
| 534 server_cert_status_ = CertStatusFromNetError(net_error); |
| 535 LOG(ERROR) << "handshake failed; NSS error code " << prerr |
| 536 << ", net_error " << net_error << ", server_cert_status " |
| 537 << server_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 return NetErrorFromNSPRError(prerr); |
448 return ERR_SSL_PROTOCOL_ERROR; | |
449 } | 563 } |
450 | 564 |
451 int SSLClientSocketNSS::DoPayloadWrite() { | 565 int SSLClientSocketNSS::DoPayloadWrite() { |
452 EnterFunction(user_buf_len_); | 566 EnterFunction(user_buf_len_); |
453 int rv = PR_Write(nss_fd_, user_buf_, user_buf_len_); | 567 int rv = PR_Write(nss_fd_, user_buf_, user_buf_len_); |
454 if (rv >= 0) { | 568 if (rv >= 0) { |
| 569 LogData(user_buf_, rv); |
455 user_buf_ = NULL; | 570 user_buf_ = NULL; |
456 LeaveFunction(""); | 571 LeaveFunction(""); |
457 return rv; | 572 return rv; |
458 } | 573 } |
459 PRErrorCode prerr = PR_GetError(); | 574 PRErrorCode prerr = PR_GetError(); |
460 if (prerr == PR_WOULD_BLOCK_ERROR) { | 575 if (prerr == PR_WOULD_BLOCK_ERROR) { |
461 GotoState(STATE_PAYLOAD_WRITE); | 576 GotoState(STATE_PAYLOAD_WRITE); |
462 return ERR_IO_PENDING; | 577 return ERR_IO_PENDING; |
463 } | 578 } |
464 user_buf_ = NULL; | 579 user_buf_ = NULL; |
465 LeaveFunction(""); | 580 LeaveFunction(""); |
466 // TODO: map rv to net error code properly | 581 return NetErrorFromNSPRError(prerr); |
467 return ERR_SSL_PROTOCOL_ERROR; | |
468 } | 582 } |
469 | 583 |
470 } // namespace net | 584 } // namespace net |
471 | 585 |
OLD | NEW |