diff options
Diffstat (limited to 'toolkit/modules')
-rw-r--r-- | toolkit/modules/GMPInstallManager.sys.mjs | 48 | ||||
-rw-r--r-- | toolkit/modules/GMPUtils.sys.mjs | 1 | ||||
-rw-r--r-- | toolkit/modules/tests/xpcshell/test_GMPInstallManager.js | 54 |
3 files changed, 100 insertions, 3 deletions
diff --git a/toolkit/modules/GMPInstallManager.sys.mjs b/toolkit/modules/GMPInstallManager.sys.mjs index 9cb4802e58..421a843c71 100644 --- a/toolkit/modules/GMPInstallManager.sys.mjs +++ b/toolkit/modules/GMPInstallManager.sys.mjs @@ -43,6 +43,16 @@ const LOCAL_GMP_SOURCES = [ }, ]; +function getLocalSources() { + if (GMPPrefs.getBool(GMPPrefs.KEY_ALLOW_LOCAL_SOURCES, true)) { + return LOCAL_GMP_SOURCES; + } + + let log = getScopedLogger("GMPInstallManager.downloadLocalConfig"); + log.info("ignoring local sources"); + return []; +} + function downloadJSON(uri) { let log = getScopedLogger("GMPInstallManager.checkForAddons"); log.info("fetching config from: " + uri); @@ -70,7 +80,7 @@ function downloadJSON(uri) { function downloadLocalConfig() { let log = getScopedLogger("GMPInstallManager.downloadLocalConfig"); return Promise.all( - LOCAL_GMP_SOURCES.map(conf => { + getLocalSources().map(conf => { return downloadJSON(conf.src).then(addons => { let platforms = addons.vendors[conf.id].platforms; let target = Services.appinfo.OS + "_" + lazy.UpdateUtils.ABI; @@ -146,6 +156,36 @@ GMPInstallManager.prototype = { }, /** + * Determines the root to use for verifying content signatures. + * @param url + * The Balrog URL, i.e. the return value of _getURL(). + */ + _getContentSignatureRootForURL(url) { + // The prod and stage URLs of Balrog are documented at: + // https://mozilla-balrog.readthedocs.io/en/latest/infrastructure.html + // Note: we are matching by prefix without the full domain nor slash, to + // enable us to move to a different host name in the future if desired. + if (url.startsWith("https://aus")) { + return Ci.nsIContentSignatureVerifier.ContentSignatureProdRoot; + } + if (url.startsWith("https://stage.")) { + return Ci.nsIContentSignatureVerifier.ContentSignatureStageRoot; + } + if (Services.env.exists("XPCSHELL_TEST_PROFILE_DIR")) { + return Ci.nsIX509CertDB.AppXPCShellRoot; + } + // When content signature verification for GMP was added (bug 1714621), a + // pref existed to configure an arbitrary root, which enabled local testing. + // This pref was removed later in bug 1769669, and replaced with hard-coded + // roots (prod and tests only). Support for testing against the stage server + // was restored in bug 1771992. + // Note: other verifiers ultimately fall back to ContentSignatureLocalRoot, + // to support local development. Here we use ContentSignatureProdRoot to + // minimize risk (and the unclear demand for "local" development). + return Ci.nsIContentSignatureVerifier.ContentSignatureProdRoot; + }, + + /** * Records telemetry results on if fetching update.xml from Balrog succeeded * when content signature was used to verify the response from Balrog. * @param didGetAddonList @@ -318,15 +358,17 @@ GMPInstallManager.prototype = { } let url = await this._getURL(); + let trustedContentSignatureRoot = this._getContentSignatureRootForURL(url); log.info( - `Fetching product addon list url=${url}, allowNonBuiltIn=${allowNonBuiltIn}, certs=${certs}, checkContentSignature=${checkContentSignature}` + `Fetching product addon list url=${url}, allowNonBuiltIn=${allowNonBuiltIn}, certs=${certs}, checkContentSignature=${checkContentSignature}, trustedContentSignatureRoot=${trustedContentSignatureRoot}` ); let addonPromise = ProductAddonChecker.getProductAddonList( url, allowNonBuiltIn, certs, - checkContentSignature + checkContentSignature, + trustedContentSignatureRoot ) .then(res => { if (checkContentSignature) { diff --git a/toolkit/modules/GMPUtils.sys.mjs b/toolkit/modules/GMPUtils.sys.mjs index 488a024d13..c21576e0a9 100644 --- a/toolkit/modules/GMPUtils.sys.mjs +++ b/toolkit/modules/GMPUtils.sys.mjs @@ -124,6 +124,7 @@ export var GMPPrefs = { KEY_PLUGIN_ABI: "media.{0}.abi", KEY_PLUGIN_FORCE_SUPPORTED: "media.{0}.forceSupported", KEY_PLUGIN_ALLOW_X64_ON_ARM64: "media.{0}.allow-x64-plugin-on-arm64", + KEY_ALLOW_LOCAL_SOURCES: "media.gmp-manager.allowLocalSources", KEY_URL: "media.gmp-manager.url", KEY_URL_OVERRIDE: "media.gmp-manager.url.override", KEY_CERT_CHECKATTRS: "media.gmp-manager.cert.checkAttributes", diff --git a/toolkit/modules/tests/xpcshell/test_GMPInstallManager.js b/toolkit/modules/tests/xpcshell/test_GMPInstallManager.js index 87de57efaf..e755690e6c 100644 --- a/toolkit/modules/tests/xpcshell/test_GMPInstallManager.js +++ b/toolkit/modules/tests/xpcshell/test_GMPInstallManager.js @@ -802,6 +802,60 @@ add_task(async function test_checkForAddons_contentSignatureFailure() { }); /** + * Tests that the signature verification URL is as expected. + */ +add_task(async function test_checkForAddons_get_verifier_url() { + const previousUrlOverride = setupContentSigTestPrefs(); + + let installManager = new GMPInstallManager(); + // checkForAddons() calls _getContentSignatureRootForURL() with the return + // value of _getURL(), which is effectively KEY_URL_OVERRIDE or KEY_URL + // followed by some normalization. + const rootForUrl = async () => { + const url = await installManager._getURL(); + return installManager._getContentSignatureRootForURL(url); + }; + + Assert.equal( + await rootForUrl(), + Ci.nsIX509CertDB.AppXPCShellRoot, + "XPCShell root used by default in xpcshell test" + ); + + const defaultPrefs = Services.prefs.getDefaultBranch(""); + const defaultUrl = defaultPrefs.getStringPref(GMPPrefs.KEY_URL); + Preferences.set(GMPPrefs.KEY_URL_OVERRIDE, defaultUrl); + Assert.equal( + await rootForUrl(), + Ci.nsIContentSignatureVerifier.ContentSignatureProdRoot, + "Production cert should be used for the default Balrog URL: " + defaultUrl + ); + + // The current Balrog endpoint is at aus5.mozilla.org. Confirm that the prod + // cert is used even if we bump the version (e.g. aus6): + const potentialProdUrl = "https://aus1337.mozilla.org/potential/prod/URL"; + Preferences.set(GMPPrefs.KEY_URL_OVERRIDE, potentialProdUrl); + Assert.equal( + await rootForUrl(), + Ci.nsIContentSignatureVerifier.ContentSignatureProdRoot, + "Production cert should be used for: " + potentialProdUrl + ); + + // Stage URL documented at https://mozilla-balrog.readthedocs.io/en/latest/infrastructure.html + const stageUrl = "https://stage.balrog.nonprod.cloudops.mozgcp.net/etc."; + Preferences.set(GMPPrefs.KEY_URL_OVERRIDE, stageUrl); + Assert.equal( + await rootForUrl(), + Ci.nsIContentSignatureVerifier.ContentSignatureStageRoot, + "Stage cert should be used with the stage URL: " + stageUrl + ); + + installManager.uninit(); + + revertContentSigTestPrefs(previousUrlOverride); +}); + +/** * Tests that checkForAddons() works as expected when certificate pinning * checking is enabled. We plan to move away from cert pinning in favor of * content signature checks, but part of doing this is comparing the telemetry |