negotiating_client_authenticator.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // 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. #include "remoting/protocol/negotiating_client_authenticator.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <sstream>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/callback.h"
  11. #include "base/check_op.h"
  12. #include "base/memory/ptr_util.h"
  13. #include "base/notreached.h"
  14. #include "base/strings/string_split.h"
  15. #include "remoting/protocol/auth_util.h"
  16. #include "remoting/protocol/channel_authenticator.h"
  17. #include "remoting/protocol/pairing_client_authenticator.h"
  18. #include "remoting/protocol/spake2_authenticator.h"
  19. #include "remoting/protocol/v2_authenticator.h"
  20. #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
  21. namespace remoting {
  22. namespace protocol {
  23. NegotiatingClientAuthenticator::NegotiatingClientAuthenticator(
  24. const std::string& local_id,
  25. const std::string& remote_id,
  26. const ClientAuthenticationConfig& config)
  27. : NegotiatingAuthenticatorBase(MESSAGE_READY),
  28. local_id_(local_id),
  29. remote_id_(remote_id),
  30. config_(config) {
  31. if (!config_.fetch_third_party_token_callback.is_null()) {
  32. AddMethod(Method::THIRD_PARTY_SPAKE2_CURVE25519);
  33. AddMethod(Method::THIRD_PARTY_SPAKE2_P224);
  34. }
  35. AddMethod(Method::PAIRED_SPAKE2_CURVE25519);
  36. AddMethod(Method::PAIRED_SPAKE2_P224);
  37. AddMethod(Method::SHARED_SECRET_SPAKE2_CURVE25519);
  38. AddMethod(Method::SHARED_SECRET_SPAKE2_P224);
  39. AddMethod(Method::SHARED_SECRET_PLAIN_SPAKE2_P224);
  40. }
  41. NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() = default;
  42. void NegotiatingClientAuthenticator::ProcessMessage(
  43. const jingle_xmpp::XmlElement* message,
  44. base::OnceClosure resume_callback) {
  45. DCHECK_EQ(state(), WAITING_MESSAGE);
  46. state_ = PROCESSING_MESSAGE;
  47. std::string method_attr = message->Attr(kMethodAttributeQName);
  48. Method method = ParseMethodString(method_attr);
  49. // The host picked a method different from the one the client had selected.
  50. if (method != current_method_) {
  51. // The host must pick a method that is valid and supported by the client,
  52. // and it must not change methods after it has picked one.
  53. if (method_set_by_host_ || method == Method::INVALID ||
  54. std::find(methods_.begin(), methods_.end(), method) == methods_.end()) {
  55. state_ = REJECTED;
  56. rejection_reason_ = RejectionReason::PROTOCOL_ERROR;
  57. std::move(resume_callback).Run();
  58. return;
  59. }
  60. current_method_ = method;
  61. method_set_by_host_ = true;
  62. // Copy the message since the authenticator may process it asynchronously.
  63. CreateAuthenticatorForCurrentMethod(
  64. WAITING_MESSAGE,
  65. base::BindOnce(&NegotiatingAuthenticatorBase::ProcessMessageInternal,
  66. base::Unretained(this),
  67. base::Owned(new jingle_xmpp::XmlElement(*message)),
  68. std::move(resume_callback)));
  69. return;
  70. }
  71. ProcessMessageInternal(message, std::move(resume_callback));
  72. }
  73. std::unique_ptr<jingle_xmpp::XmlElement>
  74. NegotiatingClientAuthenticator::GetNextMessage() {
  75. DCHECK_EQ(state(), MESSAGE_READY);
  76. // This is the first message to the host, send a list of supported methods.
  77. if (current_method_ == Method::INVALID) {
  78. // If no authentication method has been chosen, see if we can optimistically
  79. // choose one.
  80. std::unique_ptr<jingle_xmpp::XmlElement> result;
  81. CreatePreferredAuthenticator();
  82. if (current_authenticator_) {
  83. DCHECK(current_authenticator_->state() == MESSAGE_READY);
  84. result = GetNextMessageInternal();
  85. } else {
  86. result = CreateEmptyAuthenticatorMessage();
  87. }
  88. if (is_paired()) {
  89. // If the client is paired with the host then attach pairing client_id to
  90. // the message.
  91. jingle_xmpp::XmlElement* pairing_tag = new jingle_xmpp::XmlElement(kPairingInfoTag);
  92. result->AddElement(pairing_tag);
  93. pairing_tag->AddAttr(kClientIdAttribute, config_.pairing_client_id);
  94. }
  95. // Include a list of supported methods.
  96. std::string supported_methods;
  97. for (Method method : methods_) {
  98. if (!supported_methods.empty())
  99. supported_methods += kSupportedMethodsSeparator;
  100. supported_methods += MethodToString(method);
  101. }
  102. result->AddAttr(kSupportedMethodsAttributeQName, supported_methods);
  103. state_ = WAITING_MESSAGE;
  104. return result;
  105. }
  106. return GetNextMessageInternal();
  107. }
  108. void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod(
  109. Authenticator::State preferred_initial_state,
  110. base::OnceClosure resume_callback) {
  111. DCHECK_EQ(state(), PROCESSING_MESSAGE);
  112. DCHECK(current_method_ != Method::INVALID);
  113. switch (current_method_) {
  114. case Method::INVALID:
  115. NOTREACHED();
  116. break;
  117. case Method::THIRD_PARTY_SPAKE2_P224:
  118. current_authenticator_ = std::make_unique<ThirdPartyClientAuthenticator>(
  119. base::BindRepeating(&V2Authenticator::CreateForClient),
  120. config_.fetch_third_party_token_callback);
  121. std::move(resume_callback).Run();
  122. break;
  123. case Method::THIRD_PARTY_SPAKE2_CURVE25519:
  124. current_authenticator_ = std::make_unique<ThirdPartyClientAuthenticator>(
  125. base::BindRepeating(&Spake2Authenticator::CreateForClient, local_id_,
  126. remote_id_),
  127. config_.fetch_third_party_token_callback);
  128. std::move(resume_callback).Run();
  129. break;
  130. case Method::PAIRED_SPAKE2_P224: {
  131. PairingClientAuthenticator* pairing_authenticator =
  132. new PairingClientAuthenticator(
  133. config_, base::BindRepeating(&V2Authenticator::CreateForClient));
  134. current_authenticator_ = base::WrapUnique(pairing_authenticator);
  135. pairing_authenticator->Start(preferred_initial_state,
  136. std::move(resume_callback));
  137. break;
  138. }
  139. case Method::PAIRED_SPAKE2_CURVE25519: {
  140. PairingClientAuthenticator* pairing_authenticator =
  141. new PairingClientAuthenticator(
  142. config_,
  143. base::BindRepeating(&Spake2Authenticator::CreateForClient,
  144. local_id_, remote_id_));
  145. current_authenticator_ = base::WrapUnique(pairing_authenticator);
  146. pairing_authenticator->Start(preferred_initial_state,
  147. std::move(resume_callback));
  148. break;
  149. }
  150. case Method::SHARED_SECRET_PLAIN_SPAKE2_P224:
  151. case Method::SHARED_SECRET_SPAKE2_P224:
  152. case Method::SHARED_SECRET_SPAKE2_CURVE25519:
  153. config_.fetch_secret_callback.Run(
  154. false,
  155. base::BindRepeating(
  156. &NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator,
  157. weak_factory_.GetWeakPtr(), preferred_initial_state,
  158. base::Passed(std::move(resume_callback))));
  159. break;
  160. }
  161. }
  162. void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() {
  163. if (is_paired() &&
  164. std::find(methods_.begin(), methods_.end(), Method::PAIRED_SPAKE2_P224) !=
  165. methods_.end()) {
  166. PairingClientAuthenticator* pairing_authenticator =
  167. new PairingClientAuthenticator(
  168. config_, base::BindRepeating(&V2Authenticator::CreateForClient));
  169. current_authenticator_ = base::WrapUnique(pairing_authenticator);
  170. pairing_authenticator->StartPaired(MESSAGE_READY);
  171. current_method_ = Method::PAIRED_SPAKE2_P224;
  172. }
  173. }
  174. void NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator(
  175. Authenticator::State initial_state,
  176. base::OnceClosure resume_callback,
  177. const std::string& shared_secret) {
  178. std::string shared_secret_hash =
  179. (current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224)
  180. ? shared_secret
  181. : GetSharedSecretHash(config_.host_id, shared_secret);
  182. if (current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519) {
  183. current_authenticator_ = Spake2Authenticator::CreateForClient(
  184. local_id_, remote_id_, shared_secret_hash, initial_state);
  185. } else {
  186. current_authenticator_ =
  187. V2Authenticator::CreateForClient(shared_secret_hash, initial_state);
  188. }
  189. std::move(resume_callback).Run();
  190. }
  191. bool NegotiatingClientAuthenticator::is_paired() {
  192. return !config_.pairing_client_id.empty() && !config_.pairing_secret.empty();
  193. }
  194. } // namespace protocol
  195. } // namespace remoting