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