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 adde711e7ec9f2ff27bd2cfbfba16ea69e55aae9..393676fd3ba5b48eafba6f124cadb885b1ce3a11 100644 |
--- a/net/socket/ssl_server_socket_openssl.cc |
+++ b/net/socket/ssl_server_socket_openssl.cc |
@@ -19,7 +19,6 @@ |
#include "net/cert/client_cert_verifier.h" |
#include "net/cert/x509_util_openssl.h" |
#include "net/ssl/openssl_ssl_util.h" |
-#include "net/ssl/scoped_openssl_types.h" |
#include "net/ssl/ssl_connection_status_flags.h" |
#include "net/ssl/ssl_info.h" |
@@ -52,34 +51,154 @@ scoped_refptr<X509Certificate> CreateX509Certificate(X509* cert, |
return X509Certificate::CreateFromDERCertChain(der_chain); |
} |
-} // namespace |
- |
-void EnableSSLServerSockets() { |
- // No-op because CreateSSLServerSocket() calls crypto::EnsureOpenSSLInit(). |
-} |
- |
-scoped_ptr<SSLServerSocket> CreateSSLServerSocket( |
- scoped_ptr<StreamSocket> socket, |
- X509Certificate* certificate, |
- const crypto::RSAPrivateKey& key, |
- const SSLServerConfig& ssl_server_config) { |
- crypto::EnsureOpenSSLInit(); |
- return scoped_ptr<SSLServerSocket>(new SSLServerSocketOpenSSL( |
- std::move(socket), certificate, key, ssl_server_config)); |
-} |
+class SSLServerSocketOpenSSL : public SSLServerSocket { |
+ public: |
+ // See comments on CreateSSLServerSocket for details of how these |
+ // parameters are used. |
+ SSLServerSocketOpenSSL(scoped_ptr<StreamSocket> socket, |
+ X509Certificate* certificate, |
+ const crypto::RSAPrivateKey& key, |
+ const SSLServerConfig& ssl_server_config, |
+ SSL* ssl); |
+ ~SSLServerSocketOpenSSL() override; |
+ |
+ // SSLServerSocket interface. |
+ int Handshake(const CompletionCallback& callback) override; |
+ |
+ // SSLSocket interface. |
+ int ExportKeyingMaterial(const base::StringPiece& label, |
+ bool has_context, |
+ const base::StringPiece& context, |
+ unsigned char* out, |
+ unsigned int outlen) override; |
+ int GetTLSUniqueChannelBinding(std::string* out) override; |
+ |
+ // Socket interface (via StreamSocket). |
+ int Read(IOBuffer* buf, |
+ int buf_len, |
+ const CompletionCallback& callback) override; |
+ int Write(IOBuffer* buf, |
+ int buf_len, |
+ const CompletionCallback& callback) override; |
+ int SetReceiveBufferSize(int32_t size) override; |
+ int SetSendBufferSize(int32_t size) override; |
+ |
+ // StreamSocket implementation. |
+ int Connect(const CompletionCallback& callback) override; |
+ void Disconnect() override; |
+ bool IsConnected() const override; |
+ bool IsConnectedAndIdle() const override; |
+ int GetPeerAddress(IPEndPoint* address) const override; |
+ int GetLocalAddress(IPEndPoint* address) const override; |
+ const BoundNetLog& NetLog() const override; |
+ void SetSubresourceSpeculation() override; |
+ void SetOmniboxSpeculation() override; |
+ bool WasEverUsed() const override; |
+ bool UsingTCPFastOpen() const override; |
+ bool WasNpnNegotiated() const override; |
+ NextProto GetNegotiatedProtocol() const override; |
+ bool GetSSLInfo(SSLInfo* ssl_info) override; |
+ void GetConnectionAttempts(ConnectionAttempts* out) const override; |
+ void ClearConnectionAttempts() override {} |
+ void AddConnectionAttempts(const ConnectionAttempts& attempts) override {} |
+ int64_t GetTotalReceivedBytes() const override; |
+ static int CertVerifyCallback(X509_STORE_CTX* store_ctx, void* arg); |
+ |
+ private: |
+ enum State { |
+ STATE_NONE, |
+ STATE_HANDSHAKE, |
+ }; |
+ |
+ void OnSendComplete(int result); |
+ void OnRecvComplete(int result); |
+ void OnHandshakeIOComplete(int result); |
+ |
+ int BufferSend(); |
+ void BufferSendComplete(int result); |
+ void TransportWriteComplete(int result); |
+ int BufferRecv(); |
+ void BufferRecvComplete(int result); |
+ int TransportReadComplete(int result); |
+ bool DoTransportIO(); |
+ int DoPayloadRead(); |
+ int DoPayloadWrite(); |
+ |
+ int DoHandshakeLoop(int last_io_result); |
+ int DoReadLoop(int result); |
+ int DoWriteLoop(int result); |
+ int DoHandshake(); |
+ void DoHandshakeCallback(int result); |
+ void DoReadCallback(int result); |
+ void DoWriteCallback(int result); |
+ |
+ int Init(); |
+ void ExtractClientCert(); |
+ |
+ // Members used to send and receive buffer. |
+ bool transport_send_busy_; |
+ bool transport_recv_busy_; |
+ bool transport_recv_eof_; |
+ |
+ scoped_refptr<DrainableIOBuffer> send_buffer_; |
+ scoped_refptr<IOBuffer> recv_buffer_; |
+ |
+ BoundNetLog net_log_; |
+ |
+ CompletionCallback user_handshake_callback_; |
+ CompletionCallback user_read_callback_; |
+ CompletionCallback user_write_callback_; |
+ |
+ // Used by Read function. |
+ scoped_refptr<IOBuffer> user_read_buf_; |
+ int user_read_buf_len_; |
+ |
+ // Used by Write function. |
+ scoped_refptr<IOBuffer> user_write_buf_; |
+ int user_write_buf_len_; |
+ |
+ // Used by TransportWriteComplete() and TransportReadComplete() to signify an |
+ // error writing to the transport socket. A value of OK indicates no error. |
+ int transport_write_error_; |
+ |
+ // OpenSSL stuff |
+ SSL* ssl_; |
+ BIO* transport_bio_; |
+ |
+ // StreamSocket for sending and receiving data. |
+ scoped_ptr<StreamSocket> transport_socket_; |
+ |
+ // Options for the SSL socket. |
+ SSLServerConfig ssl_server_config_; |
davidben
2016/02/24 21:01:25
I'm not sure this is actually used.
ryanchung
2016/02/25 00:46:39
Done.
|
+ |
+ // Certificate for the server. |
+ scoped_refptr<X509Certificate> cert_; |
davidben
2016/02/24 21:01:26
Ditto.
ryanchung
2016/02/25 00:46:39
Done.
|
+ |
+ // Private key used by the server. |
+ scoped_ptr<crypto::RSAPrivateKey> key_; |
davidben
2016/02/24 21:01:26
Ditto.
ryanchung
2016/02/25 00:46:39
Done.
|
+ |
+ // Certificate for the client. |
+ scoped_refptr<X509Certificate> client_cert_; |
+ |
+ State next_handshake_state_; |
+ bool completed_handshake_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SSLServerSocketOpenSSL); |
+}; |
SSLServerSocketOpenSSL::SSLServerSocketOpenSSL( |
scoped_ptr<StreamSocket> transport_socket, |
- scoped_refptr<X509Certificate> certificate, |
+ X509Certificate* certificate, |
const crypto::RSAPrivateKey& key, |
- const SSLServerConfig& ssl_server_config) |
+ const SSLServerConfig& ssl_server_config, |
+ SSL* ssl) |
: 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), |
+ ssl_(ssl), |
transport_bio_(NULL), |
transport_socket_(std::move(transport_socket)), |
ssl_server_config_(ssl_server_config), |
@@ -160,7 +279,8 @@ int SSLServerSocketOpenSSL::GetTLSUniqueChannelBinding(std::string* out) { |
return ERR_NOT_IMPLEMENTED; |
} |
-int SSLServerSocketOpenSSL::Read(IOBuffer* buf, int buf_len, |
+int SSLServerSocketOpenSSL::Read(IOBuffer* buf, |
+ int buf_len, |
const CompletionCallback& callback) { |
DCHECK(user_read_callback_.is_null()); |
DCHECK(user_handshake_callback_.is_null()); |
@@ -184,7 +304,8 @@ int SSLServerSocketOpenSSL::Read(IOBuffer* buf, int buf_len, |
return rv; |
} |
-int SSLServerSocketOpenSSL::Write(IOBuffer* buf, int buf_len, |
+int SSLServerSocketOpenSSL::Write(IOBuffer* buf, |
+ int buf_len, |
const CompletionCallback& callback) { |
DCHECK(user_write_callback_.is_null()); |
DCHECK(!user_write_buf_); |
@@ -377,8 +498,7 @@ int SSLServerSocketOpenSSL::BufferSend() { |
} |
int rv = transport_socket_->Write( |
- send_buffer_.get(), |
- send_buffer_->BytesRemaining(), |
+ send_buffer_.get(), send_buffer_->BytesRemaining(), |
base::Bind(&SSLServerSocketOpenSSL::BufferSendComplete, |
base::Unretained(this))); |
if (rv == ERR_IO_PENDING) { |
@@ -450,8 +570,7 @@ int SSLServerSocketOpenSSL::BufferRecv() { |
recv_buffer_ = new IOBuffer(max_write); |
int rv = transport_socket_->Read( |
- recv_buffer_.get(), |
- max_write, |
+ recv_buffer_.get(), max_write, |
base::Bind(&SSLServerSocketOpenSSL::BufferRecvComplete, |
base::Unretained(this))); |
if (rv == ERR_IO_PENDING) { |
@@ -681,27 +800,10 @@ void SSLServerSocketOpenSSL::DoWriteCallback(int rv) { |
} |
int SSLServerSocketOpenSSL::Init() { |
- DCHECK(!ssl_); |
DCHECK(!transport_bio_); |
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
- ScopedSSL_CTX ssl_ctx(SSL_CTX_new(TLS_method())); |
- int verify_mode = 0; |
- switch (ssl_server_config_.client_cert_type) { |
- case SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT: |
- verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
- // Fall-through |
- case SSLServerConfig::ClientCertType::OPTIONAL_CLIENT_CERT: |
- verify_mode |= SSL_VERIFY_PEER; |
- SSL_CTX_set_verify(ssl_ctx.get(), verify_mode, nullptr); |
- SSL_CTX_set_cert_verify_callback(ssl_ctx.get(), CertVerifyCallback, |
- ssl_server_config_.client_cert_verifier); |
- break; |
- case SSLServerConfig::ClientCertType::NO_CLIENT_CERT: |
- break; |
- } |
- ssl_ = SSL_new(ssl_ctx.get()); |
if (!ssl_) |
return ERR_UNEXPECTED; |
@@ -714,59 +816,122 @@ int SSLServerSocketOpenSSL::Init() { |
SSL_set_bio(ssl_, ssl_bio, ssl_bio); |
+ return OK; |
+} |
+ |
+// static |
+int SSLServerSocketOpenSSL::CertVerifyCallback(X509_STORE_CTX* store_ctx, |
+ void* arg) { |
+ ClientCertVerifier* verifier = reinterpret_cast<ClientCertVerifier*>(arg); |
+ // If a verifier was not supplied, all certificates are accepted. |
+ if (!verifier) |
+ return 1; |
+ STACK_OF(X509)* chain = store_ctx->untrusted; |
+ scoped_refptr<X509Certificate> client_cert( |
+ CreateX509Certificate(nullptr, chain)); |
+ if (!client_cert.get()) { |
+ X509_STORE_CTX_set_error(store_ctx, X509_V_ERR_CERT_REJECTED); |
+ return 0; |
+ } |
+ // Asynchronous completion of Verify is currently not supported. |
+ // http://crbug.com/347402 |
+ // The API for Verify supports the parts needed for async completion |
+ // but is currently expected to complete synchronously. |
+ scoped_ptr<ClientCertVerifier::Request> ignore_async; |
+ int res = |
+ verifier->Verify(client_cert.get(), CompletionCallback(), &ignore_async); |
+ DCHECK_NE(res, ERR_IO_PENDING); |
+ |
+ if (res != OK) { |
+ X509_STORE_CTX_set_error(store_ctx, X509_V_ERR_CERT_REJECTED); |
+ return 0; |
+ } |
+ return 1; |
+} |
+ |
+} // namespace |
+ |
+scoped_ptr<SSLServerContext> CreateSSLServerContext( |
+ X509Certificate* certificate, |
+ const crypto::RSAPrivateKey& key, |
+ const SSLServerConfig& ssl_server_config) { |
+ crypto::EnsureOpenSSLInit(); |
+ return scoped_ptr<SSLServerContext>( |
+ new SSLServerContextOpenSSL(certificate, key, ssl_server_config)); |
+} |
+ |
+SSLServerContextOpenSSL::SSLServerContextOpenSSL( |
+ X509Certificate* certificate, |
+ const crypto::RSAPrivateKey& key, |
+ const SSLServerConfig& ssl_server_config) |
+ : ssl_ctx_(SSL_CTX_new(TLS_method())), |
+ ssl_server_config_(ssl_server_config), |
+ cert_(certificate), |
+ key_(key.Copy()) { |
+ CHECK(key_); |
+ SSL_CTX_set_session_cache_mode(ssl_ctx_.get(), SSL_SESS_CACHE_SERVER); |
+ uint8_t session_ctx_id = 0; |
+ SSL_CTX_set_session_id_context(ssl_ctx_.get(), &session_ctx_id, |
+ sizeof(session_ctx_id)); |
+ |
+ int verify_mode = 0; |
+ switch (ssl_server_config_.client_cert_type) { |
+ case SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT: |
+ verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; |
+ // Fall-through |
+ case SSLServerConfig::ClientCertType::OPTIONAL_CLIENT_CERT: |
+ verify_mode |= SSL_VERIFY_PEER; |
+ SSL_CTX_set_verify(ssl_ctx_.get(), verify_mode, nullptr); |
+ SSL_CTX_set_cert_verify_callback( |
+ ssl_ctx_.get(), SSLServerSocketOpenSSL::CertVerifyCallback, |
+ ssl_server_config_.client_cert_verifier); |
+ break; |
+ case SSLServerConfig::ClientCertType::NO_CLIENT_CERT: |
+ break; |
+ } |
+ |
// Set certificate and private key. |
DCHECK(cert_->os_cert_handle()); |
#if defined(USE_OPENSSL_CERTS) |
- if (SSL_use_certificate(ssl_, cert_->os_cert_handle()) != 1) { |
- LOG(ERROR) << "Cannot set certificate."; |
- return ERR_UNEXPECTED; |
- } |
+ CHECK(SSL_CTX_use_certificate(ssl_ctx_.get(), cert_->os_cert_handle()) == 1); |
davidben
2016/02/24 21:01:26
Nit: The == 1 is a remnant of OpenSSL returning -1
ryanchung
2016/02/25 00:46:39
Done.
|
#else |
// Convert OSCertHandle to X509 structure. |
std::string der_string; |
- if (!X509Certificate::GetDEREncoded(cert_->os_cert_handle(), &der_string)) |
- return ERR_UNEXPECTED; |
+ CHECK(X509Certificate::GetDEREncoded(cert_->os_cert_handle(), &der_string)); |
const unsigned char* der_string_array = |
reinterpret_cast<const unsigned char*>(der_string.data()); |
ScopedX509 x509(d2i_X509(NULL, &der_string_array, der_string.length())); |
- if (!x509) |
- return ERR_UNEXPECTED; |
+ CHECK(x509); |
- // On success, SSL_use_certificate acquires a reference to |x509|. |
- if (SSL_use_certificate(ssl_, x509.get()) != 1) { |
- LOG(ERROR) << "Cannot set certificate."; |
- return ERR_UNEXPECTED; |
- } |
+ // On success, SSL_CTX_use_certificate acquires a reference to |x509|. |
+ CHECK(SSL_CTX_use_certificate(ssl_ctx_.get(), x509.get()) == 1); |
davidben
2016/02/24 21:01:25
Nit: ditto
ryanchung
2016/02/25 00:46:38
Done.
|
#endif // USE_OPENSSL_CERTS |
DCHECK(key_->key()); |
- if (SSL_use_PrivateKey(ssl_, key_->key()) != 1) { |
- LOG(ERROR) << "Cannot set private key."; |
- return ERR_UNEXPECTED; |
- } |
+ CHECK(SSL_CTX_use_PrivateKey(ssl_ctx_.get(), key_->key()) == 1); |
davidben
2016/02/24 21:01:26
Nit: ditto
ryanchung
2016/02/25 00:46:39
Done.
|
DCHECK_LT(SSL3_VERSION, ssl_server_config_.version_min); |
DCHECK_LT(SSL3_VERSION, ssl_server_config_.version_max); |
- SSL_set_min_version(ssl_, ssl_server_config_.version_min); |
- SSL_set_max_version(ssl_, ssl_server_config_.version_max); |
+ SSL_CTX_set_min_version(ssl_ctx_.get(), ssl_server_config_.version_min); |
+ SSL_CTX_set_max_version(ssl_ctx_.get(), ssl_server_config_.version_max); |
// 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_COMPRESSION, true); |
- SSL_set_options(ssl_, options.set_mask); |
- SSL_clear_options(ssl_, options.clear_mask); |
+ SSL_CTX_set_options(ssl_ctx_.get(), options.set_mask); |
+ SSL_CTX_clear_options(ssl_ctx_.get(), 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); |
+ SSL_CTX_set_mode(ssl_ctx_.get(), mode.set_mask); |
+ SSL_CTX_clear_mode(ssl_ctx_.get(), mode.clear_mask); |
// See SSLServerConfig::disabled_cipher_suites for description of the suites |
// disabled by default. Note that !SHA256 and !SHA384 only remove HMAC-SHA256 |
@@ -786,7 +951,7 @@ int SSLServerSocketOpenSSL::Init() { |
} |
} |
- int rv = SSL_set_cipher_list(ssl_, command.c_str()); |
+ int rv = SSL_CTX_set_cipher_list(ssl_ctx_.get(), command.c_str()); |
// If this fails (rv = 0) it means there are no ciphers enabled on this SSL. |
// This will almost certainly result in the socket failing to complete the |
// handshake at which point the appropriate error is bubbled up to the client. |
@@ -801,44 +966,25 @@ int SSLServerSocketOpenSSL::Init() { |
const uint8_t* name = reinterpret_cast<const uint8_t*>(authority.c_str()); |
const uint8_t* name_start = name; |
ScopedX509_NAME subj(d2i_X509_NAME(nullptr, &name, authority.length())); |
- if (!subj || name != name_start + authority.length()) |
- return ERR_UNEXPECTED; |
+ CHECK(subj && name == name_start + authority.length()); |
sk_X509_NAME_push(stack.get(), subj.release()); |
} |
- SSL_set_client_CA_list(ssl_, stack.release()); |
+ SSL_CTX_set_client_CA_list(ssl_ctx_.get(), stack.release()); |
} |
- |
- return OK; |
} |
-// static |
-int SSLServerSocketOpenSSL::CertVerifyCallback(X509_STORE_CTX* store_ctx, |
- void* arg) { |
- ClientCertVerifier* verifier = reinterpret_cast<ClientCertVerifier*>(arg); |
- // If a verifier was not supplied, all certificates are accepted. |
- if (!verifier) |
- return 1; |
- STACK_OF(X509)* chain = store_ctx->untrusted; |
- scoped_refptr<X509Certificate> client_cert( |
- CreateX509Certificate(nullptr, chain)); |
- if (!client_cert.get()) { |
- X509_STORE_CTX_set_error(store_ctx, X509_V_ERR_CERT_REJECTED); |
- return 0; |
- } |
- // Asynchronous completion of Verify is currently not supported. |
- // http://crbug.com/347402 |
- // The API for Verify supports the parts needed for async completion |
- // but is currently expected to complete synchronously. |
- scoped_ptr<ClientCertVerifier::Request> ignore_async; |
- int res = |
- verifier->Verify(client_cert.get(), CompletionCallback(), &ignore_async); |
- DCHECK_NE(res, ERR_IO_PENDING); |
+SSLServerContextOpenSSL::~SSLServerContextOpenSSL() {} |
- if (res != OK) { |
- X509_STORE_CTX_set_error(store_ctx, X509_V_ERR_CERT_REJECTED); |
- return 0; |
- } |
- return 1; |
+scoped_ptr<SSLServerSocket> SSLServerContextOpenSSL::CreateSSLServerSocket( |
+ scoped_ptr<StreamSocket> socket) { |
+ crypto::EnsureOpenSSLInit(); |
davidben
2016/02/24 21:01:25
This needs to happen before the SSL_CTX_new call.
ryanchung
2016/02/25 00:46:39
Done.
Or alternately, can we just call EnsureOpenS
|
+ SSL* ssl = SSL_new(ssl_ctx_.get()); |
+ return scoped_ptr<SSLServerSocket>(new SSLServerSocketOpenSSL( |
+ std::move(socket), cert_.get(), *key_, ssl_server_config_, ssl)); |
davidben
2016/02/24 21:01:25
I think this comment is moot because we can just g
ryanchung
2016/02/25 00:46:39
Thanks!
|
+} |
+ |
+void EnableSSLServerSockets() { |
+ // No-op because CreateSSLServerSocket() calls crypto::EnsureOpenSSLInit(). |
} |
} // namespace net |