Input.h (9085B)
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> 69 explicit Input(const uint8_t (&aData)[N]) : data(aData), len(N) {} 70 71 // Construct a valid, empty, Init-able 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. 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. 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. 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. 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 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: 136 Reader() : input(nullptr), end(nullptr) {} 137 138 explicit Reader(Input aInput) 139 : input(aInput.UnsafeGetData()), 140 end(aInput.UnsafeGetData() + aInput.GetLength()) {} 141 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 151 bool Peek(uint8_t expectedByte) const { 152 return input < end && *input == expectedByte; 153 } 154 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 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> 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 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 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 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 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 240 void SkipToEnd() { input = end; } 241 242 Result SkipToEnd(/*out*/ Input& skipped) { 243 return Skip(static_cast<Input::size_type>(end - input), skipped); 244 } 245 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 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; 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 267 Mark GetMark() const { return Mark(*this, input); } 268 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: 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 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 } // namespace pkix 308 } // namespace mozilla 309 310 #endif // mozilla_pkix_Input_h