| 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_host_authenticator.h" | 5 #include "remoting/protocol/negotiating_host_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 20 matching lines...) Expand all Loading... |
| 31 local_key_pair_(key_pair) {} | 31 local_key_pair_(key_pair) {} |
| 32 | 32 |
| 33 // static | 33 // static |
| 34 scoped_ptr<Authenticator> NegotiatingHostAuthenticator::CreateForIt2Me( | 34 scoped_ptr<Authenticator> NegotiatingHostAuthenticator::CreateForIt2Me( |
| 35 const std::string& local_cert, | 35 const std::string& local_cert, |
| 36 scoped_refptr<RsaKeyPair> key_pair, | 36 scoped_refptr<RsaKeyPair> key_pair, |
| 37 const std::string& access_code) { | 37 const std::string& access_code) { |
| 38 scoped_ptr<NegotiatingHostAuthenticator> result( | 38 scoped_ptr<NegotiatingHostAuthenticator> result( |
| 39 new NegotiatingHostAuthenticator(local_cert, key_pair)); | 39 new NegotiatingHostAuthenticator(local_cert, key_pair)); |
| 40 result->shared_secret_hash_ = access_code; | 40 result->shared_secret_hash_ = access_code; |
| 41 result->AddMethod(AuthenticationMethod::SPAKE2_SHARED_SECRET_PLAIN); | 41 result->AddMethod(Method::SPAKE2_SHARED_SECRET_PLAIN); |
| 42 return std::move(result); | 42 return std::move(result); |
| 43 } | 43 } |
| 44 | 44 |
| 45 // static | 45 // static |
| 46 scoped_ptr<Authenticator> NegotiatingHostAuthenticator::CreateWithPin( | 46 scoped_ptr<Authenticator> NegotiatingHostAuthenticator::CreateWithPin( |
| 47 const std::string& local_cert, | 47 const std::string& local_cert, |
| 48 scoped_refptr<RsaKeyPair> key_pair, | 48 scoped_refptr<RsaKeyPair> key_pair, |
| 49 const std::string& pin_hash, | 49 const std::string& pin_hash, |
| 50 scoped_refptr<PairingRegistry> pairing_registry) { | 50 scoped_refptr<PairingRegistry> pairing_registry) { |
| 51 scoped_ptr<NegotiatingHostAuthenticator> result( | 51 scoped_ptr<NegotiatingHostAuthenticator> result( |
| 52 new NegotiatingHostAuthenticator(local_cert, key_pair)); | 52 new NegotiatingHostAuthenticator(local_cert, key_pair)); |
| 53 result->shared_secret_hash_ = pin_hash; | 53 result->shared_secret_hash_ = pin_hash; |
| 54 result->pairing_registry_ = pairing_registry; | 54 result->pairing_registry_ = pairing_registry; |
| 55 result->AddMethod(AuthenticationMethod::SPAKE2_SHARED_SECRET_HMAC); | 55 result->AddMethod(Method::SPAKE2_SHARED_SECRET_HMAC); |
| 56 if (pairing_registry.get()) { | 56 if (pairing_registry.get()) { |
| 57 result->AddMethod(AuthenticationMethod::SPAKE2_PAIR); | 57 result->AddMethod(Method::SPAKE2_PAIR); |
| 58 } | 58 } |
| 59 return std::move(result); | 59 return std::move(result); |
| 60 } | 60 } |
| 61 | 61 |
| 62 // static | 62 // static |
| 63 scoped_ptr<Authenticator> | 63 scoped_ptr<Authenticator> |
| 64 NegotiatingHostAuthenticator::CreateWithThirdPartyAuth( | 64 NegotiatingHostAuthenticator::CreateWithThirdPartyAuth( |
| 65 const std::string& local_cert, | 65 const std::string& local_cert, |
| 66 scoped_refptr<RsaKeyPair> key_pair, | 66 scoped_refptr<RsaKeyPair> key_pair, |
| 67 scoped_ptr<TokenValidator> token_validator) { | 67 scoped_ptr<TokenValidator> token_validator) { |
| 68 scoped_ptr<NegotiatingHostAuthenticator> result( | 68 scoped_ptr<NegotiatingHostAuthenticator> result( |
| 69 new NegotiatingHostAuthenticator(local_cert, key_pair)); | 69 new NegotiatingHostAuthenticator(local_cert, key_pair)); |
| 70 result->token_validator_ = std::move(token_validator); | 70 result->token_validator_ = std::move(token_validator); |
| 71 result->AddMethod(AuthenticationMethod::THIRD_PARTY); | 71 result->AddMethod(Method::THIRD_PARTY); |
| 72 return std::move(result); | 72 return std::move(result); |
| 73 } | 73 } |
| 74 | 74 |
| 75 NegotiatingHostAuthenticator::~NegotiatingHostAuthenticator() { | 75 NegotiatingHostAuthenticator::~NegotiatingHostAuthenticator() { |
| 76 } | 76 } |
| 77 | 77 |
| 78 void NegotiatingHostAuthenticator::ProcessMessage( | 78 void NegotiatingHostAuthenticator::ProcessMessage( |
| 79 const buzz::XmlElement* message, | 79 const buzz::XmlElement* message, |
| 80 const base::Closure& resume_callback) { | 80 const base::Closure& resume_callback) { |
| 81 DCHECK_EQ(state(), WAITING_MESSAGE); | 81 DCHECK_EQ(state(), WAITING_MESSAGE); |
| 82 | 82 |
| 83 std::string method_attr = message->Attr(kMethodAttributeQName); | 83 std::string method_attr = message->Attr(kMethodAttributeQName); |
| 84 AuthenticationMethod method = ParseAuthenticationMethodString(method_attr); | 84 Method method = ParseMethodString(method_attr); |
| 85 | 85 |
| 86 // If the host has already chosen a method, it can't be changed by the client. | 86 // If the host has already chosen a method, it can't be changed by the client. |
| 87 if (current_method_ != AuthenticationMethod::INVALID && | 87 if (current_method_ != Method::INVALID && method != current_method_) { |
| 88 method != current_method_) { | |
| 89 state_ = REJECTED; | 88 state_ = REJECTED; |
| 90 rejection_reason_ = PROTOCOL_ERROR; | 89 rejection_reason_ = PROTOCOL_ERROR; |
| 91 resume_callback.Run(); | 90 resume_callback.Run(); |
| 92 return; | 91 return; |
| 93 } | 92 } |
| 94 | 93 |
| 95 // If the client did not specify a preferred auth method, or specified an | 94 // If the client did not specify a preferred auth method, or specified an |
| 96 // unknown or unsupported method, then select the first known method from | 95 // unknown or unsupported method, then select the first known method from |
| 97 // the supported-methods attribute. | 96 // the supported-methods attribute. |
| 98 if (method == AuthenticationMethod::INVALID || | 97 if (method == Method::INVALID || |
| 99 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { | 98 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { |
| 100 method = AuthenticationMethod::INVALID; | 99 method = Method::INVALID; |
| 101 | 100 |
| 102 std::string supported_methods_attr = | 101 std::string supported_methods_attr = |
| 103 message->Attr(kSupportedMethodsAttributeQName); | 102 message->Attr(kSupportedMethodsAttributeQName); |
| 104 if (supported_methods_attr.empty()) { | 103 if (supported_methods_attr.empty()) { |
| 105 // Message contains neither method nor supported-methods attributes. | 104 // Message contains neither method nor supported-methods attributes. |
| 106 state_ = REJECTED; | 105 state_ = REJECTED; |
| 107 rejection_reason_ = PROTOCOL_ERROR; | 106 rejection_reason_ = PROTOCOL_ERROR; |
| 108 resume_callback.Run(); | 107 resume_callback.Run(); |
| 109 return; | 108 return; |
| 110 } | 109 } |
| 111 | 110 |
| 112 // Find the first mutually-supported method in the client's list of | 111 // Find the first mutually-supported method in the client's list of |
| 113 // supported-methods. | 112 // supported-methods. |
| 114 for (const std::string& method_str : | 113 for (const std::string& method_str : |
| 115 base::SplitString(supported_methods_attr, | 114 base::SplitString(supported_methods_attr, |
| 116 std::string(1, kSupportedMethodsSeparator), | 115 std::string(1, kSupportedMethodsSeparator), |
| 117 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { | 116 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { |
| 118 AuthenticationMethod list_value = | 117 Method list_value = ParseMethodString(method_str); |
| 119 ParseAuthenticationMethodString(method_str); | 118 if (list_value != Method::INVALID && |
| 120 if (list_value != AuthenticationMethod::INVALID && | |
| 121 std::find(methods_.begin(), methods_.end(), list_value) != | 119 std::find(methods_.begin(), methods_.end(), list_value) != |
| 122 methods_.end()) { | 120 methods_.end()) { |
| 123 // Found common method. | 121 // Found common method. |
| 124 method = list_value; | 122 method = list_value; |
| 125 break; | 123 break; |
| 126 } | 124 } |
| 127 } | 125 } |
| 128 | 126 |
| 129 if (method == AuthenticationMethod::INVALID) { | 127 if (method == Method::INVALID) { |
| 130 // Failed to find a common auth method. | 128 // Failed to find a common auth method. |
| 131 state_ = REJECTED; | 129 state_ = REJECTED; |
| 132 rejection_reason_ = PROTOCOL_ERROR; | 130 rejection_reason_ = PROTOCOL_ERROR; |
| 133 resume_callback.Run(); | 131 resume_callback.Run(); |
| 134 return; | 132 return; |
| 135 } | 133 } |
| 136 | 134 |
| 137 // Drop the current message because we've chosen a different method. | 135 // Drop the current message because we've chosen a different method. |
| 138 current_method_ = method; | 136 current_method_ = method; |
| 139 state_ = PROCESSING_MESSAGE; | 137 state_ = PROCESSING_MESSAGE; |
| 140 CreateAuthenticator(MESSAGE_READY, base::Bind( | 138 CreateAuthenticator(MESSAGE_READY, base::Bind( |
| 141 &NegotiatingHostAuthenticator::UpdateState, | 139 &NegotiatingHostAuthenticator::UpdateState, |
| 142 base::Unretained(this), resume_callback)); | 140 base::Unretained(this), resume_callback)); |
| 143 return; | 141 return; |
| 144 } | 142 } |
| 145 | 143 |
| 146 // If the client specified a supported method, and the host hasn't chosen a | 144 // If the client specified a supported method, and the host hasn't chosen a |
| 147 // method yet, use the client's preferred method and process the message. | 145 // method yet, use the client's preferred method and process the message. |
| 148 if (current_method_ == AuthenticationMethod::INVALID) { | 146 if (current_method_ == Method::INVALID) { |
| 149 current_method_ = method; | 147 current_method_ = method; |
| 150 state_ = PROCESSING_MESSAGE; | 148 state_ = PROCESSING_MESSAGE; |
| 151 // Copy the message since the authenticator may process it asynchronously. | 149 // Copy the message since the authenticator may process it asynchronously. |
| 152 CreateAuthenticator(WAITING_MESSAGE, base::Bind( | 150 CreateAuthenticator(WAITING_MESSAGE, base::Bind( |
| 153 &NegotiatingAuthenticatorBase::ProcessMessageInternal, | 151 &NegotiatingAuthenticatorBase::ProcessMessageInternal, |
| 154 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), | 152 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), |
| 155 resume_callback)); | 153 resume_callback)); |
| 156 return; | 154 return; |
| 157 } | 155 } |
| 158 | 156 |
| 159 // If the client is using the host's current method, just process the message. | 157 // If the client is using the host's current method, just process the message. |
| 160 ProcessMessageInternal(message, resume_callback); | 158 ProcessMessageInternal(message, resume_callback); |
| 161 } | 159 } |
| 162 | 160 |
| 163 scoped_ptr<buzz::XmlElement> NegotiatingHostAuthenticator::GetNextMessage() { | 161 scoped_ptr<buzz::XmlElement> NegotiatingHostAuthenticator::GetNextMessage() { |
| 164 return GetNextMessageInternal(); | 162 return GetNextMessageInternal(); |
| 165 } | 163 } |
| 166 | 164 |
| 167 void NegotiatingHostAuthenticator::CreateAuthenticator( | 165 void NegotiatingHostAuthenticator::CreateAuthenticator( |
| 168 Authenticator::State preferred_initial_state, | 166 Authenticator::State preferred_initial_state, |
| 169 const base::Closure& resume_callback) { | 167 const base::Closure& resume_callback) { |
| 170 DCHECK(current_method_ != AuthenticationMethod::INVALID); | 168 DCHECK(current_method_ != Method::INVALID); |
| 171 | 169 |
| 172 if (current_method_ == AuthenticationMethod::THIRD_PARTY) { | 170 if (current_method_ == Method::THIRD_PARTY) { |
| 173 // |ThirdPartyHostAuthenticator| takes ownership of |token_validator_|. | 171 // |ThirdPartyHostAuthenticator| takes ownership of |token_validator_|. |
| 174 // The authentication method negotiation logic should guarantee that only | 172 // The authentication method negotiation logic should guarantee that only |
| 175 // one |ThirdPartyHostAuthenticator| will need to be created per session. | 173 // one |ThirdPartyHostAuthenticator| will need to be created per session. |
| 176 DCHECK(token_validator_); | 174 DCHECK(token_validator_); |
| 177 current_authenticator_.reset(new ThirdPartyHostAuthenticator( | 175 current_authenticator_.reset(new ThirdPartyHostAuthenticator( |
| 178 base::Bind(&V2Authenticator::CreateForHost, local_cert_, | 176 base::Bind(&V2Authenticator::CreateForHost, local_cert_, |
| 179 local_key_pair_), | 177 local_key_pair_), |
| 180 std::move(token_validator_))); | 178 std::move(token_validator_))); |
| 181 } else if (current_method_ == AuthenticationMethod::SPAKE2_PAIR && | 179 } else if (current_method_ == Method::SPAKE2_PAIR && |
| 182 preferred_initial_state == WAITING_MESSAGE) { | 180 preferred_initial_state == WAITING_MESSAGE) { |
| 183 // If the client requested Spake2Pair and sent an initial message, attempt | 181 // If the client requested Spake2Pair and sent an initial message, attempt |
| 184 // the paired connection protocol. | 182 // the paired connection protocol. |
| 185 current_authenticator_.reset(new PairingHostAuthenticator( | 183 current_authenticator_.reset(new PairingHostAuthenticator( |
| 186 pairing_registry_, base::Bind(&V2Authenticator::CreateForHost, | 184 pairing_registry_, base::Bind(&V2Authenticator::CreateForHost, |
| 187 local_cert_, local_key_pair_), | 185 local_cert_, local_key_pair_), |
| 188 shared_secret_hash_)); | 186 shared_secret_hash_)); |
| 189 } else { | 187 } else { |
| 190 // In all other cases, use the V2 protocol. Note that this includes the | 188 // In all other cases, use the V2 protocol. Note that this includes the |
| 191 // case where the protocol is Spake2Pair but the client is not yet paired. | 189 // case where the protocol is Spake2Pair but the client is not yet paired. |
| 192 // In this case, the on-the-wire protocol is plain Spake2, advertised as | 190 // In this case, the on-the-wire protocol is plain Spake2, advertised as |
| 193 // Spake2Pair so that the client knows that the host supports pairing and | 191 // Spake2Pair so that the client knows that the host supports pairing and |
| 194 // that it can therefore present the option to the user when they enter | 192 // that it can therefore present the option to the user when they enter |
| 195 // the PIN. | 193 // the PIN. |
| 196 DCHECK(current_method_ == | 194 DCHECK(current_method_ == Method::SPAKE2_SHARED_SECRET_PLAIN || |
| 197 AuthenticationMethod::SPAKE2_SHARED_SECRET_PLAIN || | 195 current_method_ == Method::SPAKE2_SHARED_SECRET_HMAC || |
| 198 current_method_ == AuthenticationMethod::SPAKE2_SHARED_SECRET_HMAC || | 196 current_method_ == Method::SPAKE2_PAIR); |
| 199 current_method_ == AuthenticationMethod::SPAKE2_PAIR); | |
| 200 current_authenticator_ = V2Authenticator::CreateForHost( | 197 current_authenticator_ = V2Authenticator::CreateForHost( |
| 201 local_cert_, local_key_pair_, shared_secret_hash_, | 198 local_cert_, local_key_pair_, shared_secret_hash_, |
| 202 preferred_initial_state); | 199 preferred_initial_state); |
| 203 } | 200 } |
| 204 resume_callback.Run(); | 201 resume_callback.Run(); |
| 205 } | 202 } |
| 206 | 203 |
| 207 } // namespace protocol | 204 } // namespace protocol |
| 208 } // namespace remoting | 205 } // namespace remoting |
| OLD | NEW |