| 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..75a76da205b04ee514235352bb008d2c654de359 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,43 +51,142 @@ 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, 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_;
|
| +
|
| + // 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,
|
| - const crypto::RSAPrivateKey& key,
|
| - 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),
|
| - cert_(certificate),
|
| - key_(key.Copy()),
|
| next_handshake_state_(STATE_NONE),
|
| - completed_handshake_(false) {
|
| - CHECK(key_);
|
| -}
|
| + completed_handshake_(false) {}
|
|
|
| SSLServerSocketOpenSSL::~SSLServerSocketOpenSSL() {
|
| if (ssl_) {
|
| @@ -160,7 +258,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 +283,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 +477,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 +549,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 +779,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 +795,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) {
|
| + 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_server_config_(ssl_server_config),
|
| + cert_(certificate),
|
| + key_(key.Copy()) {
|
| + CHECK(key_);
|
| + crypto::EnsureOpenSSLInit();
|
| + ssl_ctx_.reset(SSL_CTX_new(TLS_method()));
|
| + 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()));
|
| #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()));
|
| #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()));
|
|
|
| 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 +930,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 +945,24 @@ 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) {
|
| + SSL* ssl = SSL_new(ssl_ctx_.get());
|
| + return scoped_ptr<SSLServerSocket>(
|
| + new SSLServerSocketOpenSSL(std::move(socket), ssl));
|
| +}
|
| +
|
| +void EnableSSLServerSockets() {
|
| + // No-op because CreateSSLServerSocket() calls crypto::EnsureOpenSSLInit().
|
| }
|
|
|
| } // namespace net
|
|
|