tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }