| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/socket/ssl_client_socket.h" |
| |
| #include <string> |
| |
| #include "base/logging.h" |
| #include "base/observer_list.h" |
| #include "net/socket/ssl_client_socket_impl.h" |
| #include "net/socket/stream_socket.h" |
| #include "net/ssl/ssl_client_session_cache.h" |
| #include "net/ssl/ssl_key_logger.h" |
| |
| namespace net { |
| |
| SSLClientSocket::SSLClientSocket() = default; |
| |
| // static |
| void SSLClientSocket::SetSSLKeyLogger(std::unique_ptr<SSLKeyLogger> logger) { |
| SSLClientSocketImpl::SetSSLKeyLogger(std::move(logger)); |
| } |
| |
| // static |
| std::vector<uint8_t> SSLClientSocket::SerializeNextProtos( |
| const NextProtoVector& next_protos) { |
| std::vector<uint8_t> wire_protos; |
| for (const NextProto next_proto : next_protos) { |
| const std::string proto = NextProtoToString(next_proto); |
| if (proto.size() > 255) { |
| LOG(WARNING) << "Ignoring overlong ALPN protocol: " << proto; |
| continue; |
| } |
| if (proto.size() == 0) { |
| LOG(WARNING) << "Ignoring empty ALPN protocol"; |
| continue; |
| } |
| wire_protos.push_back(proto.size()); |
| for (const char ch : proto) { |
| wire_protos.push_back(static_cast<uint8_t>(ch)); |
| } |
| } |
| |
| return wire_protos; |
| } |
| |
| SSLClientContext::SSLClientContext( |
| SSLConfigService* ssl_config_service, |
| CertVerifier* cert_verifier, |
| TransportSecurityState* transport_security_state, |
| CTPolicyEnforcer* ct_policy_enforcer, |
| SSLClientSessionCache* ssl_client_session_cache, |
| SCTAuditingDelegate* sct_auditing_delegate) |
| : ssl_config_service_(ssl_config_service), |
| cert_verifier_(cert_verifier), |
| transport_security_state_(transport_security_state), |
| ct_policy_enforcer_(ct_policy_enforcer), |
| ssl_client_session_cache_(ssl_client_session_cache), |
| sct_auditing_delegate_(sct_auditing_delegate) { |
| CHECK(cert_verifier_); |
| CHECK(transport_security_state_); |
| CHECK(ct_policy_enforcer_); |
| |
| if (ssl_config_service_) { |
| config_ = ssl_config_service_->GetSSLContextConfig(); |
| ssl_config_service_->AddObserver(this); |
| } |
| cert_verifier_->AddObserver(this); |
| CertDatabase::GetInstance()->AddObserver(this); |
| } |
| |
| SSLClientContext::~SSLClientContext() { |
| if (ssl_config_service_) { |
| ssl_config_service_->RemoveObserver(this); |
| } |
| cert_verifier_->RemoveObserver(this); |
| CertDatabase::GetInstance()->RemoveObserver(this); |
| } |
| |
| std::unique_ptr<SSLClientSocket> SSLClientContext::CreateSSLClientSocket( |
| std::unique_ptr<StreamSocket> stream_socket, |
| const HostPortPair& host_and_port, |
| const SSLConfig& ssl_config) { |
| return std::make_unique<SSLClientSocketImpl>(this, std::move(stream_socket), |
| host_and_port, ssl_config); |
| } |
| |
| bool SSLClientContext::GetClientCertificate( |
| const HostPortPair& server, |
| scoped_refptr<X509Certificate>* client_cert, |
| scoped_refptr<SSLPrivateKey>* private_key) { |
| return ssl_client_auth_cache_.Lookup(server, client_cert, private_key); |
| } |
| |
| void SSLClientContext::SetClientCertificate( |
| const HostPortPair& server, |
| scoped_refptr<X509Certificate> client_cert, |
| scoped_refptr<SSLPrivateKey> private_key) { |
| ssl_client_auth_cache_.Add(server, std::move(client_cert), |
| std::move(private_key)); |
| |
| if (ssl_client_session_cache_) { |
| // Session resumption bypasses client certificate negotiation, so flush all |
| // associated sessions when preferences change. |
| ssl_client_session_cache_->FlushForServer(server); |
| } |
| NotifySSLConfigForServerChanged(server); |
| } |
| |
| bool SSLClientContext::ClearClientCertificate(const HostPortPair& server) { |
| if (!ssl_client_auth_cache_.Remove(server)) { |
| return false; |
| } |
| |
| if (ssl_client_session_cache_) { |
| // Session resumption bypasses client certificate negotiation, so flush all |
| // associated sessions when preferences change. |
| ssl_client_session_cache_->FlushForServer(server); |
| } |
| NotifySSLConfigForServerChanged(server); |
| return true; |
| } |
| |
| void SSLClientContext::AddObserver(Observer* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void SSLClientContext::RemoveObserver(Observer* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| void SSLClientContext::OnSSLContextConfigChanged() { |
| // TODO(davidben): Should we flush |ssl_client_session_cache_| here? We flush |
| // the socket pools, but not the session cache. While BoringSSL-based servers |
| // never change version or cipher negotiation based on client-offered |
| // sessions, other servers do. |
| config_ = ssl_config_service_->GetSSLContextConfig(); |
| NotifySSLConfigChanged(SSLConfigChangeType::kSSLConfigChanged); |
| } |
| |
| void SSLClientContext::OnCertVerifierChanged() { |
| NotifySSLConfigChanged(SSLConfigChangeType::kCertVerifierChanged); |
| } |
| |
| void SSLClientContext::OnCertDBChanged() { |
| // Both the trust store and client certificate store may have changed. |
| ssl_client_auth_cache_.Clear(); |
| if (ssl_client_session_cache_) { |
| ssl_client_session_cache_->Flush(); |
| } |
| NotifySSLConfigChanged(SSLConfigChangeType::kCertDatabaseChanged); |
| } |
| |
| void SSLClientContext::NotifySSLConfigChanged(SSLConfigChangeType change_type) { |
| for (Observer& observer : observers_) { |
| observer.OnSSLConfigChanged(change_type); |
| } |
| } |
| |
| void SSLClientContext::NotifySSLConfigForServerChanged( |
| const HostPortPair& server) { |
| for (Observer& observer : observers_) { |
| observer.OnSSLConfigForServerChanged(server); |
| } |
| } |
| |
| } // namespace net |