123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- // 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 <memory>
- #include <sstream>
- #include <utility>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/check_op.h"
- #include "base/memory/ptr_util.h"
- #include "base/notreached.h"
- #include "base/strings/string_split.h"
- #include "remoting/protocol/auth_util.h"
- #include "remoting/protocol/channel_authenticator.h"
- #include "remoting/protocol/pairing_client_authenticator.h"
- #include "remoting/protocol/spake2_authenticator.h"
- #include "remoting/protocol/v2_authenticator.h"
- #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
- namespace remoting {
- namespace protocol {
- NegotiatingClientAuthenticator::NegotiatingClientAuthenticator(
- const std::string& local_id,
- const std::string& remote_id,
- const ClientAuthenticationConfig& config)
- : NegotiatingAuthenticatorBase(MESSAGE_READY),
- local_id_(local_id),
- remote_id_(remote_id),
- config_(config) {
- if (!config_.fetch_third_party_token_callback.is_null()) {
- AddMethod(Method::THIRD_PARTY_SPAKE2_CURVE25519);
- AddMethod(Method::THIRD_PARTY_SPAKE2_P224);
- }
- AddMethod(Method::PAIRED_SPAKE2_CURVE25519);
- AddMethod(Method::PAIRED_SPAKE2_P224);
- AddMethod(Method::SHARED_SECRET_SPAKE2_CURVE25519);
- AddMethod(Method::SHARED_SECRET_SPAKE2_P224);
- AddMethod(Method::SHARED_SECRET_PLAIN_SPAKE2_P224);
- }
- NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() = default;
- void NegotiatingClientAuthenticator::ProcessMessage(
- const jingle_xmpp::XmlElement* message,
- base::OnceClosure resume_callback) {
- DCHECK_EQ(state(), WAITING_MESSAGE);
- state_ = PROCESSING_MESSAGE;
- std::string method_attr = message->Attr(kMethodAttributeQName);
- Method method = ParseMethodString(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 == Method::INVALID ||
- std::find(methods_.begin(), methods_.end(), method) == methods_.end()) {
- state_ = REJECTED;
- rejection_reason_ = RejectionReason::PROTOCOL_ERROR;
- std::move(resume_callback).Run();
- return;
- }
- current_method_ = method;
- method_set_by_host_ = true;
- // Copy the message since the authenticator may process it asynchronously.
- CreateAuthenticatorForCurrentMethod(
- WAITING_MESSAGE,
- base::BindOnce(&NegotiatingAuthenticatorBase::ProcessMessageInternal,
- base::Unretained(this),
- base::Owned(new jingle_xmpp::XmlElement(*message)),
- std::move(resume_callback)));
- return;
- }
- ProcessMessageInternal(message, std::move(resume_callback));
- }
- std::unique_ptr<jingle_xmpp::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_ == Method::INVALID) {
- // If no authentication method has been chosen, see if we can optimistically
- // choose one.
- std::unique_ptr<jingle_xmpp::XmlElement> result;
- CreatePreferredAuthenticator();
- if (current_authenticator_) {
- DCHECK(current_authenticator_->state() == MESSAGE_READY);
- result = GetNextMessageInternal();
- } else {
- result = CreateEmptyAuthenticatorMessage();
- }
- if (is_paired()) {
- // If the client is paired with the host then attach pairing client_id to
- // the message.
- jingle_xmpp::XmlElement* pairing_tag = new jingle_xmpp::XmlElement(kPairingInfoTag);
- result->AddElement(pairing_tag);
- pairing_tag->AddAttr(kClientIdAttribute, config_.pairing_client_id);
- }
- // Include a list of supported methods.
- std::string supported_methods;
- for (Method method : methods_) {
- if (!supported_methods.empty())
- supported_methods += kSupportedMethodsSeparator;
- supported_methods += MethodToString(method);
- }
- result->AddAttr(kSupportedMethodsAttributeQName, supported_methods);
- state_ = WAITING_MESSAGE;
- return result;
- }
- return GetNextMessageInternal();
- }
- void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod(
- Authenticator::State preferred_initial_state,
- base::OnceClosure resume_callback) {
- DCHECK_EQ(state(), PROCESSING_MESSAGE);
- DCHECK(current_method_ != Method::INVALID);
- switch (current_method_) {
- case Method::INVALID:
- NOTREACHED();
- break;
- case Method::THIRD_PARTY_SPAKE2_P224:
- current_authenticator_ = std::make_unique<ThirdPartyClientAuthenticator>(
- base::BindRepeating(&V2Authenticator::CreateForClient),
- config_.fetch_third_party_token_callback);
- std::move(resume_callback).Run();
- break;
- case Method::THIRD_PARTY_SPAKE2_CURVE25519:
- current_authenticator_ = std::make_unique<ThirdPartyClientAuthenticator>(
- base::BindRepeating(&Spake2Authenticator::CreateForClient, local_id_,
- remote_id_),
- config_.fetch_third_party_token_callback);
- std::move(resume_callback).Run();
- break;
- case Method::PAIRED_SPAKE2_P224: {
- PairingClientAuthenticator* pairing_authenticator =
- new PairingClientAuthenticator(
- config_, base::BindRepeating(&V2Authenticator::CreateForClient));
- current_authenticator_ = base::WrapUnique(pairing_authenticator);
- pairing_authenticator->Start(preferred_initial_state,
- std::move(resume_callback));
- break;
- }
- case Method::PAIRED_SPAKE2_CURVE25519: {
- PairingClientAuthenticator* pairing_authenticator =
- new PairingClientAuthenticator(
- config_,
- base::BindRepeating(&Spake2Authenticator::CreateForClient,
- local_id_, remote_id_));
- current_authenticator_ = base::WrapUnique(pairing_authenticator);
- pairing_authenticator->Start(preferred_initial_state,
- std::move(resume_callback));
- break;
- }
- case Method::SHARED_SECRET_PLAIN_SPAKE2_P224:
- case Method::SHARED_SECRET_SPAKE2_P224:
- case Method::SHARED_SECRET_SPAKE2_CURVE25519:
- config_.fetch_secret_callback.Run(
- false,
- base::BindRepeating(
- &NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator,
- weak_factory_.GetWeakPtr(), preferred_initial_state,
- base::Passed(std::move(resume_callback))));
- break;
- }
- }
- void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() {
- if (is_paired() &&
- std::find(methods_.begin(), methods_.end(), Method::PAIRED_SPAKE2_P224) !=
- methods_.end()) {
- PairingClientAuthenticator* pairing_authenticator =
- new PairingClientAuthenticator(
- config_, base::BindRepeating(&V2Authenticator::CreateForClient));
- current_authenticator_ = base::WrapUnique(pairing_authenticator);
- pairing_authenticator->StartPaired(MESSAGE_READY);
- current_method_ = Method::PAIRED_SPAKE2_P224;
- }
- }
- void NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator(
- Authenticator::State initial_state,
- base::OnceClosure resume_callback,
- const std::string& shared_secret) {
- std::string shared_secret_hash =
- (current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224)
- ? shared_secret
- : GetSharedSecretHash(config_.host_id, shared_secret);
- if (current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519) {
- current_authenticator_ = Spake2Authenticator::CreateForClient(
- local_id_, remote_id_, shared_secret_hash, initial_state);
- } else {
- current_authenticator_ =
- V2Authenticator::CreateForClient(shared_secret_hash, initial_state);
- }
- std::move(resume_callback).Run();
- }
- bool NegotiatingClientAuthenticator::is_paired() {
- return !config_.pairing_client_id.empty() && !config_.pairing_secret.empty();
- }
- } // namespace protocol
- } // namespace remoting
|