Skip to content

Commit

Permalink
Implement CTAP MakeCredential per device request logic
Browse files Browse the repository at this point in the history
Implements FidoTask class and MakeCredentialTask class. FidoTask handles
shared logic between MakeCredential request and GetAssertion request
such as logic for AuthenticatorGetInfo request which is a preliminary
request for MakeCredential request. MakeCredentialTask class initiates
asynchronous MakeCredential request for a single device upon construction
and decodes cbor encodeded response into MakeCredentialResponse object.

Change-Id: Icbb6295436b4501bcb94be58b503821e9aa35ce8
Reviewed-on: https://chromium-review.googlesource.com/936382
Commit-Queue: Jun Choi <hongjunchoi@chromium.org>
Reviewed-by: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: Balazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#545293}
  • Loading branch information
Jun Choi authored and Commit Bot committed Mar 22, 2018
1 parent 3df0f4e commit f15afe4
Show file tree
Hide file tree
Showing 15 changed files with 523 additions and 9 deletions.
1 change: 1 addition & 0 deletions device/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ test("device_unittests") {
"fido/fido_ble_frames_unittest.cc",
"fido/fido_discovery_unittest.cc",
"fido/fido_hid_message_unittest.cc",
"fido/make_credential_task_unittest.cc",
"fido/test_callback_receiver_unittest.cc",
"fido/u2f_parsing_utils_unittest.cc",
"fido/u2f_register_unittest.cc",
Expand Down
4 changes: 4 additions & 0 deletions device/fido/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ component("fido") {
"fido_hid_message.h",
"fido_hid_packet.cc",
"fido_hid_packet.h",
"fido_task.cc",
"fido_task.h",
"make_credential_task.cc",
"make_credential_task.h",
"opaque_attestation_statement.cc",
"opaque_attestation_statement.h",
"opaque_public_key.cc",
Expand Down
3 changes: 2 additions & 1 deletion device/fido/device_response_converter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ base::Optional<AuthenticatorGetAssertionResponse> ReadCTAPGetAssertionResponse(

base::Optional<AuthenticatorGetInfoResponse> ReadCTAPGetInfoResponse(
base::span<const uint8_t> buffer) {
if (buffer.size() <= kResponseCodeLength)
if (buffer.size() <= kResponseCodeLength ||
GetResponseCode(buffer) != CtapDeviceResponseCode::kSuccess)
return base::nullopt;

base::Optional<CBOR> decoded_response =
Expand Down
6 changes: 6 additions & 0 deletions device/fido/fido_device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@

#include "device/fido/fido_device.h"

#include <utility>

namespace device {

FidoDevice::FidoDevice() = default;
FidoDevice::~FidoDevice() = default;

void FidoDevice::SetDeviceInfo(AuthenticatorGetInfoResponse device_info) {
device_info_ = std::move(device_info);
}

} // namespace device
19 changes: 18 additions & 1 deletion device/fido/fido_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "device/fido/authenticator_get_info_response.h"
#include "device/fido/fido_constants.h"

namespace device {

Expand All @@ -39,9 +40,25 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDevice {
virtual void TryWink(WinkCallback callback) = 0;
virtual std::string GetId() const = 0;

void SetDeviceInfo(AuthenticatorGetInfoResponse device_info);
void set_supported_protocol(ProtocolVersion supported_protocol) {
supported_protocol_ = supported_protocol;
}
void set_state(State state) { state_ = state; }

ProtocolVersion supported_protocol() const { return supported_protocol_; }
const base::Optional<AuthenticatorGetInfoResponse>& device_info() const {
return device_info_;
}
State state() const { return state_; }

protected:
virtual base::WeakPtr<FidoDevice> GetWeakPtr() = 0;

State state_ = State::kInit;
ProtocolVersion supported_protocol_ = ProtocolVersion::kUnknown;
base::Optional<AuthenticatorGetInfoResponse> device_info_;

DISALLOW_COPY_AND_ASSIGN(FidoDevice);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file contains common data used to test U2F register and sign responses.
// This file contains common data used to test CTAP/U2F register and sign
// responses.

#ifndef DEVICE_FIDO_U2F_RESPONSE_TEST_DATA_H_
#define DEVICE_FIDO_U2F_RESPONSE_TEST_DATA_H_
#ifndef DEVICE_FIDO_FIDO_RESPONSE_TEST_DATA_H_
#define DEVICE_FIDO_FIDO_RESPONSE_TEST_DATA_H_

#include <stdint.h>

namespace device {

Expand Down Expand Up @@ -102,8 +105,83 @@ constexpr uint8_t kTestU2fSignResponse[] = {

// A sample corrupted response to a U2F sign request.
constexpr uint8_t kTestCorruptedU2fSignResponse[] = {0x01, 0x00, 0x00, 0x00};

// A sample well formed response to CTAP AuthenticatorGetInfo request.
constexpr uint8_t kTestAuthenticatorGetInfoResponse[] = {
0x00, 0xA6, 0x01, 0x82, 0x68, 0x46, 0x49, 0x44, 0x4F, 0x5F, 0x32, 0x5F,
0x30, 0x66, 0x55, 0x32, 0x46, 0x5F, 0x56, 0x32, 0x02, 0x82, 0x63, 0x75,
0x76, 0x6D, 0x6B, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x65, 0x63, 0x72,
0x65, 0x74, 0x03, 0x50, 0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15,
0x80, 0x06, 0x17, 0x11, 0x1F, 0x9E, 0xDC, 0x7D, 0x04, 0xA4, 0x62, 0x72,
0x6B, 0xF4, 0x62, 0x75, 0x70, 0xF5, 0x64, 0x70, 0x6C, 0x61, 0x74, 0xF4,
0x69, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x50, 0x69, 0x6E, 0xF4, 0x05,
0x19, 0x04, 0xB0, 0x06, 0x81, 0x01};

// A Sample well formed response to CTAP MakeCredential request.
constexpr uint8_t kTestMakeCredentialResponse[] = {
0x00, 0xA3, 0x01, 0x66, 0x70, 0x61, 0x63, 0x6B, 0x65, 0x64, 0x02, 0x58,
0xC4, 0x46, 0xCC, 0x7F, 0xB9, 0x67, 0x9D, 0x55, 0xB2, 0xDB, 0x90, 0x92,
0xE1, 0xC8, 0xD9, 0xE5, 0xE1, 0xD0, 0x2B, 0x75, 0x80, 0xF0, 0xB4, 0x81,
0x2C, 0x77, 0x09, 0x62, 0xE1, 0xE4, 0x8F, 0x5A, 0xD8, 0x41, 0x00, 0x00,
0x00, 0x52, 0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15, 0x80, 0x06,
0x17, 0x11, 0x1F, 0x9E, 0xDC, 0x7D, 0x00, 0x40, 0x2C, 0xC4, 0x73, 0x23,
0xA0, 0xEE, 0x0D, 0x5F, 0x66, 0x35, 0x4A, 0x2B, 0x35, 0xC5, 0xFA, 0xFB,
0xE7, 0x3D, 0x98, 0x18, 0xB4, 0xC0, 0x53, 0xE9, 0x29, 0x19, 0xAE, 0x3B,
0x67, 0xD7, 0xAF, 0x4F, 0x15, 0x6E, 0x67, 0xD0, 0x46, 0x5B, 0x39, 0x06,
0x70, 0x93, 0x2F, 0xCE, 0x79, 0x33, 0xDD, 0xD5, 0x96, 0x8F, 0xD0, 0xBF,
0xFF, 0x85, 0x62, 0x1F, 0xFD, 0x12, 0x95, 0xBD, 0x0A, 0x41, 0x81, 0x24,
0xA5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xEB, 0x78,
0x4F, 0x0B, 0x6C, 0x78, 0x1E, 0xA1, 0x1E, 0xC8, 0x14, 0x24, 0x36, 0x66,
0x07, 0x2F, 0x4B, 0xDB, 0x53, 0xF6, 0x95, 0x8D, 0xDF, 0xC2, 0xCB, 0x6B,
0xA0, 0xC2, 0x69, 0xA4, 0x16, 0x03, 0x22, 0x58, 0x20, 0xD4, 0xC3, 0xDC,
0xD9, 0x3D, 0xF9, 0x60, 0x9A, 0xF8, 0x56, 0x96, 0xE2, 0xA6, 0x62, 0xF1,
0x05, 0xAE, 0x9C, 0x76, 0x9A, 0x0B, 0x3F, 0xFA, 0x5C, 0x05, 0xED, 0xE5,
0x7C, 0x64, 0x0A, 0x60, 0x28, 0x03, 0xA3, 0x63, 0x61, 0x6C, 0x67, 0x26,
0x63, 0x73, 0x69, 0x67, 0x58, 0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xA2,
0xA4, 0x1B, 0x2A, 0xE3, 0xA2, 0x0D, 0xFA, 0xF8, 0x0B, 0xB6, 0x96, 0xA0,
0x9A, 0xC4, 0x37, 0x84, 0xA7, 0x96, 0x08, 0x90, 0xB8, 0x96, 0xA1, 0x52,
0xC8, 0x59, 0x19, 0x68, 0xA3, 0xED, 0x6D, 0x02, 0x20, 0x4B, 0xD3, 0x1E,
0xBF, 0x6B, 0xA0, 0x05, 0x5A, 0x73, 0x12, 0x6F, 0x3E, 0x4B, 0xC2, 0x7D,
0xA1, 0xCD, 0x68, 0x5E, 0xBB, 0x86, 0x77, 0x8C, 0xC0, 0x7F, 0x8E, 0xA3,
0x91, 0x44, 0x19, 0x50, 0x19, 0x63, 0x78, 0x35, 0x63, 0x81, 0x59, 0x01,
0x97, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xA0, 0x03, 0x02,
0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0x9B, 0x72, 0x6C, 0xB2, 0x4B, 0x4C,
0x29, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03,
0x02, 0x30, 0x47, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04,
0x0A, 0x0C, 0x0B, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6F, 0x20, 0x54, 0x65,
0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C,
0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6E, 0x74, 0x69, 0x63, 0x61, 0x74,
0x6F, 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69,
0x6F, 0x6E, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x36, 0x31, 0x32, 0x30, 0x34,
0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x32, 0x36, 0x31,
0x32, 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5A, 0x30, 0x47,
0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0B,
0x59, 0x75, 0x62, 0x69, 0x63, 0x6F, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31,
0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x19, 0x41, 0x75,
0x74, 0x68, 0x65, 0x6E, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6F, 0x72, 0x20,
0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x30,
0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42,
0x00, 0x04, 0xAD, 0x11, 0xEB, 0x0E, 0x88, 0x52, 0xE5, 0x3A, 0xD5, 0xDF,
0xED, 0x86, 0xB4, 0x1E, 0x61, 0x34, 0xA1, 0x8E, 0xC4, 0xE1, 0xAF, 0x8F,
0x22, 0x1A, 0x3C, 0x7D, 0x6E, 0x63, 0x6C, 0x80, 0xEA, 0x13, 0xC3, 0xD5,
0x04, 0xFF, 0x2E, 0x76, 0x21, 0x1B, 0xB4, 0x45, 0x25, 0xB1, 0x96, 0xC4,
0x4C, 0xB4, 0x84, 0x99, 0x79, 0xCF, 0x6F, 0x89, 0x6E, 0xCD, 0x2B, 0xB8,
0x60, 0xDE, 0x1B, 0xF4, 0x37, 0x6B, 0xA3, 0x0D, 0x30, 0x0B, 0x30, 0x09,
0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0A, 0x06,
0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00,
0x30, 0x46, 0x02, 0x21, 0x00, 0xE9, 0xA3, 0x9F, 0x1B, 0x03, 0x19, 0x75,
0x25, 0xF7, 0x37, 0x3E, 0x10, 0xCE, 0x77, 0xE7, 0x80, 0x21, 0x73, 0x1B,
0x94, 0xD0, 0xC0, 0x3F, 0x3F, 0xDA, 0x1F, 0xD2, 0x2D, 0xB3, 0xD0, 0x30,
0xE7, 0x02, 0x21, 0x00, 0xC4, 0xFA, 0xEC, 0x34, 0x45, 0xA8, 0x20, 0xCF,
0x43, 0x12, 0x9C, 0xDB, 0x00, 0xAA, 0xBE, 0xFD, 0x9A, 0xE2, 0xD8, 0x74,
0xF9, 0xC5, 0xD3, 0x43, 0xCB, 0x2F, 0x11, 0x3D, 0xA2, 0x37, 0x23, 0xF3,
};

} // namespace test_data

} // namespace device

#endif // DEVICE_FIDO_U2F_RESPONSE_TEST_DATA_H_
#endif // DEVICE_FIDO_FIDO_RESPONSE_TEST_DATA_H_
62 changes: 62 additions & 0 deletions device/fido/fido_task.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "device/fido/fido_task.h"

#include <utility>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "device/fido/ctap_empty_authenticator_request.h"
#include "device/fido/device_response_converter.h"
#include "device/fido/fido_constants.h"

namespace device {

FidoTask::FidoTask(FidoDevice* device) : device_(device), weak_factory_(this) {
DCHECK(device_);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&FidoTask::StartTask, weak_factory_.GetWeakPtr()));
}

FidoTask::~FidoTask() = default;

void FidoTask::CancelTask() {
if (device()->supported_protocol() != ProtocolVersion::kCtap)
return;

device()->DeviceTransact(AuthenticatorCancelRequest().Serialize(),
base::DoNothing());
}

void FidoTask::GetAuthenticatorInfo(base::OnceClosure ctap_callback,
base::OnceClosure u2f_callback) {
device()->DeviceTransact(
AuthenticatorGetInfoRequest().Serialize(),
base::BindOnce(&FidoTask::OnAuthenticatorInfoReceived,
weak_factory_.GetWeakPtr(), std::move(ctap_callback),
std::move(u2f_callback)));
}

void FidoTask::OnAuthenticatorInfoReceived(
base::OnceClosure ctap_callback,
base::OnceClosure u2f_callback,
base::Optional<std::vector<uint8_t>> response) {
device()->set_state(FidoDevice::State::kReady);

base::Optional<AuthenticatorGetInfoResponse> get_info_response;
if (!response || !(get_info_response = ReadCTAPGetInfoResponse(*response))) {
device()->set_supported_protocol(ProtocolVersion::kU2f);
std::move(u2f_callback).Run();
return;
}

device()->SetDeviceInfo(std::move(*get_info_response));
device()->set_supported_protocol(ProtocolVersion::kCtap);
std::move(ctap_callback).Run();
}

} // namespace device
74 changes: 74 additions & 0 deletions device/fido/fido_task.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef DEVICE_FIDO_FIDO_TASK_H_
#define DEVICE_FIDO_FIDO_TASK_H_

#include <stdint.h>

#include <vector>

#include "base/callback.h"
#include "base/component_export.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "device/fido/fido_device.h"

namespace device {

// Encapsulates per-device request logic shared between MakeCredential and
// GetAssertion. Handles issuing the AuthenticatorGetInfo command to tokens,
// caching device info, and distinguishing U2F tokens from CTAP tokens.
//
// FidoTask is owned by FidoRequestHandler and manages all interaction with
// |device_|. It is created when a new device is discovered by FidoDiscovery and
// destroyed when the device is removed or when a successful response has been
// issued to the relying party from another authenticator.
class COMPONENT_EXPORT(DEVICE_FIDO) FidoTask {
public:
// The |device| must outlive the FidoTask instance.
explicit FidoTask(FidoDevice* device);
virtual ~FidoTask();

// Invokes the AuthenticatorCancel method on |device_| if it supports the
// CTAP protocol. Upon receiving AuthenticatorCancel request, authenticators
// cancel ongoing requests (if any) immediately. Calling this method itself
// neither destructs |this| instance nor destroys |device_|.
void CancelTask();

protected:
// Asynchronously initiates CTAP request operation for a single device.
virtual void StartTask() = 0;

// Invokes the AuthenticatorGetInfo method on |device_|. If successful and a
// well formed response is received, then |device_| is deemed to support CTAP
// protocol and |ctap_callback| is invoked, which sends CBOR encoded command
// to the authenticator. For all failure cases, |device_| is assumed to
// support the U2F protocol as FidoDiscovery selects only devices that support
// either the U2F or CTAP protocols during discovery. Therefore |u2f_callback|
// is invoked, which sends APDU encoded request to authenticator.
void GetAuthenticatorInfo(base::OnceClosure ctap_callback,
base::OnceClosure u2f_callback);

FidoDevice* device() const {
DCHECK(device_);
return device_;
}

private:
void OnAuthenticatorInfoReceived(
base::OnceClosure ctap_callback,
base::OnceClosure u2f_callback,
base::Optional<std::vector<uint8_t>> response);

FidoDevice* const device_;
base::WeakPtrFactory<FidoTask> weak_factory_;

DISALLOW_COPY_AND_ASSIGN(FidoTask);
};

} // namespace device

#endif // DEVICE_FIDO_FIDO_TASK_H_
61 changes: 61 additions & 0 deletions device/fido/make_credential_task.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "device/fido/make_credential_task.h"

#include <utility>

#include "base/bind.h"
#include "device/fido/ctap_empty_authenticator_request.h"
#include "device/fido/device_response_converter.h"

namespace device {

MakeCredentialTask::MakeCredentialTask(
FidoDevice* device,
CtapMakeCredentialRequest request_parameter,
MakeCredentialTaskCallback callback)
: FidoTask(device),
request_parameter_(std::move(request_parameter)),
callback_(std::move(callback)),
weak_factory_(this) {}

MakeCredentialTask::~MakeCredentialTask() = default;

void MakeCredentialTask::StartTask() {
GetAuthenticatorInfo(base::BindOnce(&MakeCredentialTask::MakeCredential,
weak_factory_.GetWeakPtr()),
base::BindOnce(&MakeCredentialTask::U2fRegister,
weak_factory_.GetWeakPtr()));
}

void MakeCredentialTask::MakeCredential() {
device()->DeviceTransact(
request_parameter_.EncodeAsCBOR(),
base::BindOnce(&MakeCredentialTask::OnCtapMakeCredentialResponseReceived,
weak_factory_.GetWeakPtr()));
}

void MakeCredentialTask::U2fRegister() {
// TODO(hongjunchoi): Implement U2F register request logic to support
// interoperability with U2F protocol. Currently all U2F devices are not
// supported and request to U2F devices will be silently dropped.
// See: https://crbug.com/798573
std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther,
base::nullopt);
}

void MakeCredentialTask::OnCtapMakeCredentialResponseReceived(
base::Optional<std::vector<uint8_t>> device_response) {
if (!device_response) {
std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther,
base::nullopt);
return;
}

std::move(callback_).Run(GetResponseCode(*device_response),
ReadCTAPMakeCredentialResponse(*device_response));
}

} // namespace device
Loading

0 comments on commit f15afe4

Please sign in to comment.