Chromium Code Reviews| 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 |