/* -*- 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 JsonReader::ReadHex() { SkipWhitespace(); uint8_t c = take(); EXPECT_EQ(c, '"'); std::vector 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; } SECStatus JsonReader::ReadSECStatus() { std::string s = ReadString(); if (s == "SECSuccess") { return SECSuccess; } else if (s == "SECFailure") { return SECFailure; } else if (s == "SECWouldBlock") { return SECWouldBlock; } ADD_FAILURE() << "unknown SECStatus"; return SECFailure; } bool JsonReader::ReadBool() { std::string s = ReadString(); if (s == "true") { return true; } else if (s == "false") { return false; } ADD_FAILURE() << "not a bool"; return false; } 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(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 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"; } } }