Commit 67d30672 authored by Adam Langley's avatar Adam Langley Committed by Commit Bot

VirtualU2fDevice: don't hairpin callbacks.

AuthenticatorImpl doesn't support the callbacks being made immediately.
Instead, defer them via the current MessageLoop.

Change-Id: I57b43049e8dca8e1d113f86eb1ea5728e7d953a8
Reviewed-on: https://chromium-review.googlesource.com/963096Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Commit-Queue: Adam Langley <agl@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543710}
parent 41de0ebf
...@@ -33,7 +33,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) U2fDevice { ...@@ -33,7 +33,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) U2fDevice {
U2fDevice(); U2fDevice();
virtual ~U2fDevice(); virtual ~U2fDevice();
// Pure virtual function defined by each device type, implementing // Pure virtual function defined by each device type, implementing
// the device communication transaction. // the device communication transaction. The function must not immediately
// call (i.e. hairpin) |callback|.
virtual void DeviceTransact(std::vector<uint8_t> command, virtual void DeviceTransact(std::vector<uint8_t> command,
DeviceCallback callback) = 0; DeviceCallback callback) = 0;
virtual void TryWink(WinkCallback callback) = 0; virtual void TryWink(WinkCallback callback) = 0;
......
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
#include <utility> #include <utility>
#include "base/bind.h"
#include "base/location.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/apdu/apdu_command.h" #include "components/apdu/apdu_command.h"
#include "components/apdu/apdu_response.h" #include "components/apdu/apdu_response.h"
#include "crypto/ec_private_key.h" #include "crypto/ec_private_key.h"
...@@ -81,6 +84,13 @@ void AppendTo(std::vector<uint8_t>* dst, const T& src) { ...@@ -81,6 +84,13 @@ void AppendTo(std::vector<uint8_t>* dst, const T& src) {
dst->insert(dst->end(), std::begin(src), std::end(src)); dst->insert(dst->end(), std::begin(src), std::end(src));
} }
// Returns an error response with the given status.
base::Optional<std::vector<uint8_t>> ErrorStatus(
apdu::ApduResponse::Status status) {
return apdu::ApduResponse(std::vector<uint8_t>(), status)
.GetEncodedResponse();
}
} // namespace } // namespace
VirtualU2fDevice::RegistrationData::RegistrationData() = default; VirtualU2fDevice::RegistrationData::RegistrationData() = default;
...@@ -125,40 +135,41 @@ void VirtualU2fDevice::DeviceTransact(std::vector<uint8_t> command, ...@@ -125,40 +135,41 @@ void VirtualU2fDevice::DeviceTransact(std::vector<uint8_t> command,
DeviceCallback cb) { DeviceCallback cb) {
// Note, here we are using the code-under-test in this fake. // Note, here we are using the code-under-test in this fake.
auto parsed_command = apdu::ApduCommand::CreateFromMessage(command); auto parsed_command = apdu::ApduCommand::CreateFromMessage(command);
base::Optional<std::vector<uint8_t>> response;
switch (parsed_command->ins()) { switch (parsed_command->ins()) {
case base::strict_cast<uint8_t>(U2fApduInstruction::kVersion): case base::strict_cast<uint8_t>(U2fApduInstruction::kVersion):
break; break;
case base::strict_cast<uint8_t>(U2fApduInstruction::kRegister): case base::strict_cast<uint8_t>(U2fApduInstruction::kRegister):
DoRegister(parsed_command->ins(), parsed_command->p1(), response = DoRegister(parsed_command->ins(), parsed_command->p1(),
parsed_command->p2(), parsed_command->data(), std::move(cb)); parsed_command->p2(), parsed_command->data());
break; break;
case base::strict_cast<uint8_t>(U2fApduInstruction::kSign): case base::strict_cast<uint8_t>(U2fApduInstruction::kSign):
DoSign(parsed_command->ins(), parsed_command->p1(), parsed_command->p2(), response = DoSign(parsed_command->ins(), parsed_command->p1(),
parsed_command->data(), std::move(cb)); parsed_command->p2(), parsed_command->data());
break; break;
default: default:
std::move(cb).Run( response = ErrorStatus(apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED);
apdu::ApduResponse(std::vector<uint8_t>(),
apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED)
.GetEncodedResponse());
} }
// Call |callback| via the |MessageLoop| because |AuthenticatorImpl| doesn't
// support callback hairpinning.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(cb), std::move(response)));
} }
base::WeakPtr<U2fDevice> VirtualU2fDevice::GetWeakPtr() { base::WeakPtr<U2fDevice> VirtualU2fDevice::GetWeakPtr() {
return weak_factory_.GetWeakPtr(); return weak_factory_.GetWeakPtr();
} }
void VirtualU2fDevice::DoRegister(uint8_t ins, base::Optional<std::vector<uint8_t>> VirtualU2fDevice::DoRegister(
uint8_t p1, uint8_t ins,
uint8_t p2, uint8_t p1,
base::span<const uint8_t> data, uint8_t p2,
DeviceCallback cb) { base::span<const uint8_t> data) {
if (data.size() != 64) { if (data.size() != 64) {
std::move(cb).Run( return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_LENGTH);
apdu::ApduResponse(std::vector<uint8_t>(),
apdu::ApduResponse::Status::SW_WRONG_LENGTH)
.GetEncodedResponse());
return;
} }
// For now we ignore P1 here. Spec says it should always be 0, and TUP is // For now we ignore P1 here. Spec says it should always be 0, and TUP is
...@@ -219,24 +230,20 @@ void VirtualU2fDevice::DoRegister(uint8_t ins, ...@@ -219,24 +230,20 @@ void VirtualU2fDevice::DoRegister(uint8_t ins,
std::vector<uint8_t>(app_id_hash.begin(), app_id_hash.end()), std::vector<uint8_t>(app_id_hash.begin(), app_id_hash.end()),
1); 1);
std::move(cb).Run(apdu::ApduResponse(std::move(response), return apdu::ApduResponse(std::move(response),
apdu::ApduResponse::Status::SW_NO_ERROR) apdu::ApduResponse::Status::SW_NO_ERROR)
.GetEncodedResponse()); .GetEncodedResponse();
} }
void VirtualU2fDevice::DoSign(uint8_t ins, base::Optional<std::vector<uint8_t>> VirtualU2fDevice::DoSign(
uint8_t p1, uint8_t ins,
uint8_t p2, uint8_t p1,
base::span<const uint8_t> data, uint8_t p2,
DeviceCallback cb) { base::span<const uint8_t> data) {
if (!(p1 == kP1CheckOnly || p1 == kP1TupRequiredConsumed || if (!(p1 == kP1CheckOnly || p1 == kP1TupRequiredConsumed ||
p1 == kP1IndividualAttestation) || p1 == kP1IndividualAttestation) ||
p2 != 0) { p2 != 0) {
std::move(cb).Run( return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
apdu::ApduResponse(std::vector<uint8_t>(),
apdu::ApduResponse::Status::SW_WRONG_DATA)
.GetEncodedResponse());
return;
} }
auto challenge_param = data.first(32); auto challenge_param = data.first(32);
...@@ -245,18 +252,10 @@ void VirtualU2fDevice::DoSign(uint8_t ins, ...@@ -245,18 +252,10 @@ void VirtualU2fDevice::DoSign(uint8_t ins,
if (key_handle_length != 32) { if (key_handle_length != 32) {
// Our own keyhandles are always 32 bytes long, if the request has something // Our own keyhandles are always 32 bytes long, if the request has something
// else then we already know it is not ours. // else then we already know it is not ours.
std::move(cb).Run( return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
apdu::ApduResponse(std::vector<uint8_t>(),
apdu::ApduResponse::Status::SW_WRONG_DATA)
.GetEncodedResponse());
return;
} }
if (data.size() != 32 + 32 + 1 + key_handle_length) { if (data.size() != 32 + 32 + 1 + key_handle_length) {
std::move(cb).Run( return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_LENGTH);
apdu::ApduResponse(std::vector<uint8_t>(),
apdu::ApduResponse::Status::SW_WRONG_LENGTH)
.GetEncodedResponse());
return;
} }
auto key_handle = data.last(key_handle_length); auto key_handle = data.last(key_handle_length);
...@@ -265,11 +264,7 @@ void VirtualU2fDevice::DoSign(uint8_t ins, ...@@ -265,11 +264,7 @@ void VirtualU2fDevice::DoSign(uint8_t ins,
std::vector<uint8_t>(key_handle.cbegin(), key_handle.cend())); std::vector<uint8_t>(key_handle.cbegin(), key_handle.cend()));
if (it == registrations_.end()) { if (it == registrations_.end()) {
std::move(cb).Run( return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
apdu::ApduResponse(std::vector<uint8_t>(),
apdu::ApduResponse::Status::SW_WRONG_DATA)
.GetEncodedResponse());
return;
} }
base::span<const uint8_t> registered_app_id_hash = base::span<const uint8_t> registered_app_id_hash =
...@@ -277,11 +272,7 @@ void VirtualU2fDevice::DoSign(uint8_t ins, ...@@ -277,11 +272,7 @@ void VirtualU2fDevice::DoSign(uint8_t ins,
if (app_id_hash != registered_app_id_hash) { if (app_id_hash != registered_app_id_hash) {
// It's important this error looks identical to the previous one, as // It's important this error looks identical to the previous one, as
// tokens should not reveal the existence of keyHandles to unrelated appIds. // tokens should not reveal the existence of keyHandles to unrelated appIds.
std::move(cb).Run( return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
apdu::ApduResponse(std::vector<uint8_t>(),
apdu::ApduResponse::Status::SW_WRONG_DATA)
.GetEncodedResponse());
return;
} }
auto& registration = it->second; auto& registration = it->second;
...@@ -312,9 +303,9 @@ void VirtualU2fDevice::DoSign(uint8_t ins, ...@@ -312,9 +303,9 @@ void VirtualU2fDevice::DoSign(uint8_t ins,
// Add signature for full response. // Add signature for full response.
AppendTo(&response, sig); AppendTo(&response, sig);
std::move(cb).Run(apdu::ApduResponse(std::move(response), return apdu::ApduResponse(std::move(response),
apdu::ApduResponse::Status::SW_NO_ERROR) apdu::ApduResponse::Status::SW_NO_ERROR)
.GetEncodedResponse()); .GetEncodedResponse();
} }
} // namespace device } // namespace device
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "base/component_export.h" #include "base/component_export.h"
...@@ -58,17 +59,16 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualU2fDevice : public U2fDevice { ...@@ -58,17 +59,16 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualU2fDevice : public U2fDevice {
DISALLOW_COPY_AND_ASSIGN(RegistrationData); DISALLOW_COPY_AND_ASSIGN(RegistrationData);
}; };
void DoRegister(uint8_t ins, base::Optional<std::vector<uint8_t>> DoRegister(
uint8_t p1, uint8_t ins,
uint8_t p2, uint8_t p1,
base::span<const uint8_t> data, uint8_t p2,
DeviceCallback cb); base::span<const uint8_t> data);
void DoSign(uint8_t ins, base::Optional<std::vector<uint8_t>> DoSign(uint8_t ins,
uint8_t p1, uint8_t p1,
uint8_t p2, uint8_t p2,
base::span<const uint8_t> data, base::span<const uint8_t> data);
DeviceCallback cb);
// Keyed on appId/rpId hash (aka "applicationParam") // Keyed on appId/rpId hash (aka "applicationParam")
std::map<std::vector<uint8_t>, RegistrationData> registrations_; std::map<std::vector<uint8_t>, RegistrationData> registrations_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment