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. | |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |