Chromium Code Reviews| 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 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 44 | 44 |
| 45 NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() { | 45 NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() { |
| 46 } | 46 } |
| 47 | 47 |
| 48 void NegotiatingClientAuthenticator::ProcessMessage( | 48 void NegotiatingClientAuthenticator::ProcessMessage( |
| 49 const buzz::XmlElement* message, | 49 const buzz::XmlElement* message, |
| 50 const base::Closure& resume_callback) { | 50 const base::Closure& resume_callback) { |
| 51 DCHECK_EQ(state(), WAITING_MESSAGE); | 51 DCHECK_EQ(state(), WAITING_MESSAGE); |
| 52 | 52 |
| 53 std::string method_attr = message->Attr(kMethodAttributeQName); | 53 std::string method_attr = message->Attr(kMethodAttributeQName); |
| 54 AuthenticationMethod method = AuthenticationMethod::FromString(method_attr); | 54 AuthenticationMethod method = ParseAuthenticationMethodString(method_attr); |
| 55 | 55 |
| 56 // The host picked a method different from the one the client had selected. | 56 // The host picked a method different from the one the client had selected. |
| 57 if (method != current_method_) { | 57 if (method != current_method_) { |
| 58 // The host must pick a method that is valid and supported by the client, | 58 // The host must pick a method that is valid and supported by the client, |
| 59 // and it must not change methods after it has picked one. | 59 // and it must not change methods after it has picked one. |
| 60 if (method_set_by_host_ || !method.is_valid() || | 60 if (method_set_by_host_ || method == AuthenticationMethod::INVALID || |
| 61 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { | 61 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { |
| 62 state_ = REJECTED; | 62 state_ = REJECTED; |
| 63 rejection_reason_ = PROTOCOL_ERROR; | 63 rejection_reason_ = PROTOCOL_ERROR; |
| 64 resume_callback.Run(); | 64 resume_callback.Run(); |
| 65 return; | 65 return; |
| 66 } | 66 } |
| 67 | 67 |
| 68 current_method_ = method; | 68 current_method_ = method; |
| 69 method_set_by_host_ = true; | 69 method_set_by_host_ = true; |
| 70 state_ = PROCESSING_MESSAGE; | 70 state_ = PROCESSING_MESSAGE; |
| 71 | 71 |
| 72 // Copy the message since the authenticator may process it asynchronously. | 72 // Copy the message since the authenticator may process it asynchronously. |
| 73 base::Closure callback = base::Bind( | 73 base::Closure callback = base::Bind( |
| 74 &NegotiatingAuthenticatorBase::ProcessMessageInternal, | 74 &NegotiatingAuthenticatorBase::ProcessMessageInternal, |
| 75 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), | 75 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), |
| 76 resume_callback); | 76 resume_callback); |
| 77 CreateAuthenticatorForCurrentMethod(WAITING_MESSAGE, callback); | 77 CreateAuthenticatorForCurrentMethod(WAITING_MESSAGE, callback); |
| 78 return; | 78 return; |
| 79 } | 79 } |
| 80 ProcessMessageInternal(message, resume_callback); | 80 ProcessMessageInternal(message, resume_callback); |
| 81 } | 81 } |
| 82 | 82 |
| 83 scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { | 83 scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { |
| 84 DCHECK_EQ(state(), MESSAGE_READY); | 84 DCHECK_EQ(state(), MESSAGE_READY); |
| 85 | 85 |
| 86 // This is the first message to the host, send a list of supported methods. | 86 // This is the first message to the host, send a list of supported methods. |
| 87 if (!current_method_.is_valid()) { | 87 if (current_method_ == AuthenticationMethod::INVALID) { |
| 88 // If no authentication method has been chosen, see if we can optimistically | 88 // If no authentication method has been chosen, see if we can optimistically |
| 89 // choose one. | 89 // choose one. |
| 90 scoped_ptr<buzz::XmlElement> result; | 90 scoped_ptr<buzz::XmlElement> result; |
| 91 CreatePreferredAuthenticator(); | 91 CreatePreferredAuthenticator(); |
| 92 if (current_authenticator_) { | 92 if (current_authenticator_) { |
| 93 DCHECK(current_authenticator_->state() == MESSAGE_READY); | 93 DCHECK(current_authenticator_->state() == MESSAGE_READY); |
| 94 result = GetNextMessageInternal(); | 94 result = GetNextMessageInternal(); |
| 95 } else { | 95 } else { |
| 96 result = CreateEmptyAuthenticatorMessage(); | 96 result = CreateEmptyAuthenticatorMessage(); |
| 97 } | 97 } |
| 98 | 98 |
| 99 // Include a list of supported methods. | 99 // Include a list of supported methods. |
| 100 std::stringstream supported_methods(std::stringstream::out); | 100 std::string supported_methods; |
|
kelvinp
2016/03/04 18:40:54
Out of curiosity, why do we switch from stringstre
Sergey Ulanov
2016/03/04 20:48:51
I don't know why thought it was a good idea when I
| |
| 101 for (std::vector<AuthenticationMethod>::iterator it = methods_.begin(); | 101 for (AuthenticationMethod method : methods_) { |
| 102 it != methods_.end(); ++it) { | 102 if (!supported_methods.empty()) |
| 103 if (it != methods_.begin()) | 103 supported_methods += kSupportedMethodsSeparator; |
| 104 supported_methods << kSupportedMethodsSeparator; | 104 supported_methods += AuthenticationMethodToString(method); |
| 105 supported_methods << it->ToString(); | |
| 106 } | 105 } |
| 107 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods.str()); | 106 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods); |
| 108 state_ = WAITING_MESSAGE; | 107 state_ = WAITING_MESSAGE; |
| 109 return result; | 108 return result; |
| 110 } | 109 } |
| 111 return GetNextMessageInternal(); | 110 return GetNextMessageInternal(); |
| 112 } | 111 } |
| 113 | 112 |
| 114 void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( | 113 void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( |
| 115 Authenticator::State preferred_initial_state, | 114 Authenticator::State preferred_initial_state, |
| 116 const base::Closure& resume_callback) { | 115 const base::Closure& resume_callback) { |
| 117 DCHECK(current_method_.is_valid()); | 116 DCHECK(current_method_ != AuthenticationMethod::INVALID); |
| 118 if (current_method_.type() == AuthenticationMethod::THIRD_PARTY) { | 117 if (current_method_ == AuthenticationMethod::THIRD_PARTY) { |
| 119 // |ThirdPartyClientAuthenticator| takes ownership of |token_fetcher_|. | 118 // |ThirdPartyClientAuthenticator| takes ownership of |token_fetcher_|. |
| 120 // The authentication method negotiation logic should guarantee that only | 119 // The authentication method negotiation logic should guarantee that only |
| 121 // one |ThirdPartyClientAuthenticator| will need to be created per session. | 120 // one |ThirdPartyClientAuthenticator| will need to be created per session. |
| 122 DCHECK(token_fetcher_); | 121 DCHECK(token_fetcher_); |
| 123 current_authenticator_.reset(new ThirdPartyClientAuthenticator( | 122 current_authenticator_.reset(new ThirdPartyClientAuthenticator( |
| 124 std::move(token_fetcher_))); | 123 std::move(token_fetcher_))); |
| 125 resume_callback.Run(); | 124 resume_callback.Run(); |
| 126 } else { | 125 } else { |
| 127 DCHECK(current_method_.type() == AuthenticationMethod::SPAKE2 || | 126 DCHECK(current_method_ == |
| 128 current_method_.type() == AuthenticationMethod::SPAKE2_PAIR); | 127 AuthenticationMethod::SPAKE2_SHARED_SECRET_PLAIN || |
| 128 current_method_ == AuthenticationMethod::SPAKE2_SHARED_SECRET_HMAC || | |
| 129 current_method_ == AuthenticationMethod::SPAKE2_PAIR); | |
| 129 bool pairing_supported = | 130 bool pairing_supported = |
| 130 (current_method_.type() == AuthenticationMethod::SPAKE2_PAIR); | 131 (current_method_ == AuthenticationMethod::SPAKE2_PAIR); |
| 131 SecretFetchedCallback callback = base::Bind( | 132 SecretFetchedCallback callback = base::Bind( |
| 132 &NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret, | 133 &NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret, |
| 133 weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback); | 134 weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback); |
| 134 fetch_secret_callback_.Run(pairing_supported, callback); | 135 fetch_secret_callback_.Run(pairing_supported, callback); |
| 135 } | 136 } |
| 136 } | 137 } |
| 137 | 138 |
| 138 void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { | 139 void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { |
| 139 if (!client_pairing_id_.empty() && !shared_secret_.empty() && | 140 if (!client_pairing_id_.empty() && !shared_secret_.empty() && |
| 140 std::find(methods_.begin(), methods_.end(), | 141 std::find(methods_.begin(), methods_.end(), |
| 141 AuthenticationMethod::Spake2Pair()) != methods_.end()) { | 142 AuthenticationMethod::SPAKE2_PAIR) != methods_.end()) { |
| 142 // If the client specified a pairing id and shared secret, then create a | 143 // If the client specified a pairing id and shared secret, then create a |
| 143 // PairingAuthenticator. | 144 // PairingAuthenticator. |
| 144 current_authenticator_.reset(new PairingClientAuthenticator( | 145 current_authenticator_.reset(new PairingClientAuthenticator( |
| 145 client_pairing_id_, shared_secret_, fetch_secret_callback_, | 146 client_pairing_id_, shared_secret_, fetch_secret_callback_, |
| 146 authentication_tag_)); | 147 authentication_tag_)); |
| 147 current_method_ = AuthenticationMethod::Spake2Pair(); | 148 current_method_ = AuthenticationMethod::SPAKE2_PAIR; |
| 148 } | 149 } |
| 149 } | 150 } |
| 150 | 151 |
| 151 void NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret( | 152 void NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret( |
| 152 Authenticator::State initial_state, | 153 Authenticator::State initial_state, |
| 153 const base::Closure& resume_callback, | 154 const base::Closure& resume_callback, |
| 154 const std::string& shared_secret) { | 155 const std::string& shared_secret) { |
| 155 current_authenticator_ = V2Authenticator::CreateForClient( | 156 current_authenticator_ = V2Authenticator::CreateForClient( |
| 156 AuthenticationMethod::ApplyHashFunction( | 157 ApplySharedSecretHashFunction( |
| 157 current_method_.hash_function(), authentication_tag_, shared_secret), | 158 GetHashFunctionForAuthenticationMethod(current_method_), |
| 159 authentication_tag_, shared_secret), | |
| 158 initial_state); | 160 initial_state); |
| 159 resume_callback.Run(); | 161 resume_callback.Run(); |
| 160 } | 162 } |
| 161 | 163 |
| 162 } // namespace protocol | 164 } // namespace protocol |
| 163 } // namespace remoting | 165 } // namespace remoting |
| OLD | NEW |