tor-browser

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

json_reader.cc (5561B)


      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 #include "json_reader.h"
      8 
      9 #include "pk11pub.h"
     10 
     11 JsonReader::JsonReader(const std::string& n) : buf_(), available_(0), i_(0) {
     12  f_.reset(PR_Open(n.c_str(), PR_RDONLY, 00600));
     13  EXPECT_TRUE(f_) << "error opening vectors from: " << n;
     14  buf_[0] = 0;
     15 }
     16 
     17 uint64_t JsonReader::ReadInt() {
     18  SkipWhitespace();
     19  uint8_t c = peek();
     20  uint64_t v = 0;
     21  while (c >= '0' && c <= '9') {
     22    v = v * 10 + c - '0';
     23    next();
     24    c = peek();
     25  }
     26  return v;
     27 }
     28 
     29 // No input checking, no unicode, no escaping (not even \"), just read ASCII.
     30 std::string JsonReader::ReadString() {
     31  SkipWhitespace();
     32  if (peek() != '"') {
     33    return "";
     34  }
     35  next();
     36 
     37  std::string s;
     38  uint8_t c = take();
     39  while (c != '"') {
     40    s.push_back(c);
     41    c = take();
     42  }
     43  return s;
     44 }
     45 
     46 std::string JsonReader::ReadLabel() {
     47  std::string s = ReadString();
     48  SkipWhitespace();
     49  EXPECT_EQ(take(), ':');
     50  return s;
     51 }
     52 
     53 std::vector<uint8_t> JsonReader::ReadHex() {
     54  SkipWhitespace();
     55  uint8_t c = take();
     56  EXPECT_EQ(c, '"');
     57  std::vector<uint8_t> v;
     58  c = take();
     59  while (c != '"') {
     60    v.push_back(JsonReader::Hex(c) << 4 | JsonReader::Hex(take()));
     61    c = take();
     62  }
     63  return v;
     64 }
     65 
     66 SECOidTag JsonReader::ReadHash() {
     67  std::string s = ReadString();
     68  if (s == "SHA-1") {
     69    return SEC_OID_SHA1;
     70  }
     71  if (s == "SHA-224") {
     72    return SEC_OID_SHA224;
     73  }
     74  if (s == "SHA-256") {
     75    return SEC_OID_SHA256;
     76  }
     77  if (s == "SHA-384") {
     78    return SEC_OID_SHA384;
     79  }
     80  if (s == "SHA-512") {
     81    return SEC_OID_SHA512;
     82  }
     83  ADD_FAILURE() << "unsupported hash";
     84  return SEC_OID_UNKNOWN;
     85 }
     86 
     87 SECStatus JsonReader::ReadSECStatus() {
     88  std::string s = ReadString();
     89  if (s == "SECSuccess") {
     90    return SECSuccess;
     91  } else if (s == "SECFailure") {
     92    return SECFailure;
     93  } else if (s == "SECWouldBlock") {
     94    return SECWouldBlock;
     95  }
     96  ADD_FAILURE() << "unknown SECStatus";
     97  return SECFailure;
     98 }
     99 
    100 bool JsonReader::ReadBool() {
    101  std::string s = ReadString();
    102  if (s == "true") {
    103    return true;
    104  } else if (s == "false") {
    105    return false;
    106  }
    107  ADD_FAILURE() << "not a bool";
    108  return false;
    109 }
    110 
    111 bool JsonReader::NextItem(uint8_t h, uint8_t t) {
    112  SkipWhitespace();
    113  switch (uint8_t c = take()) {
    114    case ',':
    115      return true;
    116    case '{':
    117    case '[':
    118      EXPECT_EQ(c, h);
    119      SkipWhitespace();
    120      if (peek() == t) {
    121        next();
    122        return false;
    123      }
    124      return true;
    125    case '}':
    126    case ']':
    127      EXPECT_EQ(c, t);
    128      return false;
    129    default:
    130      ADD_FAILURE() << "Unexpected '" << c << "'";
    131  }
    132  return false;
    133 }
    134 
    135 void JsonReader::SkipValue() {
    136  SkipWhitespace();
    137 
    138  uint8_t c = take();
    139  if (c == '"') {
    140    do {
    141      c = take();
    142    } while (c != '"');
    143 
    144  } else if (c >= '0' && c <= '9') {
    145    c = peek();
    146    while (c >= '0' && c <= '9') {
    147      next();
    148      c = peek();
    149    }
    150 
    151  } else if (c == '[') {
    152    do {
    153      SkipWhitespace();
    154      if (peek() != ']') {
    155        SkipValue();
    156      }
    157    } while (NextItemArray());
    158 
    159  } else if (c == '{') {
    160    do {
    161      SkipWhitespace();
    162      if (peek() == '}') {
    163        continue;
    164      }
    165 
    166      std::string n = ReadLabel();
    167      if (n == "") {
    168        break;
    169      }
    170      SkipValue();
    171    } while (NextItem());
    172 
    173  } else {
    174    ADD_FAILURE() << "No idea how to skip '" << c << "'";
    175  }
    176 }
    177 
    178 void JsonReader::TopUp() {
    179  if (available_ > i_) {
    180    return;
    181  }
    182  i_ = 0;
    183  if (!f_) {
    184    return;
    185  }
    186  PRInt32 res = PR_Read(f_.get(), buf_, sizeof(buf_));
    187  if (res > 0) {
    188    available_ = static_cast<size_t>(res);
    189  } else {
    190    available_ = 1;
    191    f_.reset(nullptr);
    192    buf_[0] = 0;
    193  }
    194 }
    195 
    196 void JsonReader::SkipWhitespace() {
    197  uint8_t c = peek();
    198  while (c && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) {
    199    next();
    200    c = peek();
    201  }
    202 }
    203 
    204 // This only handles lowercase.
    205 uint8_t JsonReader::Hex(uint8_t c) {
    206  if (c >= '0' && c <= '9') {
    207    return c - '0';
    208  }
    209  EXPECT_TRUE(c >= 'a' && c <= 'f');
    210  return c - 'a' + 10;
    211 }
    212 
    213 extern std::string g_source_dir;
    214 
    215 void WycheproofHeader(const std::string& name, const std::string& algorithm,
    216                      const std::string& schema,
    217                      std::function<void(JsonReader& r)> group_handler) {
    218  std::string basename = name + "_test.json";
    219  std::string dir = ::g_source_dir + "/../common/wycheproof/source_vectors/";
    220  std::cout << "Reading tests from: " << basename << std::endl;
    221 
    222  JsonReader r(dir + basename);
    223  while (r.NextItem()) {
    224    std::string n = r.ReadLabel();
    225    if (n == "") {
    226      break;
    227    }
    228    if (n == "algorithm") {
    229      ASSERT_EQ(algorithm, r.ReadString());
    230    } else if (n == "generatorVersion" || n == "numberOfTests") {
    231      r.SkipValue();
    232    } else if (n == "header") {
    233      while (r.NextItemArray()) {
    234        std::cout << "  " << r.ReadString() << std::endl;
    235      }
    236    } else if (n == "notes") {
    237      while (r.NextItem()) {
    238        std::string note = r.ReadLabel();
    239        if (note == "") {
    240          break;
    241        }
    242        std::cout << "    " << note << ": " << r.ReadString() << std::endl;
    243      }
    244    } else if (n == "schema") {
    245      ASSERT_EQ(schema, r.ReadString());
    246    } else if (n == "testGroups") {
    247      while (r.NextItemArray()) {
    248        group_handler(r);
    249      }
    250    } else {
    251      FAIL() << "unknown value in header";
    252    }
    253  }
    254 }