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 |