summaryrefslogtreecommitdiffstats
path: root/dom/security/SRICheck.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /dom/security/SRICheck.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/security/SRICheck.cpp')
-rw-r--r--dom/security/SRICheck.cpp543
1 files changed, 543 insertions, 0 deletions
diff --git a/dom/security/SRICheck.cpp b/dom/security/SRICheck.cpp
new file mode 100644
index 000000000..534909f81
--- /dev/null
+++ b/dom/security/SRICheck.cpp
@@ -0,0 +1,543 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "SRICheck.h"
+
+#include "mozilla/Base64.h"
+#include "mozilla/LoadTainting.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/dom/SRILogHelper.h"
+#include "mozilla/dom/SRIMetadata.h"
+#include "nsContentUtils.h"
+#include "nsIChannel.h"
+#include "nsIConsoleReportCollector.h"
+#include "nsIProtocolHandler.h"
+#include "nsIScriptError.h"
+#include "nsIIncrementalStreamLoader.h"
+#include "nsIUnicharStreamLoader.h"
+#include "nsIURI.h"
+#include "nsNetUtil.h"
+#include "nsWhitespaceTokenizer.h"
+
+#define SRIVERBOSE(args) \
+ MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Verbose, args)
+#define SRILOG(args) \
+ MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug, args)
+#define SRIERROR(args) \
+ MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Error, args)
+
+namespace mozilla {
+namespace dom {
+
+/**
+ * Returns whether or not the sub-resource about to be loaded is eligible
+ * for integrity checks. If it's not, the checks will be skipped and the
+ * sub-resource will be loaded.
+ */
+static nsresult
+IsEligible(nsIChannel* aChannel, mozilla::LoadTainting aTainting,
+ const nsACString& aSourceFileURI,
+ nsIConsoleReportCollector* aReporter)
+{
+ NS_ENSURE_ARG_POINTER(aReporter);
+
+ if (!aChannel) {
+ SRILOG(("SRICheck::IsEligible, null channel"));
+ return NS_ERROR_SRI_NOT_ELIGIBLE;
+ }
+
+ // Was the sub-resource loaded via CORS?
+ if (aTainting == LoadTainting::CORS) {
+ SRILOG(("SRICheck::IsEligible, CORS mode"));
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIURI> finalURI;
+ nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIURI> originalURI;
+ rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsAutoCString requestSpec;
+ rv = originalURI->GetSpec(requestSpec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
+ SRILOG(("SRICheck::IsEligible, requestURI=%s; finalURI=%s",
+ requestSpec.get(),
+ finalURI ? finalURI->GetSpecOrDefault().get() : ""));
+ }
+
+ // Is the sub-resource same-origin?
+ if (aTainting == LoadTainting::Basic) {
+ SRILOG(("SRICheck::IsEligible, same-origin"));
+ return NS_OK;
+ }
+ SRILOG(("SRICheck::IsEligible, NOT same origin"));
+
+ NS_ConvertUTF8toUTF16 requestSpecUTF16(requestSpec);
+ nsTArray<nsString> params;
+ params.AppendElement(requestSpecUTF16);
+ aReporter->AddConsoleReport(nsIScriptError::errorFlag,
+ NS_LITERAL_CSTRING("Sub-resource Integrity"),
+ nsContentUtils::eSECURITY_PROPERTIES,
+ aSourceFileURI, 0, 0,
+ NS_LITERAL_CSTRING("IneligibleResource"),
+ const_cast<const nsTArray<nsString>&>(params));
+ return NS_ERROR_SRI_NOT_ELIGIBLE;
+}
+
+/* static */ nsresult
+SRICheck::IntegrityMetadata(const nsAString& aMetadataList,
+ const nsACString& aSourceFileURI,
+ nsIConsoleReportCollector* aReporter,
+ SRIMetadata* outMetadata)
+{
+ NS_ENSURE_ARG_POINTER(outMetadata);
+ NS_ENSURE_ARG_POINTER(aReporter);
+ MOZ_ASSERT(outMetadata->IsEmpty()); // caller must pass empty metadata
+
+ if (!Preferences::GetBool("security.sri.enable", false)) {
+ SRILOG(("SRICheck::IntegrityMetadata, sri is disabled (pref)"));
+ return NS_ERROR_SRI_DISABLED;
+ }
+
+ // put a reasonable bound on the length of the metadata
+ NS_ConvertUTF16toUTF8 metadataList(aMetadataList);
+ if (metadataList.Length() > SRICheck::MAX_METADATA_LENGTH) {
+ metadataList.Truncate(SRICheck::MAX_METADATA_LENGTH);
+ }
+ MOZ_ASSERT(metadataList.Length() <= aMetadataList.Length());
+
+ // the integrity attribute is a list of whitespace-separated hashes
+ // and options so we need to look at them one by one and pick the
+ // strongest (valid) one
+ nsCWhitespaceTokenizer tokenizer(metadataList);
+ nsAutoCString token;
+ for (uint32_t i=0; tokenizer.hasMoreTokens() &&
+ i < SRICheck::MAX_METADATA_TOKENS; ++i) {
+ token = tokenizer.nextToken();
+
+ SRIMetadata metadata(token);
+ if (metadata.IsMalformed()) {
+ NS_ConvertUTF8toUTF16 tokenUTF16(token);
+ nsTArray<nsString> params;
+ params.AppendElement(tokenUTF16);
+ aReporter->AddConsoleReport(nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("Sub-resource Integrity"),
+ nsContentUtils::eSECURITY_PROPERTIES,
+ aSourceFileURI, 0, 0,
+ NS_LITERAL_CSTRING("MalformedIntegrityHash"),
+ const_cast<const nsTArray<nsString>&>(params));
+ } else if (!metadata.IsAlgorithmSupported()) {
+ nsAutoCString alg;
+ metadata.GetAlgorithm(&alg);
+ NS_ConvertUTF8toUTF16 algUTF16(alg);
+ nsTArray<nsString> params;
+ params.AppendElement(algUTF16);
+ aReporter->AddConsoleReport(nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("Sub-resource Integrity"),
+ nsContentUtils::eSECURITY_PROPERTIES,
+ aSourceFileURI, 0, 0,
+ NS_LITERAL_CSTRING("UnsupportedHashAlg"),
+ const_cast<const nsTArray<nsString>&>(params));
+ }
+
+ nsAutoCString alg1, alg2;
+ if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
+ outMetadata->GetAlgorithm(&alg1);
+ metadata.GetAlgorithm(&alg2);
+ }
+ if (*outMetadata == metadata) {
+ SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is the same as '%s'",
+ alg1.get(), alg2.get()));
+ *outMetadata += metadata; // add new hash to strongest metadata
+ } else if (*outMetadata < metadata) {
+ SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is weaker than '%s'",
+ alg1.get(), alg2.get()));
+ *outMetadata = metadata; // replace strongest metadata with current
+ }
+ }
+
+ outMetadata->mIntegrityString = aMetadataList;
+
+ if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
+ if (outMetadata->IsValid()) {
+ nsAutoCString alg;
+ outMetadata->GetAlgorithm(&alg);
+ SRILOG(("SRICheck::IntegrityMetadata, using a '%s' hash", alg.get()));
+ } else if (outMetadata->IsEmpty()) {
+ SRILOG(("SRICheck::IntegrityMetadata, no metadata"));
+ } else {
+ SRILOG(("SRICheck::IntegrityMetadata, no valid metadata found"));
+ }
+ }
+ return NS_OK;
+}
+
+/* static */ nsresult
+SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
+ nsIUnicharStreamLoader* aLoader,
+ const nsAString& aString,
+ const nsACString& aSourceFileURI,
+ nsIConsoleReportCollector* aReporter)
+{
+ NS_ENSURE_ARG_POINTER(aLoader);
+ NS_ENSURE_ARG_POINTER(aReporter);
+
+ nsCOMPtr<nsIChannel> channel;
+ aLoader->GetChannel(getter_AddRefs(channel));
+
+ if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
+ nsAutoCString requestURL;
+ nsCOMPtr<nsIURI> originalURI;
+ if (channel &&
+ NS_SUCCEEDED(channel->GetOriginalURI(getter_AddRefs(originalURI))) &&
+ originalURI) {
+ originalURI->GetAsciiSpec(requestURL);
+ }
+ SRILOG(("SRICheck::VerifyIntegrity (unichar stream)"));
+ }
+
+ SRICheckDataVerifier verifier(aMetadata, aSourceFileURI, aReporter);
+ nsresult rv;
+ nsDependentCString rawBuffer;
+ rv = aLoader->GetRawBuffer(rawBuffer);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = verifier.Update(rawBuffer.Length(), (const uint8_t*)rawBuffer.get());
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return verifier.Verify(aMetadata, channel, aSourceFileURI, aReporter);
+}
+
+//////////////////////////////////////////////////////////////
+//
+//////////////////////////////////////////////////////////////
+SRICheckDataVerifier::SRICheckDataVerifier(const SRIMetadata& aMetadata,
+ const nsACString& aSourceFileURI,
+ nsIConsoleReportCollector* aReporter)
+ : mCryptoHash(nullptr),
+ mBytesHashed(0),
+ mInvalidMetadata(false),
+ mComplete(false)
+{
+ MOZ_ASSERT(!aMetadata.IsEmpty()); // should be checked by caller
+
+ // IntegrityMetadata() checks this and returns "no metadata" if
+ // it's disabled so we should never make it this far
+ MOZ_ASSERT(Preferences::GetBool("security.sri.enable", false));
+ MOZ_ASSERT(aReporter);
+
+ if (!aMetadata.IsValid()) {
+ nsTArray<nsString> params;
+ aReporter->AddConsoleReport(nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("Sub-resource Integrity"),
+ nsContentUtils::eSECURITY_PROPERTIES,
+ aSourceFileURI, 0, 0,
+ NS_LITERAL_CSTRING("NoValidMetadata"),
+ const_cast<const nsTArray<nsString>&>(params));
+ mInvalidMetadata = true;
+ return; // ignore invalid metadata for forward-compatibility
+ }
+
+ aMetadata.GetHashType(&mHashType, &mHashLength);
+}
+
+nsresult
+SRICheckDataVerifier::EnsureCryptoHash()
+{
+ MOZ_ASSERT(!mInvalidMetadata);
+
+ if (mCryptoHash) {
+ return NS_OK;
+ }
+
+ nsresult rv;
+ nsCOMPtr<nsICryptoHash> cryptoHash =
+ do_CreateInstance("@mozilla.org/security/hash;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = cryptoHash->Init(mHashType);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mCryptoHash = cryptoHash;
+ return NS_OK;
+}
+
+nsresult
+SRICheckDataVerifier::Update(uint32_t aStringLen, const uint8_t* aString)
+{
+ NS_ENSURE_ARG_POINTER(aString);
+ if (mInvalidMetadata) {
+ return NS_OK; // ignoring any data updates, see mInvalidMetadata usage
+ }
+
+ nsresult rv;
+ rv = EnsureCryptoHash();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mBytesHashed += aStringLen;
+
+ return mCryptoHash->Update(aString, aStringLen);
+}
+
+nsresult
+SRICheckDataVerifier::Finish()
+{
+ if (mInvalidMetadata || mComplete) {
+ return NS_OK; // already finished or invalid metadata
+ }
+
+ nsresult rv;
+ rv = EnsureCryptoHash(); // we need computed hash even for 0-length data
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = mCryptoHash->Finish(false, mComputedHash);
+ mCryptoHash = nullptr;
+ mComplete = true;
+ return rv;
+}
+
+nsresult
+SRICheckDataVerifier::VerifyHash(const SRIMetadata& aMetadata,
+ uint32_t aHashIndex,
+ const nsACString& aSourceFileURI,
+ nsIConsoleReportCollector* aReporter)
+{
+ NS_ENSURE_ARG_POINTER(aReporter);
+
+ nsAutoCString base64Hash;
+ aMetadata.GetHash(aHashIndex, &base64Hash);
+ SRILOG(("SRICheckDataVerifier::VerifyHash, hash[%u]=%s", aHashIndex, base64Hash.get()));
+
+ nsAutoCString binaryHash;
+ if (NS_WARN_IF(NS_FAILED(Base64Decode(base64Hash, binaryHash)))) {
+ nsTArray<nsString> params;
+ aReporter->AddConsoleReport(nsIScriptError::errorFlag,
+ NS_LITERAL_CSTRING("Sub-resource Integrity"),
+ nsContentUtils::eSECURITY_PROPERTIES,
+ aSourceFileURI, 0, 0,
+ NS_LITERAL_CSTRING("InvalidIntegrityBase64"),
+ const_cast<const nsTArray<nsString>&>(params));
+ return NS_ERROR_SRI_CORRUPT;
+ }
+
+ uint32_t hashLength;
+ int8_t hashType;
+ aMetadata.GetHashType(&hashType, &hashLength);
+ if (binaryHash.Length() != hashLength) {
+ nsTArray<nsString> params;
+ aReporter->AddConsoleReport(nsIScriptError::errorFlag,
+ NS_LITERAL_CSTRING("Sub-resource Integrity"),
+ nsContentUtils::eSECURITY_PROPERTIES,
+ aSourceFileURI, 0, 0,
+ NS_LITERAL_CSTRING("InvalidIntegrityLength"),
+ const_cast<const nsTArray<nsString>&>(params));
+ return NS_ERROR_SRI_CORRUPT;
+ }
+
+ if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
+ nsAutoCString encodedHash;
+ nsresult rv = Base64Encode(mComputedHash, encodedHash);
+ if (NS_SUCCEEDED(rv)) {
+ SRILOG(("SRICheckDataVerifier::VerifyHash, mComputedHash=%s",
+ encodedHash.get()));
+ }
+ }
+
+ if (!binaryHash.Equals(mComputedHash)) {
+ SRILOG(("SRICheckDataVerifier::VerifyHash, hash[%u] did not match", aHashIndex));
+ return NS_ERROR_SRI_CORRUPT;
+ }
+
+ SRILOG(("SRICheckDataVerifier::VerifyHash, hash[%u] verified successfully", aHashIndex));
+ return NS_OK;
+}
+
+nsresult
+SRICheckDataVerifier::Verify(const SRIMetadata& aMetadata,
+ nsIChannel* aChannel,
+ const nsACString& aSourceFileURI,
+ nsIConsoleReportCollector* aReporter)
+{
+ NS_ENSURE_ARG_POINTER(aReporter);
+
+ if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
+ nsAutoCString requestURL;
+ nsCOMPtr<nsIRequest> request;
+ request = do_QueryInterface(aChannel);
+ request->GetName(requestURL);
+ SRILOG(("SRICheckDataVerifier::Verify, url=%s (length=%lu)",
+ requestURL.get(), mBytesHashed));
+ }
+
+ nsresult rv = Finish();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+ NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
+ LoadTainting tainting = loadInfo->GetTainting();
+
+ if (NS_FAILED(IsEligible(aChannel, tainting, aSourceFileURI, aReporter))) {
+ return NS_ERROR_SRI_NOT_ELIGIBLE;
+ }
+
+ if (mInvalidMetadata) {
+ return NS_OK; // ignore invalid metadata for forward-compatibility
+ }
+
+ for (uint32_t i = 0; i < aMetadata.HashCount(); i++) {
+ if (NS_SUCCEEDED(VerifyHash(aMetadata, i, aSourceFileURI, aReporter))) {
+ return NS_OK; // stop at the first valid hash
+ }
+ }
+
+ nsAutoCString alg;
+ aMetadata.GetAlgorithm(&alg);
+ NS_ConvertUTF8toUTF16 algUTF16(alg);
+ nsTArray<nsString> params;
+ params.AppendElement(algUTF16);
+ aReporter->AddConsoleReport(nsIScriptError::errorFlag,
+ NS_LITERAL_CSTRING("Sub-resource Integrity"),
+ nsContentUtils::eSECURITY_PROPERTIES,
+ aSourceFileURI, 0, 0,
+ NS_LITERAL_CSTRING("IntegrityMismatch"),
+ const_cast<const nsTArray<nsString>&>(params));
+ return NS_ERROR_SRI_CORRUPT;
+}
+
+uint32_t
+SRICheckDataVerifier::DataSummaryLength()
+{
+ MOZ_ASSERT(!mInvalidMetadata);
+ return sizeof(mHashType) + sizeof(mHashLength) + mHashLength;
+}
+
+uint32_t
+SRICheckDataVerifier::EmptyDataSummaryLength()
+{
+ return sizeof(int8_t) + sizeof(uint32_t);
+}
+
+nsresult
+SRICheckDataVerifier::DataSummaryLength(uint32_t aDataLen, const uint8_t* aData, uint32_t* length)
+{
+ *length = 0;
+ NS_ENSURE_ARG_POINTER(aData);
+
+ // we expect to always encode an SRI, even if it is empty or incomplete
+ if (aDataLen < EmptyDataSummaryLength()) {
+ SRILOG(("SRICheckDataVerifier::DataSummaryLength, encoded length[%u] is too small", aDataLen));
+ return NS_ERROR_SRI_IMPORT;
+ }
+
+ // decode the content of the buffer
+ size_t offset = sizeof(mHashType);
+ size_t len = *reinterpret_cast<const decltype(mHashLength)*>(&aData[offset]);
+ offset += sizeof(mHashLength);
+
+ SRIVERBOSE(("SRICheckDataVerifier::DataSummaryLength, header {%x, %x, %x, %x, %x, ...}",
+ aData[0], aData[1], aData[2], aData[3], aData[4]));
+
+ if (offset + len > aDataLen) {
+ SRILOG(("SRICheckDataVerifier::DataSummaryLength, encoded length[%u] overflow the buffer size", aDataLen));
+ SRIVERBOSE(("SRICheckDataVerifier::DataSummaryLength, offset[%u], len[%u]",
+ uint32_t(offset), uint32_t(len)));
+ return NS_ERROR_SRI_IMPORT;
+ }
+ *length = uint32_t(offset + len);
+ return NS_OK;
+}
+
+nsresult
+SRICheckDataVerifier::ImportDataSummary(uint32_t aDataLen, const uint8_t* aData)
+{
+ MOZ_ASSERT(!mInvalidMetadata); // mHashType and mHashLength should be valid
+ MOZ_ASSERT(!mCryptoHash); // EnsureCryptoHash should not have been called
+ NS_ENSURE_ARG_POINTER(aData);
+ if (mInvalidMetadata) {
+ return NS_OK; // ignoring any data updates, see mInvalidMetadata usage
+ }
+
+ // we expect to always encode an SRI, even if it is empty or incomplete
+ if (aDataLen < DataSummaryLength()) {
+ SRILOG(("SRICheckDataVerifier::ImportDataSummary, encoded length[%u] is too small", aDataLen));
+ return NS_ERROR_SRI_IMPORT;
+ }
+
+ SRIVERBOSE(("SRICheckDataVerifier::ImportDataSummary, header {%x, %x, %x, %x, %x, ...}",
+ aData[0], aData[1], aData[2], aData[3], aData[4]));
+
+ // decode the content of the buffer
+ size_t offset = 0;
+ if (*reinterpret_cast<const decltype(mHashType)*>(&aData[offset]) != mHashType) {
+ SRILOG(("SRICheckDataVerifier::ImportDataSummary, hash type[%d] does not match[%d]",
+ *reinterpret_cast<const decltype(mHashType)*>(&aData[offset]),
+ mHashType));
+ return NS_ERROR_SRI_UNEXPECTED_HASH_TYPE;
+ }
+ offset += sizeof(mHashType);
+
+ if (*reinterpret_cast<const decltype(mHashLength)*>(&aData[offset]) != mHashLength) {
+ SRILOG(("SRICheckDataVerifier::ImportDataSummary, hash length[%d] does not match[%d]",
+ *reinterpret_cast<const decltype(mHashLength)*>(&aData[offset]),
+ mHashLength));
+ return NS_ERROR_SRI_UNEXPECTED_HASH_TYPE;
+ }
+ offset += sizeof(mHashLength);
+
+ // copy the hash to mComputedHash, as-if we had finished streaming the bytes
+ mComputedHash.Assign(reinterpret_cast<const char*>(&aData[offset]), mHashLength);
+ mCryptoHash = nullptr;
+ mComplete = true;
+ return NS_OK;
+}
+
+nsresult
+SRICheckDataVerifier::ExportDataSummary(uint32_t aDataLen, uint8_t* aData)
+{
+ MOZ_ASSERT(!mInvalidMetadata); // mHashType and mHashLength should be valid
+ MOZ_ASSERT(mComplete); // finished streaming
+ NS_ENSURE_ARG_POINTER(aData);
+ NS_ENSURE_TRUE(aDataLen >= DataSummaryLength(), NS_ERROR_INVALID_ARG);
+
+ // serialize the hash in the buffer
+ size_t offset = 0;
+ *reinterpret_cast<decltype(mHashType)*>(&aData[offset]) = mHashType;
+ offset += sizeof(mHashType);
+ *reinterpret_cast<decltype(mHashLength)*>(&aData[offset]) = mHashLength;
+ offset += sizeof(mHashLength);
+
+ SRIVERBOSE(("SRICheckDataVerifier::ExportDataSummary, header {%x, %x, %x, %x, %x, ...}",
+ aData[0], aData[1], aData[2], aData[3], aData[4]));
+
+ // copy the hash to mComputedHash, as-if we had finished streaming the bytes
+ nsCharTraits<char>::copy(reinterpret_cast<char*>(&aData[offset]),
+ mComputedHash.get(), mHashLength);
+ return NS_OK;
+}
+
+nsresult
+SRICheckDataVerifier::ExportEmptyDataSummary(uint32_t aDataLen, uint8_t* aData)
+{
+ NS_ENSURE_ARG_POINTER(aData);
+ NS_ENSURE_TRUE(aDataLen >= EmptyDataSummaryLength(), NS_ERROR_INVALID_ARG);
+
+ // serialize an unknown hash in the buffer, to be able to skip it later
+ size_t offset = 0;
+ *reinterpret_cast<decltype(mHashType)*>(&aData[offset]) = 0;
+ offset += sizeof(mHashType);
+ *reinterpret_cast<decltype(mHashLength)*>(&aData[offset]) = 0;
+ offset += sizeof(mHashLength);
+
+ SRIVERBOSE(("SRICheckDataVerifier::ExportEmptyDataSummary, header {%x, %x, %x, %x, %x, ...}",
+ aData[0], aData[1], aData[2], aData[3], aData[4]));
+
+ return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla