Update mojo sdk to rev c02a28868825edfa57ab77947b8cb15e741c5598
[chromium-blink-merge.git] / components / proximity_auth / device_to_device_authenticator.cc
blobcf023b15ff8c3ac2795710fe0046199b1a4d50a9
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 {
19 namespace {
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/";
30 } // namespace
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) {
41 DCHECK(connection_);
44 DeviceToDeviceAuthenticator::~DeviceToDeviceAuthenticator() {
45 connection_->RemoveObserver(this);
48 void DeviceToDeviceAuthenticator::Authenticate(
49 const AuthenticationCallback& callback) {
50 if (state_ != State::NOT_STARTED) {
51 PA_LOG(ERROR)
52 << "Authenticator was already used. Do not reuse this instance!";
53 callback.Run(Result::FAILURE, nullptr);
54 return;
57 callback_ = callback;
58 if (!connection_->IsConnected()) {
59 Fail("Not connected to remote device", Result::DISCONNECTED);
60 return;
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");
78 return;
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]");
100 return;
103 // Add a timeout for receiving the [Responder Auth] message as a guard.
104 timer_ = CreateTimer();
105 timer_->Start(
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(
124 bool validated,
125 const std::string& session_symmetric_key) {
126 if (!validated) {
127 Fail("Unable to validated [Responder Auth]");
128 return;
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]");
150 return;
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,
162 Result result) {
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);
168 timer_.reset();
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);
179 callback_.Run(
180 Result::SUCCESS,
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;
204 timer_.reset();
205 responder_auth_message_ = message.payload();
207 // Attempt to validate the [Responder Auth] message received from the remote
208 // device.
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()));
217 } else {
218 Fail("Unexpected message received");
222 void DeviceToDeviceAuthenticator::OnSendCompleted(const Connection& connection,
223 const WireMessage& message,
224 bool success) {
225 if (state_ == State::SENT_INITIATOR_AUTH) {
226 if (success)
227 Succeed();
228 else
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