tor-browser

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

json_reader.h (4394B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef PK11GTEST_JSON_H_
      8 #define PK11GTEST_JSON_H_
      9 
     10 #include <functional>
     11 #include <iostream>
     12 #include <vector>
     13 #include "gtest/gtest.h"
     14 #include "nss_scoped_ptrs.h"
     15 #include "secoidt.h"
     16 
     17 // If we make a few assumptions about the file, parsing JSON can be easy.
     18 // This is not a full parser, it only works on a narrow set of inputs.
     19 class JsonReader {
     20 public:
     21  JsonReader(const std::string& n);
     22 
     23  void next() { i_++; }
     24  uint8_t peek() {
     25    TopUp();
     26    return buf_[i_];
     27  }
     28  uint8_t take() {
     29    uint8_t v = peek();
     30    next();
     31    return v;
     32  }
     33 
     34  // No input checking, overflow protection, or any safety.
     35  // Returns 0 if there isn't a number here rather than aborting.
     36  uint64_t ReadInt();
     37  // No input checking, no unicode, no escaping (not even \"), just read ASCII.
     38  std::string ReadString();
     39  std::string ReadLabel();
     40  std::vector<uint8_t> ReadHex();
     41  SECOidTag ReadHash();
     42  SECStatus ReadSECStatus();
     43  bool ReadBool();
     44 
     45  bool NextItem(uint8_t h = '{', uint8_t t = '}');
     46  bool NextItemArray() { return NextItem('[', ']'); }
     47  void SkipValue();
     48 
     49 private:
     50  void TopUp();
     51  void SkipWhitespace();
     52  // This only handles lowercase.
     53  uint8_t Hex(uint8_t c);
     54 
     55  ScopedPRFileDesc f_;
     56  uint8_t buf_[4096];
     57  size_t available_;
     58  size_t i_;
     59 };
     60 
     61 // The way this is expected to work is that this reads the header, then
     62 // passes off the content of each "testGroups" member to `group_handler`.
     63 // That function processes any attributes in that structure, calls
     64 // `WycheproofReadTests` to load individual cases and runs those tests.
     65 void WycheproofHeader(const std::string& name, const std::string& algorithm,
     66                      const std::string& schema,
     67                      std::function<void(JsonReader& r)> group_handler);
     68 
     69 template <typename T>
     70 struct id {
     71  typedef T type;
     72 };
     73 
     74 template <typename T>
     75 using nondeduced = typename id<T>::type;
     76 
     77 // Read into a block of test cases, handling standard attributes on Wycheproof
     78 // tests.
     79 //
     80 // `T` needs `uint64_t id` and `bool valid` fields.
     81 // `attr_reader` is responsible for reading values into the test case struct.
     82 // `acceptable` determines whether a test marked "acceptable" is valid by
     83 // default. `process_flags` allows for processing the flags on an entry.
     84 //
     85 // Note that this gathers all tests into a vector rather than running tests as
     86 // they arrive.  This is necessary because the testGroup JSON struct might have
     87 // fields that haven't been read when this list is constructed (it doesn't in
     88 // the current files, but this is not guaranteed).  Tests can only run after all
     89 // of the group attributes have been read and processed.
     90 template <typename T>
     91 void WycheproofReadTests(
     92    JsonReader& r, std::vector<T>* tests,
     93    const std::function<nondeduced<void(T&, const std::string&, JsonReader&)>>&
     94        attr_reader,
     95    bool acceptable = true,
     96    const std::function<nondeduced<void(T&, const std::string&,
     97                                        const std::vector<std::string>&)>>&
     98        process_flags = nullptr) {
     99  while (r.NextItemArray()) {
    100    T tc;
    101    std::string comment;
    102    std::string result;
    103    std::vector<std::string> flags;
    104 
    105    while (r.NextItem()) {
    106      std::string n = r.ReadLabel();
    107      if (n == "") {
    108        break;
    109      }
    110      if (n == "tcId") {
    111        tc.id = r.ReadInt();
    112      } else if (n == "result") {
    113        result = r.ReadString();
    114      } else if (n == "comment") {
    115        comment = r.ReadString();
    116      } else if (n == "flags") {
    117        while (r.NextItemArray()) {
    118          flags.push_back(r.ReadString());
    119        }
    120      } else {
    121        ASSERT_NO_FATAL_FAILURE(attr_reader(tc, n, r));
    122      }
    123    }
    124 
    125    tc.valid = (result == "valid") || (acceptable && result == "acceptable");
    126    if (process_flags) {
    127      process_flags(tc, result, flags);
    128    }
    129 
    130    std::cout << "  tc " << tc.id << ": " << comment << " [" << result;
    131    for (auto& f : flags) {
    132      std::cout << ", " << f;
    133    }
    134    std::cout << "] expect " << (tc.valid ? "success" : "failure") << std::endl;
    135 
    136    tests->push_back(tc);
    137  }
    138 }
    139 
    140 #endif  // PK11GTEST_JSON_H_