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 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/callback.h" | 12 #include "base/callback.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/strings/string_split.h" | 14 #include "base/strings/string_split.h" |
| 15 #include "remoting/protocol/auth_util.h" |
15 #include "remoting/protocol/channel_authenticator.h" | 16 #include "remoting/protocol/channel_authenticator.h" |
16 #include "remoting/protocol/pairing_client_authenticator.h" | 17 #include "remoting/protocol/pairing_client_authenticator.h" |
17 #include "remoting/protocol/v2_authenticator.h" | 18 #include "remoting/protocol/v2_authenticator.h" |
18 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" | 19 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" |
19 | 20 |
20 namespace remoting { | 21 namespace remoting { |
21 namespace protocol { | 22 namespace protocol { |
22 | 23 |
23 NegotiatingClientAuthenticator::NegotiatingClientAuthenticator( | 24 NegotiatingClientAuthenticator::NegotiatingClientAuthenticator( |
24 const std::string& client_pairing_id, | 25 const std::string& client_pairing_id, |
25 const std::string& shared_secret, | 26 const std::string& shared_secret, |
26 const std::string& authentication_tag, | 27 const std::string& authentication_tag, |
27 const FetchSecretCallback& fetch_secret_callback, | 28 const FetchSecretCallback& fetch_secret_callback, |
28 scoped_ptr<ThirdPartyClientAuthenticator::TokenFetcher> token_fetcher, | 29 scoped_ptr<ThirdPartyClientAuthenticator::TokenFetcher> token_fetcher) |
29 const std::vector<AuthenticationMethod>& methods) | |
30 : NegotiatingAuthenticatorBase(MESSAGE_READY), | 30 : NegotiatingAuthenticatorBase(MESSAGE_READY), |
31 client_pairing_id_(client_pairing_id), | 31 client_pairing_id_(client_pairing_id), |
32 shared_secret_(shared_secret), | 32 shared_secret_(shared_secret), |
33 authentication_tag_(authentication_tag), | 33 authentication_tag_(authentication_tag), |
34 fetch_secret_callback_(fetch_secret_callback), | 34 fetch_secret_callback_(fetch_secret_callback), |
35 token_fetcher_(std::move(token_fetcher)), | 35 token_fetcher_(std::move(token_fetcher)), |
36 method_set_by_host_(false), | |
37 weak_factory_(this) { | 36 weak_factory_(this) { |
38 DCHECK(!methods.empty()); | 37 AddMethod(Method::THIRD_PARTY); |
39 for (std::vector<AuthenticationMethod>::const_iterator it = methods.begin(); | 38 AddMethod(Method::SPAKE2_PAIR); |
40 it != methods.end(); ++it) { | 39 AddMethod(Method::SPAKE2_SHARED_SECRET_HMAC); |
41 AddMethod(*it); | 40 AddMethod(Method::SPAKE2_SHARED_SECRET_PLAIN); |
42 } | |
43 } | 41 } |
44 | 42 |
45 NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() {} | 43 NegotiatingClientAuthenticator::~NegotiatingClientAuthenticator() {} |
46 | 44 |
47 void NegotiatingClientAuthenticator::ProcessMessage( | 45 void NegotiatingClientAuthenticator::ProcessMessage( |
48 const buzz::XmlElement* message, | 46 const buzz::XmlElement* message, |
49 const base::Closure& resume_callback) { | 47 const base::Closure& resume_callback) { |
50 DCHECK_EQ(state(), WAITING_MESSAGE); | 48 DCHECK_EQ(state(), WAITING_MESSAGE); |
51 | 49 |
52 std::string method_attr = message->Attr(kMethodAttributeQName); | 50 std::string method_attr = message->Attr(kMethodAttributeQName); |
53 AuthenticationMethod method = ParseAuthenticationMethodString(method_attr); | 51 Method method = ParseMethodString(method_attr); |
54 | 52 |
55 // The host picked a method different from the one the client had selected. | 53 // The host picked a method different from the one the client had selected. |
56 if (method != current_method_) { | 54 if (method != current_method_) { |
57 // The host must pick a method that is valid and supported by the client, | 55 // The host must pick a method that is valid and supported by the client, |
58 // and it must not change methods after it has picked one. | 56 // and it must not change methods after it has picked one. |
59 if (method_set_by_host_ || method == AuthenticationMethod::INVALID || | 57 if (method_set_by_host_ || method == Method::INVALID || |
60 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { | 58 std::find(methods_.begin(), methods_.end(), method) == methods_.end()) { |
61 state_ = REJECTED; | 59 state_ = REJECTED; |
62 rejection_reason_ = PROTOCOL_ERROR; | 60 rejection_reason_ = PROTOCOL_ERROR; |
63 resume_callback.Run(); | 61 resume_callback.Run(); |
64 return; | 62 return; |
65 } | 63 } |
66 | 64 |
67 current_method_ = method; | 65 current_method_ = method; |
68 method_set_by_host_ = true; | 66 method_set_by_host_ = true; |
69 state_ = PROCESSING_MESSAGE; | 67 state_ = PROCESSING_MESSAGE; |
70 | 68 |
71 // Copy the message since the authenticator may process it asynchronously. | 69 // Copy the message since the authenticator may process it asynchronously. |
72 base::Closure callback = base::Bind( | 70 base::Closure callback = base::Bind( |
73 &NegotiatingAuthenticatorBase::ProcessMessageInternal, | 71 &NegotiatingAuthenticatorBase::ProcessMessageInternal, |
74 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), | 72 base::Unretained(this), base::Owned(new buzz::XmlElement(*message)), |
75 resume_callback); | 73 resume_callback); |
76 CreateAuthenticatorForCurrentMethod(WAITING_MESSAGE, callback); | 74 CreateAuthenticatorForCurrentMethod(WAITING_MESSAGE, callback); |
77 return; | 75 return; |
78 } | 76 } |
79 ProcessMessageInternal(message, resume_callback); | 77 ProcessMessageInternal(message, resume_callback); |
80 } | 78 } |
81 | 79 |
82 scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { | 80 scoped_ptr<buzz::XmlElement> NegotiatingClientAuthenticator::GetNextMessage() { |
83 DCHECK_EQ(state(), MESSAGE_READY); | 81 DCHECK_EQ(state(), MESSAGE_READY); |
84 | 82 |
85 // This is the first message to the host, send a list of supported methods. | 83 // This is the first message to the host, send a list of supported methods. |
86 if (current_method_ == AuthenticationMethod::INVALID) { | 84 if (current_method_ == Method::INVALID) { |
87 // If no authentication method has been chosen, see if we can optimistically | 85 // If no authentication method has been chosen, see if we can optimistically |
88 // choose one. | 86 // choose one. |
89 scoped_ptr<buzz::XmlElement> result; | 87 scoped_ptr<buzz::XmlElement> result; |
90 CreatePreferredAuthenticator(); | 88 CreatePreferredAuthenticator(); |
91 if (current_authenticator_) { | 89 if (current_authenticator_) { |
92 DCHECK(current_authenticator_->state() == MESSAGE_READY); | 90 DCHECK(current_authenticator_->state() == MESSAGE_READY); |
93 result = GetNextMessageInternal(); | 91 result = GetNextMessageInternal(); |
94 } else { | 92 } else { |
95 result = CreateEmptyAuthenticatorMessage(); | 93 result = CreateEmptyAuthenticatorMessage(); |
96 } | 94 } |
97 | 95 |
98 // Include a list of supported methods. | 96 // Include a list of supported methods. |
99 std::string supported_methods; | 97 std::string supported_methods; |
100 for (AuthenticationMethod method : methods_) { | 98 for (Method method : methods_) { |
101 if (!supported_methods.empty()) | 99 if (!supported_methods.empty()) |
102 supported_methods += kSupportedMethodsSeparator; | 100 supported_methods += kSupportedMethodsSeparator; |
103 supported_methods += AuthenticationMethodToString(method); | 101 supported_methods += MethodToString(method); |
104 } | 102 } |
105 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods); | 103 result->AddAttr(kSupportedMethodsAttributeQName, supported_methods); |
106 state_ = WAITING_MESSAGE; | 104 state_ = WAITING_MESSAGE; |
107 return result; | 105 return result; |
108 } | 106 } |
109 return GetNextMessageInternal(); | 107 return GetNextMessageInternal(); |
110 } | 108 } |
111 | 109 |
112 void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( | 110 void NegotiatingClientAuthenticator::CreateAuthenticatorForCurrentMethod( |
113 Authenticator::State preferred_initial_state, | 111 Authenticator::State preferred_initial_state, |
114 const base::Closure& resume_callback) { | 112 const base::Closure& resume_callback) { |
115 DCHECK(current_method_ != AuthenticationMethod::INVALID); | 113 DCHECK(current_method_ != Method::INVALID); |
116 if (current_method_ == AuthenticationMethod::THIRD_PARTY) { | 114 if (current_method_ == Method::THIRD_PARTY) { |
117 // |ThirdPartyClientAuthenticator| takes ownership of |token_fetcher_|. | 115 // |ThirdPartyClientAuthenticator| takes ownership of |token_fetcher_|. |
118 // The authentication method negotiation logic should guarantee that only | 116 // The authentication method negotiation logic should guarantee that only |
119 // one |ThirdPartyClientAuthenticator| will need to be created per session. | 117 // one |ThirdPartyClientAuthenticator| will need to be created per session. |
120 DCHECK(token_fetcher_); | 118 DCHECK(token_fetcher_); |
121 current_authenticator_.reset(new ThirdPartyClientAuthenticator( | 119 current_authenticator_.reset(new ThirdPartyClientAuthenticator( |
122 base::Bind(&V2Authenticator::CreateForClient), | 120 base::Bind(&V2Authenticator::CreateForClient), |
123 std::move(token_fetcher_))); | 121 std::move(token_fetcher_))); |
124 resume_callback.Run(); | 122 resume_callback.Run(); |
125 } else { | 123 } else { |
126 DCHECK(current_method_ == | 124 DCHECK(current_method_ == Method::SPAKE2_SHARED_SECRET_PLAIN || |
127 AuthenticationMethod::SPAKE2_SHARED_SECRET_PLAIN || | 125 current_method_ == Method::SPAKE2_PAIR || |
128 current_method_ == AuthenticationMethod::SPAKE2_SHARED_SECRET_HMAC || | 126 current_method_ == Method::SPAKE2_SHARED_SECRET_HMAC); |
129 current_method_ == AuthenticationMethod::SPAKE2_PAIR); | 127 bool pairing_supported = (current_method_ == Method::SPAKE2_PAIR); |
130 bool pairing_supported = | |
131 (current_method_ == AuthenticationMethod::SPAKE2_PAIR); | |
132 SecretFetchedCallback callback = base::Bind( | 128 SecretFetchedCallback callback = base::Bind( |
133 &NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret, | 129 &NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret, |
134 weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback); | 130 weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback); |
135 fetch_secret_callback_.Run(pairing_supported, callback); | 131 fetch_secret_callback_.Run(pairing_supported, callback); |
136 } | 132 } |
137 } | 133 } |
138 | 134 |
139 void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { | 135 void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { |
140 if (!client_pairing_id_.empty() && !shared_secret_.empty() && | 136 if (!client_pairing_id_.empty() && !shared_secret_.empty() && |
141 std::find(methods_.begin(), methods_.end(), | 137 std::find(methods_.begin(), methods_.end(), Method::SPAKE2_PAIR) != |
142 AuthenticationMethod::SPAKE2_PAIR) != methods_.end()) { | 138 methods_.end()) { |
143 // If the client specified a pairing id and shared secret, then create a | 139 // If the client specified a pairing id and shared secret, then create a |
144 // PairingAuthenticator. | 140 // PairingAuthenticator. |
145 current_authenticator_.reset(new PairingClientAuthenticator( | 141 current_authenticator_.reset(new PairingClientAuthenticator( |
146 client_pairing_id_, shared_secret_, | 142 client_pairing_id_, shared_secret_, |
147 base::Bind(&V2Authenticator::CreateForClient), fetch_secret_callback_, | 143 base::Bind(&V2Authenticator::CreateForClient), fetch_secret_callback_, |
148 authentication_tag_)); | 144 authentication_tag_)); |
149 current_method_ = AuthenticationMethod::SPAKE2_PAIR; | 145 current_method_ = Method::SPAKE2_PAIR; |
150 } | 146 } |
151 } | 147 } |
152 | 148 |
153 void NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret( | 149 void NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret( |
154 Authenticator::State initial_state, | 150 Authenticator::State initial_state, |
155 const base::Closure& resume_callback, | 151 const base::Closure& resume_callback, |
156 const std::string& shared_secret) { | 152 const std::string& shared_secret) { |
157 current_authenticator_ = V2Authenticator::CreateForClient( | 153 current_authenticator_ = V2Authenticator::CreateForClient( |
158 ApplySharedSecretHashFunction( | 154 (current_method_ == Method::SPAKE2_SHARED_SECRET_PLAIN) |
159 GetHashFunctionForAuthenticationMethod(current_method_), | 155 ? shared_secret |
160 authentication_tag_, shared_secret), | 156 : GetSharedSecretHash(authentication_tag_, shared_secret), |
161 initial_state); | 157 initial_state); |
162 resume_callback.Run(); | 158 resume_callback.Run(); |
163 } | 159 } |
164 | 160 |
165 } // namespace protocol | 161 } // namespace protocol |
166 } // namespace remoting | 162 } // namespace remoting |
OLD | NEW |