/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 "gtest/gtest.h" #include "mozilla/gtest/MozAssertions.h" #include "mozilla/security/lockstore/lockstore_ffi_generated.h" #include "nsCOMPtr.h" #include "nsDirectoryServiceDefs.h" #include "nsIFile.h" #include "nsString.h" #include "nsTArray.h" using mozilla::security::lockstore::lockstore_keystore_add_security_level; using mozilla::security::lockstore::lockstore_keystore_close; using mozilla::security::lockstore::lockstore_keystore_create_dek; using mozilla::security::lockstore::lockstore_keystore_delete_dek; using mozilla::security::lockstore::lockstore_keystore_get_dek; using mozilla::security::lockstore::lockstore_keystore_list_collections; using mozilla::security::lockstore::lockstore_keystore_open; using mozilla::security::lockstore::lockstore_keystore_remove_security_level; using mozilla::security::lockstore::LockstoreKeystoreHandle; using mozilla::security::lockstore::LockstoreSecurityLevel; class LockstoreKeystoreTest : public ::testing::Test { protected: nsCOMPtr mTmpDir; nsAutoCString mProfilePath; LockstoreKeystoreHandle* mKeystore = nullptr; void SetUp() override { nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mTmpDir)); ASSERT_NS_SUCCEEDED(rv); rv = mTmpDir->AppendNative("lockstore_ks_test"_ns); ASSERT_NS_SUCCEEDED(rv); rv = mTmpDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700); ASSERT_NS_SUCCEEDED(rv); nsAutoString profilePathWide; rv = mTmpDir->GetPath(profilePathWide); ASSERT_NS_SUCCEEDED(rv); mProfilePath = NS_ConvertUTF16toUTF8(profilePathWide); } void TearDown() override { if (mKeystore) { EXPECT_NS_SUCCEEDED(lockstore_keystore_close(mKeystore)); mKeystore = nullptr; } if (mTmpDir) { mTmpDir->Remove(true); } } }; TEST_F(LockstoreKeystoreTest, OpenAndClose) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); ASSERT_NE(mKeystore, nullptr); nsresult rvClose = lockstore_keystore_close(mKeystore); mKeystore = nullptr; ASSERT_NS_SUCCEEDED(rvClose); } TEST_F(LockstoreKeystoreTest, OpenEmptyPath) { nsAutoCString empty; nsresult rv = lockstore_keystore_open(&empty, &mKeystore); ASSERT_EQ(rv, NS_ERROR_INVALID_ARG); ASSERT_EQ(mKeystore, nullptr); } TEST_F(LockstoreKeystoreTest, CreateAndListDek) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("mycoll"); rv = lockstore_keystore_create_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); nsTArray collections; rv = lockstore_keystore_list_collections(mKeystore, &collections); ASSERT_NS_SUCCEEDED(rv); ASSERT_EQ(collections.Length(), 1u); EXPECT_EQ(collections[0], coll); } TEST_F(LockstoreKeystoreTest, CreateDekEmptyCollection) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); nsAutoCString empty; rv = lockstore_keystore_create_dek(mKeystore, &empty, LockstoreSecurityLevel::LocalKey, false); ASSERT_EQ(rv, NS_ERROR_INVALID_ARG); } TEST_F(LockstoreKeystoreTest, CreateDekDuplicate) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("dup"); rv = lockstore_keystore_create_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); rv = lockstore_keystore_create_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, false); ASSERT_EQ(rv, NS_ERROR_FAILURE); } TEST_F(LockstoreKeystoreTest, GetDekExtractable) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("extract"); rv = lockstore_keystore_create_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, true); ASSERT_NS_SUCCEEDED(rv); nsTArray dek; rv = lockstore_keystore_get_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, &dek); ASSERT_NS_SUCCEEDED(rv); EXPECT_GT(dek.Length(), 0u); } TEST_F(LockstoreKeystoreTest, GetDekEmptyCollection) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); nsAutoCString empty; nsTArray dek; rv = lockstore_keystore_get_dek(mKeystore, &empty, LockstoreSecurityLevel::LocalKey, &dek); ASSERT_EQ(rv, NS_ERROR_INVALID_ARG); } TEST_F(LockstoreKeystoreTest, GetDekNonexistent) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("nosuch"); nsTArray dek; rv = lockstore_keystore_get_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, &dek); ASSERT_EQ(rv, NS_ERROR_NOT_AVAILABLE); } TEST_F(LockstoreKeystoreTest, GetDekNotExtractable) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("noextract"); rv = lockstore_keystore_create_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); nsTArray dek; rv = lockstore_keystore_get_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, &dek); ASSERT_EQ(rv, NS_ERROR_NOT_AVAILABLE); } TEST_F(LockstoreKeystoreTest, DeleteDek) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("todelete"); rv = lockstore_keystore_create_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); rv = lockstore_keystore_delete_dek(mKeystore, &coll); ASSERT_NS_SUCCEEDED(rv); nsTArray collections; rv = lockstore_keystore_list_collections(mKeystore, &collections); ASSERT_NS_SUCCEEDED(rv); EXPECT_EQ(collections.Length(), 0u); } TEST_F(LockstoreKeystoreTest, DeleteDekEmptyCollection) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); nsAutoCString empty; rv = lockstore_keystore_delete_dek(mKeystore, &empty); ASSERT_EQ(rv, NS_ERROR_INVALID_ARG); } TEST_F(LockstoreKeystoreTest, DeleteDekNonexistent) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("nosuch"); rv = lockstore_keystore_delete_dek(mKeystore, &coll); ASSERT_EQ(rv, NS_ERROR_NOT_AVAILABLE); } TEST_F(LockstoreKeystoreTest, ListCollectionsEmpty) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); nsTArray collections; rv = lockstore_keystore_list_collections(mKeystore, &collections); ASSERT_NS_SUCCEEDED(rv); EXPECT_EQ(collections.Length(), 0u); } TEST_F(LockstoreKeystoreTest, ListMultipleCollections) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString alpha("alpha"); const nsCString beta("beta"); const nsCString gamma("gamma"); rv = lockstore_keystore_create_dek(mKeystore, &alpha, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); rv = lockstore_keystore_create_dek(mKeystore, &beta, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); rv = lockstore_keystore_create_dek(mKeystore, &gamma, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); nsTArray collections; rv = lockstore_keystore_list_collections(mKeystore, &collections); ASSERT_NS_SUCCEEDED(rv); ASSERT_EQ(collections.Length(), 3u); EXPECT_TRUE(collections.Contains(alpha)); EXPECT_TRUE(collections.Contains(beta)); EXPECT_TRUE(collections.Contains(gamma)); } TEST_F(LockstoreKeystoreTest, PersistenceAcrossReopen) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("persist"); rv = lockstore_keystore_create_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); ASSERT_NS_SUCCEEDED(lockstore_keystore_close(mKeystore)); mKeystore = nullptr; rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); nsTArray collections; rv = lockstore_keystore_list_collections(mKeystore, &collections); ASSERT_NS_SUCCEEDED(rv); ASSERT_EQ(collections.Length(), 1u); EXPECT_EQ(collections[0], coll); } TEST_F(LockstoreKeystoreTest, AddSecurityLevelEmptyCollection) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); nsAutoCString empty; rv = lockstore_keystore_add_security_level(mKeystore, &empty, LockstoreSecurityLevel::LocalKey, LockstoreSecurityLevel::LocalKey); ASSERT_EQ(rv, NS_ERROR_INVALID_ARG); } TEST_F(LockstoreKeystoreTest, AddSecurityLevelNonexistentCollection) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("nosuch"); rv = lockstore_keystore_add_security_level(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, LockstoreSecurityLevel::LocalKey); ASSERT_EQ(rv, NS_ERROR_NOT_AVAILABLE); } TEST_F(LockstoreKeystoreTest, AddSecurityLevelDuplicate) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("adddup"); rv = lockstore_keystore_create_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); rv = lockstore_keystore_add_security_level(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, LockstoreSecurityLevel::LocalKey); ASSERT_EQ(rv, NS_ERROR_FAILURE); } TEST_F(LockstoreKeystoreTest, RemoveSecurityLevelEmptyCollection) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); nsAutoCString empty; rv = lockstore_keystore_remove_security_level( mKeystore, &empty, LockstoreSecurityLevel::LocalKey); ASSERT_EQ(rv, NS_ERROR_INVALID_ARG); } TEST_F(LockstoreKeystoreTest, RemoveSecurityLevelNonexistentCollection) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("nosuch"); rv = lockstore_keystore_remove_security_level( mKeystore, &coll, LockstoreSecurityLevel::LocalKey); ASSERT_EQ(rv, NS_ERROR_NOT_AVAILABLE); } TEST_F(LockstoreKeystoreTest, RemoveSecurityLevelLastRemaining) { nsresult rv = lockstore_keystore_open(&mProfilePath, &mKeystore); ASSERT_NS_SUCCEEDED(rv); const nsCString coll("removelast"); rv = lockstore_keystore_create_dek(mKeystore, &coll, LockstoreSecurityLevel::LocalKey, false); ASSERT_NS_SUCCEEDED(rv); rv = lockstore_keystore_remove_security_level( mKeystore, &coll, LockstoreSecurityLevel::LocalKey); ASSERT_EQ(rv, NS_ERROR_FAILURE); }