| 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 base::Passed(&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(std::move(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 std::unique_ptr<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(std::move(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 } |
| 62 case State::BUSY: | 62 case State::BUSY: |
| 63 pending_transactions_.push_back({std::move(command), callback}); | 63 pending_transactions_.push_back({std::move(command), callback}); |
| 64 break; | 64 break; |
| 65 case State::DEVICE_ERROR: | 65 case State::DEVICE_ERROR: |
| 66 default: | 66 default: |
| 67 base::WeakPtr<U2fHidDevice> self = weak_factory_.GetWeakPtr(); | 67 base::WeakPtr<U2fHidDevice> self = weak_factory_.GetWeakPtr(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 93 state_ = State::DEVICE_ERROR; | 93 state_ = State::DEVICE_ERROR; |
| 94 } | 94 } |
| 95 Transition(std::move(command), callback); | 95 Transition(std::move(command), callback); |
| 96 } | 96 } |
| 97 | 97 |
| 98 void U2fHidDevice::AllocateChannel(std::unique_ptr<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 std::unique_ptr<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 std::move(message), true, |
| 108 base::Bind(&U2fHidDevice::OnAllocateChannel, weak_factory_.GetWeakPtr(), | 108 base::Bind(&U2fHidDevice::OnAllocateChannel, weak_factory_.GetWeakPtr(), |
| 109 nonce, base::Passed(&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 std::unique_ptr<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 std::unique_ptr<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 |
| 124 // 8: 4 byte channel id | 124 // 8: 4 byte channel id |
| 125 // 12: Protocol version id | 125 // 12: Protocol version id |
| 126 // 13: Major device version | 126 // 13: Major device version |
| (...skipping 19 matching lines...) Expand all Loading... |
| 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(std::move(command), callback); | 153 Transition(std::move(command), callback); |
| 154 } | 154 } |
| 155 | 155 |
| 156 void U2fHidDevice::WriteMessage(scoped_refptr<U2fMessage> message, | 156 void U2fHidDevice::WriteMessage(std::unique_ptr<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(&callback))); | 169 base::Passed(&message), true, base::Passed(&callback))); |
| 170 } | 170 } |
| 171 | 171 |
| 172 void U2fHidDevice::PacketWritten(scoped_refptr<U2fMessage> message, | 172 void U2fHidDevice::PacketWritten(std::unique_ptr<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(std::move(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(&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 std::unique_ptr<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(&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, std::move(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( |
| 230 weak_factory_.GetWeakPtr(), read_message, | 230 base::Bind(&U2fHidDevice::OnReadContinuation, weak_factory_.GetWeakPtr(), |
| 231 base::Passed(&callback))); | 231 base::Passed(&read_message), base::Passed(&callback))); |
| 232 } | 232 } |
| 233 | 233 |
| 234 void U2fHidDevice::OnReadContinuation(scoped_refptr<U2fMessage> message, | 234 void U2fHidDevice::OnReadContinuation(std::unique_ptr<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, std::move(message)); |
| 249 return; | 249 return; |
| 250 } | 250 } |
| 251 connection_->Read(base::Bind(&U2fHidDevice::OnReadContinuation, | 251 connection_->Read( |
| 252 weak_factory_.GetWeakPtr(), message, | 252 base::Bind(&U2fHidDevice::OnReadContinuation, weak_factory_.GetWeakPtr(), |
| 253 base::Passed(&callback))); | 253 base::Passed(&message), 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 std::unique_ptr<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 std::unique_ptr<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(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 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 |
| 289 scoped_refptr<U2fMessage> wink_message = device::U2fMessage::Create( | 289 std::unique_ptr<U2fMessage> wink_message = U2fMessage::Create( |
| 290 channel_id_, U2fMessage::Type::CMD_WINK, std::vector<uint8_t>()); | 290 channel_id_, U2fMessage::Type::CMD_WINK, std::vector<uint8_t>()); |
| 291 WriteMessage( | 291 WriteMessage( |
| 292 wink_message, true, | 292 std::move(wink_message), true, |
| 293 base::Bind(&U2fHidDevice::OnWink, weak_factory_.GetWeakPtr(), callback)); | 293 base::Bind(&U2fHidDevice::OnWink, weak_factory_.GetWeakPtr(), callback)); |
| 294 } | 294 } |
| 295 | 295 |
| 296 void U2fHidDevice::OnWink(const WinkCallback& callback, | 296 void U2fHidDevice::OnWink(const WinkCallback& callback, |
| 297 bool success, | 297 bool success, |
| 298 scoped_refptr<U2fMessage> response) { | 298 std::unique_ptr<U2fMessage> response) { |
| 299 callback.Run(); | 299 callback.Run(); |
| 300 } | 300 } |
| 301 | 301 |
| 302 std::string U2fHidDevice::GetId() { | 302 std::string U2fHidDevice::GetId() { |
| 303 std::ostringstream id("hid:"); | 303 std::ostringstream id("hid:"); |
| 304 id << device_info_->device_id(); | 304 id << device_info_->device_id(); |
| 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 |