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