1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=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 "ContentSignatureVerifier.h"
8
9 #include "BRNameMatchingPolicy.h"
10 #include "SharedCertVerifier.h"
11 #include "cryptohi.h"
12 #include "keyhi.h"
13 #include "mozilla/Assertions.h"
14 #include "mozilla/Base64.h"
15 #include "mozilla/Casting.h"
16 #include "mozilla/Unused.h"
17 #include "nsCOMPtr.h"
18 #include "nsContentUtils.h"
19 #include "nsISupportsPriority.h"
20 #include "nsIURI.h"
21 #include "nsNSSComponent.h"
22 #include "nsPromiseFlatString.h"
23 #include "nsSecurityHeaderParser.h"
24 #include "nsStreamUtils.h"
25 #include "nsWhitespaceTokenizer.h"
26 #include "pkix/pkix.h"
27 #include "pkix/pkixtypes.h"
28 #include "secerr.h"
29
30 NS_IMPL_ISUPPORTS(ContentSignatureVerifier, nsIContentSignatureVerifier,
31 nsIInterfaceRequestor, nsIStreamListener)
32
33 using namespace mozilla;
34 using namespace mozilla::pkix;
35 using namespace mozilla::psm;
36
37 static LazyLogModule gCSVerifierPRLog("ContentSignatureVerifier");
38 #define CSVerifier_LOG(args) MOZ_LOG(gCSVerifierPRLog, LogLevel::Debug, args)
39
40 // Content-Signature prefix
41 const nsLiteralCString kPREFIX = NS_LITERAL_CSTRING("Content-Signature:\x00");
42
43 NS_IMETHODIMP
VerifyContentSignature(const nsACString & aData,const nsACString & aCSHeader,const nsACString & aCertChain,const nsACString & aName,bool * _retval)44 ContentSignatureVerifier::VerifyContentSignature(const nsACString& aData,
45 const nsACString& aCSHeader,
46 const nsACString& aCertChain,
47 const nsACString& aName,
48 bool* _retval) {
49 NS_ENSURE_ARG(_retval);
50 nsresult rv = CreateContext(aData, aCSHeader, aCertChain, aName);
51 if (NS_FAILED(rv)) {
52 *_retval = false;
53 CSVerifier_LOG(("CSVerifier: Signature verification failed\n"));
54 if (rv == NS_ERROR_INVALID_SIGNATURE) {
55 return NS_OK;
56 }
57 // This failure can have many different reasons but we don't treat it as
58 // invalid signature.
59 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 3);
60 Telemetry::AccumulateCategoricalKeyed(
61 mFingerprint,
62 Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err3);
63 return rv;
64 }
65
66 return End(_retval);
67 }
68
IsNewLine(char16_t c)69 bool IsNewLine(char16_t c) { return c == '\n' || c == '\r'; }
70
ReadChainIntoCertList(const nsACString & aCertChain,CERTCertList * aCertList)71 nsresult ReadChainIntoCertList(const nsACString& aCertChain,
72 CERTCertList* aCertList) {
73 bool inBlock = false;
74 bool certFound = false;
75
76 const nsCString header = NS_LITERAL_CSTRING("-----BEGIN CERTIFICATE-----");
77 const nsCString footer = NS_LITERAL_CSTRING("-----END CERTIFICATE-----");
78
79 nsCWhitespaceTokenizerTemplate<IsNewLine> tokenizer(aCertChain);
80
81 nsAutoCString blockData;
82 while (tokenizer.hasMoreTokens()) {
83 nsDependentCSubstring token = tokenizer.nextToken();
84 if (token.IsEmpty()) {
85 continue;
86 }
87 if (inBlock) {
88 if (token.Equals(footer)) {
89 inBlock = false;
90 certFound = true;
91 // base64 decode data, make certs, append to chain
92 nsAutoCString derString;
93 nsresult rv = Base64Decode(blockData, derString);
94 if (NS_FAILED(rv)) {
95 CSVerifier_LOG(("CSVerifier: decoding the signature failed\n"));
96 return rv;
97 }
98 SECItem der = {
99 siBuffer,
100 BitwiseCast<unsigned char*, const char*>(derString.get()),
101 derString.Length(),
102 };
103 UniqueCERTCertificate tmpCert(CERT_NewTempCertificate(
104 CERT_GetDefaultCertDB(), &der, nullptr, false, true));
105 if (!tmpCert) {
106 return NS_ERROR_FAILURE;
107 }
108 // if adding tmpCert succeeds, tmpCert will now be owned by aCertList
109 SECStatus res = CERT_AddCertToListTail(aCertList, tmpCert.get());
110 if (res != SECSuccess) {
111 return MapSECStatus(res);
112 }
113 Unused << tmpCert.release();
114 } else {
115 blockData.Append(token);
116 }
117 } else if (token.Equals(header)) {
118 inBlock = true;
119 blockData = "";
120 }
121 }
122 if (inBlock || !certFound) {
123 // the PEM data did not end; bad data.
124 CSVerifier_LOG(("CSVerifier: supplied chain contains bad data\n"));
125 return NS_ERROR_FAILURE;
126 }
127 return NS_OK;
128 }
129
CreateContextInternal(const nsACString & aData,const nsACString & aCertChain,const nsACString & aName)130 nsresult ContentSignatureVerifier::CreateContextInternal(
131 const nsACString& aData, const nsACString& aCertChain,
132 const nsACString& aName) {
133 MOZ_ASSERT(NS_IsMainThread());
134
135 UniqueCERTCertList certCertList(CERT_NewCertList());
136 if (!certCertList) {
137 return NS_ERROR_OUT_OF_MEMORY;
138 }
139
140 nsresult rv = ReadChainIntoCertList(aCertChain, certCertList.get());
141 if (NS_FAILED(rv)) {
142 return rv;
143 }
144
145 CERTCertListNode* node = CERT_LIST_HEAD(certCertList.get());
146 if (!node || CERT_LIST_END(node, certCertList.get()) || !node->cert) {
147 return NS_ERROR_FAILURE;
148 }
149
150 SECItem* certSecItem = &node->cert->derCert;
151
152 Input certDER;
153 mozilla::pkix::Result result =
154 certDER.Init(BitwiseCast<uint8_t*, unsigned char*>(certSecItem->data),
155 certSecItem->len);
156 if (result != Success) {
157 return NS_ERROR_FAILURE;
158 }
159
160 // Get EE certificate fingerprint for telemetry.
161 unsigned char fingerprint[SHA256_LENGTH] = {0};
162 SECStatus srv = PK11_HashBuf(SEC_OID_SHA256, fingerprint, certSecItem->data,
163 AssertedCast<int32_t>(certSecItem->len));
164 if (srv != SECSuccess) {
165 return NS_ERROR_FAILURE;
166 }
167 SECItem fingerprintItem = {siBuffer, fingerprint, SHA256_LENGTH};
168 mFingerprint.Truncate();
169 UniquePORTString tmpFingerprintString(CERT_Hexify(&fingerprintItem, 0));
170 mFingerprint.Append(tmpFingerprintString.get());
171
172 // Check the signerCert chain is good
173 CSTrustDomain trustDomain(certCertList);
174 result = BuildCertChain(
175 trustDomain, certDER, Now(), EndEntityOrCA::MustBeEndEntity,
176 KeyUsage::noParticularKeyUsageRequired, KeyPurposeId::id_kp_codeSigning,
177 CertPolicyId::anyPolicy, nullptr /*stapledOCSPResponse*/);
178 if (result != Success) {
179 // if there was a library error, return an appropriate error
180 if (IsFatalError(result)) {
181 return NS_ERROR_FAILURE;
182 }
183 // otherwise, assume the signature was invalid
184 if (result == mozilla::pkix::Result::ERROR_EXPIRED_CERTIFICATE) {
185 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 4);
186 Telemetry::AccumulateCategoricalKeyed(
187 mFingerprint,
188 Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err4);
189 } else if (result ==
190 mozilla::pkix::Result::ERROR_NOT_YET_VALID_CERTIFICATE) {
191 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 5);
192 Telemetry::AccumulateCategoricalKeyed(
193 mFingerprint,
194 Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err5);
195 } else {
196 // Building cert chain failed for some other reason.
197 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 6);
198 Telemetry::AccumulateCategoricalKeyed(
199 mFingerprint,
200 Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err6);
201 }
202 CSVerifier_LOG(("CSVerifier: The supplied chain is bad (%s)\n",
203 MapResultToName(result)));
204 return NS_ERROR_INVALID_SIGNATURE;
205 }
206
207 // Check the SAN
208 Input hostnameInput;
209
210 result = hostnameInput.Init(
211 BitwiseCast<const uint8_t*, const char*>(aName.BeginReading()),
212 aName.Length());
213 if (result != Success) {
214 return NS_ERROR_FAILURE;
215 }
216
217 BRNameMatchingPolicy nameMatchingPolicy(BRNameMatchingPolicy::Mode::Enforce);
218 result = CheckCertHostname(certDER, hostnameInput, nameMatchingPolicy);
219 if (result != Success) {
220 // EE cert isnot valid for the given host name.
221 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 7);
222 Telemetry::AccumulateCategoricalKeyed(
223 mFingerprint,
224 Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err7);
225 return NS_ERROR_INVALID_SIGNATURE;
226 }
227
228 mKey.reset(CERT_ExtractPublicKey(node->cert));
229
230 // in case we were not able to extract a key
231 if (!mKey) {
232 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 8);
233 Telemetry::AccumulateCategoricalKeyed(
234 mFingerprint,
235 Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err8);
236 CSVerifier_LOG(("CSVerifier: unable to extract a key\n"));
237 return NS_ERROR_INVALID_SIGNATURE;
238 }
239
240 // Base 64 decode the signature
241 nsAutoCString rawSignature;
242 rv = Base64Decode(mSignature, rawSignature);
243 if (NS_FAILED(rv)) {
244 CSVerifier_LOG(("CSVerifier: decoding the signature failed\n"));
245 return rv;
246 }
247
248 // get signature object
249 ScopedAutoSECItem signatureItem;
250 SECItem rawSignatureItem = {
251 siBuffer,
252 BitwiseCast<unsigned char*, const char*>(rawSignature.get()),
253 rawSignature.Length(),
254 };
255 // We have a raw ecdsa signature r||s so we have to DER-encode it first
256 // Note that we have to check rawSignatureItem->len % 2 here as
257 // DSAU_EncodeDerSigWithLen asserts this
258 if (rawSignatureItem.len == 0 || rawSignatureItem.len % 2 != 0) {
259 CSVerifier_LOG(("CSVerifier: signature length is bad\n"));
260 return NS_ERROR_FAILURE;
261 }
262 if (DSAU_EncodeDerSigWithLen(&signatureItem, &rawSignatureItem,
263 rawSignatureItem.len) != SECSuccess) {
264 CSVerifier_LOG(("CSVerifier: encoding the signature failed\n"));
265 return NS_ERROR_FAILURE;
266 }
267
268 // this is the only OID we support for now
269 SECOidTag oid = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE;
270
271 mCx = UniqueVFYContext(
272 VFY_CreateContext(mKey.get(), &signatureItem, oid, nullptr));
273 if (!mCx) {
274 // Creating context failed.
275 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 9);
276 Telemetry::AccumulateCategoricalKeyed(
277 mFingerprint,
278 Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err9);
279 return NS_ERROR_INVALID_SIGNATURE;
280 }
281
282 if (VFY_Begin(mCx.get()) != SECSuccess) {
283 // Creating context failed.
284 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 9);
285 Telemetry::AccumulateCategoricalKeyed(
286 mFingerprint,
287 Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err9);
288 return NS_ERROR_INVALID_SIGNATURE;
289 }
290
291 rv = UpdateInternal(kPREFIX);
292 if (NS_FAILED(rv)) {
293 return rv;
294 }
295 // add data if we got any
296 return UpdateInternal(aData);
297 }
298
DownloadCertChain()299 nsresult ContentSignatureVerifier::DownloadCertChain() {
300 MOZ_ASSERT(NS_IsMainThread());
301
302 if (mCertChainURL.IsEmpty()) {
303 return NS_ERROR_INVALID_SIGNATURE;
304 }
305
306 nsCOMPtr<nsIURI> certChainURI;
307 nsresult rv = NS_NewURI(getter_AddRefs(certChainURI), mCertChainURL);
308 if (NS_FAILED(rv) || !certChainURI) {
309 return rv;
310 }
311
312 // If the address is not https, fail.
313 bool isHttps = false;
314 rv = certChainURI->SchemeIs("https", &isHttps);
315 if (NS_FAILED(rv)) {
316 return rv;
317 }
318 if (!isHttps) {
319 return NS_ERROR_INVALID_SIGNATURE;
320 }
321
322 rv = NS_NewChannel(getter_AddRefs(mChannel), certChainURI,
323 nsContentUtils::GetSystemPrincipal(),
324 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
325 nsIContentPolicy::TYPE_OTHER);
326 if (NS_FAILED(rv)) {
327 return rv;
328 }
329
330 // we need this chain soon
331 nsCOMPtr<nsISupportsPriority> priorityChannel = do_QueryInterface(mChannel);
332 if (priorityChannel) {
333 priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
334 }
335
336 rv = mChannel->AsyncOpen2(this);
337 if (NS_FAILED(rv)) {
338 return rv;
339 }
340
341 return NS_OK;
342 }
343
344 // Create a context for content signature verification using CreateContext
345 // below. This function doesn't require a cert chain to be passed, but instead
346 // aCSHeader must contain an x5u value that is then used to download the cert
347 // chain.
348 NS_IMETHODIMP
CreateContextWithoutCertChain(nsIContentSignatureReceiverCallback * aCallback,const nsACString & aCSHeader,const nsACString & aName)349 ContentSignatureVerifier::CreateContextWithoutCertChain(
350 nsIContentSignatureReceiverCallback* aCallback, const nsACString& aCSHeader,
351 const nsACString& aName) {
352 MOZ_ASSERT(NS_IsMainThread());
353 MOZ_ASSERT(aCallback);
354 if (mInitialised) {
355 return NS_ERROR_ALREADY_INITIALIZED;
356 }
357 mInitialised = true;
358
359 // we get the raw content-signature header here, so first parse aCSHeader
360 nsresult rv = ParseContentSignatureHeader(aCSHeader);
361 if (NS_FAILED(rv)) {
362 return rv;
363 }
364
365 mCallback = aCallback;
366 mName.Assign(aName);
367
368 // We must download the cert chain now.
369 // This is async and blocks createContextInternal calls.
370 return DownloadCertChain();
371 }
372
373 // Create a context for a content signature verification.
374 // It sets signature, certificate chain and name that should be used to verify
375 // the data. The data parameter is the first part of the data to verify (this
376 // can be the empty string).
377 NS_IMETHODIMP
CreateContext(const nsACString & aData,const nsACString & aCSHeader,const nsACString & aCertChain,const nsACString & aName)378 ContentSignatureVerifier::CreateContext(const nsACString& aData,
379 const nsACString& aCSHeader,
380 const nsACString& aCertChain,
381 const nsACString& aName) {
382 if (mInitialised) {
383 return NS_ERROR_ALREADY_INITIALIZED;
384 }
385 mInitialised = true;
386 // The cert chain is given in aCertChain so we don't have to download
387 // anything.
388 mHasCertChain = true;
389
390 // we get the raw content-signature header here, so first parse aCSHeader
391 nsresult rv = ParseContentSignatureHeader(aCSHeader);
392 if (NS_FAILED(rv)) {
393 return rv;
394 }
395
396 return CreateContextInternal(aData, aCertChain, aName);
397 }
398
UpdateInternal(const nsACString & aData)399 nsresult ContentSignatureVerifier::UpdateInternal(const nsACString& aData) {
400 if (!aData.IsEmpty()) {
401 if (VFY_Update(mCx.get(),
402 (const unsigned char*)nsPromiseFlatCString(aData).get(),
403 aData.Length()) != SECSuccess) {
404 return NS_ERROR_INVALID_SIGNATURE;
405 }
406 }
407 return NS_OK;
408 }
409
410 /**
411 * Add data to the context that shold be verified.
412 */
413 NS_IMETHODIMP
Update(const nsACString & aData)414 ContentSignatureVerifier::Update(const nsACString& aData) {
415 MOZ_ASSERT(NS_IsMainThread());
416
417 // If we didn't create the context yet, bail!
418 if (!mHasCertChain) {
419 MOZ_ASSERT_UNREACHABLE(
420 "Someone called ContentSignatureVerifier::Update before "
421 "downloading the cert chain.");
422 return NS_ERROR_FAILURE;
423 }
424
425 return UpdateInternal(aData);
426 }
427
428 /**
429 * Finish signature verification and return the result in _retval.
430 */
431 NS_IMETHODIMP
End(bool * _retval)432 ContentSignatureVerifier::End(bool* _retval) {
433 NS_ENSURE_ARG(_retval);
434 MOZ_ASSERT(NS_IsMainThread());
435
436 // If we didn't create the context yet, bail!
437 if (!mHasCertChain) {
438 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 2);
439 MOZ_ASSERT_UNREACHABLE(
440 "Someone called ContentSignatureVerifier::End before "
441 "downloading the cert chain.");
442 return NS_ERROR_FAILURE;
443 }
444
445 bool result = (VFY_End(mCx.get()) == SECSuccess);
446 if (result) {
447 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 0);
448 } else {
449 Accumulate(Telemetry::CONTENT_SIGNATURE_VERIFICATION_STATUS, 1);
450 Telemetry::AccumulateCategoricalKeyed(
451 mFingerprint,
452 Telemetry::LABELS_CONTENT_SIGNATURE_VERIFICATION_ERRORS::err1);
453 }
454 *_retval = result;
455
456 return NS_OK;
457 }
458
ParseContentSignatureHeader(const nsACString & aContentSignatureHeader)459 nsresult ContentSignatureVerifier::ParseContentSignatureHeader(
460 const nsACString& aContentSignatureHeader) {
461 MOZ_ASSERT(NS_IsMainThread());
462 // We only support p384 ecdsa according to spec
463 NS_NAMED_LITERAL_CSTRING(signature_var, "p384ecdsa");
464 NS_NAMED_LITERAL_CSTRING(certChainURL_var, "x5u");
465
466 const nsCString& flatHeader = PromiseFlatCString(aContentSignatureHeader);
467 nsSecurityHeaderParser parser(flatHeader);
468 nsresult rv = parser.Parse();
469 if (NS_FAILED(rv)) {
470 CSVerifier_LOG(("CSVerifier: could not parse ContentSignature header\n"));
471 return NS_ERROR_FAILURE;
472 }
473 LinkedList<nsSecurityHeaderDirective>* directives = parser.GetDirectives();
474
475 for (nsSecurityHeaderDirective* directive = directives->getFirst();
476 directive != nullptr; directive = directive->getNext()) {
477 CSVerifier_LOG(
478 ("CSVerifier: found directive %s\n", directive->mName.get()));
479 if (directive->mName.Length() == signature_var.Length() &&
480 directive->mName.EqualsIgnoreCase(signature_var.get(),
481 signature_var.Length())) {
482 if (!mSignature.IsEmpty()) {
483 CSVerifier_LOG(("CSVerifier: found two ContentSignatures\n"));
484 return NS_ERROR_INVALID_SIGNATURE;
485 }
486
487 CSVerifier_LOG(("CSVerifier: found a ContentSignature directive\n"));
488 mSignature = directive->mValue;
489 }
490 if (directive->mName.Length() == certChainURL_var.Length() &&
491 directive->mName.EqualsIgnoreCase(certChainURL_var.get(),
492 certChainURL_var.Length())) {
493 if (!mCertChainURL.IsEmpty()) {
494 CSVerifier_LOG(("CSVerifier: found two x5u values\n"));
495 return NS_ERROR_INVALID_SIGNATURE;
496 }
497
498 CSVerifier_LOG(("CSVerifier: found an x5u directive\n"));
499 mCertChainURL = directive->mValue;
500 }
501 }
502
503 // we have to ensure that we found a signature at this point
504 if (mSignature.IsEmpty()) {
505 CSVerifier_LOG(
506 ("CSVerifier: got a Content-Signature header but didn't find a "
507 "signature.\n"));
508 return NS_ERROR_FAILURE;
509 }
510
511 // Bug 769521: We have to change b64 url to regular encoding as long as we
512 // don't have a b64 url decoder. This should change soon, but in the meantime
513 // we have to live with this.
514 mSignature.ReplaceChar('-', '+');
515 mSignature.ReplaceChar('_', '/');
516
517 return NS_OK;
518 }
519
520 /* nsIStreamListener implementation */
521
522 NS_IMETHODIMP
OnStartRequest(nsIRequest * aRequest,nsISupports * aContext)523 ContentSignatureVerifier::OnStartRequest(nsIRequest* aRequest,
524 nsISupports* aContext) {
525 MOZ_ASSERT(NS_IsMainThread());
526 return NS_OK;
527 }
528
529 NS_IMETHODIMP
OnStopRequest(nsIRequest * aRequest,nsISupports * aContext,nsresult aStatus)530 ContentSignatureVerifier::OnStopRequest(nsIRequest* aRequest,
531 nsISupports* aContext,
532 nsresult aStatus) {
533 MOZ_ASSERT(NS_IsMainThread());
534 nsCOMPtr<nsIContentSignatureReceiverCallback> callback;
535 callback.swap(mCallback);
536 nsresult rv;
537
538 // Check HTTP status code and return if it's not 200.
539 nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest, &rv);
540 uint32_t httpResponseCode;
541 if (NS_FAILED(rv) || NS_FAILED(http->GetResponseStatus(&httpResponseCode)) ||
542 httpResponseCode != 200) {
543 callback->ContextCreated(false);
544 return NS_OK;
545 }
546
547 if (NS_FAILED(aStatus)) {
548 callback->ContextCreated(false);
549 return NS_OK;
550 }
551
552 nsAutoCString certChain;
553 for (uint32_t i = 0; i < mCertChain.Length(); ++i) {
554 certChain.Append(mCertChain[i]);
555 }
556
557 // We got the cert chain now. Let's create the context.
558 rv = CreateContextInternal(NS_LITERAL_CSTRING(""), certChain, mName);
559 if (NS_FAILED(rv)) {
560 callback->ContextCreated(false);
561 return NS_OK;
562 }
563
564 mHasCertChain = true;
565 callback->ContextCreated(true);
566 return NS_OK;
567 }
568
569 NS_IMETHODIMP
OnDataAvailable(nsIRequest * aRequest,nsISupports * aContext,nsIInputStream * aInputStream,uint64_t aOffset,uint32_t aCount)570 ContentSignatureVerifier::OnDataAvailable(nsIRequest* aRequest,
571 nsISupports* aContext,
572 nsIInputStream* aInputStream,
573 uint64_t aOffset, uint32_t aCount) {
574 MOZ_ASSERT(NS_IsMainThread());
575 nsAutoCString buffer;
576
577 nsresult rv = NS_ConsumeStream(aInputStream, aCount, buffer);
578 if (NS_FAILED(rv)) {
579 return rv;
580 }
581
582 if (!mCertChain.AppendElement(buffer, fallible)) {
583 mCertChain.TruncateLength(0);
584 return NS_ERROR_OUT_OF_MEMORY;
585 }
586
587 return NS_OK;
588 }
589
590 NS_IMETHODIMP
GetInterface(const nsIID & uuid,void ** result)591 ContentSignatureVerifier::GetInterface(const nsIID& uuid, void** result) {
592 return QueryInterface(uuid, result);
593 }
594