// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef NET_SOCKET_SSL_CLIENT_SOCKET_NSS_H_ #define NET_SOCKET_SSL_CLIENT_SOCKET_NSS_H_ #pragma once #include <certt.h> #include <keyt.h> #include <nspr.h> #include <nss.h> #include <string> #include <vector> #include "base/memory/scoped_ptr.h" #include "base/synchronization/lock.h" #include "base/threading/platform_thread.h" #include "base/time.h" #include "base/timer.h" #include "net/base/cert_verify_result.h" #include "net/base/completion_callback.h" #include "net/base/host_port_pair.h" #include "net/base/net_log.h" #include "net/base/nss_memio.h" #include "net/base/ssl_config_service.h" #include "net/base/x509_certificate.h" #include "net/socket/ssl_client_socket.h" namespace net { class BoundNetLog; class CertVerifier; class ClientSocketHandle; class DnsCertProvenanceChecker; class SingleRequestCertVerifier; class SSLHostInfo; class X509Certificate; // An SSL client socket implemented with Mozilla NSS. class SSLClientSocketNSS : public SSLClientSocket { public: // Takes ownership of the |transport_socket|, which must already be connected. // The hostname specified in |host_and_port| will be compared with the name(s) // in the server's certificate during the SSL handshake. If SSL client // authentication is requested, the host_and_port field of SSLCertRequestInfo // will be populated with |host_and_port|. |ssl_config| specifies // the SSL settings. SSLClientSocketNSS(ClientSocketHandle* transport_socket, const HostPortPair& host_and_port, const SSLConfig& ssl_config, SSLHostInfo* ssl_host_info, CertVerifier* cert_verifier, DnsCertProvenanceChecker* dnsrr_resolver); ~SSLClientSocketNSS(); // For tests static void ClearSessionCache(); // SSLClientSocket methods: virtual void GetSSLInfo(SSLInfo* ssl_info); virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); virtual NextProtoStatus GetNextProto(std::string* proto); virtual void UseDNSSEC(DNSSECProvider* provider); // ClientSocket methods: virtual int Connect(CompletionCallback* callback #ifdef ANDROID , bool wait_for_connect #endif ); virtual void Disconnect(); virtual bool IsConnected() const; virtual bool IsConnectedAndIdle() const; virtual int GetPeerAddress(AddressList* address) const; virtual int GetLocalAddress(IPEndPoint* address) const; virtual const BoundNetLog& NetLog() const; virtual void SetSubresourceSpeculation(); virtual void SetOmniboxSpeculation(); virtual bool WasEverUsed() const; virtual bool UsingTCPFastOpen() const; // Socket methods: virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback); virtual int Write(IOBuffer* buf, int buf_len, CompletionCallback* callback); virtual bool SetReceiveBufferSize(int32 size); virtual bool SetSendBufferSize(int32 size); private: enum State { STATE_NONE, STATE_HANDSHAKE, STATE_VERIFY_DNSSEC, STATE_VERIFY_DNSSEC_COMPLETE, STATE_VERIFY_CERT, STATE_VERIFY_CERT_COMPLETE, }; int Init(); // Initializes NSS SSL options. Returns a net error code. int InitializeSSLOptions(); // Initializes the socket peer name in SSL. Returns a net error code. int InitializeSSLPeerName(); #if defined(OS_MACOSX) || defined(OS_WIN) // Creates an OS certificate from a DER-encoded certificate. static X509Certificate::OSCertHandle CreateOSCert(const SECItem& der_cert); #endif X509Certificate* UpdateServerCert(); void UpdateConnectionStatus(); void DoReadCallback(int result); void DoWriteCallback(int result); void DoConnectCallback(int result); void OnHandshakeIOComplete(int result); void OnSendComplete(int result); void OnRecvComplete(int result); int DoHandshakeLoop(int last_io_result); int DoReadLoop(int result); int DoWriteLoop(int result); int DoHandshake(); int DoVerifyDNSSEC(int result); int DoVerifyDNSSECComplete(int result); int DoVerifyCert(int result); int DoVerifyCertComplete(int result); int DoPayloadRead(); int DoPayloadWrite(); void LogConnectionTypeMetrics() const; void SaveSSLHostInfo(); void UncorkAfterTimeout(); bool DoTransportIO(); int BufferSend(void); void BufferSendComplete(int result); int BufferRecv(void); void BufferRecvComplete(int result); // Handles an NSS error generated while handshaking or performing IO. // Returns a network error code mapped from the original NSS error. int HandleNSSError(PRErrorCode error, bool handshake_error); // NSS calls this when checking certificates. We pass 'this' as the first // argument. static SECStatus OwnAuthCertHandler(void* arg, PRFileDesc* socket, PRBool checksig, PRBool is_server); // NSS calls this when client authentication is requested. #if defined(NSS_PLATFORM_CLIENT_AUTH) static SECStatus PlatformClientAuthHandler(void* arg, PRFileDesc* socket, CERTDistNames* ca_names, CERTCertList** result_certs, void** result_private_key); #else static SECStatus ClientAuthHandler(void* arg, PRFileDesc* socket, CERTDistNames* ca_names, CERTCertificate** result_certificate, SECKEYPrivateKey** result_private_key); #endif // NSS calls this when handshake is completed. We pass 'this' as the second // argument. static void HandshakeCallback(PRFileDesc* socket, void* arg); // The following methods are for debugging bug 65948. Will remove this code // after fixing bug 65948. void EnsureThreadIdAssigned() const; bool CalledOnValidThread() const; CompletionCallbackImpl<SSLClientSocketNSS> buffer_send_callback_; CompletionCallbackImpl<SSLClientSocketNSS> buffer_recv_callback_; bool transport_send_busy_; bool transport_recv_busy_; // corked_ is true if we are currently suspending writes to the network. This // is named after the similar kernel flag, TCP_CORK. bool corked_; // uncork_timer_ is used to limit the amount of time that we'll delay the // Finished message while waiting for a Write. base::OneShotTimer<SSLClientSocketNSS> uncork_timer_; scoped_refptr<IOBuffer> recv_buffer_; CompletionCallbackImpl<SSLClientSocketNSS> handshake_io_callback_; scoped_ptr<ClientSocketHandle> transport_; HostPortPair host_and_port_; SSLConfig ssl_config_; CompletionCallback* user_connect_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_; // Set when handshake finishes. The server certificate is first received // from NSS as an NSS certificate handle (server_cert_nss_), and then // converted into an X509Certificate object (server_cert_). scoped_refptr<X509Certificate> server_cert_; CERTCertificate* server_cert_nss_; // |server_cert_verify_result_| points at the verification result, which may, // or may not be, |&local_server_cert_verify_result_|, depending on whether // we used an SSLHostInfo's verification. const CertVerifyResult* server_cert_verify_result_; CertVerifyResult local_server_cert_verify_result_; int ssl_connection_status_; // Stores client authentication information between ClientAuthHandler and // GetSSLCertRequestInfo calls. std::vector<scoped_refptr<X509Certificate> > client_certs_; bool client_auth_cert_needed_; CertVerifier* const cert_verifier_; scoped_ptr<SingleRequestCertVerifier> verifier_; // True if NSS has called HandshakeCallback. bool handshake_callback_called_; // True if the SSL handshake has been completed. bool completed_handshake_; // True iff we believe that the user has an ESET product intercepting our // HTTPS connections. bool eset_mitm_detected_; // True iff |ssl_host_info_| contained a predicted certificate chain and // that we found the prediction to be correct. bool predicted_cert_chain_correct_; // True if the peer name has been initialized. bool peername_initialized_; // This pointer is owned by the caller of UseDNSSEC. DNSSECProvider* dnssec_provider_; // The time when we started waiting for DNSSEC records. base::Time dnssec_wait_start_time_; State next_handshake_state_; // The NSS SSL state machine PRFileDesc* nss_fd_; // Buffers for the network end of the SSL state machine memio_Private* nss_bufs_; BoundNetLog net_log_; base::TimeTicks start_cert_verification_time_; scoped_ptr<SSLHostInfo> ssl_host_info_; DnsCertProvenanceChecker* const dns_cert_checker_; // The following two variables are added for debugging bug 65948. Will // remove this code after fixing bug 65948. // Added the following code Debugging in release mode. mutable base::Lock lock_; // This is mutable so that CalledOnValidThread can set it. // It's guarded by |lock_|. mutable base::PlatformThreadId valid_thread_id_; }; } // namespace net #endif // NET_SOCKET_SSL_CLIENT_SOCKET_NSS_H_