Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef BSSL_DER_INPUT_H_ |
| 6 | #define BSSL_DER_INPUT_H_ |
| 7 | |
| 8 | #include "fillins/openssl_util.h" |
| 9 | #include <stddef.h> |
| 10 | #include <stdint.h> |
| 11 | |
| 12 | #include <string> |
| 13 | |
| 14 | #include <openssl/span.h> |
| 15 | |
| 16 | |
| 17 | namespace bssl::der { |
| 18 | |
| 19 | // An opaque class that represents a fixed buffer of data of a fixed length, |
| 20 | // to be used as an input to other operations. An Input object does not own |
| 21 | // the data it references, so callers are responsible for making sure that |
| 22 | // the data outlives the Input object and any other associated objects. |
| 23 | // |
| 24 | // All data access for an Input should be done through the ByteReader class. |
| 25 | // This class and associated classes are designed with safety in mind to make it |
| 26 | // difficult to read memory outside of an Input. ByteReader provides a simple |
| 27 | // API for reading through the Input sequentially. For more complicated uses, |
| 28 | // multiple instances of a ByteReader for a particular Input can be created. |
| 29 | class OPENSSL_EXPORT Input { |
| 30 | public: |
| 31 | // Creates an empty Input, one from which no data can be read. |
| 32 | constexpr Input() = default; |
| 33 | |
| 34 | // Creates an Input from a constant array |data|. |
| 35 | template <size_t N> |
| 36 | constexpr explicit Input(const uint8_t (&data)[N]) : data_(data), len_(N) {} |
| 37 | |
| 38 | // Creates an Input from the given |data| and |len|. |
| 39 | constexpr explicit Input(const uint8_t* data, size_t len) |
| 40 | : data_(data), len_(len) {} |
| 41 | |
| 42 | // Creates an Input from a std::string_view |
| 43 | explicit Input(std::string_view sp); |
| 44 | |
| 45 | // Creates an Input from a std::string. The lifetimes are a bit subtle when |
| 46 | // using this function: The constructed Input is only valid so long as |s| is |
| 47 | // still alive and not mutated. |
| 48 | explicit Input(const std::string* s); |
| 49 | |
| 50 | // Returns the length in bytes of an Input's data. |
| 51 | constexpr size_t Length() const { return len_; } |
| 52 | |
| 53 | // Returns a pointer to the Input's data. This method is marked as "unsafe" |
| 54 | // because access to the Input's data should be done through ByteReader |
| 55 | // instead. This method should only be used where using a ByteReader truly |
| 56 | // is not an option. |
| 57 | constexpr const uint8_t* UnsafeData() const { return data_; } |
| 58 | |
| 59 | // Returns a copy of the data represented by this object as a std::string. |
| 60 | std::string AsString() const; |
| 61 | |
| 62 | // Returns a std::string_view pointing to the same data as the Input. The |
| 63 | // resulting string_view must not outlive the data that was used to construct |
| 64 | // this Input. |
| 65 | std::string_view AsStringView() const; |
| 66 | |
| 67 | // Returns a bssl::Span pointing to the same data as the Input. The resulting |
| 68 | // bssl::Span must not outlive the data that was used to construct this |
| 69 | // Input. |
| 70 | bssl::Span<const uint8_t> AsSpan() const; |
| 71 | |
| 72 | private: |
| 73 | // This constructor is deleted to prevent constructing an Input from a |
| 74 | // std::string r-value. Since the Input points to memory owned by another |
| 75 | // object, such an Input would point to invalid memory. Without this deleted |
| 76 | // constructor, a std::string could be passed in to the std::string_view |
| 77 | // constructor because of std::string_view's implicit constructor. |
| 78 | Input(std::string) = delete; |
| 79 | |
| 80 | const uint8_t* data_ = nullptr; |
| 81 | size_t len_ = 0; |
| 82 | }; |
| 83 | |
| 84 | // Return true if |lhs|'s data and |rhs|'s data are byte-wise equal. |
| 85 | OPENSSL_EXPORT bool operator==(const Input& lhs, const Input& rhs); |
| 86 | |
| 87 | // Return true if |lhs|'s data and |rhs|'s data are not byte-wise equal. |
| 88 | OPENSSL_EXPORT bool operator!=(const Input& lhs, const Input& rhs); |
| 89 | |
| 90 | // Returns true if |lhs|'s data is lexicographically less than |rhs|'s data. |
| 91 | OPENSSL_EXPORT constexpr bool operator<(const Input& lhs, |
| 92 | const Input& rhs) { |
| 93 | // This is `std::lexicographical_compare`, but that's not `constexpr` until |
| 94 | // C++-20. |
| 95 | auto* it1 = lhs.UnsafeData(); |
| 96 | auto* it2 = rhs.UnsafeData(); |
| 97 | const auto* end1 = lhs.UnsafeData() + lhs.Length(); |
| 98 | const auto* end2 = rhs.UnsafeData() + rhs.Length(); |
| 99 | for (; it1 != end1 && it2 != end2; ++it1, ++it2) { |
| 100 | if (*it1 < *it2) { |
| 101 | return true; |
| 102 | } else if (*it2 < *it1) { |
| 103 | return false; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | return it2 != end2; |
| 108 | } |
| 109 | |
| 110 | // This class provides ways to read data from an Input in a bounds-checked way. |
| 111 | // The ByteReader is designed to read through the input sequentially. Once a |
| 112 | // byte has been read with a ByteReader, the caller can't go back and re-read |
| 113 | // that byte with the same reader. Of course, the caller can create multiple |
| 114 | // ByteReaders for the same input (or copy an existing ByteReader). |
| 115 | // |
| 116 | // For something simple like a single byte lookahead, the easiest way to do |
| 117 | // that is to copy the ByteReader and call ReadByte() on the copy - the original |
| 118 | // ByteReader will be unaffected and the peeked byte will be read through |
| 119 | // ReadByte(). For other read patterns, it can be useful to mark where one is |
| 120 | // in a ByteReader to be able to return to that spot. |
| 121 | // |
| 122 | // Some operations using Mark can also be done by creating a copy of the |
| 123 | // ByteReader. By using a Mark instead, you use less memory, but more |
| 124 | // importantly, you end up with an immutable object that matches the semantics |
| 125 | // of what is intended. |
| 126 | class OPENSSL_EXPORT ByteReader { |
| 127 | public: |
| 128 | // Creates a ByteReader to read the data represented by an Input. |
| 129 | explicit ByteReader(const Input& in); |
| 130 | |
| 131 | // Reads a single byte from the input source, putting the byte read in |
| 132 | // |*byte_p|. If a byte cannot be read from the input (because there is |
| 133 | // no input left), then this method returns false. |
| 134 | [[nodiscard]] bool ReadByte(uint8_t* out); |
| 135 | |
| 136 | // Reads |len| bytes from the input source, and initializes an Input to |
| 137 | // point to that data. If there aren't enough bytes left in the input source, |
| 138 | // then this method returns false. |
| 139 | [[nodiscard]] bool ReadBytes(size_t len, Input* out); |
| 140 | |
| 141 | // Returns how many bytes are left to read. |
| 142 | size_t BytesLeft() const { return len_; } |
| 143 | |
| 144 | // Returns whether there is any more data to be read. |
| 145 | bool HasMore(); |
| 146 | |
| 147 | private: |
| 148 | void Advance(size_t len); |
| 149 | |
| 150 | const uint8_t* data_; |
| 151 | size_t len_; |
| 152 | }; |
| 153 | |
| 154 | } // namespace bssl::der |
| 155 | |
| 156 | #endif // BSSL_DER_INPUT_H_ |