• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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