summaryrefslogtreecommitdiffstats
path: root/remoting/protocol
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-23 03:58:43 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-23 03:58:43 +0000
commit8d1f875d17695b508b8ac6ada9cef468f6fd181e (patch)
tree71dd26ccb18e60b4e569c738715a3153e5e91042 /remoting/protocol
parent313b80bd2c5b7257d8daa2ef4aef0ee5b6e1555c (diff)
downloadchromium_src-8d1f875d17695b508b8ac6ada9cef468f6fd181e.zip
chromium_src-8d1f875d17695b508b8ac6ada9cef468f6fd181e.tar.gz
chromium_src-8d1f875d17695b508b8ac6ada9cef468f6fd181e.tar.bz2
Move SSL layer initialization into ChannelAuthenticator implementations.
Also separate client and host authenticators into separate files. Review URL: http://codereview.chromium.org/8604001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111311 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/protocol')
-rw-r--r--remoting/protocol/auth_util.cc (renamed from remoting/protocol/auth_token_utils.cc)28
-rw-r--r--remoting/protocol/auth_util.h (renamed from remoting/protocol/auth_token_utils.h)20
-rw-r--r--remoting/protocol/channel_authenticator.cc220
-rw-r--r--remoting/protocol/channel_authenticator.h98
-rw-r--r--remoting/protocol/connection_to_host.cc2
-rw-r--r--remoting/protocol/jingle_channel_connector.h9
-rw-r--r--remoting/protocol/jingle_datagram_connector.cc8
-rw-r--r--remoting/protocol/jingle_datagram_connector.h14
-rw-r--r--remoting/protocol/jingle_session.cc13
-rw-r--r--remoting/protocol/jingle_stream_connector.cc129
-rw-r--r--remoting/protocol/jingle_stream_connector.h25
-rw-r--r--remoting/protocol/pepper_channel.h9
-rw-r--r--remoting/protocol/pepper_session.cc5
-rw-r--r--remoting/protocol/pepper_stream_channel.cc100
-rw-r--r--remoting/protocol/pepper_stream_channel.h25
-rw-r--r--remoting/protocol/v1_client_channel_authenticator.cc135
-rw-r--r--remoting/protocol/v1_client_channel_authenticator.h63
-rw-r--r--remoting/protocol/v1_host_channel_authenticator.cc142
-rw-r--r--remoting/protocol/v1_host_channel_authenticator.h67
19 files changed, 537 insertions, 575 deletions
diff --git a/remoting/protocol/auth_token_utils.cc b/remoting/protocol/auth_util.cc
index 50edca3..51f7af5 100644
--- a/remoting/protocol/auth_token_utils.cc
+++ b/remoting/protocol/auth_util.cc
@@ -2,16 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "remoting/protocol/auth_token_utils.h"
+#include "remoting/protocol/auth_util.h"
#include "base/base64.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "crypto/hmac.h"
#include "crypto/sha2.h"
namespace remoting {
namespace protocol {
+const char kClientAuthSslExporterLabel[] =
+ "EXPORTER-remoting-channel-auth-client";
+
+const char kSslFakeHostName[] = "chromoting";
+
std::string GenerateSupportAuthToken(const std::string& jid,
const std::string& access_code) {
std::string sha256 = crypto::SHA256HashString(jid + " " + access_code);
@@ -30,5 +36,25 @@ bool VerifySupportAuthToken(const std::string& jid,
return expected_token == auth_token;
}
+// static
+bool GetAuthBytes(const std::string& shared_secret,
+ const std::string& key_material,
+ std::string* auth_bytes) {
+ // Generate auth digest based on the keying material and shared secret.
+ crypto::HMAC response(crypto::HMAC::SHA256);
+ if (!response.Init(key_material)) {
+ NOTREACHED() << "HMAC::Init failed";
+ return false;
+ }
+ unsigned char out_bytes[kAuthDigestLength];
+ if (!response.Sign(shared_secret, out_bytes, kAuthDigestLength)) {
+ NOTREACHED() << "HMAC::Sign failed";
+ return false;
+ }
+
+ auth_bytes->assign(out_bytes, out_bytes + kAuthDigestLength);
+ return true;
+}
+
} // namespace protocol
} // namespace remoting
diff --git a/remoting/protocol/auth_token_utils.h b/remoting/protocol/auth_util.h
index 9be1170..7a81c12 100644
--- a/remoting/protocol/auth_token_utils.h
+++ b/remoting/protocol/auth_util.h
@@ -2,14 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef REMOTING_PROTOCOL_AUTH_TOKEN_UTILS_H_
-#define REMOTING_PROTOCOL_AUTH_TOKEN_UTILS_H_
+#ifndef REMOTING_PROTOCOL_AUTH_UTIL_H_
+#define REMOTING_PROTOCOL_AUTH_UTIL_H_
#include <string>
namespace remoting {
namespace protocol {
+// Labels for use when exporting the SSL master keys.
+extern const char kClientAuthSslExporterLabel[];
+
+// Fake hostname used for SSL connections.
+extern const char kSslFakeHostName[];
+
+// Size of the HMAC-SHA-256 authentication digest.
+const size_t kAuthDigestLength = 32;
+
// Generates auth token for the specified |jid| and |access_code|.
std::string GenerateSupportAuthToken(const std::string& jid,
const std::string& access_code);
@@ -19,7 +28,12 @@ bool VerifySupportAuthToken(const std::string& jid,
const std::string& access_code,
const std::string& auth_token);
+// Returns hash used for channel authentication.
+bool GetAuthBytes(const std::string& shared_secret,
+ const std::string& key_material,
+ std::string* auth_bytes);
+
} // namespace protocol
} // namespace remoting
-#endif // REMOTING_PROTOCOL_AUTH_TOKEN_UTILS_H_
+#endif // REMOTING_PROTOCOL_AUTH_UTIL_H_
diff --git a/remoting/protocol/channel_authenticator.cc b/remoting/protocol/channel_authenticator.cc
deleted file mode 100644
index fcce9b1..0000000
--- a/remoting/protocol/channel_authenticator.cc
+++ /dev/null
@@ -1,220 +0,0 @@
-// 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/channel_authenticator.h"
-
-#include "base/compiler_specific.h"
-#include "base/string_piece.h"
-#include "crypto/hmac.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/socket/ssl_socket.h"
-#include "net/socket/stream_socket.h"
-
-namespace remoting {
-namespace protocol {
-
-namespace {
-
-// Labels for use when exporting the SSL master keys.
-const char kClientSslExporterLabel[] = "EXPORTER-remoting-channel-auth-client";
-
-// Size of the HMAC-SHA-256 authentication digest.
-const size_t kAuthDigestLength = 32;
-
-// static
-bool GetAuthBytes(const std::string& shared_secret,
- const std::string& key_material,
- std::string* auth_bytes) {
- // Generate auth digest based on the keying material and shared secret.
- crypto::HMAC response(crypto::HMAC::SHA256);
- if (!response.Init(key_material)) {
- NOTREACHED() << "HMAC::Init failed";
- return false;
- }
- unsigned char out_bytes[kAuthDigestLength];
- if (!response.Sign(shared_secret, out_bytes, kAuthDigestLength)) {
- NOTREACHED() << "HMAC::Sign failed";
- return false;
- }
-
- auth_bytes->assign(out_bytes, out_bytes + kAuthDigestLength);
- return true;
-}
-
-} // namespace
-
-HostChannelAuthenticator::HostChannelAuthenticator(
- const std::string& shared_secret)
- : shared_secret_(shared_secret),
- socket_(NULL),
- ALLOW_THIS_IN_INITIALIZER_LIST(auth_read_callback_(
- this, &HostChannelAuthenticator::OnAuthBytesRead)) {
-}
-
-HostChannelAuthenticator::~HostChannelAuthenticator() {
-}
-
-void HostChannelAuthenticator::Authenticate(net::SSLSocket* socket,
- const DoneCallback& done_callback) {
- DCHECK(CalledOnValidThread());
-
- socket_ = socket;
- done_callback_ = done_callback;
-
- unsigned char key_material[kAuthDigestLength];
- int result = socket_->ExportKeyingMaterial(
- kClientSslExporterLabel, "", key_material, kAuthDigestLength);
- if (result != net::OK) {
- LOG(ERROR) << "Error fetching keying material: " << result;
- done_callback.Run(FAILURE);
- return;
- }
-
- if (!GetAuthBytes(shared_secret_,
- std::string(key_material, key_material + kAuthDigestLength),
- &auth_bytes_)) {
- done_callback.Run(FAILURE);
- return;
- }
-
- // Read an authentication digest.
- auth_read_buf_ = new net::GrowableIOBuffer();
- auth_read_buf_->SetCapacity(kAuthDigestLength);
- DoAuthRead();
-}
-
-void HostChannelAuthenticator::DoAuthRead() {
- while (true) {
- int result = socket_->Read(auth_read_buf_,
- auth_read_buf_->RemainingCapacity(),
- &auth_read_callback_);
- if (result == net::ERR_IO_PENDING)
- break;
- if (!HandleAuthBytesRead(result))
- break;
- }
-}
-
-void HostChannelAuthenticator::OnAuthBytesRead(int result) {
- DCHECK(CalledOnValidThread());
-
- if (HandleAuthBytesRead(result))
- DoAuthRead();
-}
-
-bool HostChannelAuthenticator::HandleAuthBytesRead(int read_result) {
- if (read_result <= 0) {
- LOG(ERROR) << "Error reading authentication: " << read_result;
- done_callback_.Run(FAILURE);
- return false;
- }
-
- auth_read_buf_->set_offset(auth_read_buf_->offset() + read_result);
- if (auth_read_buf_->RemainingCapacity() > 0)
- return true;
-
- if (!VerifyAuthBytes(std::string(
- auth_read_buf_->StartOfBuffer(),
- auth_read_buf_->StartOfBuffer() + kAuthDigestLength))) {
- LOG(ERROR) << "Mismatched authentication";
- done_callback_.Run(FAILURE);
- return false;
- }
-
- done_callback_.Run(SUCCESS);
- return false;
-}
-
-bool HostChannelAuthenticator::VerifyAuthBytes(
- const std::string& received_auth_bytes) {
- DCHECK(received_auth_bytes.length() == kAuthDigestLength);
-
- // Compare the received and expected digests in fixed time, to limit the
- // scope for timing attacks.
- uint8 result = 0;
- for (unsigned i = 0; i < auth_bytes_.length(); i++) {
- result |= received_auth_bytes[i] ^ auth_bytes_[i];
- }
- return result == 0;
-}
-
-ClientChannelAuthenticator::ClientChannelAuthenticator(
- const std::string& shared_secret)
- : shared_secret_(shared_secret),
-socket_(NULL),
- ALLOW_THIS_IN_INITIALIZER_LIST(auth_write_callback_(
- this, &ClientChannelAuthenticator::OnAuthBytesWritten)) {
-}
-
-ClientChannelAuthenticator::~ClientChannelAuthenticator() {
-}
-
-void ClientChannelAuthenticator::Authenticate(
- net::SSLSocket* socket,
- const DoneCallback& done_callback) {
- DCHECK(CalledOnValidThread());
-
- socket_ = socket;
- done_callback_ = done_callback;
-
- unsigned char key_material[kAuthDigestLength];
- int result = socket_->ExportKeyingMaterial(
- kClientSslExporterLabel, "", key_material, kAuthDigestLength);
- if (result != net::OK) {
- LOG(ERROR) << "Error fetching keying material: " << result;
- done_callback.Run(FAILURE);
- return;
- }
-
- std::string auth_bytes;
- if (!GetAuthBytes(shared_secret_,
- std::string(key_material, key_material + kAuthDigestLength),
- &auth_bytes)) {
- done_callback.Run(FAILURE);
- return;
- }
-
- // Allocate a buffer to write the authentication digest.
- auth_write_buf_ = new net::DrainableIOBuffer(
- new net::StringIOBuffer(auth_bytes), auth_bytes.size());
- DoAuthWrite();
-}
-
-void ClientChannelAuthenticator::DoAuthWrite() {
- 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 ClientChannelAuthenticator::OnAuthBytesWritten(int result) {
- DCHECK(CalledOnValidThread());
-
- if (HandleAuthBytesWritten(result))
- DoAuthWrite();
-}
-
-bool ClientChannelAuthenticator::HandleAuthBytesWritten(int result) {
- if (result <= 0) {
- LOG(ERROR) << "Error writing authentication: " << result;
- done_callback_.Run(FAILURE);
- return false;
- }
-
- auth_write_buf_->DidConsume(result);
- if (auth_write_buf_->BytesRemaining() > 0)
- return true;
-
- done_callback_.Run(SUCCESS);
- return false;
-}
-
-} // namespace protocol
-} // namespace remoting
diff --git a/remoting/protocol/channel_authenticator.h b/remoting/protocol/channel_authenticator.h
index c925ea9..535730a 100644
--- a/remoting/protocol/channel_authenticator.h
+++ b/remoting/protocol/channel_authenticator.h
@@ -8,93 +8,33 @@
#include <string>
#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/threading/non_thread_safe.h"
-#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
namespace net {
-class DrainableIOBuffer;
-class GrowableIOBuffer;
-class SSLSocket;
+class StreamSocket;
} // namespace net
namespace remoting {
namespace protocol {
-class ChannelAuthenticator : public base::NonThreadSafe {
+// Interface for channel authentications that perform channel-level
+// authentication. Depending on implementation channel authenticators
+// may also establish SSL connection. Each instance of this interface
+// should be used only once for one channel.
+class ChannelAuthenticator {
public:
- enum Result {
- SUCCESS,
- FAILURE,
- };
-
- typedef base::Callback<void(Result)> DoneCallback;
-
- ChannelAuthenticator() { }
- virtual ~ChannelAuthenticator() { }
-
- // Starts authentication of the |socket|. |done_callback| is called
- // when authentication is finished. Caller retains ownership of
- // |socket|. |shared_secret| is a shared secret that we use to
- // authenticate the channel.
- virtual void Authenticate(net::SSLSocket* socket,
- const DoneCallback& done_callback) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ChannelAuthenticator);
-};
-
-class HostChannelAuthenticator : public ChannelAuthenticator {
- public:
- HostChannelAuthenticator(const std::string& shared_secret);
- virtual ~HostChannelAuthenticator();
-
- // ChannelAuthenticator overrides.
- virtual void Authenticate(net::SSLSocket* socket,
- const DoneCallback& done_callback) OVERRIDE;
-
- private:
- void DoAuthRead();
- void OnAuthBytesRead(int result);
- bool HandleAuthBytesRead(int result);
- bool VerifyAuthBytes(const std::string& received_auth_bytes);
-
- std::string shared_secret_;
- std::string auth_bytes_;
- net::SSLSocket* socket_;
- DoneCallback done_callback_;
-
- scoped_refptr<net::GrowableIOBuffer> auth_read_buf_;
-
- net::OldCompletionCallbackImpl<HostChannelAuthenticator> auth_read_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(HostChannelAuthenticator);
-};
-
-class ClientChannelAuthenticator : public ChannelAuthenticator {
- public:
- ClientChannelAuthenticator(const std::string& shared_secret);
- virtual ~ClientChannelAuthenticator();
-
- // ChannelAuthenticator overrides.
- virtual void Authenticate(net::SSLSocket* socket,
- const DoneCallback& done_callback) OVERRIDE;
-
- private:
- void DoAuthWrite();
- void OnAuthBytesWritten(int result);
- bool HandleAuthBytesWritten(int result);
-
- std::string shared_secret_;
- net::SSLSocket* socket_;
- DoneCallback done_callback_;
-
- scoped_refptr<net::DrainableIOBuffer> auth_write_buf_;
-
- net::OldCompletionCallbackImpl<ClientChannelAuthenticator>
- auth_write_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(ClientChannelAuthenticator);
+ typedef base::Callback<void(net::Error error, net::StreamSocket*)>
+ DoneCallback;
+
+ virtual ~ChannelAuthenticator() {}
+
+ // Start authentication of the given |socket|. Takes ownership of
+ // |socket|, and caller must not use |socket| after calling this
+ // method. |done_callback| is called when authentication is
+ // finished. Callback may be invoked before this method
+ // returns. Callback handler must take ownership of the result.
+ virtual void SecureAndAuthenticate(
+ net::StreamSocket* socket, const DoneCallback& done_callback) = 0;
};
} // namespace protocol
diff --git a/remoting/protocol/connection_to_host.cc b/remoting/protocol/connection_to_host.cc
index f3638ad..53bc030 100644
--- a/remoting/protocol/connection_to_host.cc
+++ b/remoting/protocol/connection_to_host.cc
@@ -11,7 +11,7 @@
#include "remoting/base/constants.h"
#include "remoting/jingle_glue/javascript_signal_strategy.h"
#include "remoting/jingle_glue/xmpp_signal_strategy.h"
-#include "remoting/protocol/auth_token_utils.h"
+#include "remoting/protocol/auth_util.h"
#include "remoting/protocol/client_control_dispatcher.h"
#include "remoting/protocol/client_event_dispatcher.h"
#include "remoting/protocol/client_stub.h"
diff --git a/remoting/protocol/jingle_channel_connector.h b/remoting/protocol/jingle_channel_connector.h
index 8327ebf..09c8150 100644
--- a/remoting/protocol/jingle_channel_connector.h
+++ b/remoting/protocol/jingle_channel_connector.h
@@ -21,15 +21,16 @@ class RSAPrivateKey;
namespace remoting {
namespace protocol {
+class ChannelAuthenticator;
+
class JingleChannelConnector : public base::NonThreadSafe {
public:
JingleChannelConnector() { }
virtual ~JingleChannelConnector() { }
- virtual void Connect(bool initiator,
- const std::string& local_cert,
- const std::string& remote_cert,
- crypto::RSAPrivateKey* local_private_key,
+ // Starts the connection process for the channel. Takes ownership of
+ // |authenticator|.
+ virtual void Connect(ChannelAuthenticator* authenticator,
cricket::TransportChannel* raw_channel) = 0;
protected:
diff --git a/remoting/protocol/jingle_datagram_connector.cc b/remoting/protocol/jingle_datagram_connector.cc
index 4a90b3d..4673efc 100644
--- a/remoting/protocol/jingle_datagram_connector.cc
+++ b/remoting/protocol/jingle_datagram_connector.cc
@@ -5,6 +5,7 @@
#include "remoting/protocol/jingle_datagram_connector.h"
#include "jingle/glue/channel_socket_adapter.h"
+#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/jingle_session.h"
namespace remoting {
@@ -23,13 +24,12 @@ JingleDatagramConnector::~JingleDatagramConnector() {
}
void JingleDatagramConnector::Connect(
- bool initiator,
- const std::string& local_cert,
- const std::string& remote_cert,
- crypto::RSAPrivateKey* local_private_key,
+ ChannelAuthenticator* authenticator,
cricket::TransportChannel* raw_channel) {
DCHECK(CalledOnValidThread());
+ authenticator_.reset(authenticator);
+
net::Socket* socket =
new jingle_glue::TransportChannelSocketAdapter(raw_channel);
diff --git a/remoting/protocol/jingle_datagram_connector.h b/remoting/protocol/jingle_datagram_connector.h
index 621bbee..930ec0f 100644
--- a/remoting/protocol/jingle_datagram_connector.h
+++ b/remoting/protocol/jingle_datagram_connector.h
@@ -23,13 +23,11 @@ class JingleDatagramConnector : public JingleChannelConnector {
const Session::DatagramChannelCallback& callback);
virtual ~JingleDatagramConnector();
- // Starts connection process for the channel. |local_private_key| is
- // owned by the caller, and must exist until this object is
- // destroyed.
- virtual void Connect(bool initiator,
- const std::string& local_cert,
- const std::string& remote_cert,
- crypto::RSAPrivateKey* local_private_key,
+ // JingleChannelConnector implementation.
+ // TODO(sergeyu): In the current implementation ChannelAuthenticator
+ // cannot be used for datagram channels, so needs to be either
+ // extended or replaced with something else here.
+ virtual void Connect(ChannelAuthenticator* authenticator,
cricket::TransportChannel* raw_channel) OVERRIDE;
private:
@@ -37,6 +35,8 @@ class JingleDatagramConnector : public JingleChannelConnector {
std::string name_;
Session::DatagramChannelCallback callback_;
+ scoped_ptr<ChannelAuthenticator> authenticator_;
+
DISALLOW_COPY_AND_ASSIGN(JingleDatagramConnector);
};
diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc
index 8e22f54..21f8426 100644
--- a/remoting/protocol/jingle_session.cc
+++ b/remoting/protocol/jingle_session.cc
@@ -17,6 +17,8 @@
#include "remoting/protocol/jingle_datagram_connector.h"
#include "remoting/protocol/jingle_session_manager.h"
#include "remoting/protocol/jingle_stream_connector.h"
+#include "remoting/protocol/v1_client_channel_authenticator.h"
+#include "remoting/protocol/v1_host_channel_authenticator.h"
#include "third_party/libjingle/source/talk/base/thread.h"
#include "third_party/libjingle/source/talk/p2p/base/p2ptransportchannel.h"
#include "third_party/libjingle/source/talk/p2p/base/session.h"
@@ -413,8 +415,15 @@ void JingleSession::AddChannelConnector(
}
channel_connectors_[name] = connector;
- connector->Connect(cricket_session_->initiator(), local_cert_,
- remote_cert_, local_private_key_.get(), raw_channel);
+ ChannelAuthenticator* authenticator;
+ if (cricket_session_->initiator()) {
+ authenticator = new V1ClientChannelAuthenticator(
+ remote_cert_, shared_secret_);
+ } else {
+ authenticator = new V1HostChannelAuthenticator(
+ local_cert_, local_private_key_.get(), shared_secret_);
+ }
+ connector->Connect(authenticator, raw_channel);
// Workaround bug in libjingle - it doesn't connect channels if they
// are created after the session is accepted. See crbug.com/89384.
diff --git a/remoting/protocol/jingle_stream_connector.cc b/remoting/protocol/jingle_stream_connector.cc
index 44cc3c5..4eab85e 100644
--- a/remoting/protocol/jingle_stream_connector.cc
+++ b/remoting/protocol/jingle_stream_connector.cc
@@ -32,34 +32,6 @@ const int kTcpAckDelayMilliseconds = 10;
const int kTcpReceiveBufferSize = 256 * 1024;
const int kTcpSendBufferSize = kTcpReceiveBufferSize + 30 * 1024;
-// Helper method to create a SSL client socket.
-net::SSLClientSocket* CreateSSLClientSocket(
- net::StreamSocket* socket, const std::string& der_cert,
- net::CertVerifier* cert_verifier) {
- net::SSLConfig ssl_config;
-
- // Certificate provided by the host doesn't need authority.
- net::SSLConfig::CertAndStatus cert_and_status;
- cert_and_status.cert_status = net::CERT_STATUS_AUTHORITY_INVALID;
- cert_and_status.der_cert = der_cert;
- ssl_config.allowed_bad_certs.push_back(cert_and_status);
-
- // Revocation checking is not needed because we use self-signed
- // certs. Disable it so that SSL layer doesn't try to initialize
- // OCSP (OCSP works only on IO thread).
- ssl_config.rev_checking_enabled = false;
-
- // SSLClientSocket takes ownership of the adapter.
- net::HostPortPair host_and_port(
- ContentDescription::kChromotingContentName, 0);
- net::SSLClientSocketContext context;
- context.cert_verifier = cert_verifier;
- net::SSLClientSocket* ssl_socket =
- net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
- socket, host_and_port, ssl_config, NULL, context);
- return ssl_socket;
-}
-
} // namespace
JingleStreamConnector::JingleStreamConnector(
@@ -69,30 +41,20 @@ JingleStreamConnector::JingleStreamConnector(
: session_(session),
name_(name),
callback_(callback),
- initiator_(false),
- local_private_key_(NULL),
raw_channel_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(tcp_connect_callback_(
- this, &JingleStreamConnector::OnTCPConnect)),
- ALLOW_THIS_IN_INITIALIZER_LIST(ssl_connect_callback_(
- this, &JingleStreamConnector::OnSSLConnect)) {
+ this, &JingleStreamConnector::OnTCPConnect)) {
}
JingleStreamConnector::~JingleStreamConnector() {
}
-void JingleStreamConnector::Connect(bool initiator,
- const std::string& local_cert,
- const std::string& remote_cert,
- crypto::RSAPrivateKey* local_private_key,
+void JingleStreamConnector::Connect(ChannelAuthenticator* authenticator,
cricket::TransportChannel* raw_channel) {
DCHECK(CalledOnValidThread());
DCHECK(!raw_channel_);
- initiator_ = initiator;
- local_cert_ = local_cert;
- remote_cert_ = remote_cert;
- local_private_key_ = local_private_key;
+ authenticator_.reset(authenticator);
raw_channel_ = raw_channel;
net::Socket* socket =
@@ -132,49 +94,6 @@ bool JingleStreamConnector::EstablishTCPConnection(net::Socket* socket) {
return false;
}
-bool JingleStreamConnector::EstablishSSLConnection() {
- DCHECK(tcp_socket_->IsConnected());
-
- int result;
- if (initiator_) {
- cert_verifier_.reset(new net::CertVerifier());
-
- // Create client SSL socket.
- net::SSLClientSocket* socket = CreateSSLClientSocket(
- tcp_socket_.release(), remote_cert_, cert_verifier_.get());
- socket_.reset(socket);
-
- result = socket->Connect(&ssl_connect_callback_);
- } else {
- scoped_refptr<net::X509Certificate> cert =
- net::X509Certificate::CreateFromBytes(
- local_cert_.data(), local_cert_.length());
- if (!cert) {
- LOG(ERROR) << "Failed to parse X509Certificate";
- return false;
- }
-
- // Create server SSL socket.
- net::SSLConfig ssl_config;
- net::SSLServerSocket* socket = net::CreateSSLServerSocket(
- tcp_socket_.release(), cert, local_private_key_, ssl_config);
- socket_.reset(socket);
-
- result = socket->Handshake(&ssl_connect_callback_);
- }
-
- if (result == net::ERR_IO_PENDING) {
- return true;
- } else if (result != net::OK) {
- LOG(ERROR) << "Failed to establish SSL connection";
- return false;
- }
-
- // Reach here if net::OK is received.
- ssl_connect_callback_.Run(net::OK);
- return true;
-}
-
void JingleStreamConnector::OnTCPConnect(int result) {
DCHECK(CalledOnValidThread());
@@ -184,45 +103,16 @@ void JingleStreamConnector::OnTCPConnect(int result) {
return;
}
- if (!EstablishSSLConnection())
- NotifyError();
-}
-
-void JingleStreamConnector::OnSSLConnect(int result) {
- DCHECK(CalledOnValidThread());
-
- if (result != net::OK) {
- LOG(ERROR) << "Error during SSL connection: " << result;
- NotifyError();
- return;
- }
-
- DCHECK(socket_->IsConnected());
- AuthenticateChannel();
-}
-
-void JingleStreamConnector::AuthenticateChannel() {
- if (initiator_) {
- authenticator_.reset(
- new ClientChannelAuthenticator(session_->shared_secret()));
- } else {
- authenticator_.reset(
- new HostChannelAuthenticator(session_->shared_secret()));
- }
- authenticator_->Authenticate(socket_.get(), base::Bind(
+ authenticator_->SecureAndAuthenticate(tcp_socket_.release(), base::Bind(
&JingleStreamConnector::OnAuthenticationDone, base::Unretained(this)));
}
void JingleStreamConnector::OnAuthenticationDone(
- ChannelAuthenticator::Result result) {
- switch (result) {
- case ChannelAuthenticator::SUCCESS:
- NotifyDone(socket_.release());
- break;
-
- case ChannelAuthenticator::FAILURE:
- NotifyError();
- break;
+ net::Error error, net::StreamSocket* socket) {
+ if (error != net::OK) {
+ NotifyError();
+ } else {
+ NotifyDone(socket);
}
}
@@ -233,7 +123,6 @@ void JingleStreamConnector::NotifyDone(net::StreamSocket* socket) {
}
void JingleStreamConnector::NotifyError() {
- socket_.reset();
NotifyDone(NULL);
}
diff --git a/remoting/protocol/jingle_stream_connector.h b/remoting/protocol/jingle_stream_connector.h
index 27103de..f37a691 100644
--- a/remoting/protocol/jingle_stream_connector.h
+++ b/remoting/protocol/jingle_stream_connector.h
@@ -41,24 +41,14 @@ class JingleStreamConnector : public JingleChannelConnector {
const Session::StreamChannelCallback& callback);
virtual ~JingleStreamConnector();
- // Starts connection process for the channel. |local_private_key| is
- // owned by the caller, and must exist until this object is
- // destroyed.
- virtual void Connect(bool initiator,
- const std::string& local_cert,
- const std::string& remote_cert,
- crypto::RSAPrivateKey* local_private_key,
+ // JingleChannelConnector implementation.
+ virtual void Connect(ChannelAuthenticator* authenticator,
cricket::TransportChannel* raw_channel) OVERRIDE;
private:
bool EstablishTCPConnection(net::Socket* socket);
void OnTCPConnect(int result);
-
- bool EstablishSSLConnection();
- void OnSSLConnect(int result);
-
- void AuthenticateChannel();
- void OnAuthenticationDone(ChannelAuthenticator::Result result);
+ void OnAuthenticationDone(net::Error error, net::StreamSocket* socket);
void NotifyDone(net::StreamSocket* socket);
void NotifyError();
@@ -67,23 +57,14 @@ class JingleStreamConnector : public JingleChannelConnector {
std::string name_;
Session::StreamChannelCallback callback_;
- bool initiator_;
- std::string local_cert_;
- std::string remote_cert_;
- crypto::RSAPrivateKey* local_private_key_;
-
cricket::TransportChannel* raw_channel_;
scoped_ptr<net::StreamSocket> tcp_socket_;
scoped_ptr<net::SSLSocket> socket_;
- // Used to verify the certificate received in SSLClientSocket.
- scoped_ptr<net::CertVerifier> cert_verifier_;
-
scoped_ptr<ChannelAuthenticator> authenticator_;
// Callback called by the TCP and SSL layers.
net::OldCompletionCallbackImpl<JingleStreamConnector> tcp_connect_callback_;
- net::OldCompletionCallbackImpl<JingleStreamConnector> ssl_connect_callback_;
DISALLOW_COPY_AND_ASSIGN(JingleStreamConnector);
};
diff --git a/remoting/protocol/pepper_channel.h b/remoting/protocol/pepper_channel.h
index cb77b17..de6b93b 100644
--- a/remoting/protocol/pepper_channel.h
+++ b/remoting/protocol/pepper_channel.h
@@ -21,6 +21,7 @@ class Candidate;
namespace remoting {
namespace protocol {
+class ChannelAuthenticator;
struct TransportConfig;
// Interface for stream and datagram channels used by PepperSession.
@@ -29,10 +30,12 @@ class PepperChannel : public base::NonThreadSafe {
PepperChannel() { }
virtual ~PepperChannel() { }
- // Connect the channel using specified |config|.
+ // Connect the channel using specified |config|. The specified
+ // |authenticator| is used to authenticate the channel. Takes
+ // ownership of |authenticator|.
virtual void Connect(pp::Instance* pp_instance,
const TransportConfig& config,
- const std::string& remote_cert) = 0;
+ ChannelAuthenticator* authenticator) = 0;
// Adds |candidate| received from the peer.
virtual void AddRemoveCandidate(const cricket::Candidate& candidate) = 0;
@@ -40,7 +43,7 @@ class PepperChannel : public base::NonThreadSafe {
// Name of the channel.
virtual const std::string& name() const = 0;
- // returns true if the channel is already connected
+ // Returns true if the channel is already connected.
virtual bool is_connected() const = 0;
protected:
diff --git a/remoting/protocol/pepper_session.cc b/remoting/protocol/pepper_session.cc
index d9bab52..138993b 100644
--- a/remoting/protocol/pepper_session.cc
+++ b/remoting/protocol/pepper_session.cc
@@ -14,6 +14,7 @@
#include "remoting/protocol/jingle_messages.h"
#include "remoting/protocol/pepper_session_manager.h"
#include "remoting/protocol/pepper_stream_channel.h"
+#include "remoting/protocol/v1_client_channel_authenticator.h"
#include "third_party/libjingle/source/talk/p2p/base/candidate.h"
#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
@@ -114,7 +115,9 @@ void PepperSession::CreateStreamChannel(
PepperStreamChannel* channel = new PepperStreamChannel(this, name, callback);
channels_[name] = channel;
channel->Connect(session_manager_->pp_instance_,
- session_manager_->transport_config_, remote_cert_);
+ session_manager_->transport_config_,
+ new V1ClientChannelAuthenticator(
+ remote_cert_, shared_secret_));
}
void PepperSession::CreateDatagramChannel(
diff --git a/remoting/protocol/pepper_stream_channel.cc b/remoting/protocol/pepper_stream_channel.cc
index 84abe25..e51d265 100644
--- a/remoting/protocol/pepper_stream_channel.cc
+++ b/remoting/protocol/pepper_stream_channel.cc
@@ -35,33 +35,6 @@ const int kTcpAckDelayMilliseconds = 10;
const int kTcpReceiveBufferSize = 256 * 1024;
const int kTcpSendBufferSize = kTcpReceiveBufferSize + 30 * 1024;
-// Helper method to create a SSL client socket.
-net::SSLClientSocket* CreateSSLClientSocket(
- net::StreamSocket* socket, const std::string& der_cert,
- net::CertVerifier* cert_verifier) {
- net::SSLConfig ssl_config;
-
- // Certificate provided by the host doesn't need authority.
- net::SSLConfig::CertAndStatus cert_and_status;
- cert_and_status.cert_status = net::CERT_STATUS_AUTHORITY_INVALID;
- cert_and_status.der_cert = der_cert;
- ssl_config.allowed_bad_certs.push_back(cert_and_status);
-
- // Revocation checking is not needed because we use self-signed
- // certs. Disable it so that SSL layer doesn't try to initialize
- // OCSP (OCSP works only on IO thread).
- ssl_config.rev_checking_enabled = false;
-
- // SSLClientSocket takes ownership of the |socket|.
- net::HostPortPair host_and_port("chromoting", 0);
- net::SSLClientSocketContext context;
- context.cert_verifier = cert_verifier;
- net::SSLClientSocket* ssl_socket =
- net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
- socket, host_and_port, ssl_config, NULL, context);
- return ssl_socket;
-}
-
} // namespace
PepperStreamChannel::PepperStreamChannel(
@@ -73,11 +46,8 @@ PepperStreamChannel::PepperStreamChannel(
callback_(callback),
channel_(NULL),
connected_(false),
- ssl_client_socket_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(p2p_connect_callback_(
- this, &PepperStreamChannel::OnP2PConnect)),
- ALLOW_THIS_IN_INITIALIZER_LIST(ssl_connect_callback_(
- this, &PepperStreamChannel::OnSSLConnect)) {
+ this, &PepperStreamChannel::OnP2PConnect)) {
}
PepperStreamChannel::~PepperStreamChannel() {
@@ -90,10 +60,10 @@ PepperStreamChannel::~PepperStreamChannel() {
void PepperStreamChannel::Connect(pp::Instance* pp_instance,
const TransportConfig& transport_config,
- const std::string& remote_cert) {
+ ChannelAuthenticator* authenticator) {
DCHECK(CalledOnValidThread());
- remote_cert_ = remote_cert;
+ authenticator_.reset(authenticator);
pp::Transport_Dev* transport =
new pp::Transport_Dev(pp_instance, name_.c_str(),
@@ -197,69 +167,23 @@ void PepperStreamChannel::OnChannelNewLocalCandidate(
void PepperStreamChannel::OnP2PConnect(int result) {
DCHECK(CalledOnValidThread());
- if (result != net::OK || !EstablishSSLConnection())
+ if (result != net::OK)
NotifyConnectFailed();
-}
-
-bool PepperStreamChannel::EstablishSSLConnection() {
- DCHECK(CalledOnValidThread());
-
- cert_verifier_.reset(new net::CertVerifier());
-
- // Create client SSL socket.
- ssl_client_socket_ = CreateSSLClientSocket(
- owned_channel_.release(), remote_cert_, cert_verifier_.get());
- socket_.reset(ssl_client_socket_);
- int result = ssl_client_socket_->Connect(&ssl_connect_callback_);
-
- if (result == net::ERR_IO_PENDING) {
- return true;
- } else if (result != net::OK) {
- LOG(ERROR) << "Failed to establish SSL connection";
- return false;
- }
-
- // Reach here if net::OK is received.
- ssl_connect_callback_.Run(net::OK);
- return true;
+ authenticator_->SecureAndAuthenticate(owned_channel_.release(), base::Bind(
+ &PepperStreamChannel::OnAuthenticationDone, base::Unretained(this)));
}
-void PepperStreamChannel::OnSSLConnect(int result) {
- DCHECK(CalledOnValidThread());
- if (result != net::OK) {
- LOG(ERROR) << "Error during SSL connection: " << result;
+void PepperStreamChannel::OnAuthenticationDone(
+ net::Error error, net::StreamSocket* socket) {
+ DCHECK(CalledOnValidThread());
+ if (error != net::OK) {
NotifyConnectFailed();
return;
}
- DCHECK(socket_->IsConnected());
- AuthenticateChannel();
-}
-
-void PepperStreamChannel::AuthenticateChannel() {
- DCHECK(CalledOnValidThread());
-
- authenticator_.reset(
- new ClientChannelAuthenticator(session_->shared_secret()));
- authenticator_->Authenticate(ssl_client_socket_, base::Bind(
- &PepperStreamChannel::OnAuthenticationDone, base::Unretained(this)));
-}
-
-void PepperStreamChannel::OnAuthenticationDone(
- ChannelAuthenticator::Result result) {
- DCHECK(CalledOnValidThread());
-
- switch (result) {
- case ChannelAuthenticator::SUCCESS:
- NotifyConnected(socket_.release());
- break;
-
- case ChannelAuthenticator::FAILURE:
- NotifyConnectFailed();
- break;
- }
+ NotifyConnected(socket);
}
void PepperStreamChannel::NotifyConnected(net::StreamSocket* socket) {
@@ -271,7 +195,7 @@ void PepperStreamChannel::NotifyConnected(net::StreamSocket* socket) {
void PepperStreamChannel::NotifyConnectFailed() {
channel_ = NULL;
owned_channel_.reset();
- socket_.reset();
+ authenticator_.reset();
NotifyConnected(NULL);
}
diff --git a/remoting/protocol/pepper_stream_channel.h b/remoting/protocol/pepper_stream_channel.h
index dbe206e..5c17e4f 100644
--- a/remoting/protocol/pepper_stream_channel.h
+++ b/remoting/protocol/pepper_stream_channel.h
@@ -37,7 +37,7 @@ class PepperStreamChannel : public PepperChannel,
// PepperChannel implementation.
virtual void Connect(pp::Instance* pp_instance,
const TransportConfig& transport_config,
- const std::string& remote_cert) OVERRIDE;
+ ChannelAuthenticator* authenticator) OVERRIDE;
virtual void AddRemoveCandidate(const cricket::Candidate& candidate) OVERRIDE;
virtual const std::string& name() const OVERRIDE;
virtual bool is_connected() const OVERRIDE;
@@ -49,12 +49,7 @@ class PepperStreamChannel : public PepperChannel,
private:
void OnP2PConnect(int result);
-
- bool EstablishSSLConnection();
- void OnSSLConnect(int result);
-
- void AuthenticateChannel();
- void OnAuthenticationDone(ChannelAuthenticator::Result result);
+ void OnAuthenticationDone(net::Error error, net::StreamSocket* socket);
void NotifyConnected(net::StreamSocket* socket);
void NotifyConnectFailed();
@@ -62,28 +57,18 @@ class PepperStreamChannel : public PepperChannel,
PepperSession* session_;
std::string name_;
Session::StreamChannelCallback callback_;
-
- std::string remote_cert_;
+ scoped_ptr<ChannelAuthenticator> authenticator_;
// We own |channel_| until it is connected. After that
- // SSLClientSocket owns it.
+ // |authenticator_| owns it.
scoped_ptr<PepperTransportSocketAdapter> owned_channel_;
PepperTransportSocketAdapter* channel_;
// Indicates that we've finished connecting.
bool connected_;
- scoped_ptr<net::StreamSocket> socket_;
- net::SSLClientSocket* ssl_client_socket_;
-
- // Used to verify the certificate received in SSLClientSocket.
- scoped_ptr<net::CertVerifier> cert_verifier_;
-
- scoped_ptr<ChannelAuthenticator> authenticator_;
-
- // Callback called by the TCP and SSL layers.
+ // Callback called by the TCP layer.
net::OldCompletionCallbackImpl<PepperStreamChannel> p2p_connect_callback_;
- net::OldCompletionCallbackImpl<PepperStreamChannel> ssl_connect_callback_;
DISALLOW_COPY_AND_ASSIGN(PepperStreamChannel);
};
diff --git a/remoting/protocol/v1_client_channel_authenticator.cc b/remoting/protocol/v1_client_channel_authenticator.cc
new file mode 100644
index 0000000..312403b
--- /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
diff --git a/remoting/protocol/v1_client_channel_authenticator.h b/remoting/protocol/v1_client_channel_authenticator.h
new file mode 100644
index 0000000..d8b2659
--- /dev/null
+++ b/remoting/protocol/v1_client_channel_authenticator.h
@@ -0,0 +1,63 @@
+// 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 REMOTING_PROTOCOL_V1_CLIENT_CHANNEL_AUTHENTICATOR_H_
+#define REMOTING_PROTOCOL_V1_CLIENT_CHANNEL_AUTHENTICATOR_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "net/base/completion_callback.h"
+#include "remoting/protocol/channel_authenticator.h"
+
+namespace net {
+class CertVerifier;
+class DrainableIOBuffer;
+class GrowableIOBuffer;
+class SSLClientSocket;
+} // namespace net
+
+namespace remoting {
+namespace protocol {
+
+class V1ClientChannelAuthenticator : public ChannelAuthenticator,
+ public base::NonThreadSafe {
+ public:
+ V1ClientChannelAuthenticator(const std::string& host_cert,
+ const std::string& shared_secret);
+ virtual ~V1ClientChannelAuthenticator();
+
+ // ChannelAuthenticator implementation.
+ virtual void SecureAndAuthenticate(
+ net::StreamSocket* socket, const DoneCallback& done_callback) OVERRIDE;
+
+ private:
+ void OnConnected(int result);
+ void WriteAuthenticationBytes();
+ void OnAuthBytesWritten(int result);
+ bool HandleAuthBytesWritten(int result);
+
+ std::string host_cert_;
+ std::string shared_secret_;
+ scoped_ptr<net::SSLClientSocket> socket_;
+ DoneCallback done_callback_;
+
+ scoped_ptr<net::CertVerifier> cert_verifier_;
+ scoped_refptr<net::DrainableIOBuffer> auth_write_buf_;
+
+ net::OldCompletionCallbackImpl<V1ClientChannelAuthenticator>
+ connect_callback_;
+ net::OldCompletionCallbackImpl<V1ClientChannelAuthenticator>
+ auth_write_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(V1ClientChannelAuthenticator);
+};
+
+} // namespace protocol
+} // namespace remoting
+
+#endif // REMOTING_PROTOCOL_V1_CLIENT_CHANNEL_AUTHENTICATOR_H_
diff --git a/remoting/protocol/v1_host_channel_authenticator.cc b/remoting/protocol/v1_host_channel_authenticator.cc
new file mode 100644
index 0000000..c124d47
--- /dev/null
+++ b/remoting/protocol/v1_host_channel_authenticator.cc
@@ -0,0 +1,142 @@
+// 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_host_channel_authenticator.h"
+
+#include "crypto/rsa_private_key.h"
+#include "crypto/secure_util.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/ssl_config_service.h"
+#include "net/base/x509_certificate.h"
+#include "net/socket/ssl_server_socket.h"
+#include "remoting/protocol/auth_util.h"
+
+namespace remoting {
+namespace protocol {
+
+V1HostChannelAuthenticator::V1HostChannelAuthenticator(
+ const std::string& local_cert,
+ crypto::RSAPrivateKey* local_private_key,
+ const std::string& shared_secret)
+ : local_cert_(local_cert),
+ local_private_key_(local_private_key),
+ shared_secret_(shared_secret),
+ socket_(NULL),
+ ALLOW_THIS_IN_INITIALIZER_LIST(connect_callback_(
+ this, &V1HostChannelAuthenticator::OnConnected)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(auth_read_callback_(
+ this, &V1HostChannelAuthenticator::OnAuthBytesRead)) {
+}
+
+V1HostChannelAuthenticator::~V1HostChannelAuthenticator() {
+}
+
+void V1HostChannelAuthenticator::SecureAndAuthenticate(
+ net::StreamSocket* socket, const DoneCallback& done_callback) {
+ DCHECK(CalledOnValidThread());
+
+ scoped_ptr<net::StreamSocket> channel_socket(socket);
+ done_callback_ = done_callback;
+
+ scoped_refptr<net::X509Certificate> cert =
+ net::X509Certificate::CreateFromBytes(
+ local_cert_.data(), local_cert_.length());
+ if (!cert) {
+ LOG(ERROR) << "Failed to parse X509Certificate";
+ done_callback.Run(net::ERR_FAILED, NULL);
+ return;
+ }
+
+ net::SSLConfig ssl_config;
+ socket_.reset(net::CreateSSLServerSocket(
+ channel_socket.release(), cert, local_private_key_, ssl_config));
+
+ int result = socket_->Handshake(&connect_callback_);
+ if (result == net::ERR_IO_PENDING) {
+ return;
+ }
+ OnConnected(result);
+}
+
+void V1HostChannelAuthenticator::OnConnected(int result) {
+ if (result != net::OK) {
+ LOG(ERROR) << "Failed to establish SSL connection";
+ done_callback_.Run(static_cast<net::Error>(result), NULL);
+ }
+
+ // Read an authentication digest.
+ auth_read_buf_ = new net::GrowableIOBuffer();
+ auth_read_buf_->SetCapacity(kAuthDigestLength);
+ DoAuthRead();
+}
+
+void V1HostChannelAuthenticator::DoAuthRead(){
+ while (true) {
+ int result = socket_->Read(auth_read_buf_,
+ auth_read_buf_->RemainingCapacity(),
+ &auth_read_callback_);
+ if (result == net::ERR_IO_PENDING)
+ break;
+ if (!HandleAuthBytesRead(result))
+ break;
+ }
+}
+
+void V1HostChannelAuthenticator::OnAuthBytesRead(int result) {
+ DCHECK(CalledOnValidThread());
+
+ if (HandleAuthBytesRead(result))
+ DoAuthRead();
+}
+
+bool V1HostChannelAuthenticator::HandleAuthBytesRead(int read_result) {
+ if (read_result <= 0) {
+ done_callback_.Run(static_cast<net::Error>(read_result), NULL);
+ return false;
+ }
+
+ auth_read_buf_->set_offset(auth_read_buf_->offset() + read_result);
+ if (auth_read_buf_->RemainingCapacity() > 0)
+ return true;
+
+ if (!VerifyAuthBytes(std::string(
+ auth_read_buf_->StartOfBuffer(),
+ auth_read_buf_->StartOfBuffer() + kAuthDigestLength))) {
+ LOG(WARNING) << "Mismatched authentication";
+ done_callback_.Run(net::ERR_FAILED, NULL);
+ return false;
+ }
+
+ done_callback_.Run(net::OK, socket_.release());
+ return false;
+}
+
+bool V1HostChannelAuthenticator::VerifyAuthBytes(
+ const std::string& received_auth_bytes) {
+ DCHECK(received_auth_bytes.length() == kAuthDigestLength);
+
+ 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 false;
+ }
+
+ std::string auth_bytes;
+ if (!GetAuthBytes(shared_secret_,
+ std::string(key_material, key_material + kAuthDigestLength),
+ &auth_bytes)) {
+ done_callback_.Run(net::ERR_FAILED, NULL);
+ return false;
+ }
+
+ return crypto::SecureMemEqual(received_auth_bytes.data(),
+ &(auth_bytes[0]), kAuthDigestLength);
+}
+
+} // namespace protocol
+} // namespace remoting
diff --git a/remoting/protocol/v1_host_channel_authenticator.h b/remoting/protocol/v1_host_channel_authenticator.h
new file mode 100644
index 0000000..081eff7
--- /dev/null
+++ b/remoting/protocol/v1_host_channel_authenticator.h
@@ -0,0 +1,67 @@
+// 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 REMOTING_PROTOCOL_V1_HOST_CHANNEL_AUTHENTICATOR_H_
+#define REMOTING_PROTOCOL_V1_HOST_CHANNEL_AUTHENTICATOR_H_
+
+#include "remoting/protocol/channel_authenticator.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "net/base/completion_callback.h"
+
+namespace crypto {
+class RSAPrivateKey;
+} // namespace crypto
+
+namespace net {
+class GrowableIOBuffer;
+class SSLServerSocket;
+class SSLSocket;
+} // namespace net
+
+namespace remoting {
+namespace protocol {
+
+class V1HostChannelAuthenticator : public ChannelAuthenticator,
+ public base::NonThreadSafe {
+ public:
+ // Caller retains ownership of |local_private_key|. It must exist
+ // while this object exists.
+ V1HostChannelAuthenticator(const std::string& local_cert,
+ crypto::RSAPrivateKey* local_private_key,
+ const std::string& shared_secret);
+ virtual ~V1HostChannelAuthenticator();
+
+ // ChannelAuthenticator interface.
+ virtual void SecureAndAuthenticate(
+ net::StreamSocket* socket, const DoneCallback& done_callback) OVERRIDE;
+
+ private:
+ void OnConnected(int result);
+ void DoAuthRead();
+ void OnAuthBytesRead(int result);
+ bool HandleAuthBytesRead(int result);
+ bool VerifyAuthBytes(const std::string& received_auth_bytes);
+
+ std::string local_cert_;
+ crypto::RSAPrivateKey* local_private_key_;
+ std::string shared_secret_;
+ scoped_ptr<net::SSLServerSocket> socket_;
+ DoneCallback done_callback_;
+
+ scoped_refptr<net::GrowableIOBuffer> auth_read_buf_;
+
+ net::OldCompletionCallbackImpl<V1HostChannelAuthenticator>
+ connect_callback_;
+ net::OldCompletionCallbackImpl<V1HostChannelAuthenticator>
+ auth_read_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(V1HostChannelAuthenticator);
+};
+
+} // namespace protocol
+} // namespace remoting
+
+#endif // REMOTING_PROTOCOL_V1_HOST_CHANNEL_AUTHENTICATOR_H_