mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 704988: Check the add-on hotfix is signed by a specific certificate. r=robstrong, r=Unfocused
This commit is contained in:
parent
9db4de22b4
commit
7e30293660
@ -82,6 +82,8 @@ pref("extensions.blocklist.itemURL", "https://addons.mozilla.org/%LOCALE%/%APP%/
|
||||
pref("extensions.update.autoUpdateDefault", true);
|
||||
|
||||
pref("extensions.hotfix.id", "firefox-hotfix@mozilla.org");
|
||||
pref("extensions.hotfix.cert.checkAttributes", true);
|
||||
pref("extensions.hotfix.certs.1.sha1Fingerprint", "foo");
|
||||
|
||||
// Disable add-ons installed into the shared user and shared system areas by
|
||||
// default. This does not include the application directory. See the SCOPE
|
||||
|
@ -396,6 +396,7 @@ user_pref("browser.safebrowsing.provider.0.updateURL", "http://%(server)s/safebr
|
||||
// Point update checks to the local testing server for fast failures
|
||||
user_pref("extensions.update.url", "http://%(server)s/extensions-dummy/updateURL");
|
||||
user_pref("extensions.blocklist.url", "http://%(server)s/extensions-dummy/blocklistURL");
|
||||
user_pref("extensions.hotfix.url", "http://%(server)s/extensions-dummy/hotfixURL");
|
||||
// Make sure opening about:addons won't hit the network
|
||||
user_pref("extensions.webservice.discoverURL", "http://%(server)s/extensions-dummy/discoveryURL");
|
||||
// Make sure AddonRepository won't hit the network
|
||||
|
@ -56,6 +56,8 @@ const PREF_APP_UPDATE_AUTO = "app.update.auto";
|
||||
const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
|
||||
const PREF_EM_HOTFIX_LASTVERSION = "extensions.hotfix.lastVersion";
|
||||
const PREF_EM_HOTFIX_URL = "extensions.hotfix.url";
|
||||
const PREF_EM_CERT_CHECKATTRIBUTES = "extensions.hotfix.cert.checkAttributes";
|
||||
const PREF_EM_HOTFIX_CERTS = "extensions.hotfix.certs.";
|
||||
const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
|
||||
const PREF_SELECTED_LOCALE = "general.useragent.locale";
|
||||
|
||||
@ -70,6 +72,8 @@ const TOOLKIT_ID = "toolkit@mozilla.org";
|
||||
const VALID_TYPES_REGEXP = /^[\w\-]+$/;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
var CertUtils = {};
|
||||
Components.utils.import("resource://gre/modules/CertUtils.jsm", CertUtils);
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "AddonManager", "AddonManagerPrivate" ];
|
||||
|
||||
@ -831,6 +835,27 @@ var AddonManagerInternal = {
|
||||
LOG("Downloading hotfix version " + update.version);
|
||||
AddonManager.getInstallForURL(update.updateURL, function(aInstall) {
|
||||
aInstall.addListener({
|
||||
onDownloadEnded: function(aInstall) {
|
||||
try {
|
||||
if (!Services.prefs.getBoolPref(PREF_EM_CERT_CHECKATTRIBUTES))
|
||||
return;
|
||||
}
|
||||
catch (e) {
|
||||
// By default don't do certificate checks.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
CertUtils.validateCert(aInstall.certificate,
|
||||
CertUtils.readCertPrefs(PREF_EM_HOTFIX_CERTS));
|
||||
}
|
||||
catch (e) {
|
||||
WARN("The hotfix add-on was not signed by the expected " +
|
||||
"certificate and so will not be installed.");
|
||||
aInstall.cancel();
|
||||
}
|
||||
},
|
||||
|
||||
onInstallEnded: function(aInstall) {
|
||||
// Remember the last successfully installed version.
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_LASTVERSION,
|
||||
|
@ -97,6 +97,7 @@ _TEST_FILES = \
|
||||
head.js \
|
||||
browser_bug557956.js \
|
||||
browser_bug616841.js \
|
||||
browser_hotfix.js \
|
||||
browser_updatessl.js \
|
||||
browser_installssl.js \
|
||||
browser_newaddon.js \
|
||||
@ -127,6 +128,10 @@ _TEST_RESOURCES = \
|
||||
browser_eula.xml \
|
||||
browser_purchase.xml \
|
||||
discovery.html \
|
||||
signed_hotfix.rdf \
|
||||
signed_hotfix.xpi \
|
||||
unsigned_hotfix.rdf \
|
||||
unsigned_hotfix.xpi \
|
||||
more_options.xul \
|
||||
options.xul \
|
||||
redirect.sjs \
|
||||
|
186
toolkit/mozapps/extensions/test/browser/browser_hotfix.js
Normal file
186
toolkit/mozapps/extensions/test/browser/browser_hotfix.js
Normal file
@ -0,0 +1,186 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
|
||||
const PREF_EM_HOTFIX_LASTVERSION = "extensions.hotfix.lastVersion";
|
||||
const PREF_EM_HOTFIX_URL = "extensions.hotfix.url";
|
||||
const PREF_EM_HOTFIX_CERTS = "extensions.hotfix.certs.";
|
||||
const PREF_EM_CERT_CHECKATTRIBUTES = "extensions.hotfix.cert.checkAttributes";
|
||||
|
||||
const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
|
||||
const PREF_UPDATE_REQUIREBUILTINCERTS = "extensions.update.requireBuiltInCerts";
|
||||
|
||||
const PREF_APP_UPDATE_ENABLED = "app.update.enabled";
|
||||
|
||||
const HOTFIX_ID = "hotfix@tests.mozilla.org";
|
||||
|
||||
var gNextTest;
|
||||
|
||||
var SuccessfulInstallListener = {
|
||||
onDownloadCancelled: function(aInstall) {
|
||||
ok(false, "Should not have seen the download cancelled");
|
||||
is(aInstall.addon.id, HOTFIX_ID, "Should have seen the right add-on");
|
||||
|
||||
AddonManager.removeInstallListener(this);
|
||||
gNextTest();
|
||||
},
|
||||
|
||||
onInstallEnded: function(aInstall) {
|
||||
ok(true, "Should have seen the install complete");
|
||||
is(aInstall.addon.id, HOTFIX_ID, "Should have installed the right add-on");
|
||||
|
||||
AddonManager.removeInstallListener(this);
|
||||
aInstall.addon.uninstall();
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_LASTVERSION);
|
||||
gNextTest();
|
||||
}
|
||||
}
|
||||
|
||||
var FailedInstallListener = {
|
||||
onDownloadCancelled: function(aInstall) {
|
||||
ok(true, "Should have seen the download cancelled");
|
||||
is(aInstall.addon.id, HOTFIX_ID, "Should have seen the right add-on");
|
||||
|
||||
AddonManager.removeInstallListener(this);
|
||||
gNextTest();
|
||||
},
|
||||
|
||||
onInstallEnded: function(aInstall) {
|
||||
ok(false, "Should not have seen the install complete");
|
||||
is(aInstall.addon.id, HOTFIX_ID, "Should have installed the right add-on");
|
||||
|
||||
AddonManager.removeInstallListener(this);
|
||||
aInstall.addon.uninstall();
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_LASTVERSION);
|
||||
gNextTest();
|
||||
}
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true);
|
||||
Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
|
||||
Services.prefs.setBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS, false);
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_ID, HOTFIX_ID);
|
||||
var oldURL = Services.prefs.getCharPref(PREF_EM_HOTFIX_URL);
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_URL, TESTROOT + "signed_hotfix.rdf");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, false);
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_ID);
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_URL, oldURL);
|
||||
Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
|
||||
Services.prefs.clearUserPref(PREF_UPDATE_REQUIREBUILTINCERTS);
|
||||
|
||||
Services.prefs.clearUserPref(PREF_EM_CERT_CHECKATTRIBUTES);
|
||||
var prefs = Services.prefs.getChildList(PREF_EM_HOTFIX_CERTS);
|
||||
prefs.forEach(Services.prefs.clearUserPref);
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function end_test() {
|
||||
finish();
|
||||
}
|
||||
|
||||
add_test(function check_no_cert_checks() {
|
||||
Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, false);
|
||||
AddonManager.addInstallListener(SuccessfulInstallListener);
|
||||
|
||||
gNextTest = run_next_test;
|
||||
|
||||
AddonManagerPrivate.backgroundUpdateCheck();
|
||||
});
|
||||
|
||||
add_test(function check_wrong_cert_fingerprint() {
|
||||
Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "foo");
|
||||
|
||||
AddonManager.addInstallListener(FailedInstallListener);
|
||||
|
||||
gNextTest = function() {
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
|
||||
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
AddonManagerPrivate.backgroundUpdateCheck();
|
||||
});
|
||||
|
||||
add_test(function check_right_cert_fingerprint() {
|
||||
Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "3E:B9:4E:07:12:FE:3C:01:41:46:13:46:FC:84:52:1A:8C:BE:1D:A2");
|
||||
|
||||
AddonManager.addInstallListener(SuccessfulInstallListener);
|
||||
|
||||
gNextTest = function() {
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
|
||||
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
AddonManagerPrivate.backgroundUpdateCheck();
|
||||
});
|
||||
|
||||
add_test(function check_multi_cert_fingerprint_1() {
|
||||
Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "3E:B9:4E:07:12:FE:3C:01:41:46:13:46:FC:84:52:1A:8C:BE:1D:A2");
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "2.sha1Fingerprint", "foo");
|
||||
|
||||
AddonManager.addInstallListener(SuccessfulInstallListener);
|
||||
|
||||
gNextTest = function() {
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "2.sha1Fingerprint");
|
||||
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
AddonManagerPrivate.backgroundUpdateCheck();
|
||||
});
|
||||
|
||||
add_test(function check_multi_cert_fingerprint_2() {
|
||||
Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "foo");
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "2.sha1Fingerprint", "3E:B9:4E:07:12:FE:3C:01:41:46:13:46:FC:84:52:1A:8C:BE:1D:A2");
|
||||
|
||||
AddonManager.addInstallListener(SuccessfulInstallListener);
|
||||
|
||||
gNextTest = function() {
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "2.sha1Fingerprint");
|
||||
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
AddonManagerPrivate.backgroundUpdateCheck();
|
||||
});
|
||||
|
||||
add_test(function check_no_cert_no_checks() {
|
||||
Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, false);
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_URL, TESTROOT + "unsigned_hotfix.rdf");
|
||||
|
||||
AddonManager.addInstallListener(SuccessfulInstallListener);
|
||||
|
||||
gNextTest = run_next_test;
|
||||
|
||||
AddonManagerPrivate.backgroundUpdateCheck();
|
||||
});
|
||||
|
||||
add_test(function check_no_cert_cert_fingerprint_check() {
|
||||
Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
|
||||
Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "3E:B9:4E:07:12:FE:3C:01:41:46:13:46:FC:84:52:1A:8C:BE:1D:A2");
|
||||
|
||||
AddonManager.addInstallListener(FailedInstallListener);
|
||||
|
||||
gNextTest = function() {
|
||||
Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
|
||||
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
AddonManagerPrivate.backgroundUpdateCheck();
|
||||
});
|
26
toolkit/mozapps/extensions/test/browser/signed_hotfix.rdf
Normal file
26
toolkit/mozapps/extensions/test/browser/signed_hotfix.rdf
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:extension:hotfix@tests.mozilla.org">
|
||||
<em:updates>
|
||||
<Seq>
|
||||
<li>
|
||||
<Description>
|
||||
<em:version>1.0</em:version>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
<em:updateLink>https://example.com/browser/toolkit/mozapps/extensions/test/browser/signed_hotfix.xpi</em:updateLink>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</li>
|
||||
</Seq>
|
||||
</em:updates>
|
||||
</Description>
|
||||
|
||||
</RDF>
|
BIN
toolkit/mozapps/extensions/test/browser/signed_hotfix.xpi
Normal file
BIN
toolkit/mozapps/extensions/test/browser/signed_hotfix.xpi
Normal file
Binary file not shown.
26
toolkit/mozapps/extensions/test/browser/unsigned_hotfix.rdf
Normal file
26
toolkit/mozapps/extensions/test/browser/unsigned_hotfix.rdf
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:extension:hotfix@tests.mozilla.org">
|
||||
<em:updates>
|
||||
<Seq>
|
||||
<li>
|
||||
<Description>
|
||||
<em:version>1.0</em:version>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
<em:updateLink>https://example.com/browser/toolkit/mozapps/extensions/test/browser/unsigned_hotfix.xpi</em:updateLink>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</li>
|
||||
</Seq>
|
||||
</em:updates>
|
||||
</Description>
|
||||
|
||||
</RDF>
|
BIN
toolkit/mozapps/extensions/test/browser/unsigned_hotfix.xpi
Normal file
BIN
toolkit/mozapps/extensions/test/browser/unsigned_hotfix.xpi
Normal file
Binary file not shown.
@ -6,6 +6,8 @@
|
||||
|
||||
// The test extension uses an insecure update url.
|
||||
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
|
||||
// Ignore any certificate requirements the app has set
|
||||
Services.prefs.setBoolPref("extensions.hotfix.cert.checkAttributes", false);
|
||||
|
||||
do_load_httpd_js();
|
||||
var testserver;
|
||||
|
@ -39,13 +39,116 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#endif
|
||||
EXPORTED_SYMBOLS = [ "BadCertHandler", "checkCert" ];
|
||||
EXPORTED_SYMBOLS = [ "BadCertHandler", "checkCert", "readCertPrefs", "validateCert" ];
|
||||
|
||||
const Ce = Components.Exception;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* Reads a set of expected certificate attributes from preferences. The returned
|
||||
* array can be passed to validateCert or checkCert to validate that a
|
||||
* certificate matches the expected attributes. The preferences should look like
|
||||
* this:
|
||||
* prefix.1.attribute1
|
||||
* prefix.1.attribute2
|
||||
* prefix.2.attribute1
|
||||
* etc.
|
||||
* Each numeric branch contains a set of required attributes for a single
|
||||
* certificate. Having multiple numeric branches means that multiple
|
||||
* certificates would be accepted by validateCert.
|
||||
*
|
||||
* @param aPrefBranch
|
||||
* The prefix for all preferences, should end with a ".".
|
||||
* @return An array of JS objects with names / values corresponding to the
|
||||
* expected certificate's attribute names / values.
|
||||
*/
|
||||
function readCertPrefs(aPrefBranch) {
|
||||
if (Services.prefs.getBranch(aPrefBranch).getChildList("").length == 0)
|
||||
return null;
|
||||
|
||||
let certs = [];
|
||||
let counter = 1;
|
||||
while (true) {
|
||||
let prefBranchCert = Services.prefs.getBranch(aPrefBranch + counter + ".");
|
||||
let prefCertAttrs = prefBranchCert.getChildList("");
|
||||
if (prefCertAttrs.length == 0)
|
||||
break;
|
||||
|
||||
let certAttrs = {};
|
||||
for each (let prefCertAttr in prefCertAttrs)
|
||||
certAttrs[prefCertAttr] = prefBranchCert.getCharPref(prefCertAttr);
|
||||
|
||||
certs.push(certAttrs);
|
||||
counter++;
|
||||
}
|
||||
|
||||
return certs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that an nsIX509Cert matches the expected certificate attribute
|
||||
* values.
|
||||
*
|
||||
* @param aCertificate
|
||||
* The nsIX509Cert to compare to the expected attributes.
|
||||
* @param aCerts
|
||||
* An array of JS objects with names / values corresponding to the
|
||||
* expected certificate's attribute names / values. If this is null or
|
||||
* an empty array then no checks are performed.
|
||||
* @throws NS_ERROR_ILLEGAL_VALUE if a certificate attribute name from the
|
||||
* aCerts param does not exist or the value for a certificate attribute
|
||||
* from the aCerts param is different than the expected value or
|
||||
* aCertificate wasn't specified and aCerts is not null or an empty
|
||||
* array.
|
||||
*/
|
||||
function validateCert(aCertificate, aCerts) {
|
||||
// If there are no certificate requirements then just exit
|
||||
if (!aCerts || aCerts.length == 0)
|
||||
return;
|
||||
|
||||
if (!aCertificate) {
|
||||
const missingCertErr = "A required certificate was not present.";
|
||||
Cu.reportError(missingCertErr);
|
||||
throw new Ce(missingCertErr, Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
}
|
||||
|
||||
var errors = [];
|
||||
for (var i = 0; i < aCerts.length; ++i) {
|
||||
var error = false;
|
||||
var certAttrs = aCerts[i];
|
||||
for (var name in certAttrs) {
|
||||
if (!(name in aCertificate)) {
|
||||
error = true;
|
||||
errors.push("Expected attribute '" + name + "' not present in " +
|
||||
"certificate.");
|
||||
break;
|
||||
}
|
||||
if (aCertificate[name] != certAttrs[name]) {
|
||||
error = true;
|
||||
errors.push("Expected certificate attribute '" + name + "' " +
|
||||
"value incorrect, expected: '" + certAttrs[name] +
|
||||
"', got: '" + aCertificate[name] + "'.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error)
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
errors.forEach(Cu.reportError);
|
||||
const certCheckErr = "Certificate checks failed. See previous errors " +
|
||||
"for details.";
|
||||
Cu.reportError(certCheckErr);
|
||||
throw new Ce(certCheckErr, Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the connection must be HTTPS and if so, only allows built-in
|
||||
* certificates and validates application specified certificate attribute
|
||||
@ -65,7 +168,7 @@ const Cu = Components.utils;
|
||||
* @throws NS_ERROR_UNEXPECTED if a certificate is expected and the URI scheme
|
||||
* is not https.
|
||||
* NS_ERROR_ILLEGAL_VALUE if a certificate attribute name from the
|
||||
* cert param does not exist or the value for a certificate attribute
|
||||
* aCerts param does not exist or the value for a certificate attribute
|
||||
* from the aCerts param is different than the expected value.
|
||||
* NS_ERROR_ABORT if the certificate issuer is not built-in.
|
||||
*/
|
||||
@ -83,37 +186,7 @@ function checkCert(aChannel, aAllowNonBuiltInCerts, aCerts) {
|
||||
aChannel.securityInfo.QueryInterface(Ci.nsISSLStatusProvider).
|
||||
SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
|
||||
|
||||
if (aCerts) {
|
||||
for (var i = 0; i < aCerts.length; ++i) {
|
||||
var error = false;
|
||||
var certAttrs = aCerts[i];
|
||||
for (var name in certAttrs) {
|
||||
if (!(name in cert)) {
|
||||
error = true;
|
||||
Cu.reportError("Expected attribute '" + name + "' not present in " +
|
||||
"certificate.");
|
||||
break;
|
||||
}
|
||||
if (cert[name] != certAttrs[name]) {
|
||||
error = true;
|
||||
Cu.reportError("Expected certificate attribute '" + name + "' " +
|
||||
"value incorrect, expected: '" + certAttrs[name] +
|
||||
"', got: '" + cert[name] + "'.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error)
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
const certCheckErr = "Certificate checks failed. See previous errors " +
|
||||
"for details.";
|
||||
Cu.reportError(certCheckErr);
|
||||
throw new Ce(certCheckErr, Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
}
|
||||
}
|
||||
validateCert(cert, aCerts);
|
||||
|
||||
if (aAllowNonBuiltInCerts === true)
|
||||
return;
|
||||
|
97
toolkit/mozapps/shared/test/unit/test_readCertPrefs.js
Normal file
97
toolkit/mozapps/shared/test/unit/test_readCertPrefs.js
Normal file
@ -0,0 +1,97 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/CertUtils.jsm");
|
||||
|
||||
const PREF_PREFIX = "certutils.certs.";
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function resetPrefs() {
|
||||
var prefs = Services.prefs.getChildList(PREF_PREFIX);
|
||||
prefs.forEach(Services.prefs.clearUserPref);
|
||||
}
|
||||
|
||||
function attributes_match(aCert, aExpected) {
|
||||
if (Object.keys(aCert).length != Object.keys(aExpected).length)
|
||||
return false;
|
||||
|
||||
for (var attribute in aCert) {
|
||||
if (!(attribute in aExpected))
|
||||
return false;
|
||||
if (aCert[attribute] != aExpected[attribute])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function test_results(aCerts, aExpected) {
|
||||
do_check_eq(aCerts.length, aExpected.length);
|
||||
|
||||
for (var i = 0; i < aCerts.length; i++) {
|
||||
if (!attributes_match(aCerts[i], aExpected[i])) {
|
||||
dump("Attributes for certificate " + (i + 1) + " did not match expected attributes\n");
|
||||
dump("Saw: " + aCerts[i].toSource() + "\n");
|
||||
dump("Expected: " + aExpected[i].toSource() + "\n");
|
||||
do_check_true(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_test(function test_singleCert() {
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.attribute1", "foo");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.attribute2", "bar");
|
||||
|
||||
var certs = readCertPrefs(PREF_PREFIX);
|
||||
test_results(certs, [{
|
||||
attribute1: "foo",
|
||||
attribute2: "bar"
|
||||
}]);
|
||||
|
||||
resetPrefs();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_multipleCert() {
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.md5Fingerprint", "cf84a9a2a804e021f27cb5128fe151f4");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.nickname", "1st cert");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "2.md5Fingerprint", "9441051b7eb50e5ca2226095af710c1a");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "2.nickname", "2nd cert");
|
||||
|
||||
var certs = readCertPrefs(PREF_PREFIX);
|
||||
test_results(certs, [{
|
||||
md5Fingerprint: "cf84a9a2a804e021f27cb5128fe151f4",
|
||||
nickname: "1st cert"
|
||||
}, {
|
||||
md5Fingerprint: "9441051b7eb50e5ca2226095af710c1a",
|
||||
nickname: "2nd cert"
|
||||
}]);
|
||||
|
||||
resetPrefs();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_skippedCert() {
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.issuerName", "Mozilla");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.nickname", "1st cert");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "2.issuerName", "Top CA");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "2.nickname", "2nd cert");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "4.issuerName", "Unknown CA");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "4.nickname", "Ignored cert");
|
||||
|
||||
var certs = readCertPrefs(PREF_PREFIX);
|
||||
test_results(certs, [{
|
||||
issuerName: "Mozilla",
|
||||
nickname: "1st cert"
|
||||
}, {
|
||||
issuerName: "Top CA",
|
||||
nickname: "2nd cert"
|
||||
}]);
|
||||
|
||||
resetPrefs();
|
||||
run_next_test();
|
||||
});
|
@ -3,3 +3,5 @@ head =
|
||||
tail =
|
||||
|
||||
[test_FileUtils.js]
|
||||
|
||||
[test_readCertPrefs.js]
|
||||
|
@ -2394,24 +2394,8 @@ Checker.prototype = {
|
||||
var prefs = Services.prefs;
|
||||
var certs = null;
|
||||
if (!prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE) &&
|
||||
getPref("getBoolPref", PREF_APP_UPDATE_CERT_CHECKATTRS, true) &&
|
||||
prefs.getBranch(PREF_APP_UPDATE_CERTS_BRANCH).getChildList("").length) {
|
||||
certs = [];
|
||||
let counter = 1;
|
||||
while (true) {
|
||||
let prefBranchCert = prefs.getBranch(PREF_APP_UPDATE_CERTS_BRANCH +
|
||||
counter + ".");
|
||||
let prefCertAttrs = prefBranchCert.getChildList("");
|
||||
if (prefCertAttrs.length == 0)
|
||||
break;
|
||||
|
||||
let certAttrs = {};
|
||||
for each (let prefCertAttr in prefCertAttrs)
|
||||
certAttrs[prefCertAttr] = prefBranchCert.getCharPref(prefCertAttr);
|
||||
|
||||
certs.push(certAttrs);
|
||||
counter++;
|
||||
}
|
||||
getPref("getBoolPref", PREF_APP_UPDATE_CERT_CHECKATTRS, true)) {
|
||||
certs = gCertUtils.readCertPrefs(PREF_APP_UPDATE_CERTS_BRANCH);
|
||||
}
|
||||
|
||||
try {
|
||||
|
Loading…
Reference in New Issue
Block a user