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