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