1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
2 // Any copyright is dedicated to the Public Domain.
3 // http://creativecommons.org/publicdomain/zero/1.0/
6 // Tests the methods and attributes for interfacing with nsIOSKeyStore.
8 // Ensure that the appropriate initialization has happened.
11 const LABELS = ["mylabel1", "mylabel2", "mylabel3"];
13 async function delete_all_secrets() {
14 let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
17 for (let label of LABELS) {
18 if (await keystore.asyncSecretAvailable(label)) {
19 await keystore.asyncDeleteSecret(label);
21 !(await keystore.asyncSecretAvailable(label)),
22 label + " should be deleted now."
28 async function encrypt_decrypt_test() {
29 let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
33 !(await keystore.asyncSecretAvailable(LABELS[0])),
34 "The secret should not be available yet."
37 let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
38 ok(recoveryPhrase, "A recovery phrase should've been created.");
39 let recoveryPhrase2 = await keystore.asyncGenerateSecret(LABELS[1]);
40 ok(recoveryPhrase2, "A recovery phrase should've been created.");
42 let text = new Uint8Array([0x01, 0x00, 0x01]);
45 ciphertext = await keystore.asyncEncryptBytes(LABELS[0], text);
46 ok(ciphertext, "We should have a ciphertext now.");
48 ok(false, "Error encrypting " + e);
51 // Decrypting should give us the plaintext bytes again.
53 let plaintext = await keystore.asyncDecryptBytes(LABELS[0], ciphertext);
57 "Decrypted plaintext should be the same as text."
60 ok(false, "Error decrypting ciphertext " + e);
63 // Decrypting with a wrong key should throw an error.
65 await keystore.asyncDecryptBytes(LABELS[1], ciphertext);
66 ok(false, "Decrypting with the wrong key should fail.");
68 ok(true, "Decrypting with the wrong key should fail " + e);
72 add_task(async function () {
73 await delete_all_secrets();
74 await encrypt_decrypt_test();
75 await delete_all_secrets();
78 // Test that using a recovery phrase works.
79 add_task(async function () {
80 await delete_all_secrets();
82 let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
86 let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
87 ok(recoveryPhrase, "A recovery phrase should've been created.");
89 let text = new Uint8Array([0x01, 0x00, 0x01]);
90 let ciphertext = await keystore.asyncEncryptBytes(LABELS[0], text);
91 ok(ciphertext, "We should have a ciphertext now.");
93 await keystore.asyncDeleteSecret(LABELS[0]);
94 // Decrypting should fail after deleting the secret.
96 .asyncDecryptBytes(LABELS[0], ciphertext)
98 ok(false, "decrypting didn't throw as expected after deleting the secret")
101 ok(true, "decrypting threw as expected after deleting the secret")
104 await keystore.asyncRecoverSecret(LABELS[0], recoveryPhrase);
105 let plaintext = await keystore.asyncDecryptBytes(LABELS[0], ciphertext);
107 plaintext.toString(),
109 "Decrypted plaintext should be the same as text."
112 await delete_all_secrets();
115 // Test that trying to use a non-base64 recovery phrase fails.
116 add_task(async function () {
117 await delete_all_secrets();
119 let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
123 .asyncRecoverSecret(LABELS[0], "@##$^&*()#$^&*(@#%&*_")
125 ok(false, "base64-decoding non-base64 should have failed but didn't")
127 .catch(() => ok(true, "base64-decoding non-base64 failed as expected"));
130 !(await keystore.asyncSecretAvailable(LABELS[0])),
131 "we didn't recover a secret, so the secret shouldn't be available"
133 let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
135 recoveryPhrase && !!recoveryPhrase.length,
136 "we should be able to re-use that label to generate a new secret"
138 await delete_all_secrets();
141 // Test that re-using a label overwrites any previously-stored secret.
142 add_task(async function () {
143 await delete_all_secrets();
145 let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
149 let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
150 ok(recoveryPhrase, "A recovery phrase should've been created.");
152 let text = new Uint8Array([0x66, 0x6f, 0x6f, 0x66]);
153 let ciphertext = await keystore.asyncEncryptBytes(LABELS[0], text);
154 ok(ciphertext, "We should have a ciphertext now.");
156 let newRecoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
157 ok(newRecoveryPhrase, "A new recovery phrase should've been created.");
159 // The new secret replaced the old one so we shouldn't be able to decrypt the ciphertext now.
161 .asyncDecryptBytes(LABELS[0], ciphertext)
163 ok(false, "decrypting without the original key should have failed")
166 ok(true, "decrypting without the original key failed as expected")
169 await keystore.asyncRecoverSecret(LABELS[0], recoveryPhrase);
170 let plaintext = await keystore.asyncDecryptBytes(LABELS[0], ciphertext);
172 plaintext.toString(),
174 "Decrypted plaintext should be the same as text (once we have the original key again)."
177 await delete_all_secrets();
180 // Test that re-using a label (this time using a recovery phrase) overwrites any previously-stored
182 add_task(async function () {
183 await delete_all_secrets();
185 let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
189 let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
190 ok(recoveryPhrase, "A recovery phrase should've been created.");
192 let newRecoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
193 ok(newRecoveryPhrase, "A new recovery phrase should've been created.");
195 let text = new Uint8Array([0x66, 0x6f, 0x6f, 0x66]);
196 let ciphertext = await keystore.asyncEncryptBytes(LABELS[0], text);
197 ok(ciphertext, "We should have a ciphertext now.");
199 await keystore.asyncRecoverSecret(LABELS[0], recoveryPhrase);
201 // We recovered the old secret, so decrypting ciphertext that had been encrypted with the newer
204 .asyncDecryptBytes(LABELS[0], ciphertext)
205 .then(() => ok(false, "decrypting without the new key should have failed"))
206 .catch(() => ok(true, "decrypting without the new key failed as expected"));
208 await keystore.asyncRecoverSecret(LABELS[0], newRecoveryPhrase);
209 let plaintext = await keystore.asyncDecryptBytes(LABELS[0], ciphertext);
211 plaintext.toString(),
213 "Decrypted plaintext should be the same as text (once we have the new key again)."
216 await delete_all_secrets();
219 // Test that trying to use recovery phrases that are the wrong size fails.
220 add_task(async function () {
221 await delete_all_secrets();
223 let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
228 .asyncRecoverSecret(LABELS[0], "")
229 .then(() => ok(false, "'recovering' with an empty key should have failed"))
230 .catch(() => ok(true, "'recovering' with an empty key failed as expected"));
232 !(await keystore.asyncSecretAvailable(LABELS[0])),
233 "we didn't recover a secret, so the secret shouldn't be available"
237 .asyncRecoverSecret(LABELS[0], "AAAAAA")
239 ok(false, "recovering with a key that is too short should have failed")
242 ok(true, "recovering with a key that is too short failed as expected")
245 !(await keystore.asyncSecretAvailable(LABELS[0])),
246 "we didn't recover a secret, so the secret shouldn't be available"
252 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
255 ok(false, "recovering with a key that is too long should have failed")
258 ok(true, "recovering with a key that is too long failed as expected")
261 !(await keystore.asyncSecretAvailable(LABELS[0])),
262 "we didn't recover a secret, so the secret shouldn't be available"
265 let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
267 recoveryPhrase && !!recoveryPhrase.length,
268 "we should be able to use that label to generate a new secret"
271 await keystore.asyncSecretAvailable(LABELS[0]),
272 "the generated secret should now be available"
275 await delete_all_secrets();