#include "nix/store/tests/https-store.hh" #include namespace nix::testing { void TestHttpBinaryCacheStore::init() { BinaryCacheStore::init(); } ref TestHttpBinaryCacheStoreConfig::openTestStore(ref fileTransfer) const { auto store = make_ref( ref{// FIXME we shouldn't actually need a mutable config std::const_pointer_cast(shared_from_this())}, fileTransfer); store->init(); return store; } void HttpsBinaryCacheStoreTest::openssl(Strings args) { runProgram("openssl", /*lookupPath=*/true, args); } void HttpsBinaryCacheStoreTest::SetUp() { LibStoreNetworkTest::SetUp(); #ifdef _WIN32 GTEST_SKIP() << "HTTPS store tests are not supported on Windows"; #endif tmpDir = createTempDir(); cacheDir = tmpDir / "cache"; delTmpDir = std::make_unique(tmpDir); localCacheStore = make_ref("file", cacheDir.string(), LocalBinaryCacheStoreConfig::Params{}) ->openStore(); caCert = tmpDir / "ca.crt"; caKey = tmpDir / "ca.key"; serverCert = tmpDir / "server.crt"; serverKey = tmpDir / "server.key"; clientCert = tmpDir / "client.crt"; clientKey = tmpDir / "client.key"; // clang-format off openssl({"ecparam", "-genkey", "-name", "prime256v1", "-out", caKey.string()}); openssl({"req", "-new", "-x509", "-days", "1", "-key", caKey.string(), "-out", caCert.string(), "-subj", "/CN=TestCA"}); auto serverExtFile = tmpDir / "server.ext"; writeFile(serverExtFile, "subjectAltName=DNS:localhost,IP:127.0.0.1"); openssl({"ecparam", "-genkey", "-name", "prime256v1", "-out", serverKey.string()}); openssl({"req", "-new", "-key", serverKey.string(), "-out", (tmpDir / "server.csr").string(), "-subj", "/CN=localhost", "-addext", "subjectAltName=DNS:localhost,IP:127.0.0.1"}); openssl({"x509", "-req", "-in", (tmpDir / "server.csr").string(), "-CA", caCert.string(), "-CAkey", caKey.string(), "-CAcreateserial", "-out", serverCert.string(), "-days", "1", "-extfile", serverExtFile.string()}); openssl({"ecparam", "-genkey", "-name", "prime256v1", "-out", clientKey.string()}); openssl({"req", "-new", "-key", clientKey.string(), "-out", (tmpDir / "client.csr").string(), "-subj", "/CN=TestClient"}); openssl({"x509", "-req", "-in", (tmpDir / "client.csr").string(), "-CA", caCert.string(), "-CAkey", caKey.string(), "-CAcreateserial", "-out", clientCert.string(), "-days", "1"}); // clang-format on #ifndef _WIN32 /* FIXME: Can't yet start processes on windows */ auto args = serverArgs(); serverPid = startProcess( [&] { if (chdir(cacheDir.c_str()) == -1) _exit(1); std::vector argv; argv.push_back(const_cast("openssl")); for (auto & a : args) argv.push_back(const_cast(a.c_str())); argv.push_back(nullptr); execvp("openssl", argv.data()); _exit(1); }, {.dieWithParent = true}); #endif /* As an optimization, sleep for a bit to allow the server to come up to avoid retrying when connecting. This won't make the tests fail, but does make them run faster. We don't need to overcomplicate by waiting for the port explicitly - this is enough. */ std::this_thread::sleep_for(std::chrono::milliseconds(50)); /* Create custom FileTransferSettings with our test CA certificate. This avoids mutating global settings. */ testFileTransferSettings = std::make_unique(); testFileTransferSettings->caFile = caCert; testFileTransfer = makeFileTransfer(*testFileTransferSettings); } void HttpsBinaryCacheStoreTest::TearDown() { serverPid.kill(); delTmpDir.reset(); testFileTransferSettings.reset(); } std::vector HttpsBinaryCacheStoreTest::serverArgs() { return { "s_server", "-accept", std::to_string(port), "-cert", serverCert.string(), "-key", serverKey.string(), "-WWW", /* Serve from current directory. */ "-quiet", }; } std::vector HttpsBinaryCacheStoreMtlsTest::serverArgs() { auto args = HttpsBinaryCacheStoreTest::serverArgs(); /* With the -Verify option the client must supply a certificate or an error occurs, which is not the case with -verify. */ args.insert(args.end(), {"-CAfile", caCert.string(), "-Verify", "1", "-verify_return_error"}); return args; } ref HttpsBinaryCacheStoreTest::makeConfig() { auto res = make_ref( ParsedURL{ .scheme = "https", .authority = ParsedURL::Authority{ .host = "localhost", .port = port, }, }, TestHttpBinaryCacheStoreConfig::Params{}); res->pathInfoCacheSize = 0; /* We don't want any caching in tests. */ return res; } ref HttpsBinaryCacheStoreTest::openStore(ref config) { return config->openTestStore(ref{testFileTransfer}); } } // namespace nix::testing