| // Copyright 2017 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/u2f_device.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "device/fido/u2f_apdu_command.h" |
| #include "device/fido/u2f_apdu_response.h" |
| |
| namespace device { |
| |
| constexpr base::TimeDelta U2fDevice::kDeviceTimeout; |
| |
| U2fDevice::U2fDevice() = default; |
| |
| U2fDevice::~U2fDevice() = default; |
| |
| void U2fDevice::Register(const std::vector<uint8_t>& application_parameter, |
| const std::vector<uint8_t>& challenge_param, |
| bool individual_attestation_ok, |
| MessageCallback callback) { |
| auto register_cmd = U2fApduCommand::CreateRegister( |
| application_parameter, challenge_param, individual_attestation_ok); |
| if (!register_cmd) { |
| std::move(callback).Run(U2fReturnCode::INVALID_PARAMS, |
| std::vector<uint8_t>()); |
| return; |
| } |
| DeviceTransact(register_cmd->GetEncodedCommand(), |
| base::BindOnce(&U2fDevice::OnRegisterComplete, GetWeakPtr(), |
| std::move(callback))); |
| } |
| |
| void U2fDevice::Sign(const std::vector<uint8_t>& application_parameter, |
| const std::vector<uint8_t>& challenge_param, |
| const std::vector<uint8_t>& key_handle, |
| MessageCallback callback, |
| bool check_only) { |
| auto sign_cmd = U2fApduCommand::CreateSign( |
| application_parameter, challenge_param, key_handle, check_only); |
| if (!sign_cmd) { |
| std::move(callback).Run(U2fReturnCode::INVALID_PARAMS, |
| std::vector<uint8_t>()); |
| return; |
| } |
| DeviceTransact(sign_cmd->GetEncodedCommand(), |
| base::BindOnce(&U2fDevice::OnSignComplete, GetWeakPtr(), |
| std::move(callback))); |
| } |
| |
| void U2fDevice::Version(VersionCallback callback) { |
| auto version_cmd = U2fApduCommand::CreateVersion(); |
| if (!version_cmd) { |
| std::move(callback).Run(false, ProtocolVersion::UNKNOWN); |
| return; |
| } |
| DeviceTransact(version_cmd->GetEncodedCommand(), |
| base::BindOnce(&U2fDevice::OnVersionComplete, GetWeakPtr(), |
| std::move(callback), false /* legacy */)); |
| } |
| |
| void U2fDevice::OnRegisterComplete( |
| MessageCallback callback, |
| bool success, |
| std::unique_ptr<U2fApduResponse> register_response) { |
| if (!success || !register_response) { |
| std::move(callback).Run(U2fReturnCode::FAILURE, std::vector<uint8_t>()); |
| return; |
| } |
| switch (register_response->status()) { |
| case U2fApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED: |
| std::move(callback).Run(U2fReturnCode::CONDITIONS_NOT_SATISFIED, |
| std::vector<uint8_t>()); |
| break; |
| case U2fApduResponse::Status::SW_NO_ERROR: |
| std::move(callback).Run(U2fReturnCode::SUCCESS, |
| register_response->data()); |
| break; |
| case U2fApduResponse::Status::SW_WRONG_DATA: |
| std::move(callback).Run(U2fReturnCode::INVALID_PARAMS, |
| std::vector<uint8_t>()); |
| break; |
| default: |
| std::move(callback).Run(U2fReturnCode::FAILURE, std::vector<uint8_t>()); |
| break; |
| } |
| } |
| |
| void U2fDevice::OnSignComplete(MessageCallback callback, |
| bool success, |
| std::unique_ptr<U2fApduResponse> sign_response) { |
| if (!success || !sign_response) { |
| std::move(callback).Run(U2fReturnCode::FAILURE, std::vector<uint8_t>()); |
| return; |
| } |
| switch (sign_response->status()) { |
| case U2fApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED: |
| std::move(callback).Run(U2fReturnCode::CONDITIONS_NOT_SATISFIED, |
| std::vector<uint8_t>()); |
| break; |
| case U2fApduResponse::Status::SW_NO_ERROR: |
| std::move(callback).Run(U2fReturnCode::SUCCESS, sign_response->data()); |
| break; |
| case U2fApduResponse::Status::SW_WRONG_DATA: |
| case U2fApduResponse::Status::SW_WRONG_LENGTH: |
| default: |
| std::move(callback).Run(U2fReturnCode::INVALID_PARAMS, |
| std::vector<uint8_t>()); |
| break; |
| } |
| } |
| |
| void U2fDevice::OnVersionComplete( |
| VersionCallback callback, |
| bool legacy, |
| bool success, |
| std::unique_ptr<U2fApduResponse> version_response) { |
| if (success && version_response && |
| version_response->status() == U2fApduResponse::Status::SW_NO_ERROR && |
| version_response->data() == |
| std::vector<uint8_t>({'U', '2', 'F', '_', 'V', '2'})) { |
| std::move(callback).Run(success, ProtocolVersion::U2F_V2); |
| } else if (!legacy) { |
| // Standard GetVersion failed, attempt legacy GetVersion command |
| auto version_cmd = U2fApduCommand::CreateLegacyVersion(); |
| if (!version_cmd) { |
| std::move(callback).Run(false, ProtocolVersion::UNKNOWN); |
| } else { |
| DeviceTransact(version_cmd->GetEncodedCommand(), |
| base::BindOnce(&U2fDevice::OnVersionComplete, GetWeakPtr(), |
| std::move(callback), true /* legacy */)); |
| } |
| } else { |
| std::move(callback).Run(success, ProtocolVersion::UNKNOWN); |
| } |
| } |
| |
| } // namespace device |