From 74488c46a3335a019d65622271375c16ad52d192 Mon Sep 17 00:00:00 2001 From: "mstoltz%netscape.com" Date: Wed, 10 May 2000 01:49:33 +0000 Subject: [PATCH] Removed dependency of libjar on psm-glue, bug 36853. Fixed out parameter type problem in PSMComponent::HashEnd --- caps/idl/MANIFEST | 2 + caps/idl/Makefile.in | 1 + caps/idl/makefile.win | 1 + caps/idl/nsISignatureVerifier.idl | 64 ++++++ .../psm-glue/public/nsIPSMComponent.idl | 29 --- extensions/psm-glue/src/nsPSMComponent.cpp | 196 +++++++----------- extensions/psm-glue/src/nsPSMComponent.h | 6 +- modules/libjar/nsIZipReader.idl | 7 + modules/libjar/nsJAR.cpp | 162 ++++++--------- modules/libjar/nsJAR.h | 14 +- 10 files changed, 229 insertions(+), 253 deletions(-) create mode 100644 caps/idl/nsISignatureVerifier.idl diff --git a/caps/idl/MANIFEST b/caps/idl/MANIFEST index 81d33167d77a..3bf58bd7e924 100644 --- a/caps/idl/MANIFEST +++ b/caps/idl/MANIFEST @@ -2,3 +2,5 @@ nsICertificatePrincipal.idl nsICodebasePrincipal.idl nsIPrincipal.idl nsIScriptSecurityManager.idl +nsISignatureVerifier.idl + diff --git a/caps/idl/Makefile.in b/caps/idl/Makefile.in index b452f5e57aaf..0b49944a4fd1 100644 --- a/caps/idl/Makefile.in +++ b/caps/idl/Makefile.in @@ -34,6 +34,7 @@ XPIDLSRCS = \ nsICodebasePrincipal.idl \ nsICertificatePrincipal.idl \ nsIAggregatePrincipal.idl \ + nsISignatureVerifier.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/caps/idl/makefile.win b/caps/idl/makefile.win index bd448dccc554..195dff4a71c3 100644 --- a/caps/idl/makefile.win +++ b/caps/idl/makefile.win @@ -29,6 +29,7 @@ XPIDLSRCS= \ .\nsICertificatePrincipal.idl \ .\nsICodebasePrincipal.idl \ .\nsIAggregatePrincipal.idl \ + .\nsISignatureVerifier.idl \ $(NULL) include <$(DEPTH)\config\rules.mak> diff --git a/caps/idl/nsISignatureVerifier.idl b/caps/idl/nsISignatureVerifier.idl new file mode 100644 index 000000000000..2b448713d225 --- /dev/null +++ b/caps/idl/nsISignatureVerifier.idl @@ -0,0 +1,64 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1999-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Mitchell Stoltz + */ + +/* An interface for calculating secure hashes and verifying signatures*/ +#include "nsIPrincipal.idl" + +[ptr] native UnsignedCharPtr(unsigned char); + +[uuid(7bdbdb36-1dd2-11b2-a44f-e303037f214d)] +interface nsISignatureVerifier : nsISupports +{ + /* Sig Verification Error Codes */ + const long VERIFY_OK = 0; + const long VERIFY_ERROR_UNKNOWN_CA = -8172; /* -8172 is the error code returned by PSM */ + + /* Hash Algorithms (based on cmtcmn.h) */ + const short MD2 = 1; + const short MD5 = 2; + const short SHA1 = 3; + const unsigned long MD2_LENGTH = 16; + const unsigned long MD5_LENGTH = 16; + const unsigned long SHA1_LENGTH = 20; + const unsigned long MAX_HASH_LENGTH = SHA1_LENGTH; + + /* Secure Hashing functions */ + void hashBegin(in unsigned long alg, out unsigned long id); + void hashUpdate(in unsigned long id, in string buf, in unsigned long buflen); + [noscript] void hashEnd(in unsigned long id, out UnsignedCharPtr hash, + out unsigned long hashlen, in unsigned long maxLen); + + /* Signature Verification functions */ + nsIPrincipal createPrincipalFromSignature(in string aSignature, + in unsigned long aSignatureLen); + nsIPrincipal verifySignature(in string aSignature, + in unsigned long aSignatureLen, + in string plaintext, + in unsigned long plaintextLen, + out long errorCode); +}; + + +%{C++ +#define SIGNATURE_VERIFIER_PROGID "component://netscape/psm" +%} diff --git a/extensions/psm-glue/public/nsIPSMComponent.idl b/extensions/psm-glue/public/nsIPSMComponent.idl index 467b91d8d02e..1d7533fbfcc3 100644 --- a/extensions/psm-glue/public/nsIPSMComponent.idl +++ b/extensions/psm-glue/public/nsIPSMComponent.idl @@ -49,35 +49,6 @@ interface nsIPSMComponent : nsISupports * This will send PSM all preferences that we know about. */ void passPrefs(); - - /* Sig Verification Error Codes */ - const long VERIFY_OK = 0; - const long VERIFY_NOSIG = -2; - const long VERIFY_ERROR_UNKNOWN_CA = -8172; - - /* Hash Algorithms (based on cmtcmn.h) */ - const short MD2 = 1; - const short MD5 = 2; - const short SHA1 = 3; - const unsigned long MD2_LENGTH = 16; - const unsigned long MD5_LENGTH = 16; - const unsigned long SHA1_LENGTH = 20; - const unsigned long MAX_HASH_LENGTH = SHA1_LENGTH; - - /* Secure Hashing functions */ - void hashBegin(in unsigned long alg, out unsigned long id); - void hashUpdate(in unsigned long id, in string buf, in unsigned long buflen); - void hashEnd(in unsigned long id, out string hash, out unsigned long hashlen, - in unsigned long maxLen); - - /* Signature Verification functions */ - void verifyRSABegin(out unsigned long id); - void verifyRSAUpdate(in unsigned long id, in string buf, - in unsigned long buflen); - void verifyRSAEnd(in unsigned long id, in string plaintext, - in unsigned long plaintextLen, - in boolean keepCert, out nsIPrincipal principal, out long result); - nsIPrincipal CreatePrincipalFromCert(in unsigned long certID); }; %{C++ diff --git a/extensions/psm-glue/src/nsPSMComponent.cpp b/extensions/psm-glue/src/nsPSMComponent.cpp index c43b26ffd3a1..e472f59c332a 100644 --- a/extensions/psm-glue/src/nsPSMComponent.cpp +++ b/extensions/psm-glue/src/nsPSMComponent.cpp @@ -120,9 +120,10 @@ nsPSMComponent::CreatePSMComponent(nsISupports* aOuter, REFNSIID aIID, void **aR } /* nsISupports Implementation for the class */ -NS_IMPL_THREADSAFE_ISUPPORTS2(nsPSMComponent, +NS_IMPL_THREADSAFE_ISUPPORTS3(nsPSMComponent, nsIPSMComponent, - nsIContentHandler); + nsIContentHandler, + nsISignatureVerifier); #define INIT_NUM_PREFS 100 /* preference types */ @@ -758,9 +759,9 @@ nsPSMComponent::HandleContent(const char * aContentType, } -//----------------------------------------- -// Secure Hash Functions -//----------------------------------------- +//--------------------------------------------- +// Functions Implenenting NSISignatureVerifier +//--------------------------------------------- NS_IMETHODIMP nsPSMComponent::HashBegin(PRUint32 alg, PRUint32* id) { @@ -791,8 +792,8 @@ nsPSMComponent::HashUpdate(PRUint32 id, const char* buf, PRUint32 buflen) } NS_IMETHODIMP -nsPSMComponent::HashEnd(PRUint32 id, char** hash, PRUint32* hashlen, - PRUint32 maxLen) +nsPSMComponent::HashEnd(PRUint32 id, unsigned char** hash, + PRUint32* hashLen, PRUint32 maxLen) { if (!hash) return NS_ERROR_ILLEGAL_VALUE; @@ -801,147 +802,105 @@ nsPSMComponent::HashEnd(PRUint32 id, char** hash, PRUint32* hashlen, if (NS_FAILED(GetControlConnection( &controlConnection ))) return NS_ERROR_FAILURE; - if(CMT_HASH_End(controlConnection, id, (unsigned char*)*hash, - (CMUint32*)hashlen, maxLen) != CMTSuccess) + if(CMT_HASH_End(controlConnection, id, *hash, + (CMUint32*)hashLen, maxLen) != CMTSuccess) return NS_ERROR_FAILURE; CMT_HASH_Destroy(controlConnection, id); return NS_OK; } -//----------------------------------------- -// Signature Verification Functions -//----------------------------------------- +NS_IMETHODIMP +nsPSMComponent::CreatePrincipalFromSignature(const char* aRSABuf, PRUint32 aRSABufLen, + nsIPrincipal** aPrincipal) +{ + PRInt32 errorCode; + return VerifySignature(aRSABuf, aRSABufLen, nsnull, 0, &errorCode, aPrincipal); +} + PR_STATIC_CALLBACK(void) UselessPK7DataSink(void* arg, const char* buf, CMUint32 len) { } NS_IMETHODIMP -nsPSMComponent::VerifyRSABegin(PRUint32* id) +nsPSMComponent::VerifySignature(const char* aRSABuf, PRUint32 aRSABufLen, + const char* aPlaintext, PRUint32 aPlaintextLen, + PRInt32* aErrorCode, + nsIPrincipal** aPrincipal) { - if (!id) - return NS_ERROR_ILLEGAL_VALUE; + if (!aPrincipal || !aErrorCode) + return NS_ERROR_NULL_POINTER; + *aErrorCode = 0; + *aPrincipal = nsnull; CMT_CONTROL *controlConnection; if (NS_FAILED(GetControlConnection( &controlConnection ))) return NS_ERROR_FAILURE; + //-- Decode the signature stream + CMUint32 decoderID; CMInt32* blah = nsnull; CMTStatus result = CMT_PKCS7DecoderStart(controlConnection, nsnull, - (CMUint32*)id, blah, + &decoderID, blah, UselessPK7DataSink, nsnull); - if (result == CMTSuccess) - return NS_OK; - else - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsPSMComponent::VerifyRSAUpdate(PRUint32 id, const char* buf, PRUint32 buflen) -{ - CMT_CONTROL *controlConnection; - if (NS_FAILED(GetControlConnection( &controlConnection ))) - return NS_ERROR_FAILURE; - - CMTStatus result = CMT_PKCS7DecoderUpdate(controlConnection, id, buf, buflen); - if (result == CMTSuccess) - return NS_OK; - else - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -nsPSMComponent::VerifyRSAEnd(PRUint32 id, const char* plaintext, - PRUint32 plaintextLen, - PRBool aKeepCert, - nsIPrincipal** aPrincipal, - PRInt32* aVerifyError) -{ - *aVerifyError = -1; - CMT_CONTROL *controlConnection; - if (NS_FAILED(GetControlConnection( &controlConnection ))) - return NS_ERROR_FAILURE; - + if (result != CMTSuccess) return NS_ERROR_FAILURE; + result = CMT_PKCS7DecoderUpdate(controlConnection, decoderID, aRSABuf, aRSABufLen); + if (result != CMTSuccess) return NS_ERROR_FAILURE; CMUint32 contentInfo; - CMTStatus result = CMT_PKCS7DecoderFinish(controlConnection, - id, &contentInfo); - if (result != CMTSuccess) - return NS_ERROR_FAILURE; - - //-- Make sure a signature is present - CMInt32 isSigned; - result = CMT_GetNumericAttribute(controlConnection, contentInfo, - SSM_FID_P7CINFO_IS_SIGNED, &isSigned); - if (result != CMTSuccess) return NS_ERROR_FAILURE; - if (!isSigned) - { - *aPrincipal = nsnull; - *aVerifyError = nsIPSMComponent::VERIFY_NOSIG; - return NS_OK; - } - // SHA1 hash the plaintext to compare it to the signature - CMUint32 hashId; - CMT_HashCreate(controlConnection, nsIPSMComponent::SHA1, &hashId); - CMT_HASH_Begin(controlConnection, hashId); - result = CMT_HASH_Update(controlConnection, hashId, - (const unsigned char*)plaintext, plaintextLen); + result = CMT_PKCS7DecoderFinish(controlConnection, + decoderID, &contentInfo); if (result != CMTSuccess) return NS_ERROR_FAILURE; - unsigned char* hash = (unsigned char*)PR_MALLOC(nsIPSMComponent::SHA1_LENGTH); - if (!hash) return NS_ERROR_OUT_OF_MEMORY; - CMUint32 hashLen; - result = CMT_HASH_End(controlConnection, hashId, hash, - &hashLen, nsIPSMComponent::SHA1_LENGTH); - NS_ASSERTION(hashLen == nsIPSMComponent::SHA1_LENGTH, - "PSMComponent: Hash too short."); - CMT_HASH_Destroy(controlConnection, hashId); - if (result != CMTSuccess) + CMTItem hashItem; + hashItem.data = 0; + hashItem.len = 0; + //-- If a plaintext was provided, hash it. + if (aPlaintext) { - PR_FREEIF(hash); - return NS_ERROR_FAILURE; + CMUint32 hashId; + CMT_HashCreate(controlConnection, nsISignatureVerifier::SHA1, &hashId); + CMT_HASH_Begin(controlConnection, hashId); + CMTStatus result = CMT_HASH_Update(controlConnection, hashId, + (const unsigned char*)aPlaintext, aPlaintextLen); + if (result != CMTSuccess) return NS_ERROR_FAILURE; + + unsigned char* hash = (unsigned char*)PR_MALLOC(nsISignatureVerifier::SHA1_LENGTH); + if (!hash) return NS_ERROR_OUT_OF_MEMORY; + CMUint32 hashLen; + result = CMT_HASH_End(controlConnection, hashId, hash, + &hashLen, nsISignatureVerifier::SHA1_LENGTH); + if (result != CMTSuccess) + { + PR_FREEIF(hash); + return NS_ERROR_FAILURE; + } + NS_ASSERTION(hashLen == nsISignatureVerifier::SHA1_LENGTH, + "PSMComponent: Hash too short."); + CMT_HASH_Destroy(controlConnection, hashId); + hashItem.data = hash; + hashItem.len = hashLen; } + //-- Verify signature - CMTItemStr hashItem; - hashItem.data = hash; - hashItem.len = hashLen; + // We need to call this function even if we're only creating a principal, not + // verifying, because PSM won't give us certificate information unless this + // function has been called. result = CMT_PKCS7VerifyDetachedSignature(controlConnection, contentInfo, 6 /* =Object Signing Cert */, 3 /* =SHA1 algorithm (MD5=2)*/, - (CMUint32)aKeepCert, - &hashItem, (CMInt32*)aVerifyError); - PR_FREEIF(hash); + 1,/* Save Certificate */ + &hashItem, (CMInt32*)aErrorCode); + if (result != CMTSuccess) return NS_ERROR_FAILURE; - //-- Did it verify? + if (aPlaintext && *aErrorCode != 0) return NS_OK; // Verification failed. + + CMUint32 certID; + result = CMT_GetRIDAttribute(controlConnection, contentInfo, + SSM_FID_P7CINFO_SIGNER_CERT, &certID); + if ((result != CMTSuccess) || !certID) return NS_OK; // No signature present - if (*aVerifyError != 0) - *aPrincipal = nsnull; - else - { - //-- Generate a principal from the cert - CMUint32 certID; - result = CMT_GetRIDAttribute(controlConnection, contentInfo, - SSM_FID_P7CINFO_SIGNER_CERT, &certID); - if (result != CMTSuccess) return NS_ERROR_FAILURE; - if (NS_FAILED(CreatePrincipalFromCert(certID, aPrincipal))) - return NS_ERROR_FAILURE; - } - - CMT_PKCS7DestroyContentInfo(controlConnection, contentInfo); - return NS_OK; -} - -NS_IMETHODIMP -nsPSMComponent::CreatePrincipalFromCert(PRUint32 aCertID, nsIPrincipal** aPrincipal) -{ - CMT_CONTROL *controlConnection; - if (NS_FAILED(GetControlConnection( &controlConnection ))) - return NS_ERROR_FAILURE; - - //-- Read cert ID - CMTStatus result; - CMTItem fingerprint; - result = CMT_GetStringAttribute(controlConnection, aCertID, + result = CMT_GetStringAttribute(controlConnection, certID, SSM_FID_CERT_FINGERPRINT, &fingerprint); if (result != CMTSuccess) return NS_ERROR_FAILURE; @@ -960,11 +919,11 @@ nsPSMComponent::CreatePrincipalFromCert(PRUint32 aCertID, nsIPrincipal** aPrinci if (NS_FAILED(rv)) return NS_ERROR_FAILURE; CMTItem common; - result = CMT_GetStringAttribute(controlConnection, aCertID, + result = CMT_GetStringAttribute(controlConnection, certID, SSM_FID_CERT_COMMON_NAME, &common); if (result != CMTSuccess) return NS_ERROR_FAILURE; CMTItem subject; - result = CMT_GetStringAttribute(controlConnection, aCertID, + result = CMT_GetStringAttribute(controlConnection, certID, SSM_FID_CERT_SUBJECT_NAME, &subject); if (result != CMTSuccess) return NS_ERROR_FAILURE; @@ -990,4 +949,3 @@ nsPSMComponent::CreatePrincipalFromCert(PRUint32 aCertID, nsIPrincipal** aPrinci Recycle(commonChar); return rv; } - diff --git a/extensions/psm-glue/src/nsPSMComponent.h b/extensions/psm-glue/src/nsPSMComponent.h index 62f9d9dfa922..0da1f8e272ed 100644 --- a/extensions/psm-glue/src/nsPSMComponent.h +++ b/extensions/psm-glue/src/nsPSMComponent.h @@ -24,6 +24,7 @@ #include "nscore.h" #include "nsIPSMComponent.h" +#include "nsISignatureVerifier.h" #include "nsIStringBundle.h" #include "nsIContentHandler.h" @@ -33,7 +34,9 @@ #define NS_PSMCOMPONENT_CID {0xddcae170, 0x5412, 0x11d3, {0xbb, 0xc8, 0x00, 0x00, 0x86, 0x1d, 0x12, 0x37}} // Implementation of the PSM component interface. -class nsPSMComponent : public nsIPSMComponent, public nsIContentHandler +class nsPSMComponent : public nsIPSMComponent, + public nsIContentHandler, + public nsISignatureVerifier { public: NS_DEFINE_STATIC_CID_ACCESSOR( NS_PSMCOMPONENT_CID ); @@ -44,6 +47,7 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIPSMCOMPONENT NS_DECL_NSICONTENTHANDLER + NS_DECL_NSISIGNATUREVERIFIER static NS_METHOD CreatePSMComponent(nsISupports* aOuter, REFNSIID aIID, void **aResult); diff --git a/modules/libjar/nsIZipReader.idl b/modules/libjar/nsIZipReader.idl index 043c608b124a..db45e2c0b711 100644 --- a/modules/libjar/nsIZipReader.idl +++ b/modules/libjar/nsIZipReader.idl @@ -100,6 +100,13 @@ interface nsIZipReader : nsISupports * be called before getPrincipal. */ void getCertificatePrincipal(in string aEntryName, out nsIPrincipal aPrincipal); + + /** + * Verifies aData against a digital signature stored in the archive. Returns + * a principal if verification succeeds, null otherwise. + */ + nsIPrincipal verifyExternalData(in string aEntryName, in string aData, + in unsigned long aLength); }; //////////////////////////////////////////////////////////////////////////////// diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp index 9c3d4e406492..d1fb2f348949 100644 --- a/modules/libjar/nsJAR.cpp +++ b/modules/libjar/nsJAR.cpp @@ -33,10 +33,6 @@ #include "plbase64.h" #include "nsIConsoleService.h" -#ifndef XP_MAC -#include "nsIPSMComponent.h" -#endif - #ifdef XP_UNIX #include #elif defined (XP_PC) @@ -298,18 +294,11 @@ nsJAR::GetInputStream(const char *aFilename, nsIInputStream **result) NS_IMETHODIMP nsJAR::GetCertificatePrincipal(const char* aFilename, nsIPrincipal** aPrincipal) { -#ifdef XP_MAC - return NS_ERROR_NOT_IMPLEMENTED; -#else //-- Parameter check if (!aPrincipal) return NS_ERROR_NULL_POINTER; *aPrincipal = nsnull; - DumpMetadata("GetPrincipal"); - if (!mParsedManifest) - ParseManifest(); - PRInt16 requestedStatus; if (aFilename) { @@ -323,18 +312,24 @@ nsJAR::GetCertificatePrincipal(const char* aFilename, nsIPrincipal** aPrincipal) } if (!manItem->step2Complete) { - //-- Creating an input stream causes step 2 of verification - nsCOMPtr tempStream; - if (NS_FAILED(CreateInputStream(aFilename, PR_TRUE, getter_AddRefs(tempStream)))) - return NS_ERROR_FAILURE; - NS_ASSERTION(manItem->step2Complete, "Verification step 2 is not complete"); - if (!manItem->step2Complete) - return NS_ERROR_FAILURE; + NS_ASSERTION(manItem->step2Complete, + "nsJAR: Attempt to get principal before verification."); + return NS_ERROR_FAILURE; } requestedStatus = manItem->status; } else // User wants identity of signer w/o verifying any entries + { + if (!mParsedManifest) + { + nsresult rv; + NS_WITH_SERVICE(nsISignatureVerifier, verifier, SIGNATURE_VERIFIER_PROGID, &rv); + if (NS_FAILED(rv)) // No signature verifier available + return NS_ERROR_FAILURE; + ParseManifest(verifier); + } requestedStatus = mGlobalStatus; + } if (requestedStatus != nsIZipReader::VALID) ReportError(aFilename, requestedStatus); @@ -344,7 +339,15 @@ nsJAR::GetCertificatePrincipal(const char* aFilename, nsIPrincipal** aPrincipal) NS_IF_ADDREF(*aPrincipal); } return NS_OK; -#endif +} + +NS_IMETHODIMP +nsJAR::VerifyExternalData(const char* aFilename, const char* aData, PRUint32 aLen, + nsIPrincipal** result) +{ + if (NS_FAILED(VerifyEntry(aFilename, aData, aLen))) + return NS_ERROR_FAILURE; + return GetCertificatePrincipal(aFilename, result); } //---------------------------------------------- @@ -431,11 +434,8 @@ nsJAR::ReadLine(const char** src) #define JAR_SF_HEADER (const char*)"Signature-Version: 1.0" nsresult -nsJAR::ParseManifest() +nsJAR::ParseManifest(nsISignatureVerifier* verifier) { -#ifdef XP_MAC -return NS_OK; -#else //-- Verification Step 1 if (mParsedManifest) return NS_OK; @@ -464,7 +464,7 @@ return NS_OK; if (NS_FAILED(rv)) return rv; //-- Parse it - rv = ParseOneFile(manifestBuffer, JAR_MF); + rv = ParseOneFile(verifier, manifestBuffer, JAR_MF); if (NS_FAILED(rv)) return rv; DumpMetadata("PM Pass 1 End"); @@ -497,23 +497,30 @@ return NS_OK; if (NS_FAILED(rv)) return rv; //-- Verify that the signature file is a valid signature of the SF file - rv = VerifySignature(manifestBuffer, manifestLen, - sigBuffer, sigLen, getter_AddRefs(mPrincipal), &mGlobalStatus); + PRInt32 verifyError; + rv = verifier->VerifySignature(sigBuffer, sigLen, manifestBuffer, manifestLen, + &verifyError, getter_AddRefs(mPrincipal)); if (NS_FAILED(rv)) return rv; - + if (mPrincipal) + mGlobalStatus = nsIZipReader::VALID; + else if (verifyError == nsISignatureVerifier::VERIFY_ERROR_UNKNOWN_CA) + mGlobalStatus = nsIZipReader::INVALID_UNKNOWN_CA; + else + mGlobalStatus = nsIZipReader::INVALID_SIG; + //-- 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); + ParseOneFile(verifier, manifestBuffer, JAR_SF); DumpMetadata("PM Pass 2 End"); return NS_OK; - #endif } nsresult -nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType) +nsJAR::ParseOneFile(nsISignatureVerifier* verifier, + const char* filebuf, PRInt16 aFileType) { //-- Check file header const char* nextLineStart = filebuf; @@ -579,7 +586,7 @@ nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType) else //-- calculate section digest { PRUint32 sectionLength = curPos - sectionStart; - CalculateDigest(sectionStart, sectionLength, + CalculateDigest(verifier, sectionStart, sectionLength, &(curItemMF->calculatedSectionDigest)); //-- Save item in the hashtable nsStringKey itemKey(curItemName); @@ -691,15 +698,17 @@ nsJAR::ParseOneFile(const char* filebuf, PRInt16 aFileType) } //ParseOneFile() nsresult -nsJAR::VerifyEntry(const char* aEntryName, char* aEntryData, +nsJAR::VerifyEntry(const char* aEntryName, const char* aEntryData, PRUint32 aLen) { -#ifndef XP_MAC + nsresult rv; + NS_WITH_SERVICE(nsISignatureVerifier, verifier, SIGNATURE_VERIFIER_PROGID, &rv); + if (NS_FAILED(rv)) return NS_OK; // No verifier available; just continue. + //-- Verification Step 2 // Check that verification is supported and step 1 has been done - if (!mParsedManifest) - ParseManifest(); + ParseManifest(verifier); NS_ASSERTION(mParsedManifest, "Verification step 2 called before step 1 complete"); if (!mParsedManifest) return NS_ERROR_FAILURE; @@ -717,25 +726,25 @@ nsJAR::VerifyEntry(const char* aEntryName, char* aEntryData, else { //-- Calculate and compare digests char* calculatedEntryDigest; - nsresult rv = CalculateDigest(aEntryData, aLen, &calculatedEntryDigest); - if (NS_FAILED(rv)) return rv; + rv = CalculateDigest(verifier, aEntryData, aLen, &calculatedEntryDigest); + if (NS_FAILED(rv)) return NS_ERROR_FAILURE; if (PL_strcmp(manItem->storedEntryDigest, calculatedEntryDigest) != 0) manItem->status = nsIZipReader::INVALID_ENTRY; JAR_NULLFREE(calculatedEntryDigest) JAR_NULLFREE(manItem->storedEntryDigest) } } - - manItem->step2Complete = PR_TRUE; + if (NS_SUCCEEDED(rv)) + manItem->step2Complete = PR_TRUE; DumpMetadata("VerifyEntry end"); -#endif - return NS_OK; + return rv; } void nsJAR::ReportError(const char* aFilename, PRInt16 errorCode) { //-- Generate error message - nsAutoString message; message.AssignWithConversion("Signature Verification Error: the signature on "); + nsAutoString message; + message.AssignWithConversion("Signature Verification Error: the signature on "); if (aFilename) message.AppendWithConversion(aFilename); else @@ -747,27 +756,23 @@ void nsJAR::ReportError(const char* aFilename, PRInt16 errorCode) message.AppendWithConversion("the archive did not contain a valid PKCS7 signature."); break; case nsIZipReader::INVALID_SIG: - message.AppendWithConversion("the digital signature (*.RSA) file is not a valid signature of "); - message.AppendWithConversion("the signature instruction file (*.SF)."); + message.AppendWithConversion("the digital signature (*.RSA) file is not a valid signature of the signature instruction file (*.SF)."); break; case nsIZipReader::INVALID_UNKNOWN_CA: message.AppendWithConversion("the certificate used to sign this file has an unrecognized issuer."); break; case nsIZipReader::INVALID_MANIFEST: - message.AppendWithConversion("the signature instruction file (*.SF) does not contain a valid hash "); - message.AppendWithConversion("of the MANIFEST.MF file."); + message.AppendWithConversion("the signature instruction file (*.SF) does not contain a valid hash of the MANIFEST.MF file."); break; case nsIZipReader::INVALID_ENTRY: - message.AppendWithConversion("the MANIFEST.MF file does not contain a valid hash of the file "); - message.AppendWithConversion("being verified."); + message.AppendWithConversion("the MANIFEST.MF file does not contain a valid hash of the file being verified."); break; default: message.AppendWithConversion("of an unknown problem."); } // Report error in JS console - nsCOMPtr console - (do_GetService("mozilla.consoleservice.1")); + nsCOMPtr console(do_GetService("mozilla.consoleservice.1")); if (console) { PRUnichar* messageUni = message.ToNewUnicode(); @@ -775,7 +780,9 @@ void nsJAR::ReportError(const char* aFilename, PRInt16 errorCode) console->LogStringMessage(messageUni); nsAllocator::Free(messageUni); } +#ifndef DEBUG else // If JS console reporting failed, print to stderr. +#endif { char* messageCstr = message.ToNewCString(); if (!messageCstr) return; @@ -813,77 +820,38 @@ nsJAR::RestoreModTime(nsZipItem *aItem, nsIFile *aExtractedFile) return rv; } -//---------------------------------------------- -// Hashing and verification functions -//---------------------------------------------- - -nsresult nsJAR::CalculateDigest(const char* aInBuf, PRUint32 aLen, - char** digest) +nsresult nsJAR::CalculateDigest(nsISignatureVerifier* verifier, + const char* aInBuf, PRUint32 aLen, + char** digest) { -#ifndef XP_MAC *digest = nsnull; nsresult rv; - NS_WITH_SERVICE(nsIPSMComponent, psmComp, PSM_COMPONENT_PROGID, &rv); - if (NS_FAILED(rv)) return rv; //-- Calculate the digest PRUint32 id; - rv = psmComp->HashBegin(nsIPSMComponent::SHA1, &id); + rv = verifier->HashBegin(nsISignatureVerifier::SHA1, &id); if (NS_FAILED(rv)) return rv; - rv = psmComp->HashUpdate(id, aInBuf, aLen); + rv = verifier->HashUpdate(id, aInBuf, aLen); if (NS_FAILED(rv)) return rv; PRUint32 len; - char* rawDigest = (char*)PR_MALLOC(nsIPSMComponent::SHA1_LENGTH); + unsigned char* rawDigest = (unsigned char*)PR_MALLOC(nsISignatureVerifier::SHA1_LENGTH); if (rawDigest == nsnull) return NS_ERROR_OUT_OF_MEMORY; - rv = psmComp->HashEnd(id, &rawDigest, &len, nsIPSMComponent::SHA1_LENGTH); + rv = verifier->HashEnd(id, &rawDigest, &len, nsISignatureVerifier::SHA1_LENGTH); if (NS_FAILED(rv)) { PR_FREEIF(rawDigest); return rv; } //-- Encode the digest in base64 - *digest = PL_Base64Encode(rawDigest, len, *digest); + *digest = PL_Base64Encode((char*)rawDigest, len, *digest); if (!(*digest)) { PR_FREEIF(rawDigest); return NS_ERROR_OUT_OF_MEMORY; } PR_FREEIF(rawDigest); -#endif return NS_OK; } -nsresult nsJAR::VerifySignature(const char* sfBuf, PRUint32 sfBufLen, - const char* rsaBuf, PRUint32 rsaBufLen, - nsIPrincipal** aPrincipal, PRInt16* status) -{ - nsresult rv = NS_OK; -#ifndef XP_MAC - NS_WITH_SERVICE(nsIPSMComponent, psmComp, PSM_COMPONENT_PROGID, &rv); - if (NS_FAILED(rv)) return rv; - - PRUint32 id; - rv = psmComp->VerifyRSABegin(&id); - if (NS_SUCCEEDED(rv)) - rv = psmComp->VerifyRSAUpdate(id, rsaBuf, rsaBufLen); - PRInt32 psmStatus; - if (NS_SUCCEEDED(rv)) - rv = psmComp->VerifyRSAEnd(id, sfBuf, sfBufLen, PR_TRUE, aPrincipal, &psmStatus); - switch (psmStatus) - { - case nsIPSMComponent::VERIFY_NOSIG: - *status = nsIZipReader::NOT_SIGNED; break; - case nsIPSMComponent::VERIFY_OK: - *status = nsIZipReader::VALID; break; - case nsIPSMComponent::VERIFY_ERROR_UNKNOWN_CA: - *status = nsIZipReader::INVALID_UNKNOWN_CA; break; - default: - *status = nsIZipReader::INVALID_SIG; - } -#endif - return rv; -} - //---------------------------------------------- // Debugging functions //---------------------------------------------- - #if 0 PR_STATIC_CALLBACK(PRBool) PrintManItem(nsHashKey* aKey, void* aData, void* closure) diff --git a/modules/libjar/nsJAR.h b/modules/libjar/nsJAR.h index f9d8681e4865..c37157c4db86 100644 --- a/modules/libjar/nsJAR.h +++ b/modules/libjar/nsJAR.h @@ -50,6 +50,7 @@ #include "nsZipArchive.h" #include "zipfile.h" #include "nsIPrincipal.h" +#include "nsISignatureVerifier.h" class nsIInputStream; @@ -87,23 +88,22 @@ class nsJAR : public nsIZipReader PRInt16 mGlobalStatus; // Global signature verification status //-- Private functions - nsresult ParseManifest(); + nsresult ParseManifest(nsISignatureVerifier* verifier); void ReportError(const char* aFilename, PRInt16 errorCode); nsresult CreateInputStream(const char* aFilename, PRBool verify, nsIInputStream** result); nsresult LoadEntry(const char* aFilename, char** aBuf, PRUint32* aBufLen = nsnull); PRInt32 ReadLine(const char** src); - nsresult ParseOneFile(const char* filebuf, PRInt16 aFileType); - nsresult VerifyEntry(const char* aEntryName, char* aEntryData, + nsresult ParseOneFile(nsISignatureVerifier* verifier, + const char* filebuf, PRInt16 aFileType); + nsresult VerifyEntry(const char* aEntryName, const char* aEntryData, PRUint32 aLen); nsresult RestoreModTime(nsZipItem *aItem, nsIFile *aExtractedFile); - nsresult CalculateDigest(const char* aInBuf, PRUint32 aInBufLen, + nsresult CalculateDigest(nsISignatureVerifier* verifier, + const char* aInBuf, PRUint32 aInBufLen, char** digest); - nsresult VerifySignature(const char* sfBuf, PRUint32 sfBufLen, - const char* rsaBuf, PRUint32 rsaBufLen, - nsIPrincipal** aPrincipal, PRInt16* status); //-- Debugging void DumpMetadata(const char* aMessage);