blob: 6191619a965843767f7f4d5388e9e1d86090bb2f [file] [log] [blame]
[email protected]76cfd032013-04-03 10:49:441// Copyright 2013 The Chromium Authors. All rights reserved.
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_host_authenticator.h"
6
7#include <algorithm>
8#include <sstream>
sergeyu89d088b2015-12-24 00:22:449#include <utility>
[email protected]76cfd032013-04-03 10:49:4410
11#include "base/bind.h"
12#include "base/callback.h"
13#include "base/logging.h"
14#include "base/strings/string_split.h"
15#include "remoting/base/rsa_key_pair.h"
16#include "remoting/protocol/channel_authenticator.h"
[email protected]6434bfe2013-05-22 09:00:2317#include "remoting/protocol/pairing_host_authenticator.h"
18#include "remoting/protocol/pairing_registry.h"
sergeyu4357fda52016-03-12 07:23:2419#include "remoting/protocol/spake2_authenticator.h"
[email protected]d95ee262014-02-26 06:30:3120#include "remoting/protocol/token_validator.h"
[email protected]76cfd032013-04-03 10:49:4421#include "remoting/protocol/v2_authenticator.h"
kjellanderf0e410b2017-01-04 14:45:0122#include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
[email protected]76cfd032013-04-03 10:49:4423
24namespace remoting {
25namespace protocol {
26
27NegotiatingHostAuthenticator::NegotiatingHostAuthenticator(
sergeyu4357fda52016-03-12 07:23:2428 const std::string& local_id,
29 const std::string& remote_id,
[email protected]76cfd032013-04-03 10:49:4430 const std::string& local_cert,
[email protected]4386f0a2013-04-06 04:50:4331 scoped_refptr<RsaKeyPair> key_pair)
[email protected]76cfd032013-04-03 10:49:4432 : NegotiatingAuthenticatorBase(WAITING_MESSAGE),
sergeyu4357fda52016-03-12 07:23:2433 local_id_(local_id),
34 remote_id_(remote_id),
[email protected]76cfd032013-04-03 10:49:4435 local_cert_(local_cert),
sergeyu3c759242016-03-04 21:34:3336 local_key_pair_(key_pair) {}
37
38// static
dcheng0765c492016-04-06 22:41:5339std::unique_ptr<NegotiatingHostAuthenticator>
sergeyud5d7539f2016-03-17 18:08:0340NegotiatingHostAuthenticator::CreateWithSharedSecret(
sergeyu4357fda52016-03-12 07:23:2441 const std::string& local_id,
42 const std::string& remote_id,
[email protected]4386f0a2013-04-06 04:50:4343 const std::string& local_cert,
44 scoped_refptr<RsaKeyPair> key_pair,
sergeyud5d7539f2016-03-17 18:08:0345 const std::string& shared_secret_hash,
[email protected]6434bfe2013-05-22 09:00:2346 scoped_refptr<PairingRegistry> pairing_registry) {
dcheng0765c492016-04-06 22:41:5347 std::unique_ptr<NegotiatingHostAuthenticator> result(
sergeyu4357fda52016-03-12 07:23:2448 new NegotiatingHostAuthenticator(local_id, remote_id, local_cert,
49 key_pair));
sergeyud5d7539f2016-03-17 18:08:0350 result->shared_secret_hash_ = shared_secret_hash;
[email protected]6434bfe2013-05-22 09:00:2351 result->pairing_registry_ = pairing_registry;
sergeyu4357fda52016-03-12 07:23:2452 result->AddMethod(Method::SHARED_SECRET_SPAKE2_CURVE25519);
53 result->AddMethod(Method::SHARED_SECRET_SPAKE2_P224);
[email protected]f9d8a772013-06-01 04:33:1754 if (pairing_registry.get()) {
sergeyu410cd112016-03-17 06:15:0055 result->AddMethod(Method::PAIRED_SPAKE2_CURVE25519);
sergeyu4357fda52016-03-12 07:23:2456 result->AddMethod(Method::PAIRED_SPAKE2_P224);
[email protected]6434bfe2013-05-22 09:00:2357 }
sergeyu410cd112016-03-17 06:15:0058 return result;
[email protected]4386f0a2013-04-06 04:50:4359}
60
61// static
dcheng0765c492016-04-06 22:41:5362std::unique_ptr<NegotiatingHostAuthenticator>
[email protected]4386f0a2013-04-06 04:50:4363NegotiatingHostAuthenticator::CreateWithThirdPartyAuth(
sergeyu4357fda52016-03-12 07:23:2464 const std::string& local_id,
65 const std::string& remote_id,
[email protected]4386f0a2013-04-06 04:50:4366 const std::string& local_cert,
67 scoped_refptr<RsaKeyPair> key_pair,
sergeyua15e4f0a2016-03-12 09:09:5868 scoped_refptr<TokenValidatorFactory> token_validator_factory) {
dcheng0765c492016-04-06 22:41:5369 std::unique_ptr<NegotiatingHostAuthenticator> result(
sergeyu4357fda52016-03-12 07:23:2470 new NegotiatingHostAuthenticator(local_id, remote_id, local_cert,
71 key_pair));
sergeyua15e4f0a2016-03-12 09:09:5872 result->token_validator_factory_ = token_validator_factory;
sergeyu4357fda52016-03-12 07:23:2473 result->AddMethod(Method::THIRD_PARTY_SPAKE2_CURVE25519);
74 result->AddMethod(Method::THIRD_PARTY_SPAKE2_P224);
sergeyu410cd112016-03-17 06:15:0075 return result;
[email protected]76cfd032013-04-03 10:49:4476}
77
Chris Watkins6fe52aa2017-11-28 03:24:0578NegotiatingHostAuthenticator::~NegotiatingHostAuthenticator() = default;
[email protected]76cfd032013-04-03 10:49:4479
80void NegotiatingHostAuthenticator::ProcessMessage(
Mirko Bonadei80d1cea2019-01-18 22:22:1781 const jingle_xmpp::XmlElement* message,
[email protected]76cfd032013-04-03 10:49:4482 const base::Closure& resume_callback) {
83 DCHECK_EQ(state(), WAITING_MESSAGE);
sergeyu843ef122016-03-17 01:44:1784 state_ = PROCESSING_MESSAGE;
85
Mirko Bonadei80d1cea2019-01-18 22:22:1786 const jingle_xmpp::XmlElement* pairing_tag = message->FirstNamed(kPairingInfoTag);
sergeyu843ef122016-03-17 01:44:1787 if (pairing_tag) {
88 client_id_ = pairing_tag->Attr(kClientIdAttribute);
89 }
[email protected]76cfd032013-04-03 10:49:4490
91 std::string method_attr = message->Attr(kMethodAttributeQName);
sergeyu42cb6f9f2016-03-09 05:37:0392 Method method = ParseMethodString(method_attr);
[email protected]76cfd032013-04-03 10:49:4493
94 // If the host has already chosen a method, it can't be changed by the client.
sergeyu42cb6f9f2016-03-09 05:37:0395 if (current_method_ != Method::INVALID && method != current_method_) {
[email protected]76cfd032013-04-03 10:49:4496 state_ = REJECTED;
97 rejection_reason_ = PROTOCOL_ERROR;
98 resume_callback.Run();
99 return;
100 }
101
[email protected]6434bfe2013-05-22 09:00:23102 // If the client did not specify a preferred auth method, or specified an
103 // unknown or unsupported method, then select the first known method from
104 // the supported-methods attribute.
sergeyu42cb6f9f2016-03-09 05:37:03105 if (method == Method::INVALID ||
[email protected]76cfd032013-04-03 10:49:44106 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) {
sergeyu42cb6f9f2016-03-09 05:37:03107 method = Method::INVALID;
[email protected]76cfd032013-04-03 10:49:44108
109 std::string supported_methods_attr =
110 message->Attr(kSupportedMethodsAttributeQName);
111 if (supported_methods_attr.empty()) {
112 // Message contains neither method nor supported-methods attributes.
113 state_ = REJECTED;
114 rejection_reason_ = PROTOCOL_ERROR;
115 resume_callback.Run();
116 return;
117 }
118
119 // Find the first mutually-supported method in the client's list of
120 // supported-methods.
brettw26dab8f02015-08-08 00:28:47121 for (const std::string& method_str :
122 base::SplitString(supported_methods_attr,
123 std::string(1, kSupportedMethodsSeparator),
124 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
sergeyu42cb6f9f2016-03-09 05:37:03125 Method list_value = ParseMethodString(method_str);
126 if (list_value != Method::INVALID &&
sergeyu3c759242016-03-04 21:34:33127 std::find(methods_.begin(), methods_.end(), list_value) !=
128 methods_.end()) {
[email protected]76cfd032013-04-03 10:49:44129 // Found common method.
130 method = list_value;
131 break;
132 }
133 }
134
sergeyu42cb6f9f2016-03-09 05:37:03135 if (method == Method::INVALID) {
[email protected]76cfd032013-04-03 10:49:44136 // Failed to find a common auth method.
137 state_ = REJECTED;
138 rejection_reason_ = PROTOCOL_ERROR;
139 resume_callback.Run();
140 return;
141 }
142
143 // Drop the current message because we've chosen a different method.
144 current_method_ = method;
sergeyu843ef122016-03-17 01:44:17145 CreateAuthenticator(MESSAGE_READY,
146 base::Bind(&NegotiatingHostAuthenticator::UpdateState,
147 base::Unretained(this), resume_callback));
[email protected]76cfd032013-04-03 10:49:44148 return;
149 }
150
151 // If the client specified a supported method, and the host hasn't chosen a
152 // method yet, use the client's preferred method and process the message.
sergeyu42cb6f9f2016-03-09 05:37:03153 if (current_method_ == Method::INVALID) {
[email protected]76cfd032013-04-03 10:49:44154 current_method_ = method;
[email protected]76cfd032013-04-03 10:49:44155 // Copy the message since the authenticator may process it asynchronously.
sergeyu843ef122016-03-17 01:44:17156 CreateAuthenticator(
157 WAITING_MESSAGE,
158 base::Bind(&NegotiatingAuthenticatorBase::ProcessMessageInternal,
159 base::Unretained(this),
Mirko Bonadei80d1cea2019-01-18 22:22:17160 base::Owned(new jingle_xmpp::XmlElement(*message)),
sergeyu843ef122016-03-17 01:44:17161 resume_callback));
[email protected]76cfd032013-04-03 10:49:44162 return;
163 }
164
165 // If the client is using the host's current method, just process the message.
166 ProcessMessageInternal(message, resume_callback);
167}
168
Mirko Bonadei80d1cea2019-01-18 22:22:17169std::unique_ptr<jingle_xmpp::XmlElement>
dcheng0765c492016-04-06 22:41:53170NegotiatingHostAuthenticator::GetNextMessage() {
[email protected]76cfd032013-04-03 10:49:44171 return GetNextMessageInternal();
172}
173
174void NegotiatingHostAuthenticator::CreateAuthenticator(
175 Authenticator::State preferred_initial_state,
176 const base::Closure& resume_callback) {
sergeyu42cb6f9f2016-03-09 05:37:03177 DCHECK(current_method_ != Method::INVALID);
[email protected]4386f0a2013-04-06 04:50:43178
sergeyu410cd112016-03-17 06:15:00179 switch(current_method_) {
180 case Method::INVALID:
181 NOTREACHED();
182 break;
183
184 case Method::THIRD_PARTY_SPAKE2_P224:
185 current_authenticator_.reset(new ThirdPartyHostAuthenticator(
186 base::Bind(&V2Authenticator::CreateForHost, local_cert_,
187 local_key_pair_),
188 token_validator_factory_->CreateTokenValidator(local_id_,
189 remote_id_)));
190 resume_callback.Run();
191 break;
192
193 case Method::THIRD_PARTY_SPAKE2_CURVE25519:
194 current_authenticator_.reset(new ThirdPartyHostAuthenticator(
195 base::Bind(&Spake2Authenticator::CreateForHost, local_id_, remote_id_,
196 local_cert_, local_key_pair_),
197 token_validator_factory_->CreateTokenValidator(local_id_,
198 remote_id_)));
199 resume_callback.Run();
200 break;
201
202 case Method::PAIRED_SPAKE2_P224: {
203 PairingHostAuthenticator* pairing_authenticator =
204 new PairingHostAuthenticator(
205 pairing_registry_, base::Bind(&V2Authenticator::CreateForHost,
206 local_cert_, local_key_pair_),
207 shared_secret_hash_);
208 current_authenticator_.reset(pairing_authenticator);
209 pairing_authenticator->Initialize(client_id_, preferred_initial_state,
210 resume_callback);
211 break;
212 }
213
214 case Method::PAIRED_SPAKE2_CURVE25519: {
215 PairingHostAuthenticator* pairing_authenticator =
216 new PairingHostAuthenticator(
217 pairing_registry_,
218 base::Bind(&Spake2Authenticator::CreateForHost, local_id_,
219 remote_id_, local_cert_, local_key_pair_),
220 shared_secret_hash_);
221 current_authenticator_.reset(pairing_authenticator);
222 pairing_authenticator->Initialize(client_id_, preferred_initial_state,
223 resume_callback);
224 break;
225 }
226
227 case Method::SHARED_SECRET_SPAKE2_CURVE25519:
228 current_authenticator_ = Spake2Authenticator::CreateForHost(
229 local_id_, remote_id_, local_cert_, local_key_pair_,
230 shared_secret_hash_, preferred_initial_state);
231 resume_callback.Run();
232 break;
233
jamiewalch5c5aec852016-05-03 01:21:11234 case Method::SHARED_SECRET_PLAIN_SPAKE2_P224:
sergeyu410cd112016-03-17 06:15:00235 case Method::SHARED_SECRET_SPAKE2_P224:
236 current_authenticator_ = V2Authenticator::CreateForHost(
237 local_cert_, local_key_pair_, shared_secret_hash_,
238 preferred_initial_state);
239 resume_callback.Run();
240 break;
[email protected]4386f0a2013-04-06 04:50:43241 }
[email protected]76cfd032013-04-03 10:49:44242}
243
244} // namespace protocol
245} // namespace remoting