Line data Source code
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>
69 0 : explicit Input(const uint8_t (&data)[N])
70 : : data(data)
71 0 : , len(N)
72 : {
73 0 : }
74 :
75 : // Construct a valid, empty, Init-able Input.
76 128 : Input()
77 128 : : data(nullptr)
78 128 : , len(0u)
79 : {
80 128 : }
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.
87 128 : Result Init(const uint8_t* data, size_t len)
88 : {
89 128 : if (this->data) {
90 : // already initialized
91 0 : return Result::FATAL_ERROR_INVALID_ARGS;
92 : }
93 128 : if (!data || len > 0xffffu) {
94 : // input too large
95 0 : return Result::ERROR_BAD_DER;
96 : }
97 :
98 128 : this->data = data;
99 128 : this->len = len;
100 :
101 128 : 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.
110 0 : Result Init(Input other)
111 : {
112 0 : 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.
119 170 : 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.
123 264 : 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
133 0 : InputsAreEqual(const Input& a, const Input& b)
134 : {
135 0 : return a.GetLength() == b.GetLength() &&
136 0 : 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:
150 79 : Reader()
151 79 : : input(nullptr)
152 79 : , end(nullptr)
153 : {
154 79 : }
155 :
156 38 : explicit Reader(Input input)
157 38 : : input(input.UnsafeGetData())
158 38 : , end(input.UnsafeGetData() + input.GetLength())
159 : {
160 38 : }
161 :
162 79 : Result Init(Input input)
163 : {
164 79 : if (this->input) {
165 0 : return Result::FATAL_ERROR_INVALID_ARGS;
166 : }
167 79 : this->input = input.UnsafeGetData();
168 79 : this->end = input.UnsafeGetData() + input.GetLength();
169 79 : return Success;
170 : }
171 :
172 0 : bool Peek(uint8_t expectedByte) const
173 : {
174 0 : return input < end && *input == expectedByte;
175 : }
176 :
177 212 : Result Read(uint8_t& out)
178 : {
179 212 : Result rv = EnsureLength(1);
180 212 : if (rv != Success) {
181 0 : return rv;
182 : }
183 212 : out = *input++;
184 212 : return Success;
185 : }
186 :
187 16 : Result Read(uint16_t& out)
188 : {
189 16 : Result rv = EnsureLength(2);
190 16 : if (rv != Success) {
191 0 : return rv;
192 : }
193 16 : out = *input++;
194 16 : out <<= 8u;
195 16 : out |= *input++;
196 16 : return Success;
197 : }
198 :
199 : template <Input::size_type N>
200 30 : 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 30 : if (static_cast<size_t>(end - input) != N) {
206 4 : return false;
207 : }
208 26 : if (!std::equal(input, end, toMatch)) {
209 0 : return false;
210 : }
211 26 : input = end;
212 26 : return true;
213 : }
214 :
215 0 : 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 0 : size_t remaining = static_cast<size_t>(end - input);
221 0 : if (toMatch.GetLength() != remaining) {
222 0 : return false;
223 : }
224 0 : if (!std::equal(input, end, toMatch.UnsafeGetData())) {
225 0 : return false;
226 : }
227 0 : input = end;
228 0 : return true;
229 : }
230 :
231 0 : Result Skip(Input::size_type len)
232 : {
233 0 : Result rv = EnsureLength(len);
234 0 : if (rv != Success) {
235 0 : return rv;
236 : }
237 0 : input += len;
238 0 : return Success;
239 : }
240 :
241 0 : Result Skip(Input::size_type len, Reader& skipped)
242 : {
243 0 : Result rv = EnsureLength(len);
244 0 : if (rv != Success) {
245 0 : return rv;
246 : }
247 0 : rv = skipped.Init(input, len);
248 0 : if (rv != Success) {
249 0 : return rv;
250 : }
251 0 : input += len;
252 0 : return Success;
253 : }
254 :
255 113 : Result Skip(Input::size_type len, /*out*/ Input& skipped)
256 : {
257 113 : Result rv = EnsureLength(len);
258 113 : if (rv != Success) {
259 0 : return rv;
260 : }
261 113 : rv = skipped.Init(input, len);
262 113 : if (rv != Success) {
263 0 : return rv;
264 : }
265 113 : input += len;
266 113 : return Success;
267 : }
268 :
269 0 : void SkipToEnd()
270 : {
271 0 : input = end;
272 0 : }
273 :
274 26 : Result SkipToEnd(/*out*/ Input& skipped)
275 : {
276 26 : return Skip(static_cast<Input::size_type>(end - input), skipped);
277 : }
278 :
279 341 : Result EnsureLength(Input::size_type len)
280 : {
281 341 : if (static_cast<size_t>(end - input) < len) {
282 0 : return Result::ERROR_BAD_DER;
283 : }
284 341 : return Success;
285 : }
286 :
287 91 : 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;
295 0 : 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 :
301 0 : Mark GetMark() const { return Mark(*this, input); }
302 :
303 0 : Result GetInput(const Mark& mark, /*out*/ Input& item)
304 : {
305 0 : if (&mark.input != this || mark.mark > input) {
306 0 : return NotReached("invalid mark", Result::FATAL_ERROR_INVALID_ARGS);
307 : }
308 0 : return item.Init(mark.mark,
309 0 : static_cast<Input::size_type>(input - mark.mark));
310 : }
311 :
312 : private:
313 0 : Result Init(const uint8_t* data, Input::size_type len)
314 : {
315 0 : if (input) {
316 : // already initialized
317 0 : return Result::FATAL_ERROR_INVALID_ARGS;
318 : }
319 0 : input = data;
320 0 : end = data + len;
321 0 : 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
332 0 : InputContains(const Input& input, uint8_t toFind)
333 : {
334 0 : Reader reader(input);
335 : for (;;) {
336 : uint8_t b;
337 0 : if (reader.Read(b) != Success) {
338 0 : return false;
339 : }
340 0 : if (b == toFind) {
341 0 : return true;
342 : }
343 0 : }
344 : }
345 :
346 : } } // namespace mozilla::pkix
347 :
348 : #endif // mozilla_pkix_Input_h
|