blob: 586c1200efc213259164f70700db62efe931acc5 [file] [log] [blame]
// Copyright 2017 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/fido_parsing_utils.h"
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
namespace device::fido_parsing_utils {
namespace {
constexpr bool AreSpansDisjoint(base::span<const uint8_t> lhs,
base::span<const uint8_t> rhs) {
return UNSAFE_TODO(lhs.data() + lhs.size()) <= rhs.data() || // [lhs)...[rhs)
UNSAFE_TODO(rhs.data() + rhs.size()) <= lhs.data(); // [rhs)...[lhs)
}
// Redacts `path` from `cbor` using the semantics described for `RedactCbor`.
// Mutates `cbor` in place.
void RedactPath(cbor::Value* cbor, base::span<const cbor::Value> path) {
if (cbor->is_array()) {
// Mutate all the elements in the array.
cbor::Value::ArrayValue& array =
const_cast<cbor::Value::ArrayValue&>(cbor->GetArray());
for (cbor::Value& value : array) {
RedactPath(&value, path);
}
return;
}
if (!cbor->is_map()) {
// Only maps and arrays are supported.
return;
}
cbor::Value::MapValue& map =
const_cast<cbor::Value::MapValue&>(cbor->GetMap());
base::span<const cbor::Value> field = path.take_first<1>();
const auto it = map.find(field.front());
if (it == map.end()) {
// Could not find some part of the path, bail out.
return;
}
if (path.empty()) {
// Found the leaf, replace the map value regardless of its type.
it->second = cbor::Value("[redacted]");
return;
}
RedactPath(&it->second, path);
}
} // namespace
std::vector<uint8_t> Materialize(base::span<const uint8_t> span) {
return std::vector<uint8_t>(span.begin(), span.end());
}
std::optional<std::vector<uint8_t>> MaterializeOrNull(
std::optional<base::span<const uint8_t>> span) {
if (span)
return Materialize(*span);
return std::nullopt;
}
void Append(std::vector<uint8_t>* target, base::span<const uint8_t> in_values) {
CHECK(AreSpansDisjoint(*target, in_values));
target->insert(target->end(), in_values.begin(), in_values.end());
}
std::vector<uint8_t> Extract(base::span<const uint8_t> span,
size_t pos,
size_t length) {
return Materialize(ExtractSpan(span, pos, length));
}
base::span<const uint8_t> ExtractSpan(base::span<const uint8_t> span,
size_t pos,
size_t length) {
if (!(pos <= span.size() && length <= span.size() - pos))
return base::span<const uint8_t>();
return span.subspan(pos, length);
}
std::vector<uint8_t> ExtractSuffix(base::span<const uint8_t> span, size_t pos) {
return Materialize(ExtractSuffixSpan(span, pos));
}
base::span<const uint8_t> ExtractSuffixSpan(base::span<const uint8_t> span,
size_t pos) {
return span.subspan(std::min(pos, span.size()));
}
std::vector<base::span<const uint8_t>> SplitSpan(base::span<const uint8_t> span,
size_t max_chunk_size) {
DCHECK_NE(0u, max_chunk_size);
std::vector<base::span<const uint8_t>> chunks;
const size_t num_chunks = (span.size() + max_chunk_size - 1) / max_chunk_size;
chunks.reserve(num_chunks);
while (!span.empty()) {
const size_t chunk_size = std::min(span.size(), max_chunk_size);
chunks.emplace_back(span.first(chunk_size));
span = span.subspan(chunk_size);
}
return chunks;
}
std::string ConvertBytesToUuid(base::span<const uint8_t, 16> bytes) {
uint64_t most_significant_bytes = 0;
for (size_t i = 0; i < sizeof(uint64_t); i++) {
most_significant_bytes |= base::strict_cast<uint64_t>(bytes[i])
<< 8 * (7 - i);
}
uint64_t least_significant_bytes = 0;
for (size_t i = 0; i < sizeof(uint64_t); i++) {
least_significant_bytes |= base::strict_cast<uint64_t>(bytes[i + 8])
<< 8 * (7 - i);
}
return base::StringPrintf(
"%08x-%04x-%04x-%04x-%012llx",
static_cast<unsigned int>(most_significant_bytes >> 32),
static_cast<unsigned int>((most_significant_bytes >> 16) & 0x0000ffff),
static_cast<unsigned int>(most_significant_bytes & 0x0000ffff),
static_cast<unsigned int>(least_significant_bytes >> 48),
least_significant_bytes & 0x0000ffff'ffffffffULL);
}
cbor::Value RedactCbor(
const cbor::Value& cbor,
base::span<const std::vector<cbor::Value>> paths_to_redact) {
cbor::Value response = cbor.Clone();
for (base::span<const cbor::Value> field_to_redact : paths_to_redact) {
RedactPath(&response, field_to_redact);
}
return response;
}
} // namespace device::fido_parsing_utils