Commit 843ef124 authored by sergeyu's avatar sergeyu Committed by Commit bot

Handle pairing client ID in the negotiating authenticators.

Previously PairingAuthenticator classes were responsible for handling
client ID. This meant that in case there are multiple pairing
authentication methods the client would have to resend the client_id
if the host chooses different authentication method. Now the client
ID is handled by the negotiating layer, so client_id needs to be sent
only once.

Also now NegotiatingAuthenticators create PairingAuthenticators even
when falling back to PIN. This ensures that <pairing-failed> tag is
always present when falling back to PIN.

BUG=593123

Review URL: https://codereview.chromium.org/1781173005

Cr-Commit-Position: refs/heads/master@{#381633}
parent 81412f81
...@@ -40,7 +40,9 @@ class Authenticator { ...@@ -40,7 +40,9 @@ class Authenticator {
// WAITING_MESSAGE -> REJECTED // WAITING_MESSAGE -> REJECTED
// WAITING_MESSAGE -> PROCESSING_MESSAGE // WAITING_MESSAGE -> PROCESSING_MESSAGE
// After asynchronous message processing finishes: // After asynchronous message processing finishes:
/// PROCESSING_MESSAGE -> MESSAGE_READY // PROCESSING_MESSAGE -> MESSAGE_READY
// PROCESSING_MESSAGE -> ACCEPTED
// PROCESSING_MESSAGE -> REJECTED
// When GetNextMessage() is called: // When GetNextMessage() is called:
// MESSAGE_READY -> WAITING_MESSAGE // MESSAGE_READY -> WAITING_MESSAGE
// MESSAGE_READY -> ACCEPTED // MESSAGE_READY -> ACCEPTED
......
...@@ -87,8 +87,9 @@ void AuthenticatorTestBase::ContinueAuthExchangeWith(Authenticator* sender, ...@@ -87,8 +87,9 @@ void AuthenticatorTestBase::ContinueAuthExchangeWith(Authenticator* sender,
scoped_ptr<buzz::XmlElement> message; scoped_ptr<buzz::XmlElement> message;
ASSERT_NE(Authenticator::WAITING_MESSAGE, sender->state()); ASSERT_NE(Authenticator::WAITING_MESSAGE, sender->state());
if (sender->state() == Authenticator::ACCEPTED || if (sender->state() == Authenticator::ACCEPTED ||
sender->state() == Authenticator::REJECTED) sender->state() == Authenticator::REJECTED) {
return; return;
}
// Verify that once the started flag for either party is set to true, // Verify that once the started flag for either party is set to true,
// it should always stay true. // it should always stay true.
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "remoting/base/constants.h"
#include "remoting/base/rsa_key_pair.h" #include "remoting/base/rsa_key_pair.h"
#include "remoting/protocol/channel_authenticator.h" #include "remoting/protocol/channel_authenticator.h"
#include "remoting/protocol/name_value_map.h" #include "remoting/protocol/name_value_map.h"
...@@ -42,13 +43,18 @@ const NameMapElement<NegotiatingAuthenticatorBase::Method> ...@@ -42,13 +43,18 @@ const NameMapElement<NegotiatingAuthenticatorBase::Method>
} // namespace } // namespace
const buzz::StaticQName NegotiatingAuthenticatorBase::kMethodAttributeQName = const buzz::StaticQName NegotiatingAuthenticatorBase::kMethodAttributeQName = {
{ "", "method" }; "", "method"};
const buzz::StaticQName const buzz::StaticQName
NegotiatingAuthenticatorBase::kSupportedMethodsAttributeQName = NegotiatingAuthenticatorBase::kSupportedMethodsAttributeQName = {
{ "", "supported-methods" }; "", "supported-methods"};
const char NegotiatingAuthenticatorBase::kSupportedMethodsSeparator = ','; const char NegotiatingAuthenticatorBase::kSupportedMethodsSeparator = ',';
const buzz::StaticQName NegotiatingAuthenticatorBase::kPairingInfoTag = {
kChromotingXmlNamespace, "pairing-info"};
const buzz::StaticQName NegotiatingAuthenticatorBase::kClientIdAttribute = {
"", "client-id"};
NegotiatingAuthenticatorBase::NegotiatingAuthenticatorBase( NegotiatingAuthenticatorBase::NegotiatingAuthenticatorBase(
Authenticator::State initial_state) Authenticator::State initial_state)
: state_(initial_state) {} : state_(initial_state) {}
...@@ -88,28 +94,37 @@ std::string NegotiatingAuthenticatorBase::MethodToString(Method method) { ...@@ -88,28 +94,37 @@ std::string NegotiatingAuthenticatorBase::MethodToString(Method method) {
void NegotiatingAuthenticatorBase::ProcessMessageInternal( void NegotiatingAuthenticatorBase::ProcessMessageInternal(
const buzz::XmlElement* message, const buzz::XmlElement* message,
const base::Closure& resume_callback) { const base::Closure& resume_callback) {
DCHECK_EQ(state_, PROCESSING_MESSAGE);
if (current_authenticator_->state() == WAITING_MESSAGE) { if (current_authenticator_->state() == WAITING_MESSAGE) {
// If the message was not discarded and the authenticator is waiting for it, // If the message was not discarded and the authenticator is waiting for it,
// give it to the underlying authenticator to process. // give it to the underlying authenticator to process.
// |current_authenticator_| is owned, so Unretained() is safe here. // |current_authenticator_| is owned, so Unretained() is safe here.
state_ = PROCESSING_MESSAGE; current_authenticator_->ProcessMessage(
current_authenticator_->ProcessMessage(message, base::Bind( message, base::Bind(&NegotiatingAuthenticatorBase::UpdateState,
&NegotiatingAuthenticatorBase::UpdateState, base::Unretained(this), resume_callback));
base::Unretained(this), resume_callback));
} else { } else {
// Otherwise, just discard the message and run the callback. // Otherwise, just discard the message.
resume_callback.Run(); UpdateState(resume_callback);
} }
} }
void NegotiatingAuthenticatorBase::UpdateState( void NegotiatingAuthenticatorBase::UpdateState(
const base::Closure& resume_callback) { const base::Closure& resume_callback) {
DCHECK_EQ(state_, PROCESSING_MESSAGE);
// After the underlying authenticator finishes processing the message, the // After the underlying authenticator finishes processing the message, the
// NegotiatingAuthenticatorBase must update its own state before running the // NegotiatingAuthenticatorBase must update its own state before running the
// |resume_callback| to resume the session negotiation. // |resume_callback| to resume the session negotiation.
state_ = current_authenticator_->state(); state_ = current_authenticator_->state();
// Verify that this is a valid state transition.
DCHECK(state_ == MESSAGE_READY || state_ == ACCEPTED || state_ == REJECTED)
<< "State: " << state_;
if (state_ == REJECTED) if (state_ == REJECTED)
rejection_reason_ = current_authenticator_->rejection_reason(); rejection_reason_ = current_authenticator_->rejection_reason();
resume_callback.Run(); resume_callback.Run();
} }
......
...@@ -109,6 +109,9 @@ class NegotiatingAuthenticatorBase : public Authenticator { ...@@ -109,6 +109,9 @@ class NegotiatingAuthenticatorBase : public Authenticator {
static const buzz::StaticQName kSupportedMethodsAttributeQName; static const buzz::StaticQName kSupportedMethodsAttributeQName;
static const char kSupportedMethodsSeparator; static const char kSupportedMethodsSeparator;
static const buzz::StaticQName kPairingInfoTag;
static const buzz::StaticQName kClientIdAttribute;
// Parses a string that defines an authentication method. Returns // Parses a string that defines an authentication method. Returns
// Method::INVALID if the string is invalid. // Method::INVALID if the string is invalid.
static Method ParseMethodString(const std::string& value); static Method ParseMethodString(const std::string& value);
......
...@@ -50,6 +50,7 @@ void NegotiatingClientAuthenticator::ProcessMessage( ...@@ -50,6 +50,7 @@ void NegotiatingClientAuthenticator::ProcessMessage(
const buzz::XmlElement* message, const buzz::XmlElement* message,
const base::Closure& resume_callback) { const base::Closure& resume_callback) {
DCHECK_EQ(state(), WAITING_MESSAGE); DCHECK_EQ(state(), WAITING_MESSAGE);
state_ = PROCESSING_MESSAGE;
std::string method_attr = message->Attr(kMethodAttributeQName); std::string method_attr = message->Attr(kMethodAttributeQName);
Method method = ParseMethodString(method_attr); Method method = ParseMethodString(method_attr);
...@@ -68,7 +69,6 @@ void NegotiatingClientAuthenticator::ProcessMessage( ...@@ -68,7 +69,6 @@ void NegotiatingClientAuthenticator::ProcessMessage(
current_method_ = method; current_method_ = method;
method_set_by_host_ = true; method_set_by_host_ = true;
state_ = PROCESSING_MESSAGE;
// Copy the message since the authenticator may process it asynchronously. // Copy the message since the authenticator may process it asynchronously.
base::Closure callback = base::Bind( base::Closure callback = base::Bind(
...@@ -97,6 +97,14 @@ scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { ...@@ -97,6 +97,14 @@ scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() {
result = CreateEmptyAuthenticatorMessage(); result = CreateEmptyAuthenticatorMessage();
} }
if (is_paired()) {
// If the client is paired with the host then attach pairing client_id to
// the message.
buzz::XmlElement* pairing_tag = new buzz::XmlElement(kPairingInfoTag);
result->AddElement(pairing_tag);
pairing_tag->AddAttr(kClientIdAttribute, config_.pairing_client_id);
}
// Include a list of supported methods. // Include a list of supported methods.
std::string supported_methods; std::string supported_methods;
for (Method method : methods_) { for (Method method : methods_) {
...@@ -114,6 +122,7 @@ scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { ...@@ -114,6 +122,7 @@ scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() {
void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod(
Authenticator::State preferred_initial_state, Authenticator::State preferred_initial_state,
const base::Closure& resume_callback) { const base::Closure& resume_callback) {
DCHECK_EQ(state(), PROCESSING_MESSAGE);
DCHECK(current_method_ != Method::INVALID); DCHECK(current_method_ != Method::INVALID);
if (current_method_ == Method::THIRD_PARTY_SPAKE2_P224) { if (current_method_ == Method::THIRD_PARTY_SPAKE2_P224) {
current_authenticator_.reset(new ThirdPartyClientAuthenticator( current_authenticator_.reset(new ThirdPartyClientAuthenticator(
...@@ -126,14 +135,18 @@ void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( ...@@ -126,14 +135,18 @@ void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod(
remote_id_), remote_id_),
config_.fetch_third_party_token_callback)); config_.fetch_third_party_token_callback));
resume_callback.Run(); resume_callback.Run();
} else if (current_method_ == Method::PAIRED_SPAKE2_P224) {
PairingClientAuthenticator* pairing_authenticator =
new PairingClientAuthenticator(
config_, base::Bind(&V2Authenticator::CreateForClient));
current_authenticator_ = make_scoped_ptr(pairing_authenticator);
pairing_authenticator->Start(preferred_initial_state, resume_callback);
} else { } else {
DCHECK(current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224 || DCHECK(current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224 ||
current_method_ == Method::PAIRED_SPAKE2_P224 ||
current_method_ == Method::SHARED_SECRET_SPAKE2_P224 || current_method_ == Method::SHARED_SECRET_SPAKE2_P224 ||
current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519); current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519);
bool pairing_supported = (current_method_ == Method::PAIRED_SPAKE2_P224);
config_.fetch_secret_callback.Run( config_.fetch_secret_callback.Run(
pairing_supported, false,
base::Bind( base::Bind(
&NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator, &NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator,
weak_factory_.GetWeakPtr(), preferred_initial_state, weak_factory_.GetWeakPtr(), preferred_initial_state,
...@@ -142,13 +155,14 @@ void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( ...@@ -142,13 +155,14 @@ void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod(
} }
void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() {
if (!config_.pairing_client_id.empty() && !config_.pairing_secret.empty() && if (is_paired() &&
std::find(methods_.begin(), methods_.end(), Method::PAIRED_SPAKE2_P224) != std::find(methods_.begin(), methods_.end(), Method::PAIRED_SPAKE2_P224) !=
methods_.end()) { methods_.end()) {
// If the client specified a pairing id and shared secret, then create a PairingClientAuthenticator* pairing_authenticator =
// PairingAuthenticator. new PairingClientAuthenticator(
current_authenticator_.reset(new PairingClientAuthenticator( config_, base::Bind(&V2Authenticator::CreateForClient));
config_, base::Bind(&V2Authenticator::CreateForClient))); current_authenticator_ = make_scoped_ptr(pairing_authenticator);
pairing_authenticator->StartPaired(MESSAGE_READY);
current_method_ = Method::PAIRED_SPAKE2_P224; current_method_ = Method::PAIRED_SPAKE2_P224;
} }
} }
...@@ -172,5 +186,9 @@ void NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator( ...@@ -172,5 +186,9 @@ void NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator(
resume_callback.Run(); resume_callback.Run();
} }
bool NegotiatingClientAuthenticator::is_paired() {
return !config_.pairing_client_id.empty() && !config_.pairing_secret.empty();
}
} // namespace protocol } // namespace protocol
} // namespace remoting } // namespace remoting
...@@ -60,6 +60,8 @@ class NegotiatingClientAuthenticator : public NegotiatingAuthenticatorBase { ...@@ -60,6 +60,8 @@ class NegotiatingClientAuthenticator : public NegotiatingAuthenticatorBase {
const base::Closure& resume_callback, const base::Closure& resume_callback,
const std::string& shared_secret); const std::string& shared_secret);
bool is_paired();
std::string local_id_; std::string local_id_;
std::string remote_id_; std::string remote_id_;
......
...@@ -94,6 +94,12 @@ void NegotiatingHostAuthenticator::ProcessMessage( ...@@ -94,6 +94,12 @@ void NegotiatingHostAuthenticator::ProcessMessage(
const buzz::XmlElement* message, const buzz::XmlElement* message,
const base::Closure& resume_callback) { const base::Closure& resume_callback) {
DCHECK_EQ(state(), WAITING_MESSAGE); DCHECK_EQ(state(), WAITING_MESSAGE);
state_ = PROCESSING_MESSAGE;
const buzz::XmlElement* pairing_tag = message->FirstNamed(kPairingInfoTag);
if (pairing_tag) {
client_id_ = pairing_tag->Attr(kClientIdAttribute);
}
std::string method_attr = message->Attr(kMethodAttributeQName); std::string method_attr = message->Attr(kMethodAttributeQName);
Method method = ParseMethodString(method_attr); Method method = ParseMethodString(method_attr);
...@@ -149,10 +155,9 @@ void NegotiatingHostAuthenticator::ProcessMessage( ...@@ -149,10 +155,9 @@ void NegotiatingHostAuthenticator::ProcessMessage(
// Drop the current message because we've chosen a different method. // Drop the current message because we've chosen a different method.
current_method_ = method; current_method_ = method;
state_ = PROCESSING_MESSAGE; CreateAuthenticator(MESSAGE_READY,
CreateAuthenticator(MESSAGE_READY, base::Bind( base::Bind(&NegotiatingHostAuthenticator::UpdateState,
&NegotiatingHostAuthenticator::UpdateState, base::Unretained(this), resume_callback));
base::Unretained(this), resume_callback));
return; return;
} }
...@@ -160,12 +165,13 @@ void NegotiatingHostAuthenticator::ProcessMessage( ...@@ -160,12 +165,13 @@ void NegotiatingHostAuthenticator::ProcessMessage(
// method yet, use the client's preferred method and process the message. // method yet, use the client's preferred method and process the message.
if (current_method_ == Method::INVALID) { if (current_method_ == Method::INVALID) {
current_method_ = method; current_method_ = method;
state_ = PROCESSING_MESSAGE;
// Copy the message since the authenticator may process it asynchronously. // Copy the message since the authenticator may process it asynchronously.
CreateAuthenticator(WAITING_MESSAGE, base::Bind( CreateAuthenticator(
&NegotiatingAuthenticatorBase::ProcessMessageInternal, WAITING_MESSAGE,
base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), base::Bind(&NegotiatingAuthenticatorBase::ProcessMessageInternal,
resume_callback)); base::Unretained(this),
base::Owned(new buzz::XmlElement(*message)),
resume_callback));
return; return;
} }
...@@ -192,28 +198,23 @@ void NegotiatingHostAuthenticator::CreateAuthenticator( ...@@ -192,28 +198,23 @@ void NegotiatingHostAuthenticator::CreateAuthenticator(
base::Bind(&Spake2Authenticator::CreateForHost, local_id_, remote_id_, base::Bind(&Spake2Authenticator::CreateForHost, local_id_, remote_id_,
local_cert_, local_key_pair_), local_cert_, local_key_pair_),
token_validator_factory_->CreateTokenValidator(local_id_, remote_id_))); token_validator_factory_->CreateTokenValidator(local_id_, remote_id_)));
} else if (current_method_ == Method::PAIRED_SPAKE2_P224) {
PairingHostAuthenticator* pairing_authenticator =
new PairingHostAuthenticator(pairing_registry_,
base::Bind(&V2Authenticator::CreateForHost,
local_cert_, local_key_pair_),
shared_secret_hash_);
current_authenticator_.reset(pairing_authenticator);
pairing_authenticator->Initialize(client_id_, preferred_initial_state,
resume_callback);
return;
} else if (current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519) { } else if (current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519) {
current_authenticator_ = Spake2Authenticator::CreateForHost( current_authenticator_ = Spake2Authenticator::CreateForHost(
local_id_, remote_id_, local_cert_, local_key_pair_, local_id_, remote_id_, local_cert_, local_key_pair_,
shared_secret_hash_, preferred_initial_state); shared_secret_hash_, preferred_initial_state);
} else if (current_method_ == Method::PAIRED_SPAKE2_P224 &&
preferred_initial_state == WAITING_MESSAGE) {
// If the client requested Spake2Pair and sent an initial message, attempt
// the paired connection protocol.
current_authenticator_.reset(new PairingHostAuthenticator(
pairing_registry_, base::Bind(&V2Authenticator::CreateForHost,
local_cert_, local_key_pair_),
shared_secret_hash_));
} else { } else {
// In all other cases, use the V2 protocol. Note that this includes the
// case where the protocol is Spake2Pair but the client is not yet paired.
// In this case, the on-the-wire protocol is plain Spake2, advertised as
// Spake2Pair so that the client knows that the host supports pairing and
// that it can therefore present the option to the user when they enter
// the PIN.
DCHECK(current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224 || DCHECK(current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224 ||
current_method_ == Method::SHARED_SECRET_SPAKE2_P224 || current_method_ == Method::SHARED_SECRET_SPAKE2_P224);
current_method_ == Method::PAIRED_SPAKE2_P224);
current_authenticator_ = V2Authenticator::CreateForHost( current_authenticator_ = V2Authenticator::CreateForHost(
local_cert_, local_key_pair_, shared_secret_hash_, local_cert_, local_key_pair_, shared_secret_hash_,
preferred_initial_state); preferred_initial_state);
......
...@@ -71,7 +71,6 @@ class NegotiatingHostAuthenticator : public NegotiatingAuthenticatorBase { ...@@ -71,7 +71,6 @@ class NegotiatingHostAuthenticator : public NegotiatingAuthenticatorBase {
// (Asynchronously) creates an authenticator, and stores it in // (Asynchronously) creates an authenticator, and stores it in
// |current_authenticator_|. Authenticators that can be started in either // |current_authenticator_|. Authenticators that can be started in either
// state will be created in |preferred_initial_state|. // state will be created in |preferred_initial_state|.
// |resume_callback| is called after |current_authenticator_| is set.
void CreateAuthenticator(Authenticator::State preferred_initial_state, void CreateAuthenticator(Authenticator::State preferred_initial_state,
const base::Closure& resume_callback); const base::Closure& resume_callback);
...@@ -90,6 +89,8 @@ class NegotiatingHostAuthenticator : public NegotiatingAuthenticatorBase { ...@@ -90,6 +89,8 @@ class NegotiatingHostAuthenticator : public NegotiatingAuthenticatorBase {
// Used only for pairing authenticators. // Used only for pairing authenticators.
scoped_refptr<PairingRegistry> pairing_registry_; scoped_refptr<PairingRegistry> pairing_registry_;
std::string client_id_;
DISALLOW_COPY_AND_ASSIGN(NegotiatingHostAuthenticator); DISALLOW_COPY_AND_ASSIGN(NegotiatingHostAuthenticator);
}; };
......
...@@ -13,11 +13,6 @@ ...@@ -13,11 +13,6 @@
namespace remoting { namespace remoting {
namespace protocol { namespace protocol {
const buzz::StaticQName PairingAuthenticatorBase::kPairingInfoTag =
{ kChromotingXmlNamespace, "pairing-info" };
const buzz::StaticQName PairingAuthenticatorBase::kClientIdAttribute =
{ "", "client-id" };
namespace { namespace {
const buzz::StaticQName kPairingFailedTag = const buzz::StaticQName kPairingFailedTag =
{ kChromotingXmlNamespace, "pairing-failed" }; { kChromotingXmlNamespace, "pairing-failed" };
...@@ -82,7 +77,6 @@ void PairingAuthenticatorBase::ProcessMessage( ...@@ -82,7 +77,6 @@ void PairingAuthenticatorBase::ProcessMessage(
scoped_ptr<buzz::XmlElement> PairingAuthenticatorBase::GetNextMessage() { scoped_ptr<buzz::XmlElement> PairingAuthenticatorBase::GetNextMessage() {
DCHECK_EQ(state(), MESSAGE_READY); DCHECK_EQ(state(), MESSAGE_READY);
scoped_ptr<buzz::XmlElement> result = spake2_authenticator_->GetNextMessage(); scoped_ptr<buzz::XmlElement> result = spake2_authenticator_->GetNextMessage();
AddPairingElements(result.get());
MaybeAddErrorMessage(result.get()); MaybeAddErrorMessage(result.get());
return result; return result;
} }
......
...@@ -53,19 +53,12 @@ class PairingAuthenticatorBase : public Authenticator { ...@@ -53,19 +53,12 @@ class PairingAuthenticatorBase : public Authenticator {
scoped_ptr<ChannelAuthenticator> CreateChannelAuthenticator() const override; scoped_ptr<ChannelAuthenticator> CreateChannelAuthenticator() const override;
protected: protected:
static const buzz::StaticQName kPairingInfoTag;
static const buzz::StaticQName kClientIdAttribute;
// Create a Spake2 authenticator in the specified state, prompting the user // Create a Spake2 authenticator in the specified state, prompting the user
// for the PIN first if necessary. // for the PIN first if necessary.
virtual void CreateSpakeAuthenticatorWithPin( virtual void CreateSpakeAuthenticatorWithPin(
State initial_state, State initial_state,
const base::Closure& resume_callback) = 0; const base::Closure& resume_callback) = 0;
// Amend an authenticator message, for example to add client- or host-specific
// elements to it.
virtual void AddPairingElements(buzz::XmlElement* message) = 0;
// A non-fatal error message that derived classes should set in order to // A non-fatal error message that derived classes should set in order to
// cause the peer to be notified that pairing has failed and that it should // cause the peer to be notified that pairing has failed and that it should
// fall back on PIN authentication. This string need not be human-readable, // fall back on PIN authentication. This string need not be human-readable,
...@@ -81,7 +74,7 @@ class PairingAuthenticatorBase : public Authenticator { ...@@ -81,7 +74,7 @@ class PairingAuthenticatorBase : public Authenticator {
bool using_paired_secret_ = false; bool using_paired_secret_ = false;
private: private:
// Helper methods for ProcessMessage and GetNextMessage // Helper methods for ProcessMessage() and GetNextMessage().
void MaybeAddErrorMessage(buzz::XmlElement* message); void MaybeAddErrorMessage(buzz::XmlElement* message);
bool HasErrorMessage(const buzz::XmlElement* message) const; bool HasErrorMessage(const buzz::XmlElement* message) const;
void CheckForFailedSpakeExchange(const base::Closure& resume_callback); void CheckForFailedSpakeExchange(const base::Closure& resume_callback);
......
...@@ -19,14 +19,34 @@ PairingClientAuthenticator::PairingClientAuthenticator( ...@@ -19,14 +19,34 @@ PairingClientAuthenticator::PairingClientAuthenticator(
const CreateBaseAuthenticatorCallback& create_base_authenticator_callback) const CreateBaseAuthenticatorCallback& create_base_authenticator_callback)
: client_auth_config_(client_auth_config), : client_auth_config_(client_auth_config),
create_base_authenticator_callback_(create_base_authenticator_callback), create_base_authenticator_callback_(create_base_authenticator_callback),
weak_factory_(this) { weak_factory_(this) {}
spake2_authenticator_ = create_base_authenticator_callback_.Run(
client_auth_config.pairing_secret, MESSAGE_READY);
using_paired_secret_ = true;
}
PairingClientAuthenticator::~PairingClientAuthenticator() {} PairingClientAuthenticator::~PairingClientAuthenticator() {}
void PairingClientAuthenticator::Start(State initial_state,
const base::Closure& resume_callback) {
if (client_auth_config_.pairing_client_id.empty() ||
client_auth_config_.pairing_secret.empty()) {
// Send pairing error to make it clear that PIN is being used instead of
// pairing secret.
error_message_ = "not-paired";
using_paired_secret_ = false;
CreateSpakeAuthenticatorWithPin(initial_state, resume_callback);
} else {
StartPaired(initial_state);
resume_callback.Run();
}
}
void PairingClientAuthenticator::StartPaired(State initial_state) {
DCHECK(!client_auth_config_.pairing_client_id.empty());
DCHECK(!client_auth_config_.pairing_secret.empty());
using_paired_secret_ = true;
spake2_authenticator_ = create_base_authenticator_callback_.Run(
client_auth_config_.pairing_secret, initial_state);
}
Authenticator::State PairingClientAuthenticator::state() const { Authenticator::State PairingClientAuthenticator::state() const {
if (waiting_for_pin_) if (waiting_for_pin_)
return PROCESSING_MESSAGE; return PROCESSING_MESSAGE;
...@@ -44,20 +64,6 @@ void PairingClientAuthenticator::CreateSpakeAuthenticatorWithPin( ...@@ -44,20 +64,6 @@ void PairingClientAuthenticator::CreateSpakeAuthenticatorWithPin(
weak_factory_.GetWeakPtr(), initial_state, resume_callback)); weak_factory_.GetWeakPtr(), initial_state, resume_callback));
} }
void PairingClientAuthenticator::AddPairingElements(buzz::XmlElement* message) {
// If the client id and secret have not yet been sent, do so now. Note that
// in this case the V2Authenticator is being used optimistically to send the
// first message of the SPAKE exchange since we don't yet know whether or not
// the host will accept the client id or request that we fall back to the PIN.
if (!sent_client_id_) {
buzz::XmlElement* pairing_tag = new buzz::XmlElement(kPairingInfoTag);
pairing_tag->AddAttr(kClientIdAttribute,
client_auth_config_.pairing_client_id);
message->AddElement(pairing_tag);
sent_client_id_ = true;
}
}
void PairingClientAuthenticator::OnPinFetched( void PairingClientAuthenticator::OnPinFetched(
State initial_state, State initial_state,
const base::Closure& resume_callback, const base::Closure& resume_callback,
......
...@@ -21,6 +21,16 @@ class PairingClientAuthenticator : public PairingAuthenticatorBase { ...@@ -21,6 +21,16 @@ class PairingClientAuthenticator : public PairingAuthenticatorBase {
create_base_authenticator_callback); create_base_authenticator_callback);
~PairingClientAuthenticator() override; ~PairingClientAuthenticator() override;
// Start() or StartPaired() must be called after the authenticator is created.
// Start() handles both cases when pairing exists and when it doesn't.
// StartPaired() can only be used when pairing exists (i.e. client_id and
// pairing_secret are set in the |client_auth_config|). It is used to
// initialize the authenticator synchronously in
// NegotiatingClientAuthentitcator, while Start() may be executed
// asynchronously to fetch the PIN.
void Start(State initial_state, const base::Closure& resume_callback);
void StartPaired(State initial_state);
// Authenticator interface. // Authenticator interface.
State state() const override; State state() const override;
...@@ -29,7 +39,6 @@ class PairingClientAuthenticator : public PairingAuthenticatorBase { ...@@ -29,7 +39,6 @@ class PairingClientAuthenticator : public PairingAuthenticatorBase {
void CreateSpakeAuthenticatorWithPin( void CreateSpakeAuthenticatorWithPin(
State initial_state, State initial_state,
const base::Closure& resume_callback) override; const base::Closure& resume_callback) override;
void AddPairingElements(buzz::XmlElement* message) override;
void OnPinFetched(State initial_state, void OnPinFetched(State initial_state,
const base::Closure& resume_callback, const base::Closure& resume_callback,
...@@ -38,9 +47,6 @@ class PairingClientAuthenticator : public PairingAuthenticatorBase { ...@@ -38,9 +47,6 @@ class PairingClientAuthenticator : public PairingAuthenticatorBase {
ClientAuthenticationConfig client_auth_config_; ClientAuthenticationConfig client_auth_config_;
CreateBaseAuthenticatorCallback create_base_authenticator_callback_; CreateBaseAuthenticatorCallback create_base_authenticator_callback_;
// Set to true after client_id is sent to the host.
bool sent_client_id_ = false;
// Set to true if a PIN-based authenticator has been requested but has not // Set to true if a PIN-based authenticator has been requested but has not
// yet been set. // yet been set.
bool waiting_for_pin_ = false; bool waiting_for_pin_ = false;
......
...@@ -22,6 +22,29 @@ PairingHostAuthenticator::PairingHostAuthenticator( ...@@ -22,6 +22,29 @@ PairingHostAuthenticator::PairingHostAuthenticator(
pin_(pin), pin_(pin),
weak_factory_(this) {} weak_factory_(this) {}
void PairingHostAuthenticator::Initialize(
const std::string& client_id,
Authenticator::State preferred_initial_state,
const base::Closure& resume_callback) {
DCHECK(!spake2_authenticator_);
if (client_id.empty()) {
using_paired_secret_ = false;
error_message_ = "client-id-unknown";
spake2_authenticator_ =
create_base_authenticator_callback_.Run(pin_, MESSAGE_READY);
resume_callback.Run();
return;
}
using_paired_secret_ = true;
waiting_for_paired_secret_ = true;
pairing_registry_->GetPairing(
client_id, base::Bind(&PairingHostAuthenticator::InitializeWithPairing,
weak_factory_.GetWeakPtr(), preferred_initial_state,
resume_callback));
}
PairingHostAuthenticator::~PairingHostAuthenticator() {} PairingHostAuthenticator::~PairingHostAuthenticator() {}
Authenticator::State PairingHostAuthenticator::state() const { Authenticator::State PairingHostAuthenticator::state() const {
...@@ -29,8 +52,6 @@ Authenticator::State PairingHostAuthenticator::state() const { ...@@ -29,8 +52,6 @@ Authenticator::State PairingHostAuthenticator::state() const {
return REJECTED; return REJECTED;
} else if (waiting_for_paired_secret_) { } else if (waiting_for_paired_secret_) {
return PROCESSING_MESSAGE; return PROCESSING_MESSAGE;
} else if (!spake2_authenticator_) {
return WAITING_MESSAGE;
} }
return PairingAuthenticatorBase::state(); return PairingAuthenticatorBase::state();
} }
...@@ -51,63 +72,26 @@ void PairingHostAuthenticator::CreateSpakeAuthenticatorWithPin( ...@@ -51,63 +72,26 @@ void PairingHostAuthenticator::CreateSpakeAuthenticatorWithPin(
resume_callback.Run(); resume_callback.Run();
} }
void PairingHostAuthenticator::ProcessMessage( void PairingHostAuthenticator::InitializeWithPairing(
const buzz::XmlElement* message, Authenticator::State preferred_initial_state,
const base::Closure& resume_callback) {
if (!spake2_authenticator_) {
std::string client_id;
const buzz::XmlElement* pairing_tag = message->FirstNamed(kPairingInfoTag);
if (pairing_tag) {
client_id = pairing_tag->Attr(kClientIdAttribute);
}
if (client_id.empty()) {
LOG(ERROR) << "No client id specified.";
protocol_error_ = true;
return;
}
waiting_for_paired_secret_ = true;
pairing_registry_->GetPairing(
client_id,
base::Bind(&PairingHostAuthenticator::ProcessMessageWithPairing,
weak_factory_.GetWeakPtr(),
base::Owned(new buzz::XmlElement(*message)),
resume_callback));
return;
}
PairingAuthenticatorBase::ProcessMessage(message, resume_callback);
}
void PairingHostAuthenticator::AddPairingElements(buzz::XmlElement* message) {
// Nothing to do here
}
void PairingHostAuthenticator::ProcessMessageWithPairing(
const buzz::XmlElement* message,
const base::Closure& resume_callback, const base::Closure& resume_callback,
PairingRegistry::Pairing pairing) { PairingRegistry::Pairing pairing) {
DCHECK(waiting_for_paired_secret_);
waiting_for_paired_secret_ = false; waiting_for_paired_secret_ = false;
std::string paired_secret = pairing.shared_secret(); std::string pairing_secret = pairing.shared_secret();
if (paired_secret.empty()) { if (pairing_secret.empty()) {
VLOG(0) << "Unknown client id"; VLOG(0) << "Unknown client id";
error_message_ = "unknown-client-id"; error_message_ = "unknown-client-id";
} using_paired_secret_ = false;
// If pairing wasn't found then always start in the MESSAGE_READY state.
using_paired_secret_ = !paired_secret.empty();
if (using_paired_secret_) {
spake2_authenticator_ =
create_base_authenticator_callback_.Run(paired_secret, WAITING_MESSAGE);
PairingAuthenticatorBase::ProcessMessage(message, resume_callback);
} else {
spake2_authenticator_ = spake2_authenticator_ =
create_base_authenticator_callback_.Run(pin_, MESSAGE_READY); create_base_authenticator_callback_.Run(pin_, MESSAGE_READY);
// The client's optimistic SPAKE message is using a Paired Secret to } else {
// which the host doesn't have access, so don't bother processing it. using_paired_secret_ = true;
resume_callback.Run(); spake2_authenticator_ = create_base_authenticator_callback_.Run(
pairing_secret, preferred_initial_state);
} }
resume_callback.Run();
} }
} // namespace protocol } // namespace protocol
......
...@@ -23,24 +23,27 @@ class PairingHostAuthenticator : public PairingAuthenticatorBase { ...@@ -23,24 +23,27 @@ class PairingHostAuthenticator : public PairingAuthenticatorBase {
const std::string& pin); const std::string& pin);
~PairingHostAuthenticator() override; ~PairingHostAuthenticator() override;
// Initialize the authenticator with the given |client_id| in
// |preferred_initial_state|.
void Initialize(const std::string& client_id,
Authenticator::State preferred_initial_state,
const base::Closure& resume_callback);
// Authenticator interface. // Authenticator interface.
State state() const override; State state() const override;
RejectionReason rejection_reason() const override; RejectionReason rejection_reason() const override;
void ProcessMessage(const buzz::XmlElement* message,
const base::Closure& resume_callback) override;
private: private:
// PairingAuthenticatorBase overrides. // PairingAuthenticatorBase overrides.
void CreateSpakeAuthenticatorWithPin( void CreateSpakeAuthenticatorWithPin(
State initial_state, State initial_state,
const base::Closure& resume_callback) override; const base::Closure& resume_callback) override;
void AddPairingElements(buzz::XmlElement* message) override;
// Continue processing a protocol message once the pairing information for // Continue initializing once the pairing information for the client id has
// the client id has been received. // been received.
void ProcessMessageWithPairing(const buzz::XmlElement* message, void InitializeWithPairing(Authenticator::State preferred_initial_state,
const base::Closure& resume_callback, const base::Closure& resume_callback,
PairingRegistry::Pairing pairing); PairingRegistry::Pairing pairing);
// Protocol state. // Protocol state.
scoped_refptr<PairingRegistry> pairing_registry_; scoped_refptr<PairingRegistry> pairing_registry_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment