1 // Copyright 2017 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
5 #include "device/fido/authenticator_data.h"
6
7 #include <utility>
8
9 #include "base/strings/string_number_conversions.h"
10 #include "components/cbor/diagnostic_writer.h"
11 #include "components/cbor/reader.h"
12 #include "components/cbor/writer.h"
13 #include "components/device_event_log/device_event_log.h"
14 #include "device/fido/attested_credential_data.h"
15 #include "device/fido/fido_parsing_utils.h"
16
17 namespace device {
18
19 namespace {
20
21 constexpr size_t kAttestedCredentialDataOffset =
22 kRpIdHashLength + kFlagsLength + kSignCounterLength;
23
24 } // namespace
25
26 // static
DecodeAuthenticatorData(base::span<const uint8_t> auth_data)27 base::Optional<AuthenticatorData> AuthenticatorData::DecodeAuthenticatorData(
28 base::span<const uint8_t> auth_data) {
29 if (auth_data.size() < kAttestedCredentialDataOffset)
30 return base::nullopt;
31 auto application_parameter = auth_data.first<kRpIdHashLength>();
32 uint8_t flag_byte = auth_data[kRpIdHashLength];
33 auto counter =
34 auth_data.subspan<kRpIdHashLength + kFlagsLength, kSignCounterLength>();
35
36 auth_data = auth_data.subspan(kAttestedCredentialDataOffset);
37 base::Optional<AttestedCredentialData> attested_credential_data;
38 if (flag_byte & static_cast<uint8_t>(Flag::kAttestation)) {
39 auto maybe_result =
40 AttestedCredentialData::ConsumeFromCtapResponse(auth_data);
41 if (!maybe_result) {
42 return base::nullopt;
43 }
44 std::tie(attested_credential_data, auth_data) = std::move(*maybe_result);
45 }
46
47 base::Optional<cbor::Value> extensions;
48 if (flag_byte & static_cast<uint8_t>(Flag::kExtensionDataIncluded)) {
49 cbor::Reader::DecoderError error;
50 extensions = cbor::Reader::Read(auth_data, &error);
51 if (!extensions) {
52 FIDO_LOG(ERROR)
53 << "CBOR decoding of authenticator data extensions failed ("
54 << cbor::Reader::ErrorCodeToString(error) << ") from "
55 << base::HexEncode(auth_data.data(), auth_data.size());
56 return base::nullopt;
57 }
58 if (!extensions->is_map()) {
59 FIDO_LOG(ERROR)
60 << "Incorrect CBOR structure of authenticator data extensions: "
61 << cbor::DiagnosticWriter::Write(*extensions);
62 return base::nullopt;
63 }
64 } else if (!auth_data.empty()) {
65 return base::nullopt;
66 }
67
68 return AuthenticatorData(application_parameter, flag_byte, counter,
69 std::move(attested_credential_data),
70 std::move(extensions));
71 }
72
AuthenticatorData(base::span<const uint8_t,kRpIdHashLength> application_parameter,uint8_t flags,base::span<const uint8_t,kSignCounterLength> counter,base::Optional<AttestedCredentialData> data,base::Optional<cbor::Value> extensions)73 AuthenticatorData::AuthenticatorData(
74 base::span<const uint8_t, kRpIdHashLength> application_parameter,
75 uint8_t flags,
76 base::span<const uint8_t, kSignCounterLength> counter,
77 base::Optional<AttestedCredentialData> data,
78 base::Optional<cbor::Value> extensions)
79 : application_parameter_(
80 fido_parsing_utils::Materialize(application_parameter)),
81 flags_(flags),
82 counter_(fido_parsing_utils::Materialize(counter)),
83 attested_data_(std::move(data)),
84 extensions_(std::move(extensions)) {
85 DCHECK(!extensions_ || extensions_->is_map());
86 DCHECK_EQ((flags_ & static_cast<uint8_t>(Flag::kExtensionDataIncluded)) != 0,
87 !!extensions_);
88 DCHECK_EQ(((flags_ & static_cast<uint8_t>(Flag::kAttestation)) != 0),
89 !!attested_data_);
90 }
91
92 AuthenticatorData::AuthenticatorData(AuthenticatorData&& other) = default;
93 AuthenticatorData& AuthenticatorData::operator=(AuthenticatorData&& other) =
94 default;
95
96 AuthenticatorData::~AuthenticatorData() = default;
97
DeleteDeviceAaguid()98 void AuthenticatorData::DeleteDeviceAaguid() {
99 if (!attested_data_)
100 return;
101
102 attested_data_->DeleteAaguid();
103 }
104
SerializeToByteArray() const105 std::vector<uint8_t> AuthenticatorData::SerializeToByteArray() const {
106 std::vector<uint8_t> authenticator_data;
107 fido_parsing_utils::Append(&authenticator_data, application_parameter_);
108 authenticator_data.insert(authenticator_data.end(), flags_);
109 fido_parsing_utils::Append(&authenticator_data, counter_);
110
111 if (attested_data_) {
112 // Attestations are returned in registration responses but not in assertion
113 // responses.
114 fido_parsing_utils::Append(&authenticator_data,
115 attested_data_->SerializeAsBytes());
116 }
117
118 if (extensions_) {
119 const auto maybe_extensions = cbor::Writer::Write(*extensions_);
120 if (maybe_extensions) {
121 fido_parsing_utils::Append(&authenticator_data, *maybe_extensions);
122 }
123 }
124
125 return authenticator_data;
126 }
127
GetCredentialId() const128 std::vector<uint8_t> AuthenticatorData::GetCredentialId() const {
129 if (!attested_data_)
130 return std::vector<uint8_t>();
131
132 return attested_data_->credential_id();
133 }
134
135 } // namespace device
136