1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/proximity_auth/device_to_device_authenticator.h"
8 #include "base/memory/scoped_vector.h"
9 #include "base/rand_util.h"
10 #include "base/timer/mock_timer.h"
11 #include "components/proximity_auth/connection.h"
12 #include "components/proximity_auth/cryptauth/base64url.h"
13 #include "components/proximity_auth/cryptauth/fake_secure_message_delegate.h"
14 #include "components/proximity_auth/device_to_device_responder_operations.h"
15 #include "components/proximity_auth/secure_context.h"
16 #include "components/proximity_auth/wire_message.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace proximity_auth
{
24 // The account id of the user.
25 const char kAccountId
[] = "example@gmail.com";
27 // Attributes of the connected remote device.
28 const char kRemoteDeviceName
[] = "iPhone 6";
29 const char kRemoteDevicePublicKey
[] = "remote public key";
30 const char kRemoteDeviceBluetoothAddress
[] = "AA:BB:CC:DD:EE:FF";
31 const char kRemoteDevicePersistentSymmetricKey
[] = "PSK";
33 // The initiator's session public key in base64url form. Note that this is
34 // actually a serialized proto.
35 const char kInitiatorSessionPublicKeyBase64
[] =
36 "CAESRQogOlH8DgPMQu7eAt-b6yoTXcazG8mAl6SPC5Ds-LTULIcSIQDZDMqsoYRO4tNMej1FB"
37 "El1sTiTiVDqrcGq-CkYCzDThw==";
39 // The initiator's session public key in base64url form. Note that this is
40 // actually a serialized proto.
41 const char kResponderSessionPublicKeyBase64
[] =
42 "CAESRgohAN9QYU5HySO14Gi9PDIClacBnC0C8wqPwXsNHUNG_vXlEiEAggzU80ZOd9DWuCBdp"
43 "6bzpGcC-oj1yrwdVCHGg_yeaAQ=";
45 // Callback saving a string from |result| to |result_out|.
46 void SaveStringResult(std::string
* result_out
, const std::string
& result
) {
50 // Callback saving a boolean from |result| to |result_out|.
51 void SaveBooleanResult(bool* result_out
, bool result
) {
55 // Callback saving the result of ValidateHelloMessage().
56 void SaveValidateHelloMessageResult(bool* validated_out
,
57 std::string
* public_key_out
,
59 const std::string
& public_key
) {
60 *validated_out
= validated
;
61 *public_key_out
= public_key
;
64 // Connection implementation for testing.
65 class FakeConnection
: public Connection
{
67 FakeConnection(const RemoteDevice
& remote_device
)
68 : Connection(remote_device
), connection_blocked_(false) {}
69 ~FakeConnection() override
{}
72 void Connect() override
{ SetStatus(Connection::Status::CONNECTED
); }
73 void Disconnect() override
{ SetStatus(Connection::Status::DISCONNECTED
); }
75 using Connection::OnBytesReceived
;
77 void ClearMessageBuffer() { message_buffer_
.clear(); }
79 const ScopedVector
<WireMessage
>& message_buffer() { return message_buffer_
; }
81 void set_connection_blocked(bool connection_blocked
) {
82 connection_blocked_
= connection_blocked
;
85 bool connection_blocked() { return connection_blocked_
; }
89 void SendMessageImpl(scoped_ptr
<WireMessage
> message
) override
{
90 const WireMessage
& message_alias
= *message
;
91 message_buffer_
.push_back(message
.Pass());
92 OnDidSendMessage(message_alias
, !connection_blocked_
);
96 ScopedVector
<WireMessage
> message_buffer_
;
98 bool connection_blocked_
;
100 DISALLOW_COPY_AND_ASSIGN(FakeConnection
);
103 // Harness for testing DeviceToDeviceAuthenticator.
104 class DeviceToDeviceAuthenticatorForTest
: public DeviceToDeviceAuthenticator
{
106 DeviceToDeviceAuthenticatorForTest(
107 Connection
* connection
,
108 scoped_ptr
<SecureMessageDelegate
> secure_message_delegate
)
109 : DeviceToDeviceAuthenticator(connection
,
111 secure_message_delegate
.Pass()),
113 ~DeviceToDeviceAuthenticatorForTest() override
{}
115 base::MockTimer
* timer() { return timer_
; }
118 // DeviceToDeviceAuthenticator:
119 scoped_ptr
<base::Timer
> CreateTimer() override
{
120 bool retain_user_task
= false;
121 bool is_repeating
= false;
123 scoped_ptr
<base::MockTimer
> timer(
124 new base::MockTimer(retain_user_task
, is_repeating
));
126 timer_
= timer
.get();
130 // This instance is owned by the super class.
131 base::MockTimer
* timer_
;
133 DISALLOW_COPY_AND_ASSIGN(DeviceToDeviceAuthenticatorForTest
);
138 class ProximityAuthDeviceToDeviceAuthenticatorTest
: public testing::Test
{
140 ProximityAuthDeviceToDeviceAuthenticatorTest()
141 : remote_device_(kRemoteDeviceName
,
142 kRemoteDevicePublicKey
,
143 kRemoteDeviceBluetoothAddress
,
144 kRemoteDevicePersistentSymmetricKey
),
145 connection_(remote_device_
),
146 secure_message_delegate_(new FakeSecureMessageDelegate
),
147 authenticator_(&connection_
,
148 make_scoped_ptr(secure_message_delegate_
)) {}
149 ~ProximityAuthDeviceToDeviceAuthenticatorTest() override
{}
151 void SetUp() override
{
152 // Set up the session asymmetric keys for both the local and remote devices.
153 Base64UrlDecode(kInitiatorSessionPublicKeyBase64
,
154 &local_session_public_key_
);
155 Base64UrlDecode(kResponderSessionPublicKeyBase64
,
156 &remote_session_public_key_
);
157 remote_session_private_key_
=
158 secure_message_delegate_
->GetPrivateKeyForPublicKey(
159 remote_session_public_key_
),
161 secure_message_delegate_
->set_next_public_key(local_session_public_key_
);
162 connection_
.Connect();
164 secure_message_delegate_
->DeriveKey(
165 remote_session_private_key_
, local_session_public_key_
,
166 base::Bind(&SaveStringResult
, &session_symmetric_key_
));
169 // Begins authentication, and returns the [Hello] message sent from the local
170 // device to the remote device.
171 std::string
BeginAuthentication() {
172 authenticator_
.Authenticate(base::Bind(
173 &ProximityAuthDeviceToDeviceAuthenticatorTest::OnAuthenticationResult
,
174 base::Unretained(this)));
176 EXPECT_EQ(1u, connection_
.message_buffer().size());
177 EXPECT_EQ(std::string("permit://google.com/easyunlock/v1/") + kAccountId
,
178 connection_
.message_buffer()[0]->permit_id());
179 std::string hello_message
= connection_
.message_buffer()[0]->payload();
180 connection_
.ClearMessageBuffer();
182 bool validated
= false;
183 std::string local_session_public_key
;
184 DeviceToDeviceResponderOperations::ValidateHelloMessage(
185 hello_message
, remote_device_
.persistent_symmetric_key
,
186 secure_message_delegate_
,
187 base::Bind(&SaveValidateHelloMessageResult
, &validated
,
188 &local_session_public_key
));
190 EXPECT_TRUE(validated
);
191 EXPECT_EQ(local_session_public_key_
, local_session_public_key
);
193 return hello_message
;
196 // Simulate receiving a valid [Responder Auth] message from the remote device.
197 std::string
SimulateResponderAuth(const std::string
& hello_message
) {
198 std::string remote_device_private_key
=
199 secure_message_delegate_
->GetPrivateKeyForPublicKey(
200 kRemoteDevicePublicKey
);
202 std::string responder_auth_message
;
203 DeviceToDeviceResponderOperations::CreateResponderAuthMessage(
204 hello_message
, remote_session_public_key_
, remote_session_private_key_
,
205 remote_device_private_key
, remote_device_
.persistent_symmetric_key
,
206 secure_message_delegate_
,
207 base::Bind(&SaveStringResult
, &responder_auth_message
));
208 EXPECT_FALSE(responder_auth_message
.empty());
210 WireMessage
wire_message(responder_auth_message
);
211 connection_
.OnBytesReceived(wire_message
.Serialize());
213 return responder_auth_message
;
216 void OnAuthenticationResult(Authenticator::Result result
,
217 scoped_ptr
<SecureContext
> secure_context
) {
218 secure_context_
= secure_context
.Pass();
219 OnAuthenticationResultProxy(result
);
222 MOCK_METHOD1(OnAuthenticationResultProxy
, void(Authenticator::Result result
));
224 // Contains information about the remote device.
225 const RemoteDevice remote_device_
;
227 // Simulates the connection to the remote device.
228 FakeConnection connection_
;
230 // The SecureMessageDelegate used by the authenticator.
231 // Owned by |authenticator_|.
232 FakeSecureMessageDelegate
* secure_message_delegate_
;
234 // The DeviceToDeviceAuthenticator under test.
235 DeviceToDeviceAuthenticatorForTest authenticator_
;
237 // The session keys in play during authentication.
238 std::string local_session_public_key_
;
239 std::string remote_session_public_key_
;
240 std::string remote_session_private_key_
;
241 std::string session_symmetric_key_
;
243 // Stores the SecureContext returned after authentication succeeds.
244 scoped_ptr
<SecureContext
> secure_context_
;
246 DISALLOW_COPY_AND_ASSIGN(ProximityAuthDeviceToDeviceAuthenticatorTest
);
249 TEST_F(ProximityAuthDeviceToDeviceAuthenticatorTest
, AuthenticateSucceeds
) {
250 // Starts the authentication protocol and grab [Hello] message.
251 std::string hello_message
= BeginAuthentication();
253 // Simulate receiving a valid [Responder Auth] from the remote device.
255 OnAuthenticationResultProxy(Authenticator::Result::SUCCESS
));
256 std::string responder_auth_message
= SimulateResponderAuth(hello_message
);
257 EXPECT_TRUE(secure_context_
);
259 // Validate the local device sends a valid [Initiator Auth] message.
260 ASSERT_EQ(1u, connection_
.message_buffer().size());
261 std::string initiator_auth
= connection_
.message_buffer()[0]->payload();
263 bool initiator_auth_validated
= false;
264 DeviceToDeviceResponderOperations::ValidateInitiatorAuthMessage(
265 initiator_auth
, session_symmetric_key_
,
266 remote_device_
.persistent_symmetric_key
, responder_auth_message
,
267 secure_message_delegate_
,
268 base::Bind(&SaveBooleanResult
, &initiator_auth_validated
));
269 ASSERT_TRUE(initiator_auth_validated
);
272 TEST_F(ProximityAuthDeviceToDeviceAuthenticatorTest
, ResponderRejectsHello
) {
273 std::string hello_message
= BeginAuthentication();
275 // If the responder could not validate the [Hello message], it essentially
276 // sends random bytes back for privacy reasons.
277 WireMessage
wire_message(base::RandBytesAsString(300u));
279 OnAuthenticationResultProxy(Authenticator::Result::FAILURE
));
280 connection_
.OnBytesReceived(wire_message
.Serialize());
281 EXPECT_FALSE(secure_context_
);
284 TEST_F(ProximityAuthDeviceToDeviceAuthenticatorTest
, ResponderAuthTimesOut
) {
285 // Starts the authentication protocol and grab [Hello] message.
286 std::string hello_message
= BeginAuthentication();
287 ASSERT_TRUE(authenticator_
.timer());
289 OnAuthenticationResultProxy(Authenticator::Result::FAILURE
));
290 authenticator_
.timer()->Fire();
291 EXPECT_FALSE(secure_context_
);
294 TEST_F(ProximityAuthDeviceToDeviceAuthenticatorTest
,
295 DisconnectsWaitingForResponderAuth
) {
296 std::string hello_message
= BeginAuthentication();
298 OnAuthenticationResultProxy(Authenticator::Result::DISCONNECTED
));
299 connection_
.Disconnect();
300 EXPECT_FALSE(secure_context_
);
303 TEST_F(ProximityAuthDeviceToDeviceAuthenticatorTest
, NotConnectedInitially
) {
304 connection_
.Disconnect();
306 OnAuthenticationResultProxy(Authenticator::Result::DISCONNECTED
));
307 authenticator_
.Authenticate(base::Bind(
308 &ProximityAuthDeviceToDeviceAuthenticatorTest::OnAuthenticationResult
,
309 base::Unretained(this)));
310 EXPECT_FALSE(secure_context_
);
313 TEST_F(ProximityAuthDeviceToDeviceAuthenticatorTest
, FailToSendHello
) {
314 connection_
.set_connection_blocked(true);
316 OnAuthenticationResultProxy(Authenticator::Result::FAILURE
));
317 authenticator_
.Authenticate(base::Bind(
318 &ProximityAuthDeviceToDeviceAuthenticatorTest::OnAuthenticationResult
,
319 base::Unretained(this)));
320 EXPECT_FALSE(secure_context_
);
323 TEST_F(ProximityAuthDeviceToDeviceAuthenticatorTest
, FailToSendInitiatorAuth
) {
324 std::string hello_message
= BeginAuthentication();
326 connection_
.set_connection_blocked(true);
328 OnAuthenticationResultProxy(Authenticator::Result::FAILURE
));
329 SimulateResponderAuth(hello_message
);
330 EXPECT_FALSE(secure_context_
);
333 TEST_F(ProximityAuthDeviceToDeviceAuthenticatorTest
,
334 SendMessagesAfterAuthenticationSuccess
) {
335 std::string hello_message
= BeginAuthentication();
337 OnAuthenticationResultProxy(Authenticator::Result::SUCCESS
));
338 SimulateResponderAuth(hello_message
);
340 // Test that the authenticator is properly cleaned up after authentication
342 WireMessage
wire_message(base::RandBytesAsString(300u));
343 connection_
.SendMessage(
344 make_scoped_ptr(new WireMessage(base::RandBytesAsString(300u))));
345 connection_
.OnBytesReceived(wire_message
.Serialize());
346 connection_
.SendMessage(
347 make_scoped_ptr(new WireMessage(base::RandBytesAsString(300u))));
348 connection_
.OnBytesReceived(wire_message
.Serialize());
351 } // namespace proximity_auth