Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: device/u2f/u2f_hid_device.cc

Issue 2824803003: Add timeout task to U2F HID state machine (Closed)
Patch Set: Create ArmTimeout function Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « device/u2f/u2f_hid_device.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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 "u2f_hid_device.h" 5 #include "u2f_hid_device.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/threading/thread_task_runner_handle.h"
10 #include "crypto/random.h" 11 #include "crypto/random.h"
11 #include "device/base/device_client.h" 12 #include "device/base/device_client.h"
12 #include "device/hid/hid_connection.h" 13 #include "device/hid/hid_connection.h"
13 #include "u2f_apdu_command.h" 14 #include "u2f_apdu_command.h"
14 #include "u2f_message.h" 15 #include "u2f_message.h"
15 16
16 namespace device { 17 namespace device {
17 18
18 namespace switches { 19 namespace switches {
19 static constexpr char kEnableU2fHidTest[] = "enable-u2f-hid-tests"; 20 static constexpr char kEnableU2fHidTest[] = "enable-u2f-hid-tests";
20 } // namespace switches 21 } // namespace switches
21 22
22 U2fHidDevice::U2fHidDevice(scoped_refptr<HidDeviceInfo> device_info) 23 U2fHidDevice::U2fHidDevice(scoped_refptr<HidDeviceInfo> device_info)
23 : U2fDevice(), 24 : U2fDevice(),
24 state_(State::INIT), 25 state_(State::INIT),
25 device_info_(device_info), 26 device_info_(device_info),
26 weak_factory_(this) { 27 weak_factory_(this) {
27 channel_id_ = kBroadcastChannel; 28 channel_id_ = kBroadcastChannel;
28 } 29 }
29 30
30 U2fHidDevice::~U2fHidDevice() { 31 U2fHidDevice::~U2fHidDevice() {
31 // Cleanup connection 32 // Cleanup connection
32 if (connection_) 33 if (connection_ && !connection_->closed())
33 connection_->Close(); 34 connection_->Close();
34 } 35 }
35 36
36 void U2fHidDevice::DeviceTransact(std::unique_ptr<U2fApduCommand> command, 37 void U2fHidDevice::DeviceTransact(std::unique_ptr<U2fApduCommand> command,
37 const DeviceCallback& callback) { 38 const DeviceCallback& callback) {
38 Transition(std::move(command), callback); 39 Transition(std::move(command), callback);
39 } 40 }
40 41
41 void U2fHidDevice::Transition(std::unique_ptr<U2fApduCommand> command, 42 void U2fHidDevice::Transition(std::unique_ptr<U2fApduCommand> command,
42 const DeviceCallback& callback) { 43 const DeviceCallback& callback) {
43 switch (state_) { 44 switch (state_) {
44 case State::INIT: 45 case State::INIT: {
45 state_ = State::BUSY; 46 state_ = State::BUSY;
47 ArmTimeout(callback);
46 Connect(base::Bind(&U2fHidDevice::OnConnect, weak_factory_.GetWeakPtr(), 48 Connect(base::Bind(&U2fHidDevice::OnConnect, weak_factory_.GetWeakPtr(),
47 base::Passed(&command), callback)); 49 base::Passed(&command), callback));
48 break; 50 break;
49 case State::CONNECTED: 51 }
Reilly Grant (use Gerrit) 2017/04/17 23:31:05 nit: braces unnecessary
piperc 2017/04/17 23:43:59 Acknowledged.
52 case State::CONNECTED: {
50 state_ = State::BUSY; 53 state_ = State::BUSY;
54 ArmTimeout(callback);
51 AllocateChannel(std::move(command), callback); 55 AllocateChannel(std::move(command), callback);
52 break; 56 break;
57 }
Reilly Grant (use Gerrit) 2017/04/17 23:31:05 nit: braces unnecessary
piperc 2017/04/17 23:43:59 Acknowledged.
53 case State::IDLE: { 58 case State::IDLE: {
54 state_ = State::BUSY; 59 state_ = State::BUSY;
55 std::unique_ptr<U2fMessage> msg = U2fMessage::Create( 60 std::unique_ptr<U2fMessage> msg = U2fMessage::Create(
56 channel_id_, U2fMessage::Type::CMD_MSG, command->GetEncodedCommand()); 61 channel_id_, U2fMessage::Type::CMD_MSG, command->GetEncodedCommand());
62
63 ArmTimeout(callback);
64 // Write message to the device
57 WriteMessage(std::move(msg), true, 65 WriteMessage(std::move(msg), true,
58 base::Bind(&U2fHidDevice::MessageReceived, 66 base::Bind(&U2fHidDevice::MessageReceived,
59 weak_factory_.GetWeakPtr(), callback)); 67 weak_factory_.GetWeakPtr(), callback));
60 break; 68 break;
61 } 69 }
62 case State::BUSY: 70 case State::BUSY:
63 pending_transactions_.push_back({std::move(command), callback}); 71 pending_transactions_.push_back({std::move(command), callback});
64 break; 72 break;
65 case State::DEVICE_ERROR: 73 case State::DEVICE_ERROR:
66 default: 74 default:
(...skipping 12 matching lines...) Expand all
79 87
80 void U2fHidDevice::Connect(const HidService::ConnectCallback& callback) { 88 void U2fHidDevice::Connect(const HidService::ConnectCallback& callback) {
81 HidService* hid_service = DeviceClient::Get()->GetHidService(); 89 HidService* hid_service = DeviceClient::Get()->GetHidService();
82 90
83 hid_service->Connect(device_info_->device_id(), callback); 91 hid_service->Connect(device_info_->device_id(), callback);
84 } 92 }
85 93
86 void U2fHidDevice::OnConnect(std::unique_ptr<U2fApduCommand> command, 94 void U2fHidDevice::OnConnect(std::unique_ptr<U2fApduCommand> command,
87 const DeviceCallback& callback, 95 const DeviceCallback& callback,
88 scoped_refptr<HidConnection> connection) { 96 scoped_refptr<HidConnection> connection) {
97 if (state_ == State::DEVICE_ERROR)
98 return;
99 timeout_callback_.Cancel();
100
89 if (connection) { 101 if (connection) {
90 connection_ = connection; 102 connection_ = connection;
91 state_ = State::CONNECTED; 103 state_ = State::CONNECTED;
92 } else { 104 } else {
93 state_ = State::DEVICE_ERROR; 105 state_ = State::DEVICE_ERROR;
94 } 106 }
95 Transition(std::move(command), callback); 107 Transition(std::move(command), callback);
96 } 108 }
97 109
98 void U2fHidDevice::AllocateChannel(std::unique_ptr<U2fApduCommand> command, 110 void U2fHidDevice::AllocateChannel(std::unique_ptr<U2fApduCommand> command,
99 const DeviceCallback& callback) { 111 const DeviceCallback& callback) {
100 // Send random nonce to device to verify received message 112 // Send random nonce to device to verify received message
101 std::vector<uint8_t> nonce(8); 113 std::vector<uint8_t> nonce(8);
102 crypto::RandBytes(nonce.data(), nonce.size()); 114 crypto::RandBytes(nonce.data(), nonce.size());
103 std::unique_ptr<U2fMessage> message = 115 std::unique_ptr<U2fMessage> message =
104 U2fMessage::Create(channel_id_, U2fMessage::Type::CMD_INIT, nonce); 116 U2fMessage::Create(channel_id_, U2fMessage::Type::CMD_INIT, nonce);
105 117
106 WriteMessage( 118 WriteMessage(
107 std::move(message), true, 119 std::move(message), true,
108 base::Bind(&U2fHidDevice::OnAllocateChannel, weak_factory_.GetWeakPtr(), 120 base::Bind(&U2fHidDevice::OnAllocateChannel, weak_factory_.GetWeakPtr(),
109 nonce, base::Passed(&command), callback)); 121 nonce, base::Passed(&command), callback));
110 } 122 }
111 123
112 void U2fHidDevice::OnAllocateChannel(std::vector<uint8_t> nonce, 124 void U2fHidDevice::OnAllocateChannel(std::vector<uint8_t> nonce,
113 std::unique_ptr<U2fApduCommand> command, 125 std::unique_ptr<U2fApduCommand> command,
114 const DeviceCallback& callback, 126 const DeviceCallback& callback,
115 bool success, 127 bool success,
116 std::unique_ptr<U2fMessage> message) { 128 std::unique_ptr<U2fMessage> message) {
129 if (state_ == State::DEVICE_ERROR)
130 return;
131 timeout_callback_.Cancel();
132
117 if (!success || !message) { 133 if (!success || !message) {
118 state_ = State::DEVICE_ERROR; 134 state_ = State::DEVICE_ERROR;
119 Transition(nullptr, callback); 135 Transition(nullptr, callback);
120 return; 136 return;
121 } 137 }
122 // Channel allocation response is defined as: 138 // Channel allocation response is defined as:
123 // 0: 8 byte nonce 139 // 0: 8 byte nonce
124 // 8: 4 byte channel id 140 // 8: 4 byte channel id
125 // 12: Protocol version id 141 // 12: Protocol version id
126 // 13: Major device version 142 // 13: Major device version
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 std::unique_ptr<U2fMessage> read_message = 222 std::unique_ptr<U2fMessage> read_message =
207 U2fMessage::CreateFromSerializedData(read_buffer); 223 U2fMessage::CreateFromSerializedData(read_buffer);
208 224
209 if (!read_message) { 225 if (!read_message) {
210 std::move(callback).Run(false, nullptr); 226 std::move(callback).Run(false, nullptr);
211 return; 227 return;
212 } 228 }
213 229
214 // Received a message from a different channel, so try again 230 // Received a message from a different channel, so try again
215 if (channel_id_ != read_message->channel_id()) { 231 if (channel_id_ != read_message->channel_id()) {
216 connection_->Read(base::Bind(&U2fHidDevice::OnRead, 232 base::ThreadTaskRunnerHandle::Get()->PostTask(
Reilly Grant (use Gerrit) 2017/04/17 23:31:05 I think my recent changes to HidConnection make it
piperc 2017/04/17 23:43:59 Acknowledged.
217 weak_factory_.GetWeakPtr(), 233 FROM_HERE,
218 base::Passed(&callback))); 234 base::Bind(&U2fHidDevice::ReadMessage, weak_factory_.GetWeakPtr(),
235 base::Passed(&callback)));
219 return; 236 return;
220 } 237 }
221 238
222 if (read_message->MessageComplete()) { 239 if (read_message->MessageComplete()) {
223 std::move(callback).Run(success, std::move(read_message)); 240 std::move(callback).Run(success, std::move(read_message));
224 return; 241 return;
225 } 242 }
226 243
227 // Continue reading additional packets 244 // Continue reading additional packets
228 connection_->Read( 245 connection_->Read(
(...skipping 18 matching lines...) Expand all
247 return; 264 return;
248 } 265 }
249 connection_->Read( 266 connection_->Read(
250 base::Bind(&U2fHidDevice::OnReadContinuation, weak_factory_.GetWeakPtr(), 267 base::Bind(&U2fHidDevice::OnReadContinuation, weak_factory_.GetWeakPtr(),
251 base::Passed(&message), base::Passed(&callback))); 268 base::Passed(&message), base::Passed(&callback)));
252 } 269 }
253 270
254 void U2fHidDevice::MessageReceived(const DeviceCallback& callback, 271 void U2fHidDevice::MessageReceived(const DeviceCallback& callback,
255 bool success, 272 bool success,
256 std::unique_ptr<U2fMessage> message) { 273 std::unique_ptr<U2fMessage> message) {
274 if (state_ == State::DEVICE_ERROR)
275 return;
276 timeout_callback_.Cancel();
277
257 if (!success) { 278 if (!success) {
258 state_ = State::DEVICE_ERROR; 279 state_ = State::DEVICE_ERROR;
259 Transition(nullptr, callback); 280 Transition(nullptr, callback);
260 return; 281 return;
261 } 282 }
283
262 std::unique_ptr<U2fApduResponse> response = nullptr; 284 std::unique_ptr<U2fApduResponse> response = nullptr;
263 if (message) 285 if (message)
264 response = U2fApduResponse::CreateFromMessage(message->GetMessagePayload()); 286 response = U2fApduResponse::CreateFromMessage(message->GetMessagePayload());
265 state_ = State::IDLE; 287 state_ = State::IDLE;
266 base::WeakPtr<U2fHidDevice> self = weak_factory_.GetWeakPtr(); 288 base::WeakPtr<U2fHidDevice> self = weak_factory_.GetWeakPtr();
267 callback.Run(success, std::move(response)); 289 callback.Run(success, std::move(response));
268 290
269 // Executing |callback| may have freed |this|. Check |self| first. 291 // Executing |callback| may have freed |this|. Check |self| first.
270 if (self && !pending_transactions_.empty()) { 292 if (self && !pending_transactions_.empty()) {
271 // If any transactions were queued, process the first one 293 // If any transactions were queued, process the first one
(...skipping 18 matching lines...) Expand all
290 std::move(wink_message), true, 312 std::move(wink_message), true,
291 base::Bind(&U2fHidDevice::OnWink, weak_factory_.GetWeakPtr(), callback)); 313 base::Bind(&U2fHidDevice::OnWink, weak_factory_.GetWeakPtr(), callback));
292 } 314 }
293 315
294 void U2fHidDevice::OnWink(const WinkCallback& callback, 316 void U2fHidDevice::OnWink(const WinkCallback& callback,
295 bool success, 317 bool success,
296 std::unique_ptr<U2fMessage> response) { 318 std::unique_ptr<U2fMessage> response) {
297 callback.Run(); 319 callback.Run();
298 } 320 }
299 321
322 void U2fHidDevice::ArmTimeout(const DeviceCallback& callback) {
323 DCHECK(timeout_callback_.IsCancelled());
324 timeout_callback_.Reset(base::Bind(&U2fHidDevice::OnTimeout,
325 weak_factory_.GetWeakPtr(), callback));
326 // Setup timeout task for 3 seconds
327 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
328 FROM_HERE, timeout_callback_.callback(),
329 base::TimeDelta::FromMilliseconds(3000));
330 }
331
332 void U2fHidDevice::OnTimeout(const DeviceCallback& callback) {
333 state_ = State::DEVICE_ERROR;
334 Transition(nullptr, callback);
335 }
336
300 std::string U2fHidDevice::GetId() { 337 std::string U2fHidDevice::GetId() {
301 std::ostringstream id("hid:"); 338 std::ostringstream id("hid:", std::ios::ate);
302 id << device_info_->device_id(); 339 id << device_info_->device_id();
303 return id.str(); 340 return id.str();
304 } 341 }
305 342
306 // static 343 // static
307 bool U2fHidDevice::IsTestEnabled() { 344 bool U2fHidDevice::IsTestEnabled() {
308 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); 345 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
309 return command_line->HasSwitch(switches::kEnableU2fHidTest); 346 return command_line->HasSwitch(switches::kEnableU2fHidTest);
310 } 347 }
311 348
312 } // namespace device 349 } // namespace device
OLDNEW
« no previous file with comments | « device/u2f/u2f_hid_device.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698