1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This code is made available to you under your choice of the following sets
4 * of licensing terms:
5 */
6 /* This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
10 /* Copyright 2013 Mozilla Contributors
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 */
24
25 #ifndef mozilla_pkix_Input_h
26 #define mozilla_pkix_Input_h
27
28 #include <algorithm>
29
30 #include "mozpkix/Result.h"
31 #include "stdint.h"
32
33 namespace mozilla {
34 namespace pkix {
35
36 class Reader;
37
38 // An Input is a safety-oriented immutable weak reference to a array of bytes
39 // of a known size. The data can only be legally accessed by constructing a
40 // Reader object, which guarantees all accesses to the data are memory safe.
41 // Neither Input not Reader provide any facilities for modifying the data
42 // they reference.
43 //
44 // Inputs are small and should usually be passed by value, not by reference,
45 // though for inline functions the distinction doesn't matter:
46 //
47 // Result GoodExample(Input input);
48 // Result BadExample(const Input& input);
49 // Result WorseExample(const uint8_t* input, size_t len);
50 //
51 // Note that in the example, GoodExample has the same performance
52 // characteristics as WorseExample, but with much better safety guarantees.
53 class Input final {
54 public:
55 typedef uint16_t size_type;
56
57 // This constructor is useful for inputs that are statically known to be of a
58 // fixed size, e.g.:
59 //
60 // static const uint8_t EXPECTED_BYTES[] = { 0x00, 0x01, 0x02 };
61 // const Input expected(EXPECTED_BYTES);
62 //
63 // This is equivalent to (and preferred over):
64 //
65 // static const uint8_t EXPECTED_BYTES[] = { 0x00, 0x01, 0x02 };
66 // Input expected;
67 // Result rv = expected.Init(EXPECTED_BYTES, sizeof EXPECTED_BYTES);
68 template <size_type N>
Input(const uint8_t (& aData)[N])69 explicit Input(const uint8_t (&aData)[N]) : data(aData), len(N) {}
70
71 // Construct a valid, empty, Init-able Input.
Input()72 Input() : data(nullptr), len(0u) {}
73
74 // This is intentionally not explicit in order to allow value semantics.
75 Input(const Input&) = default;
76
77 // Initialize the input. data must be non-null and len must be less than
78 // 65536. Init may not be called more than once.
Init(const uint8_t * aData,size_t aLen)79 Result Init(const uint8_t* aData, size_t aLen) {
80 if (this->data) {
81 // already initialized
82 return Result::FATAL_ERROR_INVALID_ARGS;
83 }
84 if (!aData || aLen > 0xffffu) {
85 // input too large
86 return Result::ERROR_BAD_DER;
87 }
88
89 this->data = aData;
90 this->len = aLen;
91
92 return Success;
93 }
94
95 // Initialize the input to be equivalent to the given input. Init may not be
96 // called more than once.
97 //
98 // This is basically operator=, but it wasn't given that name because
99 // normally callers do not check the result of operator=, and normally
100 // operator= can be used multiple times.
Init(Input other)101 Result Init(Input other) { return Init(other.data, other.len); }
102
103 // Returns the length of the input.
104 //
105 // Having the return type be size_type instead of size_t avoids the need for
106 // callers to ensure that the result is small enough.
GetLength()107 size_type GetLength() const { return static_cast<size_type>(len); }
108
109 // Don't use this. It is here because we have some "friend" functions that we
110 // don't want to declare in this header file.
UnsafeGetData()111 const uint8_t* UnsafeGetData() const { return data; }
112
113 private:
114 const uint8_t* data;
115 size_t len;
116
117 void operator=(const Input&) = delete; // Use Init instead.
118 };
119
InputsAreEqual(const Input & a,const Input & b)120 inline bool InputsAreEqual(const Input& a, const Input& b) {
121 return a.GetLength() == b.GetLength() &&
122 std::equal(a.UnsafeGetData(), a.UnsafeGetData() + a.GetLength(),
123 b.UnsafeGetData());
124 }
125
126 // An Reader is a cursor/iterator through the contents of an Input, designed to
127 // maximize safety during parsing while minimizing the performance cost of that
128 // safety. In particular, all methods do strict bounds checking to ensure
129 // buffer overflows are impossible, and they are all inline so that the
130 // compiler can coalesce as many of those checks together as possible.
131 //
132 // In general, Reader allows for one byte of lookahead and no backtracking.
133 // However, the Match* functions internally may have more lookahead.
134 class Reader final {
135 public:
Reader()136 Reader() : input(nullptr), end(nullptr) {}
137
Reader(Input aInput)138 explicit Reader(Input aInput)
139 : input(aInput.UnsafeGetData()),
140 end(aInput.UnsafeGetData() + aInput.GetLength()) {}
141
Init(Input aInput)142 Result Init(Input aInput) {
143 if (this->input) {
144 return Result::FATAL_ERROR_INVALID_ARGS;
145 }
146 this->input = aInput.UnsafeGetData();
147 this->end = aInput.UnsafeGetData() + aInput.GetLength();
148 return Success;
149 }
150
Peek(uint8_t expectedByte)151 bool Peek(uint8_t expectedByte) const {
152 return input < end && *input == expectedByte;
153 }
154
Read(uint8_t & out)155 Result Read(uint8_t& out) {
156 Result rv = EnsureLength(1);
157 if (rv != Success) {
158 return rv;
159 }
160 out = *input++;
161 return Success;
162 }
163
Read(uint16_t & out)164 Result Read(uint16_t& out) {
165 Result rv = EnsureLength(2);
166 if (rv != Success) {
167 return rv;
168 }
169 out = *input++;
170 out <<= 8u;
171 out |= *input++;
172 return Success;
173 }
174
175 template <Input::size_type N>
MatchRest(const uint8_t (& toMatch)[N])176 bool MatchRest(const uint8_t (&toMatch)[N]) {
177 // Normally we use EnsureLength which compares (input + len < end), but
178 // here we want to be sure that there is nothing following the matched
179 // bytes
180 if (static_cast<size_t>(end - input) != N) {
181 return false;
182 }
183 if (!std::equal(input, end, toMatch)) {
184 return false;
185 }
186 input = end;
187 return true;
188 }
189
MatchRest(Input toMatch)190 bool MatchRest(Input toMatch) {
191 // Normally we use EnsureLength which compares (input + len < end), but
192 // here we want to be sure that there is nothing following the matched
193 // bytes
194 size_t remaining = static_cast<size_t>(end - input);
195 if (toMatch.GetLength() != remaining) {
196 return false;
197 }
198 if (!std::equal(input, end, toMatch.UnsafeGetData())) {
199 return false;
200 }
201 input = end;
202 return true;
203 }
204
Skip(Input::size_type len)205 Result Skip(Input::size_type len) {
206 Result rv = EnsureLength(len);
207 if (rv != Success) {
208 return rv;
209 }
210 input += len;
211 return Success;
212 }
213
Skip(Input::size_type len,Reader & skipped)214 Result Skip(Input::size_type len, Reader& skipped) {
215 Result rv = EnsureLength(len);
216 if (rv != Success) {
217 return rv;
218 }
219 rv = skipped.Init(input, len);
220 if (rv != Success) {
221 return rv;
222 }
223 input += len;
224 return Success;
225 }
226
Skip(Input::size_type len,Input & skipped)227 Result Skip(Input::size_type len, /*out*/ Input& skipped) {
228 Result rv = EnsureLength(len);
229 if (rv != Success) {
230 return rv;
231 }
232 rv = skipped.Init(input, len);
233 if (rv != Success) {
234 return rv;
235 }
236 input += len;
237 return Success;
238 }
239
SkipToEnd()240 void SkipToEnd() { input = end; }
241
SkipToEnd(Input & skipped)242 Result SkipToEnd(/*out*/ Input& skipped) {
243 return Skip(static_cast<Input::size_type>(end - input), skipped);
244 }
245
EnsureLength(Input::size_type len)246 Result EnsureLength(Input::size_type len) {
247 if (static_cast<size_t>(end - input) < len) {
248 return Result::ERROR_BAD_DER;
249 }
250 return Success;
251 }
252
AtEnd()253 bool AtEnd() const { return input == end; }
254
255 class Mark final {
256 public:
257 Mark(const Mark&) = default; // Intentionally not explicit.
258 private:
259 friend class Reader;
Mark(const Reader & aInput,const uint8_t * aMark)260 Mark(const Reader& aInput, const uint8_t* aMark)
261 : input(aInput), mark(aMark) {}
262 const Reader& input;
263 const uint8_t* const mark;
264 void operator=(const Mark&) = delete;
265 };
266
GetMark()267 Mark GetMark() const { return Mark(*this, input); }
268
GetInput(const Mark & mark,Input & item)269 Result GetInput(const Mark& mark, /*out*/ Input& item) {
270 if (&mark.input != this || mark.mark > input) {
271 return NotReached("invalid mark", Result::FATAL_ERROR_INVALID_ARGS);
272 }
273 return item.Init(mark.mark,
274 static_cast<Input::size_type>(input - mark.mark));
275 }
276
277 private:
Init(const uint8_t * data,Input::size_type len)278 Result Init(const uint8_t* data, Input::size_type len) {
279 if (input) {
280 // already initialized
281 return Result::FATAL_ERROR_INVALID_ARGS;
282 }
283 input = data;
284 end = data + len;
285 return Success;
286 }
287
288 const uint8_t* input;
289 const uint8_t* end;
290
291 Reader(const Reader&) = delete;
292 void operator=(const Reader&) = delete;
293 };
294
InputContains(const Input & input,uint8_t toFind)295 inline bool InputContains(const Input& input, uint8_t toFind) {
296 Reader reader(input);
297 for (;;) {
298 uint8_t b;
299 if (reader.Read(b) != Success) {
300 return false;
301 }
302 if (b == toFind) {
303 return true;
304 }
305 }
306 }
307 }
308 } // namespace mozilla::pkix
309
310 #endif // mozilla_pkix_Input_h
311