diff options
Diffstat (limited to 'security/nss/gtests/pk11_gtest/json_reader.cc')
-rw-r--r-- | security/nss/gtests/pk11_gtest/json_reader.cc | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/security/nss/gtests/pk11_gtest/json_reader.cc b/security/nss/gtests/pk11_gtest/json_reader.cc new file mode 100644 index 0000000000..da8920240c --- /dev/null +++ b/security/nss/gtests/pk11_gtest/json_reader.cc @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "json_reader.h" + +#include "pk11pub.h" + +JsonReader::JsonReader(const std::string& n) : buf_(), available_(0), i_(0) { + f_.reset(PR_Open(n.c_str(), PR_RDONLY, 00600)); + EXPECT_TRUE(f_) << "error opening vectors from: " << n; + buf_[0] = 0; +} + +uint64_t JsonReader::ReadInt() { + SkipWhitespace(); + uint8_t c = peek(); + uint64_t v = 0; + while (c >= '0' && c <= '9') { + v = v * 10 + c - '0'; + next(); + c = peek(); + } + return v; +} + +// No input checking, no unicode, no escaping (not even \"), just read ASCII. +std::string JsonReader::ReadString() { + SkipWhitespace(); + if (peek() != '"') { + return ""; + } + next(); + + std::string s; + uint8_t c = take(); + while (c != '"') { + s.push_back(c); + c = take(); + } + return s; +} + +std::string JsonReader::ReadLabel() { + std::string s = ReadString(); + SkipWhitespace(); + EXPECT_EQ(take(), ':'); + return s; +} + +std::vector<uint8_t> JsonReader::ReadHex() { + SkipWhitespace(); + uint8_t c = take(); + EXPECT_EQ(c, '"'); + std::vector<uint8_t> v; + c = take(); + while (c != '"') { + v.push_back(JsonReader::Hex(c) << 4 | JsonReader::Hex(take())); + c = take(); + } + return v; +} + +SECOidTag JsonReader::ReadHash() { + std::string s = ReadString(); + if (s == "SHA-1") { + return SEC_OID_SHA1; + } + if (s == "SHA-224") { + return SEC_OID_SHA224; + } + if (s == "SHA-256") { + return SEC_OID_SHA256; + } + if (s == "SHA-384") { + return SEC_OID_SHA384; + } + if (s == "SHA-512") { + return SEC_OID_SHA512; + } + ADD_FAILURE() << "unsupported hash"; + return SEC_OID_UNKNOWN; +} + +bool JsonReader::NextItem(uint8_t h, uint8_t t) { + SkipWhitespace(); + switch (uint8_t c = take()) { + case ',': + return true; + case '{': + case '[': + EXPECT_EQ(c, h); + SkipWhitespace(); + if (peek() == t) { + next(); + return false; + } + return true; + case '}': + case ']': + EXPECT_EQ(c, t); + return false; + default: + ADD_FAILURE() << "Unexpected '" << c << "'"; + } + return false; +} + +void JsonReader::SkipValue() { + SkipWhitespace(); + + uint8_t c = take(); + if (c == '"') { + do { + c = take(); + } while (c != '"'); + + } else if (c >= '0' && c <= '9') { + c = peek(); + while (c >= '0' && c <= '9') { + next(); + c = peek(); + } + + } else if (c == '[') { + do { + SkipWhitespace(); + if (peek() != ']') { + SkipValue(); + } + } while (NextItemArray()); + + } else if (c == '{') { + do { + SkipWhitespace(); + if (peek() == '}') { + continue; + } + + std::string n = ReadLabel(); + if (n == "") { + break; + } + SkipValue(); + } while (NextItem()); + + } else { + ADD_FAILURE() << "No idea how to skip '" << c << "'"; + } +} + +void JsonReader::TopUp() { + if (available_ > i_) { + return; + } + i_ = 0; + if (!f_) { + return; + } + PRInt32 res = PR_Read(f_.get(), buf_, sizeof(buf_)); + if (res > 0) { + available_ = static_cast<size_t>(res); + } else { + available_ = 1; + f_.reset(nullptr); + buf_[0] = 0; + } +} + +void JsonReader::SkipWhitespace() { + uint8_t c = peek(); + while (c && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) { + next(); + c = peek(); + } +} + +// This only handles lowercase. +uint8_t JsonReader::Hex(uint8_t c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + EXPECT_TRUE(c >= 'a' && c <= 'f'); + return c - 'a' + 10; +} + +extern std::string g_source_dir; + +void WycheproofHeader(const std::string& name, const std::string& algorithm, + const std::string& schema, + std::function<void(JsonReader& r)> group_handler) { + std::string basename = name + "_test.json"; + std::string dir = ::g_source_dir + "/../common/wycheproof/source_vectors/"; + std::cout << "Reading tests from: " << basename << std::endl; + + JsonReader r(dir + basename); + while (r.NextItem()) { + std::string n = r.ReadLabel(); + if (n == "") { + break; + } + if (n == "algorithm") { + ASSERT_EQ(algorithm, r.ReadString()); + } else if (n == "generatorVersion" || n == "numberOfTests") { + r.SkipValue(); + } else if (n == "header") { + while (r.NextItemArray()) { + std::cout << " " << r.ReadString() << std::endl; + } + } else if (n == "notes") { + while (r.NextItem()) { + std::string note = r.ReadLabel(); + if (note == "") { + break; + } + std::cout << " " << note << ": " << r.ReadString() << std::endl; + } + } else if (n == "schema") { + ASSERT_EQ(schema, r.ReadString()); + } else if (n == "testGroups") { + while (r.NextItemArray()) { + group_handler(r); + } + } else { + FAIL() << "unknown value in header"; + } + } +} |