blob: 733d99cfeb81f4f11c42faa1ab1f153a48d805aa [file] [log] [blame]
// 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/u2f_command_constructor.h"
#include <string>
#include <utility>
#include "components/apdu/apdu_command.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
namespace device {
bool IsConvertibleToU2fRegisterCommand(
const CtapMakeCredentialRequest& request) {
if (request.user_verification() == UserVerificationRequirement::kRequired ||
request.resident_key_required())
return false;
const auto& public_key_credential_info =
request.public_key_credential_params().public_key_credential_params();
return std::any_of(
public_key_credential_info.begin(), public_key_credential_info.end(),
[](const auto& credential_info) {
return credential_info.algorithm ==
base::strict_cast<int>(CoseAlgorithmIdentifier::kCoseEs256);
});
}
bool IsConvertibleToU2fSignCommand(const CtapGetAssertionRequest& request) {
const auto& allow_list = request.allow_list();
return request.user_verification() !=
UserVerificationRequirement::kRequired &&
allow_list && !allow_list->empty();
}
base::Optional<std::vector<uint8_t>> ConvertToU2fRegisterCommand(
const CtapMakeCredentialRequest& request) {
if (!IsConvertibleToU2fRegisterCommand(request))
return base::nullopt;
return ConstructU2fRegisterCommand(
fido_parsing_utils::CreateSHA256Hash(request.rp().rp_id()),
request.client_data_hash(), request.is_individual_attestation());
}
base::Optional<std::vector<uint8_t>> ConvertToU2fCheckOnlySignCommand(
const CtapMakeCredentialRequest& request,
const PublicKeyCredentialDescriptor& key_handle) {
if (key_handle.credential_type() != CredentialType::kPublicKey)
return base::nullopt;
return ConstructU2fSignCommand(
fido_parsing_utils::CreateSHA256Hash(request.rp().rp_id()),
request.client_data_hash(), key_handle.id(), true /* check_only */);
}
base::Optional<std::vector<uint8_t>> ConvertToU2fSignCommand(
const CtapGetAssertionRequest& request,
ApplicationParameterType application_parameter_type,
base::span<const uint8_t> key_handle,
bool check_only) {
if (!IsConvertibleToU2fSignCommand(request))
return base::nullopt;
const auto& application_parameter =
application_parameter_type == ApplicationParameterType::kPrimary
? fido_parsing_utils::CreateSHA256Hash(request.rp_id())
: request.alternative_application_parameter().value_or(
std::array<uint8_t, kRpIdHashLength>());
return ConstructU2fSignCommand(application_parameter,
request.client_data_hash(), key_handle,
check_only);
}
std::vector<uint8_t> ConstructU2fRegisterCommand(
base::span<const uint8_t, kU2fApplicationParamLength> application_parameter,
base::span<const uint8_t, kU2fChallengeParamLength> challenge_parameter,
bool is_individual_attestation) {
std::vector<uint8_t> data;
data.reserve(kU2fChallengeParamLength + kU2fApplicationParamLength);
fido_parsing_utils::Append(&data, challenge_parameter);
fido_parsing_utils::Append(&data, application_parameter);
apdu::ApduCommand command;
command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kRegister));
command.set_p1(kP1TupRequiredConsumed |
(is_individual_attestation ? kP1IndividualAttestation : 0));
command.set_data(std::move(data));
command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
return command.GetEncodedCommand();
}
base::Optional<std::vector<uint8_t>> ConstructU2fSignCommand(
base::span<const uint8_t, kU2fApplicationParamLength> application_parameter,
base::span<const uint8_t, kU2fChallengeParamLength> challenge_parameter,
base::span<const uint8_t> key_handle,
bool check_only) {
if (key_handle.size() > kMaxKeyHandleLength) {
return base::nullopt;
}
std::vector<uint8_t> data;
data.reserve(kU2fChallengeParamLength + kU2fApplicationParamLength + 1 +
key_handle.size());
fido_parsing_utils::Append(&data, challenge_parameter);
fido_parsing_utils::Append(&data, application_parameter);
data.push_back(static_cast<uint8_t>(key_handle.size()));
fido_parsing_utils::Append(&data, key_handle);
apdu::ApduCommand command;
command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kSign));
command.set_p1(check_only ? kP1CheckOnly : kP1TupRequiredConsumed);
command.set_data(std::move(data));
command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
return command.GetEncodedCommand();
}
std::vector<uint8_t> ConstructBogusU2fRegistrationCommand() {
return ConstructU2fRegisterCommand(kBogusAppParam, kBogusChallenge);
}
} // namespace device