1 // Copyright 2015 The Chromium Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef BSSL_DER_INPUT_H_ 16 #define BSSL_DER_INPUT_H_ 17 18 #include <stddef.h> 19 #include <stdint.h> 20 21 #include <string> 22 #include <string_view> 23 24 #include <openssl/base.h> 25 #include <openssl/span.h> 26 27 #if __has_include(<version>) 28 #include <version> 29 #endif 30 31 #if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L 32 #include <ranges> 33 BSSL_NAMESPACE_BEGIN 34 namespace der { 35 class OPENSSL_EXPORT Input; 36 } 37 BSSL_NAMESPACE_END 38 39 // Mark `Input` as satisfying the `view` and `borrowed_range` concepts. This 40 // should be done before the definition of `Input`, so that any inlined calls to 41 // range functionality use the correct specializations. 42 template <> 43 inline constexpr bool std::ranges::enable_view<bssl::der::Input> = true; 44 template <> 45 inline constexpr bool std::ranges::enable_borrowed_range<bssl::der::Input> = 46 true; 47 #endif 48 49 BSSL_NAMESPACE_BEGIN 50 namespace der { 51 52 // An opaque class that represents a fixed buffer of data of a fixed length, 53 // to be used as an input to other operations. An Input object does not own 54 // the data it references, so callers are responsible for making sure that 55 // the data outlives the Input object and any other associated objects. 56 // 57 // All data access for an Input should be done through the ByteReader class. 58 // This class and associated classes are designed with safety in mind to make it 59 // difficult to read memory outside of an Input. ByteReader provides a simple 60 // API for reading through the Input sequentially. For more complicated uses, 61 // multiple instances of a ByteReader for a particular Input can be created. 62 // 63 // TODO(crbug.com/boringssl/661): This class will gradually be replaced with 64 // bssl::Span<const uint8_t>. Avoid relying on APIs that are not part of 65 // bssl::Span. 66 class OPENSSL_EXPORT Input { 67 public: 68 // Creates an empty Input, one from which no data can be read. 69 constexpr Input() = default; 70 71 // Creates an Input from a span. The constructed Input is only valid as long 72 // as |data| points to live memory. If constructed from, say, a 73 // |std::vector<uint8_t>|, mutating the vector will invalidate the Input. Input(bssl::Span<const uint8_t> data)74 constexpr Input(bssl::Span<const uint8_t> data) : data_(data) {} 75 76 // Creates an Input from the given |data| and |len|. Input(const uint8_t * data,size_t len)77 constexpr explicit Input(const uint8_t *data, size_t len) 78 : data_(Span(data, len)) {} 79 80 // Deprecated: Use StringAsBytes. 81 // 82 // Creates an Input from a std::string_view. The constructed Input is only 83 // valid as long as |data| points to live memory. If constructed from, say, a 84 // |std::string|, mutating the vector will invalidate the Input. Input(std::string_view str)85 explicit Input(std::string_view str) : data_(StringAsBytes(str)) {} 86 87 // The following APIs have the same semantics as in |bssl::Span|. begin()88 constexpr Span<const uint8_t>::iterator begin() const { 89 return data_.begin(); 90 } end()91 constexpr Span<const uint8_t>::iterator end() const { return data_.end(); } data()92 constexpr const uint8_t *data() const { return data_.data(); } size()93 constexpr size_t size() const { return data_.size(); } empty()94 constexpr bool empty() const { return data_.empty(); } 95 constexpr uint8_t operator[](size_t idx) const { return data_[idx]; } front()96 constexpr uint8_t front() const { return data_.front(); } back()97 constexpr uint8_t back() const { return data_.back(); } 98 constexpr Input subspan(size_t pos = 0, 99 size_t len = Span<const uint8_t>::npos) const { 100 return Input(data_.subspan(pos, len)); 101 } first(size_t len)102 constexpr Input first(size_t len) const { return Input(data_.first(len)); } last(size_t len)103 constexpr Input last(size_t len) const { return Input(data_.last(len)); } 104 105 // Deprecated: use BytesAsStringView and convert to std::string. 106 // 107 // Returns a copy of the data represented by this object as a std::string. 108 std::string AsString() const; 109 110 // Deprecated: Use ByteAsString. 111 // 112 // Returns a std::string_view pointing to the same data as the Input. The 113 // resulting string_view must not outlive the data that was used to construct 114 // this Input. AsStringView()115 std::string_view AsStringView() const { return BytesAsStringView(data_); } 116 117 // Deprecated: This class implicitly converts to bssl::Span<const uint8_t>. 118 // 119 // Returns a span pointing to the same data as the Input. The resulting span 120 // must not outlive the data that was used to construct this Input. AsSpan()121 Span<const uint8_t> AsSpan() const { return *this; } 122 123 // Deprecated: Use size() instead. Length()124 constexpr size_t Length() const { return size(); } 125 126 // Deprecated: Use data() instead. UnsafeData()127 constexpr const uint8_t *UnsafeData() const { return data(); } 128 129 private: 130 // TODO(crbug.com/770501): Replace this type with span altogether. 131 Span<const uint8_t> data_; 132 }; 133 134 // Return true if |lhs|'s data and |rhs|'s data are byte-wise equal. 135 OPENSSL_EXPORT bool operator==(Input lhs, Input rhs); 136 137 // Return true if |lhs|'s data and |rhs|'s data are not byte-wise equal. 138 OPENSSL_EXPORT bool operator!=(Input lhs, Input rhs); 139 140 // Returns true if |lhs|'s data is lexicographically less than |rhs|'s data. 141 OPENSSL_EXPORT constexpr bool operator<(Input lhs, Input rhs) { 142 // This is `std::lexicographical_compare`, but that's not `constexpr` until 143 // C++-20. 144 auto *it1 = lhs.data(); 145 auto *it2 = rhs.data(); 146 const auto *end1 = lhs.data() + lhs.size(); 147 const auto *end2 = rhs.data() + rhs.size(); 148 for (; it1 != end1 && it2 != end2; ++it1, ++it2) { 149 if (*it1 < *it2) { 150 return true; 151 } else if (*it2 < *it1) { 152 return false; 153 } 154 } 155 156 return it2 != end2; 157 } 158 159 // This class provides ways to read data from an Input in a bounds-checked way. 160 // The ByteReader is designed to read through the input sequentially. Once a 161 // byte has been read with a ByteReader, the caller can't go back and re-read 162 // that byte with the same reader. Of course, the caller can create multiple 163 // ByteReaders for the same input (or copy an existing ByteReader). 164 // 165 // For something simple like a single byte lookahead, the easiest way to do 166 // that is to copy the ByteReader and call ReadByte() on the copy - the original 167 // ByteReader will be unaffected and the peeked byte will be read through 168 // ReadByte(). For other read patterns, it can be useful to mark where one is 169 // in a ByteReader to be able to return to that spot. 170 // 171 // Some operations using Mark can also be done by creating a copy of the 172 // ByteReader. By using a Mark instead, you use less memory, but more 173 // importantly, you end up with an immutable object that matches the semantics 174 // of what is intended. 175 class OPENSSL_EXPORT ByteReader { 176 public: 177 // Creates a ByteReader to read the data represented by an Input. 178 explicit ByteReader(Input in); 179 180 // Reads a single byte from the input source, putting the byte read in 181 // |*byte_p|. If a byte cannot be read from the input (because there is 182 // no input left), then this method returns false. 183 [[nodiscard]] bool ReadByte(uint8_t *out); 184 185 // Reads |len| bytes from the input source, and initializes an Input to 186 // point to that data. If there aren't enough bytes left in the input source, 187 // then this method returns false. 188 [[nodiscard]] bool ReadBytes(size_t len, Input *out); 189 190 // Returns how many bytes are left to read. BytesLeft()191 size_t BytesLeft() const { return data_.size(); } 192 193 // Returns whether there is any more data to be read. 194 bool HasMore(); 195 196 private: 197 void Advance(size_t len); 198 199 bssl::Span<const uint8_t> data_; 200 }; 201 202 } // namespace der 203 BSSL_NAMESPACE_END 204 205 #endif // BSSL_DER_INPUT_H_ 206