diff options
Diffstat (limited to 'security/nss/gtests/pk11_gtest/json_reader.h')
-rw-r--r-- | security/nss/gtests/pk11_gtest/json_reader.h | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/security/nss/gtests/pk11_gtest/json_reader.h b/security/nss/gtests/pk11_gtest/json_reader.h new file mode 100644 index 0000000000..dd520a8969 --- /dev/null +++ b/security/nss/gtests/pk11_gtest/json_reader.h @@ -0,0 +1,138 @@ +/* -*- 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/. */ + +#ifndef PK11GTEST_JSON_H_ +#define PK11GTEST_JSON_H_ + +#include <functional> +#include <iostream> +#include <vector> +#include "gtest/gtest.h" +#include "nss_scoped_ptrs.h" +#include "secoidt.h" + +// If we make a few assumptions about the file, parsing JSON can be easy. +// This is not a full parser, it only works on a narrow set of inputs. +class JsonReader { + public: + JsonReader(const std::string& n); + + void next() { i_++; } + uint8_t peek() { + TopUp(); + return buf_[i_]; + } + uint8_t take() { + uint8_t v = peek(); + next(); + return v; + } + + // No input checking, overflow protection, or any safety. + // Returns 0 if there isn't a number here rather than aborting. + uint64_t ReadInt(); + // No input checking, no unicode, no escaping (not even \"), just read ASCII. + std::string ReadString(); + std::string ReadLabel(); + std::vector<uint8_t> ReadHex(); + SECOidTag ReadHash(); + + bool NextItem(uint8_t h = '{', uint8_t t = '}'); + bool NextItemArray() { return NextItem('[', ']'); } + void SkipValue(); + + private: + void TopUp(); + void SkipWhitespace(); + // This only handles lowercase. + uint8_t Hex(uint8_t c); + + ScopedPRFileDesc f_; + uint8_t buf_[4096]; + size_t available_; + size_t i_; +}; + +// The way this is expected to work is that this reads the header, then +// passes off the content of each "testGroups" member to `group_handler`. +// That function processes any attributes in that structure, calls +// `WycheproofReadTests` to load individual cases and runs those tests. +void WycheproofHeader(const std::string& name, const std::string& algorithm, + const std::string& schema, + std::function<void(JsonReader& r)> group_handler); + +template <typename T> +struct id { + typedef T type; +}; + +template <typename T> +using nondeduced = typename id<T>::type; + +// Read into a block of test cases, handling standard attributes on Wycheproof +// tests. +// +// `T` needs `uint64_t id` and `bool valid` fields. +// `attr_reader` is responsible for reading values into the test case struct. +// `acceptable` determines whether a test marked "acceptable" is valid by +// default. `process_flags` allows for processing the flags on an entry. +// +// Note that this gathers all tests into a vector rather than running tests as +// they arrive. This is necessary because the testGroup JSON struct might have +// fields that haven't been read when this list is constructed (it doesn't in +// the current files, but this is not guaranteed). Tests can only run after all +// of the group attributes have been read and processed. +template <typename T> +void WycheproofReadTests( + JsonReader& r, std::vector<T>* tests, + const std::function<nondeduced<void(T&, const std::string&, JsonReader&)>>& + attr_reader, + bool acceptable = true, + const std::function<nondeduced<void(T&, const std::string&, + const std::vector<std::string>&)>>& + process_flags = nullptr) { + while (r.NextItemArray()) { + T tc; + std::string comment; + std::string result; + std::vector<std::string> flags; + + while (r.NextItem()) { + std::string n = r.ReadLabel(); + if (n == "") { + break; + } + if (n == "tcId") { + tc.id = r.ReadInt(); + } else if (n == "result") { + result = r.ReadString(); + } else if (n == "comment") { + comment = r.ReadString(); + } else if (n == "flags") { + while (r.NextItemArray()) { + flags.push_back(r.ReadString()); + } + } else { + ASSERT_NO_FATAL_FAILURE(attr_reader(tc, n, r)); + } + } + + tc.valid = (result == "valid") || (acceptable && result == "acceptable"); + if (process_flags) { + process_flags(tc, result, flags); + } + + std::cout << " tc " << tc.id << ": " << comment << " [" << result; + for (auto& f : flags) { + std::cout << ", " << f; + } + std::cout << "] expect " << (tc.valid ? "success" : "failure") << std::endl; + + tests->push_back(tc); + } +} + +#endif // PK11GTEST_JSON_H_ |