OLD | NEW |
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 "crypto/random.h" | 10 #include "crypto/random.h" |
(...skipping 15 matching lines...) Expand all Loading... |
26 weak_factory_(this) { | 26 weak_factory_(this) { |
27 channel_id_ = kBroadcastChannel; | 27 channel_id_ = kBroadcastChannel; |
28 } | 28 } |
29 | 29 |
30 U2fHidDevice::~U2fHidDevice() { | 30 U2fHidDevice::~U2fHidDevice() { |
31 // Cleanup connection | 31 // Cleanup connection |
32 if (connection_) | 32 if (connection_) |
33 connection_->Close(); | 33 connection_->Close(); |
34 } | 34 } |
35 | 35 |
36 void U2fHidDevice::DeviceTransact(scoped_refptr<U2fApduCommand> command, | 36 void U2fHidDevice::DeviceTransact(std::unique_ptr<U2fApduCommand> command, |
37 const DeviceCallback& callback) { | 37 const DeviceCallback& callback) { |
38 Transition(command, callback); | 38 Transition(std::move(command), callback); |
39 } | 39 } |
40 | 40 |
41 void U2fHidDevice::Transition(scoped_refptr<U2fApduCommand> command, | 41 void U2fHidDevice::Transition(std::unique_ptr<U2fApduCommand> command, |
42 const DeviceCallback& callback) { | 42 const DeviceCallback& callback) { |
43 switch (state_) { | 43 switch (state_) { |
44 case State::INIT: | 44 case State::INIT: |
45 state_ = State::BUSY; | 45 state_ = State::BUSY; |
46 Connect(base::Bind(&U2fHidDevice::OnConnect, weak_factory_.GetWeakPtr(), | 46 Connect(base::Bind(&U2fHidDevice::OnConnect, weak_factory_.GetWeakPtr(), |
47 command, callback)); | 47 base::Passed(&command), callback)); |
48 break; | 48 break; |
49 case State::CONNECTED: | 49 case State::CONNECTED: |
50 state_ = State::BUSY; | 50 state_ = State::BUSY; |
51 AllocateChannel(command, callback); | 51 AllocateChannel(std::move(command), callback); |
52 break; | 52 break; |
53 case State::IDLE: { | 53 case State::IDLE: { |
54 state_ = State::BUSY; | 54 state_ = State::BUSY; |
55 scoped_refptr<U2fMessage> msg = U2fMessage::Create( | 55 scoped_refptr<U2fMessage> msg = U2fMessage::Create( |
56 channel_id_, U2fMessage::Type::CMD_MSG, command->GetEncodedCommand()); | 56 channel_id_, U2fMessage::Type::CMD_MSG, command->GetEncodedCommand()); |
57 WriteMessage(msg, true, | 57 WriteMessage(msg, true, |
58 base::Bind(&U2fHidDevice::MessageReceived, | 58 base::Bind(&U2fHidDevice::MessageReceived, |
59 weak_factory_.GetWeakPtr(), callback)); | 59 weak_factory_.GetWeakPtr(), callback)); |
60 break; | 60 break; |
61 } | 61 } |
(...skipping 14 matching lines...) Expand all Loading... |
76 break; | 76 break; |
77 } | 77 } |
78 } | 78 } |
79 | 79 |
80 void U2fHidDevice::Connect(const HidService::ConnectCallback& callback) { | 80 void U2fHidDevice::Connect(const HidService::ConnectCallback& callback) { |
81 HidService* hid_service = DeviceClient::Get()->GetHidService(); | 81 HidService* hid_service = DeviceClient::Get()->GetHidService(); |
82 | 82 |
83 hid_service->Connect(device_info_->device_id(), callback); | 83 hid_service->Connect(device_info_->device_id(), callback); |
84 } | 84 } |
85 | 85 |
86 void U2fHidDevice::OnConnect(scoped_refptr<U2fApduCommand> command, | 86 void U2fHidDevice::OnConnect(std::unique_ptr<U2fApduCommand> command, |
87 const DeviceCallback& callback, | 87 const DeviceCallback& callback, |
88 scoped_refptr<HidConnection> connection) { | 88 scoped_refptr<HidConnection> connection) { |
89 if (connection) { | 89 if (connection) { |
90 connection_ = connection; | 90 connection_ = connection; |
91 state_ = State::CONNECTED; | 91 state_ = State::CONNECTED; |
92 } else { | 92 } else { |
93 state_ = State::DEVICE_ERROR; | 93 state_ = State::DEVICE_ERROR; |
94 } | 94 } |
95 Transition(command, callback); | 95 Transition(std::move(command), callback); |
96 } | 96 } |
97 | 97 |
98 void U2fHidDevice::AllocateChannel(scoped_refptr<U2fApduCommand> command, | 98 void U2fHidDevice::AllocateChannel(std::unique_ptr<U2fApduCommand> command, |
99 const DeviceCallback& callback) { | 99 const DeviceCallback& callback) { |
100 // Send random nonce to device to verify received message | 100 // Send random nonce to device to verify received message |
101 std::vector<uint8_t> nonce(8); | 101 std::vector<uint8_t> nonce(8); |
102 crypto::RandBytes(nonce.data(), nonce.size()); | 102 crypto::RandBytes(nonce.data(), nonce.size()); |
103 scoped_refptr<U2fMessage> message = | 103 scoped_refptr<U2fMessage> message = |
104 U2fMessage::Create(channel_id_, U2fMessage::Type::CMD_INIT, nonce); | 104 U2fMessage::Create(channel_id_, U2fMessage::Type::CMD_INIT, nonce); |
105 | 105 |
106 WriteMessage( | 106 WriteMessage( |
107 message, true, | 107 message, true, |
108 base::Bind(&U2fHidDevice::OnAllocateChannel, weak_factory_.GetWeakPtr(), | 108 base::Bind(&U2fHidDevice::OnAllocateChannel, weak_factory_.GetWeakPtr(), |
109 nonce, command, callback)); | 109 nonce, base::Passed(&command), callback)); |
110 } | 110 } |
111 | 111 |
112 void U2fHidDevice::OnAllocateChannel(std::vector<uint8_t> nonce, | 112 void U2fHidDevice::OnAllocateChannel(std::vector<uint8_t> nonce, |
113 scoped_refptr<U2fApduCommand> command, | 113 std::unique_ptr<U2fApduCommand> command, |
114 const DeviceCallback& callback, | 114 const DeviceCallback& callback, |
115 bool success, | 115 bool success, |
116 scoped_refptr<U2fMessage> message) { | 116 scoped_refptr<U2fMessage> message) { |
117 if (!success || !message) { | 117 if (!success || !message) { |
118 state_ = State::DEVICE_ERROR; | 118 state_ = State::DEVICE_ERROR; |
119 Transition(nullptr, callback); | 119 Transition(nullptr, callback); |
120 return; | 120 return; |
121 } | 121 } |
122 // Channel allocation response is defined as: | 122 // Channel allocation response is defined as: |
123 // 0: 8 byte nonce | 123 // 0: 8 byte nonce |
(...skipping 19 matching lines...) Expand all Loading... |
143 } | 143 } |
144 | 144 |
145 size_t index = 8; | 145 size_t index = 8; |
146 channel_id_ = payload[index++] << 24; | 146 channel_id_ = payload[index++] << 24; |
147 channel_id_ |= payload[index++] << 16; | 147 channel_id_ |= payload[index++] << 16; |
148 channel_id_ |= payload[index++] << 8; | 148 channel_id_ |= payload[index++] << 8; |
149 channel_id_ |= payload[index++]; | 149 channel_id_ |= payload[index++]; |
150 capabilities_ = payload[16]; | 150 capabilities_ = payload[16]; |
151 | 151 |
152 state_ = State::IDLE; | 152 state_ = State::IDLE; |
153 Transition(command, callback); | 153 Transition(std::move(command), callback); |
154 } | 154 } |
155 | 155 |
156 void U2fHidDevice::WriteMessage(scoped_refptr<U2fMessage> message, | 156 void U2fHidDevice::WriteMessage(scoped_refptr<U2fMessage> message, |
157 bool response_expected, | 157 bool response_expected, |
158 U2fHidMessageCallback callback) { | 158 U2fHidMessageCallback callback) { |
159 if (!connection_ || !message || message->NumPackets() == 0) { | 159 if (!connection_ || !message || message->NumPackets() == 0) { |
160 std::move(callback).Run(false, nullptr); | 160 std::move(callback).Run(false, nullptr); |
161 return; | 161 return; |
162 } | 162 } |
163 | 163 |
164 scoped_refptr<net::IOBufferWithSize> buffer = message->PopNextPacket(); | 164 scoped_refptr<net::IOBufferWithSize> buffer = message->PopNextPacket(); |
165 | 165 |
166 connection_->Write( | 166 connection_->Write( |
167 buffer, buffer->size(), | 167 buffer, buffer->size(), |
168 base::Bind(&U2fHidDevice::PacketWritten, weak_factory_.GetWeakPtr(), | 168 base::Bind(&U2fHidDevice::PacketWritten, weak_factory_.GetWeakPtr(), |
169 message, true, base::Passed(std::move(callback)))); | 169 message, true, base::Passed(&callback))); |
170 } | 170 } |
171 | 171 |
172 void U2fHidDevice::PacketWritten(scoped_refptr<U2fMessage> message, | 172 void U2fHidDevice::PacketWritten(scoped_refptr<U2fMessage> message, |
173 bool response_expected, | 173 bool response_expected, |
174 U2fHidMessageCallback callback, | 174 U2fHidMessageCallback callback, |
175 bool success) { | 175 bool success) { |
176 if (success && message->NumPackets() > 0) { | 176 if (success && message->NumPackets() > 0) { |
177 WriteMessage(message, response_expected, std::move(callback)); | 177 WriteMessage(message, response_expected, std::move(callback)); |
178 } else if (success && response_expected) { | 178 } else if (success && response_expected) { |
179 ReadMessage(std::move(callback)); | 179 ReadMessage(std::move(callback)); |
180 } else { | 180 } else { |
181 std::move(callback).Run(success, nullptr); | 181 std::move(callback).Run(success, nullptr); |
182 } | 182 } |
183 } | 183 } |
184 | 184 |
185 void U2fHidDevice::ReadMessage(U2fHidMessageCallback callback) { | 185 void U2fHidDevice::ReadMessage(U2fHidMessageCallback callback) { |
186 if (!connection_) { | 186 if (!connection_) { |
187 std::move(callback).Run(false, nullptr); | 187 std::move(callback).Run(false, nullptr); |
188 return; | 188 return; |
189 } | 189 } |
190 | 190 |
191 connection_->Read(base::Bind(&U2fHidDevice::OnRead, | 191 connection_->Read(base::Bind(&U2fHidDevice::OnRead, |
192 weak_factory_.GetWeakPtr(), | 192 weak_factory_.GetWeakPtr(), |
193 base::Passed(std::move(callback)))); | 193 base::Passed(&callback))); |
194 } | 194 } |
195 | 195 |
196 void U2fHidDevice::OnRead(U2fHidMessageCallback callback, | 196 void U2fHidDevice::OnRead(U2fHidMessageCallback callback, |
197 bool success, | 197 bool success, |
198 scoped_refptr<net::IOBuffer> buf, | 198 scoped_refptr<net::IOBuffer> buf, |
199 size_t size) { | 199 size_t size) { |
200 if (!success) { | 200 if (!success) { |
201 std::move(callback).Run(success, nullptr); | 201 std::move(callback).Run(success, nullptr); |
202 return; | 202 return; |
203 } | 203 } |
204 | 204 |
205 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(size)); | 205 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(size)); |
206 memcpy(buffer->data(), buf->data(), size); | 206 memcpy(buffer->data(), buf->data(), size); |
207 scoped_refptr<U2fMessage> read_message = | 207 scoped_refptr<U2fMessage> read_message = |
208 U2fMessage::CreateFromSerializedData(buffer); | 208 U2fMessage::CreateFromSerializedData(buffer); |
209 | 209 |
210 if (!read_message) { | 210 if (!read_message) { |
211 std::move(callback).Run(false, nullptr); | 211 std::move(callback).Run(false, nullptr); |
212 return; | 212 return; |
213 } | 213 } |
214 | 214 |
215 // Received a message from a different channel, so try again | 215 // Received a message from a different channel, so try again |
216 if (channel_id_ != read_message->channel_id()) { | 216 if (channel_id_ != read_message->channel_id()) { |
217 connection_->Read(base::Bind(&U2fHidDevice::OnRead, | 217 connection_->Read(base::Bind(&U2fHidDevice::OnRead, |
218 weak_factory_.GetWeakPtr(), | 218 weak_factory_.GetWeakPtr(), |
219 base::Passed(std::move(callback)))); | 219 base::Passed(&callback))); |
220 return; | 220 return; |
221 } | 221 } |
222 | 222 |
223 if (read_message->MessageComplete()) { | 223 if (read_message->MessageComplete()) { |
224 std::move(callback).Run(success, read_message); | 224 std::move(callback).Run(success, read_message); |
225 return; | 225 return; |
226 } | 226 } |
227 | 227 |
228 // Continue reading additional packets | 228 // Continue reading additional packets |
229 connection_->Read(base::Bind(&U2fHidDevice::OnReadContinuation, | 229 connection_->Read(base::Bind(&U2fHidDevice::OnReadContinuation, |
230 weak_factory_.GetWeakPtr(), read_message, | 230 weak_factory_.GetWeakPtr(), read_message, |
231 base::Passed(std::move(callback)))); | 231 base::Passed(&callback))); |
232 } | 232 } |
233 | 233 |
234 void U2fHidDevice::OnReadContinuation(scoped_refptr<U2fMessage> message, | 234 void U2fHidDevice::OnReadContinuation(scoped_refptr<U2fMessage> message, |
235 U2fHidMessageCallback callback, | 235 U2fHidMessageCallback callback, |
236 bool success, | 236 bool success, |
237 scoped_refptr<net::IOBuffer> buf, | 237 scoped_refptr<net::IOBuffer> buf, |
238 size_t size) { | 238 size_t size) { |
239 if (!success) { | 239 if (!success) { |
240 std::move(callback).Run(success, nullptr); | 240 std::move(callback).Run(success, nullptr); |
241 return; | 241 return; |
242 } | 242 } |
243 | 243 |
244 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(size)); | 244 scoped_refptr<net::IOBufferWithSize> buffer(new net::IOBufferWithSize(size)); |
245 memcpy(buffer->data(), buf->data(), size); | 245 memcpy(buffer->data(), buf->data(), size); |
246 message->AddContinuationPacket(buffer); | 246 message->AddContinuationPacket(buffer); |
247 if (message->MessageComplete()) { | 247 if (message->MessageComplete()) { |
248 std::move(callback).Run(success, message); | 248 std::move(callback).Run(success, message); |
249 return; | 249 return; |
250 } | 250 } |
251 connection_->Read(base::Bind(&U2fHidDevice::OnReadContinuation, | 251 connection_->Read(base::Bind(&U2fHidDevice::OnReadContinuation, |
252 weak_factory_.GetWeakPtr(), message, | 252 weak_factory_.GetWeakPtr(), message, |
253 base::Passed(std::move(callback)))); | 253 base::Passed(&callback))); |
254 } | 254 } |
255 | 255 |
256 void U2fHidDevice::MessageReceived(const DeviceCallback& callback, | 256 void U2fHidDevice::MessageReceived(const DeviceCallback& callback, |
257 bool success, | 257 bool success, |
258 scoped_refptr<U2fMessage> message) { | 258 scoped_refptr<U2fMessage> message) { |
259 if (!success) { | 259 if (!success) { |
260 state_ = State::DEVICE_ERROR; | 260 state_ = State::DEVICE_ERROR; |
261 Transition(nullptr, callback); | 261 Transition(nullptr, callback); |
262 return; | 262 return; |
263 } | 263 } |
264 scoped_refptr<U2fApduResponse> response = nullptr; | 264 std::unique_ptr<U2fApduResponse> response = nullptr; |
265 if (message) | 265 if (message) |
266 response = U2fApduResponse::CreateFromMessage(message->GetMessagePayload()); | 266 response = U2fApduResponse::CreateFromMessage(message->GetMessagePayload()); |
267 state_ = State::IDLE; | 267 state_ = State::IDLE; |
268 base::WeakPtr<U2fHidDevice> self = weak_factory_.GetWeakPtr(); | 268 base::WeakPtr<U2fHidDevice> self = weak_factory_.GetWeakPtr(); |
269 callback.Run(success, response); | 269 callback.Run(success, std::move(response)); |
270 | 270 |
271 // Executing |callback| may have freed |this|. Check |self| first. | 271 // Executing |callback| may have freed |this|. Check |self| first. |
272 if (self && !pending_transactions_.empty()) { | 272 if (self && !pending_transactions_.empty()) { |
273 // If any transactions were queued, process the first one | 273 // If any transactions were queued, process the first one |
274 scoped_refptr<U2fApduCommand> pending_cmd = | 274 std::unique_ptr<U2fApduCommand> pending_cmd = |
275 std::move(pending_transactions_.front().first); | 275 std::move(pending_transactions_.front().first); |
276 DeviceCallback pending_cb = pending_transactions_.front().second; | 276 DeviceCallback pending_cb = pending_transactions_.front().second; |
277 pending_transactions_.pop_front(); | 277 pending_transactions_.pop_front(); |
278 Transition(pending_cmd, pending_cb); | 278 Transition(std::move(pending_cmd), pending_cb); |
279 } | 279 } |
280 } | 280 } |
281 | 281 |
282 void U2fHidDevice::TryWink(const WinkCallback& callback) { | 282 void U2fHidDevice::TryWink(const WinkCallback& callback) { |
283 // Only try to wink if device claims support | 283 // Only try to wink if device claims support |
284 if (!(capabilities_ & kWinkCapability) || state_ != State::IDLE) { | 284 if (!(capabilities_ & kWinkCapability) || state_ != State::IDLE) { |
285 callback.Run(); | 285 callback.Run(); |
286 return; | 286 return; |
287 } | 287 } |
288 | 288 |
(...skipping 16 matching lines...) Expand all Loading... |
305 return id.str(); | 305 return id.str(); |
306 } | 306 } |
307 | 307 |
308 // static | 308 // static |
309 bool U2fHidDevice::IsTestEnabled() { | 309 bool U2fHidDevice::IsTestEnabled() { |
310 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 310 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
311 return command_line->HasSwitch(switches::kEnableU2fHidTest); | 311 return command_line->HasSwitch(switches::kEnableU2fHidTest); |
312 } | 312 } |
313 | 313 |
314 } // namespace device | 314 } // namespace device |
OLD | NEW |