u2f_command_constructor.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/fido/u2f_command_constructor.h"
  5. #include <string>
  6. #include <utility>
  7. #include "components/apdu/apdu_command.h"
  8. #include "device/fido/fido_constants.h"
  9. #include "device/fido/fido_parsing_utils.h"
  10. namespace device {
  11. bool IsConvertibleToU2fRegisterCommand(
  12. const CtapMakeCredentialRequest& request) {
  13. if (request.user_verification == UserVerificationRequirement::kRequired ||
  14. request.resident_key_required)
  15. return false;
  16. const auto& public_key_credential_info =
  17. request.public_key_credential_params.public_key_credential_params();
  18. return std::any_of(
  19. public_key_credential_info.begin(), public_key_credential_info.end(),
  20. [](const auto& credential_info) {
  21. return credential_info.algorithm ==
  22. base::strict_cast<int>(CoseAlgorithmIdentifier::kEs256);
  23. });
  24. }
  25. bool ShouldPreferCTAP2EvenIfItNeedsAPIN(
  26. const CtapMakeCredentialRequest& request) {
  27. return request.hmac_secret ||
  28. // U2F devices can only support |kEnterpriseApprovedByBrowser| so
  29. // |kEnterpriseIfRPListedOnAuthenticator| should go over CTAP2.
  30. request.attestation_preference ==
  31. AttestationConveyancePreference::
  32. kEnterpriseIfRPListedOnAuthenticator;
  33. }
  34. bool IsConvertibleToU2fSignCommand(const CtapGetAssertionRequest& request) {
  35. return request.user_verification != UserVerificationRequirement::kRequired &&
  36. !request.allow_list.empty();
  37. }
  38. absl::optional<std::vector<uint8_t>> ConvertToU2fRegisterCommand(
  39. const CtapMakeCredentialRequest& request) {
  40. if (!IsConvertibleToU2fRegisterCommand(request))
  41. return absl::nullopt;
  42. if (request.pin_auth && request.pin_auth->size() == 0) {
  43. // An empty pin_auth in CTAP2 indicates that the device should just wait
  44. // for a touch.
  45. return ConstructBogusU2fRegistrationCommand();
  46. }
  47. const bool is_individual_attestation =
  48. request.attestation_preference ==
  49. AttestationConveyancePreference::kEnterpriseApprovedByBrowser;
  50. return ConstructU2fRegisterCommand(
  51. fido_parsing_utils::CreateSHA256Hash(request.rp.id),
  52. request.client_data_hash, is_individual_attestation);
  53. }
  54. absl::optional<std::vector<uint8_t>> ConvertToU2fSignCommandWithBogusChallenge(
  55. const CtapMakeCredentialRequest& request,
  56. base::span<const uint8_t> key_handle) {
  57. return ConstructU2fSignCommand(
  58. fido_parsing_utils::CreateSHA256Hash(request.rp.id),
  59. kBogusChallenge, key_handle);
  60. }
  61. absl::optional<std::vector<uint8_t>> ConvertToU2fSignCommand(
  62. const CtapGetAssertionRequest& request,
  63. ApplicationParameterType application_parameter_type,
  64. base::span<const uint8_t> key_handle) {
  65. if (!IsConvertibleToU2fSignCommand(request))
  66. return absl::nullopt;
  67. const auto& application_parameter =
  68. application_parameter_type == ApplicationParameterType::kPrimary
  69. ? fido_parsing_utils::CreateSHA256Hash(request.rp_id)
  70. : request.alternative_application_parameter.value_or(
  71. std::array<uint8_t, kRpIdHashLength>());
  72. return ConstructU2fSignCommand(application_parameter,
  73. request.client_data_hash, key_handle);
  74. }
  75. std::vector<uint8_t> ConstructU2fRegisterCommand(
  76. base::span<const uint8_t, kU2fApplicationParamLength> application_parameter,
  77. base::span<const uint8_t, kU2fChallengeParamLength> challenge_parameter,
  78. bool is_individual_attestation) {
  79. std::vector<uint8_t> data;
  80. data.reserve(kU2fChallengeParamLength + kU2fApplicationParamLength);
  81. fido_parsing_utils::Append(&data, challenge_parameter);
  82. fido_parsing_utils::Append(&data, application_parameter);
  83. apdu::ApduCommand command;
  84. command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kRegister));
  85. command.set_p1(kP1TupRequiredConsumed |
  86. (is_individual_attestation ? kP1IndividualAttestation : 0));
  87. command.set_data(std::move(data));
  88. command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
  89. return command.GetEncodedCommand();
  90. }
  91. absl::optional<std::vector<uint8_t>> ConstructU2fSignCommand(
  92. base::span<const uint8_t, kU2fApplicationParamLength> application_parameter,
  93. base::span<const uint8_t, kU2fChallengeParamLength> challenge_parameter,
  94. base::span<const uint8_t> key_handle) {
  95. if (key_handle.size() > kMaxKeyHandleLength) {
  96. return absl::nullopt;
  97. }
  98. std::vector<uint8_t> data;
  99. data.reserve(kU2fChallengeParamLength + kU2fApplicationParamLength + 1 +
  100. key_handle.size());
  101. fido_parsing_utils::Append(&data, challenge_parameter);
  102. fido_parsing_utils::Append(&data, application_parameter);
  103. data.push_back(static_cast<uint8_t>(key_handle.size()));
  104. fido_parsing_utils::Append(&data, key_handle);
  105. apdu::ApduCommand command;
  106. command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kSign));
  107. command.set_p1(kP1TupRequiredConsumed);
  108. command.set_data(std::move(data));
  109. command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
  110. return command.GetEncodedCommand();
  111. }
  112. std::vector<uint8_t> ConstructBogusU2fRegistrationCommand() {
  113. return ConstructU2fRegisterCommand(kBogusAppParam, kBogusChallenge);
  114. }
  115. } // namespace device