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