123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "device/fido/cbor_extract.h"
- #include <type_traits>
- #include "base/callback.h"
- #include "base/check_op.h"
- #include "components/cbor/values.h"
- namespace device {
- namespace cbor_extract {
- namespace {
- using internal::Type;
- static_assert(sizeof(StepOrByte<void>) == 1,
- "things should fit into a single byte");
- const bool kTrue = true;
- const bool kFalse = false;
- constexpr uint8_t CBORTypeToBitfield(const cbor::Value::Type type) {
- const unsigned type_u = static_cast<unsigned>(type);
- if (type_u >= 8) {
- __builtin_unreachable();
- }
- return 1u << type_u;
- }
- // ASSERT_TYPE_IS asserts that the type of |a| is |b|. This is used to ensure
- // that the documented output types for elements of |Type| are correct.
- #define ASSERT_TYPE_IS(a, b) \
- static_assert( \
- std::is_same<decltype(&a), decltype(reinterpret_cast<b*>(0))>::value, \
- "types need updating");
- class Extractor {
- public:
- Extractor(base::span<const void*> outputs,
- base::span<const StepOrByte<void>> steps)
- : outputs_(outputs), steps_(steps) {}
- bool ValuesFromMap(const cbor::Value::MapValue& map) {
- for (;;) {
- const internal::Step step = steps_[step_i_++].step;
- const Type value_type = static_cast<Type>(step.value_type);
- if (value_type == Type::kStop) {
- return true;
- }
- const cbor::Value::MapValue::const_iterator map_it = map.find(NextKey());
- const void** output = nullptr;
- if (value_type != Type::kMap) {
- DCHECK_LT(step.output_index, outputs_.size());
- output = &outputs_[step.output_index];
- }
- if (map_it == map.end()) {
- if (step.required) {
- return false;
- }
- if (output) {
- *output = nullptr;
- }
- if (value_type == Type::kMap) {
- // When skipping an optional map, all the |StepOrByte| for the
- // elements of the map need to be skipped over.
- SeekPastNextStop();
- }
- continue;
- }
- // kExpectedCBORTypes is an array of bitmaps of acceptable types for each
- // |Type|.
- static constexpr uint8_t kExpectedCBORTypes[] = {
- // kBytestring
- CBORTypeToBitfield(cbor::Value::Type::BYTE_STRING),
- // kString
- CBORTypeToBitfield(cbor::Value::Type::STRING),
- // kBoolean
- CBORTypeToBitfield(cbor::Value::Type::SIMPLE_VALUE),
- // kInt
- CBORTypeToBitfield(cbor::Value::Type::NEGATIVE) |
- CBORTypeToBitfield(cbor::Value::Type::UNSIGNED),
- // kMap
- CBORTypeToBitfield(cbor::Value::Type::MAP),
- // kArray
- CBORTypeToBitfield(cbor::Value::Type::ARRAY),
- // kValue
- 0xff,
- };
- const cbor::Value& value = map_it->second;
- const unsigned cbor_type_u = static_cast<unsigned>(value.type());
- const unsigned value_type_u = static_cast<unsigned>(value_type);
- DCHECK(value_type_u < std::size(kExpectedCBORTypes));
- if (cbor_type_u >= 8 ||
- (kExpectedCBORTypes[value_type_u] & (1u << cbor_type_u)) == 0) {
- return false;
- }
- switch (value_type) {
- case Type::kBytestring:
- ASSERT_TYPE_IS(value.GetBytestring(), const std::vector<uint8_t>);
- *output = &value.GetBytestring();
- break;
- case Type::kString:
- ASSERT_TYPE_IS(value.GetString(), const std::string);
- *output = &value.GetString();
- break;
- case Type::kBoolean:
- switch (value.GetSimpleValue()) {
- case cbor::Value::SimpleValue::TRUE_VALUE:
- *output = &kTrue;
- break;
- case cbor::Value::SimpleValue::FALSE_VALUE:
- *output = &kFalse;
- break;
- default:
- return false;
- }
- break;
- case Type::kInt:
- ASSERT_TYPE_IS(value.GetInteger(), const int64_t);
- *output = &value.GetInteger();
- break;
- case Type::kMap:
- if (!ValuesFromMap(value.GetMap())) {
- return false;
- }
- break;
- case Type::kArray:
- ASSERT_TYPE_IS(value.GetArray(), const std::vector<cbor::Value>);
- *output = &value.GetArray();
- break;
- case Type::kValue:
- *output = &value;
- break;
- case Type::kStop:
- return false;
- }
- }
- }
- private:
- // SeekPastNextStop increments |step_i_| until just after the next |Stop|
- // element, taking into account nested maps.
- void SeekPastNextStop() {
- for (;;) {
- const internal::Step step = steps_[step_i_++].step;
- const Type value_type = static_cast<Type>(step.value_type);
- if (value_type == Type::kStop) {
- break;
- }
- NextKey();
- if (value_type == Type::kMap) {
- SeekPastNextStop();
- } else {
- outputs_[step.output_index] = nullptr;
- }
- }
- }
- cbor::Value NextKey() {
- DCHECK_LT(step_i_, steps_.size());
- const uint8_t key_or_string_indicator = steps_[step_i_++].u8;
- if (key_or_string_indicator != StepOrByte<void>::STRING_KEY) {
- return cbor::Value(
- static_cast<int64_t>(static_cast<int8_t>(key_or_string_indicator)));
- }
- DCHECK_LT(step_i_, steps_.size());
- std::string key(&steps_[step_i_].c);
- step_i_ += key.size() + 1;
- DCHECK_LE(step_i_, steps_.size());
- return cbor::Value(std::move(key));
- }
- base::span<const void*> outputs_;
- base::span<const StepOrByte<void>> steps_;
- size_t step_i_ = 0;
- };
- } // namespace
- namespace internal {
- bool Extract(base::span<const void*> outputs,
- base::span<const StepOrByte<void>> steps,
- const cbor::Value::MapValue& map) {
- DCHECK(steps[steps.size() - 1].step.value_type ==
- static_cast<uint8_t>(Type::kStop));
- Extractor extractor(outputs, steps);
- return extractor.ValuesFromMap(map);
- }
- } // namespace internal
- bool ForEachPublicKeyEntry(
- const cbor::Value::ArrayValue& array,
- const cbor::Value& key,
- base::RepeatingCallback<bool(const cbor::Value&)> callback) {
- const cbor::Value type_key("type");
- const std::string public_key("public-key");
- for (const cbor::Value& value : array) {
- if (!value.is_map()) {
- return false;
- }
- const cbor::Value::MapValue& map = value.GetMap();
- const auto type_it = map.find(type_key);
- if (type_it == map.end() || !type_it->second.is_string()) {
- return false;
- }
- if (type_it->second.GetString() != public_key) {
- continue;
- }
- const auto value_it = map.find(key);
- if (value_it == map.end() || !callback.Run(value_it->second)) {
- return false;
- }
- }
- return true;
- }
- } // namespace cbor_extract
- } // namespace device
|