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