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