Avi Drissman | d6cdf9b | 2022-09-15 19:52:53 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 2 | // 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öm | 42afa23f | 2021-04-02 22:10:46 | [diff] [blame] | 7 | #include <memory> |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 8 | #include <sstream> |
sergeyu | 89d088b | 2015-12-24 00:22:44 | [diff] [blame] | 9 | #include <utility> |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 10 | |
Hans Wennborg | 828a097 | 2020-04-27 18:10:09 | [diff] [blame] | 11 | #include "base/check_op.h" |
Peter Kasting | d84876c | 2022-09-30 16:59:14 | [diff] [blame] | 12 | #include "base/containers/contains.h" |
Avi Drissman | 135261e | 2023-01-11 22:43:15 | [diff] [blame^] | 13 | #include "base/functional/bind.h" |
| 14 | #include "base/functional/callback.h" |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 15 | #include "base/memory/ptr_util.h" |
Hans Wennborg | 828a097 | 2020-04-27 18:10:09 | [diff] [blame] | 16 | #include "base/notreached.h" |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 17 | #include "base/strings/string_split.h" |
sergeyu | 42cb6f9f | 2016-03-09 05:37:03 | [diff] [blame] | 18 | #include "remoting/protocol/auth_util.h" |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 19 | #include "remoting/protocol/channel_authenticator.h" |
[email protected] | 6434bfe | 2013-05-22 09:00:23 | [diff] [blame] | 20 | #include "remoting/protocol/pairing_client_authenticator.h" |
sergeyu | 4357fda5 | 2016-03-12 07:23:24 | [diff] [blame] | 21 | #include "remoting/protocol/spake2_authenticator.h" |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 22 | #include "remoting/protocol/v2_authenticator.h" |
kjellander | f0e410b | 2017-01-04 14:45:01 | [diff] [blame] | 23 | #include "third_party/libjingle_xmpp/xmllite/xmlelement.h" |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 24 | |
Joe Downing | 39d710e | 2022-08-25 20:11:45 | [diff] [blame] | 25 | namespace remoting::protocol { |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 26 | |
| 27 | NegotiatingClientAuthenticator::NegotiatingClientAuthenticator( |
sergeyu | 4357fda5 | 2016-03-12 07:23:24 | [diff] [blame] | 28 | const std::string& local_id, |
| 29 | const std::string& remote_id, |
sergeyu | 396d933 | 2016-03-12 01:58:58 | [diff] [blame] | 30 | const ClientAuthenticationConfig& config) |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 31 | : NegotiatingAuthenticatorBase(MESSAGE_READY), |
sergeyu | 4357fda5 | 2016-03-12 07:23:24 | [diff] [blame] | 32 | local_id_(local_id), |
| 33 | remote_id_(remote_id), |
Jeremy Roman | 7c5cfabd | 2019-08-12 15:45:27 | [diff] [blame] | 34 | config_(config) { |
sergeyu | 4357fda5 | 2016-03-12 07:23:24 | [diff] [blame] | 35 | 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 | |
sergeyu | 410cd11 | 2016-03-17 06:15:00 | [diff] [blame] | 40 | AddMethod(Method::PAIRED_SPAKE2_CURVE25519); |
sergeyu | 4357fda5 | 2016-03-12 07:23:24 | [diff] [blame] | 41 | AddMethod(Method::PAIRED_SPAKE2_P224); |
| 42 | |
| 43 | AddMethod(Method::SHARED_SECRET_SPAKE2_CURVE25519); |
| 44 | AddMethod(Method::SHARED_SECRET_SPAKE2_P224); |
jamiewalch | 5c5aec85 | 2016-05-03 01:21:11 | [diff] [blame] | 45 | |
| 46 | AddMethod(Method::SHARED_SECRET_PLAIN_SPAKE2_P224); |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 47 | } |
| 48 | |
Chris Watkins | 6fe52aa | 2017-11-28 03:24:05 | [diff] [blame] | 49 | NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() = default; |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 50 | |
| 51 | void NegotiatingClientAuthenticator::ProcessMessage( |
Mirko Bonadei | 80d1cea | 2019-01-18 22:22:17 | [diff] [blame] | 52 | const jingle_xmpp::XmlElement* message, |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 53 | base::OnceClosure resume_callback) { |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 54 | DCHECK_EQ(state(), WAITING_MESSAGE); |
sergeyu | 843ef12 | 2016-03-17 01:44:17 | [diff] [blame] | 55 | state_ = PROCESSING_MESSAGE; |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 56 | |
| 57 | std::string method_attr = message->Attr(kMethodAttributeQName); |
sergeyu | 42cb6f9f | 2016-03-09 05:37:03 | [diff] [blame] | 58 | Method method = ParseMethodString(method_attr); |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 59 | |
| 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. |
sergeyu | 42cb6f9f | 2016-03-09 05:37:03 | [diff] [blame] | 64 | if (method_set_by_host_ || method == Method::INVALID || |
Peter Kasting | d84876c | 2022-09-30 16:59:14 | [diff] [blame] | 65 | !base::Contains(methods_, method)) { |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 66 | state_ = REJECTED; |
Lei Zhang | 8dea471 | 2022-07-22 16:28:25 | [diff] [blame] | 67 | rejection_reason_ = RejectionReason::PROTOCOL_ERROR; |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 68 | std::move(resume_callback).Run(); |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 69 | return; |
| 70 | } |
| 71 | |
| 72 | current_method_ = method; |
| 73 | method_set_by_host_ = true; |
[email protected] | a40bc3c | 2013-05-14 05:08:35 | [diff] [blame] | 74 | |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 75 | // Copy the message since the authenticator may process it asynchronously. |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 76 | CreateAuthenticatorForCurrentMethod( |
| 77 | WAITING_MESSAGE, |
| 78 | base::BindOnce(&NegotiatingAuthenticatorBase::ProcessMessageInternal, |
| 79 | base::Unretained(this), |
| 80 | base::Owned(new jingle_xmpp::XmlElement(*message)), |
Jan Wilken Dörrie | 1494205b | 2020-03-26 09:32:53 | [diff] [blame] | 81 | std::move(resume_callback))); |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 82 | return; |
| 83 | } |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 84 | ProcessMessageInternal(message, std::move(resume_callback)); |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 85 | } |
| 86 | |
Mirko Bonadei | 80d1cea | 2019-01-18 22:22:17 | [diff] [blame] | 87 | std::unique_ptr<jingle_xmpp::XmlElement> |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 88 | NegotiatingClientAuthenticator::GetNextMessage() { |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 89 | DCHECK_EQ(state(), MESSAGE_READY); |
[email protected] | 6434bfe | 2013-05-22 09:00:23 | [diff] [blame] | 90 | |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 91 | // This is the first message to the host, send a list of supported methods. |
sergeyu | 42cb6f9f | 2016-03-09 05:37:03 | [diff] [blame] | 92 | if (current_method_ == Method::INVALID) { |
[email protected] | a40bc3c | 2013-05-14 05:08:35 | [diff] [blame] | 93 | // If no authentication method has been chosen, see if we can optimistically |
| 94 | // choose one. |
Mirko Bonadei | 80d1cea | 2019-01-18 22:22:17 | [diff] [blame] | 95 | std::unique_ptr<jingle_xmpp::XmlElement> result; |
[email protected] | 6434bfe | 2013-05-22 09:00:23 | [diff] [blame] | 96 | CreatePreferredAuthenticator(); |
[email protected] | a40bc3c | 2013-05-14 05:08:35 | [diff] [blame] | 97 | if (current_authenticator_) { |
| 98 | DCHECK(current_authenticator_->state() == MESSAGE_READY); |
| 99 | result = GetNextMessageInternal(); |
| 100 | } else { |
| 101 | result = CreateEmptyAuthenticatorMessage(); |
| 102 | } |
| 103 | |
sergeyu | 843ef12 | 2016-03-17 01:44:17 | [diff] [blame] | 104 | if (is_paired()) { |
| 105 | // If the client is paired with the host then attach pairing client_id to |
| 106 | // the message. |
Joe Downing | 353ba2c7 | 2023-01-11 22:37:34 | [diff] [blame] | 107 | jingle_xmpp::XmlElement* pairing_tag = |
| 108 | new jingle_xmpp::XmlElement(kPairingInfoTag); |
sergeyu | 843ef12 | 2016-03-17 01:44:17 | [diff] [blame] | 109 | result->AddElement(pairing_tag); |
| 110 | pairing_tag->AddAttr(kClientIdAttribute, config_.pairing_client_id); |
| 111 | } |
| 112 | |
[email protected] | a40bc3c | 2013-05-14 05:08:35 | [diff] [blame] | 113 | // Include a list of supported methods. |
sergeyu | 3c75924 | 2016-03-04 21:34:33 | [diff] [blame] | 114 | std::string supported_methods; |
sergeyu | 42cb6f9f | 2016-03-09 05:37:03 | [diff] [blame] | 115 | for (Method method : methods_) { |
Joe Downing | 353ba2c7 | 2023-01-11 22:37:34 | [diff] [blame] | 116 | if (!supported_methods.empty()) { |
sergeyu | 3c75924 | 2016-03-04 21:34:33 | [diff] [blame] | 117 | supported_methods += kSupportedMethodsSeparator; |
Joe Downing | 353ba2c7 | 2023-01-11 22:37:34 | [diff] [blame] | 118 | } |
sergeyu | 42cb6f9f | 2016-03-09 05:37:03 | [diff] [blame] | 119 | supported_methods += MethodToString(method); |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 120 | } |
sergeyu | 3c75924 | 2016-03-04 21:34:33 | [diff] [blame] | 121 | result->AddAttr(kSupportedMethodsAttributeQName, supported_methods); |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 122 | state_ = WAITING_MESSAGE; |
sergeyu | aa6fa234 | 2015-12-22 23:26:48 | [diff] [blame] | 123 | return result; |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 124 | } |
| 125 | return GetNextMessageInternal(); |
| 126 | } |
| 127 | |
[email protected] | a40bc3c | 2013-05-14 05:08:35 | [diff] [blame] | 128 | void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 129 | Authenticator::State preferred_initial_state, |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 130 | base::OnceClosure resume_callback) { |
sergeyu | 843ef12 | 2016-03-17 01:44:17 | [diff] [blame] | 131 | DCHECK_EQ(state(), PROCESSING_MESSAGE); |
sergeyu | 42cb6f9f | 2016-03-09 05:37:03 | [diff] [blame] | 132 | DCHECK(current_method_ != Method::INVALID); |
sergeyu | 410cd11 | 2016-03-17 06:15:00 | [diff] [blame] | 133 | switch (current_method_) { |
| 134 | case Method::INVALID: |
| 135 | NOTREACHED(); |
| 136 | break; |
| 137 | |
| 138 | case Method::THIRD_PARTY_SPAKE2_P224: |
Peter Boström | 42afa23f | 2021-04-02 22:10:46 | [diff] [blame] | 139 | current_authenticator_ = std::make_unique<ThirdPartyClientAuthenticator>( |
Evan Stade | c7ae0190 | 2020-07-06 16:50:40 | [diff] [blame] | 140 | base::BindRepeating(&V2Authenticator::CreateForClient), |
Peter Boström | 42afa23f | 2021-04-02 22:10:46 | [diff] [blame] | 141 | config_.fetch_third_party_token_callback); |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 142 | std::move(resume_callback).Run(); |
sergeyu | 410cd11 | 2016-03-17 06:15:00 | [diff] [blame] | 143 | break; |
| 144 | |
| 145 | case Method::THIRD_PARTY_SPAKE2_CURVE25519: |
Peter Boström | 42afa23f | 2021-04-02 22:10:46 | [diff] [blame] | 146 | current_authenticator_ = std::make_unique<ThirdPartyClientAuthenticator>( |
Evan Stade | c7ae0190 | 2020-07-06 16:50:40 | [diff] [blame] | 147 | base::BindRepeating(&Spake2Authenticator::CreateForClient, local_id_, |
| 148 | remote_id_), |
Peter Boström | 42afa23f | 2021-04-02 22:10:46 | [diff] [blame] | 149 | config_.fetch_third_party_token_callback); |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 150 | std::move(resume_callback).Run(); |
sergeyu | 410cd11 | 2016-03-17 06:15:00 | [diff] [blame] | 151 | break; |
| 152 | |
| 153 | case Method::PAIRED_SPAKE2_P224: { |
| 154 | PairingClientAuthenticator* pairing_authenticator = |
| 155 | new PairingClientAuthenticator( |
Evan Stade | c7ae0190 | 2020-07-06 16:50:40 | [diff] [blame] | 156 | config_, base::BindRepeating(&V2Authenticator::CreateForClient)); |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 157 | current_authenticator_ = base::WrapUnique(pairing_authenticator); |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 158 | pairing_authenticator->Start(preferred_initial_state, |
| 159 | std::move(resume_callback)); |
sergeyu | 410cd11 | 2016-03-17 06:15:00 | [diff] [blame] | 160 | break; |
| 161 | } |
| 162 | |
| 163 | case Method::PAIRED_SPAKE2_CURVE25519: { |
| 164 | PairingClientAuthenticator* pairing_authenticator = |
| 165 | new PairingClientAuthenticator( |
Evan Stade | c7ae0190 | 2020-07-06 16:50:40 | [diff] [blame] | 166 | config_, |
| 167 | base::BindRepeating(&Spake2Authenticator::CreateForClient, |
sergeyu | 410cd11 | 2016-03-17 06:15:00 | [diff] [blame] | 168 | local_id_, remote_id_)); |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 169 | current_authenticator_ = base::WrapUnique(pairing_authenticator); |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 170 | pairing_authenticator->Start(preferred_initial_state, |
| 171 | std::move(resume_callback)); |
sergeyu | 410cd11 | 2016-03-17 06:15:00 | [diff] [blame] | 172 | break; |
| 173 | } |
| 174 | |
jamiewalch | 5c5aec85 | 2016-05-03 01:21:11 | [diff] [blame] | 175 | case Method::SHARED_SECRET_PLAIN_SPAKE2_P224: |
sergeyu | 410cd11 | 2016-03-17 06:15:00 | [diff] [blame] | 176 | case Method::SHARED_SECRET_SPAKE2_P224: |
| 177 | case Method::SHARED_SECRET_SPAKE2_CURVE25519: |
Theresa | b64aa83 | 2020-03-19 17:00:42 | [diff] [blame] | 178 | config_.fetch_secret_callback.Run( |
| 179 | false, |
Evan Stade | c7ae0190 | 2020-07-06 16:50:40 | [diff] [blame] | 180 | base::BindRepeating( |
Theresa | b64aa83 | 2020-03-19 17:00:42 | [diff] [blame] | 181 | &NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator, |
| 182 | weak_factory_.GetWeakPtr(), preferred_initial_state, |
| 183 | base::Passed(std::move(resume_callback)))); |
sergeyu | 410cd11 | 2016-03-17 06:15:00 | [diff] [blame] | 184 | break; |
[email protected] | 34e2558 | 2013-04-06 05:01:02 | [diff] [blame] | 185 | } |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 186 | } |
| 187 | |
[email protected] | 6434bfe | 2013-05-22 09:00:23 | [diff] [blame] | 188 | void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { |
Peter Kasting | d84876c | 2022-09-30 16:59:14 | [diff] [blame] | 189 | if (is_paired() && base::Contains(methods_, Method::PAIRED_SPAKE2_P224)) { |
sergeyu | 843ef12 | 2016-03-17 01:44:17 | [diff] [blame] | 190 | PairingClientAuthenticator* pairing_authenticator = |
| 191 | new PairingClientAuthenticator( |
Evan Stade | c7ae0190 | 2020-07-06 16:50:40 | [diff] [blame] | 192 | config_, base::BindRepeating(&V2Authenticator::CreateForClient)); |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 193 | current_authenticator_ = base::WrapUnique(pairing_authenticator); |
sergeyu | 843ef12 | 2016-03-17 01:44:17 | [diff] [blame] | 194 | pairing_authenticator->StartPaired(MESSAGE_READY); |
sergeyu | 4357fda5 | 2016-03-12 07:23:24 | [diff] [blame] | 195 | current_method_ = Method::PAIRED_SPAKE2_P224; |
[email protected] | 6434bfe | 2013-05-22 09:00:23 | [diff] [blame] | 196 | } |
[email protected] | a40bc3c | 2013-05-14 05:08:35 | [diff] [blame] | 197 | } |
| 198 | |
sergeyu | 4357fda5 | 2016-03-12 07:23:24 | [diff] [blame] | 199 | void NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator( |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 200 | Authenticator::State initial_state, |
Evan Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 201 | base::OnceClosure resume_callback, |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 202 | const std::string& shared_secret) { |
sergeyu | 4357fda5 | 2016-03-12 07:23:24 | [diff] [blame] | 203 | std::string shared_secret_hash = |
jamiewalch | 5c5aec85 | 2016-05-03 01:21:11 | [diff] [blame] | 204 | (current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224) |
| 205 | ? shared_secret |
| 206 | : GetSharedSecretHash(config_.host_id, shared_secret); |
| 207 | |
sergeyu | 4357fda5 | 2016-03-12 07:23:24 | [diff] [blame] | 208 | 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 Stade | ce9372b | 2020-03-12 01:28:16 | [diff] [blame] | 215 | std::move(resume_callback).Run(); |
[email protected] | 76cfd03 | 2013-04-03 10:49:44 | [diff] [blame] | 216 | } |
| 217 | |
sergeyu | 843ef12 | 2016-03-17 01:44:17 | [diff] [blame] | 218 | bool NegotiatingClientAuthenticator::is_paired() { |
| 219 | return !config_.pairing_client_id.empty() && !config_.pairing_secret.empty(); |
| 220 | } |
| 221 | |
Joe Downing | 39d710e | 2022-08-25 20:11:45 | [diff] [blame] | 222 | } // namespace remoting::protocol |