зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1216469 - Bypass verification for signed packages from trust origins. r=valentin
This commit is contained in:
Родитель
c006ac8bbd
Коммит
3d02a2da65
|
@ -1452,12 +1452,7 @@ pref("network.http.enable-packaged-apps", false);
|
|||
|
||||
// Enable this to bring in the signature verification if the signature exists.
|
||||
// Set to false if you don't need the signed packaged web app support (i.e. NSec).
|
||||
pref("network.http.packaged-signed-apps-enabled", false);
|
||||
|
||||
// Enable this pref to skip verification process. The packaged app
|
||||
// will be considered signed no matter the package has a valid/invalid
|
||||
// signature or no signature.
|
||||
pref("network.http.packaged-apps-developer-mode", false);
|
||||
pref("network.http.signed-packages.enabled", false);
|
||||
|
||||
// default values for FTP
|
||||
// in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
|
||||
|
|
|
@ -17,7 +17,7 @@ interface nsIPackagedAppVerifierListener;
|
|||
* onStartRequest/onDataAvailable/onStopRequest.
|
||||
*
|
||||
*/
|
||||
[scriptable, uuid(fbb28ef8-d3d0-4a2b-af98-8010163a2bfb)]
|
||||
[scriptable, uuid(37a5c208-0fce-4ad6-8431-aeb904dfe543)]
|
||||
interface nsIPackagedAppVerifier : nsIStreamListener
|
||||
{
|
||||
// The package identifier of the signed package. For a unsigned package, this
|
||||
|
@ -50,6 +50,7 @@ interface nsIPackagedAppVerifier : nsIStreamListener
|
|||
* The verifier init function.
|
||||
*/
|
||||
void init(in nsIPackagedAppVerifierListener aListener,
|
||||
in ACString aPackageOrigin,
|
||||
in ACString aSignature,
|
||||
in nsICacheEntry aPackageCacheEntry);
|
||||
|
||||
|
|
|
@ -447,6 +447,7 @@ PackagedAppService::PackagedAppDownloader::EnsureVerifier(nsIRequest *aRequest)
|
|||
nsCOMPtr<nsICacheEntry> packageCacheEntry = GetPackageCacheEntry(aRequest);
|
||||
|
||||
mVerifier = new PackagedAppVerifier(this,
|
||||
mPackageOrigin,
|
||||
signature,
|
||||
packageCacheEntry);
|
||||
}
|
||||
|
|
|
@ -16,12 +16,11 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "nsIPackagedAppUtils.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIURL.h"
|
||||
|
||||
static const short kResourceHashType = nsICryptoHash::SHA256;
|
||||
|
||||
// If it's true, all the verification will be skipped and the package will
|
||||
// be treated signed.
|
||||
static bool gDeveloperMode = false;
|
||||
static bool gSignedAppEnabled = false;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -40,14 +39,15 @@ PackagedAppVerifier::PackagedAppVerifier()
|
|||
MOZ_RELEASE_ASSERT(NS_IsMainThread(),
|
||||
"PackagedAppVerifier::OnResourceVerified must be on main thread");
|
||||
|
||||
Init(nullptr, EmptyCString(), nullptr);
|
||||
Init(nullptr, EmptyCString(), EmptyCString(), nullptr);
|
||||
}
|
||||
|
||||
PackagedAppVerifier::PackagedAppVerifier(nsIPackagedAppVerifierListener* aListener,
|
||||
const nsACString& aPackageOrigin,
|
||||
const nsACString& aSignature,
|
||||
nsICacheEntry* aPackageCacheEntry)
|
||||
{
|
||||
Init(aListener, aSignature, aPackageCacheEntry);
|
||||
Init(aListener, aPackageOrigin, aSignature, aPackageCacheEntry);
|
||||
}
|
||||
|
||||
PackagedAppVerifier::~PackagedAppVerifier()
|
||||
|
@ -61,26 +61,29 @@ PackagedAppVerifier::~PackagedAppVerifier()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP PackagedAppVerifier::Init(nsIPackagedAppVerifierListener* aListener,
|
||||
const nsACString& aPackageOrigin,
|
||||
const nsACString& aSignature,
|
||||
nsICacheEntry* aPackageCacheEntry)
|
||||
{
|
||||
static bool onceThru = false;
|
||||
if (!onceThru) {
|
||||
Preferences::AddBoolVarCache(&gDeveloperMode,
|
||||
"network.http.packaged-apps-developer-mode", false);
|
||||
Preferences::AddBoolVarCache(&gSignedAppEnabled,
|
||||
"network.http.packaged-signed-apps-enabled", false);
|
||||
"network.http.signed-packages.enabled", false);
|
||||
onceThru = true;
|
||||
}
|
||||
|
||||
mListener = aListener;
|
||||
mState = STATE_UNKNOWN;
|
||||
mPackageOrigin = aPackageOrigin;
|
||||
mSignature = aSignature;
|
||||
mIsPackageSigned = false;
|
||||
mPackageCacheEntry = aPackageCacheEntry;
|
||||
mIsFirstResource = true;
|
||||
mManifest = EmptyCString();
|
||||
|
||||
mBypassVerification = (mPackageOrigin ==
|
||||
Preferences::GetCString("network.http.signed-packages.trusted-origin"));
|
||||
|
||||
nsresult rv;
|
||||
mPackagedAppUtils = do_CreateInstance(NS_PACKAGEDAPPUTILS_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -277,8 +280,11 @@ PackagedAppVerifier::VerifyManifest(const ResourceCacheInfo* aInfo)
|
|||
|
||||
LOG(("Signature: length = %u\n%s", mSignature.Length(), mSignature.get()));
|
||||
LOG(("Manifest: length = %u\n%s", mManifest.Length(), mManifest.get()));
|
||||
|
||||
bool useDeveloperRoot =
|
||||
!Preferences::GetCString("network.http.signed-packages.developer-root").IsEmpty();
|
||||
nsresult rv = mPackagedAppUtils->VerifyManifest(mSignature, mManifest,
|
||||
this, gDeveloperMode);
|
||||
this, useDeveloperRoot);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("VerifyManifest FAILED rv = %u", (unsigned)rv));
|
||||
}
|
||||
|
@ -305,6 +311,12 @@ PackagedAppVerifier::VerifyResource(const ResourceCacheInfo* aInfo)
|
|||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
if (mBypassVerification) {
|
||||
LOG(("Origin is trusted. Bypass integrity check."));
|
||||
FireVerifiedEvent(false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSignature.IsEmpty()) {
|
||||
LOG(("No signature. No need to do resource integrity check."));
|
||||
FireVerifiedEvent(false, true);
|
||||
|
@ -339,7 +351,8 @@ PackagedAppVerifier::OnManifestVerified(bool aSuccess)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!aSuccess && gDeveloperMode) {
|
||||
|
||||
if (!aSuccess && mBypassVerification) {
|
||||
aSuccess = true;
|
||||
LOG(("Developer mode! Treat junk signature valid."));
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ public:
|
|||
PackagedAppVerifier();
|
||||
|
||||
PackagedAppVerifier(nsIPackagedAppVerifierListener* aListener,
|
||||
const nsACString& aPackageOrigin,
|
||||
const nsACString& aSignature,
|
||||
nsICacheEntry* aPackageCacheEntry);
|
||||
|
||||
|
@ -170,6 +171,9 @@ private:
|
|||
// Whether this package app is signed.
|
||||
bool mIsPackageSigned;
|
||||
|
||||
// Whether we should bypass verification.
|
||||
bool mBypassVerification;
|
||||
|
||||
// The package cache entry (e.g. http://foo.com/app.pak) used to store
|
||||
// any necessarry signed package information.
|
||||
nsCOMPtr<nsICacheEntry> mPackageCacheEntry;
|
||||
|
|
|
@ -21,8 +21,8 @@ var Cr = SpecialPowers.Cr;
|
|||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["network.http.enable-packaged-apps", true],
|
||||
["network.http.packaged-signed-apps-enabled", true],
|
||||
["dom.ipc.processPriorityManager.testMode", true],
|
||||
["network.http.signed-packages.enabled", true],
|
||||
["dom.ipc.processPriorityManager.enabled", true],
|
||||
["dom.ipc.tabs.disabled", false],
|
||||
["dom.ipc.processCount", 3],
|
||||
|
|
|
@ -211,15 +211,16 @@ function run_test()
|
|||
|
||||
// Enable the feature and save the original pref value
|
||||
originalPref = Services.prefs.getBoolPref("network.http.enable-packaged-apps");
|
||||
originalSignedAppEnabled = Services.prefs.getBoolPref("network.http.packaged-signed-apps-enabled");
|
||||
originalSignedAppEnabled = Services.prefs.getBoolPref("network.http.signed-packages.enabled");
|
||||
Services.prefs.setBoolPref("network.http.enable-packaged-apps", true);
|
||||
Services.prefs.setBoolPref("network.http.packaged-signed-apps-enabled", true);
|
||||
Services.prefs.setBoolPref("network.http.signed-packages.enabled", true);
|
||||
do_register_cleanup(reset_pref);
|
||||
|
||||
add_test(test_channel);
|
||||
add_test(test_channel_no_notificationCallbacks);
|
||||
add_test(test_channel_uris);
|
||||
|
||||
add_test(test_channel_with_bad_signature_from_trusted_origin);
|
||||
add_test(test_channel_with_bad_signature);
|
||||
add_test(test_channel_with_good_signature);
|
||||
|
||||
|
@ -236,6 +237,21 @@ function test_channel_with_bad_signature() {
|
|||
}), null);
|
||||
}
|
||||
|
||||
function test_channel_with_bad_signature_from_trusted_origin() {
|
||||
let pref = "network.http.signed-packages.trusted-origin";
|
||||
ok(!!Ci.nsISupportsString, "Ci.nsISupportsString");
|
||||
let origin = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
|
||||
origin.data = uri + "^appId=1024";
|
||||
Services.prefs.setComplexValue(pref, Ci.nsISupportsString, origin);
|
||||
var channel = make_channel(uri+"/package_with_bad_signature!//index.html");
|
||||
channel.notificationCallbacks = new LoadContextCallback(1024, false, false, false);
|
||||
channel.asyncOpen(new Listener(function(l) {
|
||||
do_check_true(l.gotStopRequestOK);
|
||||
Services.prefs.clearUserPref(pref);
|
||||
run_next_test();
|
||||
}), null);
|
||||
}
|
||||
|
||||
function test_channel_with_good_signature() {
|
||||
var channel = make_channel(uri+"/package_with_good_signature!//index.html");
|
||||
channel.notificationCallbacks = new LoadContextCallback(1024, false, false, false);
|
||||
|
@ -281,5 +297,5 @@ function check_regular_response(request, buffer) {
|
|||
function reset_pref() {
|
||||
// Set the pref to its original value
|
||||
Services.prefs.setBoolPref("network.http.enable-packaged-apps", originalPref);
|
||||
Services.prefs.setBoolPref("network.http.packaged-signed-apps-enabled", originalSignedAppEnabled);
|
||||
Services.prefs.setBoolPref("network.http.signed-packages.enabled", originalSignedAppEnabled);
|
||||
}
|
||||
|
|
|
@ -220,20 +220,15 @@ function run_test()
|
|||
httpserver.registerPathHandler("/signedPackage", signedPackagedAppContentHandler);
|
||||
httpserver.start(-1);
|
||||
|
||||
// We will enable the developer mode in 'test_signed_package_callback'.
|
||||
// So restore it after testing.
|
||||
//
|
||||
// TODO: To be removed in Bug 1178518.
|
||||
do_register_cleanup(function() {
|
||||
gPrefs.clearUserPref("network.http.packaged-apps-developer-mode");
|
||||
gPrefs.clearUserPref("network.http.packaged-signed-apps-enabled");
|
||||
gPrefs.clearUserPref("network.http.signed-packages.enabled");
|
||||
});
|
||||
|
||||
paservice = Cc["@mozilla.org/network/packaged-app-service;1"]
|
||||
.getService(Ci.nsIPackagedAppService);
|
||||
ok(!!paservice, "test service exists");
|
||||
|
||||
gPrefs.setBoolPref("network.http.packaged-signed-apps-enabled", true);
|
||||
gPrefs.setBoolPref("network.http.signed-packages.enabled", true);
|
||||
|
||||
add_test(test_bad_args);
|
||||
|
||||
|
|
|
@ -40,16 +40,6 @@ const kStatusCodeIdx = 1;
|
|||
const kVerificationSuccessIdx = 2;
|
||||
const kContentIdx = 3;
|
||||
|
||||
function enable_developer_mode()
|
||||
{
|
||||
gPrefs.setBoolPref("network.http.packaged-apps-developer-mode", true);
|
||||
}
|
||||
|
||||
function reset_developer_mode()
|
||||
{
|
||||
gPrefs.clearUserPref("network.http.packaged-apps-developer-mode");
|
||||
}
|
||||
|
||||
function createVerifierListener(aExpecetedCallbacks,
|
||||
aExpectedPackageId,
|
||||
aExpectedIsSigned,
|
||||
|
@ -90,7 +80,6 @@ function createVerifierListener(aExpecetedCallbacks,
|
|||
}
|
||||
|
||||
if (isLastPart) {
|
||||
reset_developer_mode();
|
||||
run_next_test();
|
||||
}
|
||||
},
|
||||
|
@ -137,12 +126,12 @@ function createPackageCache(aPackageUriAsAscii, aLoadContextInfo) {
|
|||
return cacheStorage.openTruncate(uri, '');
|
||||
}
|
||||
|
||||
function test_no_signature(aDeveloperMode) {
|
||||
function test_no_signature(aBypassVerification) {
|
||||
const kOrigin = 'http://foo.com';
|
||||
|
||||
aDeveloperMode = !!aDeveloperMode;
|
||||
aBypassVerification = !!aBypassVerification;
|
||||
|
||||
// If the package has no signature and not in developer mode, the package is unsigned
|
||||
// If the package has no signature, the package is unsigned
|
||||
// but the verification result is always true.
|
||||
|
||||
const expectedCallbacks = [
|
||||
|
@ -158,7 +147,7 @@ function test_no_signature(aDeveloperMode) {
|
|||
let isPackageSigned = false;
|
||||
|
||||
// We only require the package URL to be different in each test case.
|
||||
let packageUriString = kOrigin + '/pak' + (aDeveloperMode ? '-dev' : '');
|
||||
let packageUriString = kOrigin + '/pak' + (aBypassVerification ? '-dev' : '');
|
||||
|
||||
let packageCacheEntry =
|
||||
createPackageCache(packageUriString, gLoadContextInfoFactory.default);
|
||||
|
@ -168,21 +157,21 @@ function test_no_signature(aDeveloperMode) {
|
|||
isPackageSigned,
|
||||
packageCacheEntry);
|
||||
|
||||
gVerifier.init(verifierListener, '', packageCacheEntry);
|
||||
gVerifier.init(verifierListener, kOrigin, '', packageCacheEntry);
|
||||
|
||||
feedResources(expectedCallbacks, '');
|
||||
}
|
||||
|
||||
function test_invalid_signature(aDeveloperMode) {
|
||||
function test_invalid_signature(aBypassVerification) {
|
||||
const kOrigin = 'http://bar.com';
|
||||
|
||||
aDeveloperMode = !!aDeveloperMode;
|
||||
aBypassVerification = !!aBypassVerification;
|
||||
|
||||
// Since we haven't implemented signature verification, the verification always
|
||||
// fails if the signature exists.
|
||||
|
||||
let verificationResult = aDeveloperMode; // Verification always success in developer mode.
|
||||
let isPackageSigned = aDeveloperMode; // Package is always considered as signed in developer mode.
|
||||
let verificationResult = aBypassVerification; // Verification always success in developer mode.
|
||||
let isPackageSigned = aBypassVerification; // Package is always considered as signed in developer mode.
|
||||
|
||||
const kPackagedId = '611FC2FE-491D-4A47-B3B3-43FBDF6F404F';
|
||||
const kManifestContent = 'Content-Location: manifest.webapp\r\n' +
|
||||
|
@ -193,35 +182,45 @@ function test_invalid_signature(aDeveloperMode) {
|
|||
const expectedCallbacks = [
|
||||
// URL statusCode verificationResult content
|
||||
[kOrigin + '/manifest', Cr.NS_OK, verificationResult, kManifestContent],
|
||||
[kOrigin + '/1.html', Cr.NS_OK, verificationResult],
|
||||
[kOrigin + '/2.js', Cr.NS_OK, verificationResult],
|
||||
[kOrigin + '/3.jpg', Cr.NS_OK, verificationResult],
|
||||
[kOrigin + '/4.html', Cr.NS_OK, verificationResult],
|
||||
[kOrigin + '/5.css', Cr.NS_OK, verificationResult],
|
||||
[kOrigin + '/1.html', Cr.NS_OK, verificationResult, 'abc'],
|
||||
[kOrigin + '/2.js', Cr.NS_OK, verificationResult, 'abc'],
|
||||
[kOrigin + '/3.jpg', Cr.NS_OK, verificationResult, 'abc'],
|
||||
[kOrigin + '/4.html', Cr.NS_OK, verificationResult, 'abc'],
|
||||
[kOrigin + '/5.css', Cr.NS_OK, verificationResult, 'abc'],
|
||||
];
|
||||
|
||||
let packageUriString = kOrigin + '/pak' + (aDeveloperMode ? '-dev' : '');
|
||||
let packageUriString = kOrigin + '/pak' + (aBypassVerification ? '-dev' : '');
|
||||
let packageCacheEntry =
|
||||
createPackageCache(packageUriString, gLoadContextInfoFactory.private);
|
||||
|
||||
let verifierListener = createVerifierListener(expectedCallbacks,
|
||||
aDeveloperMode ? kPackagedId : '',
|
||||
aBypassVerification ? kPackagedId : '',
|
||||
isPackageSigned,
|
||||
packageCacheEntry);
|
||||
|
||||
let signature = 'manifest-signature: 11111111111111111111111';
|
||||
gVerifier.init(verifierListener, signature, packageCacheEntry);
|
||||
gVerifier.init(verifierListener, kOrigin, signature, packageCacheEntry);
|
||||
|
||||
feedResources(expectedCallbacks, signature);
|
||||
}
|
||||
|
||||
function test_invalid_signature_bypass_verification() {
|
||||
let pref = "network.http.signed-packages.trusted-origin";
|
||||
ok(!!Ci.nsISupportsString, "Ci.nsISupportsString");
|
||||
let origin = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
|
||||
origin.data = "http://bar.com";
|
||||
gPrefs.setComplexValue(pref, Ci.nsISupportsString, origin);
|
||||
test_invalid_signature(true);
|
||||
gPrefs.clearUserPref(pref);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
ok(!!gVerifier);
|
||||
|
||||
// Test cases in non-developer mode.
|
||||
add_test(test_no_signature);
|
||||
add_test(test_invalid_signature);
|
||||
add_test(test_invalid_signature_bypass_verification);
|
||||
|
||||
// run tests
|
||||
run_next_test();
|
||||
|
|
|
@ -41,7 +41,7 @@ extern PRLogModuleInfo* gPIPNSSLog;
|
|||
|
||||
static const unsigned int DEFAULT_MIN_RSA_BITS = 2048;
|
||||
static char kDevImportedDER[] =
|
||||
"network.http.packaged-apps-developer-trusted-root";
|
||||
"network.http.signed-packages.developer-root";
|
||||
|
||||
namespace mozilla { namespace psm {
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче