tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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