зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1288104 part 2 - Instrument SRICheckDataVerifier to load/save the computed hash from the bytecode cache. r=francois
This commit is contained in:
Родитель
b3e4b94e1e
Коммит
395abf823f
|
@ -23,6 +23,8 @@
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsWhitespaceTokenizer.h"
|
#include "nsWhitespaceTokenizer.h"
|
||||||
|
|
||||||
|
#define SRIVERBOSE(args) \
|
||||||
|
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Verbose, args)
|
||||||
#define SRILOG(args) \
|
#define SRILOG(args) \
|
||||||
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug, args)
|
MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug, args)
|
||||||
#define SRIERROR(args) \
|
#define SRIERROR(args) \
|
||||||
|
@ -242,8 +244,7 @@ SRICheckDataVerifier::SRICheckDataVerifier(const SRIMetadata& aMetadata,
|
||||||
return; // ignore invalid metadata for forward-compatibility
|
return; // ignore invalid metadata for forward-compatibility
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t hashLength;
|
aMetadata.GetHashType(&mHashType, &mHashLength);
|
||||||
aMetadata.GetHashType(&mHashType, &hashLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -408,5 +409,135 @@ SRICheckDataVerifier::Verify(const SRIMetadata& aMetadata,
|
||||||
return NS_ERROR_SRI_CORRUPT;
|
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 dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -45,6 +45,20 @@ public:
|
||||||
nsIConsoleReportCollector* aReporter);
|
nsIConsoleReportCollector* aReporter);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The SRICheckDataVerifier can be used in 2 different mode:
|
||||||
|
//
|
||||||
|
// 1. The streaming mode involves reading bytes from an input, and to use
|
||||||
|
// the |Update| function to stream new bytes, and to use the |Verify|
|
||||||
|
// function to check the hash of the content with the hash provided by
|
||||||
|
// the metadata.
|
||||||
|
//
|
||||||
|
// Optionally, one can serialize the verified hash with |ExportDataSummary|,
|
||||||
|
// in a buffer in order to rely on the second mode the next time.
|
||||||
|
//
|
||||||
|
// 2. The pre-computed mode, involves reading a hash with |ImportDataSummary|,
|
||||||
|
// which got exported by the SRICheckDataVerifier and potentially cached, and
|
||||||
|
// then use the |Verify| function to check against the hash provided by the
|
||||||
|
// metadata.
|
||||||
class SRICheckDataVerifier final
|
class SRICheckDataVerifier final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -52,15 +66,42 @@ class SRICheckDataVerifier final
|
||||||
const nsACString& aSourceFileURI,
|
const nsACString& aSourceFileURI,
|
||||||
nsIConsoleReportCollector* aReporter);
|
nsIConsoleReportCollector* aReporter);
|
||||||
|
|
||||||
|
// Append the following bytes to the content used to compute the hash. Once
|
||||||
|
// all bytes are streamed, use the Verify function to check the integrity.
|
||||||
nsresult Update(uint32_t aStringLen, const uint8_t* aString);
|
nsresult Update(uint32_t aStringLen, const uint8_t* aString);
|
||||||
|
|
||||||
|
// Verify that the computed hash corresponds to the metadata.
|
||||||
nsresult Verify(const SRIMetadata& aMetadata, nsIChannel* aChannel,
|
nsresult Verify(const SRIMetadata& aMetadata, nsIChannel* aChannel,
|
||||||
const nsACString& aSourceFileURI,
|
const nsACString& aSourceFileURI,
|
||||||
nsIConsoleReportCollector* aReporter);
|
nsIConsoleReportCollector* aReporter);
|
||||||
|
|
||||||
|
bool IsComplete() const {
|
||||||
|
return mComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report the length of the computed hash and its type, such that we can
|
||||||
|
// reserve the space for encoding it in a vector.
|
||||||
|
uint32_t DataSummaryLength();
|
||||||
|
static uint32_t EmptyDataSummaryLength();
|
||||||
|
|
||||||
|
// Write the computed hash and its type in a pre-allocated buffer.
|
||||||
|
nsresult ExportDataSummary(uint32_t aDataLen, uint8_t* aData);
|
||||||
|
static nsresult ExportEmptyDataSummary(uint32_t aDataLen, uint8_t* aData);
|
||||||
|
|
||||||
|
// Report the length of the computed hash and its type, such that we can
|
||||||
|
// skip these data while reading a buffer.
|
||||||
|
static nsresult DataSummaryLength(uint32_t aDataLen, const uint8_t* aData, uint32_t* length);
|
||||||
|
|
||||||
|
// Extract the computed hash and its type, such that we can |Verify| if it
|
||||||
|
// matches the metadata. The buffer should be at least the same size or
|
||||||
|
// larger than the value returned by |DataSummaryLength|.
|
||||||
|
nsresult ImportDataSummary(uint32_t aDataLen, const uint8_t* aData);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsCOMPtr<nsICryptoHash> mCryptoHash;
|
nsCOMPtr<nsICryptoHash> mCryptoHash;
|
||||||
nsAutoCString mComputedHash;
|
nsAutoCString mComputedHash;
|
||||||
size_t mBytesHashed;
|
size_t mBytesHashed;
|
||||||
|
uint32_t mHashLength;
|
||||||
int8_t mHashType;
|
int8_t mHashType;
|
||||||
bool mInvalidMetadata;
|
bool mInvalidMetadata;
|
||||||
bool mComplete;
|
bool mComplete;
|
||||||
|
|
|
@ -696,6 +696,8 @@
|
||||||
ERROR(NS_ERROR_SRI_CORRUPT, FAILURE(200)),
|
ERROR(NS_ERROR_SRI_CORRUPT, FAILURE(200)),
|
||||||
ERROR(NS_ERROR_SRI_DISABLED, FAILURE(201)),
|
ERROR(NS_ERROR_SRI_DISABLED, FAILURE(201)),
|
||||||
ERROR(NS_ERROR_SRI_NOT_ELIGIBLE, FAILURE(202)),
|
ERROR(NS_ERROR_SRI_NOT_ELIGIBLE, FAILURE(202)),
|
||||||
|
ERROR(NS_ERROR_SRI_UNEXPECTED_HASH_TYPE, FAILURE(203)),
|
||||||
|
ERROR(NS_ERROR_SRI_IMPORT, FAILURE(204)),
|
||||||
|
|
||||||
/* CMS specific nsresult error codes. Note: the numbers used here correspond
|
/* CMS specific nsresult error codes. Note: the numbers used here correspond
|
||||||
* to the values in nsICMSMessageErrors.idl. */
|
* to the values in nsICMSMessageErrors.idl. */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче