/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Bug 1996558: verifies the SQLite at-rest encryption "fail-closed" contract.
// When encryption is enabled, an in-profile database that is NOT encrypted
// (e.g. a plaintext database carried in from a non-encrypting build) must be
// refused rather than silently opened as plaintext or recreated -- there is no
// plaintext->encrypted migration by design. With encryption disabled the same
// database opens normally. This is the positive counterpart to the migration
// fixture tests, which ship plaintext databases and are therefore run with
// encryption off.
const { Sqlite } = ChromeUtils.importESModule(
"resource://gre/modules/Sqlite.sys.mjs"
);
add_task(async
function test_encryption_rejects_foreign_plaintext_database() {
let encryptionEnabled = Services.prefs.getBoolPref(
"security.storage.encryption.sqlite.enabled",
false
);
// Create and populate a plaintext database OUTSIDE the profile. Out-of-profile
// databases are always opened as plaintext, even when encryption is enabled,
// so this is a genuine non-encrypted database. do_get_tempdir() is distinct
// from the profile directory.
let plaintextPath = PathUtils.join(
do_get_tempdir().path,
"foreign-plaintext.sqlite"
);
let inProfilePath = PathUtils.join(
PathUtils.profileDir,
"foreign-plaintext.sqlite"
);
registerCleanupFunction(async () => {
await IOUtils.remove(plaintextPath, { ignoreAbsent:
true });
await IOUtils.remove(inProfilePath, { ignoreAbsent:
true });
});
await IOUtils.remove(plaintextPath, { ignoreAbsent:
true });
let src = await Sqlite.openConnection({ path: plaintextPath });
await src.execute(
"CREATE TABLE t (x INTEGER)");
await src.execute(
"INSERT INTO t (x) VALUES (1)");
await src.close();
// Move the plaintext database into the profile.
Assert.ok(
!(await IOUtils.exists(inProfilePath)),
"The in-profile database should not exist yet"
);
await IOUtils.copy(plaintextPath, inProfilePath);
if (encryptionEnabled) {
// Fail-closed: the encrypting build must refuse the unencrypted in-profile
// database rather than open it as plaintext or recreate it.
await
Assert.rejects(
Sqlite.openConnection({ path: inProfilePath }),
/NS_ERROR_FAILURE/,
"An encrypting build refuses a plaintext in-profile database"
);
}
else {
// With encryption off the database opens normally as plaintext.
let conn = await Sqlite.openConnection({ path: inProfilePath });
let rows = await conn.execute(
"SELECT x FROM t");
Assert.equal(rows.length,
1,
"Plaintext database is readable when off");
Assert.equal(rows[
0].getResultByName(
"x"),
1,
"Row value is correct");
await conn.close();
}
});