LCOV - code coverage report
Current view: top level - security/pkix/include/pkix - Input.h (source / functions) Hit Total Coverage
Test: output.info Lines: 56 121 46.3 %
Date: 2017-07-14 16:53:18 Functions: 16 38 42.1 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13