Bug 1178518 - Verify signed packages. r=valentin

This commit is contained in:
Jonathan Hao 2015-09-24 10:07:01 +08:00
Родитель ae5a452f5b
Коммит 077ea1aeb2
3 изменённых файлов: 104 добавлений и 27 удалений

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

@ -225,15 +225,12 @@ CreateSharedStringStream(const char* aData, uint32_t aCount)
static bool
GetOriginalResponseHeader(nsIRequest* aRequest, nsACString& aHeader)
{
// TODO: The flattened http header might be different from the original.
// See Bug 1198669 for further information.
nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest));
if (!multiPartChannel) {
return false;
}
nsCOMPtr<nsIResponseHeadProvider> headerProvider(do_QueryInterface(aRequest));
nsHttpResponseHead *responseHead = headerProvider->GetResponseHead();
NS_ENSURE_TRUE(responseHead, false);
responseHead->Flatten(aHeader, true);
aHeader.Append("\r\n");
multiPartChannel->GetOriginalResponseHeader(aHeader);
return true;
}

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

@ -14,6 +14,8 @@
#include "nsITimer.h"
#include "nsIPackagedAppVerifier.h"
#include "mozilla/Preferences.h"
#include "nsIPackagedAppUtils.h"
#include "nsIInputStream.h"
static const short kResourceHashType = nsICryptoHash::SHA256;
@ -26,7 +28,7 @@ namespace net {
///////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS(PackagedAppVerifier, nsIPackagedAppVerifier)
NS_IMPL_ISUPPORTS(PackagedAppVerifier, nsIPackagedAppVerifier, nsIVerificationCallback)
NS_IMPL_ISUPPORTS(PackagedAppVerifier::ResourceCacheInfo, nsISupports)
@ -76,6 +78,14 @@ NS_IMETHODIMP PackagedAppVerifier::Init(nsIPackagedAppVerifierListener* aListene
mSignature = aSignature;
mIsPackageSigned = false;
mPackageCacheEntry = aPackageCacheEntry;
mIsFirstResource = true;
nsresult rv;
mPackagedAppUtils = do_CreateInstance(NS_PACKAGEDAPPUTILS_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
LOG(("create packaged app utils failed"));
return rv;
}
return NS_OK;
}
@ -90,6 +100,11 @@ NS_IMETHODIMP
PackagedAppVerifier::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
if (mIsFirstResource) {
// The first resource must be the manifest, hashes not needed
return NS_OK;
}
if (!mHasher) {
mHasher = do_CreateInstance("@mozilla.org/security/hash;1");
}
@ -103,6 +118,22 @@ PackagedAppVerifier::OnStartRequest(nsIRequest *aRequest,
return mHasher->Init(kResourceHashType);
}
NS_METHOD
PackagedAppVerifier::WriteManifest(nsIInputStream* aStream,
void* aManifest,
const char* aFromRawSegment,
uint32_t aToOffset,
uint32_t aCount,
uint32_t* aWriteCount)
{
LOG(("WriteManifest: length %u", aCount));
LOG(("%s", aFromRawSegment));
nsCString* manifest = static_cast<nsCString*>(aManifest);
manifest->AppendASCII(aFromRawSegment, aCount);
*aWriteCount = aCount;
return NS_OK;
}
// @param aRequest nullptr.
// @param aContext nullptr.
// @param aInputStream as-is.
@ -115,6 +146,16 @@ PackagedAppVerifier::OnDataAvailable(nsIRequest *aRequest,
uint64_t aOffset,
uint32_t aCount)
{
if (mIsFirstResource) {
// The first resource must be the manifest, hash value not needed.
// Instead, we read from the input stream and append to mManifest.
uint32_t count;
LOG(("ReadSegments: size = %u", aCount));
nsresult rv = aInputStream->ReadSegments(WriteManifest, &mManifest, aCount, &count);
MOZ_ASSERT(count == aCount, "Bytes read by ReadSegments don't match");
return rv;
}
MOZ_ASSERT(!mHashingResourceURI.IsEmpty(), "MUST call BeginResourceHash first.");
NS_ENSURE_TRUE(mHasher, NS_ERROR_FAILURE);
return mHasher->UpdateFromStream(aInputStream, aCount);
@ -130,17 +171,22 @@ PackagedAppVerifier::OnStopRequest(nsIRequest* aRequest,
{
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "mHashingResourceURI is not thread safe.");
NS_ENSURE_TRUE(mHasher, NS_ERROR_FAILURE);
if (mIsFirstResource) {
// The first resource must be the manifest, hash value not needed
mIsFirstResource = false;
} else {
NS_ENSURE_TRUE(mHasher, NS_ERROR_FAILURE);
nsAutoCString hash;
nsresult rv = mHasher->Finish(true, hash);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString hash;
nsresult rv = mHasher->Finish(true, hash);
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Hash of %s is %s", mHashingResourceURI.get(), hash.get()));
LOG(("Hash of %s is %s", mHashingResourceURI.get(), hash.get()));
// Store the computated hash associated with the resource URI.
mResourceHashStore.Put(mHashingResourceURI, new nsCString(hash));
mHashingResourceURI = EmptyCString();
// Store the computated hash associated with the resource URI.
mResourceHashStore.Put(mHashingResourceURI, new nsCString(hash));
mHashingResourceURI = EmptyCString();
}
// Get a internal copy and take over the life cycle handling
// since the linked list we use only supports pointer-based element.
@ -186,9 +232,10 @@ PackagedAppVerifier::ProcessResourceCache(const ResourceCacheInfo* aInfo)
}
}
void
NS_IMETHODIMP
PackagedAppVerifier::FireVerifiedEvent(bool aForManifest, bool aSuccess)
{
LOG(("FireVerifiedEvent aForManifest=%d aSuccess=%d", aForManifest, aSuccess));
nsCOMPtr<nsIRunnable> r;
if (aForManifest) {
@ -202,6 +249,8 @@ PackagedAppVerifier::FireVerifiedEvent(bool aForManifest, bool aSuccess)
}
NS_DispatchToMainThread(r);
return NS_OK;
}
void
@ -231,9 +280,12 @@ PackagedAppVerifier::VerifyManifest(const ResourceCacheInfo* aInfo)
return;
}
// TODO: Implement manifest verification.
LOG(("Manifest verification not implemented yet. See Bug 1178518."));
FireVerifiedEvent(true, false);
LOG(("Signature: length = %u\n%s", mSignature.Length(), mSignature.get()));
LOG(("Manifest: length = %u\n%s", mManifest.Length(), mManifest.get()));
nsresult rv = mPackagedAppUtils->VerifyManifest(mSignature, mManifest, this);
if (NS_FAILED(rv)) {
LOG(("VerifyManifest FAILED rv = %u", (unsigned)rv));
}
}
void
@ -269,9 +321,20 @@ PackagedAppVerifier::VerifyResource(const ResourceCacheInfo* aInfo)
return;
}
// TODO: Implement resource integrity check.
LOG(("Resource integrity check not implemented yet. See Bug 1178518."));
FireVerifiedEvent(false, false);
nsAutoCString path;
nsCOMPtr<nsIURL> url(do_QueryInterface(aInfo->mURI));
if (url) {
url->GetFilePath(path);
}
int32_t pos = path.Find("!//");
if (pos == kNotFound) {
FireVerifiedEvent(false, false);
return;
}
// Only keep the part after "!//"
path.Cut(0, pos + 3);
mPackagedAppUtils->CheckIntegrity(path, *resourceHash, this);
}
void

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

@ -14,18 +14,21 @@
#include "nsICryptoHash.h"
#include "nsIPackagedAppVerifier.h"
#include "mozilla/LinkedList.h"
#include "nsIPackagedAppUtils.h"
namespace mozilla {
namespace net {
class PackagedAppVerifier final
: public nsIPackagedAppVerifier
, public nsIVerificationCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIPACKAGEDAPPVERIFIER
NS_DECL_NSIVERIFICATIONCALLBACK
public:
enum EState {
@ -120,6 +123,14 @@ private:
//
void ProcessResourceCache(const ResourceCacheInfo* aInfo);
// Callback for nsIInputStream::ReadSegment() to read manifest
static NS_METHOD WriteManifest(nsIInputStream* aStream,
void* aManifest,
const char* aFromRawSegment,
uint32_t aToOffset,
uint32_t aCount,
uint32_t* aWriteCount);
// This two functions would call the actual verifier.
void VerifyManifest(const ResourceCacheInfo* aInfo);
void VerifyResource(const ResourceCacheInfo* aInfo);
@ -127,9 +138,6 @@ private:
void OnManifestVerified(bool aSuccess);
void OnResourceVerified(bool aSuccess);
// Fire a async event to notify the verification result.
void FireVerifiedEvent(bool aForManifest, bool aSuccess);
// To notify that either manifest or resource check is done.
nsCOMPtr<nsIPackagedAppVerifierListener> mListener;
@ -142,6 +150,12 @@ private:
// The signature of the package.
nsCString mSignature;
// The app manfiest of the package
nsCString mManifest;
// Whether we're processing the first resource, which is the manfiest
bool mIsFirstResource;
// Whether this package app is signed.
bool mIsPackageSigned;
@ -159,6 +173,9 @@ private:
// |EndResourceHash| call.
nsCString mLastComputedResourceHash;
// This will help to verify manifests and resource integrity
nsCOMPtr<nsIPackagedAppUtils> mPackagedAppUtils;
// A list of pending resource that is downloaded but not verified yet.
mozilla::LinkedList<ResourceCacheInfo> mPendingResourceCacheInfoList;