test_sdr_preexisting_with_password.js (4469B)
1 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*- 2 // This Source Code Form is subject to the terms of the Mozilla Public 3 // License, v. 2.0. If a copy of the MPL was not distributed with this 4 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 6 "use strict"; 7 8 // Tests that the SDR implementation is able to decrypt strings encrypted using 9 // a preexisting NSS key database that has a password. 10 // To create such a database, run Firefox (or xpcshell), set a primary 11 // password, and then encrypt something using nsISecretDecoderRing. 12 13 var gMockPrompter = { 14 passwordToTry: "password", 15 numPrompts: 0, 16 17 // This intentionally does not use arrow function syntax to avoid an issue 18 // where in the context of the arrow function, |this != gMockPrompter| due to 19 // how objects get wrapped when going across xpcom boundaries. 20 promptPassword(dialogTitle, text, password, checkMsg) { 21 this.numPrompts++; 22 if (this.numPrompts > 1) { 23 // don't keep retrying a bad password 24 return false; 25 } 26 equal( 27 text, 28 "Please enter your Primary Password.", 29 "password prompt text should be as expected" 30 ); 31 equal(checkMsg, null, "checkMsg should be null"); 32 ok(this.passwordToTry, "passwordToTry should be non-null"); 33 password.value = this.passwordToTry; 34 return true; 35 }, 36 37 QueryInterface: ChromeUtils.generateQI(["nsIPrompt"]), 38 }; 39 40 // Mock nsIWindowWatcher. PSM calls getNewPrompter on this to get an nsIPrompt 41 // to call promptPassword. We return the mock one, above. 42 var gWindowWatcher = { 43 getNewPrompter: () => gMockPrompter, 44 QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]), 45 }; 46 47 function run_test() { 48 let windowWatcherCID = MockRegistrar.register( 49 "@mozilla.org/embedcomp/window-watcher;1", 50 gWindowWatcher 51 ); 52 registerCleanupFunction(() => { 53 MockRegistrar.unregister(windowWatcherCID); 54 }); 55 56 // Append a single quote and non-ASCII characters to the profile path. 57 let profd = Services.env.get("XPCSHELL_TEST_PROFILE_DIR"); 58 let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); 59 file.initWithPath(profd); 60 file.append("'รท1"); 61 Services.env.set("XPCSHELL_TEST_PROFILE_DIR", file.path); 62 63 let profile = do_get_profile(); // must be called before getting nsIX509CertDB 64 Assert.ok( 65 /[^\x20-\x7f]/.test(profile.path), 66 "the profile path should contain a non-ASCII character" 67 ); 68 69 let key4DBFile = do_get_file("test_sdr_preexisting_with_password/key4.db"); 70 key4DBFile.copyTo(profile, "key4.db"); 71 72 let sdr = Cc["@mozilla.org/security/sdr;1"].getService( 73 Ci.nsISecretDecoderRing 74 ); 75 76 let testcases = [ 77 // a full padding block 78 { 79 ciphertext: 80 "MDoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECGeDHwVfyFqzBBAYvqMq/kDMsrARVNdC1C8d", 81 plaintext: "password", 82 }, 83 // 7 bytes of padding 84 { 85 ciphertext: 86 "MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECCAzLDVmYG2/BAh3IoIsMmT8dQ==", 87 plaintext: "a", 88 }, 89 // 6 bytes of padding 90 { 91 ciphertext: 92 "MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECPN8zlZzn8FdBAiu2acpT8UHsg==", 93 plaintext: "bb", 94 }, 95 // 1 byte of padding 96 { 97 ciphertext: 98 "MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECD5px1eMKkJQBAgUPp35GlrDvQ==", 99 plaintext: "!seven!", 100 }, 101 // 2 bytes of padding 102 { 103 ciphertext: 104 "MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECMh0hLtKDyUdBAixw9UZsMt+vA==", 105 plaintext: "sixsix", 106 }, 107 // long plaintext requiring more than two blocks 108 { 109 ciphertext: 110 "MFoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECDRX1qi+/FX1BDATFIcIneQjvBuq3wdFxzllJt2VtUD69ACdOKAXH3eA87oHDvuHqOeCDwRy4UzoG5s=", 111 plaintext: "thisismuchlongerandsotakesupmultipleblocks", 112 }, 113 // this differs from the previous ciphertext by one bit and demonstrates 114 // that this implementation does not enforce message integrity 115 { 116 ciphertext: 117 "MFoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECDRX1qi+/FX1BDAbFIcIneQjvBuq3wdFxzllJt2VtUD69ACdOKAXH3eA87oHDvuHqOeCDwRy4UzoG5s=", 118 plaintext: "nnLbuwLRkhlongerandsotakesupmultipleblocks", 119 }, 120 ]; 121 122 for (let testcase of testcases) { 123 let decrypted = sdr.decryptString(testcase.ciphertext); 124 equal( 125 decrypted, 126 testcase.plaintext, 127 "decrypted ciphertext should match expected plaintext" 128 ); 129 } 130 equal( 131 gMockPrompter.numPrompts, 132 1, 133 "Should have been prompted for a password once" 134 ); 135 }