// Copyright (c) 2006-2009 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_WIN_H_
#define NET_SOCKET_SSL_CLIENT_SOCKET_WIN_H_
#define SECURITY_WIN32 // Needs to be defined before including security.h
#include <windows.h>
#include <wincrypt.h>
#include <security.h>
#include <string>
#include "base/scoped_ptr.h"
#include "net/base/cert_verify_result.h"
#include "net/base/completion_callback.h"
#include "net/base/ssl_config_service.h"
#include "net/socket/ssl_client_socket.h"
namespace net {
class CertVerifier;
class LoadLog;
// An SSL client socket implemented with the Windows Schannel.
class SSLClientSocketWin : public SSLClientSocket {
public:
// Takes ownership of the transport_socket, which may already be connected.
// The given hostname will be compared with the name(s) in the server's
// certificate during the SSL handshake. ssl_config specifies the SSL
// settings.
SSLClientSocketWin(ClientSocket* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config);
~SSLClientSocketWin();
// SSLClientSocket methods:
virtual void GetSSLInfo(SSLInfo* ssl_info);
virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
virtual NextProtoStatus GetNextProto(std::string* proto);
// ClientSocket methods:
virtual int Connect(CompletionCallback* callback, LoadLog* load_log);
virtual void Disconnect();
virtual bool IsConnected() const;
virtual bool IsConnectedAndIdle() const;
virtual int GetPeerName(struct sockaddr* name, socklen_t* namelen);
// 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:
bool completed_handshake() const {
return next_state_ == STATE_COMPLETED_HANDSHAKE;
}
// Initializes the SSL options and security context. Returns a net error code.
int InitializeSSLContext();
void OnHandshakeIOComplete(int result);
void OnReadComplete(int result);
void OnWriteComplete(int result);
int DoLoop(int last_io_result);
int DoHandshakeRead();
int DoHandshakeReadComplete(int result);
int DoHandshakeWrite();
int DoHandshakeWriteComplete(int result);
int DoVerifyCert();
int DoVerifyCertComplete(int result);
int DoPayloadRead();
int DoPayloadReadComplete(int result);
int DoPayloadDecrypt();
int DoPayloadEncrypt();
int DoPayloadWrite();
int DoPayloadWriteComplete(int result);
int DoCompletedRenegotiation(int result);
int DidCallInitializeSecurityContext();
int DidCompleteHandshake();
void DidCompleteRenegotiation();
void LogConnectionTypeMetrics(bool success) const;
void FreeSendBuffer();
// Internal callbacks as async operations complete.
CompletionCallbackImpl<SSLClientSocketWin> handshake_io_callback_;
CompletionCallbackImpl<SSLClientSocketWin> read_callback_;
CompletionCallbackImpl<SSLClientSocketWin> write_callback_;
scoped_ptr<ClientSocket> transport_;
std::string hostname_;
SSLConfig ssl_config_;
// User function to callback when the Connect() completes.
CompletionCallback* user_connect_callback_;
// User function to callback when a Read() completes.
CompletionCallback* user_read_callback_;
scoped_refptr<IOBuffer> user_read_buf_;
int user_read_buf_len_;
// User function to callback when a Write() completes.
CompletionCallback* user_write_callback_;
scoped_refptr<IOBuffer> user_write_buf_;
int user_write_buf_len_;
// Used to Read and Write using transport_.
scoped_refptr<IOBuffer> transport_read_buf_;
scoped_refptr<IOBuffer> transport_write_buf_;
enum State {
STATE_NONE,
STATE_HANDSHAKE_READ,
STATE_HANDSHAKE_READ_COMPLETE,
STATE_HANDSHAKE_WRITE,
STATE_HANDSHAKE_WRITE_COMPLETE,
STATE_VERIFY_CERT,
STATE_VERIFY_CERT_COMPLETE,
STATE_COMPLETED_RENEGOTIATION,
STATE_COMPLETED_HANDSHAKE
// After the handshake, the socket remains
// in the STATE_COMPLETED_HANDSHAKE state,
// unless a renegotiate handshake occurs.
};
State next_state_;
SecPkgContext_StreamSizes stream_sizes_;
scoped_refptr<X509Certificate> server_cert_;
scoped_ptr<CertVerifier> verifier_;
CertVerifyResult server_cert_verify_result_;
CredHandle* creds_;
CtxtHandle ctxt_;
SecBuffer in_buffers_[2]; // Input buffers for InitializeSecurityContext.
SecBuffer send_buffer_; // Output buffer for InitializeSecurityContext.
SECURITY_STATUS isc_status_; // Return value of InitializeSecurityContext.
scoped_array<char> payload_send_buffer_;
int payload_send_buffer_len_;
int bytes_sent_;
// recv_buffer_ holds the received ciphertext. Since Schannel decrypts
// data in place, sometimes recv_buffer_ may contain decrypted plaintext and
// any undecrypted ciphertext. (Ciphertext is decrypted one full SSL record
// at a time.)
//
// If bytes_decrypted_ is 0, the received ciphertext is at the beginning of
// recv_buffer_, ready to be passed to DecryptMessage.
scoped_array<char> recv_buffer_;
char* decrypted_ptr_; // Points to the decrypted plaintext in recv_buffer_
int bytes_decrypted_; // The number of bytes of decrypted plaintext.
char* received_ptr_; // Points to the received ciphertext in recv_buffer_
int bytes_received_; // The number of bytes of received ciphertext.
// True if we're writing the first token (handshake message) to the server,
// false if we're writing a subsequent token. After we have written a token
// successfully, DoHandshakeWriteComplete checks this member to set the next
// state.
bool writing_first_token_;
bool completed_handshake_;
// Only used in the STATE_HANDSHAKE_READ_COMPLETE and
// STATE_PAYLOAD_READ_COMPLETE states. True if a 'result' argument of OK
// should be ignored, to prevent it from being interpreted as EOF.
//
// The reason we need this flag is that OK means not only "0 bytes of data
// were read" but also EOF. We set ignore_ok_result_ to true when we need
// to continue processing previously read data without reading more data.
// We have to pass a 'result' of OK to the DoLoop method, and don't want it
// to be interpreted as EOF.
bool ignore_ok_result_;
// Renegotiation is in progress.
bool renegotiating_;
// True when the decrypter needs more data in order to decrypt.
bool need_more_data_;
scoped_refptr<LoadLog> load_log_;
};
} // namespace net
#endif // NET_SOCKET_SSL_CLIENT_SOCKET_WIN_H_