forked from mirrors/gecko-dev
Bug 1272794 - Clean up Digest class API r=keeler,necko-reviewers,valentin
Differential Revision: https://phabricator.services.mozilla.com/D40983
This commit is contained in:
parent
96f7c5cf5c
commit
21cf959be5
9 changed files with 174 additions and 136 deletions
|
|
@ -102,8 +102,7 @@ BackgroundFileSaver::BackgroundFileSaver()
|
||||||
mSha256Enabled(false),
|
mSha256Enabled(false),
|
||||||
mSignatureInfoEnabled(false),
|
mSignatureInfoEnabled(false),
|
||||||
mActualTarget(nullptr),
|
mActualTarget(nullptr),
|
||||||
mActualTargetKeepPartial(false),
|
mActualTargetKeepPartial(false) {
|
||||||
mDigestContext(nullptr) {
|
|
||||||
LOG(("Created BackgroundFileSaver [this = %p]", this));
|
LOG(("Created BackgroundFileSaver [this = %p]", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -518,16 +517,15 @@ nsresult BackgroundFileSaver::ProcessStateChange() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the digest context if requested and NSS hasn't been shut down.
|
// Create the digest if requested and NSS hasn't been shut down.
|
||||||
if (sha256Enabled && !mDigestContext) {
|
if (sha256Enabled && mDigest.isNothing()) {
|
||||||
mDigestContext =
|
mDigest.emplace(Digest());
|
||||||
UniquePK11Context(PK11_CreateDigestContext(SEC_OID_SHA256));
|
mDigest->Begin(SEC_OID_SHA256);
|
||||||
NS_ENSURE_TRUE(mDigestContext, NS_ERROR_OUT_OF_MEMORY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we are requested to append to an existing file, we should read the
|
// When we are requested to append to an existing file, we should read the
|
||||||
// existing data and ensure we include it as part of the final hash.
|
// existing data and ensure we include it as part of the final hash.
|
||||||
if (mDigestContext && append && !isContinuation) {
|
if (mDigest.isSome() && append && !isContinuation) {
|
||||||
nsCOMPtr<nsIInputStream> inputStream;
|
nsCOMPtr<nsIInputStream> inputStream;
|
||||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), mActualTarget,
|
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), mActualTarget,
|
||||||
PR_RDONLY | nsIFile::OS_READAHEAD);
|
PR_RDONLY | nsIFile::OS_READAHEAD);
|
||||||
|
|
@ -545,9 +543,8 @@ nsresult BackgroundFileSaver::ProcessStateChange() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = MapSECStatus(
|
nsresult rv =
|
||||||
PK11_DigestOp(mDigestContext.get(),
|
mDigest->Update(BitwiseCast<unsigned char*, char*>(buffer), count);
|
||||||
BitwiseCast<unsigned char*, char*>(buffer), count));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -582,14 +579,14 @@ nsresult BackgroundFileSaver::ProcessStateChange() {
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
outputStream = bufferedStream;
|
outputStream = bufferedStream;
|
||||||
|
|
||||||
// Wrap the output stream so that it feeds the digest context if needed.
|
// Wrap the output stream so that it feeds the digest if needed.
|
||||||
if (mDigestContext) {
|
if (mDigest.isSome()) {
|
||||||
// Constructing the DigestOutputStream cannot fail. Passing mDigestContext
|
// Constructing the DigestOutputStream cannot fail. Passing mDigest
|
||||||
// to DigestOutputStream is safe, because BackgroundFileSaver always
|
// to DigestOutputStream is safe, because BackgroundFileSaver always
|
||||||
// outlives the outputStream. BackgroundFileSaver is reference-counted
|
// outlives the outputStream. BackgroundFileSaver is reference-counted
|
||||||
// before the call to AsyncCopy, and mDigestContext is never destroyed
|
// before the call to AsyncCopy, and mDigest is never destroyed
|
||||||
// before AsyncCopyCallback.
|
// before AsyncCopyCallback.
|
||||||
outputStream = new DigestOutputStream(outputStream, mDigestContext.get());
|
outputStream = new DigestOutputStream(outputStream, mDigest.ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start copying our input to the target file. No errors can be raised past
|
// Start copying our input to the target file. No errors can be raised past
|
||||||
|
|
@ -675,13 +672,13 @@ bool BackgroundFileSaver::CheckCompletion() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish computing the hash
|
// Finish computing the hash
|
||||||
if (!failed && mDigestContext) {
|
if (!failed && mDigest.isSome()) {
|
||||||
Digest d;
|
nsTArray<uint8_t> outArray;
|
||||||
rv = d.End(SEC_OID_SHA256, mDigestContext);
|
rv = mDigest->End(outArray);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
MutexAutoLock lock(mLock);
|
MutexAutoLock lock(mLock);
|
||||||
mSha256 = nsDependentCSubstring(
|
mSha256 = nsDependentCSubstring(
|
||||||
BitwiseCast<char*, unsigned char*>(d.get().data), d.get().len);
|
BitwiseCast<char*, uint8_t*>(outArray.Elements()), outArray.Length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1077,9 +1074,8 @@ nsresult BackgroundFileSaverStreamListener::NotifySuspendOrResume() {
|
||||||
NS_IMPL_ISUPPORTS(DigestOutputStream, nsIOutputStream)
|
NS_IMPL_ISUPPORTS(DigestOutputStream, nsIOutputStream)
|
||||||
|
|
||||||
DigestOutputStream::DigestOutputStream(nsIOutputStream* aStream,
|
DigestOutputStream::DigestOutputStream(nsIOutputStream* aStream,
|
||||||
PK11Context* aContext)
|
Digest& aDigest)
|
||||||
: mOutputStream(aStream), mDigestContext(aContext) {
|
: mOutputStream(aStream), mDigest(aDigest) {
|
||||||
MOZ_ASSERT(mDigestContext, "Can't have null digest context");
|
|
||||||
MOZ_ASSERT(mOutputStream, "Can't have null output stream");
|
MOZ_ASSERT(mOutputStream, "Can't have null output stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1091,9 +1087,8 @@ DigestOutputStream::Flush() { return mOutputStream->Flush(); }
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
DigestOutputStream::Write(const char* aBuf, uint32_t aCount, uint32_t* retval) {
|
DigestOutputStream::Write(const char* aBuf, uint32_t aCount, uint32_t* retval) {
|
||||||
nsresult rv = MapSECStatus(PK11_DigestOp(
|
nsresult rv = mDigest.Update(
|
||||||
mDigestContext, BitwiseCast<const unsigned char*, const char*>(aBuf),
|
BitwiseCast<const unsigned char*, const char*>(aBuf), aCount);
|
||||||
aCount));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return mOutputStream->Write(aBuf, aCount, retval);
|
return mOutputStream->Write(aBuf, aCount, retval);
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ class BackgroundFileSaver : public nsIBackgroundFileSaver {
|
||||||
* Used to calculate the file hash. This keeps state across file renames and
|
* Used to calculate the file hash. This keeps state across file renames and
|
||||||
* is lazily initialized in ProcessStateChange.
|
* is lazily initialized in ProcessStateChange.
|
||||||
*/
|
*/
|
||||||
UniquePK11Context mDigestContext;
|
Maybe<Digest> mDigest;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//// Private methods
|
//// Private methods
|
||||||
|
|
@ -376,15 +376,15 @@ class DigestOutputStream : public nsIOutputStream {
|
||||||
NS_DECL_THREADSAFE_ISUPPORTS
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
NS_DECL_NSIOUTPUTSTREAM
|
NS_DECL_NSIOUTPUTSTREAM
|
||||||
// Constructor. Neither parameter may be null. The caller owns both.
|
// Constructor. Neither parameter may be null. The caller owns both.
|
||||||
DigestOutputStream(nsIOutputStream* outputStream, PK11Context* aContext);
|
DigestOutputStream(nsIOutputStream* aStream, Digest& aDigest);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~DigestOutputStream() = default;
|
virtual ~DigestOutputStream() = default;
|
||||||
|
|
||||||
// Calls to write are passed to this stream.
|
// Calls to write are passed to this stream.
|
||||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||||
// Digest context used to compute the hash, owned by the caller.
|
// Digest used to compute the hash, owned by the caller.
|
||||||
PK11Context* mDigestContext;
|
Digest& mDigest;
|
||||||
|
|
||||||
// Don't accidentally copy construct.
|
// Don't accidentally copy construct.
|
||||||
DigestOutputStream(const DigestOutputStream& d) = delete;
|
DigestOutputStream(const DigestOutputStream& d) = delete;
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,10 @@ struct DigestWithAlgorithm {
|
||||||
};
|
};
|
||||||
|
|
||||||
// The digest must have a lifetime greater than or equal to the returned string.
|
// The digest must have a lifetime greater than or equal to the returned string.
|
||||||
inline nsDependentCSubstring DigestToDependentString(const Digest& digest) {
|
inline nsDependentCSubstring DigestToDependentString(
|
||||||
return nsDependentCSubstring(
|
nsTArray<uint8_t>& digest) {
|
||||||
BitwiseCast<char*, unsigned char*>(digest.get().data), digest.get().len);
|
return nsDependentCSubstring(BitwiseCast<char*, uint8_t*>(digest.Elements()),
|
||||||
|
digest.Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads a maximum of 8MB from a stream into the supplied buffer.
|
// Reads a maximum of 8MB from a stream into the supplied buffer.
|
||||||
|
|
@ -142,7 +143,7 @@ nsresult FindAndLoadOneEntry(
|
||||||
/*out*/ nsACString& filename,
|
/*out*/ nsACString& filename,
|
||||||
/*out*/ SECItem& buf,
|
/*out*/ SECItem& buf,
|
||||||
/*optional, in*/ SECOidTag digestAlgorithm = SEC_OID_SHA1,
|
/*optional, in*/ SECOidTag digestAlgorithm = SEC_OID_SHA1,
|
||||||
/*optional, out*/ Digest* bufDigest = nullptr) {
|
/*optional, out*/ nsTArray<uint8_t>* bufDigest = nullptr) {
|
||||||
nsCOMPtr<nsIUTF8StringEnumerator> files;
|
nsCOMPtr<nsIUTF8StringEnumerator> files;
|
||||||
nsresult rv = zip->FindEntries(searchPattern, getter_AddRefs(files));
|
nsresult rv = zip->FindEntries(searchPattern, getter_AddRefs(files));
|
||||||
if (NS_FAILED(rv) || !files) {
|
if (NS_FAILED(rv) || !files) {
|
||||||
|
|
@ -176,7 +177,8 @@ nsresult FindAndLoadOneEntry(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufDigest) {
|
if (bufDigest) {
|
||||||
rv = bufDigest->DigestBuf(digestAlgorithm, buf.data, buf.len - 1);
|
rv = Digest::DigestBuf(digestAlgorithm,
|
||||||
|
Span<uint8_t>{buf.data, buf.len - 1}, *bufDigest);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,13 +212,9 @@ nsresult VerifyStreamContentDigest(
|
||||||
return NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE;
|
return NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
UniquePK11Context digestContext(
|
Digest digest;
|
||||||
PK11_CreateDigestContext(digestFromManifest.mAlgorithm));
|
|
||||||
if (!digestContext) {
|
|
||||||
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = MapSECStatus(PK11_DigestBegin(digestContext.get()));
|
rv = digest.Begin(digestFromManifest.mAlgorithm);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
uint64_t totalBytesRead = 0;
|
uint64_t totalBytesRead = 0;
|
||||||
|
|
@ -235,7 +233,7 @@ nsresult VerifyStreamContentDigest(
|
||||||
return NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE;
|
return NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = MapSECStatus(PK11_DigestOp(digestContext.get(), buf.data, bytesRead));
|
rv = digest.Update(buf.data, bytesRead);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,11 +244,11 @@ nsresult VerifyStreamContentDigest(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that the digests match.
|
// Verify that the digests match.
|
||||||
Digest digest;
|
nsTArray<uint8_t> outArray;
|
||||||
rv = digest.End(digestFromManifest.mAlgorithm, digestContext);
|
rv = digest.End(outArray);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsDependentCSubstring digestStr(DigestToDependentString(digest));
|
nsDependentCSubstring digestStr(DigestToDependentString(outArray));
|
||||||
if (!digestStr.Equals(digestFromManifest.mDigest)) {
|
if (!digestStr.Equals(digestFromManifest.mDigest)) {
|
||||||
return NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY;
|
return NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY;
|
||||||
}
|
}
|
||||||
|
|
@ -749,13 +747,13 @@ Span<const uint8_t> GetPKCS7SignerCert(
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer,
|
nsresult VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer,
|
||||||
const SECItem& detachedSHA1Digest,
|
nsTArray<uint8_t>& detachedSHA1Digest,
|
||||||
const SECItem& detachedSHA256Digest,
|
nsTArray<uint8_t>& detachedSHA256Digest,
|
||||||
/*out*/ SECOidTag& digestAlgorithm,
|
/*out*/ SECOidTag& digestAlgorithm,
|
||||||
/*out*/ nsTArray<uint8_t>& signerCert) {
|
/*out*/ nsTArray<uint8_t>& signerCert) {
|
||||||
if (NS_WARN_IF(!buffer.data || buffer.len == 0 || !detachedSHA1Digest.data ||
|
if (NS_WARN_IF(!buffer.data || buffer.len == 0 ||
|
||||||
detachedSHA1Digest.len == 0 || !detachedSHA256Digest.data ||
|
detachedSHA1Digest.Length() == 0 ||
|
||||||
detachedSHA256Digest.len == 0)) {
|
detachedSHA256Digest.Length() == 0)) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -799,17 +797,21 @@ nsresult VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer,
|
||||||
|
|
||||||
NSSCMSSignerInfo* signerInfo =
|
NSSCMSSignerInfo* signerInfo =
|
||||||
GetSignerInfoForDigestAlgorithm(signedData, SEC_OID_SHA256);
|
GetSignerInfoForDigestAlgorithm(signedData, SEC_OID_SHA256);
|
||||||
const SECItem* detachedDigest = &detachedSHA256Digest;
|
nsTArray<uint8_t>* tmpDetachedDigest = &detachedSHA256Digest;
|
||||||
digestAlgorithm = SEC_OID_SHA256;
|
digestAlgorithm = SEC_OID_SHA256;
|
||||||
if (!signerInfo) {
|
if (!signerInfo) {
|
||||||
signerInfo = GetSignerInfoForDigestAlgorithm(signedData, SEC_OID_SHA1);
|
signerInfo = GetSignerInfoForDigestAlgorithm(signedData, SEC_OID_SHA1);
|
||||||
if (!signerInfo) {
|
if (!signerInfo) {
|
||||||
return NS_ERROR_CMS_VERIFY_NOT_SIGNED;
|
return NS_ERROR_CMS_VERIFY_NOT_SIGNED;
|
||||||
}
|
}
|
||||||
detachedDigest = &detachedSHA1Digest;
|
tmpDetachedDigest = &detachedSHA1Digest;
|
||||||
digestAlgorithm = SEC_OID_SHA1;
|
digestAlgorithm = SEC_OID_SHA1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SECItem detachedDigest = {
|
||||||
|
siBuffer, tmpDetachedDigest->Elements(),
|
||||||
|
static_cast<unsigned int>(tmpDetachedDigest->Length())};
|
||||||
|
|
||||||
// Get the certificate that issued the PKCS7 signature.
|
// Get the certificate that issued the PKCS7 signature.
|
||||||
Span<const uint8_t> signerCertSpan =
|
Span<const uint8_t> signerCertSpan =
|
||||||
GetPKCS7SignerCert(signerInfo, collectedCerts);
|
GetPKCS7SignerCert(signerInfo, collectedCerts);
|
||||||
|
|
@ -853,7 +855,7 @@ nsresult VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer,
|
||||||
return mozilla::psm::GetXPCOMFromNSSError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
|
return mozilla::psm::GetXPCOMFromNSSError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
|
||||||
}
|
}
|
||||||
return MapSECStatus(NSS_CMSSignerInfo_Verify(
|
return MapSECStatus(NSS_CMSSignerInfo_Verify(
|
||||||
signerInfo, const_cast<SECItem*>(detachedDigest), &pkcs7DataOid));
|
signerInfo, const_cast<SECItem*>(&detachedDigest), &pkcs7DataOid));
|
||||||
}
|
}
|
||||||
|
|
||||||
class CoseVerificationContext {
|
class CoseVerificationContext {
|
||||||
|
|
@ -1187,15 +1189,16 @@ nsresult VerifyPK7Signature(
|
||||||
|
|
||||||
// Calculate both the SHA-1 and SHA-256 hashes of the signature file - we
|
// Calculate both the SHA-1 and SHA-256 hashes of the signature file - we
|
||||||
// don't know what algorithm the PKCS#7 signature used.
|
// don't know what algorithm the PKCS#7 signature used.
|
||||||
Digest sfCalculatedSHA1Digest;
|
nsTArray<uint8_t> sfCalculatedSHA1Digest;
|
||||||
rv = sfCalculatedSHA1Digest.DigestBuf(SEC_OID_SHA1, sfBuffer.data,
|
rv = Digest::DigestBuf(SEC_OID_SHA1, sfBuffer.data, sfBuffer.len - 1,
|
||||||
sfBuffer.len - 1);
|
sfCalculatedSHA1Digest);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
Digest sfCalculatedSHA256Digest;
|
|
||||||
rv = sfCalculatedSHA256Digest.DigestBuf(SEC_OID_SHA256, sfBuffer.data,
|
nsTArray<uint8_t> sfCalculatedSHA256Digest;
|
||||||
sfBuffer.len - 1);
|
rv = Digest::DigestBuf(SEC_OID_SHA256, sfBuffer.data, sfBuffer.len - 1,
|
||||||
|
sfCalculatedSHA256Digest);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
@ -1204,9 +1207,8 @@ nsresult VerifyPK7Signature(
|
||||||
// If we get here, the signature has to verify even if PKCS#7 is not required.
|
// If we get here, the signature has to verify even if PKCS#7 is not required.
|
||||||
sigBuffer.type = siBuffer;
|
sigBuffer.type = siBuffer;
|
||||||
SECOidTag digestToUse;
|
SECOidTag digestToUse;
|
||||||
rv =
|
rv = VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedSHA1Digest,
|
||||||
VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedSHA1Digest.get(),
|
sfCalculatedSHA256Digest, digestToUse, aSignerCert);
|
||||||
sfCalculatedSHA256Digest.get(), digestToUse, aSignerCert);
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
@ -1225,17 +1227,18 @@ nsresult VerifyPK7Signature(
|
||||||
|
|
||||||
// Read PK7 manifest (MF) file.
|
// Read PK7 manifest (MF) file.
|
||||||
ScopedAutoSECItem manifestBuffer;
|
ScopedAutoSECItem manifestBuffer;
|
||||||
Digest mfCalculatedDigest;
|
nsTArray<uint8_t> digestArray;
|
||||||
nsAutoCString mfFilename;
|
nsAutoCString mfFilename;
|
||||||
rv = FindAndLoadOneEntry(aZip, nsLiteralCString(JAR_MF_SEARCH_STRING),
|
rv = FindAndLoadOneEntry(aZip, nsLiteralCString(JAR_MF_SEARCH_STRING),
|
||||||
mfFilename, manifestBuffer, digestToUse,
|
mfFilename, manifestBuffer, digestToUse,
|
||||||
&mfCalculatedDigest);
|
&digestArray);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsDependentCSubstring calculatedDigest(
|
nsDependentCSubstring calculatedDigest(
|
||||||
DigestToDependentString(mfCalculatedDigest));
|
BitwiseCast<char*, uint8_t*>(digestArray.Elements()),
|
||||||
|
digestArray.Length());
|
||||||
if (!mfDigest.Equals(calculatedDigest)) {
|
if (!mfDigest.Equals(calculatedDigest)) {
|
||||||
return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
|
return NS_ERROR_SIGNED_JAR_MANIFEST_INVALID;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,15 +36,16 @@ static nsresult GetBase64HashSPKI(const BackCert& cert,
|
||||||
Input derPublicKey = cert.GetSubjectPublicKeyInfo();
|
Input derPublicKey = cert.GetSubjectPublicKeyInfo();
|
||||||
|
|
||||||
hashSPKIDigest.Truncate();
|
hashSPKIDigest.Truncate();
|
||||||
Digest digest;
|
nsTArray<uint8_t> digestArray;
|
||||||
nsresult nsrv = digest.DigestBuf(SEC_OID_SHA256, derPublicKey.UnsafeGetData(),
|
nsresult nsrv =
|
||||||
derPublicKey.GetLength());
|
Digest::DigestBuf(SEC_OID_SHA256, derPublicKey.UnsafeGetData(),
|
||||||
|
derPublicKey.GetLength(), digestArray);
|
||||||
if (NS_FAILED(nsrv)) {
|
if (NS_FAILED(nsrv)) {
|
||||||
return nsrv;
|
return nsrv;
|
||||||
}
|
}
|
||||||
return Base64Encode(nsDependentCSubstring(
|
return Base64Encode(nsDependentCSubstring(
|
||||||
BitwiseCast<char*, unsigned char*>(digest.get().data),
|
BitwiseCast<char*, uint8_t*>(digestArray.Elements()),
|
||||||
digest.get().len),
|
digestArray.Length()),
|
||||||
hashSPKIDigest);
|
hashSPKIDigest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,10 @@ class BinaryHashSearchArrayComparator {
|
||||||
// storage (Enterprise Root).
|
// storage (Enterprise Root).
|
||||||
// See also the constants in RootCertificateTelemetryUtils.h.
|
// See also the constants in RootCertificateTelemetryUtils.h.
|
||||||
int32_t RootCABinNumber(Span<const uint8_t> cert) {
|
int32_t RootCABinNumber(Span<const uint8_t> cert) {
|
||||||
Digest digest;
|
nsTArray<uint8_t> digestArray;
|
||||||
|
|
||||||
// Compute SHA256 hash of the certificate
|
// Compute SHA256 hash of the certificate
|
||||||
nsresult rv = digest.DigestBuf(SEC_OID_SHA256, cert.data(), cert.size());
|
nsresult rv = Digest::DigestBuf(SEC_OID_SHA256, cert, digestArray);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return ROOT_CERTIFICATE_HASH_FAILURE;
|
return ROOT_CERTIFICATE_HASH_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -58,16 +58,15 @@ int32_t RootCABinNumber(Span<const uint8_t> cert) {
|
||||||
// Compare against list of stored hashes
|
// Compare against list of stored hashes
|
||||||
size_t idx;
|
size_t idx;
|
||||||
|
|
||||||
MOZ_LOG(
|
MOZ_LOG(gPublicKeyPinningTelemetryLog, LogLevel::Debug,
|
||||||
gPublicKeyPinningTelemetryLog, LogLevel::Debug,
|
("pkpinTelem: First bytes %02x %02x %02x %02x\n",
|
||||||
("pkpinTelem: First bytes %02x %02x %02x %02x\n", digest.get().data[0],
|
digestArray.ElementAt(0), digestArray.ElementAt(1),
|
||||||
digest.get().data[1], digest.get().data[2], digest.get().data[3]));
|
digestArray.ElementAt(2), digestArray.ElementAt(3)));
|
||||||
|
|
||||||
if (mozilla::BinarySearchIf(
|
if (mozilla::BinarySearchIf(ROOT_TABLE, 0, ArrayLength(ROOT_TABLE),
|
||||||
ROOT_TABLE, 0, ArrayLength(ROOT_TABLE),
|
BinaryHashSearchArrayComparator(
|
||||||
BinaryHashSearchArrayComparator(
|
digestArray.Elements(), digestArray.Length()),
|
||||||
static_cast<uint8_t*>(digest.get().data), digest.get().len),
|
&idx)) {
|
||||||
&idx)) {
|
|
||||||
MOZ_LOG(gPublicKeyPinningTelemetryLog, LogLevel::Debug,
|
MOZ_LOG(gPublicKeyPinningTelemetryLog, LogLevel::Debug,
|
||||||
("pkpinTelem: Telemetry index was %zu, bin is %d\n", idx,
|
("pkpinTelem: Telemetry index was %zu, bin is %d\n", idx,
|
||||||
ROOT_TABLE[idx].binNumber));
|
ROOT_TABLE[idx].binNumber));
|
||||||
|
|
|
||||||
|
|
@ -86,57 +86,96 @@ MOZ_TYPE_SPECIFIC_UNIQUE_PTR_TEMPLATE(UniquePK11Context, PK11Context,
|
||||||
* Typical usage, for digesting a buffer in memory:
|
* Typical usage, for digesting a buffer in memory:
|
||||||
*
|
*
|
||||||
* nsCOMPtr<nsISupports> nssDummy = do_GetService("@mozilla.org/psm;1", &rv);
|
* nsCOMPtr<nsISupports> nssDummy = do_GetService("@mozilla.org/psm;1", &rv);
|
||||||
* Digest digest;
|
* nsTArray<uint8_t> digestArray;
|
||||||
* nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mybuffer, myBufferLen);
|
* nsresult rv = Digest::DigestBuf(SEC_OID_SHA256, mybuffer, myBufferLen,
|
||||||
|
* digestArray);
|
||||||
* NS_ENSURE_SUCCESS(rv, rv);
|
* NS_ENSURE_SUCCESS(rv, rv);
|
||||||
* rv = MapSECStatus(SomeNSSFunction(..., digest.get(), ...));
|
|
||||||
*
|
*
|
||||||
* Less typical usage, for digesting while doing streaming I/O and similar:
|
* Less typical usage, for digesting while doing streaming I/O and similar:
|
||||||
*
|
*
|
||||||
* Digest digest;
|
* Digest digest;
|
||||||
* UniquePK11Context digestContext(PK11_CreateDigestContext(SEC_OID_SHA256));
|
* nsresult rv = digest.Begin(SEC_OID_SHA256);
|
||||||
* NS_ENSURE_TRUE(digestContext, NS_ERROR_OUT_OF_MEMORY);
|
|
||||||
* rv = MapSECStatus(PK11_DigestBegin(digestContext.get()));
|
|
||||||
* NS_ENSURE_SUCCESS(rv, rv);
|
* NS_ENSURE_SUCCESS(rv, rv);
|
||||||
* for (...) {
|
* for (...) {
|
||||||
* rv = MapSECStatus(PK11_DigestOp(digestContext.get(), ...));
|
* rv = digest.Update(buf, len);
|
||||||
* NS_ENSURE_SUCCESS(rv, rv);
|
* NS_ENSURE_SUCCESS(rv, rv);
|
||||||
* }
|
* }
|
||||||
* rv = digest.End(SEC_OID_SHA256, digestContext);
|
* nsTArray<uint8_t> digestArray;
|
||||||
|
* rv = digest.End(digestArray);
|
||||||
* NS_ENSURE_SUCCESS(rv, rv)
|
* NS_ENSURE_SUCCESS(rv, rv)
|
||||||
*/
|
*/
|
||||||
class Digest {
|
class Digest {
|
||||||
public:
|
public:
|
||||||
Digest() : mItemBuf() {
|
explicit Digest() : mLen(0), mDigestContext(nullptr) {}
|
||||||
mItem.type = siBuffer;
|
|
||||||
mItem.data = mItemBuf;
|
static nsresult DigestBuf(SECOidTag hashAlg, Span<const uint8_t> buf,
|
||||||
mItem.len = 0;
|
/*out*/ nsTArray<uint8_t>& out) {
|
||||||
|
return Digest::DigestBuf(hashAlg, buf.Elements(), buf.Length(), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult DigestBuf(SECOidTag hashAlg, const uint8_t* buf, uint32_t len) {
|
static nsresult DigestBuf(SECOidTag hashAlg, const uint8_t* buf, uint32_t len,
|
||||||
if (len > static_cast<uint32_t>(std::numeric_limits<int32_t>::max())) {
|
/*out*/ nsTArray<uint8_t>& out) {
|
||||||
|
Digest digest;
|
||||||
|
|
||||||
|
nsresult rv = digest.Begin(hashAlg);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = digest.Update(buf, len);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = digest.End(out);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Begin(SECOidTag hashAlg) {
|
||||||
|
if (hashAlg != SEC_OID_SHA1 && hashAlg != SEC_OID_SHA256) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDigestContext = UniquePK11Context(PK11_CreateDigestContext(hashAlg));
|
||||||
|
if (!mDigestContext) {
|
||||||
|
return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
nsresult rv = SetLength(hashAlg);
|
nsresult rv = SetLength(hashAlg);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
return MapSECStatus(
|
return MapSECStatus(PK11_DigestBegin(mDigestContext.get()));
|
||||||
PK11_HashBuf(hashAlg, mItem.data, buf, static_cast<int32_t>(len)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult End(SECOidTag hashAlg, UniquePK11Context& context) {
|
nsresult Update(Span<const uint8_t> in) {
|
||||||
nsresult rv = SetLength(hashAlg);
|
return Update(in.Elements(), in.Length());
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
}
|
||||||
|
|
||||||
|
nsresult Update(const unsigned char* buf, const uint32_t len) {
|
||||||
|
if (!mDigestContext) {
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
return MapSECStatus(PK11_DigestOp(mDigestContext.get(), buf, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult End(/*out*/ nsTArray<uint8_t>& out) {
|
||||||
|
if (!mDigestContext) {
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
out.SetLength(mLen);
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
rv = MapSECStatus(
|
nsresult rv = MapSECStatus(
|
||||||
PK11_DigestFinal(context.get(), mItem.data, &len, mItem.len));
|
PK11_DigestFinal(mDigestContext.get(), out.Elements(), &len, mLen));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
context = nullptr;
|
mDigestContext = nullptr;
|
||||||
NS_ENSURE_TRUE(len == mItem.len, NS_ERROR_UNEXPECTED);
|
NS_ENSURE_TRUE(len == mLen, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SECItem& get() const { return mItem; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsresult SetLength(SECOidTag hashType) {
|
nsresult SetLength(SECOidTag hashType) {
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
@ -147,16 +186,10 @@ class Digest {
|
||||||
#endif
|
#endif
|
||||||
switch (hashType) {
|
switch (hashType) {
|
||||||
case SEC_OID_SHA1:
|
case SEC_OID_SHA1:
|
||||||
mItem.len = SHA1_LENGTH;
|
mLen = SHA1_LENGTH;
|
||||||
break;
|
break;
|
||||||
case SEC_OID_SHA256:
|
case SEC_OID_SHA256:
|
||||||
mItem.len = SHA256_LENGTH;
|
mLen = SHA256_LENGTH;
|
||||||
break;
|
|
||||||
case SEC_OID_SHA384:
|
|
||||||
mItem.len = SHA384_LENGTH;
|
|
||||||
break;
|
|
||||||
case SEC_OID_SHA512:
|
|
||||||
mItem.len = SHA512_LENGTH;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
|
@ -168,8 +201,8 @@ class Digest {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t mItemBuf[HASH_LENGTH_MAX];
|
uint8_t mLen;
|
||||||
SECItem mItem;
|
UniquePK11Context mDigestContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
|
||||||
|
|
@ -101,12 +101,15 @@ void LossyUTF8ToUTF16(const char* str, uint32_t len,
|
||||||
|
|
||||||
nsresult GetCertFingerprintByOidTag(CERTCertificate* nsscert, SECOidTag aOidTag,
|
nsresult GetCertFingerprintByOidTag(CERTCertificate* nsscert, SECOidTag aOidTag,
|
||||||
nsCString& fp) {
|
nsCString& fp) {
|
||||||
Digest digest;
|
nsTArray<uint8_t> digestArray;
|
||||||
nsresult rv =
|
nsresult rv = Digest::DigestBuf(aOidTag, nsscert->derCert.data,
|
||||||
digest.DigestBuf(aOidTag, nsscert->derCert.data, nsscert->derCert.len);
|
nsscert->derCert.len, digestArray);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
UniquePORTString tmpstr(CERT_Hexify(const_cast<SECItem*>(&digest.get()), 1));
|
SECItem digestItem = {siBuffer, digestArray.Elements(),
|
||||||
|
static_cast<unsigned int>(digestArray.Length())};
|
||||||
|
|
||||||
|
UniquePORTString tmpstr(CERT_Hexify(&digestItem, 1));
|
||||||
NS_ENSURE_TRUE(tmpstr, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(tmpstr, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
fp.Assign(tmpstr.get());
|
fp.Assign(tmpstr.get());
|
||||||
|
|
|
||||||
|
|
@ -581,15 +581,17 @@ nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber) {
|
||||||
nsresult nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint,
|
nsresult nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint,
|
||||||
SECOidTag aHashAlg) {
|
SECOidTag aHashAlg) {
|
||||||
aFingerprint.Truncate();
|
aFingerprint.Truncate();
|
||||||
Digest digest;
|
nsTArray<uint8_t> digestArray;
|
||||||
nsresult rv =
|
nsresult rv = Digest::DigestBuf(aHashAlg, mCert->derCert.data,
|
||||||
digest.DigestBuf(aHashAlg, mCert->derCert.data, mCert->derCert.len);
|
mCert->derCert.len, digestArray);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
SECItem digestItem = {siBuffer, digestArray.Elements(),
|
||||||
|
static_cast<unsigned int>(digestArray.Length())};
|
||||||
|
|
||||||
UniquePORTString fpStr(CERT_Hexify(const_cast<SECItem*>(&digest.get()),
|
UniquePORTString fpStr(
|
||||||
true /* use colon delimiters */));
|
CERT_Hexify(&digestItem, true /* use colon delimiters */));
|
||||||
if (!fpStr) {
|
if (!fpStr) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -647,15 +649,15 @@ nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
pkix::Input derPublicKey = cert.GetSubjectPublicKeyInfo();
|
pkix::Input derPublicKey = cert.GetSubjectPublicKeyInfo();
|
||||||
Digest digest;
|
nsTArray<uint8_t> digestArray;
|
||||||
nsresult rv = digest.DigestBuf(SEC_OID_SHA256, derPublicKey.UnsafeGetData(),
|
nsresult rv = Digest::DigestBuf(SEC_OID_SHA256, derPublicKey.UnsafeGetData(),
|
||||||
derPublicKey.GetLength());
|
derPublicKey.GetLength(), digestArray);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
rv = Base64Encode(nsDependentCSubstring(
|
rv = Base64Encode(nsDependentCSubstring(
|
||||||
BitwiseCast<char*, unsigned char*>(digest.get().data),
|
BitwiseCast<char*, uint8_t*>(digestArray.Elements()),
|
||||||
digest.get().len),
|
digestArray.Length()),
|
||||||
aSha256SPKIDigest);
|
aSha256SPKIDigest);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
|
|
|
||||||
|
|
@ -2563,18 +2563,20 @@ nsNSSComponent::IsCertContentSigningRoot(const nsTArray<uint8_t>& cert,
|
||||||
bool* result) {
|
bool* result) {
|
||||||
NS_ENSURE_ARG_POINTER(result);
|
NS_ENSURE_ARG_POINTER(result);
|
||||||
*result = false;
|
*result = false;
|
||||||
|
|
||||||
if (cert.Length() > std::numeric_limits<uint32_t>::max()) {
|
if (cert.Length() > std::numeric_limits<uint32_t>::max()) {
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
Digest digest;
|
nsTArray<uint8_t> digestArray;
|
||||||
nsresult rv =
|
nsresult rv = Digest::DigestBuf(SEC_OID_SHA256, cert.Elements(),
|
||||||
digest.DigestBuf(SEC_OID_SHA256, cert.Elements(), cert.Length());
|
cert.Length(), digestArray);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
UniquePORTString fingerprintCString(CERT_Hexify(
|
SECItem digestItem = {siBuffer, digestArray.Elements(),
|
||||||
const_cast<SECItem*>(&digest.get()), true /* use colon delimiters */));
|
static_cast<unsigned int>(digestArray.Length())};
|
||||||
|
|
||||||
|
UniquePORTString fingerprintCString(
|
||||||
|
CERT_Hexify(&digestItem, true /* use colon delimiters */));
|
||||||
if (!fingerprintCString) {
|
if (!fingerprintCString) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue