Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "SRICheck.h"
8 :
9 : #include "mozilla/Base64.h"
10 : #include "mozilla/LoadTainting.h"
11 : #include "mozilla/Logging.h"
12 : #include "mozilla/Preferences.h"
13 : #include "mozilla/SizePrintfMacros.h"
14 : #include "mozilla/dom/SRILogHelper.h"
15 : #include "mozilla/dom/SRIMetadata.h"
16 : #include "nsContentUtils.h"
17 : #include "nsIChannel.h"
18 : #include "nsIConsoleReportCollector.h"
19 : #include "nsIProtocolHandler.h"
20 : #include "nsIScriptError.h"
21 : #include "nsIIncrementalStreamLoader.h"
22 : #include "nsIUnicharStreamLoader.h"
23 : #include "nsIURI.h"
24 : #include "nsNetUtil.h"
25 : #include "nsWhitespaceTokenizer.h"
26 :
27 : #define SRIVERBOSE(args) \
28 : MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Verbose, args)
29 : #define SRILOG(args) \
30 : MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug, args)
31 : #define SRIERROR(args) \
32 : MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Error, args)
33 :
34 : namespace mozilla {
35 : namespace dom {
36 :
37 : /**
38 : * Returns whether or not the sub-resource about to be loaded is eligible
39 : * for integrity checks. If it's not, the checks will be skipped and the
40 : * sub-resource will be loaded.
41 : */
42 : static nsresult
43 0 : IsEligible(nsIChannel* aChannel, mozilla::LoadTainting aTainting,
44 : const nsACString& aSourceFileURI,
45 : nsIConsoleReportCollector* aReporter)
46 : {
47 0 : NS_ENSURE_ARG_POINTER(aReporter);
48 :
49 0 : if (!aChannel) {
50 0 : SRILOG(("SRICheck::IsEligible, null channel"));
51 0 : return NS_ERROR_SRI_NOT_ELIGIBLE;
52 : }
53 :
54 : // Was the sub-resource loaded via CORS?
55 0 : if (aTainting == LoadTainting::CORS) {
56 0 : SRILOG(("SRICheck::IsEligible, CORS mode"));
57 0 : return NS_OK;
58 : }
59 :
60 0 : nsCOMPtr<nsIURI> finalURI;
61 0 : nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
62 0 : NS_ENSURE_SUCCESS(rv, rv);
63 0 : nsCOMPtr<nsIURI> originalURI;
64 0 : rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
65 0 : NS_ENSURE_SUCCESS(rv, rv);
66 0 : nsAutoCString requestSpec;
67 0 : rv = originalURI->GetSpec(requestSpec);
68 0 : NS_ENSURE_SUCCESS(rv, rv);
69 :
70 0 : if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
71 0 : SRILOG(("SRICheck::IsEligible, requestURI=%s; finalURI=%s",
72 : requestSpec.get(),
73 : finalURI ? finalURI->GetSpecOrDefault().get() : ""));
74 : }
75 :
76 : // Is the sub-resource same-origin?
77 0 : if (aTainting == LoadTainting::Basic) {
78 0 : SRILOG(("SRICheck::IsEligible, same-origin"));
79 0 : return NS_OK;
80 : }
81 0 : SRILOG(("SRICheck::IsEligible, NOT same origin"));
82 :
83 0 : NS_ConvertUTF8toUTF16 requestSpecUTF16(requestSpec);
84 0 : nsTArray<nsString> params;
85 0 : params.AppendElement(requestSpecUTF16);
86 0 : aReporter->AddConsoleReport(nsIScriptError::errorFlag,
87 0 : NS_LITERAL_CSTRING("Sub-resource Integrity"),
88 : nsContentUtils::eSECURITY_PROPERTIES,
89 : aSourceFileURI, 0, 0,
90 0 : NS_LITERAL_CSTRING("IneligibleResource"),
91 0 : const_cast<const nsTArray<nsString>&>(params));
92 0 : return NS_ERROR_SRI_NOT_ELIGIBLE;
93 : }
94 :
95 : /* static */ nsresult
96 0 : SRICheck::IntegrityMetadata(const nsAString& aMetadataList,
97 : const nsACString& aSourceFileURI,
98 : nsIConsoleReportCollector* aReporter,
99 : SRIMetadata* outMetadata)
100 : {
101 0 : NS_ENSURE_ARG_POINTER(outMetadata);
102 0 : NS_ENSURE_ARG_POINTER(aReporter);
103 0 : MOZ_ASSERT(outMetadata->IsEmpty()); // caller must pass empty metadata
104 :
105 0 : if (!Preferences::GetBool("security.sri.enable", false)) {
106 0 : SRILOG(("SRICheck::IntegrityMetadata, sri is disabled (pref)"));
107 0 : return NS_ERROR_SRI_DISABLED;
108 : }
109 :
110 : // put a reasonable bound on the length of the metadata
111 0 : NS_LossyConvertUTF16toASCII metadataList(aMetadataList);
112 0 : if (metadataList.Length() > SRICheck::MAX_METADATA_LENGTH) {
113 0 : metadataList.Truncate(SRICheck::MAX_METADATA_LENGTH);
114 : }
115 0 : SRILOG(("SRICheck::IntegrityMetadata, metadataList=%s", metadataList.get()));
116 0 : MOZ_ASSERT(metadataList.Length() <= aMetadataList.Length());
117 :
118 : // the integrity attribute is a list of whitespace-separated hashes
119 : // and options so we need to look at them one by one and pick the
120 : // strongest (valid) one
121 0 : nsCWhitespaceTokenizer tokenizer(metadataList);
122 0 : nsAutoCString token;
123 0 : for (uint32_t i=0; tokenizer.hasMoreTokens() &&
124 : i < SRICheck::MAX_METADATA_TOKENS; ++i) {
125 0 : token = tokenizer.nextToken();
126 :
127 0 : SRIMetadata metadata(token);
128 0 : if (metadata.IsMalformed()) {
129 0 : NS_ConvertUTF8toUTF16 tokenUTF16(token);
130 0 : nsTArray<nsString> params;
131 0 : params.AppendElement(tokenUTF16);
132 0 : aReporter->AddConsoleReport(nsIScriptError::warningFlag,
133 0 : NS_LITERAL_CSTRING("Sub-resource Integrity"),
134 : nsContentUtils::eSECURITY_PROPERTIES,
135 : aSourceFileURI, 0, 0,
136 0 : NS_LITERAL_CSTRING("MalformedIntegrityHash"),
137 0 : const_cast<const nsTArray<nsString>&>(params));
138 0 : } else if (!metadata.IsAlgorithmSupported()) {
139 0 : nsAutoCString alg;
140 0 : metadata.GetAlgorithm(&alg);
141 0 : NS_ConvertUTF8toUTF16 algUTF16(alg);
142 0 : nsTArray<nsString> params;
143 0 : params.AppendElement(algUTF16);
144 0 : aReporter->AddConsoleReport(nsIScriptError::warningFlag,
145 0 : NS_LITERAL_CSTRING("Sub-resource Integrity"),
146 : nsContentUtils::eSECURITY_PROPERTIES,
147 : aSourceFileURI, 0, 0,
148 0 : NS_LITERAL_CSTRING("UnsupportedHashAlg"),
149 0 : const_cast<const nsTArray<nsString>&>(params));
150 : }
151 :
152 0 : nsAutoCString alg1, alg2;
153 0 : if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
154 0 : outMetadata->GetAlgorithm(&alg1);
155 0 : metadata.GetAlgorithm(&alg2);
156 : }
157 0 : if (*outMetadata == metadata) {
158 0 : SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is the same as '%s'",
159 : alg1.get(), alg2.get()));
160 0 : *outMetadata += metadata; // add new hash to strongest metadata
161 0 : } else if (*outMetadata < metadata) {
162 0 : SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is weaker than '%s'",
163 : alg1.get(), alg2.get()));
164 0 : *outMetadata = metadata; // replace strongest metadata with current
165 : }
166 : }
167 :
168 0 : outMetadata->mIntegrityString = aMetadataList;
169 :
170 0 : if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
171 0 : if (outMetadata->IsValid()) {
172 0 : nsAutoCString alg;
173 0 : outMetadata->GetAlgorithm(&alg);
174 0 : SRILOG(("SRICheck::IntegrityMetadata, using a '%s' hash", alg.get()));
175 0 : } else if (outMetadata->IsEmpty()) {
176 0 : SRILOG(("SRICheck::IntegrityMetadata, no metadata"));
177 : } else {
178 0 : SRILOG(("SRICheck::IntegrityMetadata, no valid metadata found"));
179 : }
180 : }
181 0 : return NS_OK;
182 : }
183 :
184 : /* static */ nsresult
185 0 : SRICheck::VerifyIntegrity(const SRIMetadata& aMetadata,
186 : nsIUnicharStreamLoader* aLoader,
187 : const nsAString& aString,
188 : const nsACString& aSourceFileURI,
189 : nsIConsoleReportCollector* aReporter)
190 : {
191 0 : NS_ENSURE_ARG_POINTER(aLoader);
192 0 : NS_ENSURE_ARG_POINTER(aReporter);
193 :
194 0 : nsCOMPtr<nsIChannel> channel;
195 0 : aLoader->GetChannel(getter_AddRefs(channel));
196 :
197 0 : if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
198 0 : nsAutoCString requestURL;
199 0 : nsCOMPtr<nsIURI> originalURI;
200 0 : if (channel &&
201 0 : NS_SUCCEEDED(channel->GetOriginalURI(getter_AddRefs(originalURI))) &&
202 0 : originalURI) {
203 0 : originalURI->GetAsciiSpec(requestURL);
204 : }
205 0 : SRILOG(("SRICheck::VerifyIntegrity (unichar stream)"));
206 : }
207 :
208 0 : SRICheckDataVerifier verifier(aMetadata, aSourceFileURI, aReporter);
209 : nsresult rv;
210 0 : nsDependentCString rawBuffer;
211 0 : rv = aLoader->GetRawBuffer(rawBuffer);
212 0 : NS_ENSURE_SUCCESS(rv, rv);
213 0 : rv = verifier.Update(rawBuffer.Length(), (const uint8_t*)rawBuffer.get());
214 0 : NS_ENSURE_SUCCESS(rv, rv);
215 :
216 0 : return verifier.Verify(aMetadata, channel, aSourceFileURI, aReporter);
217 : }
218 :
219 : //////////////////////////////////////////////////////////////
220 : //
221 : //////////////////////////////////////////////////////////////
222 0 : SRICheckDataVerifier::SRICheckDataVerifier(const SRIMetadata& aMetadata,
223 : const nsACString& aSourceFileURI,
224 0 : nsIConsoleReportCollector* aReporter)
225 : : mCryptoHash(nullptr),
226 : mBytesHashed(0),
227 : mInvalidMetadata(false),
228 0 : mComplete(false)
229 : {
230 0 : MOZ_ASSERT(!aMetadata.IsEmpty()); // should be checked by caller
231 :
232 : // IntegrityMetadata() checks this and returns "no metadata" if
233 : // it's disabled so we should never make it this far
234 0 : MOZ_ASSERT(Preferences::GetBool("security.sri.enable", false));
235 0 : MOZ_ASSERT(aReporter);
236 :
237 0 : if (!aMetadata.IsValid()) {
238 0 : nsTArray<nsString> params;
239 0 : aReporter->AddConsoleReport(nsIScriptError::warningFlag,
240 0 : NS_LITERAL_CSTRING("Sub-resource Integrity"),
241 : nsContentUtils::eSECURITY_PROPERTIES,
242 : aSourceFileURI, 0, 0,
243 0 : NS_LITERAL_CSTRING("NoValidMetadata"),
244 0 : const_cast<const nsTArray<nsString>&>(params));
245 0 : mInvalidMetadata = true;
246 0 : return; // ignore invalid metadata for forward-compatibility
247 : }
248 :
249 0 : aMetadata.GetHashType(&mHashType, &mHashLength);
250 : }
251 :
252 : nsresult
253 0 : SRICheckDataVerifier::EnsureCryptoHash()
254 : {
255 0 : MOZ_ASSERT(!mInvalidMetadata);
256 :
257 0 : if (mCryptoHash) {
258 0 : return NS_OK;
259 : }
260 :
261 : nsresult rv;
262 : nsCOMPtr<nsICryptoHash> cryptoHash =
263 0 : do_CreateInstance("@mozilla.org/security/hash;1", &rv);
264 0 : NS_ENSURE_SUCCESS(rv, rv);
265 0 : rv = cryptoHash->Init(mHashType);
266 0 : NS_ENSURE_SUCCESS(rv, rv);
267 :
268 0 : mCryptoHash = cryptoHash;
269 0 : return NS_OK;
270 : }
271 :
272 : nsresult
273 0 : SRICheckDataVerifier::Update(uint32_t aStringLen, const uint8_t* aString)
274 : {
275 0 : NS_ENSURE_ARG_POINTER(aString);
276 0 : if (mInvalidMetadata) {
277 0 : return NS_OK; // ignoring any data updates, see mInvalidMetadata usage
278 : }
279 :
280 : nsresult rv;
281 0 : rv = EnsureCryptoHash();
282 0 : NS_ENSURE_SUCCESS(rv, rv);
283 :
284 0 : mBytesHashed += aStringLen;
285 :
286 0 : return mCryptoHash->Update(aString, aStringLen);
287 : }
288 :
289 : nsresult
290 0 : SRICheckDataVerifier::Finish()
291 : {
292 0 : if (mInvalidMetadata || mComplete) {
293 0 : return NS_OK; // already finished or invalid metadata
294 : }
295 :
296 : nsresult rv;
297 0 : rv = EnsureCryptoHash(); // we need computed hash even for 0-length data
298 0 : NS_ENSURE_SUCCESS(rv, rv);
299 :
300 0 : rv = mCryptoHash->Finish(false, mComputedHash);
301 0 : mCryptoHash = nullptr;
302 0 : mComplete = true;
303 0 : return rv;
304 : }
305 :
306 : nsresult
307 0 : SRICheckDataVerifier::VerifyHash(const SRIMetadata& aMetadata,
308 : uint32_t aHashIndex,
309 : const nsACString& aSourceFileURI,
310 : nsIConsoleReportCollector* aReporter)
311 : {
312 0 : NS_ENSURE_ARG_POINTER(aReporter);
313 :
314 0 : nsAutoCString base64Hash;
315 0 : aMetadata.GetHash(aHashIndex, &base64Hash);
316 0 : SRILOG(("SRICheckDataVerifier::VerifyHash, hash[%u]=%s", aHashIndex, base64Hash.get()));
317 :
318 0 : nsAutoCString binaryHash;
319 0 : if (NS_WARN_IF(NS_FAILED(Base64Decode(base64Hash, binaryHash)))) {
320 0 : nsTArray<nsString> params;
321 0 : aReporter->AddConsoleReport(nsIScriptError::errorFlag,
322 0 : NS_LITERAL_CSTRING("Sub-resource Integrity"),
323 : nsContentUtils::eSECURITY_PROPERTIES,
324 : aSourceFileURI, 0, 0,
325 0 : NS_LITERAL_CSTRING("InvalidIntegrityBase64"),
326 0 : const_cast<const nsTArray<nsString>&>(params));
327 0 : return NS_ERROR_SRI_CORRUPT;
328 : }
329 :
330 : uint32_t hashLength;
331 : int8_t hashType;
332 0 : aMetadata.GetHashType(&hashType, &hashLength);
333 0 : if (binaryHash.Length() != hashLength) {
334 0 : nsTArray<nsString> params;
335 0 : aReporter->AddConsoleReport(nsIScriptError::errorFlag,
336 0 : NS_LITERAL_CSTRING("Sub-resource Integrity"),
337 : nsContentUtils::eSECURITY_PROPERTIES,
338 : aSourceFileURI, 0, 0,
339 0 : NS_LITERAL_CSTRING("InvalidIntegrityLength"),
340 0 : const_cast<const nsTArray<nsString>&>(params));
341 0 : return NS_ERROR_SRI_CORRUPT;
342 : }
343 :
344 0 : if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
345 0 : nsAutoCString encodedHash;
346 0 : nsresult rv = Base64Encode(mComputedHash, encodedHash);
347 0 : if (NS_SUCCEEDED(rv)) {
348 0 : SRILOG(("SRICheckDataVerifier::VerifyHash, mComputedHash=%s",
349 : encodedHash.get()));
350 : }
351 : }
352 :
353 0 : if (!binaryHash.Equals(mComputedHash)) {
354 0 : SRILOG(("SRICheckDataVerifier::VerifyHash, hash[%u] did not match", aHashIndex));
355 0 : return NS_ERROR_SRI_CORRUPT;
356 : }
357 :
358 0 : SRILOG(("SRICheckDataVerifier::VerifyHash, hash[%u] verified successfully", aHashIndex));
359 0 : return NS_OK;
360 : }
361 :
362 : nsresult
363 0 : SRICheckDataVerifier::Verify(const SRIMetadata& aMetadata,
364 : nsIChannel* aChannel,
365 : const nsACString& aSourceFileURI,
366 : nsIConsoleReportCollector* aReporter)
367 : {
368 0 : NS_ENSURE_ARG_POINTER(aReporter);
369 :
370 0 : if (MOZ_LOG_TEST(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug)) {
371 0 : nsAutoCString requestURL;
372 0 : nsCOMPtr<nsIRequest> request;
373 0 : request = do_QueryInterface(aChannel);
374 0 : request->GetName(requestURL);
375 0 : SRILOG(("SRICheckDataVerifier::Verify, url=%s (length=%" PRIuSIZE ")",
376 : requestURL.get(), mBytesHashed));
377 : }
378 :
379 0 : nsresult rv = Finish();
380 0 : NS_ENSURE_SUCCESS(rv, rv);
381 :
382 0 : nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
383 0 : NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
384 0 : LoadTainting tainting = loadInfo->GetTainting();
385 :
386 0 : if (NS_FAILED(IsEligible(aChannel, tainting, aSourceFileURI, aReporter))) {
387 0 : return NS_ERROR_SRI_NOT_ELIGIBLE;
388 : }
389 :
390 0 : if (mInvalidMetadata) {
391 0 : return NS_OK; // ignore invalid metadata for forward-compatibility
392 : }
393 :
394 0 : for (uint32_t i = 0; i < aMetadata.HashCount(); i++) {
395 0 : if (NS_SUCCEEDED(VerifyHash(aMetadata, i, aSourceFileURI, aReporter))) {
396 0 : return NS_OK; // stop at the first valid hash
397 : }
398 : }
399 :
400 0 : nsAutoCString alg;
401 0 : aMetadata.GetAlgorithm(&alg);
402 0 : NS_ConvertUTF8toUTF16 algUTF16(alg);
403 0 : nsTArray<nsString> params;
404 0 : params.AppendElement(algUTF16);
405 0 : aReporter->AddConsoleReport(nsIScriptError::errorFlag,
406 0 : NS_LITERAL_CSTRING("Sub-resource Integrity"),
407 : nsContentUtils::eSECURITY_PROPERTIES,
408 : aSourceFileURI, 0, 0,
409 0 : NS_LITERAL_CSTRING("IntegrityMismatch"),
410 0 : const_cast<const nsTArray<nsString>&>(params));
411 0 : return NS_ERROR_SRI_CORRUPT;
412 : }
413 :
414 : uint32_t
415 0 : SRICheckDataVerifier::DataSummaryLength()
416 : {
417 0 : MOZ_ASSERT(!mInvalidMetadata);
418 0 : return sizeof(mHashType) + sizeof(mHashLength) + mHashLength;
419 : }
420 :
421 : uint32_t
422 12 : SRICheckDataVerifier::EmptyDataSummaryLength()
423 : {
424 12 : return sizeof(int8_t) + sizeof(uint32_t);
425 : }
426 :
427 : nsresult
428 4 : SRICheckDataVerifier::DataSummaryLength(uint32_t aDataLen, const uint8_t* aData, uint32_t* length)
429 : {
430 4 : *length = 0;
431 4 : NS_ENSURE_ARG_POINTER(aData);
432 :
433 : // we expect to always encode an SRI, even if it is empty or incomplete
434 4 : if (aDataLen < EmptyDataSummaryLength()) {
435 0 : SRILOG(("SRICheckDataVerifier::DataSummaryLength, encoded length[%u] is too small", aDataLen));
436 0 : return NS_ERROR_SRI_IMPORT;
437 : }
438 :
439 : // decode the content of the buffer
440 4 : size_t offset = sizeof(mHashType);
441 4 : size_t len = *reinterpret_cast<const decltype(mHashLength)*>(&aData[offset]);
442 4 : offset += sizeof(mHashLength);
443 :
444 4 : SRIVERBOSE(("SRICheckDataVerifier::DataSummaryLength, header {%x, %x, %x, %x, %x, ...}",
445 : aData[0], aData[1], aData[2], aData[3], aData[4]));
446 :
447 4 : if (offset + len > aDataLen) {
448 0 : SRILOG(("SRICheckDataVerifier::DataSummaryLength, encoded length[%u] overflow the buffer size", aDataLen));
449 0 : SRIVERBOSE(("SRICheckDataVerifier::DataSummaryLength, offset[%u], len[%u]",
450 : uint32_t(offset), uint32_t(len)));
451 0 : return NS_ERROR_SRI_IMPORT;
452 : }
453 4 : *length = uint32_t(offset + len);
454 4 : return NS_OK;
455 : }
456 :
457 : nsresult
458 0 : SRICheckDataVerifier::ImportDataSummary(uint32_t aDataLen, const uint8_t* aData)
459 : {
460 0 : MOZ_ASSERT(!mInvalidMetadata); // mHashType and mHashLength should be valid
461 0 : MOZ_ASSERT(!mCryptoHash); // EnsureCryptoHash should not have been called
462 0 : NS_ENSURE_ARG_POINTER(aData);
463 0 : if (mInvalidMetadata) {
464 0 : return NS_OK; // ignoring any data updates, see mInvalidMetadata usage
465 : }
466 :
467 : // we expect to always encode an SRI, even if it is empty or incomplete
468 0 : if (aDataLen < DataSummaryLength()) {
469 0 : SRILOG(("SRICheckDataVerifier::ImportDataSummary, encoded length[%u] is too small", aDataLen));
470 0 : return NS_ERROR_SRI_IMPORT;
471 : }
472 :
473 0 : SRIVERBOSE(("SRICheckDataVerifier::ImportDataSummary, header {%x, %x, %x, %x, %x, ...}",
474 : aData[0], aData[1], aData[2], aData[3], aData[4]));
475 :
476 : // decode the content of the buffer
477 0 : size_t offset = 0;
478 0 : if (*reinterpret_cast<const decltype(mHashType)*>(&aData[offset]) != mHashType) {
479 0 : SRILOG(("SRICheckDataVerifier::ImportDataSummary, hash type[%d] does not match[%d]",
480 : *reinterpret_cast<const decltype(mHashType)*>(&aData[offset]),
481 : mHashType));
482 0 : return NS_ERROR_SRI_UNEXPECTED_HASH_TYPE;
483 : }
484 0 : offset += sizeof(mHashType);
485 :
486 0 : if (*reinterpret_cast<const decltype(mHashLength)*>(&aData[offset]) != mHashLength) {
487 0 : SRILOG(("SRICheckDataVerifier::ImportDataSummary, hash length[%d] does not match[%d]",
488 : *reinterpret_cast<const decltype(mHashLength)*>(&aData[offset]),
489 : mHashLength));
490 0 : return NS_ERROR_SRI_UNEXPECTED_HASH_TYPE;
491 : }
492 0 : offset += sizeof(mHashLength);
493 :
494 : // copy the hash to mComputedHash, as-if we had finished streaming the bytes
495 0 : mComputedHash.Assign(reinterpret_cast<const char*>(&aData[offset]), mHashLength);
496 0 : mCryptoHash = nullptr;
497 0 : mComplete = true;
498 0 : return NS_OK;
499 : }
500 :
501 : nsresult
502 0 : SRICheckDataVerifier::ExportDataSummary(uint32_t aDataLen, uint8_t* aData)
503 : {
504 0 : MOZ_ASSERT(!mInvalidMetadata); // mHashType and mHashLength should be valid
505 0 : MOZ_ASSERT(mComplete); // finished streaming
506 0 : NS_ENSURE_ARG_POINTER(aData);
507 0 : NS_ENSURE_TRUE(aDataLen >= DataSummaryLength(), NS_ERROR_INVALID_ARG);
508 :
509 : // serialize the hash in the buffer
510 0 : size_t offset = 0;
511 0 : *reinterpret_cast<decltype(mHashType)*>(&aData[offset]) = mHashType;
512 0 : offset += sizeof(mHashType);
513 0 : *reinterpret_cast<decltype(mHashLength)*>(&aData[offset]) = mHashLength;
514 0 : offset += sizeof(mHashLength);
515 :
516 0 : SRIVERBOSE(("SRICheckDataVerifier::ExportDataSummary, header {%x, %x, %x, %x, %x, ...}",
517 : aData[0], aData[1], aData[2], aData[3], aData[4]));
518 :
519 : // copy the hash to mComputedHash, as-if we had finished streaming the bytes
520 0 : nsCharTraits<char>::copy(reinterpret_cast<char*>(&aData[offset]),
521 0 : mComputedHash.get(), mHashLength);
522 0 : return NS_OK;
523 : }
524 :
525 : nsresult
526 4 : SRICheckDataVerifier::ExportEmptyDataSummary(uint32_t aDataLen, uint8_t* aData)
527 : {
528 4 : NS_ENSURE_ARG_POINTER(aData);
529 4 : NS_ENSURE_TRUE(aDataLen >= EmptyDataSummaryLength(), NS_ERROR_INVALID_ARG);
530 :
531 : // serialize an unknown hash in the buffer, to be able to skip it later
532 4 : size_t offset = 0;
533 4 : *reinterpret_cast<decltype(mHashType)*>(&aData[offset]) = 0;
534 4 : offset += sizeof(mHashType);
535 4 : *reinterpret_cast<decltype(mHashLength)*>(&aData[offset]) = 0;
536 4 : offset += sizeof(mHashLength);
537 :
538 4 : SRIVERBOSE(("SRICheckDataVerifier::ExportEmptyDataSummary, header {%x, %x, %x, %x, %x, ...}",
539 : aData[0], aData[1], aData[2], aData[3], aData[4]));
540 :
541 4 : return NS_OK;
542 : }
543 :
544 : } // namespace dom
545 : } // namespace mozilla
|