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

Unified Diff: net/socket/ssl_server_socket_openssl.cc

Issue 274783002: Implement SSL server socket over OpenSSL. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 7 months 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 side-by-side diff with in-line comments
Download patch
Index: net/socket/ssl_server_socket_openssl.cc
diff --git a/net/socket/ssl_server_socket_openssl.cc b/net/socket/ssl_server_socket_openssl.cc
index c327f2caf10e4e179c5295f17b80dc47c1d8600a..9d6f7ec2950bd1433830778956fd43036e31284f 100644
--- a/net/socket/ssl_server_socket_openssl.cc
+++ b/net/socket/ssl_server_socket_openssl.cc
@@ -2,18 +2,42 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "net/socket/ssl_server_socket_openssl.h"
+
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+#include "base/debug/alias.h"
#include "base/logging.h"
-#include "net/socket/ssl_server_socket.h"
+#include "crypto/openssl_util.h"
+#include "crypto/rsa_private_key.h"
+#include "net/base/net_errors.h"
+#include "net/socket/openssl_util.h"
+#include "net/socket/ssl_error_params.h"
-// TODO(bulach): Provide simple stubs for EnableSSLServerSockets and
-// CreateSSLServerSocket so that when building for OpenSSL rather than NSS,
-// so that the code using SSL server sockets can be compiled and disabled
-// programatically rather than requiring to be carved out from the compile.
+// Enable this to see logging for state machine state transitions.
+#if 0
+#define GotoState(s) do { DVLOG(2) << (void *)this << " " << __FUNCTION__ << \
+ " jump to state " << s; \
+ next_handshake_state_ = s; } while (0)
+#else
+#define GotoState(s) next_handshake_state_ = s
+#endif
Ryan Sleevi 2014/05/12 01:35:25 Remove this
byungchul 2014/05/12 18:25:23 Done.
namespace net {
+namespace {
+
+bool g_openssl_server_sockets_init = false;
Ryan Sleevi 2014/05/12 01:35:25 This is not thread-safe. Use LazyInstance for thre
byungchul 2014/05/12 18:25:23 Done.
+
+} // namespace
+
+
void EnableSSLServerSockets() {
- NOTIMPLEMENTED();
+ if (!g_openssl_server_sockets_init) {
+ crypto::EnsureOpenSSLInit();
+ g_openssl_server_sockets_init = true;
+ }
}
scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
@@ -21,8 +45,638 @@ scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
X509Certificate* certificate,
crypto::RSAPrivateKey* key,
const SSLConfig& ssl_config) {
+ DCHECK(g_openssl_server_sockets_init)
+ << "EnableSSLServerSockets() has not been called yet!";
Ryan Sleevi 2014/05/12 01:35:25 Remove this
byungchul 2014/05/12 18:25:23 Done.
+
+ return scoped_ptr<SSLServerSocket>(
+ new SSLServerSocketOpenSSL(socket.Pass(), certificate, key, ssl_config));
+}
+
+SSLServerSocketOpenSSL::SSLServerSocketOpenSSL(
+ scoped_ptr<StreamSocket> transport_socket,
+ scoped_refptr<X509Certificate> certificate,
+ crypto::RSAPrivateKey* key,
+ const SSLConfig& ssl_config)
+ : transport_send_busy_(false),
+ transport_recv_busy_(false),
+ transport_recv_eof_(false),
+ user_read_buf_len_(0),
+ user_write_buf_len_(0),
+ transport_write_error_(OK),
+ ssl_(NULL),
+ transport_bio_(NULL),
+ transport_socket_(transport_socket.Pass()),
+ ssl_config_(ssl_config),
+ cert_(certificate),
+ next_handshake_state_(STATE_NONE),
+ completed_handshake_(false) {
+ // TODO(byungchul): Need a better way to clone a key.
+ std::vector<uint8> key_bytes;
+ CHECK(key->ExportPrivateKey(&key_bytes));
+ key_.reset(crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_bytes));
+ CHECK(key_.get());
+}
+
+SSLServerSocketOpenSSL::~SSLServerSocketOpenSSL() {
+ if (ssl_) {
+ // Calling SSL_shutdown prevents the session from being marked as
+ // unresumable.
+ SSL_shutdown(ssl_);
+ SSL_free(ssl_);
+ ssl_ = NULL;
+ }
+ if (transport_bio_) {
+ BIO_free_all(transport_bio_);
+ transport_bio_ = NULL;
+ }
+}
+
+int SSLServerSocketOpenSSL::Handshake(const CompletionCallback& callback) {
+ net_log_.BeginEvent(NetLog::TYPE_SSL_SERVER_HANDSHAKE);
+
+ // Set up new ssl object.
+ if (!Init()) {
+ LOG(ERROR) << "Failed to initialize OpenSSL";
+ int rv = ERR_UNEXPECTED;
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
+ return rv;
+ }
+
+ // Set SSL to server mode. Handshake happens in the loop below.
+ SSL_set_accept_state(ssl_);
+
+ GotoState(STATE_HANDSHAKE);
+ int rv = DoHandshakeLoop(OK);
+ if (rv == ERR_IO_PENDING) {
+ user_handshake_callback_ = callback;
+ } else {
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
+ }
+
+ return rv > OK ? OK : rv;
+}
+
+int SSLServerSocketOpenSSL::ExportKeyingMaterial(
+ const base::StringPiece& label,
+ bool has_context,
+ const base::StringPiece& context,
+ unsigned char* out,
+ unsigned int outlen) {
+ if (!IsConnected())
+ return ERR_SOCKET_NOT_CONNECTED;
+ if (SSL_export_keying_material(
+ ssl_, out, outlen, label.data(), label.size(),
+ reinterpret_cast<const unsigned char*>(context.data()),
+ context.length(), has_context ? 1 : 0) == 0) {
+ LOG(ERROR) << "SSL_export_keying_material error";
+ return ERR_FAILED;
+ }
+ return OK;
+}
+
+int SSLServerSocketOpenSSL::GetTLSUniqueChannelBinding(std::string* out) {
+ return ERR_NOT_IMPLEMENTED;
+}
+
+int SSLServerSocketOpenSSL::Read(IOBuffer* buf, int buf_len,
+ const CompletionCallback& callback) {
+ DCHECK(user_read_callback_.is_null());
+ DCHECK(user_handshake_callback_.is_null());
+ DCHECK(!user_read_buf_.get());
+ DCHECK(!callback.is_null());
+
+ user_read_buf_ = buf;
+ user_read_buf_len_ = buf_len;
+
+ DCHECK(completed_handshake_);
+
+ int rv = DoReadLoop(OK);
+
+ if (rv == ERR_IO_PENDING) {
+ user_read_callback_ = callback;
+ } else {
+ user_read_buf_ = NULL;
+ user_read_buf_len_ = 0;
+ }
+
+ return rv;
+}
+
+int SSLServerSocketOpenSSL::Write(IOBuffer* buf, int buf_len,
+ const CompletionCallback& callback) {
+ DCHECK(user_write_callback_.is_null());
+ DCHECK(!user_write_buf_.get());
+ DCHECK(!callback.is_null());
+
+ user_write_buf_ = buf;
+ user_write_buf_len_ = buf_len;
+
+ int rv = DoWriteLoop(OK);
+
+ if (rv == ERR_IO_PENDING) {
+ user_write_callback_ = callback;
+ } else {
+ user_write_buf_ = NULL;
+ user_write_buf_len_ = 0;
+ }
+ return rv;
+}
+
+int SSLServerSocketOpenSSL::SetReceiveBufferSize(int32 size) {
+ return transport_socket_->SetReceiveBufferSize(size);
+}
+
+int SSLServerSocketOpenSSL::SetSendBufferSize(int32 size) {
+ return transport_socket_->SetSendBufferSize(size);
+}
+
+int SSLServerSocketOpenSSL::Connect(const CompletionCallback& callback) {
NOTIMPLEMENTED();
- return scoped_ptr<SSLServerSocket>();
+ return ERR_NOT_IMPLEMENTED;
+}
+
+void SSLServerSocketOpenSSL::Disconnect() {
+ transport_socket_->Disconnect();
+}
+
+bool SSLServerSocketOpenSSL::IsConnected() const {
+ return completed_handshake_;
+}
+
+bool SSLServerSocketOpenSSL::IsConnectedAndIdle() const {
+ return completed_handshake_ && transport_socket_->IsConnectedAndIdle();
+}
+
+int SSLServerSocketOpenSSL::GetPeerAddress(IPEndPoint* address) const {
+ if (!IsConnected())
+ return ERR_SOCKET_NOT_CONNECTED;
+ return transport_socket_->GetPeerAddress(address);
+}
+
+int SSLServerSocketOpenSSL::GetLocalAddress(IPEndPoint* address) const {
+ if (!IsConnected())
+ return ERR_SOCKET_NOT_CONNECTED;
+ return transport_socket_->GetLocalAddress(address);
+}
+
+const BoundNetLog& SSLServerSocketOpenSSL::NetLog() const {
+ return net_log_;
+}
+
+void SSLServerSocketOpenSSL::SetSubresourceSpeculation() {
+ transport_socket_->SetSubresourceSpeculation();
+}
+
+void SSLServerSocketOpenSSL::SetOmniboxSpeculation() {
+ transport_socket_->SetOmniboxSpeculation();
+}
+
+bool SSLServerSocketOpenSSL::WasEverUsed() const {
+ return transport_socket_->WasEverUsed();
+}
+
+bool SSLServerSocketOpenSSL::UsingTCPFastOpen() const {
+ return transport_socket_->UsingTCPFastOpen();
+}
+
+bool SSLServerSocketOpenSSL::WasNpnNegotiated() const {
+ return false;
+}
+
+NextProto SSLServerSocketOpenSSL::GetNegotiatedProtocol() const {
+ // NPN is not supported by this class.
+ return kProtoUnknown;
+}
+
+bool SSLServerSocketOpenSSL::GetSSLInfo(SSLInfo* ssl_info) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void SSLServerSocketOpenSSL::OnSendComplete(int result) {
+ if (next_handshake_state_ == STATE_HANDSHAKE) {
+ // In handshake phase.
+ OnHandshakeIOComplete(result);
+ return;
+ }
+
+ if (!completed_handshake_)
+ return;
+
+ if (user_write_buf_.get()) {
+ int rv = DoWriteLoop(result);
+ if (rv != ERR_IO_PENDING)
+ DoWriteCallback(rv);
+ } else {
+ // Ensure that any queued ciphertext is flushed.
+ DoTransportIO();
+ }
Ryan Sleevi 2014/05/12 01:35:25 This strikes me as a bad state machine (perhaps in
byungchul 2014/05/12 18:25:23 These code here and below are imported from ssl_se
+}
+
+void SSLServerSocketOpenSSL::OnRecvComplete(int result) {
+ if (next_handshake_state_ == STATE_HANDSHAKE) {
+ // In handshake phase.
+ OnHandshakeIOComplete(result);
+ return;
+ }
+
+ // Network layer received some data, check if client requested to read
+ // decrypted data.
+ if (!user_read_buf_.get() || !completed_handshake_)
+ return;
+
+ int rv = DoReadLoop(result);
+ if (rv != ERR_IO_PENDING)
+ DoReadCallback(rv);
+}
+
+void SSLServerSocketOpenSSL::OnHandshakeIOComplete(int result) {
+ int rv = DoHandshakeLoop(result);
+ if (rv != ERR_IO_PENDING) {
Ryan Sleevi 2014/05/12 01:35:25 better to be if (rv == ERR_IO_PENDING) return n
byungchul 2014/05/12 18:25:23 Done.
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
+ if (!user_handshake_callback_.is_null())
+ DoHandshakeCallback(rv);
+ }
+}
+
+// Return 0 for EOF,
+// > 0 for bytes transferred immediately,
+// < 0 for error (or the non-error ERR_IO_PENDING).
+int SSLServerSocketOpenSSL::BufferSend() {
+ if (transport_send_busy_)
+ return ERR_IO_PENDING;
+
+ if (!send_buffer_.get()) {
+ // Get a fresh send buffer out of the send BIO.
+ size_t max_read = BIO_ctrl_pending(transport_bio_);
+ if (!max_read)
+ return 0; // Nothing pending in the OpenSSL write BIO.
+ send_buffer_ = new DrainableIOBuffer(new IOBuffer(max_read), max_read);
+ int read_bytes = BIO_read(transport_bio_, send_buffer_->data(), max_read);
+ DCHECK_GT(read_bytes, 0);
+ CHECK_EQ(static_cast<int>(max_read), read_bytes);
+ }
+
+ int rv = transport_socket_->Write(
+ send_buffer_.get(),
+ send_buffer_->BytesRemaining(),
+ base::Bind(&SSLServerSocketOpenSSL::BufferSendComplete,
+ base::Unretained(this)));
+ if (rv == ERR_IO_PENDING) {
+ transport_send_busy_ = true;
+ } else {
+ TransportWriteComplete(rv);
+ }
+ return rv;
+}
+
+void SSLServerSocketOpenSSL::BufferSendComplete(int result) {
+ transport_send_busy_ = false;
+ TransportWriteComplete(result);
+ OnSendComplete(result);
+}
+
+void SSLServerSocketOpenSSL::TransportWriteComplete(int result) {
+ DCHECK(ERR_IO_PENDING != result);
+ if (result < 0) {
+ // Got a socket write error; close the BIO to indicate this upward.
+ //
+ // TODO(davidben): The value of |result| gets lost. Feed the error back into
+ // the BIO so it gets (re-)detected in OnSendComplete. Perhaps with
+ // BIO_set_callback.
+ DVLOG(1) << "TransportWriteComplete error " << result;
+ (void)BIO_shutdown_wr(SSL_get_wbio(ssl_));
+
+ // Match the fix for http://crbug.com/249848 in NSS by erroring future reads
+ // from the socket after a write error.
+ //
+ // TODO(davidben): Avoid having read and write ends interact this way.
+ transport_write_error_ = result;
+ (void)BIO_shutdown_wr(transport_bio_);
+ send_buffer_ = NULL;
+ } else {
+ DCHECK(send_buffer_.get());
+ send_buffer_->DidConsume(result);
+ DCHECK_GE(send_buffer_->BytesRemaining(), 0);
+ if (send_buffer_->BytesRemaining() <= 0)
+ send_buffer_ = NULL;
+ }
+}
+
+int SSLServerSocketOpenSSL::BufferRecv() {
+ if (transport_recv_busy_)
+ return ERR_IO_PENDING;
+
+ // Determine how much was requested from |transport_bio_| that was not
+ // actually available.
+ size_t requested = BIO_ctrl_get_read_request(transport_bio_);
+ if (requested == 0) {
+ // This is not a perfect match of error codes, as no operation is
+ // actually pending. However, returning 0 would be interpreted as
+ // a possible sign of EOF, which is also an inappropriate match.
+ return ERR_IO_PENDING;
+ }
+
+ // Known Issue: While only reading |requested| data is the more correct
+ // implementation, it has the downside of resulting in frequent reads:
+ // One read for the SSL record header (~5 bytes) and one read for the SSL
+ // record body. Rather than issuing these reads to the underlying socket
+ // (and constantly allocating new IOBuffers), a single Read() request to
+ // fill |transport_bio_| is issued. As long as an SSL client socket cannot
+ // be gracefully shutdown (via SSL close alerts) and re-used for non-SSL
+ // traffic, this over-subscribed Read()ing will not cause issues.
+ size_t max_write = BIO_ctrl_get_write_guarantee(transport_bio_);
+ if (!max_write)
+ return ERR_IO_PENDING;
+
+ recv_buffer_ = new IOBuffer(max_write);
+ int rv = transport_socket_->Read(
+ recv_buffer_.get(),
+ max_write,
+ base::Bind(&SSLServerSocketOpenSSL::BufferRecvComplete,
+ base::Unretained(this)));
+ if (rv == ERR_IO_PENDING) {
+ transport_recv_busy_ = true;
+ } else {
+ rv = TransportReadComplete(rv);
+ }
+ return rv;
+}
+
+void SSLServerSocketOpenSSL::BufferRecvComplete(int result) {
+ result = TransportReadComplete(result);
+ OnRecvComplete(result);
+}
+
+int SSLServerSocketOpenSSL::TransportReadComplete(int result) {
+ DCHECK(ERR_IO_PENDING != result);
+ if (result <= 0) {
+ DVLOG(1) << "TransportReadComplete result " << result;
+ // Received 0 (end of file) or an error. Either way, bubble it up to the
+ // SSL layer via the BIO. TODO(joth): consider stashing the error code, to
+ // relay up to the SSL socket client (i.e. via DoReadCallback).
+ if (result == 0)
+ transport_recv_eof_ = true;
+ (void)BIO_shutdown_wr(transport_bio_);
+ } else if (transport_write_error_ < 0) {
+ // Mirror transport write errors as read failures; transport_bio_ has been
+ // shut down by TransportWriteComplete, so the BIO_write will fail, failing
+ // the CHECK. http://crbug.com/335557.
+ result = transport_write_error_;
+ } else {
+ DCHECK(recv_buffer_.get());
+ int ret = BIO_write(transport_bio_, recv_buffer_->data(), result);
+ // A write into a memory BIO should always succeed.
+ // Force values on the stack for http://crbug.com/335557
+ base::debug::Alias(&result);
+ base::debug::Alias(&ret);
+ CHECK_EQ(result, ret);
Ryan Sleevi 2014/05/12 01:35:25 crbug.com/335557 was resolved. This code should be
byungchul 2014/05/12 18:25:23 Done.
+ }
+ recv_buffer_ = NULL;
+ transport_recv_busy_ = false;
+ return result;
+}
+
+// Do as much network I/O as possible between the buffer and the
+// transport socket. Return true if some I/O performed, false
+// otherwise (error or ERR_IO_PENDING).
+bool SSLServerSocketOpenSSL::DoTransportIO() {
+ bool network_moved = false;
+ int rv;
+ // Read and write as much data as possible. The loop is necessary because
+ // Write() may return synchronously.
+ do {
+ rv = BufferSend();
+ if (rv != ERR_IO_PENDING && rv != 0)
+ network_moved = true;
+ } while (rv > 0);
+ if (!transport_recv_eof_ && BufferRecv() != ERR_IO_PENDING)
+ network_moved = true;
+ return network_moved;
+}
+
+int SSLServerSocketOpenSSL::DoPayloadRead() {
+ DCHECK(user_read_buf_.get());
+ DCHECK_GT(user_read_buf_len_, 0);
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ int rv = SSL_read(ssl_, user_read_buf_->data(), user_read_buf_len_);
+ if (rv >= 0)
+ return rv;
+ int ssl_error = SSL_get_error(ssl_, rv);
+ int net_error = MapOpenSSLError(ssl_error, err_tracer);
+ if (net_error != ERR_IO_PENDING) {
+ net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
+ CreateNetLogSSLErrorCallback(net_error, ssl_error));
+ }
+ return net_error;
+}
+
+int SSLServerSocketOpenSSL::DoPayloadWrite() {
+ DCHECK(user_write_buf_.get());
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_);
+ if (rv >= 0)
+ return rv;
+ int ssl_error = SSL_get_error(ssl_, rv);
+ int net_error = MapOpenSSLError(ssl_error, err_tracer);
+ if (net_error != ERR_IO_PENDING) {
+ net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
+ CreateNetLogSSLErrorCallback(net_error, ssl_error));
+ }
+ return net_error;
+}
+
+int SSLServerSocketOpenSSL::DoHandshakeLoop(int last_io_result) {
+ int rv = last_io_result;
+ do {
+ // Default to STATE_NONE for next state.
+ // (This is a quirk carried over from the windows
+ // implementation. It makes reading the logs a bit harder.)
+ // State handlers can and often do call GotoState just
+ // to stay in the current state.
+ State state = next_handshake_state_;
+ GotoState(STATE_NONE);
+ switch (state) {
+ case STATE_HANDSHAKE:
+ rv = DoHandshake();
+ break;
+ case STATE_NONE:
+ default:
+ rv = ERR_UNEXPECTED;
+ LOG(DFATAL) << "unexpected state " << state;
+ break;
+ }
+
+ // Do the actual network I/O
+ bool network_moved = DoTransportIO();
+ if (network_moved && next_handshake_state_ == STATE_HANDSHAKE) {
+ // In general we exit the loop if rv is ERR_IO_PENDING. In this
+ // special case we keep looping even if rv is ERR_IO_PENDING because
+ // the transport IO may allow DoHandshake to make progress.
+ rv = OK; // This causes us to stay in the loop.
+ }
+ } while (rv != ERR_IO_PENDING && next_handshake_state_ != STATE_NONE);
+ return rv;
+}
+
+int SSLServerSocketOpenSSL::DoReadLoop(int result) {
+ DCHECK(completed_handshake_);
+ DCHECK(next_handshake_state_ == STATE_NONE);
+
+ if (result < 0)
+ return result;
+
+ bool network_moved;
+ int rv;
+ do {
+ rv = DoPayloadRead();
+ network_moved = DoTransportIO();
+ } while (rv == ERR_IO_PENDING && network_moved);
+ return rv;
+}
+
+int SSLServerSocketOpenSSL::DoWriteLoop(int result) {
+ DCHECK(completed_handshake_);
+ DCHECK(next_handshake_state_ == STATE_NONE);
Ryan Sleevi 2014/05/12 01:35:25 DCHECK_EQ
byungchul 2014/05/12 18:25:23 Done.
+
+ if (result < 0)
+ return result;
+
+ bool network_moved;
+ int rv;
+ do {
+ rv = DoPayloadWrite();
+ network_moved = DoTransportIO();
+ } while (rv == ERR_IO_PENDING && network_moved);
+ return rv;
+}
+
+int SSLServerSocketOpenSSL::DoHandshake() {
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ int net_error = net::OK;
+ int rv = SSL_do_handshake(ssl_);
+
+ if (rv == 1) {
+ completed_handshake_ = true;
+ } else {
+ int ssl_error = SSL_get_error(ssl_, rv);
+ net_error = MapOpenSSLError(ssl_error, err_tracer);
+
+ // If not done, stay in this state
+ if (net_error == ERR_IO_PENDING) {
+ GotoState(STATE_HANDSHAKE);
+ } else {
+ LOG(ERROR) << "handshake failed; returned " << rv
+ << ", SSL error code " << ssl_error
+ << ", net_error " << net_error;
+ net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
+ CreateNetLogSSLErrorCallback(net_error, ssl_error));
+ }
+ }
+ return net_error;
+}
+
+void SSLServerSocketOpenSSL::DoHandshakeCallback(int rv) {
+ DCHECK_NE(rv, ERR_IO_PENDING);
+
+ CompletionCallback c = user_handshake_callback_;
+ user_handshake_callback_.Reset();
+ c.Run(rv > OK ? OK : rv);
Ryan Sleevi 2014/05/12 01:35:25 Use base::ResetAndReturn() here (base/callback_hel
byungchul 2014/05/12 18:25:23 Done.
+}
+
+void SSLServerSocketOpenSSL::DoReadCallback(int rv) {
+ DCHECK(rv != ERR_IO_PENDING);
+ DCHECK(!user_read_callback_.is_null());
+
+ // Since Run may result in Read being called, clear |user_read_callback_|
+ // up front.
+ CompletionCallback c = user_read_callback_;
+ user_read_callback_.Reset();
+ user_read_buf_ = NULL;
+ user_read_buf_len_ = 0;
+ c.Run(rv);
Ryan Sleevi 2014/05/12 01:35:25 base::ResetAndReturn here
byungchul 2014/05/12 18:25:23 Done.
+}
+
+void SSLServerSocketOpenSSL::DoWriteCallback(int rv) {
+ DCHECK(rv != ERR_IO_PENDING);
+ DCHECK(!user_write_callback_.is_null());
+
+ // Since Run may result in Write being called, clear |user_write_callback_|
+ // up front.
+ CompletionCallback c = user_write_callback_;
+ user_write_callback_.Reset();
+ user_write_buf_ = NULL;
+ user_write_buf_len_ = 0;
+ c.Run(rv);
Ryan Sleevi 2014/05/12 01:35:25 base::ResetAndReturn here
byungchul 2014/05/12 18:25:23 Done.
+}
+
+bool SSLServerSocketOpenSSL::Init() {
+ DCHECK(!ssl_);
+ DCHECK(!transport_bio_);
+
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+
+ crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx(
+ // It support SSLv2, SSLv3, and TLSv1.
+ SSL_CTX_new(SSLv23_server_method()));
+ ssl_ = SSL_new(ssl_ctx.get());
+ if (!ssl_)
+ return false;
+
+ BIO* ssl_bio = NULL;
+ // 0 => use default buffer sizes.
+ if (!BIO_new_bio_pair(&ssl_bio, 0, &transport_bio_, 0))
+ return false;
+ DCHECK(ssl_bio);
+ DCHECK(transport_bio_);
+
+ SSL_set_bio(ssl_, ssl_bio, ssl_bio);
+
+ // Set certificate and private key.
+ DCHECK(cert_->os_cert_handle());
+ if (SSL_use_certificate(ssl_, cert_->os_cert_handle()) != 1) {
+ LOG(ERROR) << "Cannot set certificate.";
+ return false;
+ }
+
+ DCHECK(key_->key());
+ if (SSL_use_PrivateKey(ssl_, key_->key()) != 1) {
+ LOG(ERROR) << "Cannot set private key.";
+ return false;
+ }
+
+ // OpenSSL defaults some options to on, others to off. To avoid ambiguity,
+ // set everything we care about to an absolute value.
+ SslSetClearMask options;
+ options.ConfigureFlag(SSL_OP_NO_SSLv2, true);
+ bool ssl3_enabled = (ssl_config_.version_min == SSL_PROTOCOL_VERSION_SSL3);
+ options.ConfigureFlag(SSL_OP_NO_SSLv3, !ssl3_enabled);
+ bool tls1_enabled = (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1 &&
+ ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1);
+ options.ConfigureFlag(SSL_OP_NO_TLSv1, !tls1_enabled);
+ bool tls1_1_enabled =
+ (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1_1 &&
+ ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1_1);
+ options.ConfigureFlag(SSL_OP_NO_TLSv1_1, !tls1_1_enabled);
+ bool tls1_2_enabled =
+ (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1_2 &&
+ ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1_2);
+ options.ConfigureFlag(SSL_OP_NO_TLSv1_2, !tls1_2_enabled);
+
+ options.ConfigureFlag(SSL_OP_NO_COMPRESSION, true);
+
+ SSL_set_options(ssl_, options.set_mask);
+ SSL_clear_options(ssl_, options.clear_mask);
+
+ // Same as above, this time for the SSL mode.
+ SslSetClearMask mode;
+
+ mode.ConfigureFlag(SSL_MODE_RELEASE_BUFFERS, true);
+
+ SSL_set_mode(ssl_, mode.set_mask);
+ SSL_clear_mode(ssl_, mode.clear_mask);
+
+ return true;
}
} // namespace net

Powered by Google App Engine
This is Rietveld 408576698