mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-14 04:03:47 +00:00
Crasher fixes and optimizations to jar signature verification. bug=7270 r=norris
This commit is contained in:
parent
66696f0a23
commit
8df8c26172
@ -90,23 +90,12 @@ interface nsIZipReader : nsISupports
|
||||
/**
|
||||
* Returns an object describing the owner (origin and/or signer) of
|
||||
* an entry. parseManifest must be called first. If aEntryName is an
|
||||
* entry in the jar, it must have been read to its end by an input
|
||||
* stream returned through getInputStream. If aEntryName is an external
|
||||
* file with meta-information stored in the jar, verifyExternalFile
|
||||
* must be called before getPrincipal.
|
||||
* entry in the jar, getInputStream must be called after parseManifest.
|
||||
* If aEntryName is an external file which has meta-information
|
||||
* stored in the jar, verifyExternalFile (not yet implemented) must
|
||||
* be called before getPrincipal.
|
||||
*/
|
||||
nsIPrincipal getPrincipal(in string aEntryName);
|
||||
|
||||
/**
|
||||
* Compares a file which is not in the jar to meta-information
|
||||
* about the file which is stored in the jar. Must be called after
|
||||
* parseManifest and before
|
||||
* calling getPrincipal on an external file (such as inline Javascript).
|
||||
* There must be an "external" entry in the manifest corresponding to
|
||||
* aFilename.
|
||||
*/
|
||||
void verifyExternalFile(in string aFilename, in string aBuf,
|
||||
in unsigned long aBufLength);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
@ -31,7 +31,9 @@
|
||||
#include "nsJAR.h"
|
||||
#include "nsXPIDLString.h"
|
||||
|
||||
|
||||
//----------------------------------------------
|
||||
// Errors and other utility definitions
|
||||
//----------------------------------------------
|
||||
#ifndef __gen_nsIFile_h__
|
||||
#define NS_ERROR_FILE_UNRECONGNIZED_PATH NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 1)
|
||||
#define NS_ERROR_FILE_UNRESOLVABLE_SYMLINK NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES, 2)
|
||||
@ -69,17 +71,84 @@ ziperr2nsresult(PRInt32 ziperr)
|
||||
_ptr = nsnull; \
|
||||
}
|
||||
|
||||
//-- Used by the JAR hashtables to delete their entries.
|
||||
//----------------------------------------------
|
||||
// nsJARManifestItem declaration
|
||||
//----------------------------------------------
|
||||
/*
|
||||
* nsJARManifestItem contains meta-information pertaining
|
||||
* to an individual JAR entry, taken from the
|
||||
* META-INF/MANIFEST.MF and META-INF/ *.SF files.
|
||||
* This is security-critical information, defined here so it is not
|
||||
* accessible from anywhere else.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JAR_INVALID = 1,
|
||||
JAR_GLOBAL = 2,
|
||||
JAR_INTERNAL = 3,
|
||||
JAR_EXTERNAL = 4
|
||||
} JARManifestItemType;
|
||||
|
||||
// Use this macro to look up global data (from the manifest file header)
|
||||
#define JAR_GLOBALMETA ""
|
||||
|
||||
class nsJARManifestItem
|
||||
{
|
||||
public:
|
||||
JARManifestItemType mType;
|
||||
|
||||
// the entity which signed this item
|
||||
nsIPrincipal* mPrincipal;
|
||||
|
||||
// True if the second step of verification (VerifyEntryDigests)
|
||||
// has taken place:
|
||||
PRBool step2Complete;
|
||||
|
||||
// True unless one or more verification steps failed
|
||||
PRBool valid;
|
||||
|
||||
// Internal storage of digests
|
||||
char* calculatedSectionDigest;
|
||||
char* storedEntryDigest;
|
||||
|
||||
nsJARManifestItem();
|
||||
virtual ~nsJARManifestItem();
|
||||
};
|
||||
|
||||
//-------------------------------------------------
|
||||
// nsJARManifestItem constructors and destructor
|
||||
//-------------------------------------------------
|
||||
nsJARManifestItem::nsJARManifestItem(): mType(JAR_INTERNAL),
|
||||
mPrincipal(nsnull),
|
||||
step2Complete(PR_FALSE),
|
||||
valid(PR_TRUE),
|
||||
calculatedSectionDigest(nsnull),
|
||||
storedEntryDigest(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
nsJARManifestItem::~nsJARManifestItem()
|
||||
{
|
||||
// Delete digests if necessary
|
||||
PR_FREEIF(calculatedSectionDigest);
|
||||
PR_FREEIF(storedEntryDigest);
|
||||
NS_IF_RELEASE(mPrincipal);
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
// nsJAR constructor/destructor
|
||||
//----------------------------------------------
|
||||
PR_STATIC_CALLBACK(PRBool)
|
||||
DeleteManifestEntry(nsHashKey* aKey, void* aData, void* closure)
|
||||
{
|
||||
//-- deletes an entry in mManifestData.
|
||||
PR_FREEIF(aData);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// The following initialization makes a guess of 25 entries per jarfile.
|
||||
nsJAR::nsJAR(): mManifestData(nsnull, nsnull, DeleteManifestEntry, nsnull, 25),
|
||||
manifestParsed(PR_FALSE),
|
||||
step1Complete(PR_FALSE),
|
||||
mVerificationService(nsnull)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
@ -92,6 +161,9 @@ nsJAR::~nsJAR()
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsJAR, nsIZipReader);
|
||||
|
||||
//----------------------------------------------
|
||||
// nsJAR public implementation
|
||||
//----------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsJAR::Init(nsIFile* zipFile)
|
||||
{
|
||||
@ -156,9 +228,9 @@ nsJAR::GetEntry(const char *zipEntry, nsIZipEntry* *result)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJAR::FindEntries(const char *aPattern, nsISimpleEnumerator **_retval)
|
||||
nsJAR::FindEntries(const char *aPattern, nsISimpleEnumerator **result)
|
||||
{
|
||||
if (!_retval)
|
||||
if (!result)
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
|
||||
nsZipFind *find = mZip.FindInit(aPattern);
|
||||
@ -170,18 +242,20 @@ nsJAR::FindEntries(const char *aPattern, nsISimpleEnumerator **_retval)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF( zipEnum );
|
||||
|
||||
*_retval = zipEnum;
|
||||
*result = zipEnum;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJAR::GetInputStream(const char *aFilename, nsIInputStream **_retval)
|
||||
nsJAR::GetInputStream(const char *aFilename, nsIInputStream **result)
|
||||
{
|
||||
if (!_retval)
|
||||
if (!result)
|
||||
return NS_OK;
|
||||
return CreateInputStream(aFilename, this, _retval);
|
||||
return CreateInputStream(aFilename, this, result);
|
||||
}
|
||||
|
||||
//-- The following #defines are used by ParseManifest()
|
||||
// and ParseOneFile(). The header strings are defined in the JAR specification.
|
||||
#define JAR_MF 1
|
||||
#define JAR_SF 2
|
||||
#define JAR_MF_SEARCH_STRING "(M|/M)ETA-INF/(M|m)(ANIFEST|anifest).(MF|mf)$"
|
||||
@ -192,28 +266,31 @@ nsJAR::GetInputStream(const char *aFilename, nsIInputStream **_retval)
|
||||
NS_IMETHODIMP
|
||||
nsJAR::ParseManifest()
|
||||
{
|
||||
if (manifestParsed || !SupportsRSAVerification())
|
||||
//-- Verification Step 1
|
||||
if (step1Complete || !SupportsRSAVerification())
|
||||
return NS_OK;
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISimpleEnumerator> files;
|
||||
nsCOMPtr<nsJARItem> file;
|
||||
char* manifestBuffer = nsnull;
|
||||
char* rsaBuffer = nsnull;
|
||||
PRUint32 rsaLen;
|
||||
nsCOMPtr<nsISimpleEnumerator> files;
|
||||
nsCOMPtr<nsJARItem> file;
|
||||
nsXPIDLCString manifestFilename;
|
||||
nsCAutoString rsaFilename;
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
|
||||
//-- (1)Manifest (MF) file
|
||||
rv = FindEntries(JAR_MF_SEARCH_STRING, getter_AddRefs(files));
|
||||
if (NS_FAILED(rv) || !files) goto cleanup;
|
||||
if (!files) rv = NS_ERROR_FAILURE;
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
|
||||
//-- Load the file into memory
|
||||
rv = files->GetNext(getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
if (!file) { rv = NS_ERROR_FILE_CORRUPTED; goto cleanup; } // No MF file
|
||||
if (NS_FAILED(rv) || !file) goto cleanup;
|
||||
PRBool more;
|
||||
rv = files->HasMoreElements(&more);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (more) { rv = NS_ERROR_FILE_CORRUPTED; goto cleanup; } // More than one MF file
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
if (more) { rv = NS_ERROR_FILE_CORRUPTED; goto cleanup; } // More than one MF file
|
||||
rv = file->GetName(getter_Copies(manifestFilename));
|
||||
if (!manifestFilename || NS_FAILED(rv)) return rv;
|
||||
rv = LoadEntry(manifestFilename, (const char**)&manifestBuffer);
|
||||
@ -223,159 +300,92 @@ nsJAR::ParseManifest()
|
||||
rv = ParseOneFile(manifestBuffer, JAR_MF);
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
JAR_NULLFREE(manifestBuffer)
|
||||
DumpMetadata("PM Pass 1 End");
|
||||
|
||||
//-- (2)Signature (SF) file
|
||||
// For now, we only read one SF file, even if the jar has multiple signatures.
|
||||
// If there are multiple signatures, we select one at random.
|
||||
rv = FindEntries(JAR_SF_SEARCH_STRING, getter_AddRefs(files));
|
||||
if (NS_FAILED(rv) || !files) goto cleanup;
|
||||
|
||||
{
|
||||
//-- Get an SF file
|
||||
rv = files->GetNext(getter_AddRefs(file));
|
||||
if (NS_FAILED(rv) || !file) goto cleanup;
|
||||
rv = file->GetName(getter_Copies(manifestFilename));
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
|
||||
rv = LoadEntry(manifestFilename, (const char**)&manifestBuffer);
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
|
||||
//-- Get its corresponding RSA file
|
||||
nsCAutoString rsaFilename(manifestFilename);
|
||||
PRInt32 extension = rsaFilename.RFindChar('.') + 1;
|
||||
NS_ASSERTION(extension != 0, "Manifest Parser: Missing file extension.");
|
||||
(void)rsaFilename.Cut(extension, 2);
|
||||
(void)rsaFilename.Append("rsa");
|
||||
rv = LoadEntry(rsaFilename, (const char**)&rsaBuffer, &rsaLen);
|
||||
if (NS_FAILED(rv)) // Try uppercase
|
||||
{
|
||||
JAR_NULLFREE(rsaBuffer)
|
||||
if (!files) rv = NS_ERROR_FAILURE;
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
//-- Get an SF file
|
||||
rv = files->GetNext(getter_AddRefs(file));
|
||||
if (NS_FAILED(rv) || !file) goto cleanup;
|
||||
rv = file->GetName(getter_Copies(manifestFilename));
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
|
||||
rv = LoadEntry(manifestFilename, (const char**)&manifestBuffer);
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
|
||||
//-- Get its corresponding RSA file
|
||||
rsaFilename = manifestFilename;
|
||||
PRInt32 extension = rsaFilename.RFindChar('.') + 1;
|
||||
NS_ASSERTION(extension != 0, "Manifest Parser: Missing file extension.");
|
||||
(void)rsaFilename.Cut(extension, 2);
|
||||
(void)rsaFilename.Append("rsa");
|
||||
rv = LoadEntry(rsaFilename, (const char**)&rsaBuffer, &rsaLen);
|
||||
if (NS_FAILED(rv)) // Try uppercase
|
||||
{
|
||||
JAR_NULLFREE(rsaBuffer)
|
||||
(void)rsaFilename.Cut(extension, 3);
|
||||
(void)rsaFilename.Append("RSA");
|
||||
rv = LoadEntry(rsaFilename, (const char**)&rsaBuffer, &rsaLen);
|
||||
}
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
|
||||
//-- Verify that the RSA file is a valid signature of the SF file
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = VerifySignature(manifestBuffer, rsaBuffer, rsaLen, getter_AddRefs(principal));
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
JAR_NULLFREE(rsaBuffer);
|
||||
|
||||
//-- Parse the SF file. If the verification above failed, principal
|
||||
// is null, and ParseOneFile will mark the relevant entries as invalid.
|
||||
// if ParseOneFile fails, then it has no effect, and we can safely
|
||||
// continue to the next SF file, or return.
|
||||
rv = ParseOneFile(manifestBuffer, JAR_SF, principal);
|
||||
JAR_NULLFREE(manifestBuffer)
|
||||
// End of signature file parsing
|
||||
(void)rsaFilename.Append("RSA");
|
||||
rv = LoadEntry(rsaFilename, (const char**)&rsaBuffer, &rsaLen);
|
||||
}
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
|
||||
//-- Verify that the RSA file is a valid signature of the SF file
|
||||
rv = VerifySignature(manifestBuffer, rsaBuffer, rsaLen, getter_AddRefs(principal));
|
||||
if (NS_FAILED(rv)) goto cleanup;
|
||||
JAR_NULLFREE(rsaBuffer);
|
||||
|
||||
//-- Parse the SF file. If the verification above failed, principal
|
||||
// is null, and ParseOneFile will mark the relevant entries as invalid.
|
||||
// if ParseOneFile fails, then it has no effect, and we can safely
|
||||
// continue to the next SF file, or return.
|
||||
ParseOneFile(manifestBuffer, JAR_SF, principal);
|
||||
JAR_NULLFREE(manifestBuffer)
|
||||
DumpMetadata("PM Pass 2 End");
|
||||
// End of signature file parsing
|
||||
|
||||
cleanup:
|
||||
DumpMetadata();
|
||||
JAR_NULLFREE(manifestBuffer)
|
||||
JAR_NULLFREE(rsaBuffer)
|
||||
manifestParsed = NS_SUCCEEDED(rv);
|
||||
step1Complete = NS_SUCCEEDED(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJAR::GetPrincipal(const char* aEntryName, nsIPrincipal** _retval)
|
||||
NS_IMETHODIMP
|
||||
nsJAR::GetPrincipal(const char* aFilename, nsIPrincipal** result)
|
||||
{
|
||||
// Check that verification is supported and manifest has been parsed
|
||||
if (!SupportsRSAVerification() || !manifestParsed)
|
||||
return NS_ERROR_FAILURE;
|
||||
// Parameter check
|
||||
if (!_retval)
|
||||
//-- Parameter check
|
||||
if (!aFilename)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
if (!result)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if(!aEntryName) // Caller wants global file principal
|
||||
aEntryName = JAR_GLOBALMETA;
|
||||
|
||||
nsStringKey key(aEntryName);
|
||||
nsJARManifestItem* manItem = (nsJARManifestItem*)mManifestData.Get(&key);
|
||||
if (!manItem) return NS_ERROR_FAILURE;
|
||||
|
||||
//-- Verify the file digest if we haven't done so already.
|
||||
if (manItem->mType != JAR_GLOBAL && (!manItem->verifyComplete))
|
||||
{
|
||||
if (manItem->hasPrincipal() && manItem->valid)
|
||||
{
|
||||
//-- Check if entry digests have been calculated (by nsJARInputStream)
|
||||
if (!manItem->entryDigestsCalculated)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PRBool foundDigest = PR_FALSE;
|
||||
for (PRInt32 a=0; a<JAR_DIGEST_COUNT; a++)
|
||||
{
|
||||
manItem->valid = manItem->valid &&
|
||||
( (!manItem->storedEntryDigests[a]) ||
|
||||
PL_strcmp(manItem->storedEntryDigests[a],
|
||||
manItem->calculatedEntryDigests[a]) == 0 );
|
||||
foundDigest = foundDigest || (manItem->storedEntryDigests[a]);
|
||||
}
|
||||
if (!foundDigest)
|
||||
// No digests in manifest file. Entry is valid but has no owner
|
||||
manItem->valid = PR_TRUE;
|
||||
if (!manItem->valid)
|
||||
manItem->setPrincipal(nsnull);
|
||||
}
|
||||
// Free up stored digests
|
||||
for(PRInt32 b = 0; b<JAR_DIGEST_COUNT; b++)
|
||||
{
|
||||
JAR_NULLFREE(manItem->calculatedEntryDigests[b])
|
||||
JAR_NULLFREE(manItem->storedEntryDigests[b])
|
||||
}
|
||||
manItem->verifyComplete = PR_TRUE;
|
||||
}
|
||||
|
||||
if (manItem && manItem->valid)
|
||||
{
|
||||
manItem->getPrincipal(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
else if (!manItem)
|
||||
{
|
||||
*_retval = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
else // Not valid
|
||||
return NS_ERROR_FAILURE; // XXX: Should this be a security error?
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJAR::VerifyExternalFile(const char* aFilename, const char* aBuf,
|
||||
PRUint32 aLen)
|
||||
{
|
||||
//-- Check if verification is supported
|
||||
if (!SupportsRSAVerification())
|
||||
return NS_OK;
|
||||
//-- Parameter check
|
||||
if (!aFilename || !aBuf)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
DumpMetadata("GetPrincipal");
|
||||
//-- Find the item
|
||||
nsStringKey key(aFilename);
|
||||
nsJARManifestItem* manItem = (nsJARManifestItem*)mManifestData.Get(&key);
|
||||
if (!manItem)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!manItem->entryDigestsCalculated)
|
||||
if(!manItem)
|
||||
{
|
||||
nsresult rv;
|
||||
for (PRInt32 b=0; b<JAR_DIGEST_COUNT && NS_SUCCEEDED(rv); b++)
|
||||
{
|
||||
PRUint32 id;
|
||||
rv = DigestBegin(&id, b);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = DigestData(id, aBuf, aLen);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = CalculateDigest(id, &(manItem->calculatedEntryDigests[b]));
|
||||
}
|
||||
if (NS_SUCCEEDED(rv))
|
||||
manItem->entryDigestsCalculated = PR_TRUE;
|
||||
}
|
||||
if (manItem->entryDigestsCalculated)
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(step1Complete && manItem->step2Complete,
|
||||
"Attempt to get principal before verifying signature.");
|
||||
|
||||
if (step1Complete && manItem->step2Complete && manItem->valid)
|
||||
{
|
||||
*result = manItem->mPrincipal;
|
||||
NS_IF_ADDREF(*result);
|
||||
return NS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
@ -398,7 +408,8 @@ nsJAR::CreateInputStream(const char* aFilename, nsJAR* aJAR, nsIInputStream **is
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsJAR::LoadEntry(const char* aFilename, const char** aBuf,
|
||||
nsresult
|
||||
nsJAR::LoadEntry(const char* aFilename, const char** aBuf,
|
||||
PRUint32* aBufLen)
|
||||
{
|
||||
//-- Get a stream for reading the manifest file
|
||||
@ -412,7 +423,7 @@ nsresult nsJAR::LoadEntry(const char* aFilename, const char** aBuf,
|
||||
PRUint32 len;
|
||||
rv = manifestStream->Available(&len);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
buf = (char*)PR_MALLOC(len);
|
||||
buf = (char*)PR_MALLOC(len+1);
|
||||
if (!buf) return NS_ERROR_OUT_OF_MEMORY;
|
||||
PRUint32 bytesRead;
|
||||
rv = manifestStream->Read(buf, len, &bytesRead);
|
||||
@ -420,6 +431,7 @@ nsresult nsJAR::LoadEntry(const char* aFilename, const char** aBuf,
|
||||
rv = NS_ERROR_FILE_CORRUPTED;
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
(void)manifestStream->Close();
|
||||
buf[len] = '\0'; //Null-terminate the buffer
|
||||
*aBuf = buf;
|
||||
if (aBufLen)
|
||||
*aBufLen = len;
|
||||
@ -427,7 +439,8 @@ nsresult nsJAR::LoadEntry(const char* aFilename, const char** aBuf,
|
||||
}
|
||||
|
||||
|
||||
PRInt32 nsJAR::ReadLine(const char** src)
|
||||
PRInt32
|
||||
nsJAR::ReadLine(const char** src)
|
||||
{
|
||||
//--Moves pointer to beginning of next line and returns line length
|
||||
// not including CR/LF.
|
||||
@ -453,9 +466,9 @@ PRInt32 nsJAR::ReadLine(const char** src)
|
||||
return length;
|
||||
}
|
||||
|
||||
nsresult nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
nsIPrincipal* aPrincipal,
|
||||
PRBool aLastSFFile) // Allows us to free up resources
|
||||
nsresult
|
||||
nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
nsIPrincipal* aPrincipal)
|
||||
{
|
||||
//-- Set up parsing variables
|
||||
nsJARManifestItem* curItem;
|
||||
@ -471,7 +484,7 @@ nsresult nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
const char* nextLineStart = filebuf;
|
||||
nsCAutoString curLine;
|
||||
PRInt32 linelen;
|
||||
nsCAutoString storedSectionDigests[JAR_DIGEST_COUNT];
|
||||
nsCAutoString storedSectionDigest;
|
||||
|
||||
//-- Check file header
|
||||
linelen = ReadLine(&nextLineStart);
|
||||
@ -492,7 +505,7 @@ nsresult nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
{
|
||||
if (curItem->mType != JAR_INVALID)
|
||||
{
|
||||
//-- Did this section have a name: line (or the global?)
|
||||
//-- Did this section have a name: line?
|
||||
if(!foundName)
|
||||
curItem->mType = JAR_INVALID;
|
||||
else
|
||||
@ -513,20 +526,14 @@ nsresult nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
}
|
||||
}
|
||||
|
||||
if (curItem->mType == JAR_INVALID)
|
||||
if (curItem->mType == JAR_INVALID ||
|
||||
curItem->mType == JAR_GLOBAL)
|
||||
delete curItem;
|
||||
else //-- calculate section digests
|
||||
else //-- calculate section digest
|
||||
{
|
||||
PRUint32 sectionLength = curPos - sectionStart;
|
||||
for (PRInt32 d=0; d<JAR_DIGEST_COUNT; d++)
|
||||
{
|
||||
PRUint32 id;
|
||||
nsresult rv = DigestBegin(&id, d);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = DigestData(id, sectionStart, sectionLength);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = CalculateDigest(id, &(curItem->calculatedSectionDigests[d]));
|
||||
}
|
||||
CalculateDigest(sectionStart, sectionLength,
|
||||
&(curItem->calculatedSectionDigest));
|
||||
//-- Save item in the hashtable
|
||||
nsStringKey itemKey(curItemName);
|
||||
mManifestData.Put(&itemKey, (void*)curItem);
|
||||
@ -548,31 +555,25 @@ nsresult nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
curSFItem = (nsJARManifestItem*)mManifestData.Get(&key);
|
||||
if(curSFItem)
|
||||
{
|
||||
PRBool valid = PR_TRUE;
|
||||
if (aPrincipal == nsnull)
|
||||
// SF file failed verification
|
||||
valid = PR_FALSE;
|
||||
else // Compare calculated digests
|
||||
curSFItem->valid = PR_FALSE;
|
||||
else // Compare digests
|
||||
{
|
||||
PRBool foundDigest = PR_FALSE;
|
||||
for (int a=0; a<JAR_DIGEST_COUNT; a++)
|
||||
if (storedSectionDigest.Length() > 0)
|
||||
{
|
||||
valid = valid &&
|
||||
( (storedSectionDigests[a].Length() == 0) ||
|
||||
storedSectionDigests[a] ==
|
||||
(const char*)curSFItem->calculatedSectionDigests[a] );
|
||||
foundDigest = foundDigest || (storedSectionDigests[a].Length() != 0);
|
||||
if (storedSectionDigest !=
|
||||
(const char*)curSFItem->calculatedSectionDigest)
|
||||
curSFItem->valid = PR_FALSE;
|
||||
else
|
||||
{
|
||||
curSFItem->mPrincipal = aPrincipal;
|
||||
NS_ADDREF(curSFItem->mPrincipal);
|
||||
}
|
||||
JAR_NULLFREE(curSFItem->calculatedSectionDigest)
|
||||
storedSectionDigest = "";
|
||||
}
|
||||
if (foundDigest && valid)
|
||||
{
|
||||
curSFItem->setPrincipal(aPrincipal);
|
||||
}
|
||||
}
|
||||
curSFItem->valid = valid;
|
||||
if (aLastSFFile)
|
||||
// Free the calculated digests; we won't need them again.
|
||||
for(PRInt16 countB=0; countB<JAR_DIGEST_COUNT; countB++)
|
||||
JAR_NULLFREE(curSFItem->calculatedSectionDigests[countB])
|
||||
} // (aPrincipal != nsnull)
|
||||
} // if(curSFItem)
|
||||
} // if(foundName)
|
||||
|
||||
@ -589,7 +590,7 @@ nsresult nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
{
|
||||
curPos = nextLineStart;
|
||||
PRInt32 continuationLen = ReadLine(&nextLineStart) - 1;
|
||||
nsAutoString continuation(curPos+1, continuationLen);
|
||||
nsCAutoString continuation(curPos+1, continuationLen);
|
||||
curLine += continuation;
|
||||
linelen += continuationLen;
|
||||
}
|
||||
@ -605,36 +606,24 @@ nsresult nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
curLine.Mid(lineData, colonPos+2, linelen - (colonPos+2));
|
||||
|
||||
//-- Lines to look for:
|
||||
// (1) *-Digest:
|
||||
if (lineName.Find("-Digest",PR_TRUE) != -1)
|
||||
// (1) Digest:
|
||||
if (lineName.Compare("SHA1-Digest",PR_TRUE) == 0)
|
||||
//-- This is a digest line, save the data in the appropriate place
|
||||
{
|
||||
PRInt32 digest;
|
||||
//** Note that in the following comparisons, the third argument to
|
||||
// Compare MUST be the length of the first argument. **
|
||||
if (lineName.Compare("MD5-", PR_TRUE, 4) == 0)
|
||||
digest = JAR_MD5;
|
||||
else if ( lineName.Compare("SHA1-", PR_TRUE, 5) == 0 ||
|
||||
lineName.Compare("SHA-", PR_TRUE, 4) == 0 )
|
||||
digest = JAR_SHA1;
|
||||
else // Unsupported algorithm
|
||||
continue;
|
||||
|
||||
if(aFileType == JAR_MF)
|
||||
{
|
||||
curItem->storedEntryDigests[digest] =
|
||||
(char*)PR_MALLOC(lineData.Length()+1);
|
||||
if (!(curItem->storedEntryDigests[digest]))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
(void)PL_strcpy(curItem->storedEntryDigests[digest], lineData);
|
||||
curItem->storedEntryDigest = (char*)PR_MALLOC(lineData.Length()+1);
|
||||
if (!(curItem->storedEntryDigest))
|
||||
continue; // Out of memory, just skip this line instead of returning.
|
||||
PL_strcpy(curItem->storedEntryDigest, lineData);
|
||||
}
|
||||
else
|
||||
storedSectionDigests[digest] = lineData;
|
||||
storedSectionDigest = lineData;
|
||||
continue;
|
||||
}
|
||||
|
||||
// (2) Name: associates this manifest section with a file in the jar.
|
||||
if (lineName.Compare("Name", PR_TRUE) == 0)
|
||||
if (!foundName && lineName.Compare("Name", PR_TRUE) == 0)
|
||||
{
|
||||
if (!(aFileType == JAR_MF && curItem->mType == JAR_GLOBAL))
|
||||
curItemName = lineData;
|
||||
@ -645,8 +634,8 @@ nsresult nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
// (3) Magic: this may be an inline Javascript.
|
||||
// We can't do any other kind of magic.
|
||||
if ( aFileType == JAR_MF &&
|
||||
lineName.Compare("Magic", PR_TRUE) == 0 &&
|
||||
curItem->mType != JAR_GLOBAL )
|
||||
curItem->mType == JAR_INTERNAL &&
|
||||
lineName.Compare("Magic", PR_TRUE) == 0)
|
||||
{
|
||||
if(lineData.Compare("javascript",PR_TRUE) == 0)
|
||||
curItem->mType = JAR_EXTERNAL;
|
||||
@ -659,6 +648,53 @@ nsresult nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
return NS_OK;
|
||||
} //ParseOneFile()
|
||||
|
||||
nsresult
|
||||
nsJAR::VerifyEntry(const char* aEntryName, char* aEntryData,
|
||||
PRUint32 aLen)
|
||||
{
|
||||
//-- Verification Step 2
|
||||
// Check that verification is supported and step 1 has been done
|
||||
|
||||
if (!SupportsRSAVerification()) return NS_OK;
|
||||
NS_ASSERTION(step1Complete,
|
||||
"Verification step 2 called before step 1 complete");
|
||||
if (!step1Complete) return NS_ERROR_FAILURE;
|
||||
|
||||
//-- Get the manifest item
|
||||
nsStringKey key(aEntryName);
|
||||
nsJARManifestItem* manItem = (nsJARManifestItem*)mManifestData.Get(&key);
|
||||
if (!manItem)
|
||||
return NS_OK;
|
||||
if (manItem->mPrincipal && manItem->valid)
|
||||
{
|
||||
if(!manItem->storedEntryDigest)
|
||||
{ // No entry digests in manifest file. Entry is unsigned.
|
||||
NS_IF_RELEASE(manItem->mPrincipal);
|
||||
manItem->mPrincipal = nsnull;
|
||||
}
|
||||
else
|
||||
{ //-- Calculate and compare digests
|
||||
char* calculatedEntryDigest;
|
||||
nsresult rv = CalculateDigest(aEntryData, aLen, &calculatedEntryDigest);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (PL_strcmp(manItem->storedEntryDigest, calculatedEntryDigest) != 0)
|
||||
{
|
||||
manItem->valid = PR_FALSE;
|
||||
NS_IF_RELEASE(manItem->mPrincipal);
|
||||
manItem->mPrincipal = nsnull;
|
||||
}
|
||||
JAR_NULLFREE(calculatedEntryDigest)
|
||||
JAR_NULLFREE(manItem->storedEntryDigest)
|
||||
NS_IF_RELEASE(mVerificationService);
|
||||
mVerificationService = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
manItem->step2Complete = PR_TRUE;
|
||||
DumpMetadata("VerifyEntry end");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
// Debugging functions
|
||||
//----------------------------------------------
|
||||
@ -671,8 +707,10 @@ PrintManItem(nsHashKey* aKey, void* aData, void* closure)
|
||||
if (manItem)
|
||||
{
|
||||
nsStringKey* key2 = (nsStringKey*)aKey;
|
||||
printf("------------\nName:%s.\n",key2->GetString().ToNewCString());
|
||||
char* name = key2->GetString().ToNewCString();
|
||||
if (PL_strcmp(name, "") != 0)
|
||||
{
|
||||
printf("------------\nName:%s.\n",name);
|
||||
if (manItem->mPrincipal)
|
||||
{
|
||||
char* toStr;
|
||||
@ -683,25 +721,26 @@ PrintManItem(nsHashKey* aKey, void* aData, void* closure)
|
||||
}
|
||||
else
|
||||
printf("No Principal.\n");
|
||||
printf("verifyComplete:%i.\n",manItem->verifyComplete);
|
||||
printf("step2Complete:%i.\n",manItem->step2Complete);
|
||||
printf("valid:%i.\n",manItem->valid);
|
||||
printf("entryDigestsCalculated:%i.\n",manItem->entryDigestsCalculated);
|
||||
/*
|
||||
for (PRInt32 x=0; x<JAR_DIGEST_COUNT; x++)
|
||||
printf("calculated section digest:%s.\n",
|
||||
manItem->calculatedSectionDigests[x]);
|
||||
for (PRInt32 y=0; y<JAR_DIGEST_COUNT; y++)
|
||||
printf("stored entry digest:%s.\n",
|
||||
manItem->storedEntryDigests[y]);
|
||||
*/
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
void nsJAR::DumpMetadata()
|
||||
void nsJAR::DumpMetadata(const char* aMessage)
|
||||
{
|
||||
#if 0
|
||||
printf("######## nsJAR::DumpMetadata Start ############\n");
|
||||
printf("### nsJAR::DumpMetadata at %s ###\n", aMessage);
|
||||
mManifestData.Enumerate(PrintManItem);
|
||||
printf("######## nsJAR::DumpMetadata End ############\n");
|
||||
#endif
|
||||
@ -710,7 +749,6 @@ void nsJAR::DumpMetadata()
|
||||
//----------------------------------------------
|
||||
// nsJAREnumerator constructor and destructor
|
||||
//----------------------------------------------
|
||||
|
||||
nsJAREnumerator::nsJAREnumerator(nsZipFind *aFind)
|
||||
: mFind(aFind),
|
||||
mCurr(nsnull),
|
||||
@ -793,13 +831,9 @@ nsJAREnumerator::GetNext(nsISupports** aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// nsJARItem constructors and destructor
|
||||
//-------------------------------------------------
|
||||
|
||||
nsJARItem::nsJARItem()
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
@ -897,60 +931,3 @@ nsJARItem::GetCRC32(PRUint32 *aCrc32)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// nsJARManifestItem constructors and destructor
|
||||
//-------------------------------------------------
|
||||
nsJARManifestItem::nsJARManifestItem(): mType(JAR_INTERNAL),
|
||||
verifyComplete(PR_FALSE),
|
||||
valid(PR_TRUE),
|
||||
entryDigestsCalculated(PR_FALSE),
|
||||
mPrincipal(nsnull)
|
||||
{
|
||||
// Initialize digests to null
|
||||
for(PRInt32 count = 0; count<JAR_DIGEST_COUNT; count++)
|
||||
{
|
||||
calculatedSectionDigests[count] = nsnull;
|
||||
calculatedEntryDigests[count] = nsnull;
|
||||
storedEntryDigests[count] = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
nsJARManifestItem::~nsJARManifestItem()
|
||||
{
|
||||
// Delete digests if necessary
|
||||
for(PRInt32 count = 0; count<JAR_DIGEST_COUNT; count++)
|
||||
{
|
||||
PR_FREEIF(calculatedSectionDigests[count]);
|
||||
PR_FREEIF(calculatedEntryDigests[count]);
|
||||
PR_FREEIF(storedEntryDigests[count]);
|
||||
}
|
||||
NS_IF_RELEASE(mPrincipal);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// nsJARManifestItem accessor functions
|
||||
//-------------------------------------------------
|
||||
void nsJARManifestItem::setPrincipal(nsIPrincipal *aPrincipal)
|
||||
{
|
||||
NS_IF_RELEASE(mPrincipal);
|
||||
mPrincipal = aPrincipal;
|
||||
NS_IF_ADDREF(mPrincipal);
|
||||
}
|
||||
|
||||
void nsJARManifestItem::getPrincipal(nsIPrincipal **result)
|
||||
{
|
||||
if (verifyComplete && valid)
|
||||
{
|
||||
*result = mPrincipal;
|
||||
NS_IF_ADDREF(*result);
|
||||
}
|
||||
else
|
||||
*result = nsnull;
|
||||
}
|
||||
|
||||
PRBool nsJARManifestItem::hasPrincipal()
|
||||
{
|
||||
return verifyComplete && valid && mPrincipal;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Copyright (C) 1998-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
@ -53,13 +53,6 @@
|
||||
class nsIInputStream;
|
||||
class nsIPrincipal;
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Supported secure digest algorithms
|
||||
*------------------------------------------------------------------------*/
|
||||
#define JAR_DIGEST_COUNT 2
|
||||
#define JAR_SHA1 0
|
||||
#define JAR_MD5 1
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Class nsJAR declaration.
|
||||
* nsJAR serves as an XPCOM wrapper for nsZipArchive with the addition of
|
||||
@ -67,7 +60,7 @@ class nsIPrincipal;
|
||||
*------------------------------------------------------------------------*/
|
||||
class nsJAR : public nsIZipReader
|
||||
{
|
||||
// Allows nsJARInputStream to call the digest functions
|
||||
// Allows nsJARInputStream to call the verification functions
|
||||
friend class nsJARInputStream;
|
||||
|
||||
public:
|
||||
@ -83,30 +76,32 @@ class nsJAR : public nsIZipReader
|
||||
|
||||
private:
|
||||
//-- Private data members
|
||||
nsCOMPtr<nsIFile> mZipFile;
|
||||
nsZipArchive mZip;
|
||||
nsObjectHashtable mManifestData;
|
||||
PRBool manifestParsed;
|
||||
nsCOMPtr<nsIFile> mZipFile; // The zip/jar file on disk
|
||||
nsZipArchive mZip; // The underlying zip archive
|
||||
nsObjectHashtable mManifestData; // Stores metadata for each entry
|
||||
PRBool step1Complete; // True if manifest has been parsed
|
||||
nsISupports* mVerificationService;
|
||||
|
||||
//-- Private functions
|
||||
nsresult CreateInputStream(const char* aFilename, nsJAR* aJAR, nsIInputStream** is);
|
||||
nsresult CreateInputStream(const char* aFilename, nsJAR* aJAR,
|
||||
nsIInputStream** is);
|
||||
nsresult LoadEntry(const char* aFilename, const char** aBuf,
|
||||
PRUint32* aBufLen = nsnull);
|
||||
PRInt32 ReadLine(const char** src);
|
||||
nsresult ParseOneFile(const char* filebuf, PRInt16 aFileType,
|
||||
nsIPrincipal* aPrincipal = nsnull,
|
||||
PRBool aLastSFFile = PR_TRUE);
|
||||
nsIPrincipal* aPrincipal = nsnull);
|
||||
nsresult VerifyEntry(const char* aEntryName, char* aEntryData,
|
||||
PRUint32 aLen);
|
||||
|
||||
//-- Debugging
|
||||
void DumpMetadata(const char* aMessage);
|
||||
|
||||
//-- The following private functions are implemented in nsJARStubs.cpp
|
||||
static PRBool SupportsRSAVerification();
|
||||
nsresult DigestBegin(PRUint32* id, PRInt32 alg);
|
||||
nsresult DigestData(PRUint32 id, const char* data, PRUint32 length);
|
||||
nsresult CalculateDigest(PRUint32 id, char** digest);
|
||||
nsresult CalculateDigest(const char* aInBuf, PRUint32 aInBufLen,
|
||||
char** digest);
|
||||
nsresult VerifySignature(const char* sfBuf, const char* rsaBuf,
|
||||
PRUint32 rsaBufLen, nsIPrincipal** aPrincipal);
|
||||
|
||||
void DumpMetadata(); // Debugging
|
||||
};
|
||||
|
||||
/**
|
||||
@ -130,59 +125,6 @@ public:
|
||||
nsZipItem* mZipItem;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsJARManifestItem
|
||||
*
|
||||
* Meta-information pertaining to an individual JAR entry, taken
|
||||
* from the META-INF/MANIFEST.MF and META-INF/ *.SF files. Ideally,
|
||||
* this would be part of nsJARItem, but nsJARItems are stored in the
|
||||
* underlying nsZipArchive which doesn't know about metadata.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
JAR_INVALID = 1,
|
||||
JAR_GLOBAL = 2,
|
||||
JAR_INTERNAL = 3,
|
||||
JAR_EXTERNAL = 4
|
||||
// Maybe we'll want jar files to sign URL's eventually.
|
||||
} JARManifestItemType;
|
||||
|
||||
// Use this macro to look up global data (from the manifest file header)
|
||||
#define JAR_GLOBALMETA ""
|
||||
|
||||
class nsJARManifestItem
|
||||
{
|
||||
public:
|
||||
JARManifestItemType mType;
|
||||
|
||||
// True if both steps of verification have taken place:
|
||||
// ParseManifest and reading the item into memory via GetInputStream
|
||||
PRBool verifyComplete;
|
||||
|
||||
// True unless one or more verification steps failed
|
||||
PRBool valid;
|
||||
|
||||
// Internal storage of digests
|
||||
char* calculatedSectionDigests[JAR_DIGEST_COUNT];
|
||||
char* calculatedEntryDigests[JAR_DIGEST_COUNT];
|
||||
char* storedEntryDigests[JAR_DIGEST_COUNT];
|
||||
PRBool entryDigestsCalculated;
|
||||
|
||||
void setPrincipal(nsIPrincipal *aPrincipal);
|
||||
|
||||
void getPrincipal(nsIPrincipal **result);
|
||||
|
||||
PRBool hasPrincipal();
|
||||
|
||||
nsJARManifestItem();
|
||||
virtual ~nsJARManifestItem();
|
||||
|
||||
private:
|
||||
// the entity which signed this item
|
||||
nsIPrincipal* mPrincipal;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* nsJAREnumerator
|
||||
*
|
||||
|
@ -46,48 +46,18 @@ nsJARInputStream::Available(PRUint32 *_retval)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJARInputStream::Read(char* buf, PRUint32 count, PRUint32 *_retval)
|
||||
nsJARInputStream::Read(char* buf, PRUint32 count, PRUint32 *bytesRead)
|
||||
{
|
||||
if (mZip == nsnull)
|
||||
{
|
||||
*_retval = 0;
|
||||
*bytesRead = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if( (mZip->Read(mReadInfo, buf, count, _retval)) != ZIP_OK )
|
||||
if( (mZip->Read(mReadInfo, buf, count, bytesRead)) != ZIP_OK )
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Pass the buffer on to the JAR parser
|
||||
if (mJAR && mJAR->SupportsRSAVerification())
|
||||
{
|
||||
nsStringKey key(mEntryName);
|
||||
nsJARManifestItem* manItem =
|
||||
(nsJARManifestItem*)mJAR->mManifestData.Get(&key);
|
||||
if (manItem && !manItem->entryDigestsCalculated)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (digestContexts[0] == 0)
|
||||
for (PRInt32 b=0; b<JAR_DIGEST_COUNT && NS_SUCCEEDED(rv); b++)
|
||||
rv = mJAR->DigestBegin(&digestContexts[b], b);
|
||||
for (PRInt32 c=0; c<JAR_DIGEST_COUNT && NS_SUCCEEDED(rv); c++)
|
||||
rv = mJAR->DigestData(digestContexts[c], buf, *_retval);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
PRUint32 available;
|
||||
rv = Available(&available);
|
||||
if (available == 0)
|
||||
{
|
||||
for (PRInt32 d=0; d<JAR_DIGEST_COUNT && NS_SUCCEEDED(rv); d++)
|
||||
rv = mJAR->CalculateDigest(digestContexts[d],
|
||||
&(manItem->calculatedEntryDigests[d]));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
manItem->entryDigestsCalculated = PR_TRUE;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
else
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -103,17 +73,18 @@ nsJARInputStream::Init(nsJAR* aJAR, nsZipArchive* aZip, const char* aFilename)
|
||||
if (!(aZip && aFilename))
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
mZip = aZip;
|
||||
mJAR = aJAR;
|
||||
mEntryName = (char*)aFilename;
|
||||
for (PRInt32 a=0; a<JAR_DIGEST_COUNT; a++)
|
||||
digestContexts[a] = 0;
|
||||
|
||||
PRInt32 result;
|
||||
result = mZip->ReadInit(mEntryName, &mReadInfo);
|
||||
if (result != ZIP_OK)
|
||||
return NS_ERROR_FAILURE;
|
||||
else
|
||||
return NS_OK;
|
||||
|
||||
// Pass the file (already in memory) on to the JAR parser
|
||||
if (aJAR)
|
||||
return aJAR->VerifyEntry(mEntryName, mReadInfo->mFileBuffer,
|
||||
mReadInfo->mItem->realsize);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
@ -135,7 +106,6 @@ nsJARInputStream::Create(nsISupports* ignored, const nsIID& aIID, void* *aResult
|
||||
nsJARInputStream::nsJARInputStream()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mJAR = nsnull;
|
||||
}
|
||||
|
||||
nsJARInputStream::~nsJARInputStream()
|
||||
|
@ -30,9 +30,7 @@
|
||||
{0x90, 0xd8, 0x9c, 0x98, 0xfc, 0x2b, 0x7a, 0xc0}}
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
#include "prio.h" // XXX: Needed by nsZipArchive.h
|
||||
#include "nsJAR.h"
|
||||
//#include "nsZipArchive.h"
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Class nsJARInputStream declaration. This class defines objects returned
|
||||
@ -61,9 +59,7 @@ class nsJARInputStream : public nsIInputStream
|
||||
Init(nsJAR* aParser, nsZipArchive* aZip, const char* aFilename);
|
||||
|
||||
private:
|
||||
|
||||
nsJAR* mJAR;
|
||||
PRUint32 digestContexts[JAR_DIGEST_COUNT];
|
||||
|
||||
char* mEntryName;
|
||||
nsZipArchive* mZip;
|
||||
nsZipRead* mReadInfo;
|
||||
|
@ -33,23 +33,15 @@ PRBool nsJAR::SupportsRSAVerification()
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult nsJAR::DigestBegin(PRUint32* id, PRInt32 alg)
|
||||
nsresult nsJAR::CalculateDigest(const char* aInBuf, PRUint32 aInBufLen,
|
||||
char** digest)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult nsJAR::DigestData(PRUint32 id, const char* data, PRUint32 length)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult nsJAR::CalculateDigest(PRUint32 id, char** digest)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult nsJAR::VerifySignature(const char* sfBuf, const char* rsaBuf,
|
||||
PRUint32 rsaBufLen, nsIPrincipal** aPrincipal)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -382,7 +382,7 @@ PRInt32 nsZipArchive::ReadInit(const char* zipEntry, nsZipRead** aRead)
|
||||
|
||||
//-- find item and seek to file position
|
||||
nsZipItem* item;
|
||||
result = ReadInitImpl(zipEntry, &item);
|
||||
result = SeekToItem(zipEntry, &item);
|
||||
if (result != ZIP_OK) return result;
|
||||
|
||||
//-- Create nsZipRead object
|
||||
@ -393,56 +393,57 @@ PRInt32 nsZipArchive::ReadInit(const char* zipEntry, nsZipRead** aRead)
|
||||
//-- initialize crc
|
||||
(*aRead)->mCRC32 = crc32(0L, Z_NULL, 0);
|
||||
|
||||
//-- If file is deflated, do the inflation now.
|
||||
// We save the complete inflated item in mInflatedFileBuffer
|
||||
// to be copied later.
|
||||
if (item->compression == DEFLATED)
|
||||
//-- Read the item into memory
|
||||
// Inflate if necessary and save in mInflatedFileBuffer
|
||||
// for sequential reading.
|
||||
// (nsJAR needs the whole file in memory before passing it on)
|
||||
char* buf = (char*)PR_Malloc(item->realsize);
|
||||
if (!buf) return ZIP_ERR_MEMORY;
|
||||
switch(item->compression)
|
||||
{
|
||||
char* buf = (char*)PR_Malloc(item->realsize);
|
||||
result = InflateItem(item, 0, buf);
|
||||
if (result != ZIP_OK) return result;
|
||||
(*aRead)->mInflatedFileBuffer = buf;
|
||||
case DEFLATED:
|
||||
result = InflateItem(item, 0, buf);
|
||||
break;
|
||||
case STORED:
|
||||
result = CopyItemToBuffer(item, buf);
|
||||
break;
|
||||
default:
|
||||
return ZIP_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return ZIP_OK;
|
||||
if (result == ZIP_OK)
|
||||
(*aRead)->mFileBuffer = buf;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------
|
||||
//------------------------------------------
|
||||
// nsZipArchive::Read
|
||||
//---------------------------------------------
|
||||
PRInt32 nsZipArchive::Read(nsZipRead* aRead, char* aBuf,
|
||||
//------------------------------------------
|
||||
PRInt32 nsZipArchive::Read(nsZipRead* aRead, char* aOutBuf,
|
||||
PRUint32 aCount, PRUint32* aBytesRead)
|
||||
{
|
||||
//-- Parameter validity check
|
||||
/*
|
||||
* Note the nsZipRead passed in must have been created
|
||||
* by this nsZipArchive.
|
||||
*/
|
||||
if (aBytesRead == 0 || aRead == 0 || aBuf == 0 ||
|
||||
//-- Copies data from aRead->mFileBuffer
|
||||
//-- Parameter check
|
||||
if (aBytesRead == 0 || aRead == 0 || aOutBuf == 0 ||
|
||||
aRead->mArchive != this)
|
||||
return ZIP_ERR_PARAM;
|
||||
|
||||
//-- extract the file using appropriate method
|
||||
switch( aRead->mItem->compression )
|
||||
{
|
||||
case STORED:
|
||||
//-- Read from the zip file directly into the caller's buffer
|
||||
return ReadItem( aRead, aBuf, aCount, aBytesRead );
|
||||
if(!aRead->mItem || !aRead->mFileBuffer)
|
||||
return ZIP_ERR_GENERAL;
|
||||
|
||||
case DEFLATED:
|
||||
//-- We've already done the inflation; copy from mInflatedFileBuffer
|
||||
// into the caller's buffer
|
||||
return ReadInflatedItem( aRead->mItem, aRead->mInflatedFileBuffer, aBuf,
|
||||
&(aRead->mCurPos), aCount, aBytesRead);
|
||||
//-- Set up the copy
|
||||
PRUint32 bigBufSize = aRead->mItem->realsize;
|
||||
PRUint32 curPos = aRead->mCurPos;
|
||||
*aBytesRead = (curPos + aCount) < bigBufSize ? aCount : bigBufSize - curPos;
|
||||
char* src = aRead->mFileBuffer + curPos;
|
||||
|
||||
default:
|
||||
//-- unsupported compression type
|
||||
return ZIP_ERR_UNSUPPORTED;
|
||||
}
|
||||
//-- Do the copy and record number of bytes copied
|
||||
memcpy(aOutBuf, src, *aBytesRead);
|
||||
aRead->mCurPos += *aBytesRead;
|
||||
|
||||
return ZIP_OK;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------
|
||||
// nsZipArchive::Available
|
||||
//---------------------------------------------
|
||||
@ -496,7 +497,7 @@ nsZipArchive::ExtractFileToFileDesc(const char * zipEntry, PRFileDesc* outFD,
|
||||
nsZipItem* item;
|
||||
|
||||
//-- Find item in archive and seek to it
|
||||
status = ReadInitImpl( zipEntry, &item );
|
||||
status = SeekToItem( zipEntry, &item );
|
||||
if (status != ZIP_OK)
|
||||
return status;
|
||||
|
||||
@ -876,9 +877,9 @@ PRUint32 nsZipArchive::HashName( const char* aName )
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// nsZipArchive::ReadInitImpl
|
||||
// nsZipArchive::SeekToItem
|
||||
//---------------------------------------------
|
||||
PRInt32 nsZipArchive::ReadInitImpl(const char* zipEntry, nsZipItem** aItem)
|
||||
PRInt32 nsZipArchive::SeekToItem(const char* zipEntry, nsZipItem** aItem)
|
||||
{
|
||||
PR_ASSERT (zipEntry != 0);
|
||||
|
||||
@ -901,39 +902,24 @@ PRInt32 nsZipArchive::ReadInitImpl(const char* zipEntry, nsZipItem** aItem)
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
// nsZipArchive::ReadItem
|
||||
// nsZipArchive::CopyItemToBuffer
|
||||
//---------------------------------------------
|
||||
PRInt32 nsZipArchive::ReadItem( nsZipRead* aRead, char* aBuf,
|
||||
PRUint32 aCount, PRUint32* aActual)
|
||||
PRInt32 nsZipArchive::CopyItemToBuffer(const nsZipItem* aItem, char* aOutBuf)
|
||||
{
|
||||
PRUint32 chunk;
|
||||
nsZipItem *item = aRead->mItem;
|
||||
PRUint32 *curpos = &(aRead->mCurPos);
|
||||
PRUint32 *crc = &(aRead->mCRC32);
|
||||
|
||||
PR_ASSERT(aBuf != 0 && item != 0);
|
||||
|
||||
// Seek to position in file
|
||||
if ( PR_Seek( mFd, (PROffset32)(item->offset + *curpos), PR_SEEK_SET ) !=
|
||||
(PROffset32)(item->offset + *curpos) )
|
||||
return ZIP_ERR_CORRUPT;
|
||||
PR_ASSERT(aOutBuf != 0 && aItem != 0);
|
||||
|
||||
//-- Already at the correct point in the file
|
||||
//-- Read from file
|
||||
chunk = (aCount <= ((item->size) - *curpos) ) ? aCount
|
||||
: ((item->size) - *curpos);
|
||||
*aActual = PR_Read( mFd, aBuf, chunk );
|
||||
*curpos += *aActual;
|
||||
|
||||
//-- incrementally update crc32
|
||||
*crc = crc32(*crc,(const unsigned char*)aBuf, chunk);
|
||||
PRUint32 actual = PR_Read( mFd, aOutBuf, aItem->realsize);
|
||||
if (actual != aItem->realsize)
|
||||
return ZIP_ERR_CORRUPT;
|
||||
|
||||
//-- verify crc32
|
||||
if (0 == (item->size - *curpos)) // eof
|
||||
{
|
||||
if (*crc != item->crc32)
|
||||
return ZIP_ERR_CORRUPT;
|
||||
}
|
||||
|
||||
PRUint32 calculatedCRC = crc32(0L, Z_NULL, 0);
|
||||
calculatedCRC = crc32( calculatedCRC,(const unsigned char*)aOutBuf,
|
||||
aItem->realsize);
|
||||
if (calculatedCRC != aItem->crc32)
|
||||
return ZIP_ERR_CORRUPT;
|
||||
return ZIP_OK;
|
||||
}
|
||||
|
||||
@ -953,7 +939,7 @@ PRInt32 nsZipArchive::CopyItemToDisk(const nsZipItem* aItem, PRFileDesc* fOut)
|
||||
return ZIP_ERR_MEMORY;
|
||||
|
||||
//-- We should already be at the correct spot in the archive.
|
||||
//-- ReadInitImpl did the seek().
|
||||
//-- SeekToItem did the seek().
|
||||
|
||||
//-- initialize crc
|
||||
crc = crc32(0L, Z_NULL, 0);
|
||||
@ -1047,7 +1033,7 @@ PRInt32 nsZipArchive::InflateItem( const nsZipItem* aItem, PRFileDesc* fOut,
|
||||
}
|
||||
|
||||
//-- We should already be at the correct spot in the archive.
|
||||
//-- ReadInitImpl did the seek().
|
||||
//-- SeekToItem did the seek().
|
||||
|
||||
//-- set up the inflate
|
||||
memset( &zs, 0, sizeof(zs) );
|
||||
@ -1185,33 +1171,6 @@ cleanup:
|
||||
return status;
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
// nsZipArchive::ReadInflatedItem
|
||||
//------------------------------------------
|
||||
PRInt32 nsZipArchive::ReadInflatedItem( const nsZipItem* aItem,
|
||||
char* inflatedBuf,
|
||||
char* outbuf,
|
||||
PRUint32* aCurPos,
|
||||
PRUint32 count,
|
||||
PRUint32* actual)
|
||||
{
|
||||
//-- Parameter check
|
||||
PR_ASSERT(inflatedBuf != 0 && outbuf != 0 && aItem != 0);
|
||||
|
||||
//-- Set up the copy
|
||||
PRUint32 bigBufSize = aItem->realsize;
|
||||
PRUint32 c = ((*aCurPos + count) < bigBufSize) ? count : bigBufSize - *aCurPos;
|
||||
char* src = inflatedBuf + (*aCurPos);
|
||||
|
||||
//-- Do the copy and record number of bytes copied
|
||||
memcpy(outbuf, src, c);
|
||||
*actual = c;
|
||||
*aCurPos += *actual;
|
||||
|
||||
return ZIP_OK;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------
|
||||
// nsZipArchive constructor and destructor
|
||||
//------------------------------------------
|
||||
@ -1283,7 +1242,7 @@ nsZipRead::nsZipRead( nsZipArchive* aZipArchive, nsZipItem* aZipItem )
|
||||
: mArchive(aZipArchive),
|
||||
mItem(aZipItem),
|
||||
mCurPos(0),
|
||||
mInflatedFileBuffer(0)
|
||||
mFileBuffer(0)
|
||||
{
|
||||
#ifndef STANDALONE
|
||||
MOZ_COUNT_CTOR(nsZipRead);
|
||||
@ -1292,7 +1251,7 @@ nsZipRead::nsZipRead( nsZipArchive* aZipArchive, nsZipItem* aZipItem )
|
||||
|
||||
nsZipRead::~nsZipRead()
|
||||
{
|
||||
PR_FREEIF(mInflatedFileBuffer);
|
||||
PR_FREEIF(mFileBuffer);
|
||||
|
||||
#ifndef STANDALONE
|
||||
MOZ_COUNT_DTOR(nsZipRead);
|
||||
|
@ -201,16 +201,12 @@ private:
|
||||
nsZipItem* GetFileItem( const char * zipEntry );
|
||||
PRUint32 HashName( const char* aName );
|
||||
|
||||
PRInt32 ReadInitImpl(const char* zipEntry, nsZipItem** aItem);
|
||||
PRInt32 ReadItem( nsZipRead* aRead, char* aBuf,
|
||||
PRUint32 aCount, PRUint32* aActual );
|
||||
PRInt32 SeekToItem(const char* zipEntry, nsZipItem** aItem);
|
||||
PRInt32 CopyItemToBuffer(const nsZipItem* aItem, char* aBuf);
|
||||
PRInt32 CopyItemToDisk( const nsZipItem* aItem, PRFileDesc* outFD );
|
||||
PRInt32 InflateItem( const nsZipItem* aItem,
|
||||
PRFileDesc* outFD,
|
||||
char* buf );
|
||||
PRInt32 ReadInflatedItem( const nsZipItem* aItem,
|
||||
char* inflatedBuf, char* outbuf,
|
||||
PRUint32* aCurPos, PRUint32 count, PRUint32* actual);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -220,7 +216,6 @@ private:
|
||||
*/
|
||||
class nsZipRead
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
nsZipRead( nsZipArchive* aZip, nsZipItem* item );
|
||||
@ -229,7 +224,7 @@ public:
|
||||
nsZipArchive* mArchive;
|
||||
nsZipItem* mItem;
|
||||
PRUint32 mCurPos;
|
||||
char* mInflatedFileBuffer;
|
||||
char* mFileBuffer;
|
||||
PRUint32 mCRC32;
|
||||
|
||||
private:
|
||||
@ -238,7 +233,6 @@ private:
|
||||
nsZipRead(const nsZipFind& rhs);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* nsZipFind
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user