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 "pkix/Result.h"
31 #include "stdint.h"
32
33 namespace mozilla { namespace pkix {
34
35 class Reader;
36
37 // An Input is a safety-oriented immutable weak reference to a array of bytes
38 // of a known size. The data can only be legally accessed by constructing a
39 // Reader object, which guarantees all accesses to the data are memory safe.
40 // Neither Input not Reader provide any facilities for modifying the data
41 // they reference.
42 //
43 // Inputs are small and should usually be passed by value, not by reference,
44 // though for inline functions the distinction doesn't matter:
45 //
46 // Result GoodExample(Input input);
47 // Result BadExample(const Input& input);
48 // Result WorseExample(const uint8_t* input, size_t len);
49 //
50 // Note that in the example, GoodExample has the same performance
51 // characteristics as WorseExample, but with much better safety guarantees.
52 class Input final
53 {
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 (& data)[N])69 explicit Input(const uint8_t (&data)[N])
70 : data(data)
71 , len(N)
72 {
73 }
74
75 // Construct a valid, empty, Init-able Input.
Input()76 Input()
77 : data(nullptr)
78 , len(0u)
79 {
80 }
81
82 // This is intentionally not explicit in order to allow value semantics.
83 Input(const Input&) = default;
84
85 // Initialize the input. data must be non-null and len must be less than
86 // 65536. Init may not be called more than once.
Init(const uint8_t * data,size_t len)87 Result Init(const uint8_t* data, size_t len)
88 {
89 if (this->data) {
90 // already initialized
91 return Result::FATAL_ERROR_INVALID_ARGS;
92 }
93 if (!data || len > 0xffffu) {
94 // input too large
95 return Result::ERROR_BAD_DER;
96 }
97
98 this->data = data;
99 this->len = len;
100
101 return Success;
102 }
103
104 // Initialize the input to be equivalent to the given input. Init may not be
105 // called more than once.
106 //
107 // This is basically operator=, but it wasn't given that name because
108 // normally callers do not check the result of operator=, and normally
109 // operator= can be used multiple times.
Init(Input other)110 Result Init(Input other)
111 {
112 return Init(other.data, other.len);
113 }
114
115 // Returns the length of the input.
116 //
117 // Having the return type be size_type instead of size_t avoids the need for
118 // callers to ensure that the result is small enough.
GetLength()119 size_type GetLength() const { return static_cast<size_type>(len); }
120
121 // Don't use this. It is here because we have some "friend" functions that we
122 // don't want to declare in this header file.
UnsafeGetData()123 const uint8_t* UnsafeGetData() const { return data; }
124
125 private:
126 const uint8_t* data;
127 size_t len;
128
129 void operator=(const Input&) = delete; // Use Init instead.
130 };
131
132 inline bool
InputsAreEqual(const Input & a,const Input & b)133 InputsAreEqual(const Input& a, const Input& b)
134 {
135 return a.GetLength() == b.GetLength() &&
136 std::equal(a.UnsafeGetData(), a.UnsafeGetData() + a.GetLength(), b.UnsafeGetData());
137 }
138
139 // An Reader is a cursor/iterator through the contents of an Input, designed to
140 // maximize safety during parsing while minimizing the performance cost of that
141 // safety. In particular, all methods do strict bounds checking to ensure
142 // buffer overflows are impossible, and they are all inline so that the
143 // compiler can coalesce as many of those checks together as possible.
144 //
145 // In general, Reader allows for one byte of lookahead and no backtracking.
146 // However, the Match* functions internally may have more lookahead.
147 class Reader final
148 {
149 public:
Reader()150 Reader()
151 : input(nullptr)
152 , end(nullptr)
153 {
154 }
155
Reader(Input input)156 explicit Reader(Input input)
157 : input(input.UnsafeGetData())
158 , end(input.UnsafeGetData() + input.GetLength())
159 {
160 }
161
Init(Input input)162 Result Init(Input input)
163 {
164 if (this->input) {
165 return Result::FATAL_ERROR_INVALID_ARGS;
166 }
167 this->input = input.UnsafeGetData();
168 this->end = input.UnsafeGetData() + input.GetLength();
169 return Success;
170 }
171
Peek(uint8_t expectedByte)172 bool Peek(uint8_t expectedByte) const
173 {
174 return input < end && *input == expectedByte;
175 }
176
Read(uint8_t & out)177 Result Read(uint8_t& out)
178 {
179 Result rv = EnsureLength(1);
180 if (rv != Success) {
181 return rv;
182 }
183 out = *input++;
184 return Success;
185 }
186
Read(uint16_t & out)187 Result Read(uint16_t& out)
188 {
189 Result rv = EnsureLength(2);
190 if (rv != Success) {
191 return rv;
192 }
193 out = *input++;
194 out <<= 8u;
195 out |= *input++;
196 return Success;
197 }
198
199 template <Input::size_type N>
MatchRest(const uint8_t (& toMatch)[N])200 bool MatchRest(const uint8_t (&toMatch)[N])
201 {
202 // Normally we use EnsureLength which compares (input + len < end), but
203 // here we want to be sure that there is nothing following the matched
204 // bytes
205 if (static_cast<size_t>(end - input) != N) {
206 return false;
207 }
208 if (!std::equal(input, end, toMatch)) {
209 return false;
210 }
211 input = end;
212 return true;
213 }
214
MatchRest(Input toMatch)215 bool MatchRest(Input toMatch)
216 {
217 // Normally we use EnsureLength which compares (input + len < end), but
218 // here we want to be sure that there is nothing following the matched
219 // bytes
220 size_t remaining = static_cast<size_t>(end - input);
221 if (toMatch.GetLength() != remaining) {
222 return false;
223 }
224 if (!std::equal(input, end, toMatch.UnsafeGetData())) {
225 return false;
226 }
227 input = end;
228 return true;
229 }
230
Skip(Input::size_type len)231 Result Skip(Input::size_type len)
232 {
233 Result rv = EnsureLength(len);
234 if (rv != Success) {
235 return rv;
236 }
237 input += len;
238 return Success;
239 }
240
Skip(Input::size_type len,Reader & skipped)241 Result Skip(Input::size_type len, Reader& skipped)
242 {
243 Result rv = EnsureLength(len);
244 if (rv != Success) {
245 return rv;
246 }
247 rv = skipped.Init(input, len);
248 if (rv != Success) {
249 return rv;
250 }
251 input += len;
252 return Success;
253 }
254
Skip(Input::size_type len,Input & skipped)255 Result Skip(Input::size_type len, /*out*/ Input& skipped)
256 {
257 Result rv = EnsureLength(len);
258 if (rv != Success) {
259 return rv;
260 }
261 rv = skipped.Init(input, len);
262 if (rv != Success) {
263 return rv;
264 }
265 input += len;
266 return Success;
267 }
268
SkipToEnd()269 void SkipToEnd()
270 {
271 input = end;
272 }
273
SkipToEnd(Input & skipped)274 Result SkipToEnd(/*out*/ Input& skipped)
275 {
276 return Skip(static_cast<Input::size_type>(end - input), skipped);
277 }
278
EnsureLength(Input::size_type len)279 Result EnsureLength(Input::size_type len)
280 {
281 if (static_cast<size_t>(end - input) < len) {
282 return Result::ERROR_BAD_DER;
283 }
284 return Success;
285 }
286
AtEnd()287 bool AtEnd() const { return input == end; }
288
289 class Mark final
290 {
291 public:
292 Mark(const Mark&) = default; // Intentionally not explicit.
293 private:
294 friend class Reader;
Mark(const Reader & input,const uint8_t * mark)295 Mark(const Reader& input, const uint8_t* mark) : input(input), mark(mark) { }
296 const Reader& input;
297 const uint8_t* const mark;
298 void operator=(const Mark&) = delete;
299 };
300
GetMark()301 Mark GetMark() const { return Mark(*this, input); }
302
GetInput(const Mark & mark,Input & item)303 Result GetInput(const Mark& mark, /*out*/ Input& item)
304 {
305 if (&mark.input != this || mark.mark > input) {
306 return NotReached("invalid mark", Result::FATAL_ERROR_INVALID_ARGS);
307 }
308 return item.Init(mark.mark,
309 static_cast<Input::size_type>(input - mark.mark));
310 }
311
312 private:
Init(const uint8_t * data,Input::size_type len)313 Result Init(const uint8_t* data, Input::size_type len)
314 {
315 if (input) {
316 // already initialized
317 return Result::FATAL_ERROR_INVALID_ARGS;
318 }
319 input = data;
320 end = data + len;
321 return Success;
322 }
323
324 const uint8_t* input;
325 const uint8_t* end;
326
327 Reader(const Reader&) = delete;
328 void operator=(const Reader&) = delete;
329 };
330
331 inline bool
InputContains(const Input & input,uint8_t toFind)332 InputContains(const Input& input, uint8_t toFind)
333 {
334 Reader reader(input);
335 for (;;) {
336 uint8_t b;
337 if (reader.Read(b) != Success) {
338 return false;
339 }
340 if (b == toFind) {
341 return true;
342 }
343 }
344 }
345
346 } } // namespace mozilla::pkix
347
348 #endif // mozilla_pkix_Input_h
349