| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/protocol/negotiating_client_authenticator.h" | 5 #include "remoting/protocol/negotiating_client_authenticator.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <sstream> | 8 #include <sstream> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/callback.h" | 12 #include "base/callback.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/strings/string_split.h" | 14 #include "base/strings/string_split.h" |
| 15 #include "remoting/protocol/auth_util.h" |
| 15 #include "remoting/protocol/channel_authenticator.h" | 16 #include "remoting/protocol/channel_authenticator.h" |
| 16 #include "remoting/protocol/pairing_client_authenticator.h" | 17 #include "remoting/protocol/pairing_client_authenticator.h" |
| 17 #include "remoting/protocol/v2_authenticator.h" | 18 #include "remoting/protocol/v2_authenticator.h" |
| 18 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" | 19 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" |
| 19 | 20 |
| 20 namespace remoting { | 21 namespace remoting { |
| 21 namespace protocol { | 22 namespace protocol { |
| 22 | 23 |
| 23 NegotiatingClientAuthenticator::NegotiatingClientAuthenticator( | 24 NegotiatingClientAuthenticator::NegotiatingClientAuthenticator( |
| 24 const std::string& client_pairing_id, | 25 const std::string& client_pairing_id, |
| 25 const std::string& shared_secret, | 26 const std::string& shared_secret, |
| 26 const std::string& authentication_tag, | 27 const std::string& authentication_tag, |
| 27 const FetchSecretCallback& fetch_secret_callback, | 28 const FetchSecretCallback& fetch_secret_callback, |
| 28 scoped_ptr<ThirdPartyClientAuthenticator::TokenFetcher> token_fetcher, | 29 scoped_ptr<ThirdPartyClientAuthenticator::TokenFetcher> token_fetcher) |
| 29 const std::vector<AuthenticationMethod>& methods) | |
| 30 : NegotiatingAuthenticatorBase(MESSAGE_READY), | 30 : NegotiatingAuthenticatorBase(MESSAGE_READY), |
| 31 client_pairing_id_(client_pairing_id), | 31 client_pairing_id_(client_pairing_id), |
| 32 shared_secret_(shared_secret), | 32 shared_secret_(shared_secret), |
| 33 authentication_tag_(authentication_tag), | 33 authentication_tag_(authentication_tag), |
| 34 fetch_secret_callback_(fetch_secret_callback), | 34 fetch_secret_callback_(fetch_secret_callback), |
| 35 token_fetcher_(std::move(token_fetcher)), | 35 token_fetcher_(std::move(token_fetcher)), |
| 36 method_set_by_host_(false), | |
| 37 weak_factory_(this) { | 36 weak_factory_(this) { |
| 38 DCHECK(!methods.empty()); | 37 AddMethod(Method::THIRD_PARTY); |
| 39 for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin(); | 38 AddMethod(Method::SPAKE2_PAIR); |
| 40 it != methods.end(); ++it) { | 39 AddMethod(Method::SPAKE2_SHARED_SECRET_HMAC); |
| 41 AddMethod(*it); | 40 AddMethod(Method::SPAKE2_SHARED_SECRET_PLAIN); |
| 42 } | |
| 43 } | 41 } |
| 44 | 42 |
| 45 NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() {} | 43 NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() {} |
| 46 | 44 |
| 47 void NegotiatingClientAuthenticator::ProcessMessage( | 45 void NegotiatingClientAuthenticator::ProcessMessage( |
| 48 const buzz::XmlElement* message, | 46 const buzz::XmlElement* message, |
| 49 const base::Closure& resume_callback) { | 47 const base::Closure& resume_callback) { |
| 50 DCHECK_EQ(state(), WAITING_MESSAGE); | 48 DCHECK_EQ(state(), WAITING_MESSAGE); |
| 51 | 49 |
| 52 std::string method_attr = message->Attr(kMethodAttributeQName); | 50 std::string method_attr = message->Attr(kMethodAttributeQName); |
| 53 AuthenticationMethod method = ParseAuthenticationMethodString(method_attr); | 51 Method method = ParseMethodString(method_attr); |
| 54 | 52 |
| 55 // The host picked a method different from the one the client had selected. | 53 // The host picked a method different from the one the client had selected. |
| 56 if (method != current_method_) { | 54 if (method != current_method_) { |
| 57 // The host must pick a method that is valid and supported by the client, | 55 // The host must pick a method that is valid and supported by the client, |
| 58 // and it must not change methods after it has picked one. | 56 // and it must not change methods after it has picked one. |
| 59 if (method_set_by_host_ || method == AuthenticationMethod::INVALID || | 57 if (method_set_by_host_ || method == Method::INVALID || |
| 60 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { | 58 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { |
| 61 state_ = REJECTED; | 59 state_ = REJECTED; |
| 62 rejection_reason_ = PROTOCOL_ERROR; | 60 rejection_reason_ = PROTOCOL_ERROR; |
| 63 resume_callback.Run(); | 61 resume_callback.Run(); |
| 64 return; | 62 return; |
| 65 } | 63 } |
| 66 | 64 |
| 67 current_method_ = method; | 65 current_method_ = method; |
| 68 method_set_by_host_ = true; | 66 method_set_by_host_ = true; |
| 69 state_ = PROCESSING_MESSAGE; | 67 state_ = PROCESSING_MESSAGE; |
| 70 | 68 |
| 71 // Copy the message since the authenticator may process it asynchronously. | 69 // Copy the message since the authenticator may process it asynchronously. |
| 72 base::Closure callback = base::Bind( | 70 base::Closure callback = base::Bind( |
| 73 &NegotiatingAuthenticatorBase::ProcessMessageInternal, | 71 &NegotiatingAuthenticatorBase::ProcessMessageInternal, |
| 74 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), | 72 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), |
| 75 resume_callback); | 73 resume_callback); |
| 76 CreateAuthenticatorForCurrentMethod(WAITING_MESSAGE, callback); | 74 CreateAuthenticatorForCurrentMethod(WAITING_MESSAGE, callback); |
| 77 return; | 75 return; |
| 78 } | 76 } |
| 79 ProcessMessageInternal(message, resume_callback); | 77 ProcessMessageInternal(message, resume_callback); |
| 80 } | 78 } |
| 81 | 79 |
| 82 scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { | 80 scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { |
| 83 DCHECK_EQ(state(), MESSAGE_READY); | 81 DCHECK_EQ(state(), MESSAGE_READY); |
| 84 | 82 |
| 85 // This is the first message to the host, send a list of supported methods. | 83 // This is the first message to the host, send a list of supported methods. |
| 86 if (current_method_ == AuthenticationMethod::INVALID) { | 84 if (current_method_ == Method::INVALID) { |
| 87 // If no authentication method has been chosen, see if we can optimistically | 85 // If no authentication method has been chosen, see if we can optimistically |
| 88 // choose one. | 86 // choose one. |
| 89 scoped_ptr<buzz::XmlElement> result; | 87 scoped_ptr<buzz::XmlElement> result; |
| 90 CreatePreferredAuthenticator(); | 88 CreatePreferredAuthenticator(); |
| 91 if (current_authenticator_) { | 89 if (current_authenticator_) { |
| 92 DCHECK(current_authenticator_->state() == MESSAGE_READY); | 90 DCHECK(current_authenticator_->state() == MESSAGE_READY); |
| 93 result = GetNextMessageInternal(); | 91 result = GetNextMessageInternal(); |
| 94 } else { | 92 } else { |
| 95 result = CreateEmptyAuthenticatorMessage(); | 93 result = CreateEmptyAuthenticatorMessage(); |
| 96 } | 94 } |
| 97 | 95 |
| 98 // Include a list of supported methods. | 96 // Include a list of supported methods. |
| 99 std::string supported_methods; | 97 std::string supported_methods; |
| 100 for (AuthenticationMethod method : methods_) { | 98 for (Method method : methods_) { |
| 101 if (!supported_methods.empty()) | 99 if (!supported_methods.empty()) |
| 102 supported_methods += kSupportedMethodsSeparator; | 100 supported_methods += kSupportedMethodsSeparator; |
| 103 supported_methods += AuthenticationMethodToString(method); | 101 supported_methods += MethodToString(method); |
| 104 } | 102 } |
| 105 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods); | 103 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods); |
| 106 state_ = WAITING_MESSAGE; | 104 state_ = WAITING_MESSAGE; |
| 107 return result; | 105 return result; |
| 108 } | 106 } |
| 109 return GetNextMessageInternal(); | 107 return GetNextMessageInternal(); |
| 110 } | 108 } |
| 111 | 109 |
| 112 void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( | 110 void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( |
| 113 Authenticator::State preferred_initial_state, | 111 Authenticator::State preferred_initial_state, |
| 114 const base::Closure& resume_callback) { | 112 const base::Closure& resume_callback) { |
| 115 DCHECK(current_method_ != AuthenticationMethod::INVALID); | 113 DCHECK(current_method_ != Method::INVALID); |
| 116 if (current_method_ == AuthenticationMethod::THIRD_PARTY) { | 114 if (current_method_ == Method::THIRD_PARTY) { |
| 117 // |ThirdPartyClientAuthenticator| takes ownership of |token_fetcher_|. | 115 // |ThirdPartyClientAuthenticator| takes ownership of |token_fetcher_|. |
| 118 // The authentication method negotiation logic should guarantee that only | 116 // The authentication method negotiation logic should guarantee that only |
| 119 // one |ThirdPartyClientAuthenticator| will need to be created per session. | 117 // one |ThirdPartyClientAuthenticator| will need to be created per session. |
| 120 DCHECK(token_fetcher_); | 118 DCHECK(token_fetcher_); |
| 121 current_authenticator_.reset(new ThirdPartyClientAuthenticator( | 119 current_authenticator_.reset(new ThirdPartyClientAuthenticator( |
| 122 base::Bind(&V2Authenticator::CreateForClient), | 120 base::Bind(&V2Authenticator::CreateForClient), |
| 123 std::move(token_fetcher_))); | 121 std::move(token_fetcher_))); |
| 124 resume_callback.Run(); | 122 resume_callback.Run(); |
| 125 } else { | 123 } else { |
| 126 DCHECK(current_method_ == | 124 DCHECK(current_method_ == Method::SPAKE2_SHARED_SECRET_PLAIN || |
| 127 AuthenticationMethod::SPAKE2_SHARED_SECRET_PLAIN || | 125 current_method_ == Method::SPAKE2_PAIR || |
| 128 current_method_ == AuthenticationMethod::SPAKE2_SHARED_SECRET_HMAC || | 126 current_method_ == Method::SPAKE2_SHARED_SECRET_HMAC); |
| 129 current_method_ == AuthenticationMethod::SPAKE2_PAIR); | 127 bool pairing_supported = (current_method_ == Method::SPAKE2_PAIR); |
| 130 bool pairing_supported = | |
| 131 (current_method_ == AuthenticationMethod::SPAKE2_PAIR); | |
| 132 SecretFetchedCallback callback = base::Bind( | 128 SecretFetchedCallback callback = base::Bind( |
| 133 &NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret, | 129 &NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret, |
| 134 weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback); | 130 weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback); |
| 135 fetch_secret_callback_.Run(pairing_supported, callback); | 131 fetch_secret_callback_.Run(pairing_supported, callback); |
| 136 } | 132 } |
| 137 } | 133 } |
| 138 | 134 |
| 139 void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { | 135 void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { |
| 140 if (!client_pairing_id_.empty() && !shared_secret_.empty() && | 136 if (!client_pairing_id_.empty() && !shared_secret_.empty() && |
| 141 std::find(methods_.begin(), methods_.end(), | 137 std::find(methods_.begin(), methods_.end(), Method::SPAKE2_PAIR) != |
| 142 AuthenticationMethod::SPAKE2_PAIR) != methods_.end()) { | 138 methods_.end()) { |
| 143 // If the client specified a pairing id and shared secret, then create a | 139 // If the client specified a pairing id and shared secret, then create a |
| 144 // PairingAuthenticator. | 140 // PairingAuthenticator. |
| 145 current_authenticator_.reset(new PairingClientAuthenticator( | 141 current_authenticator_.reset(new PairingClientAuthenticator( |
| 146 client_pairing_id_, shared_secret_, | 142 client_pairing_id_, shared_secret_, |
| 147 base::Bind(&V2Authenticator::CreateForClient), fetch_secret_callback_, | 143 base::Bind(&V2Authenticator::CreateForClient), fetch_secret_callback_, |
| 148 authentication_tag_)); | 144 authentication_tag_)); |
| 149 current_method_ = AuthenticationMethod::SPAKE2_PAIR; | 145 current_method_ = Method::SPAKE2_PAIR; |
| 150 } | 146 } |
| 151 } | 147 } |
| 152 | 148 |
| 153 void NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret( | 149 void NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret( |
| 154 Authenticator::State initial_state, | 150 Authenticator::State initial_state, |
| 155 const base::Closure& resume_callback, | 151 const base::Closure& resume_callback, |
| 156 const std::string& shared_secret) { | 152 const std::string& shared_secret) { |
| 157 current_authenticator_ = V2Authenticator::CreateForClient( | 153 current_authenticator_ = V2Authenticator::CreateForClient( |
| 158 ApplySharedSecretHashFunction( | 154 (current_method_ == Method::SPAKE2_SHARED_SECRET_PLAIN) |
| 159 GetHashFunctionForAuthenticationMethod(current_method_), | 155 ? shared_secret |
| 160 authentication_tag_, shared_secret), | 156 : GetSharedSecretHash(authentication_tag_, shared_secret), |
| 161 initial_state); | 157 initial_state); |
| 162 resume_callback.Run(); | 158 resume_callback.Run(); |
| 163 } | 159 } |
| 164 | 160 |
| 165 } // namespace protocol | 161 } // namespace protocol |
| 166 } // namespace remoting | 162 } // namespace remoting |
| OLD | NEW |