Created
January 2, 2019 20:31
-
-
Save mozkeeler/033f89c23da9307f386f6ef9357d74b7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User Dana Keeler <dkeeler@mozilla.com> | |
# Date 1540589411 25200 | |
# Fri Oct 26 14:30:11 2018 -0700 | |
# Node ID 1e46bd8dc997145cc29c7e8465d1648eab52c84e | |
# Parent 5826b2352ac08248205d3b0e29587ab8ad415bfe | |
bug 1498909 - dynamically load libsecret at runtime if available r?franziskus,jcj | |
Summary: | |
Enough linux-based systems don't have libsecret that we can't make it a | |
requirement on linux. For those that do, however, we can dynamically load the | |
library at runtime. For those that don't, we can fall back to NSS. | |
Reviewers: franziskus, jcj | |
Tags: #secure-revision | |
Differential Revision: https://phabricator.services.mozilla.com/D9969 | |
diff --git a/config/system-headers.mozbuild b/config/system-headers.mozbuild | |
--- a/config/system-headers.mozbuild | |
+++ b/config/system-headers.mozbuild | |
@@ -1345,25 +1345,8 @@ if CONFIG['ENABLE_BIGINT']: | |
if CONFIG['MOZ_WAYLAND']: | |
system_headers += [ | |
'xkbcommon/xkbcommon.h', | |
'wayland-client.h', | |
'wayland-egl.h', | |
'wayland-util.h', | |
] | |
- | |
-if CONFIG['MOZ_LIB_SECRET']: | |
- system_headers += [ | |
- 'libsecret/secret.h', | |
- 'libsecret/secret-attributes.h', | |
- 'libsecret/secret-collection.h', | |
- 'libsecret/secret-enum-types.h', | |
- 'libsecret/secret-item.h', | |
- 'libsecret/secret-password.h', | |
- 'libsecret/secret-paths.h', | |
- 'libsecret/secret-prompt.h', | |
- 'libsecret/secret-schema.h', | |
- 'libsecret/secret-schemas.h', | |
- 'libsecret/secret-types.h', | |
- 'libsecret/secret-value.h', | |
- 'libsecret/secret-service.h', | |
- ] | |
diff --git a/security/manager/ssl/LibSecret.cpp b/security/manager/ssl/LibSecret.cpp | |
--- a/security/manager/ssl/LibSecret.cpp | |
+++ b/security/manager/ssl/LibSecret.cpp | |
@@ -1,39 +1,217 @@ | |
/* -*- Mode: C++; tab-width: 2; 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 "LibSecret.h" | |
+#include <gio/gio.h> | |
#include <gmodule.h> | |
+#include <memory> | |
#include "mozilla/Base64.h" | |
+#include "prlink.h" | |
// This is the implementation of LibSecret, an instantiation of OSKeyStore for | |
// Linux. | |
using namespace mozilla; | |
LazyLogModule gLibSecretLog("libsecret"); | |
+static PRLibrary* libsecret = nullptr; | |
+ | |
+typedef struct _SecretService SecretService; | |
+typedef struct _SecretCollection SecretCollection; | |
+ | |
+typedef enum { | |
+ SECRET_SCHEMA_NONE = 0, | |
+ SECRET_SCHEMA_DONT_MATCH_NAME = 1 << 1 | |
+} SecretSchemaFlags; | |
+ | |
+typedef enum { | |
+ SECRET_SCHEMA_ATTRIBUTE_STRING = 0, | |
+ SECRET_SCHEMA_ATTRIBUTE_INTEGER = 1, | |
+ SECRET_SCHEMA_ATTRIBUTE_BOOLEAN = 2, | |
+} SecretSchemaAttributeType; | |
+ | |
+typedef struct { | |
+ const gchar* name; | |
+ SecretSchemaAttributeType type; | |
+} SecretSchemaAttribute; | |
+ | |
+typedef struct { | |
+ const gchar* name; | |
+ SecretSchemaFlags flags; | |
+ SecretSchemaAttribute attributes[32]; | |
+ | |
+ /* <private> */ | |
+ gint reserved; | |
+ gpointer reserved1; | |
+ gpointer reserved2; | |
+ gpointer reserved3; | |
+ gpointer reserved4; | |
+ gpointer reserved5; | |
+ gpointer reserved6; | |
+ gpointer reserved7; | |
+} SecretSchema; | |
+ | |
+typedef enum { | |
+ SECRET_COLLECTION_NONE = 0 << 0, | |
+ SECRET_COLLECTION_LOAD_ITEMS = 1 << 1, | |
+} SecretCollectionFlags; | |
+ | |
+typedef enum { | |
+ SECRET_SERVICE_NONE = 0, | |
+ SECRET_SERVICE_OPEN_SESSION = 1 << 1, | |
+ SECRET_SERVICE_LOAD_COLLECTIONS = 1 << 2, | |
+} SecretServiceFlags; | |
+ | |
+typedef enum { | |
+ SECRET_ERROR_PROTOCOL = 1, | |
+ SECRET_ERROR_IS_LOCKED = 2, | |
+ SECRET_ERROR_NO_SUCH_OBJECT = 3, | |
+ SECRET_ERROR_ALREADY_EXISTS = 4, | |
+} SecretError; | |
+ | |
+#define SECRET_COLLECTION_DEFAULT "default" | |
+ | |
+typedef SecretCollection* (*secret_collection_for_alias_sync_fn)( | |
+ SecretService*, const gchar*, SecretCollectionFlags, GCancellable*, | |
+ GError**); | |
+typedef SecretService* (*secret_service_get_sync_fn)(SecretServiceFlags, | |
+ GCancellable*, GError**); | |
+typedef gint (*secret_service_lock_sync_fn)(SecretService*, GList*, | |
+ GCancellable*, GList**, GError**); | |
+typedef gboolean (*secret_password_clear_sync_fn)(const SecretSchema*, | |
+ GCancellable*, GError**, ...); | |
+typedef gchar* (*secret_password_lookup_sync_fn)(const SecretSchema*, | |
+ GCancellable*, GError**, ...); | |
+typedef gboolean (*secret_password_store_sync_fn)(const SecretSchema*, | |
+ const gchar*, const gchar*, | |
+ const gchar*, GCancellable*, | |
+ GError**, ...); | |
+typedef void (*secret_password_free_fn)(const gchar*); | |
+typedef GQuark (*secret_error_get_quark_fn)(); | |
+ | |
+static secret_collection_for_alias_sync_fn secret_collection_for_alias_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_password_clear_sync_fn secret_password_clear_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_free_fn secret_password_free = nullptr; | |
+static secret_error_get_quark_fn secret_error_get_quark = nullptr; | |
+ | |
+nsresult MaybeLoadLibSecret() { | |
+ MOZ_ASSERT(NS_IsMainThread()); | |
+ if (!NS_IsMainThread()) { | |
+ return NS_ERROR_NOT_SAME_THREAD; | |
+ } | |
+ | |
+ if (!libsecret) { | |
+ libsecret = PR_LoadLibrary("libsecret-1.so.0"); | |
+ if (!libsecret) { | |
+ return NS_ERROR_NOT_AVAILABLE; | |
+ } | |
+ | |
+#define FIND_FUNCTION_SYMBOL(function) \ | |
+ function = (function##_fn)PR_FindFunctionSymbol(libsecret, #function); \ | |
+ if (!(function)) { \ | |
+ PR_UnloadLibrary(libsecret); \ | |
+ libsecret = nullptr; \ | |
+ return NS_ERROR_NOT_AVAILABLE; \ | |
+ } | |
+ FIND_FUNCTION_SYMBOL(secret_collection_for_alias_sync); | |
+ FIND_FUNCTION_SYMBOL(secret_service_get_sync); | |
+ FIND_FUNCTION_SYMBOL(secret_service_lock_sync); | |
+ FIND_FUNCTION_SYMBOL(secret_password_clear_sync); | |
+ FIND_FUNCTION_SYMBOL(secret_password_lookup_sync); | |
+ FIND_FUNCTION_SYMBOL(secret_password_store_sync); | |
+ FIND_FUNCTION_SYMBOL(secret_password_free); | |
+ FIND_FUNCTION_SYMBOL(secret_error_get_quark); | |
+#undef FIND_FUNCTION_SYMBOL | |
+ } | |
+ | |
+ return NS_OK; | |
+} | |
+ | |
+struct ScopedDelete { | |
+ void operator()(SecretService* ss) { | |
+ if (ss) g_object_unref(ss); | |
+ } | |
+ void operator()(SecretCollection* sc) { | |
+ if (sc) g_object_unref(sc); | |
+ } | |
+ void operator()(GError* error) { | |
+ if (error) g_error_free(error); | |
+ } | |
+ void operator()(GList* list) { | |
+ if (list) g_list_free(list); | |
+ } | |
+ void operator()(char* val) { | |
+ if (val) secret_password_free(val); | |
+ } | |
+}; | |
+ | |
+template <class T> | |
+struct ScopedMaybeDelete { | |
+ void operator()(T* ptr) { | |
+ if (ptr) { | |
+ ScopedDelete del; | |
+ del(ptr); | |
+ } | |
+ } | |
+}; | |
+ | |
+typedef std::unique_ptr<GError, ScopedMaybeDelete<GError>> ScopedGError; | |
+typedef std::unique_ptr<GList, ScopedMaybeDelete<GList>> ScopedGList; | |
+typedef std::unique_ptr<char, ScopedMaybeDelete<char>> ScopedPassword; | |
+typedef std::unique_ptr<SecretCollection, ScopedMaybeDelete<SecretCollection>> | |
+ ScopedSecretCollection; | |
+typedef std::unique_ptr<SecretService, ScopedMaybeDelete<SecretService>> | |
+ ScopedSecretService; | |
+ | |
LibSecret::LibSecret() {} | |
-LibSecret::~LibSecret() {} | |
+LibSecret::~LibSecret() { | |
+ MOZ_ASSERT(NS_IsMainThread()); | |
+ if (!NS_IsMainThread()) { | |
+ return; | |
+ } | |
+ if (libsecret) { | |
+ secret_collection_for_alias_sync = nullptr; | |
+ secret_service_get_sync = nullptr; | |
+ secret_service_lock_sync = nullptr; | |
+ secret_password_clear_sync = nullptr; | |
+ secret_password_lookup_sync = nullptr; | |
+ secret_password_store_sync = nullptr; | |
+ secret_password_free = nullptr; | |
+ secret_error_get_quark = nullptr; | |
+ PR_UnloadLibrary(libsecret); | |
+ libsecret = nullptr; | |
+ } | |
+} | |
static const SecretSchema kSchema = { | |
"mozilla.firefox", | |
SECRET_SCHEMA_NONE, | |
{{"string", SECRET_SCHEMA_ATTRIBUTE_STRING}, /* the label */ | |
{"NULL", SECRET_SCHEMA_ATTRIBUTE_STRING}}}; | |
nsresult GetScopedServices(ScopedSecretService& aSs, | |
ScopedSecretCollection& aSc) { | |
+ MOZ_ASSERT(secret_service_get_sync && secret_collection_for_alias_sync); | |
+ if (!secret_service_get_sync || !secret_collection_for_alias_sync) { | |
+ return NS_ERROR_FAILURE; | |
+ } | |
GError* raw_error = nullptr; | |
aSs = ScopedSecretService(secret_service_get_sync( | |
static_cast<SecretServiceFlags>( | |
SECRET_SERVICE_OPEN_SESSION), // SecretServiceFlags | |
nullptr, // GCancellable | |
&raw_error)); | |
ScopedGError error(raw_error); | |
if (error || !aSs) { | |
@@ -50,16 +228,20 @@ nsresult GetScopedServices(ScopedSecretS | |
MOZ_LOG(gLibSecretLog, LogLevel::Debug, | |
("Couldn't get a secret collection")); | |
return NS_ERROR_FAILURE; | |
} | |
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; | |
@@ -85,56 +267,85 @@ nsresult LibSecret::Unlock() { | |
if (NS_FAILED(GetScopedServices(ss, sc))) { | |
return NS_ERROR_FAILURE; | |
} | |
return NS_OK; | |
} | |
nsresult LibSecret::StoreSecret(const nsACString& aSecret, | |
const nsACString& aLabel) { | |
+ MOZ_ASSERT(secret_password_store_sync); | |
+ if (!secret_password_store_sync) { | |
+ return NS_ERROR_FAILURE; | |
+ } | |
+ // libsecret expects a null-terminated string, so to be safe we store the | |
+ // secret (which could be arbitrary bytes) base64-encoded. | |
+ nsAutoCString base64; | |
+ nsresult rv = Base64Encode(aSecret, base64); | |
+ if (NS_FAILED(rv)) { | |
+ MOZ_LOG(gLibSecretLog, LogLevel::Debug, ("Error base64-encoding secret")); | |
+ return rv; | |
+ } | |
GError* raw_error = nullptr; | |
bool stored = secret_password_store_sync( | |
&kSchema, SECRET_COLLECTION_DEFAULT, PromiseFlatCString(aLabel).get(), | |
- PromiseFlatCString(aSecret).get(), | |
+ PromiseFlatCString(base64).get(), | |
nullptr, // GCancellable | |
&raw_error, "string", PromiseFlatCString(aLabel).get(), nullptr); | |
ScopedGError error(raw_error); | |
if (raw_error) { | |
MOZ_LOG(gLibSecretLog, LogLevel::Debug, ("Error storing secret")); | |
return NS_ERROR_FAILURE; | |
} | |
return stored ? NS_OK : NS_ERROR_FAILURE; | |
} | |
nsresult LibSecret::DeleteSecret(const nsACString& aLabel) { | |
+ MOZ_ASSERT(secret_password_clear_sync && secret_error_get_quark); | |
+ if (!secret_password_clear_sync || !secret_error_get_quark) { | |
+ return NS_ERROR_FAILURE; | |
+ } | |
GError* raw_error = nullptr; | |
- bool r = secret_password_clear_sync( | |
+ Unused << secret_password_clear_sync( | |
&kSchema, | |
nullptr, // GCancellable | |
&raw_error, "string", PromiseFlatCString(aLabel).get(), nullptr); | |
ScopedGError error(raw_error); | |
- if (raw_error) { | |
+ if (raw_error && !(raw_error->domain == secret_error_get_quark() && | |
+ raw_error->code == SECRET_ERROR_NO_SUCH_OBJECT)) { | |
MOZ_LOG(gLibSecretLog, LogLevel::Debug, ("Error deleting secret")); | |
return NS_ERROR_FAILURE; | |
} | |
- return r ? NS_OK : NS_ERROR_FAILURE; | |
+ return NS_OK; | |
} | |
nsresult LibSecret::RetrieveSecret(const nsACString& aLabel, | |
/* out */ nsACString& aSecret) { | |
+ MOZ_ASSERT(secret_password_lookup_sync && secret_password_free); | |
+ if (!secret_password_lookup_sync || !secret_password_free) { | |
+ return NS_ERROR_FAILURE; | |
+ } | |
GError* raw_error = nullptr; | |
aSecret.Truncate(); | |
ScopedPassword s(secret_password_lookup_sync( | |
&kSchema, | |
nullptr, // GCancellable | |
&raw_error, "string", PromiseFlatCString(aLabel).get(), nullptr)); | |
ScopedGError error(raw_error); | |
if (raw_error || !s) { | |
MOZ_LOG(gLibSecretLog, LogLevel::Debug, | |
("Error retrieving secret or didn't find it")); | |
return NS_ERROR_FAILURE; | |
} | |
- aSecret.Assign(s.get(), strlen(s.get())); | |
+ // libsecret expects a null-terminated string, so to be safe we store the | |
+ // secret (which could be arbitrary bytes) base64-encoded, which means we have | |
+ // to base64-decode it here. | |
+ nsAutoCString base64Encoded(s.get()); | |
+ nsresult rv = Base64Decode(base64Encoded, aSecret); | |
+ if (NS_FAILED(rv)) { | |
+ MOZ_LOG(gLibSecretLog, LogLevel::Debug, ("Error base64-decoding secret")); | |
+ return rv; | |
+ } | |
return NS_OK; | |
} | |
diff --git a/security/manager/ssl/LibSecret.h b/security/manager/ssl/LibSecret.h | |
--- a/security/manager/ssl/LibSecret.h | |
+++ b/security/manager/ssl/LibSecret.h | |
@@ -1,74 +1,22 @@ | |
/* -*- Mode: C++; tab-width: 2; 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/. */ | |
-#ifndef MOZ_LIB_SECRET | |
-#error LibSecret OSKeyStore included when MOZ_LIB_SECRET is not defined! | |
-#endif | |
- | |
#ifndef LibSecret_h | |
#define LibSecret_h | |
#include "OSKeyStore.h" | |
-#include <libsecret/secret.h> | |
-#include <memory> | |
-#include <vector> | |
- | |
#include "nsString.h" | |
-struct ScopedDelete { | |
- void operator()(SecretService* ss) { | |
- if (ss) g_object_unref(ss); | |
- } | |
- void operator()(SecretCollection* sc) { | |
- if (sc) g_object_unref(sc); | |
- } | |
- void operator()(GError* error) { | |
- if (error) g_error_free(error); | |
- } | |
- void operator()(GList* list) { | |
- if (list) g_list_free(list); | |
- } | |
- void operator()(SecretValue* val) { | |
- if (val) secret_value_unref(val); | |
- } | |
- void operator()(SecretItem* val) { | |
- if (val) g_object_unref(val); | |
- } | |
- void operator()(char* val) { | |
- if (val) secret_password_free(val); | |
- } | |
-}; | |
- | |
-template <class T> | |
-struct ScopedMaybeDelete { | |
- void operator()(T* ptr) { | |
- if (ptr) { | |
- ScopedDelete del; | |
- del(ptr); | |
- } | |
- } | |
-}; | |
- | |
-#define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x>> Scoped##x | |
- | |
-SCOPED(SecretService); | |
-SCOPED(SecretCollection); | |
-SCOPED(GError); | |
-SCOPED(GList); | |
-SCOPED(SecretValue); | |
-SCOPED(SecretItem); | |
-typedef std::unique_ptr<char, ScopedMaybeDelete<char>> ScopedPassword; | |
- | |
-#undef SCOPED | |
+nsresult MaybeLoadLibSecret(); | |
class LibSecret final : public AbstractOSKeyStore { | |
public: | |
LibSecret(); | |
virtual nsresult RetrieveSecret(const nsACString& label, | |
/* out */ nsACString& secret) override; | |
virtual nsresult StoreSecret(const nsACString& secret, | |
diff --git a/security/manager/ssl/OSKeyStore.cpp b/security/manager/ssl/OSKeyStore.cpp | |
--- a/security/manager/ssl/OSKeyStore.cpp | |
+++ b/security/manager/ssl/OSKeyStore.cpp | |
@@ -7,46 +7,50 @@ | |
#include "OSKeyStore.h" | |
#include "mozilla/Base64.h" | |
#include "mozilla/dom/Promise.h" | |
#include "nsIRandomGenerator.h" | |
#include "nsXPCOM.h" | |
#include "pk11pub.h" | |
-#ifdef MOZ_LIB_SECRET | |
-#include "LibSecret.h" | |
-#elif defined(XP_MACOSX) | |
+#if defined(XP_MACOSX) | |
#include "KeychainSecret.h" | |
#elif defined(XP_WIN) | |
#include "CredentialManagerSecret.h" | |
+#elif defined(MOZ_WIDGET_GTK) | |
+#include "LibSecret.h" | |
+#include "NSSKeyStore.h" | |
#else | |
#include "NSSKeyStore.h" | |
#endif | |
NS_IMPL_ISUPPORTS(OSKeyStore, nsIOSKeyStore, nsIObserver) | |
using namespace mozilla; | |
using dom::Promise; | |
-mozilla::LazyLogModule gOSKeyStoreLog("oskeystore"); | |
- | |
OSKeyStore::OSKeyStore() | |
: mKs(nullptr), mKsThread(nullptr), mKsIsNSSKeyStore(false) { | |
MOZ_ASSERT(NS_IsMainThread()); | |
if (NS_WARN_IF(!NS_IsMainThread())) { | |
return; | |
} | |
-#ifdef MOZ_LIB_SECRET | |
- mKs.reset(new LibSecret()); | |
-#elif defined(XP_MACOSX) | |
+#if defined(XP_MACOSX) | |
mKs.reset(new KeychainSecret()); | |
#elif defined(XP_WIN) | |
mKs.reset(new CredentialManagerSecret()); | |
+#elif defined(MOZ_WIDGET_GTK) | |
+ if (NS_SUCCEEDED(MaybeLoadLibSecret())) { | |
+ mKs.reset(new LibSecret()); | |
+ } else { | |
+ mKs.reset(new NSSKeyStore()); | |
+ mKsIsNSSKeyStore = true; | |
+ } | |
#else | |
mKs.reset(new NSSKeyStore()); | |
mKsIsNSSKeyStore = true; | |
#endif | |
nsCOMPtr<nsIThread> thread; | |
nsresult rv = NS_NewNamedThread("OSKeyStore", getter_AddRefs(thread)); | |
if (NS_WARN_IF(NS_FAILED(rv))) { | |
diff --git a/security/manager/ssl/moz.build b/security/manager/ssl/moz.build | |
--- a/security/manager/ssl/moz.build | |
+++ b/security/manager/ssl/moz.build | |
@@ -136,22 +136,22 @@ UNIFIED_SOURCES += [ | |
'PublicKeyPinningService.cpp', | |
'RootCertificateTelemetryUtils.cpp', | |
'SecretDecoderRing.cpp', | |
'SharedSSLState.cpp', | |
'SSLServerCertVerification.cpp', | |
'TransportSecurityInfo.cpp', | |
] | |
-if CONFIG['MOZ_LIB_SECRET']: | |
+if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: | |
UNIFIED_SOURCES += [ | |
'LibSecret.cpp', | |
] | |
- CFLAGS += CONFIG['MOZ_LIB_SECRET_CFLAGS'] | |
- CXXFLAGS += CONFIG['MOZ_LIB_SECRET_CFLAGS'] | |
+ CFLAGS += CONFIG['GLIB_CFLAGS'] | |
+ CXXFLAGS += CONFIG['GLIB_CFLAGS'] | |
if CONFIG['OS_ARCH'] == 'Darwin': | |
UNIFIED_SOURCES += [ | |
'KeychainSecret.cpp', | |
'OSReauthenticatorDarwin.mm', | |
] | |
OS_LIBS += [ | |
'-framework LocalAuthentication', | |
diff --git a/security/manager/ssl/tests/unit/test_oskeystore.js b/security/manager/ssl/tests/unit/test_oskeystore.js | |
--- a/security/manager/ssl/tests/unit/test_oskeystore.js | |
+++ b/security/manager/ssl/tests/unit/test_oskeystore.js | |
@@ -156,8 +156,69 @@ add_task(async function() { | |
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. | |
+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."); | |
+ | |
+ let text = new Uint8Array([0x01, 0x00, 0x01]); | |
+ let ciphertext = await keystore.asyncEncryptBytes(LABELS[0], text.length, text); | |
+ ok(ciphertext, "We should have a ciphertext now."); | |
+ | |
+ await keystore.asyncDeleteSecret(LABELS[0]); | |
+ // Decrypting should fail after deleting the secret. | |
+ await keystore.asyncDecryptBytes(LABELS[0], ciphertext) | |
+ .then(() => ok(false, "decrypting didn't throw as expected after deleting the secret")) | |
+ .catch(() => ok(true, "decrypting threw as expected after deleting the secret")); | |
+ | |
+ await keystore.asyncRecoverSecret(LABELS[0], recoveryPhrase); | |
+ let plaintext = await keystore.asyncDecryptBytes(LABELS[0], ciphertext); | |
+ ok(plaintext.toString() == text.toString(), "Decrypted plaintext should be the same as text."); | |
+ | |
+ await delete_all_secrets(); | |
+}); | |
+ | |
+// Test that trying to use a non-base64 recovery phrase fails. | |
+add_task(async function() { | |
+ await delete_all_secrets(); | |
+ | |
+ let keystore = Cc["@mozilla.org/security/oskeystore;1"] | |
+ .getService(Ci.nsIOSKeyStore); | |
+ await keystore.asyncRecoverSecret(LABELS[0], "@##$^&*()#$^&*(@#%&*_") | |
+ .then(() => ok(false, "base64-decoding non-base64 should have failed but didn't")) | |
+ .catch(() => ok(true, "base64-decoding non-base64 failed as expected")); | |
+ | |
+ ok(!await keystore.asyncSecretAvailable(LABELS[0]), | |
+ "we didn't recover a secret, so the secret shouldn't be available"); | |
+ let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]); | |
+ ok(recoveryPhrase && recoveryPhrase.length > 0, | |
+ "we should be able to re-use that label to generate a new secret"); | |
+ await delete_all_secrets(); | |
+}); | |
+ | |
+// Test that "recovering" a zero-length secret doesn't throw but also doesn't result in that label | |
+// slot being unusable to store a new secret. | |
+add_task(async function() { | |
+ await delete_all_secrets(); | |
+ | |
+ let keystore = Cc["@mozilla.org/security/oskeystore;1"] | |
+ .getService(Ci.nsIOSKeyStore); | |
+ await keystore.asyncRecoverSecret(LABELS[0], ""); | |
+ ok(!await keystore.asyncSecretAvailable(LABELS[0]), | |
+ "'recovering' a zero-length secret doesn't throw, but the secret is not available"); | |
+ let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]); | |
+ ok(recoveryPhrase && recoveryPhrase.length > 0, | |
+ "we should be able to re-use that label to generate a new secret"); | |
+ await delete_all_secrets(); | |
+}); | |
diff --git a/toolkit/library/moz.build b/toolkit/library/moz.build | |
--- a/toolkit/library/moz.build | |
+++ b/toolkit/library/moz.build | |
@@ -210,19 +210,16 @@ if CONFIG['MOZ_ANDROID_GOOGLE_VR']: | |
OS_LIBS += [ | |
'-L%s' % CONFIG['MOZ_ANDROID_GOOGLE_VR_LIBS'], | |
'-lgvr', | |
] | |
OS_LIBS += CONFIG['MOZ_CAIRO_OSLIBS'] | |
OS_LIBS += CONFIG['MOZ_WEBRTC_X11_LIBS'] | |
-if CONFIG['MOZ_LIB_SECRET']: | |
- OS_LIBS += CONFIG['MOZ_LIB_SECRET_LIBS'] | |
- | |
if CONFIG['MOZ_SYSTEM_JPEG']: | |
OS_LIBS += CONFIG['MOZ_JPEG_LIBS'] | |
if CONFIG['MOZ_SYSTEM_PNG']: | |
OS_LIBS += CONFIG['MOZ_PNG_LIBS'] | |
if CONFIG['MOZ_SYSTEM_WEBP']: | |
OS_LIBS += CONFIG['MOZ_WEBP_LIBS'] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment