Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 // OpenSSL binding for SSLClientSocket. The class layout and general principle | 5 // OpenSSL binding for SSLClientSocket. The class layout and general principle |
| 6 // of operation is derived from SSLClientSocketNSS. | 6 // of operation is derived from SSLClientSocketNSS. |
| 7 | 7 |
| 8 #include "net/socket/ssl_client_socket_openssl.h" | 8 #include "net/socket/ssl_client_socket_openssl.h" |
| 9 | 9 |
| 10 #include <openssl/ssl.h> | 10 #include <openssl/ssl.h> |
| 11 #include <openssl/err.h> | 11 #include <openssl/err.h> |
| 12 | 12 |
| 13 #include "net/base/cert_verifier.h" | |
| 13 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
| 14 #include "net/base/ssl_connection_status_flags.h" | 15 #include "net/base/ssl_connection_status_flags.h" |
| 15 #include "net/base/ssl_info.h" | 16 #include "net/base/ssl_info.h" |
| 16 #include "net/base/test_certificate_data.h" // TODO(joth): Remove!! | 17 #include "net/base/test_certificate_data.h" // TODO(joth): Remove!! |
| 17 | 18 |
| 18 namespace net { | 19 namespace net { |
| 19 | 20 |
| 20 namespace { | 21 namespace { |
| 21 | 22 |
| 22 // Enable this to see logging for state machine state transitions. | 23 // Enable this to see logging for state machine state transitions. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 39 ERR_error_string_n(error_num, buf, arraysize(buf)); | 40 ERR_error_string_n(error_num, buf, arraysize(buf)); |
| 40 DVLOG(1) << "SSL error " << error_num << ": " << buf; | 41 DVLOG(1) << "SSL error " << error_num << ": " << buf; |
| 41 } | 42 } |
| 42 } | 43 } |
| 43 | 44 |
| 44 int MapOpenSSLError(int err) { | 45 int MapOpenSSLError(int err) { |
| 45 switch (err) { | 46 switch (err) { |
| 46 case SSL_ERROR_WANT_READ: | 47 case SSL_ERROR_WANT_READ: |
| 47 case SSL_ERROR_WANT_WRITE: | 48 case SSL_ERROR_WANT_WRITE: |
| 48 return ERR_IO_PENDING; | 49 return ERR_IO_PENDING; |
| 50 case SSL_ERROR_SYSCALL: | |
| 51 DVLOG(1) << "OpenSSL SYSVCALL error, errno " << errno; | |
|
wtc
2010/10/04 23:13:53
Typo: SYSVCALL => SYSCALL
Should this really be m
| |
| 52 MaybeLogSSLError(); | |
| 53 return ERR_SSL_PROTOCOL_ERROR; | |
| 49 default: | 54 default: |
| 50 // TODO(joth): Implement full mapping. | 55 // TODO(joth): Implement full mapping. |
| 51 LOG(WARNING) << "Unknown OpenSSL error " << err; | 56 LOG(WARNING) << "Unknown OpenSSL error " << err; |
| 52 MaybeLogSSLError(); | 57 MaybeLogSSLError(); |
| 53 return ERR_SSL_PROTOCOL_ERROR; | 58 return ERR_SSL_PROTOCOL_ERROR; |
| 54 } | 59 } |
| 55 } | 60 } |
| 56 | 61 |
| 57 // Registered with |g_ctx| as global verify callback handler; we unpack the | 62 // Registered with |g_ctx| as global verify callback handler; we unpack the |
| 58 // SSLClientSocketOpenSSL instance associated with this callback and delegate | 63 // SSLClientSocketOpenSSL instance associated with this callback and delegate |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 79 : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_( | 84 : ALLOW_THIS_IN_INITIALIZER_LIST(buffer_send_callback_( |
| 80 this, &SSLClientSocketOpenSSL::BufferSendComplete)), | 85 this, &SSLClientSocketOpenSSL::BufferSendComplete)), |
| 81 ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_( | 86 ALLOW_THIS_IN_INITIALIZER_LIST(buffer_recv_callback_( |
| 82 this, &SSLClientSocketOpenSSL::BufferRecvComplete)), | 87 this, &SSLClientSocketOpenSSL::BufferRecvComplete)), |
| 83 transport_send_busy_(false), | 88 transport_send_busy_(false), |
| 84 transport_recv_busy_(false), | 89 transport_recv_busy_(false), |
| 85 user_connect_callback_(NULL), | 90 user_connect_callback_(NULL), |
| 86 user_read_callback_(NULL), | 91 user_read_callback_(NULL), |
| 87 user_write_callback_(NULL), | 92 user_write_callback_(NULL), |
| 88 client_auth_cert_needed_(false), | 93 client_auth_cert_needed_(false), |
| 94 ALLOW_THIS_IN_INITIALIZER_LIST(handshake_io_callback_( | |
| 95 this, &SSLClientSocketOpenSSL::OnHandshakeIOComplete)), | |
| 89 ssl_(NULL), | 96 ssl_(NULL), |
| 90 transport_bio_(NULL), | 97 transport_bio_(NULL), |
| 91 transport_(transport_socket), | 98 transport_(transport_socket), |
| 92 hostname_(hostname), | 99 hostname_(hostname), |
| 93 ssl_config_(ssl_config), | 100 ssl_config_(ssl_config), |
| 94 completed_handshake_(false), | 101 completed_handshake_(false), |
| 95 net_log_(transport_socket->socket()->NetLog()) { | 102 net_log_(transport_socket->socket()->NetLog()) { |
| 96 } | 103 } |
| 97 | 104 |
| 98 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { | 105 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 158 | 165 |
| 159 SSL_set_bio(ssl_, ssl_bio, ssl_bio); | 166 SSL_set_bio(ssl_, ssl_bio, ssl_bio); |
| 160 | 167 |
| 161 return true; | 168 return true; |
| 162 } | 169 } |
| 163 | 170 |
| 164 int SSLClientSocketOpenSSL::SSLVerifyCallback(int preverify_ok, | 171 int SSLClientSocketOpenSSL::SSLVerifyCallback(int preverify_ok, |
| 165 SSL* ssl, | 172 SSL* ssl, |
| 166 X509_STORE_CTX* x509_ctx) { | 173 X509_STORE_CTX* x509_ctx) { |
| 167 DCHECK_EQ(ssl_, ssl); | 174 DCHECK_EQ(ssl_, ssl); |
| 168 if (!preverify_ok) { | 175 int depth = X509_STORE_CTX_get_error_depth(x509_ctx); |
| 169 int depth = X509_STORE_CTX_get_error_depth(x509_ctx); | 176 DVLOG(preverify_ok ? 3 : 1) << "SSLVerifyCallback " << preverify_ok |
| 170 DVLOG(2) << "SSLVerifyCallback " << preverify_ok << " depth " << depth; | 177 << " depth " << depth; |
| 171 MaybeLogSSLError(); | 178 MaybeLogSSLError(); |
| 172 } | |
| 173 return preverify_ok; | 179 return preverify_ok; |
| 174 } | 180 } |
| 175 | 181 |
| 176 // SSLClientSocket methods | 182 // SSLClientSocket methods |
| 177 | 183 |
| 178 void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) { | 184 void SSLClientSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) { |
| 185 ssl_info->Reset(); | |
| 186 if (!server_cert_) | |
| 187 return; | |
| 188 | |
| 179 // Chrome DCHECKs that https pages provide a valid cert. For now (whilst in | 189 // Chrome DCHECKs that https pages provide a valid cert. For now (whilst in |
| 180 // early dev) we just create a spoof cert. | 190 // early dev) we just create a spoof cert. |
| 181 // TODO(joth): implement X509Certificate for OpenSSL and remove this hack. | 191 // TODO(joth): implement X509Certificate for OpenSSL and remove this hack. |
| 182 LOG(WARNING) << "Filling in certificate with bogus content"; | 192 LOG(WARNING) << "Filling in certificate with bogus content"; |
| 183 ssl_info->Reset(); | 193 ssl_info->cert = server_cert_; |
| 184 ssl_info->cert = X509Certificate::CreateFromBytes( | 194 ssl_info->cert_status = server_cert_verify_result_.cert_status; |
| 185 reinterpret_cast<const char*>(google_der), sizeof(google_der)); | |
| 186 DCHECK(ssl_info->cert); | |
| 187 ssl_info->cert_status = 0; | |
| 188 ssl_info->security_bits = 56; | 195 ssl_info->security_bits = 56; |
| 189 ssl_info->connection_status = | 196 ssl_info->connection_status = |
| 190 ((TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA) & | 197 ((TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA) & |
| 191 SSL_CONNECTION_CIPHERSUITE_MASK) << SSL_CONNECTION_CIPHERSUITE_SHIFT; | 198 SSL_CONNECTION_CIPHERSUITE_MASK) << SSL_CONNECTION_CIPHERSUITE_SHIFT; |
| 192 | |
| 193 // Silence compiler about unused vars. | |
| 194 (void)google_der; | |
| 195 (void)webkit_der; | |
| 196 (void)thawte_der; | |
| 197 (void)paypal_null_der; | |
| 198 } | 199 } |
| 199 | 200 |
| 200 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( | 201 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( |
| 201 SSLCertRequestInfo* cert_request_info) { | 202 SSLCertRequestInfo* cert_request_info) { |
| 202 NOTREACHED(); | 203 NOTREACHED(); |
| 203 } | 204 } |
| 204 | 205 |
| 205 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( | 206 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( |
| 206 std::string* proto) { | 207 std::string* proto) { |
| 207 proto->clear(); | 208 proto->clear(); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 252 if (rv == ERR_IO_PENDING) { | 253 if (rv == ERR_IO_PENDING) { |
| 253 user_connect_callback_ = callback; | 254 user_connect_callback_ = callback; |
| 254 } else { | 255 } else { |
| 255 net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL); | 256 net_log_.EndEvent(NetLog::TYPE_SSL_CONNECT, NULL); |
| 256 } | 257 } |
| 257 | 258 |
| 258 return rv > OK ? OK : rv; | 259 return rv > OK ? OK : rv; |
| 259 } | 260 } |
| 260 | 261 |
| 261 void SSLClientSocketOpenSSL::Disconnect() { | 262 void SSLClientSocketOpenSSL::Disconnect() { |
| 263 if (ssl_) { | |
| 264 SSL_free(ssl_); | |
| 265 ssl_ = NULL; | |
| 266 } | |
| 267 if (transport_bio_) { | |
| 268 BIO_free_all(transport_bio_); | |
| 269 transport_bio_ = NULL; | |
| 270 } | |
| 271 | |
| 272 // Shut down anything that may call us back (through buffer_send_callback_, | |
| 273 // buffer_recv_callback, or handshake_io_callback_). | |
| 274 verifier_.reset(); | |
| 275 transport_->socket()->Disconnect(); | |
| 276 | |
| 262 // Null all callbacks, delete all buffers. | 277 // Null all callbacks, delete all buffers. |
| 263 transport_send_busy_ = false; | 278 transport_send_busy_ = false; |
| 264 send_buffer_ = NULL; | 279 send_buffer_ = NULL; |
| 265 transport_recv_busy_ = false; | 280 transport_recv_busy_ = false; |
| 266 recv_buffer_ = NULL; | 281 recv_buffer_ = NULL; |
| 267 | 282 |
| 268 user_connect_callback_ = NULL; | 283 user_connect_callback_ = NULL; |
| 269 user_read_callback_ = NULL; | 284 user_read_callback_ = NULL; |
| 270 user_write_callback_ = NULL; | 285 user_write_callback_ = NULL; |
| 271 user_read_buf_ = NULL; | 286 user_read_buf_ = NULL; |
| 272 user_read_buf_len_ = 0; | 287 user_read_buf_len_ = 0; |
| 273 user_write_buf_ = NULL; | 288 user_write_buf_ = NULL; |
| 274 user_write_buf_len_ = 0; | 289 user_write_buf_len_ = 0; |
| 275 | 290 |
| 276 client_certs_.clear(); | 291 client_certs_.clear(); |
| 277 client_auth_cert_needed_ = false; | 292 client_auth_cert_needed_ = false; |
| 278 | 293 |
| 279 if (ssl_) { | 294 server_cert_verify_result_.Reset(); |
| 280 SSL_free(ssl_); | |
| 281 ssl_ = NULL; | |
| 282 } | |
| 283 if (transport_bio_) { | |
| 284 BIO_free(transport_bio_); | |
| 285 transport_bio_ = NULL; | |
| 286 } | |
| 287 | |
| 288 completed_handshake_ = false; | 295 completed_handshake_ = false; |
| 289 transport_->socket()->Disconnect(); | |
| 290 } | 296 } |
| 291 | 297 |
| 292 int SSLClientSocketOpenSSL::DoHandshakeLoop(int last_io_result) { | 298 int SSLClientSocketOpenSSL::DoHandshakeLoop(int last_io_result) { |
| 293 bool network_moved; | 299 bool network_moved; |
| 294 int rv = last_io_result; | 300 int rv = last_io_result; |
| 295 do { | 301 do { |
| 296 // Default to STATE_NONE for next state. | 302 // Default to STATE_NONE for next state. |
| 297 // (This is a quirk carried over from the windows | 303 // (This is a quirk carried over from the windows |
| 298 // implementation. It makes reading the logs a bit harder.) | 304 // implementation. It makes reading the logs a bit harder.) |
| 299 // State handlers can and often do call GotoState just | 305 // State handlers can and often do call GotoState just |
| 300 // to stay in the current state. | 306 // to stay in the current state. |
| 301 State state = next_handshake_state_; | 307 State state = next_handshake_state_; |
| 302 GotoState(STATE_NONE); | 308 GotoState(STATE_NONE); |
| 303 switch (state) { | 309 switch (state) { |
| 304 case STATE_NONE: | 310 case STATE_NONE: |
| 305 // we're just pumping data between the buffer and the network | 311 // we're just pumping data between the buffer and the network |
| 306 break; | 312 break; |
| 307 case STATE_HANDSHAKE: | 313 case STATE_HANDSHAKE: |
| 308 rv = DoHandshake(); | 314 rv = DoHandshake(); |
| 309 break; | 315 break; |
| 310 #if 0 // TODO(joth): Implement cert verification. | |
| 311 case STATE_VERIFY_CERT: | 316 case STATE_VERIFY_CERT: |
| 312 DCHECK(rv == OK); | 317 DCHECK(rv == OK); |
| 313 rv = DoVerifyCert(rv); | 318 rv = DoVerifyCert(rv); |
| 314 break; | 319 break; |
| 315 case STATE_VERIFY_CERT_COMPLETE: | 320 case STATE_VERIFY_CERT_COMPLETE: |
| 316 rv = DoVerifyCertComplete(rv); | 321 rv = DoVerifyCertComplete(rv); |
| 317 break; | 322 break; |
| 318 #endif | |
| 319 default: | 323 default: |
| 320 rv = ERR_UNEXPECTED; | 324 rv = ERR_UNEXPECTED; |
| 321 NOTREACHED() << "unexpected state" << state; | 325 NOTREACHED() << "unexpected state" << state; |
| 322 break; | 326 break; |
| 323 } | 327 } |
| 324 | 328 |
| 325 // To avoid getting an ERR_IO_PENDING here after handshake complete. | 329 // To avoid getting an ERR_IO_PENDING here after handshake complete. |
| 326 if (next_handshake_state_ == STATE_NONE) | 330 if (next_handshake_state_ == STATE_NONE) |
| 327 break; | 331 break; |
| 328 | 332 |
| 329 // Do the actual network I/O. | 333 // Do the actual network I/O. |
| 330 network_moved = DoTransportIO(); | 334 network_moved = DoTransportIO(); |
| 331 } while ((rv != ERR_IO_PENDING || network_moved) && | 335 } while ((rv != ERR_IO_PENDING || network_moved) && |
| 332 next_handshake_state_ != STATE_NONE); | 336 next_handshake_state_ != STATE_NONE); |
| 333 return rv; | 337 return rv; |
| 334 } | 338 } |
| 335 | 339 |
| 336 int SSLClientSocketOpenSSL::DoHandshake() { | 340 int SSLClientSocketOpenSSL::DoHandshake() { |
| 337 int net_error = net::OK; | 341 int net_error = net::OK; |
| 338 int rv = SSL_do_handshake(ssl_); | 342 int rv = SSL_do_handshake(ssl_); |
| 339 | 343 |
| 340 if (rv == 1) { | 344 if (rv == 1) { |
| 341 // SSL handshake is completed. Let's verify the certificate. | 345 // SSL handshake is completed. Let's verify the certificate. |
| 342 // For now we are done, certificates not implemented yet. | 346 if (UpdateServerCert() == NULL) { |
| 343 // TODO(joth): Implement certificates | 347 net_error = ERR_SSL_PROTOCOL_ERROR; |
| 344 GotoState(STATE_NONE); | 348 } else { |
| 345 completed_handshake_ = true; | 349 GotoState(STATE_VERIFY_CERT); |
| 350 | |
| 351 // TODO(joth): Remove this check when X509Certificate::Verify is | |
| 352 // implemented for OpenSSL | |
| 353 long verify_result = SSL_get_verify_result(ssl_); | |
| 354 LOG_IF(WARNING, verify_result != X509_V_OK) | |
| 355 << "Built in verify failed: " << verify_result; | |
| 356 } | |
| 346 } else { | 357 } else { |
| 347 int ssl_error = SSL_get_error(ssl_, rv); | 358 int ssl_error = SSL_get_error(ssl_, rv); |
| 359 net_error = MapOpenSSLError(ssl_error); | |
| 348 | 360 |
| 349 // If not done, stay in this state | 361 // If not done, stay in this state |
| 350 GotoState(STATE_HANDSHAKE); | 362 if (net_error == ERR_IO_PENDING) { |
| 351 net_error = MapOpenSSLError(ssl_error); | 363 GotoState(STATE_HANDSHAKE); |
| 364 } else { | |
| 365 LOG(ERROR) << "handshake failed; returned " << rv | |
| 366 << ", SSL error code " << ssl_error | |
| 367 << ", net_error " << net_error; | |
| 368 MaybeLogSSLError(); | |
| 369 } | |
| 370 } | |
| 371 return net_error; | |
| 372 } | |
| 373 | |
| 374 int SSLClientSocketOpenSSL::DoVerifyCert(int result) { | |
| 375 DCHECK(server_cert_); | |
| 376 GotoState(STATE_VERIFY_CERT_COMPLETE); | |
| 377 int flags = 0; | |
| 378 | |
| 379 if (ssl_config_.rev_checking_enabled) | |
| 380 flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED; | |
| 381 if (ssl_config_.verify_ev_cert) | |
| 382 flags |= X509Certificate::VERIFY_EV_CERT; | |
| 383 verifier_.reset(new CertVerifier); | |
| 384 return verifier_->Verify(server_cert_, hostname_, flags, | |
| 385 &server_cert_verify_result_, | |
| 386 &handshake_io_callback_); | |
| 387 } | |
| 388 | |
| 389 int SSLClientSocketOpenSSL::DoVerifyCertComplete(int result) { | |
| 390 verifier_.reset(); | |
| 391 | |
| 392 if (result == OK) { | |
| 393 // TODO(joth): Work out if we need to remember the intermediate CA certs | |
| 394 // when the server sends them to us, and do so here. | |
| 352 } | 395 } |
| 353 | 396 |
| 354 return net_error; | 397 // If we have been explicitly told to accept this certificate, override the |
| 398 // result of verifier_.Verify. | |
| 399 // Eventually, we should cache the cert verification results so that we don't | |
| 400 // need to call verifier_.Verify repeatedly. But for now we need to do this. | |
| 401 // Alternatively, we could use the cert's status that we stored along with | |
| 402 // the cert in the allowed_bad_certs vector. | |
| 403 if (IsCertificateError(result) && | |
| 404 ssl_config_.IsAllowedBadCert(server_cert_)) { | |
| 405 LOG(INFO) << "accepting bad SSL certificate, as user told us to"; | |
| 406 result = OK; | |
| 407 } | |
| 408 | |
| 409 completed_handshake_ = true; | |
| 410 // The NSS version has a comment that we may not need this call because it is | |
| 411 // now harmless to have a session with a bad cert. | |
| 412 // This may or may not apply here, but let's invalidate it anyway. | |
| 413 InvalidateSessionIfBadCertificate(); | |
| 414 // Exit DoHandshakeLoop and return the result to the caller to Connect. | |
| 415 DCHECK_EQ(STATE_NONE, next_handshake_state_); | |
| 416 return result; | |
| 417 } | |
| 418 | |
| 419 void SSLClientSocketOpenSSL::InvalidateSessionIfBadCertificate() { | |
| 420 if (UpdateServerCert() != NULL && | |
| 421 ssl_config_.IsAllowedBadCert(server_cert_)) { | |
| 422 // Remove from session cache but don't clear this connection. | |
| 423 // TODO(joth): This should be a no-op until we enable session caching, | |
| 424 // see SSL_CTX_set_session_cache_mode(SSL_SESS_CACHE_CLIENT). | |
| 425 SSL_SESSION* session = SSL_get_session(ssl_); | |
| 426 LOG_IF(ERROR, session) << "Connection has a session?? " << session; | |
| 427 int rv = SSL_CTX_remove_session(g_ctx, session); | |
| 428 LOG_IF(ERROR, rv) << "Session was cached?? " << rv; | |
| 429 } | |
| 430 } | |
| 431 | |
| 432 X509Certificate* SSLClientSocketOpenSSL::UpdateServerCert() { | |
| 433 if (server_cert_) | |
| 434 return server_cert_; | |
| 435 | |
| 436 X509* cert = SSL_get_peer_certificate(ssl_); | |
| 437 if (cert == NULL) { | |
| 438 LOG(WARNING) << "SSL_get_peer_certificate returned NULL"; | |
| 439 return NULL; | |
| 440 } | |
| 441 | |
| 442 // TODO(joth): Get |server_cert_| from |cert|. | |
| 443 server_cert_ = X509Certificate::CreateFromBytes( | |
| 444 reinterpret_cast<const char*>(google_der), sizeof(google_der)); | |
| 445 X509_free(cert); | |
| 446 DCHECK(server_cert_); | |
| 447 // Silence compiler about unused vars. | |
| 448 (void)google_der; (void)webkit_der; (void)thawte_der; (void)paypal_null_der; | |
| 449 | |
| 450 return server_cert_; | |
| 355 } | 451 } |
| 356 | 452 |
| 357 bool SSLClientSocketOpenSSL::DoTransportIO() { | 453 bool SSLClientSocketOpenSSL::DoTransportIO() { |
| 358 bool network_moved = false; | 454 bool network_moved = false; |
| 359 int nsent = BufferSend(); | 455 int nsent = BufferSend(); |
| 360 int nreceived = BufferRecv(); | 456 int nreceived = BufferRecv(); |
| 361 network_moved = (nsent > 0 || nreceived >= 0); | 457 network_moved = (nsent > 0 || nreceived >= 0); |
| 362 return network_moved; | 458 return network_moved; |
| 363 } | 459 } |
| 364 | 460 |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 645 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); | 741 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); |
| 646 | 742 |
| 647 if (rv >= 0) | 743 if (rv >= 0) |
| 648 return rv; | 744 return rv; |
| 649 | 745 |
| 650 int err = SSL_get_error(ssl_, rv); | 746 int err = SSL_get_error(ssl_, rv); |
| 651 return MapOpenSSLError(err); | 747 return MapOpenSSLError(err); |
| 652 } | 748 } |
| 653 | 749 |
| 654 } // namespace net | 750 } // namespace net |
| OLD | NEW |