blob: a96780a580540f3234af447310c65e0a9144d7db [file] [log] [blame]
Avi Drissmand6cdf9b2022-09-15 19:52:531// Copyright 2013 The Chromium Authors
[email protected]76cfd032013-04-03 10:49:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/protocol/negotiating_client_authenticator.h"
6
Peter Boström42afa23f2021-04-02 22:10:467#include <memory>
[email protected]76cfd032013-04-03 10:49:448#include <sstream>
sergeyu89d088b2015-12-24 00:22:449#include <utility>
[email protected]76cfd032013-04-03 10:49:4410
Hans Wennborg828a0972020-04-27 18:10:0911#include "base/check_op.h"
Peter Kastingd84876c2022-09-30 16:59:1412#include "base/containers/contains.h"
Avi Drissman135261e2023-01-11 22:43:1513#include "base/functional/bind.h"
14#include "base/functional/callback.h"
dcheng0765c492016-04-06 22:41:5315#include "base/memory/ptr_util.h"
Hans Wennborg828a0972020-04-27 18:10:0916#include "base/notreached.h"
[email protected]76cfd032013-04-03 10:49:4417#include "base/strings/string_split.h"
sergeyu42cb6f9f2016-03-09 05:37:0318#include "remoting/protocol/auth_util.h"
[email protected]76cfd032013-04-03 10:49:4419#include "remoting/protocol/channel_authenticator.h"
[email protected]6434bfe2013-05-22 09:00:2320#include "remoting/protocol/pairing_client_authenticator.h"
sergeyu4357fda52016-03-12 07:23:2421#include "remoting/protocol/spake2_authenticator.h"
[email protected]76cfd032013-04-03 10:49:4422#include "remoting/protocol/v2_authenticator.h"
kjellanderf0e410b2017-01-04 14:45:0123#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
[email protected]76cfd032013-04-03 10:49:4424
Joe Downing39d710e2022-08-25 20:11:4525namespace remoting::protocol {
[email protected]76cfd032013-04-03 10:49:4426
27NegotiatingClientAuthenticator::NegotiatingClientAuthenticator(
sergeyu4357fda52016-03-12 07:23:2428 const std::string& local_id,
29 const std::string& remote_id,
sergeyu396d9332016-03-12 01:58:5830 const ClientAuthenticationConfig& config)
[email protected]76cfd032013-04-03 10:49:4431 : NegotiatingAuthenticatorBase(MESSAGE_READY),
sergeyu4357fda52016-03-12 07:23:2432 local_id_(local_id),
33 remote_id_(remote_id),
Jeremy Roman7c5cfabd2019-08-12 15:45:2734 config_(config) {
sergeyu4357fda52016-03-12 07:23:2435 if (!config_.fetch_third_party_token_callback.is_null()) {
36 AddMethod(Method::THIRD_PARTY_SPAKE2_CURVE25519);
37 AddMethod(Method::THIRD_PARTY_SPAKE2_P224);
38 }
39
sergeyu410cd112016-03-17 06:15:0040 AddMethod(Method::PAIRED_SPAKE2_CURVE25519);
sergeyu4357fda52016-03-12 07:23:2441 AddMethod(Method::PAIRED_SPAKE2_P224);
42
43 AddMethod(Method::SHARED_SECRET_SPAKE2_CURVE25519);
44 AddMethod(Method::SHARED_SECRET_SPAKE2_P224);
jamiewalch5c5aec852016-05-03 01:21:1145
46 AddMethod(Method::SHARED_SECRET_PLAIN_SPAKE2_P224);
[email protected]76cfd032013-04-03 10:49:4447}
48
Chris Watkins6fe52aa2017-11-28 03:24:0549NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() = default;
[email protected]76cfd032013-04-03 10:49:4450
51void NegotiatingClientAuthenticator::ProcessMessage(
Mirko Bonadei80d1cea2019-01-18 22:22:1752 const jingle_xmpp::XmlElement* message,
Evan Stadece9372b2020-03-12 01:28:1653 base::OnceClosure resume_callback) {
[email protected]76cfd032013-04-03 10:49:4454 DCHECK_EQ(state(), WAITING_MESSAGE);
sergeyu843ef122016-03-17 01:44:1755 state_ = PROCESSING_MESSAGE;
[email protected]76cfd032013-04-03 10:49:4456
57 std::string method_attr = message->Attr(kMethodAttributeQName);
sergeyu42cb6f9f2016-03-09 05:37:0358 Method method = ParseMethodString(method_attr);
[email protected]76cfd032013-04-03 10:49:4459
60 // The host picked a method different from the one the client had selected.
61 if (method != current_method_) {
62 // The host must pick a method that is valid and supported by the client,
63 // and it must not change methods after it has picked one.
sergeyu42cb6f9f2016-03-09 05:37:0364 if (method_set_by_host_ || method == Method::INVALID ||
Peter Kastingd84876c2022-09-30 16:59:1465 !base::Contains(methods_, method)) {
[email protected]76cfd032013-04-03 10:49:4466 state_ = REJECTED;
Lei Zhang8dea4712022-07-22 16:28:2567 rejection_reason_ = RejectionReason::PROTOCOL_ERROR;
Evan Stadece9372b2020-03-12 01:28:1668 std::move(resume_callback).Run();
[email protected]76cfd032013-04-03 10:49:4469 return;
70 }
71
72 current_method_ = method;
73 method_set_by_host_ = true;
[email protected]a40bc3c2013-05-14 05:08:3574
[email protected]76cfd032013-04-03 10:49:4475 // Copy the message since the authenticator may process it asynchronously.
Evan Stadece9372b2020-03-12 01:28:1676 CreateAuthenticatorForCurrentMethod(
77 WAITING_MESSAGE,
78 base::BindOnce(&NegotiatingAuthenticatorBase::ProcessMessageInternal,
79 base::Unretained(this),
80 base::Owned(new jingle_xmpp::XmlElement(*message)),
Jan Wilken Dörrie1494205b2020-03-26 09:32:5381 std::move(resume_callback)));
[email protected]76cfd032013-04-03 10:49:4482 return;
83 }
Evan Stadece9372b2020-03-12 01:28:1684 ProcessMessageInternal(message, std::move(resume_callback));
[email protected]76cfd032013-04-03 10:49:4485}
86
Mirko Bonadei80d1cea2019-01-18 22:22:1787std::unique_ptr<jingle_xmpp::XmlElement>
dcheng0765c492016-04-06 22:41:5388NegotiatingClientAuthenticator::GetNextMessage() {
[email protected]76cfd032013-04-03 10:49:4489 DCHECK_EQ(state(), MESSAGE_READY);
[email protected]6434bfe2013-05-22 09:00:2390
[email protected]76cfd032013-04-03 10:49:4491 // This is the first message to the host, send a list of supported methods.
sergeyu42cb6f9f2016-03-09 05:37:0392 if (current_method_ == Method::INVALID) {
[email protected]a40bc3c2013-05-14 05:08:3593 // If no authentication method has been chosen, see if we can optimistically
94 // choose one.
Mirko Bonadei80d1cea2019-01-18 22:22:1795 std::unique_ptr<jingle_xmpp::XmlElement> result;
[email protected]6434bfe2013-05-22 09:00:2396 CreatePreferredAuthenticator();
[email protected]a40bc3c2013-05-14 05:08:3597 if (current_authenticator_) {
98 DCHECK(current_authenticator_->state() == MESSAGE_READY);
99 result = GetNextMessageInternal();
100 } else {
101 result = CreateEmptyAuthenticatorMessage();
102 }
103
sergeyu843ef122016-03-17 01:44:17104 if (is_paired()) {
105 // If the client is paired with the host then attach pairing client_id to
106 // the message.
Joe Downing353ba2c72023-01-11 22:37:34107 jingle_xmpp::XmlElement* pairing_tag =
108 new jingle_xmpp::XmlElement(kPairingInfoTag);
sergeyu843ef122016-03-17 01:44:17109 result->AddElement(pairing_tag);
110 pairing_tag->AddAttr(kClientIdAttribute, config_.pairing_client_id);
111 }
112
[email protected]a40bc3c2013-05-14 05:08:35113 // Include a list of supported methods.
sergeyu3c759242016-03-04 21:34:33114 std::string supported_methods;
sergeyu42cb6f9f2016-03-09 05:37:03115 for (Method method : methods_) {
Joe Downing353ba2c72023-01-11 22:37:34116 if (!supported_methods.empty()) {
sergeyu3c759242016-03-04 21:34:33117 supported_methods += kSupportedMethodsSeparator;
Joe Downing353ba2c72023-01-11 22:37:34118 }
sergeyu42cb6f9f2016-03-09 05:37:03119 supported_methods += MethodToString(method);
[email protected]76cfd032013-04-03 10:49:44120 }
sergeyu3c759242016-03-04 21:34:33121 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods);
[email protected]76cfd032013-04-03 10:49:44122 state_ = WAITING_MESSAGE;
sergeyuaa6fa2342015-12-22 23:26:48123 return result;
[email protected]76cfd032013-04-03 10:49:44124 }
125 return GetNextMessageInternal();
126}
127
[email protected]a40bc3c2013-05-14 05:08:35128void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod(
[email protected]76cfd032013-04-03 10:49:44129 Authenticator::State preferred_initial_state,
Evan Stadece9372b2020-03-12 01:28:16130 base::OnceClosure resume_callback) {
sergeyu843ef122016-03-17 01:44:17131 DCHECK_EQ(state(), PROCESSING_MESSAGE);
sergeyu42cb6f9f2016-03-09 05:37:03132 DCHECK(current_method_ != Method::INVALID);
sergeyu410cd112016-03-17 06:15:00133 switch (current_method_) {
134 case Method::INVALID:
135 NOTREACHED();
136 break;
137
138 case Method::THIRD_PARTY_SPAKE2_P224:
Peter Boström42afa23f2021-04-02 22:10:46139 current_authenticator_ = std::make_unique<ThirdPartyClientAuthenticator>(
Evan Stadec7ae01902020-07-06 16:50:40140 base::BindRepeating(&V2Authenticator::CreateForClient),
Peter Boström42afa23f2021-04-02 22:10:46141 config_.fetch_third_party_token_callback);
Evan Stadece9372b2020-03-12 01:28:16142 std::move(resume_callback).Run();
sergeyu410cd112016-03-17 06:15:00143 break;
144
145 case Method::THIRD_PARTY_SPAKE2_CURVE25519:
Peter Boström42afa23f2021-04-02 22:10:46146 current_authenticator_ = std::make_unique<ThirdPartyClientAuthenticator>(
Evan Stadec7ae01902020-07-06 16:50:40147 base::BindRepeating(&Spake2Authenticator::CreateForClient, local_id_,
148 remote_id_),
Peter Boström42afa23f2021-04-02 22:10:46149 config_.fetch_third_party_token_callback);
Evan Stadece9372b2020-03-12 01:28:16150 std::move(resume_callback).Run();
sergeyu410cd112016-03-17 06:15:00151 break;
152
153 case Method::PAIRED_SPAKE2_P224: {
154 PairingClientAuthenticator* pairing_authenticator =
155 new PairingClientAuthenticator(
Evan Stadec7ae01902020-07-06 16:50:40156 config_, base::BindRepeating(&V2Authenticator::CreateForClient));
dcheng0765c492016-04-06 22:41:53157 current_authenticator_ = base::WrapUnique(pairing_authenticator);
Evan Stadece9372b2020-03-12 01:28:16158 pairing_authenticator->Start(preferred_initial_state,
159 std::move(resume_callback));
sergeyu410cd112016-03-17 06:15:00160 break;
161 }
162
163 case Method::PAIRED_SPAKE2_CURVE25519: {
164 PairingClientAuthenticator* pairing_authenticator =
165 new PairingClientAuthenticator(
Evan Stadec7ae01902020-07-06 16:50:40166 config_,
167 base::BindRepeating(&Spake2Authenticator::CreateForClient,
sergeyu410cd112016-03-17 06:15:00168 local_id_, remote_id_));
dcheng0765c492016-04-06 22:41:53169 current_authenticator_ = base::WrapUnique(pairing_authenticator);
Evan Stadece9372b2020-03-12 01:28:16170 pairing_authenticator->Start(preferred_initial_state,
171 std::move(resume_callback));
sergeyu410cd112016-03-17 06:15:00172 break;
173 }
174
jamiewalch5c5aec852016-05-03 01:21:11175 case Method::SHARED_SECRET_PLAIN_SPAKE2_P224:
sergeyu410cd112016-03-17 06:15:00176 case Method::SHARED_SECRET_SPAKE2_P224:
177 case Method::SHARED_SECRET_SPAKE2_CURVE25519:
Theresab64aa832020-03-19 17:00:42178 config_.fetch_secret_callback.Run(
179 false,
Evan Stadec7ae01902020-07-06 16:50:40180 base::BindRepeating(
Theresab64aa832020-03-19 17:00:42181 &NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator,
182 weak_factory_.GetWeakPtr(), preferred_initial_state,
183 base::Passed(std::move(resume_callback))));
sergeyu410cd112016-03-17 06:15:00184 break;
[email protected]34e25582013-04-06 05:01:02185 }
[email protected]76cfd032013-04-03 10:49:44186}
187
[email protected]6434bfe2013-05-22 09:00:23188void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() {
Peter Kastingd84876c2022-09-30 16:59:14189 if (is_paired() && base::Contains(methods_, Method::PAIRED_SPAKE2_P224)) {
sergeyu843ef122016-03-17 01:44:17190 PairingClientAuthenticator* pairing_authenticator =
191 new PairingClientAuthenticator(
Evan Stadec7ae01902020-07-06 16:50:40192 config_, base::BindRepeating(&V2Authenticator::CreateForClient));
dcheng0765c492016-04-06 22:41:53193 current_authenticator_ = base::WrapUnique(pairing_authenticator);
sergeyu843ef122016-03-17 01:44:17194 pairing_authenticator->StartPaired(MESSAGE_READY);
sergeyu4357fda52016-03-12 07:23:24195 current_method_ = Method::PAIRED_SPAKE2_P224;
[email protected]6434bfe2013-05-22 09:00:23196 }
[email protected]a40bc3c2013-05-14 05:08:35197}
198
sergeyu4357fda52016-03-12 07:23:24199void NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator(
[email protected]76cfd032013-04-03 10:49:44200 Authenticator::State initial_state,
Evan Stadece9372b2020-03-12 01:28:16201 base::OnceClosure resume_callback,
[email protected]76cfd032013-04-03 10:49:44202 const std::string& shared_secret) {
sergeyu4357fda52016-03-12 07:23:24203 std::string shared_secret_hash =
jamiewalch5c5aec852016-05-03 01:21:11204 (current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224)
205 ? shared_secret
206 : GetSharedSecretHash(config_.host_id, shared_secret);
207
sergeyu4357fda52016-03-12 07:23:24208 if (current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519) {
209 current_authenticator_ = Spake2Authenticator::CreateForClient(
210 local_id_, remote_id_, shared_secret_hash, initial_state);
211 } else {
212 current_authenticator_ =
213 V2Authenticator::CreateForClient(shared_secret_hash, initial_state);
214 }
Evan Stadece9372b2020-03-12 01:28:16215 std::move(resume_callback).Run();
[email protected]76cfd032013-04-03 10:49:44216}
217
sergeyu843ef122016-03-17 01:44:17218bool NegotiatingClientAuthenticator::is_paired() {
219 return !config_.pairing_client_id.empty() && !config_.pairing_secret.empty();
220}
221
Joe Downing39d710e2022-08-25 20:11:45222} // namespace remoting::protocol