| Index: remoting/protocol/v1_client_channel_authenticator.cc
|
| diff --git a/remoting/protocol/v1_client_channel_authenticator.cc b/remoting/protocol/v1_client_channel_authenticator.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..312403b18b7a19cdd14dd8a09af53517e6b01e9e
|
| --- /dev/null
|
| +++ b/remoting/protocol/v1_client_channel_authenticator.cc
|
| @@ -0,0 +1,135 @@
|
| +// 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.
|
| +
|
| +#include "remoting/protocol/v1_client_channel_authenticator.h"
|
| +
|
| +#include "net/base/cert_verifier.h"
|
| +#include "net/base/host_port_pair.h"
|
| +#include "net/base/io_buffer.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/base/ssl_config_service.h"
|
| +#include "net/socket/client_socket_factory.h"
|
| +#include "net/socket/ssl_client_socket.h"
|
| +#include "remoting/protocol/auth_util.h"
|
| +
|
| +namespace remoting {
|
| +namespace protocol {
|
| +
|
| +V1ClientChannelAuthenticator::V1ClientChannelAuthenticator(
|
| + const std::string& host_cert,
|
| + const std::string& shared_secret)
|
| + : host_cert_(host_cert),
|
| + shared_secret_(shared_secret),
|
| + socket_(NULL),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(connect_callback_(
|
| + this, &V1ClientChannelAuthenticator::OnConnected)),
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(auth_write_callback_(
|
| + this, &V1ClientChannelAuthenticator::OnAuthBytesWritten)) {
|
| +}
|
| +
|
| +V1ClientChannelAuthenticator::~V1ClientChannelAuthenticator() {
|
| +}
|
| +
|
| +void V1ClientChannelAuthenticator::SecureAndAuthenticate(
|
| + net::StreamSocket* socket, const DoneCallback& done_callback) {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK(socket->IsConnected());
|
| +
|
| + done_callback_ = done_callback;
|
| +
|
| + cert_verifier_.reset(new net::CertVerifier());
|
| +
|
| + net::SSLConfig::CertAndStatus cert_and_status;
|
| + cert_and_status.cert_status = net::CERT_STATUS_AUTHORITY_INVALID;
|
| + cert_and_status.der_cert = host_cert_;
|
| +
|
| + net::SSLConfig ssl_config;
|
| + // Certificate verification and revocation checking are not needed
|
| + // because we use self-signed certs. Disable it so that the SSL
|
| + // layer doesn't try to initialize OCSP (OCSP works only on the IO
|
| + // thread).
|
| + ssl_config.allowed_bad_certs.push_back(cert_and_status);
|
| + ssl_config.rev_checking_enabled = false;
|
| +
|
| + net::HostPortPair host_and_port(kSslFakeHostName, 0);
|
| + net::SSLClientSocketContext context;
|
| + context.cert_verifier = cert_verifier_.get();
|
| + socket_.reset(
|
| + net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
|
| + socket, host_and_port, ssl_config, NULL, context));
|
| +
|
| + int result = socket_->Connect(&connect_callback_);
|
| + if (result == net::ERR_IO_PENDING)
|
| + return;
|
| + OnConnected(result);
|
| +}
|
| +
|
| +void V1ClientChannelAuthenticator::OnConnected(int result) {
|
| + if (result != net::OK) {
|
| + LOG(ERROR) << "Failed to establish SSL connection";
|
| + done_callback_.Run(static_cast<net::Error>(result), NULL);
|
| + }
|
| +
|
| + // Get keying material from SSL.
|
| + unsigned char key_material[kAuthDigestLength];
|
| + int export_result = socket_->ExportKeyingMaterial(
|
| + kClientAuthSslExporterLabel, "", key_material, kAuthDigestLength);
|
| + if (export_result != net::OK) {
|
| + LOG(ERROR) << "Error fetching keying material: " << export_result;
|
| + done_callback_.Run(static_cast<net::Error>(export_result), NULL);
|
| + return;
|
| + }
|
| +
|
| + // Generate authentication digest to write to the socket.
|
| + std::string auth_bytes;
|
| + if (!GetAuthBytes(shared_secret_,
|
| + std::string(reinterpret_cast<char*>(key_material),
|
| + kAuthDigestLength),
|
| + &auth_bytes)) {
|
| + done_callback_.Run(net::ERR_FAILED, NULL);
|
| + return;
|
| + }
|
| +
|
| + // Allocate a buffer to write the digest.
|
| + auth_write_buf_ = new net::DrainableIOBuffer(
|
| + new net::StringIOBuffer(auth_bytes), auth_bytes.size());
|
| + WriteAuthenticationBytes();
|
| +}
|
| +
|
| +void V1ClientChannelAuthenticator::WriteAuthenticationBytes() {
|
| + while (true) {
|
| + int result = socket_->Write(auth_write_buf_,
|
| + auth_write_buf_->BytesRemaining(),
|
| + &auth_write_callback_);
|
| + if (result == net::ERR_IO_PENDING)
|
| + break;
|
| + if (!HandleAuthBytesWritten(result))
|
| + break;
|
| + }
|
| +}
|
| +
|
| +void V1ClientChannelAuthenticator::OnAuthBytesWritten(int result) {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + if (HandleAuthBytesWritten(result))
|
| + WriteAuthenticationBytes();
|
| +}
|
| +
|
| +bool V1ClientChannelAuthenticator::HandleAuthBytesWritten(int result) {
|
| + if (result <= 0) {
|
| + LOG(ERROR) << "Error writing authentication: " << result;
|
| + done_callback_.Run(static_cast<net::Error>(result), NULL);
|
| + return false;
|
| + }
|
| +
|
| + auth_write_buf_->DidConsume(result);
|
| + if (auth_write_buf_->BytesRemaining() > 0)
|
| + return true;
|
| +
|
| + done_callback_.Run(net::OK, socket_.release());
|
| + return false;
|
| +}
|
| +
|
| +} // namespace protocol
|
| +} // namespace remoting
|
|
|