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 |