Coverage Report

Created: 2018-09-25 14:53

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