cbor_extract.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2020 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. #include "device/fido/cbor_extract.h"
  5. #include <type_traits>
  6. #include "base/callback.h"
  7. #include "base/check_op.h"
  8. #include "components/cbor/values.h"
  9. namespace device {
  10. namespace cbor_extract {
  11. namespace {
  12. using internal::Type;
  13. static_assert(sizeof(StepOrByte<void>) == 1,
  14. "things should fit into a single byte");
  15. const bool kTrue = true;
  16. const bool kFalse = false;
  17. constexpr uint8_t CBORTypeToBitfield(const cbor::Value::Type type) {
  18. const unsigned type_u = static_cast<unsigned>(type);
  19. if (type_u >= 8) {
  20. __builtin_unreachable();
  21. }
  22. return 1u << type_u;
  23. }
  24. // ASSERT_TYPE_IS asserts that the type of |a| is |b|. This is used to ensure
  25. // that the documented output types for elements of |Type| are correct.
  26. #define ASSERT_TYPE_IS(a, b) \
  27. static_assert( \
  28. std::is_same<decltype(&a), decltype(reinterpret_cast<b*>(0))>::value, \
  29. "types need updating");
  30. class Extractor {
  31. public:
  32. Extractor(base::span<const void*> outputs,
  33. base::span<const StepOrByte<void>> steps)
  34. : outputs_(outputs), steps_(steps) {}
  35. bool ValuesFromMap(const cbor::Value::MapValue& map) {
  36. for (;;) {
  37. const internal::Step step = steps_[step_i_++].step;
  38. const Type value_type = static_cast<Type>(step.value_type);
  39. if (value_type == Type::kStop) {
  40. return true;
  41. }
  42. const cbor::Value::MapValue::const_iterator map_it = map.find(NextKey());
  43. const void** output = nullptr;
  44. if (value_type != Type::kMap) {
  45. DCHECK_LT(step.output_index, outputs_.size());
  46. output = &outputs_[step.output_index];
  47. }
  48. if (map_it == map.end()) {
  49. if (step.required) {
  50. return false;
  51. }
  52. if (output) {
  53. *output = nullptr;
  54. }
  55. if (value_type == Type::kMap) {
  56. // When skipping an optional map, all the |StepOrByte| for the
  57. // elements of the map need to be skipped over.
  58. SeekPastNextStop();
  59. }
  60. continue;
  61. }
  62. // kExpectedCBORTypes is an array of bitmaps of acceptable types for each
  63. // |Type|.
  64. static constexpr uint8_t kExpectedCBORTypes[] = {
  65. // kBytestring
  66. CBORTypeToBitfield(cbor::Value::Type::BYTE_STRING),
  67. // kString
  68. CBORTypeToBitfield(cbor::Value::Type::STRING),
  69. // kBoolean
  70. CBORTypeToBitfield(cbor::Value::Type::SIMPLE_VALUE),
  71. // kInt
  72. CBORTypeToBitfield(cbor::Value::Type::NEGATIVE) |
  73. CBORTypeToBitfield(cbor::Value::Type::UNSIGNED),
  74. // kMap
  75. CBORTypeToBitfield(cbor::Value::Type::MAP),
  76. // kArray
  77. CBORTypeToBitfield(cbor::Value::Type::ARRAY),
  78. // kValue
  79. 0xff,
  80. };
  81. const cbor::Value& value = map_it->second;
  82. const unsigned cbor_type_u = static_cast<unsigned>(value.type());
  83. const unsigned value_type_u = static_cast<unsigned>(value_type);
  84. DCHECK(value_type_u < std::size(kExpectedCBORTypes));
  85. if (cbor_type_u >= 8 ||
  86. (kExpectedCBORTypes[value_type_u] & (1u << cbor_type_u)) == 0) {
  87. return false;
  88. }
  89. switch (value_type) {
  90. case Type::kBytestring:
  91. ASSERT_TYPE_IS(value.GetBytestring(), const std::vector<uint8_t>);
  92. *output = &value.GetBytestring();
  93. break;
  94. case Type::kString:
  95. ASSERT_TYPE_IS(value.GetString(), const std::string);
  96. *output = &value.GetString();
  97. break;
  98. case Type::kBoolean:
  99. switch (value.GetSimpleValue()) {
  100. case cbor::Value::SimpleValue::TRUE_VALUE:
  101. *output = &kTrue;
  102. break;
  103. case cbor::Value::SimpleValue::FALSE_VALUE:
  104. *output = &kFalse;
  105. break;
  106. default:
  107. return false;
  108. }
  109. break;
  110. case Type::kInt:
  111. ASSERT_TYPE_IS(value.GetInteger(), const int64_t);
  112. *output = &value.GetInteger();
  113. break;
  114. case Type::kMap:
  115. if (!ValuesFromMap(value.GetMap())) {
  116. return false;
  117. }
  118. break;
  119. case Type::kArray:
  120. ASSERT_TYPE_IS(value.GetArray(), const std::vector<cbor::Value>);
  121. *output = &value.GetArray();
  122. break;
  123. case Type::kValue:
  124. *output = &value;
  125. break;
  126. case Type::kStop:
  127. return false;
  128. }
  129. }
  130. }
  131. private:
  132. // SeekPastNextStop increments |step_i_| until just after the next |Stop|
  133. // element, taking into account nested maps.
  134. void SeekPastNextStop() {
  135. for (;;) {
  136. const internal::Step step = steps_[step_i_++].step;
  137. const Type value_type = static_cast<Type>(step.value_type);
  138. if (value_type == Type::kStop) {
  139. break;
  140. }
  141. NextKey();
  142. if (value_type == Type::kMap) {
  143. SeekPastNextStop();
  144. } else {
  145. outputs_[step.output_index] = nullptr;
  146. }
  147. }
  148. }
  149. cbor::Value NextKey() {
  150. DCHECK_LT(step_i_, steps_.size());
  151. const uint8_t key_or_string_indicator = steps_[step_i_++].u8;
  152. if (key_or_string_indicator != StepOrByte<void>::STRING_KEY) {
  153. return cbor::Value(
  154. static_cast<int64_t>(static_cast<int8_t>(key_or_string_indicator)));
  155. }
  156. DCHECK_LT(step_i_, steps_.size());
  157. std::string key(&steps_[step_i_].c);
  158. step_i_ += key.size() + 1;
  159. DCHECK_LE(step_i_, steps_.size());
  160. return cbor::Value(std::move(key));
  161. }
  162. base::span<const void*> outputs_;
  163. base::span<const StepOrByte<void>> steps_;
  164. size_t step_i_ = 0;
  165. };
  166. } // namespace
  167. namespace internal {
  168. bool Extract(base::span<const void*> outputs,
  169. base::span<const StepOrByte<void>> steps,
  170. const cbor::Value::MapValue& map) {
  171. DCHECK(steps[steps.size() - 1].step.value_type ==
  172. static_cast<uint8_t>(Type::kStop));
  173. Extractor extractor(outputs, steps);
  174. return extractor.ValuesFromMap(map);
  175. }
  176. } // namespace internal
  177. bool ForEachPublicKeyEntry(
  178. const cbor::Value::ArrayValue& array,
  179. const cbor::Value& key,
  180. base::RepeatingCallback<bool(const cbor::Value&)> callback) {
  181. const cbor::Value type_key("type");
  182. const std::string public_key("public-key");
  183. for (const cbor::Value& value : array) {
  184. if (!value.is_map()) {
  185. return false;
  186. }
  187. const cbor::Value::MapValue& map = value.GetMap();
  188. const auto type_it = map.find(type_key);
  189. if (type_it == map.end() || !type_it->second.is_string()) {
  190. return false;
  191. }
  192. if (type_it->second.GetString() != public_key) {
  193. continue;
  194. }
  195. const auto value_it = map.find(key);
  196. if (value_it == map.end() || !callback.Run(value_it->second)) {
  197. return false;
  198. }
  199. }
  200. return true;
  201. }
  202. } // namespace cbor_extract
  203. } // namespace device