#include #include "CertVerifier.h" #include "CommonSocketControl.h" #include "SSLTokensCache.h" #include "TransportSecurityInfo.h" #include "gtest/gtest.h" #include "mozilla/Preferences.h" #include "nsITransportSecurityInfo.h" #include "nsIWebProgressListener.h" #include "nsIX509Cert.h" #include "nsIX509CertDB.h" #include "nsServiceManagerUtils.h" #include "sslproto.h" static already_AddRefed createDummySocketControl() { nsCOMPtr certDB(do_GetService(NS_X509CERTDB_CONTRACTID)); EXPECT_TRUE(certDB); nsLiteralCString base64( "MIIBbjCCARWgAwIBAgIUOyCxVVqw03yUxKSfSojsMF8K/" "ikwCgYIKoZIzj0EAwIwHTEbMBkGA1UEAwwScm9vdF9zZWNwMjU2azFfMjU2MCIYDzIwMjAxM" "TI3MDAwMDAwWhgPMjAyMzAyMDUwMDAwMDBaMC8xLTArBgNVBAMMJGludF9zZWNwMjU2cjFfM" "jU2LXJvb3Rfc2VjcDI1NmsxXzI1NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE+/" "u7th4Pj5saYKWayHBOLsBQtCPjz3LpI/" "LE95S0VcKmnSM0VsNsQRnQcG4A7tyNGTkNeZG3stB6ME6qBKpsCjHTAbMAwGA1UdEwQFMAMB" "Af8wCwYDVR0PBAQDAgEGMAoGCCqGSM49BAMCA0cAMEQCIFuwodUwyOUnIR4KN5ZCSrU7y4iz" "4/1EWRdHm5kWKi8dAiB6Ixn9sw3uBVbyxnQKYqGnOwM+qLOkJK0W8XkIE3n5sg=="); nsCOMPtr cert; EXPECT_TRUE(NS_SUCCEEDED( certDB->ConstructX509FromBase64(base64, getter_AddRefs(cert)))); EXPECT_TRUE(cert); nsTArray> succeededCertChain; for (size_t i = 0; i < 3; i++) { nsTArray certDER; EXPECT_TRUE(NS_SUCCEEDED(cert->GetRawDER(certDER))); succeededCertChain.AppendElement(std::move(certDER)); } RefPtr socketControl( new CommonSocketControl(nsLiteralCString("example.com"), 433, 0)); socketControl->SetServerCert(cert, mozilla::psm::EVStatus::NotEV); socketControl->SetSucceededCertChain(std::move(succeededCertChain)); return socketControl.forget(); } static auto MakeTestData(const size_t aDataSize) { auto data = nsTArray(); data.SetLength(aDataSize); std::iota(data.begin(), data.end(), 0); return data; } static void putToken(const nsACString& aKey, uint32_t aSize) { RefPtr socketControl = createDummySocketControl(); nsTArray token = MakeTestData(aSize); nsresult rv = mozilla::net::SSLTokensCache::Put(aKey, token.Elements(), aSize, socketControl, aSize); ASSERT_EQ(rv, NS_OK); } static void getAndCheckResult(const nsACString& aKey, uint32_t aExpectedSize) { nsTArray result; mozilla::net::SessionCacheInfo unused; nsresult rv = mozilla::net::SSLTokensCache::Get(aKey, result, unused); ASSERT_EQ(rv, NS_OK); ASSERT_EQ(result.Length(), (size_t)aExpectedSize); } TEST(TestTokensCache, SinglePut) { mozilla::net::SSLTokensCache::Clear(); mozilla::Preferences::SetInt("network.ssl_tokens_cache_records_per_entry", 1); mozilla::Preferences::SetBool("network.ssl_tokens_cache_use_only_once", false); putToken("anon:www.example.com:443"_ns, 100); nsTArray result; mozilla::net::SessionCacheInfo unused; uint64_t id = 0; nsresult rv = mozilla::net::SSLTokensCache::Get("anon:www.example.com:443"_ns, result, unused, &id); ASSERT_EQ(rv, NS_OK); ASSERT_EQ(result.Length(), (size_t)100); ASSERT_EQ(id, (uint64_t)1); rv = mozilla::net::SSLTokensCache::Get("anon:www.example.com:443"_ns, result, unused, &id); ASSERT_EQ(rv, NS_OK); mozilla::Preferences::SetBool("network.ssl_tokens_cache_use_only_once", true); // network.ssl_tokens_cache_use_only_once is true, so the record will be // removed after SSLTokensCache::Get below. rv = mozilla::net::SSLTokensCache::Get("anon:www.example.com:443"_ns, result, unused); ASSERT_EQ(rv, NS_OK); rv = mozilla::net::SSLTokensCache::Get("anon:www.example.com:443"_ns, result, unused); ASSERT_EQ(rv, NS_ERROR_NOT_AVAILABLE); } TEST(TestTokensCache, MultiplePut) { mozilla::net::SSLTokensCache::Clear(); mozilla::Preferences::SetInt("network.ssl_tokens_cache_records_per_entry", 3); putToken("anon:www.example1.com:443"_ns, 300); // This record will be removed because // "network.ssl_tokens_cache_records_per_entry" is 3. putToken("anon:www.example1.com:443"_ns, 100); putToken("anon:www.example1.com:443"_ns, 200); putToken("anon:www.example1.com:443"_ns, 400); // Test if records are ordered by the expiration time getAndCheckResult("anon:www.example1.com:443"_ns, 200); getAndCheckResult("anon:www.example1.com:443"_ns, 300); getAndCheckResult("anon:www.example1.com:443"_ns, 400); } TEST(TestTokensCache, RemoveAll) { mozilla::net::SSLTokensCache::Clear(); mozilla::Preferences::SetInt("network.ssl_tokens_cache_records_per_entry", 3); putToken("anon:www.example1.com:443"_ns, 100); putToken("anon:www.example1.com:443"_ns, 200); putToken("anon:www.example1.com:443"_ns, 300); putToken("anon:www.example2.com:443"_ns, 100); putToken("anon:www.example2.com:443"_ns, 200); putToken("anon:www.example2.com:443"_ns, 300); nsTArray result; mozilla::net::SessionCacheInfo unused; nsresult rv = mozilla::net::SSLTokensCache::Get( "anon:www.example1.com:443"_ns, result, unused); ASSERT_EQ(rv, NS_OK); ASSERT_EQ(result.Length(), (size_t)100); rv = mozilla::net::SSLTokensCache::RemoveAll("anon:www.example1.com:443"_ns); ASSERT_EQ(rv, NS_OK); rv = mozilla::net::SSLTokensCache::Get("anon:www.example1.com:443"_ns, result, unused); ASSERT_EQ(rv, NS_ERROR_NOT_AVAILABLE); rv = mozilla::net::SSLTokensCache::Get("anon:www.example2.com:443"_ns, result, unused); ASSERT_EQ(rv, NS_OK); ASSERT_EQ(result.Length(), (size_t)100); } TEST(TestTokensCache, Eviction) { mozilla::net::SSLTokensCache::Clear(); mozilla::Preferences::SetInt("network.ssl_tokens_cache_records_per_entry", 3); mozilla::Preferences::SetInt("network.ssl_tokens_cache_capacity", 8); putToken("anon:www.example2.com:443"_ns, 300); putToken("anon:www.example2.com:443"_ns, 400); putToken("anon:www.example2.com:443"_ns, 500); // The one has expiration time "300" will be removed because we only allow 3 // records per entry. putToken("anon:www.example2.com:443"_ns, 600); putToken("anon:www.example3.com:443"_ns, 600); putToken("anon:www.example3.com:443"_ns, 500); // The one has expiration time "400" was evicted, so we get "500". getAndCheckResult("anon:www.example2.com:443"_ns, 500); }