| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "device/fido/authenticator_get_assertion_response.h" |
| |
| #include <utility> |
| |
| #include "components/cbor/values.h" |
| #include "components/cbor/writer.h" |
| #include "components/device_event_log/device_event_log.h" |
| #include "device/fido/authenticator_data.h" |
| #include "device/fido/fido_parsing_utils.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "third_party/boringssl/src/include/openssl/ecdsa.h" |
| |
| namespace device { |
| |
| namespace { |
| |
| constexpr size_t kFlagIndex = 0; |
| constexpr size_t kFlagLength = 1; |
| constexpr size_t kCounterIndex = 1; |
| constexpr size_t kCounterLength = 4; |
| constexpr size_t kSignatureIndex = 5; |
| |
| } // namespace |
| |
| // static |
| absl::optional<AuthenticatorGetAssertionResponse> |
| AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse( |
| base::span<const uint8_t, kRpIdHashLength> relying_party_id_hash, |
| base::span<const uint8_t> u2f_data, |
| base::span<const uint8_t> key_handle) { |
| if (u2f_data.size() <= kSignatureIndex) |
| return absl::nullopt; |
| |
| if (key_handle.empty()) |
| return absl::nullopt; |
| |
| auto flags = u2f_data.subspan<kFlagIndex, kFlagLength>()[0]; |
| if (flags & |
| (static_cast<uint8_t>(AuthenticatorData::Flag::kExtensionDataIncluded) | |
| static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation))) { |
| // U2F responses cannot assert CTAP2 features. |
| return absl::nullopt; |
| } |
| auto counter = u2f_data.subspan<kCounterIndex, kCounterLength>(); |
| AuthenticatorData authenticator_data(relying_party_id_hash, flags, counter, |
| absl::nullopt); |
| |
| auto signature = |
| fido_parsing_utils::Materialize(u2f_data.subspan(kSignatureIndex)); |
| |
| bssl::UniquePtr<ECDSA_SIG> parsed_sig( |
| ECDSA_SIG_from_bytes(signature.data(), signature.size())); |
| if (!parsed_sig) { |
| FIDO_LOG(ERROR) |
| << "Rejecting U2F assertion response with invalid signature"; |
| return absl::nullopt; |
| } |
| |
| AuthenticatorGetAssertionResponse response(std::move(authenticator_data), |
| std::move(signature)); |
| response.credential = PublicKeyCredentialDescriptor( |
| CredentialType::kPublicKey, fido_parsing_utils::Materialize(key_handle)); |
| return std::move(response); |
| } |
| |
| AuthenticatorGetAssertionResponse::AuthenticatorGetAssertionResponse( |
| AuthenticatorData authenticator_data, |
| std::vector<uint8_t> signature) |
| : authenticator_data(std::move(authenticator_data)), |
| signature(std::move(signature)) {} |
| |
| AuthenticatorGetAssertionResponse::AuthenticatorGetAssertionResponse( |
| AuthenticatorGetAssertionResponse&& that) = default; |
| |
| AuthenticatorGetAssertionResponse& AuthenticatorGetAssertionResponse::operator=( |
| AuthenticatorGetAssertionResponse&& other) = default; |
| |
| AuthenticatorGetAssertionResponse::~AuthenticatorGetAssertionResponse() = |
| default; |
| |
| } // namespace device |