Bug 1059216 - Verification of Trusted Hosted Apps manifest signature, part 1. r=dkeeler,rlb

This commit is contained in:
Vlatko Markovic 2014-09-22 07:58:59 -07:00
Родитель 2915e7de92
Коммит 8818f4947f
10 изменённых файлов: 391 добавлений и 78 удалений

Просмотреть файл

@ -22,7 +22,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebappOSUtils",
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
// Shared code for AppsServiceChild.jsm, Webapps.jsm and Webapps.js
// Shared code for AppsServiceChild.jsm, TrustedHostedAppsUtils.jsm,
// Webapps.jsm and Webapps.js
this.EXPORTED_SYMBOLS =
["AppsUtils", "ManifestHelper", "isAbsoluteURI", "mozIApplication"];
@ -116,6 +117,84 @@ this.AppsUtils = {
return obj;
},
// Creates a nsILoadContext object with a given appId and isBrowser flag.
createLoadContext: function createLoadContext(aAppId, aIsBrowser) {
return {
associatedWindow: null,
topWindow : null,
appId: aAppId,
isInBrowserElement: aIsBrowser,
usePrivateBrowsing: false,
isContent: false,
isAppOfType: function(appType) {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsILoadContext,
Ci.nsIInterfaceRequestor,
Ci.nsISupports]),
getInterface: function(iid) {
if (iid.equals(Ci.nsILoadContext))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
}
},
// Sends data downloaded from aRequestChannel to a file
// identified by aId and aFileName.
getFile: function(aRequestChannel, aId, aFileName) {
let deferred = Promise.defer();
// Staging the file in TmpD until all the checks are done.
let file = FileUtils.getFile("TmpD", ["webapps", aId, aFileName], true);
// We need an output stream to write the channel content to the out file.
let outputStream = Cc["@mozilla.org/network/file-output-stream;1"]
.createInstance(Ci.nsIFileOutputStream);
// write, create, truncate
outputStream.init(file, 0x02 | 0x08 | 0x20, parseInt("0664", 8), 0);
let bufferedOutputStream =
Cc['@mozilla.org/network/buffered-output-stream;1']
.createInstance(Ci.nsIBufferedOutputStream);
bufferedOutputStream.init(outputStream, 1024);
// Create a listener that will give data to the file output stream.
let listener = Cc["@mozilla.org/network/simple-stream-listener;1"]
.createInstance(Ci.nsISimpleStreamListener);
listener.init(bufferedOutputStream, {
onStartRequest: function(aRequest, aContext) {
// Nothing to do there anymore.
},
onStopRequest: function(aRequest, aContext, aStatusCode) {
bufferedOutputStream.close();
outputStream.close();
if (!Components.isSuccessCode(aStatusCode)) {
deferred.reject({ msg: "NETWORK_ERROR", downloadAvailable: true});
return;
}
// If we get a 4XX or a 5XX http status, bail out like if we had a
// network error.
let responseStatus = aRequestChannel.responseStatus;
if (responseStatus >= 400 && responseStatus <= 599) {
// unrecoverable error, don't bug the user
deferred.reject({ msg: "NETWORK_ERROR", downloadAvailable: false});
return;
}
deferred.resolve(file);
}
});
aRequestChannel.asyncOpen(listener, null);
return deferred.promise;
},
getAppByManifestURL: function getAppByManifestURL(aApps, aManifestURL) {
debug("getAppByManifestURL " + aManifestURL);
// This could be O(1) if |webapps| was a dictionary indexed on manifestURL

Просмотреть файл

@ -16,6 +16,8 @@ const APP_TRUSTED_ROOTS= ["AppMarketplaceProdPublicRoot",
"AppMarketplaceDevPublicRoot",
"AppMarketplaceDevReviewersRoot",
"AppMarketplaceStageRoot",
"TrustedHostedAppPublicRoot",
"TrustedHostedAppTestRoot",
"AppXPCShellRoot"];
this.TrustedRootCertificate = {

Просмотреть файл

@ -2,17 +2,25 @@
* 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/. */
/* global Components, Services, dump */
/* global Components, Services, dump, AppsUtils, NetUtil, XPCOMUtils */
"use strict";
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const signatureFileExtension = ".sig";
this.EXPORTED_SYMBOLS = ["TrustedHostedAppsUtils"];
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
#ifdef MOZ_WIDGET_ANDROID
// On Android, define the "debug" function as a binding of the "d" function
@ -65,7 +73,8 @@ this.TrustedHostedAppsUtils = {
throw "CERTDB_ERROR";
}
if (siteSecurityService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP, uri.host, 0)) {
if (siteSecurityService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HPKP,
uri.host, 0)) {
debug("\tvalid certificate pinning for host: " + uri.host + "\n");
return true;
}
@ -100,7 +109,7 @@ this.TrustedHostedAppsUtils = {
.forEach(aList => {
// aList[0] contains the directive name.
// aList[1..n] contains sources.
let directiveName = aList.shift()
let directiveName = aList.shift();
let sources = aList;
if ((-1 == validDirectives.indexOf(directiveName))) {
@ -144,5 +153,105 @@ this.TrustedHostedAppsUtils = {
}
return true;
},
_verifySignedFile: function(aManifestStream, aSignatureStream, aCertDb) {
let deferred = Promise.defer();
let root = Ci.nsIX509CertDB.TrustedHostedAppPublicRoot;
try {
// Check if we should use the test certificates.
// Please note that this should be changed if we ever allow chages to the
// prefs since that would create a way for an attacker to use the test
// root for real apps.
let useTrustedAppTestCerts = Services.prefs
.getBoolPref("dom.mozApps.use_trustedapp_test_certs");
if (useTrustedAppTestCerts) {
root = Ci.nsIX509CertDB.TrustedHostedAppTestRoot;
}
} catch (ex) { }
aCertDb.verifySignedManifestAsync(
root, aManifestStream, aSignatureStream,
function(aRv, aCert) {
if (Components.isSuccessCode(aRv)) {
deferred.resolve(aCert);
} else if (aRv == Cr.NS_ERROR_FILE_CORRUPTED ||
aRv == Cr.NS_ERROR_SIGNED_MANIFEST_FILE_INVALID) {
deferred.reject("MANIFEST_SIGNATURE_FILE_INVALID");
} else {
deferred.reject("MANIFEST_SIGNATURE_VERIFICATION_ERROR");
}
}
);
return deferred.promise;
},
verifySignedManifest: function(aApp, aAppId) {
let deferred = Promise.defer();
let certDb;
try {
certDb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
} catch (e) {
debug("nsIX509CertDB error: " + e);
// unrecoverable error, don't bug the user
throw "CERTDB_ERROR";
}
let mRequestChannel = NetUtil.newChannel(aApp.manifestURL)
.QueryInterface(Ci.nsIHttpChannel);
mRequestChannel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
mRequestChannel.notificationCallbacks =
AppsUtils.createLoadContext(aAppId, false);
// The manifest signature must be located at the same path as the
// manifest and have the same file name, only the file extension
// should differ. Any fragment or query parameter will be ignored.
let signatureURL;
try {
let mURL = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(aApp.manifestURL, null, null)
.QueryInterface(Ci.nsIURL);
signatureURL = mURL.prePath +
mURL.directory + mURL.fileBaseName + signatureFileExtension;
} catch(e) {
deferred.reject("SIGNATURE_PATH_INVALID");
return;
}
let sRequestChannel = NetUtil.newChannel(signatureURL)
.QueryInterface(Ci.nsIHttpChannel);
sRequestChannel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
sRequestChannel.notificationCallbacks =
AppsUtils.createLoadContext(aAppId, false);
let getAsyncFetchCallback = (resolve, reject) =>
(aInputStream, aResult) => {
if (!Components.isSuccessCode(aResult)) {
debug("Failed to download file");
reject("MANIFEST_FILE_UNAVAILABLE");
return;
}
resolve(aInputStream);
};
Promise.all([
new Promise((resolve, reject) => {
NetUtil.asyncFetch(mRequestChannel,
getAsyncFetchCallback(resolve, reject));
}),
new Promise((resolve, reject) => {
NetUtil.asyncFetch(sRequestChannel,
getAsyncFetchCallback(resolve, reject));
})
]).then(([aManifestStream, aSignatureStream]) => {
this._verifySignedFile(aManifestStream, aSignatureStream, certDb)
.then(deferred.resolve, deferred.reject);
}, deferred.reject);
return deferred.promise;
}
};

Просмотреть файл

@ -2021,7 +2021,7 @@ this.DOMApplicationRegistry = {
xhr.setRequestHeader("If-None-Match", app.etag);
}
xhr.channel.notificationCallbacks =
this.createLoadContext(app.installerAppId, app.installerIsBrowser);
AppsUtils.createLoadContext(app.installerAppId, app.installerIsBrowser);
xhr.addEventListener("load", onload.bind(this, xhr, oldManifest), false);
xhr.addEventListener("error", (function() {
@ -2052,30 +2052,6 @@ this.DOMApplicationRegistry = {
});
},
// Creates a nsILoadContext object with a given appId and isBrowser flag.
createLoadContext: function createLoadContext(aAppId, aIsBrowser) {
return {
associatedWindow: null,
topWindow : null,
appId: aAppId,
isInBrowserElement: aIsBrowser,
usePrivateBrowsing: false,
isContent: false,
isAppOfType: function(appType) {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsILoadContext,
Ci.nsIInterfaceRequestor,
Ci.nsISupports]),
getInterface: function(iid) {
if (iid.equals(Ci.nsILoadContext))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
}
},
updatePackagedApp: Task.async(function*(aData, aId, aApp, aNewManifest) {
debug("updatePackagedApp");
@ -2342,8 +2318,8 @@ this.DOMApplicationRegistry = {
.createInstance(Ci.nsIXMLHttpRequest);
xhr.open("GET", app.manifestURL, true);
xhr.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
xhr.channel.notificationCallbacks = this.createLoadContext(aData.appId,
aData.isBrowser);
xhr.channel.notificationCallbacks = AppsUtils.createLoadContext(aData.appId,
aData.isBrowser);
xhr.responseType = "json";
xhr.addEventListener("load", (function() {
@ -2455,8 +2431,8 @@ this.DOMApplicationRegistry = {
.createInstance(Ci.nsIXMLHttpRequest);
xhr.open("GET", app.manifestURL, true);
xhr.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
xhr.channel.notificationCallbacks = this.createLoadContext(aData.appId,
aData.isBrowser);
xhr.channel.notificationCallbacks = AppsUtils.createLoadContext(aData.appId,
aData.isBrowser);
xhr.responseType = "json";
xhr.addEventListener("load", (function() {
@ -3219,52 +3195,15 @@ this.DOMApplicationRegistry = {
_getPackage: function(aRequestChannel, aId, aOldApp, aNewApp) {
let deferred = Promise.defer();
// Staging the zip in TmpD until all the checks are done.
let zipFile =
FileUtils.getFile("TmpD", ["webapps", aId, "application.zip"], true);
// We need an output stream to write the channel content to the zip file.
let outputStream = Cc["@mozilla.org/network/file-output-stream;1"]
.createInstance(Ci.nsIFileOutputStream);
// write, create, truncate
outputStream.init(zipFile, 0x02 | 0x08 | 0x20, parseInt("0664", 8), 0);
let bufferedOutputStream =
Cc['@mozilla.org/network/buffered-output-stream;1']
.createInstance(Ci.nsIBufferedOutputStream);
bufferedOutputStream.init(outputStream, 1024);
// Create a listener that will give data to the file output stream.
let listener = Cc["@mozilla.org/network/simple-stream-listener;1"]
.createInstance(Ci.nsISimpleStreamListener);
listener.init(bufferedOutputStream, {
onStartRequest: function(aRequest, aContext) {
// Nothing to do there anymore.
},
onStopRequest: function(aRequest, aContext, aStatusCode) {
bufferedOutputStream.close();
outputStream.close();
if (!Components.isSuccessCode(aStatusCode)) {
deferred.reject("NETWORK_ERROR");
return;
}
// If we get a 4XX or a 5XX http status, bail out like if we had a
// network error.
let responseStatus = aRequestChannel.responseStatus;
if (responseStatus >= 400 && responseStatus <= 599) {
// unrecoverable error, don't bug the user
aOldApp.downloadAvailable = false;
deferred.reject("NETWORK_ERROR");
return;
}
deferred.resolve(zipFile);
AppsUtils.getFile(aRequestChannel, aId, "application.zip").then((aFile) => {
deferred.resolve(aFile);
}, function(rejectStatus) {
debug("Failed to download package file: " + rejectStatus.msg);
if (!rejectStatus.downloadAvailable) {
aOldApp.downloadAvailable = false;
}
deferred.reject(rejectStatus.msg);
});
aRequestChannel.asyncOpen(listener, null);
// send a first progress event to correctly set the DOM object's properties
this._sendDownloadProgressEvent(aNewApp, 0);

Просмотреть файл

@ -203,6 +203,9 @@ XPC_MSG_DEF(NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE , "An entry in the JAR is to
XPC_MSG_DEF(NS_ERROR_SIGNED_JAR_ENTRY_INVALID , "An entry in the JAR is invalid.")
XPC_MSG_DEF(NS_ERROR_SIGNED_JAR_MANIFEST_INVALID , "The JAR's manifest or signature file is invalid.")
/* Codes related to signed manifests */
XPC_MSG_DEF(NS_ERROR_SIGNED_APP_MANIFEST_INVALID , "The signed app manifest or signature file is invalid.")
/* Codes for printing-related errors. */
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE , "No printers available.")
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_NAME_NOT_FOUND , "The selected printer could not be found.")

Просмотреть файл

@ -12,6 +12,7 @@
#include "pkix/pkix.h"
#include "pkix/pkixnss.h"
#include "pkix/ScopedPtr.h"
#include "mozilla/RefPtr.h"
#include "CryptoTask.h"
#include "AppTrustDomain.h"
@ -20,16 +21,20 @@
#include "nsDataSignatureVerifier.h"
#include "nsHashKeys.h"
#include "nsIFile.h"
#include "nsIFileStreams.h"
#include "nsIInputStream.h"
#include "nsIStringEnumerator.h"
#include "nsIZipReader.h"
#include "nsNetUtil.h"
#include "nsNSSCertificate.h"
#include "nsProxyRelease.h"
#include "NSSCertDBTrustDomain.h"
#include "nsString.h"
#include "nsTHashtable.h"
#include "base64.h"
#include "certdb.h"
#include "nssb64.h"
#include "secmime.h"
#include "plstr.h"
#include "prlog.h"
@ -768,6 +773,82 @@ OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
return NS_OK;
}
nsresult
VerifySignedManifest(AppTrustedRoot aTrustedRoot,
nsIInputStream* aManifestStream,
nsIInputStream* aSignatureStream,
/*out, optional */ nsIX509Cert** aSignerCert)
{
NS_ENSURE_ARG(aManifestStream);
NS_ENSURE_ARG(aSignatureStream);
if (aSignerCert) {
*aSignerCert = nullptr;
}
// Load signature file in buffer
ScopedAutoSECItem signatureBuffer;
nsresult rv = ReadStream(aSignatureStream, signatureBuffer);
if (NS_FAILED(rv)) {
return rv;
}
signatureBuffer.type = siBuffer;
// Load manifest file in buffer
ScopedAutoSECItem manifestBuffer;
rv = ReadStream(aManifestStream, manifestBuffer);
if (NS_FAILED(rv)) {
return rv;
}
// Calculate SHA1 digest of the manifest buffer
Digest manifestCalculatedDigest;
rv = manifestCalculatedDigest.DigestBuf(SEC_OID_SHA1,
manifestBuffer.data,
manifestBuffer.len - 1); // buffer is null terminated
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Get base64 encoded string from manifest buffer digest
ScopedPtr<char, PORT_Free_string> base64EncDigest(NSSBase64_EncodeItem(nullptr,
nullptr, 0, const_cast<SECItem*>(&manifestCalculatedDigest.get())));
if (NS_WARN_IF(!base64EncDigest)) {
return NS_ERROR_OUT_OF_MEMORY;
}
// Calculate SHA1 digest of the base64 encoded string
Digest doubleDigest;
rv = doubleDigest.DigestBuf(SEC_OID_SHA1,
reinterpret_cast<uint8_t*>(base64EncDigest.get()),
strlen(base64EncDigest.get()));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Verify the manifest signature (signed digest of the base64 encoded string)
ScopedCERTCertList builtChain;
rv = VerifySignature(aTrustedRoot, signatureBuffer,
doubleDigest.get(), builtChain);
if (NS_FAILED(rv)) {
return rv;
}
// Return the signer's certificate to the reader if they want it.
if (aSignerCert) {
MOZ_ASSERT(CERT_LIST_HEAD(builtChain));
nsCOMPtr<nsIX509Cert> signerCert =
nsNSSCertificate::Create(CERT_LIST_HEAD(builtChain)->cert);
if (NS_WARN_IF(!signerCert)) {
return NS_ERROR_OUT_OF_MEMORY;
}
signerCert.forget(aSignerCert);
}
return NS_OK;
}
class OpenSignedAppFileTask MOZ_FINAL : public CryptoTask
{
public:
@ -803,6 +884,44 @@ private:
nsCOMPtr<nsIX509Cert> mSignerCert; // out
};
class VerifySignedmanifestTask MOZ_FINAL : public CryptoTask
{
public:
VerifySignedmanifestTask(AppTrustedRoot aTrustedRoot,
nsIInputStream* aManifestStream,
nsIInputStream* aSignatureStream,
nsIVerifySignedManifestCallback* aCallback)
: mTrustedRoot(aTrustedRoot)
, mManifestStream(aManifestStream)
, mSignatureStream(aSignatureStream)
, mCallback(
new nsMainThreadPtrHolder<nsIVerifySignedManifestCallback>(aCallback))
{
}
private:
virtual nsresult CalculateResult() MOZ_OVERRIDE
{
return VerifySignedManifest(mTrustedRoot, mManifestStream,
mSignatureStream, getter_AddRefs(mSignerCert));
}
// nsNSSCertificate implements nsNSSShutdownObject, so there's nothing that
// needs to be released
virtual void ReleaseNSSResources() { }
virtual void CallCallback(nsresult rv)
{
(void) mCallback->VerifySignedManifestFinished(rv, mSignerCert);
}
const AppTrustedRoot mTrustedRoot;
const nsCOMPtr<nsIInputStream> mManifestStream;
const nsCOMPtr<nsIInputStream> mSignatureStream;
nsMainThreadPtrHandle<nsIVerifySignedManifestCallback> mCallback;
nsCOMPtr<nsIX509Cert> mSignerCert; // out
};
} // unnamed namespace
NS_IMETHODIMP
@ -817,3 +936,18 @@ nsNSSCertificateDB::OpenSignedAppFileAsync(
aCallback));
return task->Dispatch("SignedJAR");
}
NS_IMETHODIMP
nsNSSCertificateDB::VerifySignedManifestAsync(
AppTrustedRoot aTrustedRoot, nsIInputStream* aManifestStream,
nsIInputStream* aSignatureStream, nsIVerifySignedManifestCallback* aCallback)
{
NS_ENSURE_ARG_POINTER(aManifestStream);
NS_ENSURE_ARG_POINTER(aSignatureStream);
NS_ENSURE_ARG_POINTER(aCallback);
RefPtr<VerifySignedmanifestTask> task(
new VerifySignedmanifestTask(aTrustedRoot, aManifestStream,
aSignatureStream, aCallback));
return task->Dispatch("SignedManifest");
}

Просмотреть файл

@ -24,6 +24,9 @@
#include "marketplace-dev-reviewers.inc"
#include "marketplace-stage.inc"
#include "xpcshell.inc"
// Trusted Hosted Apps Certificates
#include "manifest-signing-root.inc"
#include "manifest-signing-test-root.inc"
using namespace mozilla::pkix;
@ -79,6 +82,16 @@ AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
trustedDER.len = mozilla::ArrayLength(xpcshellRoot);
break;
case nsIX509CertDB::TrustedHostedAppPublicRoot:
trustedDER.data = const_cast<uint8_t*>(trustedAppPublicRoot);
trustedDER.len = mozilla::ArrayLength(trustedAppPublicRoot);
break;
case nsIX509CertDB::TrustedHostedAppTestRoot:
trustedDER.data = const_cast<uint8_t*>(trustedAppTestRoot);
trustedDER.len = mozilla::ArrayLength(trustedAppTestRoot);
break;
default:
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
return SECFailure;

Просмотреть файл

@ -12,6 +12,7 @@ interface nsIFile;
interface nsIInterfaceRequestor;
interface nsIZipReader;
interface nsIX509CertList;
interface nsIInputStream;
%{C++
#define NS_X509CERTDB_CONTRACTID "@mozilla.org/security/x509certdb;1"
@ -27,11 +28,18 @@ interface nsIOpenSignedAppFileCallback : nsISupports
in nsIX509Cert aSignerCert);
};
[scriptable, function, uuid(3d6a9c87-5c5f-46fc-9410-96da6092f0f2)]
interface nsIVerifySignedManifestCallback : nsISupports
{
void verifySignedManifestFinished(in nsresult rv,
in nsIX509Cert aSignerCert);
};
/**
* This represents a service to access and manipulate
* X.509 certificates stored in a database.
*/
[scriptable, uuid(dd6e4af8-23bb-41d9-a1e3-9ce925429f2f)]
[scriptable, uuid(8b01c2af-3a44-44d3-8ea5-51c2455e6c4b)]
interface nsIX509CertDB : nsISupports {
/**
@ -301,10 +309,28 @@ interface nsIX509CertDB : nsISupports {
const AppTrustedRoot AppMarketplaceDevReviewersRoot = 4;
const AppTrustedRoot AppMarketplaceStageRoot = 5;
const AppTrustedRoot AppXPCShellRoot = 6;
const AppTrustedRoot TrustedHostedAppPublicRoot = 7;
const AppTrustedRoot TrustedHostedAppTestRoot = 8;
void openSignedAppFileAsync(in AppTrustedRoot trustedRoot,
in nsIFile aJarFile,
in nsIOpenSignedAppFileCallback callback);
/**
* Given streams containing a signature and a manifest file, verifies
* that the signature is valid for the manifest. The signature must
* come from a certificate that is trusted for code signing and that
* was issued by the given trusted root.
*
* On success, NS_OK and the trusted certificate that signed the
* Manifest are returned.
*
* On failure, an error code is returned.
*/
void verifySignedManifestAsync(in AppTrustedRoot trustedRoot,
in nsIInputStream aManifestStream,
in nsIInputStream aSignatureStream,
in nsIVerifySignedManifestCallback callback);
/*
* Add a cert to a cert DB from a binary string.
*

Просмотреть файл

@ -873,6 +873,13 @@
ERROR(NS_ERROR_DOM_BLUETOOTH_AUTH_REJECTED, FAILURE(11)),
#undef MODULE
/* ======================================================================= */
/* 38: NS_ERROR_MODULE_SIGNED_APP */
/* ======================================================================= */
#define MODULE NS_ERROR_MODULE_SIGNED_APP
ERROR(NS_ERROR_SIGNED_APP_MANIFEST_INVALID, FAILURE(1)),
#undef MODULE
/* ======================================================================= */
/* 51: NS_ERROR_MODULE_GENERAL */
/* ======================================================================= */

Просмотреть файл

@ -72,6 +72,7 @@
#define NS_ERROR_MODULE_SIGNED_JAR 35
#define NS_ERROR_MODULE_DOM_FILESYSTEM 36
#define NS_ERROR_MODULE_DOM_BLUETOOTH 37
#define NS_ERROR_MODULE_SIGNED_APP 38
/* NS_ERROR_MODULE_GENERAL should be used by modules that do not
* care if return code values overlap. Callers of methods that