summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--remoting/protocol/authentication_method.cc47
-rw-r--r--remoting/protocol/authentication_method.h20
-rw-r--r--remoting/protocol/me2me_host_authenticator_factory.cc3
-rw-r--r--remoting/protocol/negotiating_authenticator.cc223
-rw-r--r--remoting/protocol/negotiating_authenticator.h77
-rw-r--r--remoting/protocol/negotiating_authenticator_unittest.cc150
-rw-r--r--remoting/protocol/v2_authenticator.cc21
-rw-r--r--remoting/protocol/v2_authenticator.h15
-rw-r--r--remoting/protocol/v2_authenticator_unittest.cc5
-rw-r--r--remoting/remoting.gyp3
10 files changed, 522 insertions, 42 deletions
diff --git a/remoting/protocol/authentication_method.cc b/remoting/protocol/authentication_method.cc
index ebee009..0082126 100644
--- a/remoting/protocol/authentication_method.cc
+++ b/remoting/protocol/authentication_method.cc
@@ -42,25 +42,12 @@ AuthenticationMethod AuthenticationMethod::FromString(
}
}
-AuthenticationMethod::AuthenticationMethod()
- : invalid_(true),
- version_(VERSION_2),
- hash_function_(NONE) {
-}
-
-AuthenticationMethod::AuthenticationMethod(Version version,
- HashFunction hash_function)
- : invalid_(false),
- version_(version),
- hash_function_(hash_function) {
-}
-
+// static
std::string AuthenticationMethod::ApplyHashFunction(
+ HashFunction hash_function,
const std::string& tag,
const std::string& shared_secret) {
- DCHECK(is_valid());
-
- switch (hash_function_) {
+ switch (hash_function) {
case NONE:
return shared_secret;
break;
@@ -84,10 +71,23 @@ std::string AuthenticationMethod::ApplyHashFunction(
return shared_secret;
}
+AuthenticationMethod::AuthenticationMethod()
+ : invalid_(true),
+ version_(VERSION_2),
+ hash_function_(NONE) {
+}
+
+AuthenticationMethod::AuthenticationMethod(Version version,
+ HashFunction hash_function)
+ : invalid_(false),
+ version_(version),
+ hash_function_(hash_function) {
+}
+
scoped_ptr<Authenticator> AuthenticationMethod::CreateAuthenticator(
const std::string& local_jid,
const std::string& tag,
- const std::string& shared_secret) {
+ const std::string& shared_secret) const {
DCHECK(is_valid());
switch (version_) {
@@ -98,7 +98,8 @@ scoped_ptr<Authenticator> AuthenticationMethod::CreateAuthenticator(
case VERSION_2:
return protocol::V2Authenticator::CreateForClient(
- ApplyHashFunction(tag, shared_secret));
+ ApplyHashFunction(hash_function_, tag, shared_secret),
+ Authenticator::MESSAGE_READY);
}
NOTREACHED();
@@ -135,5 +136,15 @@ const std::string AuthenticationMethod::ToString() const {
return "";
}
+bool AuthenticationMethod::operator ==(
+ const AuthenticationMethod& other) const {
+ if (!is_valid())
+ return !other.is_valid();
+ if (!other.is_valid())
+ return false;
+ return version_ == other.version_ &&
+ hash_function_ == other.hash_function_;
+}
+
} // namespace protocol
} // namespace remoting
diff --git a/remoting/protocol/authentication_method.h b/remoting/protocol/authentication_method.h
index 402e3bc..6b94a06 100644
--- a/remoting/protocol/authentication_method.h
+++ b/remoting/protocol/authentication_method.h
@@ -49,6 +49,12 @@ class AuthenticationMethod {
// invalid value if the string is invalid.
static AuthenticationMethod FromString(const std::string& value);
+ // Applies the specified hash function to |shared_secret| with the
+ // specified |tag| as a key.
+ static std::string ApplyHashFunction(HashFunction hash_function,
+ const std::string& tag,
+ const std::string& shared_secret);
+
// Returns true
bool is_valid() const { return !invalid_; }
@@ -63,16 +69,18 @@ class AuthenticationMethod {
// Returns string representation of the value stored in this object.
const std::string ToString() const;
- // Applies the current hash function to |shared_secret| with the
- // specified |tag| as a key.
- std::string ApplyHashFunction(const std::string& tag,
- const std::string& shared_secret);
-
// Creates client authenticator using the specified parameters.
scoped_ptr<Authenticator> CreateAuthenticator(
const std::string& local_jid,
const std::string& tag,
- const std::string& shared_secret);
+ const std::string& shared_secret) const;
+
+ // Comparison operators so that std::find() can be used with
+ // collections of this class.
+ bool operator ==(const AuthenticationMethod& other) const;
+ bool operator !=(const AuthenticationMethod& other) const {
+ return !(*this == other);
+ }
private:
AuthenticationMethod();
diff --git a/remoting/protocol/me2me_host_authenticator_factory.cc b/remoting/protocol/me2me_host_authenticator_factory.cc
index c4c6052..21272cf 100644
--- a/remoting/protocol/me2me_host_authenticator_factory.cc
+++ b/remoting/protocol/me2me_host_authenticator_factory.cc
@@ -109,7 +109,8 @@ scoped_ptr<Authenticator> Me2MeHostAuthenticatorFactory::CreateAuthenticator(
if (V2Authenticator::IsEkeMessage(first_message)) {
return V2Authenticator::CreateForHost(
- local_cert_, *local_private_key_, shared_secret_hash_.value);
+ local_cert_, *local_private_key_, shared_secret_hash_.value,
+ Authenticator::WAITING_MESSAGE);
}
// TODO(sergeyu): Old clients still use V1 auth protocol. Remove
diff --git a/remoting/protocol/negotiating_authenticator.cc b/remoting/protocol/negotiating_authenticator.cc
new file mode 100644
index 0000000..55e1d78
--- /dev/null
+++ b/remoting/protocol/negotiating_authenticator.cc
@@ -0,0 +1,223 @@
+// Copyright (c) 2012 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/negotiating_authenticator.h"
+
+#include <algorithm>
+#include <sstream>
+
+#include "base/logging.h"
+#include "base/string_split.h"
+#include "crypto/rsa_private_key.h"
+#include "remoting/protocol/channel_authenticator.h"
+#include "remoting/protocol/v2_authenticator.h"
+#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
+
+namespace remoting {
+namespace protocol {
+
+namespace {
+
+const buzz::StaticQName kMethodAttributeQName = { "", "method" };
+const buzz::StaticQName kSupportedMethodsAttributeQName =
+ { "", "supported-methods" };
+
+const char kSupportedMethodsSeparator = ',';
+
+} // namespace
+
+// static
+scoped_ptr<Authenticator> NegotiatingAuthenticator::CreateForClient(
+ const std::string& authentication_tag,
+ const std::string& shared_secret,
+ const std::vector<AuthenticationMethod>& methods) {
+ scoped_ptr<NegotiatingAuthenticator> result(
+ new NegotiatingAuthenticator(MESSAGE_READY));
+ result->authentication_tag_ = authentication_tag;
+ result->shared_secret_ = shared_secret;
+
+ DCHECK(!methods.empty());
+ for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin();
+ it != methods.end(); ++it) {
+ result->AddMethod(*it);
+ }
+
+ return scoped_ptr<Authenticator>(result.Pass());
+}
+
+// static
+scoped_ptr<Authenticator> NegotiatingAuthenticator::CreateForHost(
+ const std::string& local_cert,
+ const crypto::RSAPrivateKey& local_private_key,
+ const std::string& shared_secret_hash,
+ AuthenticationMethod::HashFunction hash_function) {
+ scoped_ptr<NegotiatingAuthenticator> result(
+ new NegotiatingAuthenticator(WAITING_MESSAGE));
+ result->local_cert_ = local_cert;
+ result->local_private_key_.reset(local_private_key.Copy());
+ result->shared_secret_hash_ = shared_secret_hash;
+
+ result->AddMethod(AuthenticationMethod::Spake2(hash_function));
+
+ return scoped_ptr<Authenticator>(result.Pass());
+}
+
+
+NegotiatingAuthenticator::NegotiatingAuthenticator(
+ Authenticator::State initial_state)
+ : current_method_(AuthenticationMethod::Invalid()),
+ state_(initial_state),
+ rejection_reason_(INVALID_CREDENTIALS) {
+}
+
+NegotiatingAuthenticator::~NegotiatingAuthenticator() {
+}
+
+Authenticator::State NegotiatingAuthenticator::state() const {
+ return state_;
+}
+
+Authenticator::RejectionReason
+NegotiatingAuthenticator::rejection_reason() const {
+ return rejection_reason_;
+}
+
+void NegotiatingAuthenticator::ProcessMessage(const buzz::XmlElement* message) {
+ DCHECK_EQ(state(), WAITING_MESSAGE);
+
+ std::string method_attr = message->Attr(kMethodAttributeQName);
+ AuthenticationMethod method = AuthenticationMethod::FromString(method_attr);
+
+ // Check if the remote end specified a method that is not supported locally.
+ if (method.is_valid() &&
+ std::find(methods_.begin(), methods_.end(), method) == methods_.end()) {
+ method = AuthenticationMethod::Invalid();
+ }
+
+ // If the remote peer did not specify auth method or specified unknown
+ // method then select the first known method from the supported-methods
+ // attribute.
+ if (!method.is_valid()) {
+ std::string supported_methods_attr =
+ message->Attr(kSupportedMethodsAttributeQName);
+ if (supported_methods_attr.empty()) {
+ // Message contains neither method nor supported-methods attributes.
+ state_ = REJECTED;
+ rejection_reason_ = PROTOCOL_ERROR;
+ return;
+ }
+
+ // Find the first mutually-supported method in the peer's list of
+ // supported-methods.
+ std::vector<std::string> supported_methods_strs;
+ base::SplitString(supported_methods_attr, kSupportedMethodsSeparator,
+ &supported_methods_strs);
+ for (std::vector<std::string>::iterator it = supported_methods_strs.begin();
+ it != supported_methods_strs.end(); ++it) {
+ AuthenticationMethod list_value = AuthenticationMethod::FromString(*it);
+ if (list_value.is_valid() &&
+ std::find(methods_.begin(),
+ methods_.end(), list_value) != methods_.end()) {
+ // Found common method.
+ method = list_value;
+ break;
+ }
+ }
+
+ if (!method.is_valid()) {
+ // Failed to find a common auth method.
+ state_ = REJECTED;
+ rejection_reason_ = PROTOCOL_ERROR;
+ return;
+ }
+
+ // Drop the current message because we've chosen a different
+ // method.
+ state_ = MESSAGE_READY;
+ }
+
+ DCHECK(method.is_valid());
+
+ // Replace current authenticator if the method has changed.
+ if (method != current_method_) {
+ current_method_ = method;
+ CreateAuthenticator(state_);
+ }
+
+ if (state_ == WAITING_MESSAGE) {
+ current_authenticator_->ProcessMessage(message);
+ state_ = current_authenticator_->state();
+ if (state_ == REJECTED)
+ rejection_reason_ = current_authenticator_->rejection_reason();
+ }
+}
+
+scoped_ptr<buzz::XmlElement> NegotiatingAuthenticator::GetNextMessage() {
+ DCHECK_EQ(state(), MESSAGE_READY);
+
+ bool add_supported_methods_attr = false;
+
+ // Initialize current method in case it is not initialized
+ // yet. Normally happens only on client.
+ if (!current_method_.is_valid()) {
+ CHECK(!methods_.empty());
+
+ // Initially try the first method.
+ current_method_ = methods_[0];
+ CreateAuthenticator(MESSAGE_READY);
+ add_supported_methods_attr = true;
+ }
+
+ scoped_ptr<buzz::XmlElement> result =
+ current_authenticator_->GetNextMessage();
+ state_ = current_authenticator_->state();
+ DCHECK_NE(state_, REJECTED);
+
+ result->AddAttr(kMethodAttributeQName, current_method_.ToString());
+
+ if (add_supported_methods_attr) {
+ std::stringstream supported_methods(std::stringstream::out);
+ for (std::vector<AuthenticationMethod>::iterator it = methods_.begin();
+ it != methods_.end(); ++it) {
+ if (it != methods_.begin())
+ supported_methods << kSupportedMethodsSeparator;
+ supported_methods << it->ToString();
+ }
+ result->AddAttr(kSupportedMethodsAttributeQName, supported_methods.str());
+ }
+
+ return result.Pass();
+}
+
+void NegotiatingAuthenticator::AddMethod(const AuthenticationMethod& method) {
+ DCHECK(method.is_valid());
+ methods_.push_back(method);
+}
+
+scoped_ptr<ChannelAuthenticator>
+NegotiatingAuthenticator::CreateChannelAuthenticator() const {
+ DCHECK_EQ(state(), ACCEPTED);
+ return current_authenticator_->CreateChannelAuthenticator();
+}
+
+bool NegotiatingAuthenticator::is_host_side() const {
+ return local_private_key_.get() != NULL;
+}
+
+void NegotiatingAuthenticator::CreateAuthenticator(State initial_state) {
+ if (is_host_side()) {
+ current_authenticator_ = V2Authenticator::CreateForHost(
+ local_cert_, *local_private_key_.get(),
+ shared_secret_hash_, initial_state);
+ } else {
+ current_authenticator_ = V2Authenticator::CreateForClient(
+ AuthenticationMethod::ApplyHashFunction(
+ current_method_.hash_function(),
+ authentication_tag_, shared_secret_),
+ initial_state);
+ }
+}
+
+} // namespace protocol
+} // namespace remoting
diff --git a/remoting/protocol/negotiating_authenticator.h b/remoting/protocol/negotiating_authenticator.h
new file mode 100644
index 0000000..beda194
--- /dev/null
+++ b/remoting/protocol/negotiating_authenticator.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 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_NEGOTIATING_AUTHENTICATOR_H_
+#define REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "remoting/protocol/authenticator.h"
+#include "remoting/protocol/authentication_method.h"
+
+namespace crypto {
+class RSAPrivateKey;
+} // namespace crypto
+
+namespace remoting {
+namespace protocol {
+
+class NegotiatingAuthenticator : public Authenticator {
+ public:
+ virtual ~NegotiatingAuthenticator();
+
+ static scoped_ptr<Authenticator> CreateForClient(
+ const std::string& authentication_tag,
+ const std::string& shared_secret,
+ const std::vector<AuthenticationMethod>& methods);
+
+ static scoped_ptr<Authenticator> CreateForHost(
+ const std::string& local_cert,
+ const crypto::RSAPrivateKey& local_private_key,
+ const std::string& shared_secret_hash,
+ AuthenticationMethod::HashFunction hash_function);
+
+ // Authenticator interface.
+ virtual State state() const OVERRIDE;
+ virtual RejectionReason rejection_reason() const OVERRIDE;
+ virtual void ProcessMessage(const buzz::XmlElement* message) OVERRIDE;
+ virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE;
+ virtual scoped_ptr<ChannelAuthenticator>
+ CreateChannelAuthenticator() const OVERRIDE;
+
+ private:
+ NegotiatingAuthenticator(Authenticator::State initial_state);
+
+ void AddMethod(const AuthenticationMethod& method);
+ void CreateAuthenticator(State initial_state);
+ bool is_host_side() const;
+
+ // Used only for host authenticators.
+ std::string local_cert_;
+ scoped_ptr<crypto::RSAPrivateKey> local_private_key_;
+ bool certificate_sent_;
+ std::string shared_secret_hash_;
+
+ // Used only for client authenticators.
+ std::string remote_cert_;
+ std::string authentication_tag_;
+ std::string shared_secret_;
+
+ // Used for both host and client authenticators.
+ std::vector<AuthenticationMethod> methods_;
+ AuthenticationMethod current_method_;
+ scoped_ptr<Authenticator> current_authenticator_;
+ State state_;
+ RejectionReason rejection_reason_;
+
+ DISALLOW_COPY_AND_ASSIGN(NegotiatingAuthenticator);
+};
+
+} // namespace protocol
+} // namespace remoting
+
+#endif // REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_H_
diff --git a/remoting/protocol/negotiating_authenticator_unittest.cc b/remoting/protocol/negotiating_authenticator_unittest.cc
new file mode 100644
index 0000000..e62a8e3
--- /dev/null
+++ b/remoting/protocol/negotiating_authenticator_unittest.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 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/negotiating_authenticator.h"
+
+#include "base/bind.h"
+#include "net/base/net_errors.h"
+#include "remoting/protocol/authenticator_test_base.h"
+#include "remoting/protocol/channel_authenticator.h"
+#include "remoting/protocol/connection_tester.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
+
+using testing::_;
+using testing::DeleteArg;
+using testing::SaveArg;
+
+namespace remoting {
+namespace protocol {
+
+namespace {
+
+const int kMessageSize = 100;
+const int kMessages = 1;
+
+const char kTestHostId[] = "12345678910123456";
+
+const char kTestSharedSecret[] = "1234-1234-5678";
+const char kTestSharedSecretBad[] = "0000-0000-0001";
+
+} // namespace
+
+class NegotiatingAuthenticatorTest : public AuthenticatorTestBase {
+ public:
+ NegotiatingAuthenticatorTest() {
+ }
+ virtual ~NegotiatingAuthenticatorTest() {
+ }
+
+ protected:
+ void InitAuthenticators(
+ const std::string& client_secret,
+ const std::string& host_secret,
+ AuthenticationMethod::HashFunction hash_function,
+ bool client_hmac_only) {
+ std::string host_secret_hash = AuthenticationMethod::ApplyHashFunction(
+ hash_function, kTestHostId, host_secret);
+ host_ = NegotiatingAuthenticator::CreateForHost(
+ host_cert_, *private_key_, host_secret_hash, hash_function);
+
+ std::vector<AuthenticationMethod> methods;
+ methods.push_back(AuthenticationMethod::Spake2(
+ AuthenticationMethod::HMAC_SHA256));
+ if (!client_hmac_only) {
+ methods.push_back(AuthenticationMethod::Spake2(
+ AuthenticationMethod::NONE));
+ }
+ client_ = NegotiatingAuthenticator::CreateForClient(
+ kTestHostId, client_secret, methods);
+ }
+
+ void VerifyRejected(Authenticator::RejectionReason reason) {
+ ASSERT_TRUE((client_->state() == Authenticator::REJECTED &&
+ (client_->rejection_reason() == reason)) ||
+ (host_->state() == Authenticator::REJECTED &&
+ (host_->rejection_reason() == reason)));
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(NegotiatingAuthenticatorTest);
+};
+
+TEST_F(NegotiatingAuthenticatorTest, SuccessfulAuthHmac) {
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
+ kTestSharedSecret, kTestSharedSecret,
+ AuthenticationMethod::HMAC_SHA256, false));
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
+
+ ASSERT_EQ(Authenticator::ACCEPTED, host_->state());
+ ASSERT_EQ(Authenticator::ACCEPTED, client_->state());
+
+ client_auth_ = client_->CreateChannelAuthenticator();
+ host_auth_ = host_->CreateChannelAuthenticator();
+ RunChannelAuth(false);
+
+ EXPECT_TRUE(client_socket_.get() != NULL);
+ EXPECT_TRUE(host_socket_.get() != NULL);
+
+ StreamConnectionTester tester(host_socket_.get(), client_socket_.get(),
+ kMessageSize, kMessages);
+
+ tester.Start();
+ message_loop_.Run();
+ tester.CheckResults();
+}
+
+TEST_F(NegotiatingAuthenticatorTest, SuccessfulAuthPlain) {
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
+ kTestSharedSecret, kTestSharedSecret,
+ AuthenticationMethod::NONE, false));
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
+
+ ASSERT_EQ(Authenticator::ACCEPTED, host_->state());
+ ASSERT_EQ(Authenticator::ACCEPTED, client_->state());
+
+ client_auth_ = client_->CreateChannelAuthenticator();
+ host_auth_ = host_->CreateChannelAuthenticator();
+ RunChannelAuth(false);
+
+ EXPECT_TRUE(client_socket_.get() != NULL);
+ EXPECT_TRUE(host_socket_.get() != NULL);
+
+ StreamConnectionTester tester(host_socket_.get(), client_socket_.get(),
+ kMessageSize, kMessages);
+
+ tester.Start();
+ message_loop_.Run();
+ tester.CheckResults();
+}
+
+TEST_F(NegotiatingAuthenticatorTest, InvalidSecretHmac) {
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
+ kTestSharedSecret, kTestSharedSecretBad,
+ AuthenticationMethod::HMAC_SHA256, false));
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
+
+ VerifyRejected(Authenticator::INVALID_CREDENTIALS);
+}
+
+TEST_F(NegotiatingAuthenticatorTest, InvalidSecretPlain) {
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
+ kTestSharedSecret, kTestSharedSecretBad,
+ AuthenticationMethod::NONE, false));
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
+
+ VerifyRejected(Authenticator::INVALID_CREDENTIALS);
+}
+
+TEST_F(NegotiatingAuthenticatorTest, IncompatibleMethods) {
+ ASSERT_NO_FATAL_FAILURE(InitAuthenticators(
+ kTestSharedSecret, kTestSharedSecretBad,
+ AuthenticationMethod::NONE, true));
+ ASSERT_NO_FATAL_FAILURE(RunAuthExchange());
+
+ VerifyRejected(Authenticator::PROTOCOL_ERROR);
+}
+
+} // namespace protocol
+} // namespace remoting
diff --git a/remoting/protocol/v2_authenticator.cc b/remoting/protocol/v2_authenticator.cc
index 9e1184c..95b42d5 100644
--- a/remoting/protocol/v2_authenticator.cc
+++ b/remoting/protocol/v2_authenticator.cc
@@ -36,30 +36,32 @@ bool V2Authenticator::IsEkeMessage(const buzz::XmlElement* message) {
// static
scoped_ptr<Authenticator> V2Authenticator::CreateForClient(
- const std::string& shared_secret) {
+ const std::string& shared_secret,
+ Authenticator::State initial_state) {
return scoped_ptr<Authenticator>(new V2Authenticator(
- P224EncryptedKeyExchange::kPeerTypeClient, shared_secret));
+ P224EncryptedKeyExchange::kPeerTypeClient, shared_secret, initial_state));
}
// static
scoped_ptr<Authenticator> V2Authenticator::CreateForHost(
const std::string& local_cert,
const crypto::RSAPrivateKey& local_private_key,
- const std::string& shared_secret) {
- V2Authenticator* result = new V2Authenticator(
- P224EncryptedKeyExchange::kPeerTypeServer, shared_secret);
+ const std::string& shared_secret,
+ Authenticator::State initial_state) {
+ scoped_ptr<V2Authenticator> result(new V2Authenticator(
+ P224EncryptedKeyExchange::kPeerTypeServer, shared_secret, initial_state));
result->local_cert_ = local_cert;
result->local_private_key_.reset(local_private_key.Copy());
- result->state_ = WAITING_MESSAGE;
- return scoped_ptr<Authenticator>(result);
+ return scoped_ptr<Authenticator>(result.Pass());
}
V2Authenticator::V2Authenticator(
crypto::P224EncryptedKeyExchange::PeerType type,
- const std::string& shared_secret)
+ const std::string& shared_secret,
+ Authenticator::State initial_state)
: certificate_sent_(false),
key_exchange_impl_(type, shared_secret),
- state_(MESSAGE_READY),
+ state_(initial_state),
rejection_reason_(INVALID_CREDENTIALS) {
pending_messages_.push(key_exchange_impl_.GetMessage());
}
@@ -168,6 +170,7 @@ scoped_ptr<buzz::XmlElement> V2Authenticator::GetNextMessage() {
}
certificate_tag->SetBodyText(base64_cert);
message->AddElement(certificate_tag);
+ certificate_sent_ = true;
}
if (state_ != ACCEPTED) {
diff --git a/remoting/protocol/v2_authenticator.h b/remoting/protocol/v2_authenticator.h
index cd492b1..ef6503c 100644
--- a/remoting/protocol/v2_authenticator.h
+++ b/remoting/protocol/v2_authenticator.h
@@ -26,12 +26,14 @@ class V2Authenticator : public Authenticator {
static bool IsEkeMessage(const buzz::XmlElement* message);
static scoped_ptr<Authenticator> CreateForClient(
- const std::string& shared_secret);
+ const std::string& shared_secret,
+ State initial_state);
static scoped_ptr<Authenticator> CreateForHost(
const std::string& local_cert,
const crypto::RSAPrivateKey& local_private_key,
- const std::string& shared_secret);
+ const std::string& shared_secret,
+ State initial_state);
virtual ~V2Authenticator();
@@ -47,19 +49,20 @@ class V2Authenticator : public Authenticator {
FRIEND_TEST_ALL_PREFIXES(V2AuthenticatorTest, InvalidSecret);
V2Authenticator(crypto::P224EncryptedKeyExchange::PeerType type,
- const std::string& shared_secret);
+ const std::string& shared_secret,
+ State initial_state);
bool is_host_side() const;
- // Used only for HOST authenticators.
+ // Used only for host authenticators.
std::string local_cert_;
scoped_ptr<crypto::RSAPrivateKey> local_private_key_;
bool certificate_sent_;
- // Used only for CLIENT authenticators.
+ // Used only for client authenticators.
std::string remote_cert_;
- // Used for both HOST and CLIENT authenticators.
+ // Used for both host and client authenticators.
crypto::P224EncryptedKeyExchange key_exchange_impl_;
State state_;
RejectionReason rejection_reason_;
diff --git a/remoting/protocol/v2_authenticator_unittest.cc b/remoting/protocol/v2_authenticator_unittest.cc
index fe2458e..0d634e4 100644
--- a/remoting/protocol/v2_authenticator_unittest.cc
+++ b/remoting/protocol/v2_authenticator_unittest.cc
@@ -41,8 +41,9 @@ class V2AuthenticatorTest : public AuthenticatorTestBase {
void InitAuthenticators(const std::string& client_secret,
const std::string& host_secret) {
host_ = V2Authenticator::CreateForHost(
- host_cert_, *private_key_, host_secret);
- client_ = V2Authenticator::CreateForClient(client_secret);
+ host_cert_, *private_key_, host_secret, Authenticator::WAITING_MESSAGE);
+ client_ = V2Authenticator::CreateForClient(
+ client_secret, Authenticator::MESSAGE_READY);
}
DISALLOW_COPY_AND_ASSIGN(V2AuthenticatorTest);
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 3df81a2..996edab 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -795,6 +795,8 @@
'protocol/message_decoder.h',
'protocol/message_reader.cc',
'protocol/message_reader.h',
+ 'protocol/negotiating_authenticator.cc',
+ 'protocol/negotiating_authenticator.h',
'protocol/pepper_channel.h',
'protocol/pepper_session.cc',
'protocol/pepper_session.h',
@@ -955,6 +957,7 @@
'protocol/key_event_tracker_unittest.cc',
'protocol/message_decoder_unittest.cc',
'protocol/message_reader_unittest.cc',
+ 'protocol/negotiating_authenticator_unittest.cc',
'protocol/pepper_session_unittest.cc',
'protocol/protocol_mock_objects.cc',
'protocol/protocol_mock_objects.h',