diff --git a/CMakeLists.txt b/CMakeLists.txt index f5d8eb0b4..47fb3d2c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -609,13 +609,17 @@ set(DNS_SRC ) set(TEST_SRC + # helpers + test/main.cpp + test/test_util.cpp + # actual test cases + test/crypto/test_llarp_crypto_types.cpp test/crypto/test_llarp_crypto.cpp test/dht/test_llarp_dht_key.cpp test/dht/test_llarp_dht.cpp test/dns/test_llarp_dns_dns.cpp test/exit/test_llarp_exit_context.cpp test/link/test_llarp_link.cpp - test/main.cpp test/net/test_llarp_net_inaddr.cpp test/net/test_llarp_net.cpp test/routing/llarp_routing_transfer_traffic.cpp @@ -702,7 +706,10 @@ else() add_executable(${TEST_EXE} ${TEST_SRC} llarp/version.rc) add_executable(${EXE} ${EXE_SRC} llarp/version.rc) endif(NOT WIN32) + + target_include_directories(${TEST_EXE} PRIVATE test) target_include_directories(${TEST_EXE} PRIVATE ${GTEST_DIR}/include ${GTEST_DIR}) + install(TARGETS ${EXE} RUNTIME DESTINATION bin) if(WIN32) install(PROGRAMS ${CMAKE_SOURCE_DIR}/lokinet-bootstrap.exe DESTINATION bin) diff --git a/llarp/crypto/types.cpp b/llarp/crypto/types.cpp index ff29e68d0..2f27e19e0 100644 --- a/llarp/crypto/types.cpp +++ b/llarp/crypto/types.cpp @@ -23,30 +23,30 @@ namespace llarp bool SecretKey::LoadFromFile(const char* fname) { - std::ifstream f; - f.open(fname, std::ios::binary); + std::ifstream f(fname, std::ios::in | std::ios::binary); + if(!f.is_open()) { return false; } - size_t sz = 0; + f.seekg(0, std::ios::end); - sz = f.tellg(); + const size_t sz = f.tellg(); f.seekg(0, std::ios::beg); + if(sz == size()) { // is raw buffer - std::copy(std::istream_iterator< byte_t >(f), - std::istream_iterator< byte_t >(), begin()); + std::copy_n(std::istreambuf_iterator< char >(f), sz, begin()); return true; } - byte_t tmp[128]; - auto buf = llarp::StackBuffer< decltype(tmp) >(tmp); + std::array< byte_t, 128 > tmp; + llarp_buffer_t buf = llarp::Buffer(tmp); if(sz > sizeof(tmp)) { return false; } - f.read((char*)tmp, sz); + f.read(reinterpret_cast< char* >(tmp.data()), sz); return BDecode(&buf); } diff --git a/test/crypto/test_llarp_crypto_types.cpp b/test/crypto/test_llarp_crypto_types.cpp new file mode 100644 index 000000000..020aca0a4 --- /dev/null +++ b/test/crypto/test_llarp_crypto_types.cpp @@ -0,0 +1,288 @@ +#include + +#include +#include + +#include +#include + +struct ToStringData +{ + llarp::PubKey::Data input; + std::string output; +}; + +struct PubKeyString : public ::testing::TestWithParam< ToStringData > +{ +}; + +TEST_P(PubKeyString, tostring) +{ + auto d = GetParam(); + llarp::PubKey key(d.input); + + ASSERT_EQ(key.ToString(), d.output); +} + +TEST_P(PubKeyString, fromstring) +{ + auto d = GetParam(); + + llarp::PubKey key; + + ASSERT_TRUE(key.FromString(d.output)); + ASSERT_EQ(key, llarp::PubKey(d.input)); +} + +llarp::PubKey::Data empty = {}; +llarp::PubKey::Data full = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +// clang-format off +ToStringData toStringData[] = { + {empty, "0000000000000000000000000000000000000000000000000000000000000000"}, + {full, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}, +}; +// clang-format on + +INSTANTIATE_TEST_CASE_P(TestCryptoTypes, PubKeyString, + ::testing::ValuesIn(toStringData)); + +// Concerns +// - file missing +// - file empty +// - file too small +// - file too large +// - raw buffer +// - bencoded + +struct TestCryptoTypesSecret : public ::testing::Test +{ + std::string filename; + fs::path p; + + TestCryptoTypesSecret() : filename(llarp::test::randFilename()), p(filename) + { + } +}; + +TEST_F(TestCryptoTypesSecret, secret_key_from_file_missing) +{ + // Verify loading an empty file fails cleanly. + ASSERT_FALSE(fs::exists(fs::status(p))); + + llarp::SecretKey key; + ASSERT_FALSE(key.LoadFromFile(filename.c_str())); + + // Verify we didn't create a file + ASSERT_FALSE(fs::exists(fs::status(p))); +} + +TEST_F(TestCryptoTypesSecret, secret_key_from_file_empty) +{ + // Verify loading an empty file fails cleanly. + ASSERT_FALSE(fs::exists(fs::status(p))); + + // Create empty file + std::fstream f; + f.open(filename, std::ios::out | std::ios::binary); + f.close(); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + ASSERT_FALSE(key.LoadFromFile(filename.c_str())); + + // Verify we didn't delete the file + ASSERT_TRUE(fs::exists(fs::status(fs::path(filename)))); +} + +TEST_F(TestCryptoTypesSecret, secret_key_from_file_smaller) +{ + // Verify loading a file which is too small fails cleanly. + ASSERT_FALSE(fs::exists(fs::status(p))); + + // Create empty file + std::fstream f; + f.open(filename, std::ios::out | std::ios::binary); + std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE / 2, + 0xAA); + f.close(); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + ASSERT_FALSE(key.LoadFromFile(filename.c_str())); + + // Verify we didn't delete the file + ASSERT_TRUE(fs::exists(fs::status(fs::path(filename)))); +} + +TEST_F(TestCryptoTypesSecret, secret_key_from_file_smaller_bencode) +{ + // Verify loading a file which is too small fails cleanly. + ASSERT_FALSE(fs::exists(fs::status(p))); + + // Create empty file + std::fstream f; + f.open(filename, std::ios::out | std::ios::binary); + f.write("32:", 3); + std::fill_n(std::ostream_iterator< byte_t >(f), 32, 0xAA); + f.close(); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + ASSERT_FALSE(key.LoadFromFile(filename.c_str())); + + // Verify we didn't delete the file + ASSERT_TRUE(fs::exists(fs::status(fs::path(filename)))); +} + +TEST_F(TestCryptoTypesSecret, secret_key_from_file_smaller_corrupt_bencode) +{ + // Verify loading a file which is too small + corrupt fails cleanly. + ASSERT_FALSE(fs::exists(fs::status(p))); + + // Create empty file + std::fstream f; + f.open(filename, std::ios::out | std::ios::binary); + f.write("256:", 4); + std::fill_n(std::ostream_iterator< byte_t >(f), 32, 0xAA); + f.close(); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + ASSERT_FALSE(key.LoadFromFile(filename.c_str())); + + // Verify we didn't delete the file + ASSERT_TRUE(fs::exists(fs::status(fs::path(filename)))); +} + +TEST_F(TestCryptoTypesSecret, secret_key_from_file_larger) +{ + // Verify loading a file which is too large fails cleanly. + ASSERT_FALSE(fs::exists(fs::status(p))); + + // Create empty file + std::fstream f; + f.open(filename, std::ios::out | std::ios::binary); + std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE * 2, + 0xAA); + f.close(); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + ASSERT_FALSE(key.LoadFromFile(filename.c_str())); + + // Verify we didn't delete the file + ASSERT_TRUE(fs::exists(fs::status(fs::path(filename)))); +} + +TEST_F(TestCryptoTypesSecret, secret_key_from_file_larger_bencode) +{ + // Verify loading a file which is too large fails cleanly. + ASSERT_FALSE(fs::exists(fs::status(p))); + + // Create empty file + std::fstream f; + f.open(filename, std::ios::out | std::ios::binary); + f.write("256:", 4); + std::fill_n(std::ostream_iterator< byte_t >(f), 256, 0xAA); + f.close(); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + ASSERT_FALSE(key.LoadFromFile(filename.c_str())); + + // Verify we didn't delete the file + ASSERT_TRUE(fs::exists(fs::status(fs::path(filename)))); +} + +TEST_F(TestCryptoTypesSecret, secret_key_from_file_happy_raw) +{ + // Verify loading a valid raw file succeeds. + ASSERT_FALSE(fs::exists(fs::status(p))); + + // Create empty file + std::fstream f; + f.open(filename, std::ios::out | std::ios::binary); + std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE, 0xAA); + f.close(); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + ASSERT_TRUE(key.LoadFromFile(filename.c_str())); + + // Verify we didn't delete the file + ASSERT_TRUE(fs::exists(fs::status(fs::path(filename)))); +} + +TEST_F(TestCryptoTypesSecret, secret_key_from_file_happy_bencode) +{ + // Verify loading a valid bencoded file succeeds. + ASSERT_FALSE(fs::exists(fs::status(p))); + + // Create empty file + std::fstream f; + f.open(filename, std::ios::out | std::ios::binary); + f.write("64:", 4); + std::fill_n(std::ostream_iterator< byte_t >(f), llarp::SecretKey::SIZE, 0xAA); + f.close(); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + ASSERT_TRUE(key.LoadFromFile(filename.c_str())); + + // Verify we didn't delete the file + ASSERT_TRUE(fs::exists(fs::status(fs::path(filename)))); +} + +// Save to file + +// Concerns +// - file not writeable +// - happy path + +TEST_F(TestCryptoTypesSecret, secret_key_to_missing_file) +{ + // Verify writing to an unwritable file fails. + // Assume we're not running as root, so can't write to /dev/ + filename = "/dev/" + filename; + p = filename; + ASSERT_FALSE(fs::exists(fs::status(p))); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + ASSERT_FALSE(key.SaveToFile(filename.c_str())); + + // Verify we didn't create the file + ASSERT_FALSE(fs::exists(fs::status(fs::path(filename)))); +} + +TEST_F(TestCryptoTypesSecret, secret_key_to_file) +{ + ASSERT_FALSE(fs::exists(fs::status(p))); + + llarp::test::FileGuard guard(p); + + llarp::SecretKey key; + key.Randomize(); + ASSERT_TRUE(key.SaveToFile(filename.c_str())); + + // Verify we created the file + ASSERT_TRUE(fs::exists(fs::status(fs::path(filename)))); + + llarp::SecretKey other; + other.LoadFromFile(filename.c_str()); + + ASSERT_EQ(other, key); +} diff --git a/test/test_llarp_router.cpp b/test/test_llarp_router.cpp index c327abc05..9edcd0ddc 100644 --- a/test/test_llarp_router.cpp +++ b/test/test_llarp_router.cpp @@ -5,49 +5,9 @@ #include #include +#include #include -std::string -randFilename() -{ - static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; - - std::random_device rd; - std::uniform_int_distribution< size_t > dist{0, sizeof(alphabet) - 2}; - - std::string filename; - for(size_t i = 0; i < 5; ++i) - { - filename.push_back(alphabet[dist(rd)]); - } - - filename.push_back('.'); - - for(size_t i = 0; i < 5; ++i) - { - filename.push_back(alphabet[dist(rd)]); - } - - return filename; -} - -struct FileGuard -{ - const fs::path &p; - - explicit FileGuard(const fs::path &_p) : p(_p) - { - } - - ~FileGuard() - { - if(fs::exists(fs::status(p))) - { - fs::remove(p); - } - } -}; - using FindOrCreateFunc = std::function< bool(llarp::Crypto *, const fs::path &, llarp::SecretKey &) >; @@ -69,10 +29,10 @@ TEST_P(FindOrCreate, find_file_missing) { // File missing. Should create a new file llarp::SecretKey key; - fs::path p = randFilename(); + fs::path p = llarp::test::randFilename(); ASSERT_FALSE(fs::exists(fs::status(p))); - FileGuard guard(p); + llarp::test::FileGuard guard(p); ASSERT_TRUE(GetParam()(&crypto, p, key)); ASSERT_TRUE(fs::exists(fs::status(p))); @@ -83,14 +43,14 @@ TEST_P(FindOrCreate, find_file_empty) { // File empty. llarp::SecretKey key; - fs::path p = randFilename(); + fs::path p = llarp::test::randFilename(); ASSERT_FALSE(fs::exists(fs::status(p))); std::fstream f; f.open(p.string(), std::ios::out); f.close(); - FileGuard guard(p); + llarp::test::FileGuard guard(p); ASSERT_FALSE(GetParam()(&crypto, p, key)); // Verify we didn't delete an invalid file @@ -101,7 +61,7 @@ TEST_P(FindOrCreate, happy_path) { // happy path. llarp::SecretKey key; - fs::path p = randFilename(); + fs::path p = llarp::test::randFilename(); ASSERT_FALSE(fs::exists(fs::status(p))); std::ofstream f; @@ -109,7 +69,7 @@ TEST_P(FindOrCreate, happy_path) std::fill_n(std::ostream_iterator< byte_t >(f), key.size(), 0x20); f.close(); - FileGuard guard(p); + llarp::test::FileGuard guard(p); ASSERT_TRUE(GetParam()(&crypto, p, key)); // Verify we didn't delete the file diff --git a/test/test_util.cpp b/test/test_util.cpp new file mode 100644 index 000000000..100af14a9 --- /dev/null +++ b/test/test_util.cpp @@ -0,0 +1,33 @@ +#include + +#include + +namespace llarp +{ + namespace test + { + std::string + randFilename() + { + static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz"; + + std::random_device rd; + std::uniform_int_distribution< size_t > dist{0, sizeof(alphabet) - 2}; + + std::string filename; + for(size_t i = 0; i < 5; ++i) + { + filename.push_back(alphabet[dist(rd)]); + } + + filename.push_back('.'); + + for(size_t i = 0; i < 5; ++i) + { + filename.push_back(alphabet[dist(rd)]); + } + + return filename; + } + } // namespace test +} // namespace llarp diff --git a/test/test_util.hpp b/test/test_util.hpp new file mode 100644 index 000000000..b9d320601 --- /dev/null +++ b/test/test_util.hpp @@ -0,0 +1,33 @@ +#ifndef TEST_UTIL_HPP +#define TEST_UTIL_HPP + +#include + +namespace llarp +{ + namespace test + { + std::string + randFilename(); + + struct FileGuard + { + const fs::path &p; + + explicit FileGuard(const fs::path &_p) : p(_p) + { + } + + ~FileGuard() + { + if(fs::exists(fs::status(p))) + { + fs::remove(p); + } + } + }; + + } // namespace test +} // namespace llarp + +#endif