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"
7 #include "base/time/time.h"
8 #include "base/timer/timer.h"
9 #include "components/proximity_auth/connection.h"
10 #include "components/proximity_auth/cryptauth/secure_message_delegate.h"
11 #include "components/proximity_auth/device_to_device_initiator_operations.h"
12 #include "components/proximity_auth/device_to_device_secure_context.h"
13 #include "components/proximity_auth/logging/logging.h"
14 #include "components/proximity_auth/secure_context.h"
15 #include "components/proximity_auth/wire_message.h"
17 namespace proximity_auth
{
21 // The time to wait in seconds for the remote device to send its
22 // [Responder Auth] message. If we do not get the message in this time, then
23 // authentication will fail.
24 const int kResponderAuthTimeoutSeconds
= 5;
26 // The prefix of the permit id sent to the remote device. The permit id
27 // is used by the remote device to find the credentials of the local device.
28 const char kPermitIdPrefix
[] = "permit://google.com/easyunlock/v1/";
32 DeviceToDeviceAuthenticator::DeviceToDeviceAuthenticator(
33 Connection
* connection
,
34 const std::string
& account_id
,
35 scoped_ptr
<SecureMessageDelegate
> secure_message_delegate
)
36 : connection_(connection
),
37 account_id_(account_id
),
38 secure_message_delegate_(secure_message_delegate
.Pass()),
39 state_(State::NOT_STARTED
),
40 weak_ptr_factory_(this) {
44 DeviceToDeviceAuthenticator::~DeviceToDeviceAuthenticator() {
45 connection_
->RemoveObserver(this);
48 void DeviceToDeviceAuthenticator::Authenticate(
49 const AuthenticationCallback
& callback
) {
50 if (state_
!= State::NOT_STARTED
) {
52 << "Authenticator was already used. Do not reuse this instance!";
53 callback
.Run(Result::FAILURE
, nullptr);
58 if (!connection_
->IsConnected()) {
59 Fail("Not connected to remote device", Result::DISCONNECTED
);
63 connection_
->AddObserver(this);
65 // Generate a key-pair for this individual session.
66 state_
= State::GENERATING_SESSION_KEYS
;
67 secure_message_delegate_
->GenerateKeyPair(
68 base::Bind(&DeviceToDeviceAuthenticator::OnKeyPairGenerated
,
69 weak_ptr_factory_
.GetWeakPtr()));
72 void DeviceToDeviceAuthenticator::OnKeyPairGenerated(
73 const std::string
& public_key
,
74 const std::string
& private_key
) {
75 DCHECK(state_
== State::GENERATING_SESSION_KEYS
);
76 if (public_key
.empty() || private_key
.empty()) {
77 Fail("Failed to generate session keys");
80 local_session_private_key_
= private_key
;
82 // Create the [Hello] message to send to the remote device.
83 state_
= State::SENDING_HELLO
;
84 DeviceToDeviceInitiatorOperations::CreateHelloMessage(
85 public_key
, connection_
->remote_device().persistent_symmetric_key
,
86 secure_message_delegate_
.get(),
87 base::Bind(&DeviceToDeviceAuthenticator::OnHelloMessageCreated
,
88 weak_ptr_factory_
.GetWeakPtr()));
91 scoped_ptr
<base::Timer
> DeviceToDeviceAuthenticator::CreateTimer() {
92 return make_scoped_ptr(new base::OneShotTimer
<DeviceToDeviceAuthenticator
>());
95 void DeviceToDeviceAuthenticator::OnHelloMessageCreated(
96 const std::string
& message
) {
97 DCHECK(state_
== State::SENDING_HELLO
);
98 if (message
.empty()) {
99 Fail("Failed to create [Hello]");
103 // Add a timeout for receiving the [Responder Auth] message as a guard.
104 timer_
= CreateTimer();
106 FROM_HERE
, base::TimeDelta::FromSeconds(kResponderAuthTimeoutSeconds
),
107 base::Bind(&DeviceToDeviceAuthenticator::OnResponderAuthTimedOut
,
108 weak_ptr_factory_
.GetWeakPtr()));
110 // Send the [Hello] message to the remote device.
111 state_
= State::SENT_HELLO
;
112 hello_message_
= message
;
113 std::string permit_id
= kPermitIdPrefix
+ account_id_
;
114 connection_
->SendMessage(
115 make_scoped_ptr(new WireMessage(hello_message_
, permit_id
)));
118 void DeviceToDeviceAuthenticator::OnResponderAuthTimedOut() {
119 DCHECK(state_
== State::SENT_HELLO
);
120 Fail("Timed out waiting for [Responder Auth]");
123 void DeviceToDeviceAuthenticator::OnResponderAuthValidated(
125 const std::string
& session_symmetric_key
) {
127 Fail("Unable to validated [Responder Auth]");
131 PA_LOG(INFO
) << "Successfully validated [Responder Auth]! "
132 << "Sending [Initiator Auth]...";
133 state_
= State::VALIDATED_RESPONDER_AUTH
;
134 session_symmetric_key_
= session_symmetric_key
;
136 // Create the [Initiator Auth] message to send to the remote device.
137 DeviceToDeviceInitiatorOperations::CreateInitiatorAuthMessage(
138 session_symmetric_key
,
139 connection_
->remote_device().persistent_symmetric_key
,
140 responder_auth_message_
, secure_message_delegate_
.get(),
141 base::Bind(&DeviceToDeviceAuthenticator::OnInitiatorAuthCreated
,
142 weak_ptr_factory_
.GetWeakPtr()));
145 void DeviceToDeviceAuthenticator::OnInitiatorAuthCreated(
146 const std::string
& message
) {
147 DCHECK(state_
== State::VALIDATED_RESPONDER_AUTH
);
148 if (message
.empty()) {
149 Fail("Failed to create [Initiator Auth]");
153 state_
= State::SENT_INITIATOR_AUTH
;
154 connection_
->SendMessage(make_scoped_ptr(new WireMessage(message
)));
157 void DeviceToDeviceAuthenticator::Fail(const std::string
& error_message
) {
158 Fail(error_message
, Result::FAILURE
);
161 void DeviceToDeviceAuthenticator::Fail(const std::string
& error_message
,
163 DCHECK(result
!= Result::SUCCESS
);
164 PA_LOG(WARNING
) << "Authentication failed: " << error_message
;
165 state_
= State::AUTHENTICATION_FAILURE
;
166 weak_ptr_factory_
.InvalidateWeakPtrs();
167 connection_
->RemoveObserver(this);
169 callback_
.Run(result
, nullptr);
172 void DeviceToDeviceAuthenticator::Succeed() {
173 DCHECK(state_
== State::SENT_INITIATOR_AUTH
);
174 DCHECK(!session_symmetric_key_
.empty());
175 PA_LOG(INFO
) << "Authentication succeeded!";
177 state_
= State::AUTHENTICATION_SUCCESS
;
178 connection_
->RemoveObserver(this);
181 make_scoped_ptr(new DeviceToDeviceSecureContext(
182 secure_message_delegate_
.Pass(), session_symmetric_key_
,
183 responder_auth_message_
, SecureContext::PROTOCOL_VERSION_THREE_ONE
)));
186 void DeviceToDeviceAuthenticator::OnConnectionStatusChanged(
187 Connection
* connection
,
188 Connection::Status old_status
,
189 Connection::Status new_status
) {
190 // We do not expect the connection to drop during authentication.
191 if (new_status
== Connection::DISCONNECTED
) {
192 Fail("Disconnected while authentication is in progress",
193 Result::DISCONNECTED
);
197 void DeviceToDeviceAuthenticator::OnMessageReceived(
198 const Connection
& connection
,
199 const WireMessage
& message
) {
200 if (state_
== State::SENT_HELLO
) {
201 PA_LOG(INFO
) << "Received [Responder Auth] message, payload_size="
202 << message
.payload().size();
203 state_
= State::RECEIVED_RESPONDER_AUTH
;
205 responder_auth_message_
= message
.payload();
207 // Attempt to validate the [Responder Auth] message received from the remote
209 std::string responder_public_key
= connection
.remote_device().public_key
;
210 DeviceToDeviceInitiatorOperations::ValidateResponderAuthMessage(
211 responder_auth_message_
, responder_public_key
,
212 connection_
->remote_device().persistent_symmetric_key
,
213 local_session_private_key_
, hello_message_
,
214 secure_message_delegate_
.get(),
215 base::Bind(&DeviceToDeviceAuthenticator::OnResponderAuthValidated
,
216 weak_ptr_factory_
.GetWeakPtr()));
218 Fail("Unexpected message received");
222 void DeviceToDeviceAuthenticator::OnSendCompleted(const Connection
& connection
,
223 const WireMessage
& message
,
225 if (state_
== State::SENT_INITIATOR_AUTH
) {
229 Fail("Failed to send [Initiator Auth]");
230 } else if (!success
&& state_
== State::SENT_HELLO
) {
231 DCHECK(message
.payload() == hello_message_
);
232 Fail("Failed to send [Hello]");
236 } // namespace proximity_auth