Bug 1474683 - Add support for importing certificates. r=flod,Felipe
authorMichael Kaply <mozilla@kaply.com>
Wed, 17 Oct 2018 16:08:25 +0000
changeset 500166 8b15bab9cde939cc2f79e43e8e1890dae04f8ad3
parent 500165 2c1353f4a3f554a95bcf73521b05ef4c0335f6e0
child 500167 39b4f60d3b07d074468898f71beccf4159f12e27
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersflod, Felipe
bugs1474683
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1474683 - Add support for importing certificates. r=flod,Felipe Differential Revision: https://phabricator.services.mozilla.com/D8286
browser/components/enterprisepolicies/Policies.jsm
browser/components/enterprisepolicies/content/aboutPolicies.js
browser/components/enterprisepolicies/schemas/policies-schema.json
browser/locales/en-US/browser/policies/policies-descriptions.ftl
--- a/browser/components/enterprisepolicies/Policies.jsm
+++ b/browser/components/enterprisepolicies/Policies.jsm
@@ -2,28 +2,32 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
-XPCOMUtils.defineLazyServiceGetter(this, "gXulStore",
-                                   "@mozilla.org/xul/xulstore;1",
-                                   "nsIXULStore");
+
+XPCOMUtils.defineLazyServiceGetters(this, {
+  gCertDB: ["@mozilla.org/security/x509certdb;1", "nsIX509CertDB"],
+  gXulStore: ["@mozilla.org/xul/xulstore;1", "nsIXULStore"],
+});
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AddonManager: "resource://gre/modules/AddonManager.jsm",
   BookmarksPolicies: "resource:///modules/policies/BookmarksPolicies.jsm",
   CustomizableUI: "resource:///modules/CustomizableUI.jsm",
   ProxyPolicies: "resource:///modules/policies/ProxyPolicies.jsm",
   WebsiteFilter: "resource:///modules/policies/WebsiteFilter.jsm",
 });
 
+XPCOMUtils.defineLazyGlobalGetters(this, ["File", "FileReader"]);
+
 const PREF_LOGLEVEL           = "browser.policies.loglevel";
 const BROWSER_DOCUMENT_URL    = AppConstants.BROWSER_CHROME_URL;
 
 XPCOMUtils.defineLazyGetter(this, "log", () => {
   let { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm", {});
   return new ConsoleAPI({
     prefix: "Policies.jsm",
     // tip: set maxLogLevel to "debug" and use log.debug() to create detailed
@@ -129,16 +133,66 @@ var Policies = {
     },
   },
 
   "Certificates": {
     onBeforeAddons(manager, param) {
       if ("ImportEnterpriseRoots" in param) {
         setAndLockPref("security.enterprise_roots.enabled", param.ImportEnterpriseRoots);
       }
+      if ("Install" in param) {
+        (async () => {
+          let dirs = [];
+          let platform = AppConstants.platform;
+          if (platform == "win") {
+            dirs = [
+              // Ugly, but there is no official way to get %USERNAME\AppData\Local\Mozilla.
+              Services.dirsvc.get("XREUSysExt", Ci.nsIFile).parent,
+            ];
+          } else if (platform == "macosx" || platform == "linux") {
+            dirs = [
+              // These two keys are named wrong. They return the Mozilla directory.
+              Services.dirsvc.get("XREUserNativeManifests", Ci.nsIFile),
+              Services.dirsvc.get("XRESysNativeManifests", Ci.nsIFile),
+            ];
+          }
+          for (let dir of dirs) {
+            dir.append(platform == "linux" ? "certificates" : "Certificates");
+            for (let certfilename of param.Install) {
+              let certfile = dir.clone();
+              certfile.append(certfilename);
+              let file;
+              try {
+                file = await File.createFromNsIFile(certfile);
+              } catch (e) {
+                log.info(`Unable to open certificate - ${certfile.path}`);
+                continue;
+              }
+              let reader = new FileReader();
+              reader.onloadend = function() {
+                if (reader.readyState != reader.DONE) {
+                  log.error(`Unable to read certificate - ${certfile.path}`);
+                  return;
+                }
+                let cert = reader.result;
+                try {
+                  if (/-----BEGIN CERTIFICATE-----/.test(cert)) {
+                    gCertDB.addCertFromBase64(pemToBase64(cert), "CTu,CTu,");
+                  } else {
+                    gCertDB.addCert(cert, "CTu,CTu,");
+                  }
+                } catch (e) {
+                  log.error(`Unable to add certificate - ${certfile.path}`);
+                }
+              };
+              reader.readAsBinaryString(file);
+            }
+          }
+        })();
+      }
     },
   },
 
   "Cookies": {
     onBeforeUIStartup(manager, param) {
       addAllowDenyPermissions("cookie", param.Allow, param.Block);
 
       if (param.Block) {
@@ -1057,8 +1111,14 @@ function blockAllChromeURLs() {
                             ChromeURLBlockPolicy.classDescription,
                             ChromeURLBlockPolicy.contractID,
                             ChromeURLBlockPolicy);
 
   Services.catMan.addCategoryEntry("content-policy",
                                    ChromeURLBlockPolicy.contractID,
                                    ChromeURLBlockPolicy.contractID, false, true);
 }
+
+function pemToBase64(pem) {
+  return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
+            .replace(/-----END CERTIFICATE-----/, "")
+            .replace(/[\r\n]/g, "");
+}
--- a/browser/components/enterprisepolicies/content/aboutPolicies.js
+++ b/browser/components/enterprisepolicies/content/aboutPolicies.js
@@ -230,16 +230,17 @@ function generateErrors() {
 function generateDocumentation() {
   let new_cont = document.getElementById("documentationContent");
   new_cont.setAttribute("id", "documentationContent");
 
   // map specific policies to a different string ID, to allow updates to
   // existing descriptions
   let string_mapping = {
     "DisableSetDesktopBackground": "DisableSetAsDesktopBackground",
+    "Certificates": "CertificatesDescription",
   };
 
   for (let policyName in schema.properties) {
     let main_tbody = document.createElement("tbody");
     main_tbody.classList.add("collapsible");
     main_tbody.addEventListener("click", function() {
       let content = this.nextElementSibling;
       content.classList.toggle("content");
--- a/browser/components/enterprisepolicies/schemas/policies-schema.json
+++ b/browser/components/enterprisepolicies/schemas/policies-schema.json
@@ -90,16 +90,22 @@
       }
     },
 
     "Certificates": {
       "type": "object",
       "properties": {
         "ImportEnterpriseRoots": {
           "type": "boolean"
+        },
+        "Install": {
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
         }
       }
     },
 
     "Cookies": {
       "type": "object",
       "properties": {
         "Allow": {
--- a/browser/locales/en-US/browser/policies/policies-descriptions.ftl
+++ b/browser/locales/en-US/browser/policies/policies-descriptions.ftl
@@ -18,17 +18,17 @@ policy-BlockAboutAddons = Block access t
 policy-BlockAboutConfig = Block access to the about:config page.
 
 policy-BlockAboutProfiles = Block access to the about:profiles page.
 
 policy-BlockAboutSupport = Block access to the about:support page.
 
 policy-Bookmarks = Create bookmarks in the Bookmarks toolbar, Bookmarks menu, or a specified folder inside them.
 
-policy-Certificates = Whether or not to use built-in certificates. This policy is Windows only at this time.
+policy-CertificatesDescription = Add certificates or use built-in certificates.
 
 policy-Cookies = Allow or deny websites to set cookies.
 
 policy-DisableAppUpdate = Prevent the browser from updating.
 
 policy-DisableBuiltinPDFViewer = Disable PDF.js, the built-in PDF viewer in { -brand-short-name }.
 
 policy-DisableDeveloperTools = Block access to the developer tools.