large_blob.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. #ifndef DEVICE_FIDO_LARGE_BLOB_H_
  5. #define DEVICE_FIDO_LARGE_BLOB_H_
  6. #include <cstdint>
  7. #include <cstdlib>
  8. #include <vector>
  9. #include "base/component_export.h"
  10. #include "device/fido/fido_constants.h"
  11. #include "device/fido/pin.h"
  12. #include "third_party/abseil-cpp/absl/types/optional.h"
  13. namespace device {
  14. // https://drafts.fidoalliance.org/fido-2/stable-links-to-latest/fido-client-to-authenticator-protocol.html#largeBlobsRW
  15. enum class LargeBlobsRequestKey : uint8_t {
  16. kGet = 0x01,
  17. kSet = 0x02,
  18. kOffset = 0x03,
  19. kLength = 0x04,
  20. kPinUvAuthParam = 0x05,
  21. kPinUvAuthProtocol = 0x06,
  22. };
  23. // https://drafts.fidoalliance.org/fido-2/stable-links-to-latest/fido-client-to-authenticator-protocol.html#largeBlobsRW
  24. enum class LargeBlobsResponseKey : uint8_t {
  25. kConfig = 0x01,
  26. };
  27. // https://drafts.fidoalliance.org/fido-2/stable-links-to-latest/fido-client-to-authenticator-protocol.html#large-blob
  28. enum class LargeBlobDataKeys : uint8_t {
  29. kCiphertext = 0x01,
  30. kNonce = 0x02,
  31. kOrigSize = 0x03,
  32. };
  33. using LargeBlobKey = std::array<uint8_t, kLargeBlobKeyLength>;
  34. constexpr size_t kLargeBlobDefaultMaxFragmentLength = 960;
  35. constexpr size_t kLargeBlobReadEncodingOverhead = 64;
  36. constexpr size_t kLargeBlobArrayNonceLength = 12;
  37. constexpr std::array<uint8_t, 2> kLargeBlobPinPrefix = {0x0c, 0x00};
  38. // A complete but still compressed large blob.
  39. struct COMPONENT_EXPORT(DEVICE_FIDO) LargeBlob {
  40. LargeBlob(std::vector<uint8_t> compressed_data, uint64_t original_size);
  41. ~LargeBlob();
  42. LargeBlob(const LargeBlob&);
  43. LargeBlob& operator=(const LargeBlob&);
  44. LargeBlob(LargeBlob&&);
  45. LargeBlob& operator=(LargeBlob&&);
  46. bool operator==(const LargeBlob&) const;
  47. // The DEFLATEd large blob bytes.
  48. std::vector<uint8_t> compressed_data;
  49. // Uncompressed, original size of the large blob.
  50. uint64_t original_size;
  51. };
  52. struct COMPONENT_EXPORT(DEVICE_FIDO) LargeBlobArrayFragment {
  53. LargeBlobArrayFragment(std::vector<uint8_t> bytes, size_t offset);
  54. ~LargeBlobArrayFragment();
  55. LargeBlobArrayFragment(const LargeBlobArrayFragment&) = delete;
  56. LargeBlobArrayFragment& operator=(const LargeBlobArrayFragment&) = delete;
  57. LargeBlobArrayFragment(LargeBlobArrayFragment&&);
  58. const std::vector<uint8_t> bytes;
  59. const size_t offset;
  60. };
  61. COMPONENT_EXPORT(DEVICE_FIDO)
  62. bool VerifyLargeBlobArrayIntegrity(base::span<const uint8_t> large_blob_array);
  63. class LargeBlobsRequest {
  64. public:
  65. ~LargeBlobsRequest();
  66. LargeBlobsRequest(const LargeBlobsRequest&) = delete;
  67. LargeBlobsRequest& operator=(const LargeBlobsRequest&) = delete;
  68. LargeBlobsRequest(LargeBlobsRequest&& other);
  69. static LargeBlobsRequest ForRead(size_t bytes, size_t offset);
  70. static LargeBlobsRequest ForWrite(LargeBlobArrayFragment fragment,
  71. size_t length);
  72. void SetPinParam(const pin::TokenResponse& pin_uv_auth_token);
  73. friend std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  74. AsCTAPRequestValuePair(const LargeBlobsRequest& request);
  75. private:
  76. LargeBlobsRequest();
  77. absl::optional<int64_t> get_;
  78. absl::optional<std::vector<uint8_t>> set_;
  79. int64_t offset_ = 0;
  80. absl::optional<int64_t> length_;
  81. absl::optional<std::vector<uint8_t>> pin_uv_auth_param_;
  82. absl::optional<PINUVAuthProtocol> pin_uv_auth_protocol_;
  83. };
  84. class LargeBlobsResponse {
  85. public:
  86. LargeBlobsResponse(const LargeBlobsResponse&) = delete;
  87. LargeBlobsResponse& operator=(const LargeBlobsResponse&) = delete;
  88. LargeBlobsResponse(LargeBlobsResponse&& other);
  89. LargeBlobsResponse& operator=(LargeBlobsResponse&&);
  90. ~LargeBlobsResponse();
  91. static absl::optional<LargeBlobsResponse> ParseForRead(
  92. size_t bytes_to_read,
  93. const absl::optional<cbor::Value>& cbor_response);
  94. static absl::optional<LargeBlobsResponse> ParseForWrite(
  95. const absl::optional<cbor::Value>& cbor_response);
  96. absl::optional<std::vector<uint8_t>> config() { return config_; }
  97. private:
  98. explicit LargeBlobsResponse(
  99. absl::optional<std::vector<uint8_t>> config = absl::nullopt);
  100. absl::optional<std::vector<uint8_t>> config_;
  101. };
  102. // Represents the large-blob map structure
  103. // https://drafts.fidoalliance.org/fido-2/stable-links-to-latest/fido-client-to-authenticator-protocol.html#large-blob
  104. class COMPONENT_EXPORT(DEVICE_FIDO) LargeBlobData {
  105. public:
  106. static absl::optional<LargeBlobData> Parse(const cbor::Value& cbor_response);
  107. LargeBlobData(LargeBlobKey key, LargeBlob large_blob);
  108. LargeBlobData(const LargeBlobData&) = delete;
  109. LargeBlobData& operator=(const LargeBlobData&) = delete;
  110. LargeBlobData(LargeBlobData&&);
  111. LargeBlobData& operator=(LargeBlobData&&);
  112. ~LargeBlobData();
  113. bool operator==(const LargeBlobData&) const;
  114. absl::optional<LargeBlob> Decrypt(LargeBlobKey key) const;
  115. cbor::Value::MapValue AsCBOR() const;
  116. private:
  117. LargeBlobData(std::vector<uint8_t> ciphertext,
  118. base::span<const uint8_t, kLargeBlobArrayNonceLength> nonce,
  119. int64_t orig_size);
  120. std::vector<uint8_t> ciphertext_;
  121. std::array<uint8_t, kLargeBlobArrayNonceLength> nonce_;
  122. int64_t orig_size_;
  123. };
  124. // Reading large blob arrays is done in chunks. This class provides facilities
  125. // to assemble together those chunks.
  126. class COMPONENT_EXPORT(DEVICE_FIDO) LargeBlobArrayReader {
  127. public:
  128. LargeBlobArrayReader();
  129. LargeBlobArrayReader(const LargeBlobArrayReader&) = delete;
  130. LargeBlobArrayReader& operator=(const LargeBlobArrayReader&) = delete;
  131. LargeBlobArrayReader(LargeBlobArrayReader&&);
  132. ~LargeBlobArrayReader();
  133. // Appends a fragment to the large blob array.
  134. void Append(const std::vector<uint8_t>& fragment);
  135. // Verifies the integrity of the large blob array. This should be called after
  136. // all fragments have been |Append|ed.
  137. // If successful, parses and returns the array.
  138. absl::optional<std::vector<LargeBlobData>> Materialize();
  139. // Returns the current size of the array fragments.
  140. size_t size() const { return bytes_.size(); }
  141. private:
  142. std::vector<uint8_t> bytes_;
  143. };
  144. // Writing large blob arrays is done in chunks. This class provides facilities
  145. // to divide a blob into chunks.
  146. class COMPONENT_EXPORT(DEVICE_FIDO) LargeBlobArrayWriter {
  147. public:
  148. explicit LargeBlobArrayWriter(
  149. const std::vector<LargeBlobData>& large_blob_array);
  150. LargeBlobArrayWriter(const LargeBlobArrayWriter&) = delete;
  151. LargeBlobArrayWriter& operator=(const LargeBlobArrayWriter&) = delete;
  152. LargeBlobArrayWriter(LargeBlobArrayWriter&&);
  153. ~LargeBlobArrayWriter();
  154. // Extracts a fragment with |length|. Can only be called if
  155. // has_remaining_fragments() is true.
  156. LargeBlobArrayFragment Pop(size_t length);
  157. // Returns the current size of the array fragments.
  158. size_t size() const { return bytes_.size(); }
  159. // Returns true if there are remaining fragments to be written, false
  160. // otherwise.
  161. bool has_remaining_fragments() const { return offset_ < size(); }
  162. void set_bytes_for_testing(std::vector<uint8_t> bytes) {
  163. bytes_ = std::move(bytes);
  164. }
  165. private:
  166. std::vector<uint8_t> bytes_;
  167. size_t offset_ = 0;
  168. };
  169. std::pair<CtapRequestCommand, absl::optional<cbor::Value>>
  170. AsCTAPRequestValuePair(const LargeBlobsRequest& request);
  171. } // namespace device
  172. #endif // DEVICE_FIDO_LARGE_BLOB_H_