blob: 14a1feff29b3c147d60dfa2851e1579f19982d41 [file] [log] [blame]
Bob Beckbc97b7a2023-04-18 08:35:15 -06001// 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
17namespace 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.
29class 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.
85OPENSSL_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.
88OPENSSL_EXPORT bool operator!=(const Input& lhs, const Input& rhs);
89
90// Returns true if |lhs|'s data is lexicographically less than |rhs|'s data.
91OPENSSL_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.
126class 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_