Bug 1288104 part 2 - Instrument SRICheckDataVerifier to load/save the computed hash from the bytecode cache. r=francois

This commit is contained in:
Nicolas B. Pierron 2016-10-20 09:44:33 +00:00
Родитель b3e4b94e1e
Коммит 395abf823f
3 изменённых файлов: 176 добавлений и 2 удалений

Просмотреть файл

@ -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. */