diff options
-rw-r--r-- | remoting/client/chromoting_client.cc | 4 | ||||
-rw-r--r-- | remoting/client/client_config.h | 2 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_instance.h | 2 | ||||
-rw-r--r-- | remoting/protocol/it2me_host_authenticator_factory.cc | 7 | ||||
-rw-r--r-- | remoting/protocol/me2me_host_authenticator_factory.cc | 6 | ||||
-rw-r--r-- | remoting/protocol/negotiating_authenticator.cc | 261 | ||||
-rw-r--r-- | remoting/protocol/negotiating_authenticator_base.cc | 105 | ||||
-rw-r--r-- | remoting/protocol/negotiating_authenticator_base.h (renamed from remoting/protocol/negotiating_authenticator.h) | 91 | ||||
-rw-r--r-- | remoting/protocol/negotiating_authenticator_unittest.cc | 13 | ||||
-rw-r--r-- | remoting/protocol/negotiating_client_authenticator.cc | 117 | ||||
-rw-r--r-- | remoting/protocol/negotiating_client_authenticator.h | 67 | ||||
-rw-r--r-- | remoting/protocol/negotiating_host_authenticator.cc | 136 | ||||
-rw-r--r-- | remoting/protocol/negotiating_host_authenticator.h | 61 | ||||
-rw-r--r-- | remoting/remoting.gyp | 8 |
14 files changed, 534 insertions, 346 deletions
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc index c83002f..f9febdc 100644 --- a/remoting/client/chromoting_client.cc +++ b/remoting/client/chromoting_client.cc @@ -14,7 +14,7 @@ #include "remoting/proto/video.pb.h" #include "remoting/protocol/authentication_method.h" #include "remoting/protocol/connection_to_host.h" -#include "remoting/protocol/negotiating_authenticator.h" +#include "remoting/protocol/negotiating_client_authenticator.h" #include "remoting/protocol/session_config.h" #include "remoting/protocol/transport.h" @@ -53,7 +53,7 @@ void ChromotingClient::Start( DCHECK(task_runner_->BelongsToCurrentThread()); scoped_ptr<protocol::Authenticator> authenticator( - protocol::NegotiatingAuthenticator::CreateForClient( + new protocol::NegotiatingClientAuthenticator( config_.authentication_tag, config_.fetch_secret_callback, config_.authentication_methods)); diff --git a/remoting/client/client_config.h b/remoting/client/client_config.h index 8cc67b3..a7e87e9 100644 --- a/remoting/client/client_config.h +++ b/remoting/client/client_config.h @@ -10,7 +10,7 @@ #include "base/basictypes.h" #include "remoting/protocol/authentication_method.h" -#include "remoting/protocol/negotiating_authenticator.h" +#include "remoting/protocol/negotiating_client_authenticator.h" namespace remoting { diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h index e814eaf..a57275a 100644 --- a/remoting/client/plugin/chromoting_instance.h +++ b/remoting/client/plugin/chromoting_instance.h @@ -39,7 +39,7 @@ #include "remoting/protocol/cursor_shape_stub.h" #include "remoting/protocol/input_event_tracker.h" #include "remoting/protocol/mouse_input_filter.h" -#include "remoting/protocol/negotiating_authenticator.h" +#include "remoting/protocol/negotiating_client_authenticator.h" namespace base { class DictionaryValue; diff --git a/remoting/protocol/it2me_host_authenticator_factory.cc b/remoting/protocol/it2me_host_authenticator_factory.cc index 83fa6b6..e9f6c09 100644 --- a/remoting/protocol/it2me_host_authenticator_factory.cc +++ b/remoting/protocol/it2me_host_authenticator_factory.cc @@ -6,7 +6,7 @@ #include "base/logging.h" #include "remoting/base/rsa_key_pair.h" -#include "remoting/protocol/negotiating_authenticator.h" +#include "remoting/protocol/negotiating_host_authenticator.h" namespace remoting { namespace protocol { @@ -27,9 +27,8 @@ scoped_ptr<Authenticator> It2MeHostAuthenticatorFactory::CreateAuthenticator( const std::string& local_jid, const std::string& remote_jid, const buzz::XmlElement* first_message) { - return NegotiatingAuthenticator::CreateForHost( - local_cert_, key_pair_, shared_secret_, - AuthenticationMethod::NONE); + return scoped_ptr<Authenticator>(new NegotiatingHostAuthenticator( + local_cert_, key_pair_, shared_secret_, AuthenticationMethod::NONE)); } } // namespace protocol diff --git a/remoting/protocol/me2me_host_authenticator_factory.cc b/remoting/protocol/me2me_host_authenticator_factory.cc index 9a04d89..4ee7b65 100644 --- a/remoting/protocol/me2me_host_authenticator_factory.cc +++ b/remoting/protocol/me2me_host_authenticator_factory.cc @@ -8,7 +8,7 @@ #include "base/string_util.h" #include "remoting/base/rsa_key_pair.h" #include "remoting/protocol/channel_authenticator.h" -#include "remoting/protocol/negotiating_authenticator.h" +#include "remoting/protocol/negotiating_host_authenticator.h" #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" namespace remoting { @@ -91,9 +91,9 @@ scoped_ptr<Authenticator> Me2MeHostAuthenticatorFactory::CreateAuthenticator( return scoped_ptr<Authenticator>(new RejectingAuthenticator()); } - return NegotiatingAuthenticator::CreateForHost( + return scoped_ptr<Authenticator>(new NegotiatingHostAuthenticator( local_cert_, key_pair_, shared_secret_hash_.value, - shared_secret_hash_.hash_function); + shared_secret_hash_.hash_function)); } } // namespace protocol diff --git a/remoting/protocol/negotiating_authenticator.cc b/remoting/protocol/negotiating_authenticator.cc deleted file mode 100644 index c6ecacb..0000000 --- a/remoting/protocol/negotiating_authenticator.cc +++ /dev/null @@ -1,261 +0,0 @@ -// 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/bind.h" -#include "base/callback.h" -#include "base/logging.h" -#include "base/strings/string_split.h" -#include "remoting/base/rsa_key_pair.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 FetchSecretCallback& fetch_secret_callback, - const std::vector<AuthenticationMethod>& methods) { - scoped_ptr<NegotiatingAuthenticator> result( - new NegotiatingAuthenticator(MESSAGE_READY)); - result->authentication_tag_ = authentication_tag; - result->fetch_secret_callback_ = fetch_secret_callback; - - 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, - scoped_refptr<RsaKeyPair> key_pair, - 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_key_pair_ = key_pair; - 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), - weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { -} - -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, - const base::Closure& resume_callback) { - 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; - resume_callback.Run(); - 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; - resume_callback.Run(); - return; - } - - // Drop the current message because we've chosen a different - // method. - current_method_ = method; - state_ = PROCESSING_MESSAGE; - CreateAuthenticator(MESSAGE_READY, base::Bind( - &NegotiatingAuthenticator::UpdateState, - base::Unretained(this), resume_callback)); - return; - } - if (method != current_method_) { - current_method_ = method; - state_ = PROCESSING_MESSAGE; - // Copy the message since the authenticator may process it asynchronously. - CreateAuthenticator(WAITING_MESSAGE, base::Bind( - &NegotiatingAuthenticator::ProcessMessageInternal, - base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), - resume_callback)); - return; - } - ProcessMessageInternal(message, resume_callback); -} - -void NegotiatingAuthenticator::UpdateState( - const base::Closure& resume_callback) { - // After the underlying authenticator finishes processing the message, the - // NegotiatingAuthenticator must update its own state before running the - // |resume_callback| to resume the session negotiation. - state_ = current_authenticator_->state(); - if (state_ == REJECTED) - rejection_reason_ = current_authenticator_->rejection_reason(); - resume_callback.Run(); -} - -scoped_ptr<buzz::XmlElement> NegotiatingAuthenticator::GetNextMessage() { - DCHECK_EQ(state(), MESSAGE_READY); - - scoped_ptr<buzz::XmlElement> result; - - // No method yet, just send a message with the list of supported methods. - // Normally happens only on client. - if (!current_method_.is_valid()) { - result = CreateEmptyAuthenticatorMessage(); - 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()); - state_ = WAITING_MESSAGE; - } else { - if (current_authenticator_->state() == MESSAGE_READY) { - result = current_authenticator_->GetNextMessage(); - } else { - result = CreateEmptyAuthenticatorMessage(); - } - state_ = current_authenticator_->state(); - DCHECK(state_ == ACCEPTED || state_ == WAITING_MESSAGE); - result->AddAttr(kMethodAttributeQName, current_method_.ToString()); - } - - 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_key_pair_.get() != NULL; -} - -void NegotiatingAuthenticator::CreateAuthenticator( - Authenticator::State preferred_initial_state, - const base::Closure& resume_callback) { - if (is_host_side()) { - current_authenticator_ = V2Authenticator::CreateForHost( - local_cert_, local_key_pair_, shared_secret_hash_, - preferred_initial_state); - resume_callback.Run(); - } else { - fetch_secret_callback_.Run(base::Bind( - &NegotiatingAuthenticator::CreateV2AuthenticatorWithSecret, - weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback)); - } -} - -void NegotiatingAuthenticator::ProcessMessageInternal( - const buzz::XmlElement* message, - const base::Closure& resume_callback) { - if (current_authenticator_->state() == WAITING_MESSAGE) { - // If the message was not discarded and the authenticator is waiting for it, - // give it to the underlying authenticator to process. - // |current_authenticator_| is owned, so Unretained() is safe here. - current_authenticator_->ProcessMessage(message, base::Bind( - &NegotiatingAuthenticator::UpdateState, - base::Unretained(this), resume_callback)); - } -} - -void NegotiatingAuthenticator::CreateV2AuthenticatorWithSecret( - Authenticator::State initial_state, - const base::Closure& resume_callback, - const std::string& shared_secret) { - current_authenticator_ = V2Authenticator::CreateForClient( - AuthenticationMethod::ApplyHashFunction( - current_method_.hash_function(), authentication_tag_, shared_secret), - initial_state); - resume_callback.Run(); -} - -} // namespace protocol -} // namespace remoting diff --git a/remoting/protocol/negotiating_authenticator_base.cc b/remoting/protocol/negotiating_authenticator_base.cc new file mode 100644 index 0000000..2c2b4c5 --- /dev/null +++ b/remoting/protocol/negotiating_authenticator_base.cc @@ -0,0 +1,105 @@ +// 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_base.h" + +#include <algorithm> +#include <sstream> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/strings/string_split.h" +#include "remoting/base/rsa_key_pair.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 { + +const buzz::StaticQName NegotiatingAuthenticatorBase::kMethodAttributeQName = + { "", "method" }; +const buzz::StaticQName +NegotiatingAuthenticatorBase::kSupportedMethodsAttributeQName = + { "", "supported-methods" }; +const char NegotiatingAuthenticatorBase::kSupportedMethodsSeparator = ','; + +NegotiatingAuthenticatorBase::NegotiatingAuthenticatorBase( + Authenticator::State initial_state) + : current_method_(AuthenticationMethod::Invalid()), + state_(initial_state), + rejection_reason_(INVALID_CREDENTIALS) { +} + +NegotiatingAuthenticatorBase::~NegotiatingAuthenticatorBase() { +} + +Authenticator::State NegotiatingAuthenticatorBase::state() const { + return state_; +} + +Authenticator::RejectionReason +NegotiatingAuthenticatorBase::rejection_reason() const { + return rejection_reason_; +} + +void NegotiatingAuthenticatorBase::ProcessMessageInternal( + const buzz::XmlElement* message, + const base::Closure& resume_callback) { + if (current_authenticator_->state() == WAITING_MESSAGE) { + // If the message was not discarded and the authenticator is waiting for it, + // give it to the underlying authenticator to process. + // |current_authenticator_| is owned, so Unretained() is safe here. + current_authenticator_->ProcessMessage(message, base::Bind( + &NegotiatingAuthenticatorBase::UpdateState, + base::Unretained(this), resume_callback)); + } else { + // Otherwise, just discard the message and run the callback. + resume_callback.Run(); + } +} + +void NegotiatingAuthenticatorBase::UpdateState( + const base::Closure& resume_callback) { + // After the underlying authenticator finishes processing the message, the + // NegotiatingAuthenticatorBase must update its own state before running the + // |resume_callback| to resume the session negotiation. + state_ = current_authenticator_->state(); + if (state_ == REJECTED) + rejection_reason_ = current_authenticator_->rejection_reason(); + resume_callback.Run(); +} + +scoped_ptr<buzz::XmlElement> +NegotiatingAuthenticatorBase::GetNextMessageInternal() { + DCHECK_EQ(state(), MESSAGE_READY); + DCHECK(current_method_.is_valid()); + + scoped_ptr<buzz::XmlElement> result; + if (current_authenticator_->state() == MESSAGE_READY) { + result = current_authenticator_->GetNextMessage(); + } else { + result = CreateEmptyAuthenticatorMessage(); + } + state_ = current_authenticator_->state(); + DCHECK(state_ == ACCEPTED || state_ == WAITING_MESSAGE); + result->AddAttr(kMethodAttributeQName, current_method_.ToString()); + return result.Pass(); +} + +void NegotiatingAuthenticatorBase::AddMethod( + const AuthenticationMethod& method) { + DCHECK(method.is_valid()); + methods_.push_back(method); +} + +scoped_ptr<ChannelAuthenticator> +NegotiatingAuthenticatorBase::CreateChannelAuthenticator() const { + DCHECK_EQ(state(), ACCEPTED); + return current_authenticator_->CreateChannelAuthenticator(); +} + +} // namespace protocol +} // namespace remoting diff --git a/remoting/protocol/negotiating_authenticator.h b/remoting/protocol/negotiating_authenticator_base.h index 7166cf5..97209c5 100644 --- a/remoting/protocol/negotiating_authenticator.h +++ b/remoting/protocol/negotiating_authenticator_base.h @@ -2,8 +2,8 @@ // 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_ +#ifndef REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_BASE_H_ +#define REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_BASE_H_ #include <string> #include <vector> @@ -11,22 +11,16 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" -#include "remoting/protocol/authenticator.h" #include "remoting/protocol/authentication_method.h" +#include "remoting/protocol/authenticator.h" +#include "third_party/libjingle/source/talk/xmllite/xmlelement.h" namespace remoting { - -class RsaKeyPair; - namespace protocol { -typedef base::Callback<void(const std::string& secret)> SecretFetchedCallback; -typedef base::Callback<void( - const SecretFetchedCallback& secret_fetched_callback)> FetchSecretCallback; - -// This class provides a meta-authenticator that allows clients and hosts that -// support multiple authentication methods to negotiate a method to use. +// This class provides the common base for a meta-authenticator that allows +// clients and hosts that support multiple authentication methods to negotiate a +// method to use. // // The typical flow is: // * Client sends a message to host with its supported methods. @@ -64,84 +58,49 @@ typedef base::Callback<void( // the host picks a method from the client's list, it's final. // * Any change in this class must maintain compatibility between any version // mix of webapp, client plugin and host, for both Me2Me and IT2Me. -class NegotiatingAuthenticator : public Authenticator { +class NegotiatingAuthenticatorBase : public Authenticator { public: - virtual ~NegotiatingAuthenticator(); - - // Creates a client authenticator for the given methods. - static scoped_ptr<Authenticator> CreateForClient( - const std::string& authentication_tag, - const FetchSecretCallback& fetch_secret_callback, - const std::vector<AuthenticationMethod>& methods); - - // Creates a host authenticator, using a fixed shared secret/PIN hash. - static scoped_ptr<Authenticator> CreateForHost( - const std::string& local_cert, - scoped_refptr<RsaKeyPair> key_pair, - const std::string& shared_secret_hash, - AuthenticationMethod::HashFunction hash_function); + virtual ~NegotiatingAuthenticatorBase(); // Authenticator interface. virtual State state() const OVERRIDE; virtual RejectionReason rejection_reason() const OVERRIDE; - virtual void ProcessMessage(const buzz::XmlElement* message, - const base::Closure& resume_callback) OVERRIDE; - virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE; virtual scoped_ptr<ChannelAuthenticator> CreateChannelAuthenticator() const OVERRIDE; - private: - explicit NegotiatingAuthenticator(Authenticator::State initial_state); - - void AddMethod(const AuthenticationMethod& method); - - // (Asynchronously) creates an authenticator, and stores it in - // |current_authenticator_|. Authenticators that can be started in either - // state will be created in |preferred_initial_state|. - // |resume_callback| is called after |current_authenticator_| is set. - void CreateAuthenticator(Authenticator::State preferred_initial_state, - const base::Closure& resume_callback); - // Calls |current_authenticator_| to process |message|, passing the supplied // |resume_callback|. void ProcessMessageInternal(const buzz::XmlElement* message, - const base::Closure& resume_callback); + const base::Closure& resume_callback); - // Updates |state_| to reflect the current underlying authenticator state. - // |resume_callback| is called after the state is updated. - void UpdateState(const base::Closure& resume_callback); + protected: + static const buzz::StaticQName kMethodAttributeQName; + static const buzz::StaticQName kSupportedMethodsAttributeQName; + static const char kSupportedMethodsSeparator; - // Creates a V2Authenticator in state |initial_state| with the given - // |shared_secret|, then runs |resume_callback|. - void CreateV2AuthenticatorWithSecret( - Authenticator::State initial_state, - const base::Closure& resume_callback, - const std::string& shared_secret); + explicit NegotiatingAuthenticatorBase(Authenticator::State initial_state); - bool is_host_side() const; + void AddMethod(const AuthenticationMethod& method); - // Used only for host authenticators. - std::string local_cert_; - scoped_refptr<RsaKeyPair> local_key_pair_; - std::string shared_secret_hash_; + // Updates |state_| to reflect the current underlying authenticator state. + // |resume_callback| is called after the state is updated. + void UpdateState(const base::Closure& resume_callback); - // Used only for client authenticators. - std::string authentication_tag_; - FetchSecretCallback fetch_secret_callback_; + // Gets the next message from |current_authenticator_|, if any, and fills in + // the 'method' tag with |current_method_|. + virtual scoped_ptr<buzz::XmlElement> GetNextMessageInternal(); - // Used for both host and client authenticators. std::vector<AuthenticationMethod> methods_; AuthenticationMethod current_method_; scoped_ptr<Authenticator> current_authenticator_; State state_; RejectionReason rejection_reason_; - base::WeakPtrFactory<NegotiatingAuthenticator> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(NegotiatingAuthenticator); + private: + DISALLOW_COPY_AND_ASSIGN(NegotiatingAuthenticatorBase); }; } // namespace protocol } // namespace remoting -#endif // REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_H_ +#endif // REMOTING_PROTOCOL_NEGOTIATING_AUTHENTICATOR_BASE_H_ diff --git a/remoting/protocol/negotiating_authenticator_unittest.cc b/remoting/protocol/negotiating_authenticator_unittest.cc index b17fa6a..1a6e93f 100644 --- a/remoting/protocol/negotiating_authenticator_unittest.cc +++ b/remoting/protocol/negotiating_authenticator_unittest.cc @@ -2,14 +2,15 @@ // 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/base/rsa_key_pair.h" #include "remoting/protocol/authenticator_test_base.h" #include "remoting/protocol/channel_authenticator.h" #include "remoting/protocol/connection_tester.h" +#include "remoting/protocol/negotiating_authenticator_base.h" +#include "remoting/protocol/negotiating_client_authenticator.h" +#include "remoting/protocol/negotiating_host_authenticator.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" @@ -48,8 +49,8 @@ class NegotiatingAuthenticatorTest : public AuthenticatorTestBase { bool client_hmac_only) { std::string host_secret_hash = AuthenticationMethod::ApplyHashFunction( hash_function, kTestHostId, host_secret); - host_ = NegotiatingAuthenticator::CreateForHost( - host_cert_, key_pair_, host_secret_hash, hash_function); + host_.reset(new NegotiatingHostAuthenticator( + host_cert_, key_pair_, host_secret_hash, hash_function)); std::vector<AuthenticationMethod> methods; methods.push_back(AuthenticationMethod::Spake2( @@ -58,9 +59,9 @@ class NegotiatingAuthenticatorTest : public AuthenticatorTestBase { methods.push_back(AuthenticationMethod::Spake2( AuthenticationMethod::NONE)); } - client_ = NegotiatingAuthenticator::CreateForClient( + client_.reset(new NegotiatingClientAuthenticator( kTestHostId, base::Bind(&NegotiatingAuthenticatorTest::FetchSecret, - client_secret), methods); + client_secret), methods)); } static void FetchSecret( diff --git a/remoting/protocol/negotiating_client_authenticator.cc b/remoting/protocol/negotiating_client_authenticator.cc new file mode 100644 index 0000000..c7ab0f5 --- /dev/null +++ b/remoting/protocol/negotiating_client_authenticator.cc @@ -0,0 +1,117 @@ +// Copyright 2013 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_client_authenticator.h" + +#include <algorithm> +#include <sstream> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/strings/string_split.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 { + +NegotiatingClientAuthenticator::NegotiatingClientAuthenticator( + const std::string& authentication_tag, + const FetchSecretCallback& fetch_secret_callback, + const std::vector<AuthenticationMethod>& methods) + : NegotiatingAuthenticatorBase(MESSAGE_READY), + authentication_tag_(authentication_tag), + fetch_secret_callback_(fetch_secret_callback), + method_set_by_host_(false), + weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + DCHECK(!methods.empty()); + for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin(); + it != methods.end(); ++it) { + AddMethod(*it); + } +} + +NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() { +} + +void NegotiatingClientAuthenticator::ProcessMessage( + const buzz::XmlElement* message, + const base::Closure& resume_callback) { + DCHECK_EQ(state(), WAITING_MESSAGE); + + std::string method_attr = message->Attr(kMethodAttributeQName); + AuthenticationMethod method = AuthenticationMethod::FromString(method_attr); + + // The host picked a method different from the one the client had selected. + if (method != current_method_) { + // The host must pick a method that is valid and supported by the client, + // and it must not change methods after it has picked one. + if (method_set_by_host_ || !method.is_valid() || + std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { + state_ = REJECTED; + rejection_reason_ = PROTOCOL_ERROR; + resume_callback.Run(); + return; + } + + current_method_ = method; + method_set_by_host_ = true; + state_ = PROCESSING_MESSAGE; + // Copy the message since the authenticator may process it asynchronously. + CreateAuthenticator(WAITING_MESSAGE, base::Bind( + &NegotiatingAuthenticatorBase::ProcessMessageInternal, + base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), + resume_callback)); + return; + } + ProcessMessageInternal(message, resume_callback); +} + +scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { + DCHECK_EQ(state(), MESSAGE_READY); + // This is the first message to the host, send a list of supported methods. + if (!current_method_.is_valid()) { + // We currently send just an empty message with the supported list, but, in + // the future, the client may optimistically pick a method and send its + // first message, along with the supported methods. If the host doesn't + // support that method, it is free to ignore this first message and pick a + // different method from the supported list. + scoped_ptr<buzz::XmlElement> result = CreateEmptyAuthenticatorMessage(); + 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()); + state_ = WAITING_MESSAGE; + return result.Pass(); + } + return GetNextMessageInternal(); +} + +void NegotiatingClientAuthenticator::CreateAuthenticator( + Authenticator::State preferred_initial_state, + const base::Closure& resume_callback) { + fetch_secret_callback_.Run(base::Bind( + &NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret, + weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback)); +} + +void NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret( + Authenticator::State initial_state, + const base::Closure& resume_callback, + const std::string& shared_secret) { + current_authenticator_ = V2Authenticator::CreateForClient( + AuthenticationMethod::ApplyHashFunction( + current_method_.hash_function(), authentication_tag_, shared_secret), + initial_state); + resume_callback.Run(); +} + +} // namespace protocol +} // namespace remoting diff --git a/remoting/protocol/negotiating_client_authenticator.h b/remoting/protocol/negotiating_client_authenticator.h new file mode 100644 index 0000000..0927bd7 --- /dev/null +++ b/remoting/protocol/negotiating_client_authenticator.h @@ -0,0 +1,67 @@ +// Copyright 2013 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_CLIENT_AUTHENTICATOR_H_ +#define REMOTING_PROTOCOL_NEGOTIATING_CLIENT_AUTHENTICATOR_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "remoting/protocol/authentication_method.h" +#include "remoting/protocol/authenticator.h" +#include "remoting/protocol/negotiating_authenticator_base.h" + +namespace remoting { +namespace protocol { + +typedef base::Callback<void(const std::string& secret)> SecretFetchedCallback; +typedef base::Callback<void( + const SecretFetchedCallback& secret_fetched_callback)> FetchSecretCallback; + +// Client-side implementation of NegotiatingAuthenticatorBase. +// See comments in negotiating_authenticator_base.h for a general explanation. +class NegotiatingClientAuthenticator : public NegotiatingAuthenticatorBase { + public: + NegotiatingClientAuthenticator( + const std::string& authentication_tag, + const FetchSecretCallback& fetch_secret_callback, + const std::vector<AuthenticationMethod>& methods); + + virtual ~NegotiatingClientAuthenticator(); + + // Overriden from Authenticator. + virtual void ProcessMessage(const buzz::XmlElement* message, + const base::Closure& resume_callback) OVERRIDE; + virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE; + + private: + // (Asynchronously) creates an authenticator, and stores it in + // |current_authenticator_|. Authenticators that can be started in either + // state will be created in |preferred_initial_state|. + // |resume_callback| is called after |current_authenticator_| is set. + void CreateAuthenticator(Authenticator::State preferred_initial_state, + const base::Closure& resume_callback); + + // Creates a V2Authenticator in state |initial_state| with the given + // |shared_secret|, then runs |resume_callback|. + void CreateV2AuthenticatorWithSecret( + Authenticator::State initial_state, + const base::Closure& resume_callback, + const std::string& shared_secret); + + std::string authentication_tag_; + FetchSecretCallback fetch_secret_callback_; + bool method_set_by_host_; + base::WeakPtrFactory<NegotiatingClientAuthenticator> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(NegotiatingClientAuthenticator); +}; + +} // namespace protocol +} // namespace remoting + +#endif // REMOTING_PROTOCOL_NEGOTIATING_CLIENT_AUTHENTICATOR_H_ diff --git a/remoting/protocol/negotiating_host_authenticator.cc b/remoting/protocol/negotiating_host_authenticator.cc new file mode 100644 index 0000000..c54b6af --- /dev/null +++ b/remoting/protocol/negotiating_host_authenticator.cc @@ -0,0 +1,136 @@ +// Copyright 2013 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_host_authenticator.h" + +#include <algorithm> +#include <sstream> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/strings/string_split.h" +#include "remoting/base/rsa_key_pair.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 { + +NegotiatingHostAuthenticator::NegotiatingHostAuthenticator( + const std::string& local_cert, + scoped_refptr<RsaKeyPair> key_pair, + const std::string& shared_secret_hash, + AuthenticationMethod::HashFunction hash_function) + : NegotiatingAuthenticatorBase(WAITING_MESSAGE), + local_cert_(local_cert), + local_key_pair_(key_pair), + shared_secret_hash_(shared_secret_hash) { + + AddMethod(AuthenticationMethod::Spake2(hash_function)); +} + +NegotiatingHostAuthenticator::~NegotiatingHostAuthenticator() { +} + +void NegotiatingHostAuthenticator::ProcessMessage( + const buzz::XmlElement* message, + const base::Closure& resume_callback) { + DCHECK_EQ(state(), WAITING_MESSAGE); + + std::string method_attr = message->Attr(kMethodAttributeQName); + AuthenticationMethod method = AuthenticationMethod::FromString(method_attr); + + // If the host has already chosen a method, it can't be changed by the client. + if (current_method_.is_valid() && method != current_method_) { + state_ = REJECTED; + rejection_reason_ = PROTOCOL_ERROR; + resume_callback.Run(); + return; + } + + // If the client 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::find(methods_.begin(), methods_.end(), method) == methods_.end()) { + + method = AuthenticationMethod::Invalid(); + + 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; + resume_callback.Run(); + return; + } + + // Find the first mutually-supported method in the client'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; + resume_callback.Run(); + return; + } + + // Drop the current message because we've chosen a different method. + current_method_ = method; + state_ = PROCESSING_MESSAGE; + CreateAuthenticator(MESSAGE_READY, base::Bind( + &NegotiatingHostAuthenticator::UpdateState, + base::Unretained(this), resume_callback)); + return; + } + + // If the client specified a supported method, and the host hasn't chosen a + // method yet, use the client's preferred method and process the message. + if (!current_method_.is_valid()) { + current_method_ = method; + state_ = PROCESSING_MESSAGE; + // Copy the message since the authenticator may process it asynchronously. + CreateAuthenticator(WAITING_MESSAGE, base::Bind( + &NegotiatingAuthenticatorBase::ProcessMessageInternal, + base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), + resume_callback)); + return; + } + + // If the client is using the host's current method, just process the message. + ProcessMessageInternal(message, resume_callback); +} + +scoped_ptr<buzz::XmlElement> NegotiatingHostAuthenticator::GetNextMessage() { + return GetNextMessageInternal(); +} + +void NegotiatingHostAuthenticator::CreateAuthenticator( + Authenticator::State preferred_initial_state, + const base::Closure& resume_callback) { + current_authenticator_ = V2Authenticator::CreateForHost( + local_cert_, local_key_pair_, shared_secret_hash_, + preferred_initial_state); + resume_callback.Run(); +} + +} // namespace protocol +} // namespace remoting diff --git a/remoting/protocol/negotiating_host_authenticator.h b/remoting/protocol/negotiating_host_authenticator.h new file mode 100644 index 0000000..4ff53f6 --- /dev/null +++ b/remoting/protocol/negotiating_host_authenticator.h @@ -0,0 +1,61 @@ +// Copyright 2013 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_HOST_AUTHENTICATOR_H_ +#define REMOTING_PROTOCOL_NEGOTIATING_HOST_AUTHENTICATOR_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "remoting/protocol/authentication_method.h" +#include "remoting/protocol/authenticator.h" +#include "remoting/protocol/negotiating_authenticator_base.h" + +namespace remoting { + +class RsaKeyPair; + +namespace protocol { + +// Host-side implementation of NegotiatingAuthenticatorBase. +// See comments in negotiating_authenticator_base.h for a general explanation. +class NegotiatingHostAuthenticator : public NegotiatingAuthenticatorBase { + public: + // Creates a host authenticator, using a fixed shared secret/PIN hash. + NegotiatingHostAuthenticator( + const std::string& local_cert, + scoped_refptr<RsaKeyPair> key_pair, + const std::string& shared_secret_hash, + AuthenticationMethod::HashFunction hash_function); + + virtual ~NegotiatingHostAuthenticator(); + + // Overriden from Authenticator. + virtual void ProcessMessage(const buzz::XmlElement* message, + const base::Closure& resume_callback) OVERRIDE; + virtual scoped_ptr<buzz::XmlElement> GetNextMessage() OVERRIDE; + + private: + // (Asynchronously) creates an authenticator, and stores it in + // |current_authenticator_|. Authenticators that can be started in either + // state will be created in |preferred_initial_state|. + // |resume_callback| is called after |current_authenticator_| is set. + void CreateAuthenticator(Authenticator::State preferred_initial_state, + const base::Closure& resume_callback); + + std::string local_cert_; + scoped_refptr<RsaKeyPair> local_key_pair_; + std::string shared_secret_hash_; + + DISALLOW_COPY_AND_ASSIGN(NegotiatingHostAuthenticator); +}; + +} // namespace protocol +} // namespace remoting + +#endif // REMOTING_PROTOCOL_NEGOTIATING_HOST_AUTHENTICATOR_H_ diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 0fe1619..4db9587 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -2434,8 +2434,12 @@ 'protocol/mouse_input_filter.cc', 'protocol/mouse_input_filter.h', 'protocol/name_value_map.h', - 'protocol/negotiating_authenticator.cc', - 'protocol/negotiating_authenticator.h', + 'protocol/negotiating_authenticator_base.cc', + 'protocol/negotiating_authenticator_base.h', + 'protocol/negotiating_client_authenticator.cc', + 'protocol/negotiating_client_authenticator.h', + 'protocol/negotiating_host_authenticator.cc', + 'protocol/negotiating_host_authenticator.h', 'protocol/protobuf_video_reader.cc', 'protocol/protobuf_video_reader.h', 'protocol/protobuf_video_writer.cc', |