| 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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 | 43 |
| 44 AddMethod(Method::SHARED_SECRET_PLAIN_SPAKE2_P224); | 44 AddMethod(Method::SHARED_SECRET_PLAIN_SPAKE2_P224); |
| 45 } | 45 } |
| 46 | 46 |
| 47 NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() {} | 47 NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() {} |
| 48 | 48 |
| 49 void NegotiatingClientAuthenticator::ProcessMessage( | 49 void NegotiatingClientAuthenticator::ProcessMessage( |
| 50 const buzz::XmlElement* message, | 50 const buzz::XmlElement* message, |
| 51 const base::Closure& resume_callback) { | 51 const base::Closure& resume_callback) { |
| 52 DCHECK_EQ(state(), WAITING_MESSAGE); | 52 DCHECK_EQ(state(), WAITING_MESSAGE); |
| 53 state_ = PROCESSING_MESSAGE; |
| 53 | 54 |
| 54 std::string method_attr = message->Attr(kMethodAttributeQName); | 55 std::string method_attr = message->Attr(kMethodAttributeQName); |
| 55 Method method = ParseMethodString(method_attr); | 56 Method method = ParseMethodString(method_attr); |
| 56 | 57 |
| 57 // The host picked a method different from the one the client had selected. | 58 // The host picked a method different from the one the client had selected. |
| 58 if (method != current_method_) { | 59 if (method != current_method_) { |
| 59 // The host must pick a method that is valid and supported by the client, | 60 // The host must pick a method that is valid and supported by the client, |
| 60 // and it must not change methods after it has picked one. | 61 // and it must not change methods after it has picked one. |
| 61 if (method_set_by_host_ || method == Method::INVALID || | 62 if (method_set_by_host_ || method == Method::INVALID || |
| 62 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { | 63 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { |
| 63 state_ = REJECTED; | 64 state_ = REJECTED; |
| 64 rejection_reason_ = PROTOCOL_ERROR; | 65 rejection_reason_ = PROTOCOL_ERROR; |
| 65 resume_callback.Run(); | 66 resume_callback.Run(); |
| 66 return; | 67 return; |
| 67 } | 68 } |
| 68 | 69 |
| 69 current_method_ = method; | 70 current_method_ = method; |
| 70 method_set_by_host_ = true; | 71 method_set_by_host_ = true; |
| 71 state_ = PROCESSING_MESSAGE; | |
| 72 | 72 |
| 73 // Copy the message since the authenticator may process it asynchronously. | 73 // Copy the message since the authenticator may process it asynchronously. |
| 74 base::Closure callback = base::Bind( | 74 base::Closure callback = base::Bind( |
| 75 &NegotiatingAuthenticatorBase::ProcessMessageInternal, | 75 &NegotiatingAuthenticatorBase::ProcessMessageInternal, |
| 76 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), | 76 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), |
| 77 resume_callback); | 77 resume_callback); |
| 78 CreateAuthenticatorForCurrentMethod(WAITING_MESSAGE, callback); | 78 CreateAuthenticatorForCurrentMethod(WAITING_MESSAGE, callback); |
| 79 return; | 79 return; |
| 80 } | 80 } |
| 81 ProcessMessageInternal(message, resume_callback); | 81 ProcessMessageInternal(message, resume_callback); |
| 82 } | 82 } |
| 83 | 83 |
| 84 scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { | 84 scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { |
| 85 DCHECK_EQ(state(), MESSAGE_READY); | 85 DCHECK_EQ(state(), MESSAGE_READY); |
| 86 | 86 |
| 87 // This is the first message to the host, send a list of supported methods. | 87 // This is the first message to the host, send a list of supported methods. |
| 88 if (current_method_ == Method::INVALID) { | 88 if (current_method_ == Method::INVALID) { |
| 89 // If no authentication method has been chosen, see if we can optimistically | 89 // If no authentication method has been chosen, see if we can optimistically |
| 90 // choose one. | 90 // choose one. |
| 91 scoped_ptr<buzz::XmlElement> result; | 91 scoped_ptr<buzz::XmlElement> result; |
| 92 CreatePreferredAuthenticator(); | 92 CreatePreferredAuthenticator(); |
| 93 if (current_authenticator_) { | 93 if (current_authenticator_) { |
| 94 DCHECK(current_authenticator_->state() == MESSAGE_READY); | 94 DCHECK(current_authenticator_->state() == MESSAGE_READY); |
| 95 result = GetNextMessageInternal(); | 95 result = GetNextMessageInternal(); |
| 96 } else { | 96 } else { |
| 97 result = CreateEmptyAuthenticatorMessage(); | 97 result = CreateEmptyAuthenticatorMessage(); |
| 98 } | 98 } |
| 99 | 99 |
| 100 if (is_paired()) { |
| 101 // If the client is paired with the host then attach pairing client_id to |
| 102 // the message. |
| 103 buzz::XmlElement* pairing_tag = new buzz::XmlElement(kPairingInfoTag); |
| 104 result->AddElement(pairing_tag); |
| 105 pairing_tag->AddAttr(kClientIdAttribute, config_.pairing_client_id); |
| 106 } |
| 107 |
| 100 // Include a list of supported methods. | 108 // Include a list of supported methods. |
| 101 std::string supported_methods; | 109 std::string supported_methods; |
| 102 for (Method method : methods_) { | 110 for (Method method : methods_) { |
| 103 if (!supported_methods.empty()) | 111 if (!supported_methods.empty()) |
| 104 supported_methods += kSupportedMethodsSeparator; | 112 supported_methods += kSupportedMethodsSeparator; |
| 105 supported_methods += MethodToString(method); | 113 supported_methods += MethodToString(method); |
| 106 } | 114 } |
| 107 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods); | 115 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods); |
| 108 state_ = WAITING_MESSAGE; | 116 state_ = WAITING_MESSAGE; |
| 109 return result; | 117 return result; |
| 110 } | 118 } |
| 111 return GetNextMessageInternal(); | 119 return GetNextMessageInternal(); |
| 112 } | 120 } |
| 113 | 121 |
| 114 void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( | 122 void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( |
| 115 Authenticator::State preferred_initial_state, | 123 Authenticator::State preferred_initial_state, |
| 116 const base::Closure& resume_callback) { | 124 const base::Closure& resume_callback) { |
| 125 DCHECK_EQ(state(), PROCESSING_MESSAGE); |
| 117 DCHECK(current_method_ != Method::INVALID); | 126 DCHECK(current_method_ != Method::INVALID); |
| 118 if (current_method_ == Method::THIRD_PARTY_SPAKE2_P224) { | 127 if (current_method_ == Method::THIRD_PARTY_SPAKE2_P224) { |
| 119 current_authenticator_.reset(new ThirdPartyClientAuthenticator( | 128 current_authenticator_.reset(new ThirdPartyClientAuthenticator( |
| 120 base::Bind(&V2Authenticator::CreateForClient), | 129 base::Bind(&V2Authenticator::CreateForClient), |
| 121 config_.fetch_third_party_token_callback)); | 130 config_.fetch_third_party_token_callback)); |
| 122 resume_callback.Run(); | 131 resume_callback.Run(); |
| 123 } else if (current_method_ == Method::THIRD_PARTY_SPAKE2_CURVE25519) { | 132 } else if (current_method_ == Method::THIRD_PARTY_SPAKE2_CURVE25519) { |
| 124 current_authenticator_.reset(new ThirdPartyClientAuthenticator( | 133 current_authenticator_.reset(new ThirdPartyClientAuthenticator( |
| 125 base::Bind(&Spake2Authenticator::CreateForClient, local_id_, | 134 base::Bind(&Spake2Authenticator::CreateForClient, local_id_, |
| 126 remote_id_), | 135 remote_id_), |
| 127 config_.fetch_third_party_token_callback)); | 136 config_.fetch_third_party_token_callback)); |
| 128 resume_callback.Run(); | 137 resume_callback.Run(); |
| 138 } else if (current_method_ == Method::PAIRED_SPAKE2_P224) { |
| 139 PairingClientAuthenticator* pairing_authenticator = |
| 140 new PairingClientAuthenticator( |
| 141 config_, base::Bind(&V2Authenticator::CreateForClient)); |
| 142 current_authenticator_ = make_scoped_ptr(pairing_authenticator); |
| 143 pairing_authenticator->Start(preferred_initial_state, resume_callback); |
| 129 } else { | 144 } else { |
| 130 DCHECK(current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224 || | 145 DCHECK(current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224 || |
| 131 current_method_ == Method::PAIRED_SPAKE2_P224 || | |
| 132 current_method_ == Method::SHARED_SECRET_SPAKE2_P224 || | 146 current_method_ == Method::SHARED_SECRET_SPAKE2_P224 || |
| 133 current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519); | 147 current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519); |
| 134 bool pairing_supported = (current_method_ == Method::PAIRED_SPAKE2_P224); | |
| 135 config_.fetch_secret_callback.Run( | 148 config_.fetch_secret_callback.Run( |
| 136 pairing_supported, | 149 false, |
| 137 base::Bind( | 150 base::Bind( |
| 138 &NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator, | 151 &NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator, |
| 139 weak_factory_.GetWeakPtr(), preferred_initial_state, | 152 weak_factory_.GetWeakPtr(), preferred_initial_state, |
| 140 resume_callback)); | 153 resume_callback)); |
| 141 } | 154 } |
| 142 } | 155 } |
| 143 | 156 |
| 144 void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { | 157 void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { |
| 145 if (!config_.pairing_client_id.empty() && !config_.pairing_secret.empty() && | 158 if (is_paired() && |
| 146 std::find(methods_.begin(), methods_.end(), Method::PAIRED_SPAKE2_P224) != | 159 std::find(methods_.begin(), methods_.end(), Method::PAIRED_SPAKE2_P224) != |
| 147 methods_.end()) { | 160 methods_.end()) { |
| 148 // If the client specified a pairing id and shared secret, then create a | 161 PairingClientAuthenticator* pairing_authenticator = |
| 149 // PairingAuthenticator. | 162 new PairingClientAuthenticator( |
| 150 current_authenticator_.reset(new PairingClientAuthenticator( | 163 config_, base::Bind(&V2Authenticator::CreateForClient)); |
| 151 config_, base::Bind(&V2Authenticator::CreateForClient))); | 164 current_authenticator_ = make_scoped_ptr(pairing_authenticator); |
| 165 pairing_authenticator->StartPaired(MESSAGE_READY); |
| 152 current_method_ = Method::PAIRED_SPAKE2_P224; | 166 current_method_ = Method::PAIRED_SPAKE2_P224; |
| 153 } | 167 } |
| 154 } | 168 } |
| 155 | 169 |
| 156 void NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator( | 170 void NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator( |
| 157 Authenticator::State initial_state, | 171 Authenticator::State initial_state, |
| 158 const base::Closure& resume_callback, | 172 const base::Closure& resume_callback, |
| 159 const std::string& shared_secret) { | 173 const std::string& shared_secret) { |
| 160 std::string shared_secret_hash = | 174 std::string shared_secret_hash = |
| 161 (current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224) | 175 (current_method_ == Method::SHARED_SECRET_PLAIN_SPAKE2_P224) |
| 162 ? shared_secret | 176 ? shared_secret |
| 163 : GetSharedSecretHash(config_.host_id, shared_secret); | 177 : GetSharedSecretHash(config_.host_id, shared_secret); |
| 164 | 178 |
| 165 if (current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519) { | 179 if (current_method_ == Method::SHARED_SECRET_SPAKE2_CURVE25519) { |
| 166 current_authenticator_ = Spake2Authenticator::CreateForClient( | 180 current_authenticator_ = Spake2Authenticator::CreateForClient( |
| 167 local_id_, remote_id_, shared_secret_hash, initial_state); | 181 local_id_, remote_id_, shared_secret_hash, initial_state); |
| 168 } else { | 182 } else { |
| 169 current_authenticator_ = | 183 current_authenticator_ = |
| 170 V2Authenticator::CreateForClient(shared_secret_hash, initial_state); | 184 V2Authenticator::CreateForClient(shared_secret_hash, initial_state); |
| 171 } | 185 } |
| 172 resume_callback.Run(); | 186 resume_callback.Run(); |
| 173 } | 187 } |
| 174 | 188 |
| 189 bool NegotiatingClientAuthenticator::is_paired() { |
| 190 return !config_.pairing_client_id.empty() && !config_.pairing_secret.empty(); |
| 191 } |
| 192 |
| 175 } // namespace protocol | 193 } // namespace protocol |
| 176 } // namespace remoting | 194 } // namespace remoting |
| OLD | NEW |