summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-02 01:54:08 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-02 01:54:08 +0000
commitdd9ce7c7f312359bdc91ca6fcc158493bb478876 (patch)
tree3f81f316204c73f2cbaa84a27a0a8d7efeedd916 /remoting
parenta0bd0e4d410000c1a4a888cd3af732d93e5fd9b0 (diff)
downloadchromium_src-dd9ce7c7f312359bdc91ca6fcc158493bb478876.zip
chromium_src-dd9ce7c7f312359bdc91ca6fcc158493bb478876.tar.gz
chromium_src-dd9ce7c7f312359bdc91ca6fcc158493bb478876.tar.bz2
Separate channel authentication code from JingleStreamConnecter.
The new ChannelAuthenticator will also be used for pepper-based protocol implementation. BUG=51198 TEST=Unittests Review URL: http://codereview.chromium.org/7537036 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95030 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/protocol/channel_authenticator.cc216
-rw-r--r--remoting/protocol/channel_authenticator.h101
-rw-r--r--remoting/protocol/jingle_stream_connector.cc169
-rw-r--r--remoting/protocol/jingle_stream_connector.h18
-rw-r--r--remoting/remoting.gyp2
5 files changed, 339 insertions, 167 deletions
diff --git a/remoting/protocol/channel_authenticator.cc b/remoting/protocol/channel_authenticator.cc
new file mode 100644
index 0000000..fefab18
--- /dev/null
+++ b/remoting/protocol/channel_authenticator.cc
@@ -0,0 +1,216 @@
+// 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_client_socket.h"
+#include "net/socket/ssl_server_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-1 authentication digest.
+const size_t kAuthDigestLength = 20;
+
+// 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::SHA1);
+ if (!response.Init(shared_secret)) {
+ NOTREACHED() << "HMAC::Init failed";
+ return false;
+ }
+ unsigned char out_bytes[kAuthDigestLength];
+ if (!response.Sign(key_material, out_bytes, kAuthDigestLength)) {
+ NOTREACHED() << "HMAC::Sign failed";
+ return false;
+ }
+
+ auth_bytes->assign(out_bytes, out_bytes + kAuthDigestLength);
+ return true;
+}
+
+} // namespace
+
+HostChannelAuthenticator::HostChannelAuthenticator(net::SSLServerSocket* socket)
+ : socket_(socket),
+ ALLOW_THIS_IN_INITIALIZER_LIST(auth_read_callback_(
+ this, &HostChannelAuthenticator::OnAuthBytesRead)) {
+}
+
+HostChannelAuthenticator::~HostChannelAuthenticator() {
+}
+
+void HostChannelAuthenticator::Authenticate(const std::string& shared_secret,
+ const DoneCallback& done_callback) {
+ DCHECK(CalledOnValidThread());
+
+ 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(
+ net::SSLClientSocket* socket)
+ : socket_(socket),
+ ALLOW_THIS_IN_INITIALIZER_LIST(auth_write_callback_(
+ this, &ClientChannelAuthenticator::OnAuthBytesWritten)) {
+}
+
+ClientChannelAuthenticator::~ClientChannelAuthenticator() {
+}
+
+void ClientChannelAuthenticator::Authenticate(
+ const std::string& shared_secret,
+ const DoneCallback& done_callback) {
+ DCHECK(CalledOnValidThread());
+
+ 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
new file mode 100644
index 0000000..af646bf
--- /dev/null
+++ b/remoting/protocol/channel_authenticator.h
@@ -0,0 +1,101 @@
+// 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_CHANNEL_AUTHENTICATOR_H_
+#define REMOTING_PROTOCOL_CHANNEL_AUTHENTICATOR_H_
+
+#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"
+
+namespace net {
+class DrainableIOBuffer;
+class GrowableIOBuffer;
+class SSLClientSocket;
+class SSLServerSocket;
+} // namespace net
+
+namespace remoting {
+namespace protocol {
+
+class ChannelAuthenticator : public base::NonThreadSafe {
+ 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(const std::string& shared_secret,
+ const DoneCallback& done_callback) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChannelAuthenticator);
+};
+
+class HostChannelAuthenticator : public ChannelAuthenticator {
+ public:
+ HostChannelAuthenticator(net::SSLServerSocket* socket);
+ ~HostChannelAuthenticator();
+
+ // ChannelAuthenticator overrides.
+ virtual void Authenticate(const std::string& shared_secret,
+ 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 auth_bytes_;
+ net::SSLServerSocket* socket_;
+ DoneCallback done_callback_;
+
+ scoped_refptr<net::GrowableIOBuffer> auth_read_buf_;
+
+ net::CompletionCallbackImpl<HostChannelAuthenticator> auth_read_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostChannelAuthenticator);
+};
+
+class ClientChannelAuthenticator : public ChannelAuthenticator {
+ public:
+ ClientChannelAuthenticator(net::SSLClientSocket* socket);
+ ~ClientChannelAuthenticator();
+
+ // ChannelAuthenticator overrides.
+ void Authenticate(const std::string& shared_secret,
+ const DoneCallback& done_callback);
+
+ private:
+ void DoAuthWrite();
+ void OnAuthBytesWritten(int result);
+ bool HandleAuthBytesWritten(int result);
+
+ net::SSLClientSocket* socket_;
+ DoneCallback done_callback_;
+
+ scoped_refptr<net::DrainableIOBuffer> auth_write_buf_;
+
+ net::CompletionCallbackImpl<ClientChannelAuthenticator> auth_write_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientChannelAuthenticator);
+};
+
+} // namespace protocol
+} // namespace remoting
+
+#endif // REMOTING_PROTOCOL_CHANNEL_AUTHENTICATOR_H_
diff --git a/remoting/protocol/jingle_stream_connector.cc b/remoting/protocol/jingle_stream_connector.cc
index 849f432..01ba8f8 100644
--- a/remoting/protocol/jingle_stream_connector.cc
+++ b/remoting/protocol/jingle_stream_connector.cc
@@ -4,7 +4,7 @@
#include "remoting/protocol/jingle_stream_connector.h"
-#include "crypto/hmac.h"
+#include "base/bind.h"
#include "jingle/glue/channel_socket_adapter.h"
#include "jingle/glue/pseudotcp_adapter.h"
#include "net/base/cert_status_flags.h"
@@ -22,12 +22,6 @@ namespace protocol {
namespace {
-// Size of the HMAC-SHA-1 authentication digest.
-const int kAuthDigestLength = 20;
-
-// Labels for use when exporting the SSL master keys.
-const char kClientSslExporterLabel[] = "EXPORTER-remoting-channel-auth-client";
-
// Value is choosen to balance the extra latency against the reduced
// load due to ACK traffic.
const int kTcpAckDelayMilliseconds = 10;
@@ -76,11 +70,7 @@ JingleStreamConnector::JingleStreamConnector(
ALLOW_THIS_IN_INITIALIZER_LIST(tcp_connect_callback_(
this, &JingleStreamConnector::OnTCPConnect)),
ALLOW_THIS_IN_INITIALIZER_LIST(ssl_connect_callback_(
- this, &JingleStreamConnector::OnSSLConnect)),
- ALLOW_THIS_IN_INITIALIZER_LIST(auth_write_callback_(
- this, &JingleStreamConnector::OnAuthBytesWritten)),
- ALLOW_THIS_IN_INITIALIZER_LIST(auth_read_callback_(
- this, &JingleStreamConnector::OnAuthBytesRead)) {
+ this, &JingleStreamConnector::OnSSLConnect)) {
}
JingleStreamConnector::~JingleStreamConnector() {
@@ -197,156 +187,29 @@ void JingleStreamConnector::OnSSLConnect(int result) {
}
void JingleStreamConnector::AuthenticateChannel() {
- DCHECK(CalledOnValidThread());
if (initiator_) {
- // Allocate a buffer to write the authentication digest.
- scoped_refptr<net::IOBuffer> write_buf =
- new net::IOBuffer(kAuthDigestLength);
- auth_write_buf_ = new net::DrainableIOBuffer(write_buf,
- kAuthDigestLength);
-
- // Generate the auth digest to send.
- if (!GetAuthBytes(kClientSslExporterLabel, auth_write_buf_->data())) {
- NotifyError();
- return;
- }
-
- DoAuthWrite();
+ authenticator_.reset(new ClientChannelAuthenticator(ssl_client_socket_));
} else {
- // Read an authentication digest.
- auth_read_buf_ = new net::GrowableIOBuffer();
- auth_read_buf_->SetCapacity(kAuthDigestLength);
- DoAuthRead();
+ authenticator_.reset(new HostChannelAuthenticator(ssl_server_socket_));
}
-}
-void JingleStreamConnector::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;
- }
+ authenticator_->Authenticate(
+ session_->shared_secret(),
+ base::Bind(&JingleStreamConnector::OnAuthenticationDone,
+ base::Unretained(this)));
}
-void JingleStreamConnector::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))
+void JingleStreamConnector::OnAuthenticationDone(
+ ChannelAuthenticator::Result result) {
+ switch (result) {
+ case ChannelAuthenticator::SUCCESS:
+ NotifyDone(socket_.release());
break;
- }
-}
-
-void JingleStreamConnector::OnAuthBytesWritten(int result) {
- if (HandleAuthBytesWritten(result))
- DoAuthWrite();
-}
-
-void JingleStreamConnector::OnAuthBytesRead(int result) {
- if (HandleAuthBytesRead(result))
- DoAuthRead();
-}
-bool JingleStreamConnector::HandleAuthBytesWritten(int result) {
- DCHECK(CalledOnValidThread());
-
- if (result <= 0) {
- LOG(ERROR) << "Error writing authentication: " << result;
- NotifyError();
- return false;
- }
-
- auth_write_buf_->DidConsume(result);
- if (auth_write_buf_->BytesRemaining() > 0)
- return true;
-
- NotifyDone(socket_.release());
- return false;
-}
-
-bool JingleStreamConnector::HandleAuthBytesRead(int read_result) {
- DCHECK(CalledOnValidThread());
-
- if (read_result <= 0) {
- LOG(ERROR) << "Error reading authentication: " << read_result;
- NotifyError();
- return false;
- }
-
- auth_read_buf_->set_offset(auth_read_buf_->offset() + read_result);
- if (auth_read_buf_->RemainingCapacity() > 0)
- return true;
-
- if (!VerifyAuthBytes(
- kClientSslExporterLabel,
- auth_read_buf_->StartOfBuffer())) {
- NotifyError();
- return false;
- }
-
- NotifyDone(socket_.release());
- return false;
-}
-
-bool JingleStreamConnector::VerifyAuthBytes(const char* label,
- const char* auth_bytes) {
- char expected[kAuthDigestLength];
- if (!GetAuthBytes(label, expected))
- return false;
- // Compare the received and expected digests in fixed time, to limit the
- // scope for timing attacks.
- uint8 result = 0;
- for (unsigned i = 0; i < sizeof(expected); i++) {
- result |= auth_bytes[i] ^ expected[i];
- }
- if (result != 0) {
- LOG(ERROR) << "Mismatched authentication";
- return false;
- }
- return true;
-}
-
-bool JingleStreamConnector::GetAuthBytes(const char* label,
- char* out_bytes) {
- // Fetch keying material from the socket.
- unsigned char key_material[kAuthDigestLength];
- int result;
- if (initiator_) {
- result = ssl_client_socket_->ExportKeyingMaterial(
- kClientSslExporterLabel, "", key_material, sizeof(key_material));
- } else {
- result = ssl_server_socket_->ExportKeyingMaterial(
- kClientSslExporterLabel, "", key_material, sizeof(key_material));
- }
- if (result != net::OK) {
- LOG(ERROR) << "Error fetching keying material: " << result;
- return false;
- }
-
- // Generate auth digest based on the keying material and shared secret.
- crypto::HMAC response(crypto::HMAC::SHA1);
- if (!response.Init(session_->shared_secret())) {
- NOTREACHED() << "HMAC::Init failed";
- return false;
- }
- base::StringPiece message(reinterpret_cast<const char*>(key_material),
- sizeof(key_material));
- if (!response.Sign(
- message,
- reinterpret_cast<unsigned char*>(out_bytes),
- kAuthDigestLength)) {
- NOTREACHED() << "HMAC::Sign failed";
- return false;
+ case ChannelAuthenticator::FAILURE:
+ NotifyError();
+ break;
}
-
- return true;
}
void JingleStreamConnector::NotifyDone(net::StreamSocket* socket) {
diff --git a/remoting/protocol/jingle_stream_connector.h b/remoting/protocol/jingle_stream_connector.h
index df003e3..6f7ce3b 100644
--- a/remoting/protocol/jingle_stream_connector.h
+++ b/remoting/protocol/jingle_stream_connector.h
@@ -5,9 +5,9 @@
#ifndef REMOTING_PROTOCOL_JINGLE_STREAM_CONNECTOR_H_
#define REMOTING_PROTOCOL_JINGLE_STREAM_CONNECTOR_H_
-#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/completion_callback.h"
+#include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/jingle_channel_connector.h"
#include "remoting/protocol/session.h"
@@ -61,14 +61,7 @@ class JingleStreamConnector : public JingleChannelConnector {
void OnSSLConnect(int result);
void AuthenticateChannel();
- void DoAuthWrite();
- void DoAuthRead();
- void OnAuthBytesWritten(int result);
- void OnAuthBytesRead(int result);
- bool HandleAuthBytesWritten(int result);
- bool HandleAuthBytesRead(int result);
- bool VerifyAuthBytes(const char* label, const char* auth_bytes);
- bool GetAuthBytes(const char* label, char* out_bytes);
+ void OnAuthenticationDone(ChannelAuthenticator::Result result);
void NotifyDone(net::StreamSocket* socket);
void NotifyError();
@@ -82,9 +75,6 @@ class JingleStreamConnector : public JingleChannelConnector {
std::string remote_cert_;
crypto::RSAPrivateKey* local_private_key_;
- scoped_refptr<net::DrainableIOBuffer> auth_write_buf_;
- scoped_refptr<net::GrowableIOBuffer> auth_read_buf_;
-
cricket::TransportChannel* raw_channel_;
scoped_ptr<net::StreamSocket> socket_;
@@ -95,11 +85,11 @@ class JingleStreamConnector : public JingleChannelConnector {
// 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::CompletionCallbackImpl<JingleStreamConnector> tcp_connect_callback_;
net::CompletionCallbackImpl<JingleStreamConnector> ssl_connect_callback_;
- net::CompletionCallbackImpl<JingleStreamConnector> auth_write_callback_;
- net::CompletionCallbackImpl<JingleStreamConnector> auth_read_callback_;
DISALLOW_COPY_AND_ASSIGN(JingleStreamConnector);
};
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 0bf9948..80799a8 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -580,6 +580,8 @@
'protocol/auth_token_utils.h',
'protocol/buffered_socket_writer.cc',
'protocol/buffered_socket_writer.h',
+ 'protocol/channel_authenticator.cc',
+ 'protocol/channel_authenticator.h',
'protocol/client_control_sender.cc',
'protocol/client_control_sender.h',
'protocol/client_message_dispatcher.cc',