// 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 "nspr.h" #include "nss.h" #include "ssl.h" #include #include #define GTEST_HAS_RTTI 0 #include "gtest/gtest.h" #include "util.h" #include "blapi.h" extern std::string g_source_dir; namespace nss_test { struct PRNGTestValues { std::vector entropy; std::vector nonce; std::vector personal; std::vector expected_result; std::vector additional_entropy; std::vector additional_input_reseed; std::vector> additional_input; }; bool contains(std::string& s, const char* to_find) { return s.find(to_find) != std::string::npos; } std::string trim(std::string str) { std::string whitespace = " \t\r\n"; const auto strBegin = str.find_first_not_of(whitespace); if (strBegin == std::string::npos) { return ""; } const auto strEnd = str.find_last_not_of(whitespace); const auto strRange = strEnd - strBegin + 1; return str.substr(strBegin, strRange); } std::vector read_option_s(std::string& s) { size_t start = s.find("=") + 1; assert(start > 0); return hex_string_to_bytes(trim(s.substr(start, s.find("]", start)))); } void print_bytes(std::vector bytes, std::string name) { std::cout << name << ": "; for (auto b : bytes) { std::cout << std::setfill('0') << std::setw(2) << std::hex << static_cast(b); } std::cout << std::endl; } static std::vector ReadFile(const std::string file_name) { std::vector test_vector; std::ifstream infile(file_name); EXPECT_FALSE(infile.fail()) << "kat file: " << file_name; std::string line; // Variables holding the input for each test. bool valid_option = false; // Read the file. std::streampos pos; while (std::getline(infile, line)) { // We only implement SHA256. Skip all other tests. if (contains(line, "[SHA-")) { valid_option = contains(line, "[SHA-256]"); } if (!valid_option) { continue; } // We ignore the options and infer them from the test case. PRNGTestValues test; if (line.find("COUNT =")) { continue; } // Read test input. do { pos = infile.tellg(); std::getline(infile, line); if (contains(line, "EntropyInput ")) { test.entropy = read_option_s(line); continue; } if (contains(line, "Nonce")) { test.nonce = read_option_s(line); continue; } if (contains(line, "PersonalizationString")) { test.personal = read_option_s(line); continue; } if (contains(line, "AdditionalInput ")) { test.additional_input.push_back(read_option_s(line)); continue; } if (contains(line, "EntropyInputReseed")) { test.additional_entropy = read_option_s(line); continue; } if (contains(line, "AdditionalInputReseed")) { test.additional_input_reseed = read_option_s(line); continue; } if (contains(line, "ReturnedBits")) { test.expected_result = read_option_s(line); continue; } } while (!infile.eof() && line.find("COUNT =") && line.find("[")); // Save test case. test_vector.push_back(test); test = {}; infile.seekg(pos); } return test_vector; } class PRNGTest : public ::testing::Test { protected: void SetUp() override { test_vector_ = ReadFile(::g_source_dir + "/kat/Hash_DRBG.rsp"); ASSERT_FALSE(test_vector_.empty()); } void RunTest(PRNGTestValues& test) { ASSERT_EQ(2U, test.additional_input.size()); SECStatus rv = PRNGTEST_Instantiate_Kat( test.entropy.data(), test.entropy.size(), test.nonce.data(), test.nonce.size(), test.personal.data(), test.personal.size()); ASSERT_EQ(SECSuccess, rv); rv = PRNGTEST_Reseed(test.additional_entropy.data(), test.additional_entropy.size(), test.additional_input_reseed.data(), test.additional_input_reseed.size()); ASSERT_EQ(SECSuccess, rv); // Generate bytes. uint8_t bytes[128]; PRNGTEST_Generate(bytes, 128, test.additional_input[0].data(), test.additional_input[0].size()); PRNGTEST_Generate(bytes, 128, test.additional_input[1].data(), test.additional_input[1].size()); std::vector result(bytes, bytes + 128); if (result != test.expected_result) { print_bytes(result, "result "); print_bytes(test.expected_result, "expected"); } ASSERT_EQ(test.expected_result, result); rv = PRNGTEST_Uninstantiate(); ASSERT_EQ(SECSuccess, rv); } protected: std::vector test_vector_; }; TEST_F(PRNGTest, HashDRBG) { for (auto& v : test_vector_) { RunTest(v); } } } // namespace nss_test