зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1842303 - remove some unused nsIOSKeyStore functions r=nkulatova
Differential Revision: https://phabricator.services.mozilla.com/D183054
This commit is contained in:
Родитель
3efc235517
Коммит
f149487bb4
|
@ -39,17 +39,6 @@ CredentialManagerSecret::CredentialManagerSecret() {}
|
||||||
|
|
||||||
CredentialManagerSecret::~CredentialManagerSecret() {}
|
CredentialManagerSecret::~CredentialManagerSecret() {}
|
||||||
|
|
||||||
nsresult CredentialManagerSecret::Lock() {
|
|
||||||
// The Windows credential manager can't be locked.
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult CredentialManagerSecret::Unlock() {
|
|
||||||
// The Windows credential manager is always unlocked when the user is logged
|
|
||||||
// in.
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult CredentialManagerSecret::StoreSecret(const nsACString& aSecret,
|
nsresult CredentialManagerSecret::StoreSecret(const nsACString& aSecret,
|
||||||
const nsACString& aLabel) {
|
const nsACString& aLabel) {
|
||||||
if (aSecret.Length() > CRED_MAX_CREDENTIAL_BLOB_SIZE) {
|
if (aSecret.Length() > CRED_MAX_CREDENTIAL_BLOB_SIZE) {
|
||||||
|
|
|
@ -19,8 +19,6 @@ class CredentialManagerSecret final : public AbstractOSKeyStore {
|
||||||
virtual nsresult StoreSecret(const nsACString& secret,
|
virtual nsresult StoreSecret(const nsACString& secret,
|
||||||
const nsACString& label) override;
|
const nsACString& label) override;
|
||||||
virtual nsresult DeleteSecret(const nsACString& label) override;
|
virtual nsresult DeleteSecret(const nsACString& label) override;
|
||||||
virtual nsresult Lock() override;
|
|
||||||
virtual nsresult Unlock() override;
|
|
||||||
|
|
||||||
virtual ~CredentialManagerSecret();
|
virtual ~CredentialManagerSecret();
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,32 +21,6 @@ KeychainSecret::KeychainSecret() {}
|
||||||
|
|
||||||
KeychainSecret::~KeychainSecret() {}
|
KeychainSecret::~KeychainSecret() {}
|
||||||
|
|
||||||
nsresult KeychainSecret::Lock() {
|
|
||||||
// https://developer.apple.com/documentation/security/1402180-seckeychainlock
|
|
||||||
// Passing `nullptr` locks the default keychain.
|
|
||||||
OSStatus rv = SecKeychainLock(nullptr);
|
|
||||||
if (rv != errSecSuccess) {
|
|
||||||
MOZ_LOG(gKeychainSecretLog, LogLevel::Debug,
|
|
||||||
("SecKeychainLock failed: %d", rv));
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult KeychainSecret::Unlock() {
|
|
||||||
// https://developer.apple.com/documentation/security/1400341-seckeychainunlock
|
|
||||||
// This attempts to unlock the default keychain. Using `false` indicates we
|
|
||||||
// aren't passing in a password (if the keychain is locked, a dialog will
|
|
||||||
// appear for the user).
|
|
||||||
OSStatus rv = SecKeychainUnlock(nullptr, 0, nullptr, false);
|
|
||||||
if (rv != errSecSuccess) {
|
|
||||||
MOZ_LOG(gKeychainSecretLog, LogLevel::Debug,
|
|
||||||
("SecKeychainUnlock failed: %d", rv));
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedCFType<CFStringRef> MozillaStringToCFString(const nsACString& stringIn) {
|
ScopedCFType<CFStringRef> MozillaStringToCFString(const nsACString& stringIn) {
|
||||||
// https://developer.apple.com/documentation/corefoundation/1543419-cfstringcreatewithbytes
|
// https://developer.apple.com/documentation/corefoundation/1543419-cfstringcreatewithbytes
|
||||||
ScopedCFType<CFStringRef> stringOut(CFStringCreateWithBytes(
|
ScopedCFType<CFStringRef> stringOut(CFStringCreateWithBytes(
|
||||||
|
|
|
@ -40,8 +40,6 @@ class KeychainSecret final : public AbstractOSKeyStore {
|
||||||
virtual nsresult StoreSecret(const nsACString& secret,
|
virtual nsresult StoreSecret(const nsACString& secret,
|
||||||
const nsACString& label) override;
|
const nsACString& label) override;
|
||||||
virtual nsresult DeleteSecret(const nsACString& label) override;
|
virtual nsresult DeleteSecret(const nsACString& label) override;
|
||||||
virtual nsresult Lock() override;
|
|
||||||
virtual nsresult Unlock() override;
|
|
||||||
|
|
||||||
virtual ~KeychainSecret();
|
virtual ~KeychainSecret();
|
||||||
};
|
};
|
||||||
|
|
|
@ -84,10 +84,6 @@ typedef SecretCollection* (*secret_collection_for_alias_sync_fn)(
|
||||||
GError**);
|
GError**);
|
||||||
typedef SecretService* (*secret_service_get_sync_fn)(SecretServiceFlags,
|
typedef SecretService* (*secret_service_get_sync_fn)(SecretServiceFlags,
|
||||||
GCancellable*, GError**);
|
GCancellable*, GError**);
|
||||||
typedef gint (*secret_service_lock_sync_fn)(SecretService*, GList*,
|
|
||||||
GCancellable*, GList**, GError**);
|
|
||||||
typedef gint (*secret_service_unlock_sync_fn)(SecretService*, GList*,
|
|
||||||
GCancellable*, GList**, GError**);
|
|
||||||
typedef gboolean (*secret_password_clear_sync_fn)(const SecretSchema*,
|
typedef gboolean (*secret_password_clear_sync_fn)(const SecretSchema*,
|
||||||
GCancellable*, GError**, ...);
|
GCancellable*, GError**, ...);
|
||||||
typedef gchar* (*secret_password_lookup_sync_fn)(const SecretSchema*,
|
typedef gchar* (*secret_password_lookup_sync_fn)(const SecretSchema*,
|
||||||
|
@ -102,8 +98,6 @@ typedef GQuark (*secret_error_get_quark_fn)();
|
||||||
static secret_collection_for_alias_sync_fn secret_collection_for_alias_sync =
|
static secret_collection_for_alias_sync_fn secret_collection_for_alias_sync =
|
||||||
nullptr;
|
nullptr;
|
||||||
static secret_service_get_sync_fn secret_service_get_sync = nullptr;
|
static secret_service_get_sync_fn secret_service_get_sync = nullptr;
|
||||||
static secret_service_lock_sync_fn secret_service_lock_sync = nullptr;
|
|
||||||
static secret_service_unlock_sync_fn secret_service_unlock_sync = nullptr;
|
|
||||||
static secret_password_clear_sync_fn secret_password_clear_sync = nullptr;
|
static secret_password_clear_sync_fn secret_password_clear_sync = nullptr;
|
||||||
static secret_password_lookup_sync_fn secret_password_lookup_sync = nullptr;
|
static secret_password_lookup_sync_fn secret_password_lookup_sync = nullptr;
|
||||||
static secret_password_store_sync_fn secret_password_store_sync = nullptr;
|
static secret_password_store_sync_fn secret_password_store_sync = nullptr;
|
||||||
|
@ -142,8 +136,6 @@ nsresult MaybeLoadLibSecret() {
|
||||||
}
|
}
|
||||||
FIND_FUNCTION_SYMBOL(secret_collection_for_alias_sync);
|
FIND_FUNCTION_SYMBOL(secret_collection_for_alias_sync);
|
||||||
FIND_FUNCTION_SYMBOL(secret_service_get_sync);
|
FIND_FUNCTION_SYMBOL(secret_service_get_sync);
|
||||||
FIND_FUNCTION_SYMBOL(secret_service_lock_sync);
|
|
||||||
FIND_FUNCTION_SYMBOL(secret_service_unlock_sync);
|
|
||||||
FIND_FUNCTION_SYMBOL(secret_password_clear_sync);
|
FIND_FUNCTION_SYMBOL(secret_password_clear_sync);
|
||||||
FIND_FUNCTION_SYMBOL(secret_password_lookup_sync);
|
FIND_FUNCTION_SYMBOL(secret_password_lookup_sync);
|
||||||
FIND_FUNCTION_SYMBOL(secret_password_store_sync);
|
FIND_FUNCTION_SYMBOL(secret_password_store_sync);
|
||||||
|
@ -201,8 +193,6 @@ LibSecret::~LibSecret() {
|
||||||
if (libsecret) {
|
if (libsecret) {
|
||||||
secret_collection_for_alias_sync = nullptr;
|
secret_collection_for_alias_sync = nullptr;
|
||||||
secret_service_get_sync = nullptr;
|
secret_service_get_sync = nullptr;
|
||||||
secret_service_lock_sync = nullptr;
|
|
||||||
secret_service_unlock_sync = nullptr;
|
|
||||||
secret_password_clear_sync = nullptr;
|
secret_password_clear_sync = nullptr;
|
||||||
secret_password_lookup_sync = nullptr;
|
secret_password_lookup_sync = nullptr;
|
||||||
secret_password_store_sync = nullptr;
|
secret_password_store_sync = nullptr;
|
||||||
|
@ -250,60 +240,6 @@ nsresult GetScopedServices(ScopedSecretService& aSs,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult LibSecret::Lock() {
|
|
||||||
MOZ_ASSERT(secret_service_lock_sync);
|
|
||||||
if (!secret_service_lock_sync) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
ScopedSecretService ss;
|
|
||||||
ScopedSecretCollection sc;
|
|
||||||
if (NS_FAILED(GetScopedServices(ss, sc))) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
GError* raw_error = nullptr;
|
|
||||||
GList* collections = nullptr;
|
|
||||||
ScopedGList collectionList(g_list_append(collections, sc.get()));
|
|
||||||
int numLocked = secret_service_lock_sync(ss.get(), collectionList.get(),
|
|
||||||
nullptr, // GCancellable
|
|
||||||
nullptr, // list of locked items
|
|
||||||
&raw_error);
|
|
||||||
ScopedGError error(raw_error);
|
|
||||||
if (numLocked != 1) {
|
|
||||||
MOZ_LOG(gLibSecretLog, LogLevel::Debug,
|
|
||||||
("Couldn't lock secret collection"));
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult LibSecret::Unlock() {
|
|
||||||
MOZ_ASSERT(secret_service_unlock_sync);
|
|
||||||
if (!secret_service_unlock_sync) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
// Accessing the secret service might unlock it.
|
|
||||||
ScopedSecretService ss;
|
|
||||||
ScopedSecretCollection sc;
|
|
||||||
if (NS_FAILED(GetScopedServices(ss, sc))) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
GError* raw_error = nullptr;
|
|
||||||
GList* collections = nullptr;
|
|
||||||
ScopedGList collectionList(g_list_append(collections, sc.get()));
|
|
||||||
int numLocked = secret_service_unlock_sync(ss.get(), collectionList.get(),
|
|
||||||
nullptr, // GCancellable
|
|
||||||
nullptr, // list of unlocked items
|
|
||||||
&raw_error);
|
|
||||||
ScopedGError error(raw_error);
|
|
||||||
if (numLocked != 1) {
|
|
||||||
MOZ_LOG(gLibSecretLog, LogLevel::Debug,
|
|
||||||
("Couldn't unlock secret collection"));
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult LibSecret::StoreSecret(const nsACString& aSecret,
|
nsresult LibSecret::StoreSecret(const nsACString& aSecret,
|
||||||
const nsACString& aLabel) {
|
const nsACString& aLabel) {
|
||||||
MOZ_ASSERT(secret_password_store_sync);
|
MOZ_ASSERT(secret_password_store_sync);
|
||||||
|
|
|
@ -22,8 +22,6 @@ class LibSecret final : public AbstractOSKeyStore {
|
||||||
virtual nsresult StoreSecret(const nsACString& secret,
|
virtual nsresult StoreSecret(const nsACString& secret,
|
||||||
const nsACString& label) override;
|
const nsACString& label) override;
|
||||||
virtual nsresult DeleteSecret(const nsACString& label) override;
|
virtual nsresult DeleteSecret(const nsACString& label) override;
|
||||||
virtual nsresult Lock() override;
|
|
||||||
virtual nsresult Unlock() override;
|
|
||||||
|
|
||||||
virtual ~LibSecret();
|
virtual ~LibSecret();
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,71 +48,9 @@ nsresult NSSKeyStore::InitToken() {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult NSSKeyStoreMainThreadLock(PK11SlotInfo* aSlot) {
|
|
||||||
nsCOMPtr<nsIPK11Token> token = new nsPK11Token(aSlot);
|
|
||||||
return token->LogoutSimple();
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult NSSKeyStore::Lock() {
|
|
||||||
NS_ENSURE_STATE(mSlot);
|
|
||||||
|
|
||||||
if (!NS_IsMainThread()) {
|
|
||||||
nsCOMPtr<nsIThread> mainThread;
|
|
||||||
nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward to the main thread synchronously.
|
|
||||||
SyncRunnable::DispatchToThread(
|
|
||||||
mainThread, NS_NewRunnableFunction("NSSKeyStoreMainThreadLock",
|
|
||||||
[slot = mSlot.get()]() {
|
|
||||||
NSSKeyStoreMainThreadLock(slot);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NSSKeyStoreMainThreadLock(mSlot.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult NSSKeyStoreMainThreadUnlock(PK11SlotInfo* aSlot) {
|
|
||||||
nsCOMPtr<nsIPK11Token> token = new nsPK11Token(aSlot);
|
|
||||||
return NS_FAILED(token->Login(false /* force */)) ? NS_ERROR_FAILURE : NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult NSSKeyStore::Unlock() {
|
|
||||||
NS_ENSURE_STATE(mSlot);
|
|
||||||
|
|
||||||
if (!NS_IsMainThread()) {
|
|
||||||
nsCOMPtr<nsIThread> mainThread;
|
|
||||||
nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward to the main thread synchronously.
|
|
||||||
nsresult result = NS_ERROR_FAILURE;
|
|
||||||
SyncRunnable::DispatchToThread(
|
|
||||||
mainThread,
|
|
||||||
NS_NewRunnableFunction("NSSKeyStoreMainThreadUnlock",
|
|
||||||
[slot = mSlot.get(), result = &result]() {
|
|
||||||
*result = NSSKeyStoreMainThreadUnlock(slot);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NSSKeyStoreMainThreadUnlock(mSlot.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult NSSKeyStore::StoreSecret(const nsACString& aSecret,
|
nsresult NSSKeyStore::StoreSecret(const nsACString& aSecret,
|
||||||
const nsACString& aLabel) {
|
const nsACString& aLabel) {
|
||||||
NS_ENSURE_STATE(mSlot);
|
NS_ENSURE_STATE(mSlot);
|
||||||
if (NS_FAILED(Unlock())) {
|
|
||||||
MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is possible for multiple keys to have the same nickname in NSS. To
|
// It is possible for multiple keys to have the same nickname in NSS. To
|
||||||
// prevent the problem of not knowing which key to use in the future, simply
|
// prevent the problem of not knowing which key to use in the future, simply
|
||||||
|
@ -159,10 +97,6 @@ nsresult NSSKeyStore::StoreSecret(const nsACString& aSecret,
|
||||||
|
|
||||||
nsresult NSSKeyStore::DeleteSecret(const nsACString& aLabel) {
|
nsresult NSSKeyStore::DeleteSecret(const nsACString& aLabel) {
|
||||||
NS_ENSURE_STATE(mSlot);
|
NS_ENSURE_STATE(mSlot);
|
||||||
if (NS_FAILED(Unlock())) {
|
|
||||||
MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
|
UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
|
||||||
mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
|
mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
|
||||||
|
@ -185,10 +119,6 @@ bool NSSKeyStore::SecretAvailable(const nsACString& aLabel) {
|
||||||
if (!mSlot) {
|
if (!mSlot) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (NS_FAILED(Unlock())) {
|
|
||||||
MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
|
UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
|
||||||
mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
|
mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
|
||||||
|
@ -204,10 +134,6 @@ nsresult NSSKeyStore::EncryptDecrypt(const nsACString& aLabel,
|
||||||
std::vector<uint8_t>& outBytes,
|
std::vector<uint8_t>& outBytes,
|
||||||
bool encrypt) {
|
bool encrypt) {
|
||||||
NS_ENSURE_STATE(mSlot);
|
NS_ENSURE_STATE(mSlot);
|
||||||
if (NS_FAILED(Unlock())) {
|
|
||||||
MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
|
UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
|
||||||
mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
|
mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
|
||||||
|
|
|
@ -19,8 +19,6 @@ class NSSKeyStore final : public AbstractOSKeyStore {
|
||||||
virtual nsresult StoreSecret(const nsACString& secret,
|
virtual nsresult StoreSecret(const nsACString& secret,
|
||||||
const nsACString& label) override;
|
const nsACString& label) override;
|
||||||
virtual nsresult DeleteSecret(const nsACString& label) override;
|
virtual nsresult DeleteSecret(const nsACString& label) override;
|
||||||
virtual nsresult Lock() override;
|
|
||||||
virtual nsresult Unlock() override;
|
|
||||||
virtual nsresult EncryptDecrypt(const nsACString& label,
|
virtual nsresult EncryptDecrypt(const nsACString& label,
|
||||||
const std::vector<uint8_t>& inBytes,
|
const std::vector<uint8_t>& inBytes,
|
||||||
std::vector<uint8_t>& outBytes,
|
std::vector<uint8_t>& outBytes,
|
||||||
|
|
|
@ -28,7 +28,7 @@ NS_IMPL_ISUPPORTS(OSKeyStore, nsIOSKeyStore)
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using dom::Promise;
|
using dom::Promise;
|
||||||
|
|
||||||
OSKeyStore::OSKeyStore() : mKs(nullptr), mKsIsNSSKeyStore(false) {
|
OSKeyStore::OSKeyStore() : mKs(nullptr) {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
if (NS_WARN_IF(!NS_IsMainThread())) {
|
if (NS_WARN_IF(!NS_IsMainThread())) {
|
||||||
return;
|
return;
|
||||||
|
@ -43,11 +43,9 @@ OSKeyStore::OSKeyStore() : mKs(nullptr), mKsIsNSSKeyStore(false) {
|
||||||
mKs.reset(new LibSecret());
|
mKs.reset(new LibSecret());
|
||||||
} else {
|
} else {
|
||||||
mKs.reset(new NSSKeyStore());
|
mKs.reset(new NSSKeyStore());
|
||||||
mKsIsNSSKeyStore = true;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
mKs.reset(new NSSKeyStore());
|
mKs.reset(new NSSKeyStore());
|
||||||
mKsIsNSSKeyStore = true;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,23 +183,6 @@ nsresult OSKeyStore::DecryptBytes(const nsACString& aLabel,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult OSKeyStore::Lock() {
|
|
||||||
NS_ENSURE_STATE(mKs);
|
|
||||||
return mKs->Lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult OSKeyStore::Unlock() {
|
|
||||||
NS_ENSURE_STATE(mKs);
|
|
||||||
return mKs->Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
OSKeyStore::GetIsNSSKeyStore(bool* aNSSKeyStore) {
|
|
||||||
NS_ENSURE_ARG_POINTER(aNSSKeyStore);
|
|
||||||
*aNSSKeyStore = mKsIsNSSKeyStore;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Async interfaces that return promises because the key store implementation
|
// Async interfaces that return promises because the key store implementation
|
||||||
// might block, e.g. asking for a password.
|
// might block, e.g. asking for a password.
|
||||||
|
|
||||||
|
@ -218,85 +199,6 @@ nsresult GetPromise(JSContext* aCx, /* out */ RefPtr<Promise>& aPromise) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackgroundUnlock(RefPtr<Promise>& aPromise, RefPtr<OSKeyStore> self) {
|
|
||||||
nsAutoCString recovery;
|
|
||||||
nsresult rv = self->Unlock();
|
|
||||||
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
|
|
||||||
"BackgroundUnlockOSKSResolve", [rv, aPromise = std::move(aPromise)]() {
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
aPromise->MaybeReject(rv);
|
|
||||||
} else {
|
|
||||||
aPromise->MaybeResolveWithUndefined();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
NS_DispatchToMainThread(runnable.forget());
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
OSKeyStore::AsyncUnlock(JSContext* aCx, Promise** promiseOut) {
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
if (!NS_IsMainThread()) {
|
|
||||||
return NS_ERROR_NOT_SAME_THREAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_ENSURE_ARG_POINTER(aCx);
|
|
||||||
|
|
||||||
RefPtr<Promise> promiseHandle;
|
|
||||||
nsresult rv = GetPromise(aCx, promiseHandle);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<OSKeyStore> self = this;
|
|
||||||
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
|
|
||||||
"BackgroundUnlock", [self, promiseHandle]() mutable {
|
|
||||||
BackgroundUnlock(promiseHandle, self);
|
|
||||||
}));
|
|
||||||
|
|
||||||
promiseHandle.forget(promiseOut);
|
|
||||||
return NS_DispatchBackgroundTask(runnable.forget(),
|
|
||||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackgroundLock(RefPtr<Promise>& aPromise, RefPtr<OSKeyStore> self) {
|
|
||||||
nsresult rv = self->Lock();
|
|
||||||
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
|
|
||||||
"BackgroundLockOSKSResolve", [rv, aPromise = std::move(aPromise)]() {
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
aPromise->MaybeReject(rv);
|
|
||||||
} else {
|
|
||||||
aPromise->MaybeResolveWithUndefined();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
NS_DispatchToMainThread(runnable.forget());
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
OSKeyStore::AsyncLock(JSContext* aCx, Promise** promiseOut) {
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
if (!NS_IsMainThread()) {
|
|
||||||
return NS_ERROR_NOT_SAME_THREAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_ENSURE_ARG_POINTER(aCx);
|
|
||||||
|
|
||||||
RefPtr<Promise> promiseHandle;
|
|
||||||
nsresult rv = GetPromise(aCx, promiseHandle);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
RefPtr<OSKeyStore> self = this;
|
|
||||||
nsCOMPtr<nsIRunnable> runnable(
|
|
||||||
NS_NewRunnableFunction("BackgroundLock", [self, promiseHandle]() mutable {
|
|
||||||
BackgroundLock(promiseHandle, self);
|
|
||||||
}));
|
|
||||||
|
|
||||||
promiseHandle.forget(promiseOut);
|
|
||||||
return NS_DispatchBackgroundTask(runnable.forget(),
|
|
||||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BackgroundGenerateSecret(const nsACString& aLabel,
|
void BackgroundGenerateSecret(const nsACString& aLabel,
|
||||||
RefPtr<Promise>& aPromise,
|
RefPtr<Promise>& aPromise,
|
||||||
RefPtr<OSKeyStore> self) {
|
RefPtr<OSKeyStore> self) {
|
||||||
|
|
|
@ -28,10 +28,6 @@ class AbstractOSKeyStore {
|
||||||
const nsACString& label) = 0;
|
const nsACString& label) = 0;
|
||||||
// Delete the secret with the given label.
|
// Delete the secret with the given label.
|
||||||
virtual nsresult DeleteSecret(const nsACString& label) = 0;
|
virtual nsresult DeleteSecret(const nsACString& label) = 0;
|
||||||
// Lock the key store.
|
|
||||||
virtual nsresult Lock() = 0;
|
|
||||||
// Unlock the key store.
|
|
||||||
virtual nsresult Unlock() = 0;
|
|
||||||
virtual ~AbstractOSKeyStore() = default;
|
virtual ~AbstractOSKeyStore() = default;
|
||||||
|
|
||||||
// Returns true if the secret with the given label is available in the key
|
// Returns true if the secret with the given label is available in the key
|
||||||
|
@ -92,14 +88,11 @@ class OSKeyStore final : public nsIOSKeyStore {
|
||||||
const nsACString& aEncryptedBase64Text,
|
const nsACString& aEncryptedBase64Text,
|
||||||
/*out*/ uint32_t* outLen,
|
/*out*/ uint32_t* outLen,
|
||||||
/*out*/ uint8_t** outBytes);
|
/*out*/ uint8_t** outBytes);
|
||||||
nsresult Lock();
|
|
||||||
nsresult Unlock();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~OSKeyStore() = default;
|
~OSKeyStore() = default;
|
||||||
|
|
||||||
std::unique_ptr<AbstractOSKeyStore> mKs;
|
std::unique_ptr<AbstractOSKeyStore> mKs;
|
||||||
bool mKsIsNSSKeyStore;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // OSKeyStore_h
|
#endif // OSKeyStore_h
|
||||||
|
|
|
@ -12,18 +12,15 @@ interface nsIOSKeyStore: nsISupports {
|
||||||
* rest. The key used to encrypt and decrypt the data is stored in the OS
|
* rest. The key used to encrypt and decrypt the data is stored in the OS
|
||||||
* key store.
|
* key store.
|
||||||
*
|
*
|
||||||
|
* NB: To first authenticate the user to the system, use
|
||||||
|
* nsIOSReauthenticator.
|
||||||
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
*
|
*
|
||||||
* // obtain the singleton OSKeyStore instance
|
* // obtain the singleton OSKeyStore instance
|
||||||
* const oskeystore = Cc["@mozilla.org/security/oskeystore;1"].getService(Ci.nsIOSKeyStore);
|
* const oskeystore = Cc["@mozilla.org/security/oskeystore;1"].getService(Ci.nsIOSKeyStore);
|
||||||
*
|
*
|
||||||
* const PASSWORD_LABEL = "mylabel1";
|
* const PASSWORD_LABEL = "mylabel1";
|
||||||
* const COOKIE_LABEL = "mylabel2";
|
|
||||||
*
|
|
||||||
* // Unlock the key store.
|
|
||||||
* // Note that this is not necesssary. The key store will be unlocked
|
|
||||||
* // automatically when an operation is performed on it.
|
|
||||||
* await oskeystore.asyncUnlock();
|
|
||||||
*
|
*
|
||||||
* // Check if there's a secret for your label already.
|
* // Check if there's a secret for your label already.
|
||||||
* if (!await oskeystore.asyncSecretAvailable(PASSWORD_LABEL)) {
|
* if (!await oskeystore.asyncSecretAvailable(PASSWORD_LABEL)) {
|
||||||
|
@ -42,9 +39,6 @@ interface nsIOSKeyStore: nsISupports {
|
||||||
*
|
*
|
||||||
* // Recover a secret from a recovery code.
|
* // Recover a secret from a recovery code.
|
||||||
* await oskeystore.asyncRecoverSecret(PASSWORD_LABEL, recoveryPhrase);
|
* await oskeystore.asyncRecoverSecret(PASSWORD_LABEL, recoveryPhrase);
|
||||||
*
|
|
||||||
* // Lock the key store to prompt the user to log into her OS key store again.
|
|
||||||
* await oskeystore.asyncLock();
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,30 +109,4 @@ interface nsIOSKeyStore: nsISupports {
|
||||||
*/
|
*/
|
||||||
[implicit_jscontext, must_use]
|
[implicit_jscontext, must_use]
|
||||||
Promise asyncDecryptBytes(in ACString label, in ACString encryptedBase64Text);
|
Promise asyncDecryptBytes(in ACString label, in ACString encryptedBase64Text);
|
||||||
|
|
||||||
/**
|
|
||||||
* Lock the key store.
|
|
||||||
* The actual behaviour of this depends on the OS.
|
|
||||||
*
|
|
||||||
* @return Promise resolving to undefined or an error.
|
|
||||||
*/
|
|
||||||
[implicit_jscontext, must_use]
|
|
||||||
Promise asyncLock();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unlock the key store.
|
|
||||||
* The actual behaviour of this depends on the OS.
|
|
||||||
*
|
|
||||||
* @return Promise resolving to undefined or an error.
|
|
||||||
*/
|
|
||||||
[implicit_jscontext, must_use]
|
|
||||||
Promise asyncUnlock();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the implementation is using the NSS key store.
|
|
||||||
* This is a special case because Firefox has to handle the locking and
|
|
||||||
* unlocking.
|
|
||||||
*/
|
|
||||||
readonly attribute bool isNSSKeyStore;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,46 +25,6 @@ async function delete_all_secrets() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that Firefox handles locking and unlocking of the OSKeyStore properly.
|
|
||||||
// Does so by mocking out the actual dialog and "filling in" the
|
|
||||||
// password. Also tests that providing an incorrect password will fail (well,
|
|
||||||
// technically the user will just get prompted again, but if they then cancel
|
|
||||||
// the dialog the overall operation will fail).
|
|
||||||
|
|
||||||
var gMockPrompter = {
|
|
||||||
passwordToTry: null,
|
|
||||||
numPrompts: 0,
|
|
||||||
|
|
||||||
// This intentionally does not use arrow function syntax to avoid an issue
|
|
||||||
// where in the context of the arrow function, |this != gMockPrompter| due to
|
|
||||||
// how objects get wrapped when going across xpcom boundaries.
|
|
||||||
promptPassword(dialogTitle, text, password, checkMsg, checkValue) {
|
|
||||||
this.numPrompts++;
|
|
||||||
equal(
|
|
||||||
text,
|
|
||||||
"Please enter your Primary Password.",
|
|
||||||
"password prompt text should be as expected"
|
|
||||||
);
|
|
||||||
equal(checkMsg, null, "checkMsg should be null");
|
|
||||||
ok(this.passwordToTry, "passwordToTry should be non-null");
|
|
||||||
if (this.passwordToTry == "DontTryThisPassword") {
|
|
||||||
// Cancel the prompt in this case.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
password.value = this.passwordToTry;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
QueryInterface: ChromeUtils.generateQI(["nsIPrompt"]),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Mock nsIWindowWatcher. PSM calls getNewPrompter on this to get an nsIPrompt
|
|
||||||
// to call promptPassword. We return the mock one, above.
|
|
||||||
var gWindowWatcher = {
|
|
||||||
getNewPrompter: () => gMockPrompter,
|
|
||||||
QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]),
|
|
||||||
};
|
|
||||||
|
|
||||||
async function encrypt_decrypt_test() {
|
async function encrypt_decrypt_test() {
|
||||||
let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
|
let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
|
||||||
Ci.nsIOSKeyStore
|
Ci.nsIOSKeyStore
|
||||||
|
@ -109,110 +69,9 @@ async function encrypt_decrypt_test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
add_task(async function () {
|
add_task(async function () {
|
||||||
let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
|
|
||||||
Ci.nsIOSKeyStore
|
|
||||||
);
|
|
||||||
let windowWatcherCID;
|
|
||||||
if (keystore.isNSSKeyStore) {
|
|
||||||
windowWatcherCID = MockRegistrar.register(
|
|
||||||
"@mozilla.org/embedcomp/window-watcher;1",
|
|
||||||
gWindowWatcher
|
|
||||||
);
|
|
||||||
registerCleanupFunction(() => {
|
|
||||||
MockRegistrar.unregister(windowWatcherCID);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await delete_all_secrets();
|
await delete_all_secrets();
|
||||||
await encrypt_decrypt_test();
|
await encrypt_decrypt_test();
|
||||||
await delete_all_secrets();
|
await delete_all_secrets();
|
||||||
|
|
||||||
if (
|
|
||||||
AppConstants.platform == "macosx" ||
|
|
||||||
AppConstants.platform == "win" ||
|
|
||||||
AppConstants.platform == "linux"
|
|
||||||
) {
|
|
||||||
ok(
|
|
||||||
!keystore.isNSSKeyStore,
|
|
||||||
"OS X, Windows, and Linux should use the non-NSS implementation"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keystore.isNSSKeyStore) {
|
|
||||||
// If we use the NSS key store implementation test that everything works
|
|
||||||
// when a master password is set.
|
|
||||||
// Set an initial password.
|
|
||||||
let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].getService(
|
|
||||||
Ci.nsIPK11TokenDB
|
|
||||||
);
|
|
||||||
let token = tokenDB.getInternalKeyToken();
|
|
||||||
token.initPassword("hunter2");
|
|
||||||
|
|
||||||
// Lock the key store. This should be equivalent to token.logoutSimple()
|
|
||||||
await keystore.asyncLock();
|
|
||||||
|
|
||||||
// Set the correct password so that the test operations should succeed.
|
|
||||||
gMockPrompter.passwordToTry = "hunter2";
|
|
||||||
await encrypt_decrypt_test();
|
|
||||||
ok(
|
|
||||||
gMockPrompter.numPrompts == 1,
|
|
||||||
"There should've been one password prompt."
|
|
||||||
);
|
|
||||||
await delete_all_secrets();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check lock/unlock behaviour.
|
|
||||||
// Unfortunately we can only test this automatically for the NSS key store.
|
|
||||||
// Uncomment the outer keystore.isNSSKeyStore to test other key stores manually.
|
|
||||||
if (keystore.isNSSKeyStore) {
|
|
||||||
await delete_all_secrets();
|
|
||||||
await encrypt_decrypt_test();
|
|
||||||
await keystore.asyncLock();
|
|
||||||
info("Keystore should be locked. Cancel the login request.");
|
|
||||||
try {
|
|
||||||
if (keystore.isNSSKeyStore) {
|
|
||||||
gMockPrompter.passwordToTry = "DontTryThisPassword";
|
|
||||||
}
|
|
||||||
await keystore.asyncUnlock();
|
|
||||||
ok(false, "Unlock should've rejected.");
|
|
||||||
} catch (e) {
|
|
||||||
ok(
|
|
||||||
e.result == Cr.NS_ERROR_FAILURE || e.result == Cr.NS_ERROR_ABORT,
|
|
||||||
"Rejected login prompt."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// clean up
|
|
||||||
if (keystore.isNSSKeyStore) {
|
|
||||||
gMockPrompter.passwordToTry = "hunter2";
|
|
||||||
}
|
|
||||||
await delete_all_secrets();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Test that if we kick off a background operation and then call a synchronous function on the
|
|
||||||
// keystore, we don't deadlock.
|
|
||||||
add_task(async function () {
|
|
||||||
await delete_all_secrets();
|
|
||||||
|
|
||||||
let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
|
|
||||||
Ci.nsIOSKeyStore
|
|
||||||
);
|
|
||||||
let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
|
|
||||||
ok(recoveryPhrase, "A recovery phrase should've been created.");
|
|
||||||
|
|
||||||
try {
|
|
||||||
let text = new Uint8Array(8192);
|
|
||||||
let promise = keystore.asyncEncryptBytes(LABELS[0], text);
|
|
||||||
/* eslint-disable no-unused-expressions */
|
|
||||||
keystore.isNSSKeyStore; // we don't care what this is - we just need to access it
|
|
||||||
/* eslint-enable no-unused-expressions */
|
|
||||||
let ciphertext = await promise;
|
|
||||||
ok(ciphertext, "We should have a ciphertext now.");
|
|
||||||
} catch (e) {
|
|
||||||
ok(false, "Error encrypting " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
await delete_all_secrets();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test that using a recovery phrase works.
|
// Test that using a recovery phrase works.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче