| 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 |