// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- // Any copyright is dedicated to the Public Domain. // http://creativecommons.org/publicdomain/zero/1.0/ "use strict"; // Tests that a CA certificate can still be imported if the user has a primary // password set. do_get_profile(); const gCertDB = Cc["@mozilla.org/security/x509certdb;1"].getService( Ci.nsIX509CertDB ); const CA_CERT_COMMON_NAME = "importedCA"; let gCACertImportDialogCount = 0; // Mock implementation of nsICertificateDialogs. const gCertificateDialogs = { confirmDownloadCACert: (ctx, cert, trust) => { gCACertImportDialogCount++; equal( cert.commonName, CA_CERT_COMMON_NAME, "CA cert to import should have the correct CN" ); trust.value = Ci.nsIX509CertDB.TRUSTED_EMAIL; return true; }, setPKCS12FilePassword: () => { // This is only relevant to exporting. ok(false, "setPKCS12FilePassword() should not have been called"); }, getPKCS12FilePassword: () => { // We don't test anything that calls this method yet. ok(false, "getPKCS12FilePassword() should not have been called"); }, QueryInterface: ChromeUtils.generateQI(["nsICertificateDialogs"]), }; var gMockPrompter = { passwordToTry: "password", numPrompts: 0, // This intentionally does not use arrow function syntax to avoid an issue // where in the context of the arrow function, |this != gMockPrompter| due to // how objects get wrapped when going across xpcom boundaries. promptPassword(dialogTitle, text, password, checkMsg) { this.numPrompts++; if (this.numPrompts > 1) { // don't keep retrying a bad password return false; } equal( text, "Please enter your Primary Password.", "password prompt text should be as expected" ); equal(checkMsg, null, "checkMsg should be null"); ok(this.passwordToTry, "passwordToTry should be non-null"); password.value = this.passwordToTry; return true; }, QueryInterface: ChromeUtils.generateQI(["nsIPrompt"]), // Again with the arrow function issue. getInterface(iid) { if (iid.equals(Ci.nsIPrompt)) { return this; } throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); }, }; function getCertAsByteArray(certPath) { let certFile = do_get_file(certPath, false); let certBytes = readFile(certFile); let byteArray = []; for (let i = 0; i < certBytes.length; i++) { byteArray.push(certBytes.charCodeAt(i)); } return byteArray; } function findCertByCommonName(commonName) { for (let cert of gCertDB.getCerts()) { if (cert.commonName == commonName) { return cert; } } return null; } function run_test() { let certificateDialogsCID = MockRegistrar.register( "@mozilla.org/nsCertificateDialogs;1", gCertificateDialogs ); registerCleanupFunction(() => { MockRegistrar.unregister(certificateDialogsCID); }); // Set a primary password. let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].getService( Ci.nsIPK11TokenDB ); let token = tokenDB.getInternalKeyToken(); token.initPassword("password"); token.logoutSimple(); // Sanity check the CA cert is missing. equal( findCertByCommonName(CA_CERT_COMMON_NAME), null, "CA cert should not be in the database before import" ); // Import and check for success. let caArray = getCertAsByteArray("test_certDB_import/importedCA.pem"); gCertDB.importCertificates( caArray, caArray.length, Ci.nsIX509Cert.CA_CERT, gMockPrompter ); equal( gCACertImportDialogCount, 1, "Confirmation dialog for the CA cert should only be shown once" ); let caCert = findCertByCommonName(CA_CERT_COMMON_NAME); notEqual(caCert, null, "CA cert should now be found in the database"); ok( gCertDB.isCertTrusted( caCert, Ci.nsIX509Cert.CA_CERT, Ci.nsIX509CertDB.TRUSTED_EMAIL ), "CA cert should be trusted for e-mail" ); }