Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/nsNSSCertificateDB.cpp
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "nsNSSCertificateDB.h"
6
7
#include "CertVerifier.h"
8
#include "CryptoTask.h"
9
#include "ExtendedValidation.h"
10
#include "NSSCertDBTrustDomain.h"
11
#include "SharedSSLState.h"
12
#include "certdb.h"
13
#include "mozilla/Assertions.h"
14
#include "mozilla/Base64.h"
15
#include "mozilla/Casting.h"
16
#include "mozilla/Services.h"
17
#include "mozilla/Unused.h"
18
#include "nsArray.h"
19
#include "nsArrayUtils.h"
20
#include "nsCOMPtr.h"
21
#include "nsComponentManagerUtils.h"
22
#include "nsICertificateDialogs.h"
23
#include "nsIFile.h"
24
#include "nsIMutableArray.h"
25
#include "nsIObserverService.h"
26
#include "nsIPrefBranch.h"
27
#include "nsIPrefService.h"
28
#include "nsIPrompt.h"
29
#include "nsNSSCertHelper.h"
30
#include "nsNSSCertTrust.h"
31
#include "nsNSSCertificate.h"
32
#include "nsNSSComponent.h"
33
#include "nsNSSHelper.h"
34
#include "nsPKCS12Blob.h"
35
#include "nsPromiseFlatString.h"
36
#include "nsProxyRelease.h"
37
#include "nsReadableUtils.h"
38
#include "nsThreadUtils.h"
39
#include "nspr.h"
40
#include "pkix/Time.h"
41
#include "pkix/pkixnss.h"
42
#include "pkix/pkixtypes.h"
43
#include "secasn1.h"
44
#include "secder.h"
45
#include "secerr.h"
46
#include "ssl.h"
47
48
#ifdef XP_WIN
49
#include <winsock.h> // for ntohl
50
#endif
51
52
using namespace mozilla;
53
using namespace mozilla::psm;
54
using mozilla::psm::SharedSSLState;
55
56
extern LazyLogModule gPIPNSSLog;
57
58
NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB)
59
60
NS_IMETHODIMP
61
nsNSSCertificateDB::FindCertByDBKey(const nsACString& aDBKey,
62
                            /*out*/ nsIX509Cert** _cert)
63
0
{
64
0
  NS_ENSURE_ARG_POINTER(_cert);
65
0
  *_cert = nullptr;
66
0
67
0
  if (aDBKey.IsEmpty()) {
68
0
    return NS_ERROR_INVALID_ARG;
69
0
  }
70
0
71
0
  nsresult rv = BlockUntilLoadableRootsLoaded();
72
0
  if (NS_FAILED(rv)) {
73
0
    return rv;
74
0
  }
75
0
76
0
  UniqueCERTCertificate cert;
77
0
  rv = FindCertByDBKey(aDBKey, cert);
78
0
  if (NS_FAILED(rv)) {
79
0
    return rv;
80
0
  }
81
0
  // If we can't find the certificate, that's not an error. Just return null.
82
0
  if (!cert) {
83
0
    return NS_OK;
84
0
  }
85
0
  nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
86
0
  if (!nssCert) {
87
0
    return NS_ERROR_OUT_OF_MEMORY;
88
0
  }
89
0
  nssCert.forget(_cert);
90
0
  return NS_OK;
91
0
}
92
93
nsresult
94
nsNSSCertificateDB::FindCertByDBKey(const nsACString& aDBKey,
95
                                    UniqueCERTCertificate& cert)
96
0
{
97
0
  static_assert(sizeof(uint64_t) == 8, "type size sanity check");
98
0
  static_assert(sizeof(uint32_t) == 4, "type size sanity check");
99
0
  // (From nsNSSCertificate::GetDbKey)
100
0
  // The format of the key is the base64 encoding of the following:
101
0
  // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
102
0
  //                        never implemented)
103
0
  // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
104
0
  //                        never implemented)
105
0
  // 4 bytes: <serial number length in big-endian order>
106
0
  // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
107
0
  // n bytes: <bytes of serial number>
108
0
  // m bytes: <DER-encoded issuer distinguished name>
109
0
  nsAutoCString decoded;
110
0
  nsAutoCString tmpDBKey(aDBKey);
111
0
  // Filter out any whitespace for backwards compatibility.
112
0
  tmpDBKey.StripWhitespace();
113
0
  nsresult rv = Base64Decode(tmpDBKey, decoded);
114
0
  if (NS_FAILED(rv)) {
115
0
    return rv;
116
0
  }
117
0
  if (decoded.Length() < 16) {
118
0
    return NS_ERROR_ILLEGAL_INPUT;
119
0
  }
120
0
  const char* reader = decoded.BeginReading();
121
0
  uint64_t zeroes = *BitwiseCast<const uint64_t*, const char*>(reader);
122
0
  if (zeroes != 0) {
123
0
    return NS_ERROR_ILLEGAL_INPUT;
124
0
  }
125
0
  reader += sizeof(uint64_t);
126
0
  // Note: We surround the ntohl() argument with parentheses to stop the macro
127
0
  //       from thinking two arguments were passed.
128
0
  uint32_t serialNumberLen = ntohl(
129
0
    (*BitwiseCast<const uint32_t*, const char*>(reader)));
130
0
  reader += sizeof(uint32_t);
131
0
  uint32_t issuerLen = ntohl(
132
0
    (*BitwiseCast<const uint32_t*, const char*>(reader)));
133
0
  reader += sizeof(uint32_t);
134
0
  if (decoded.Length() != 16ULL + serialNumberLen + issuerLen) {
135
0
    return NS_ERROR_ILLEGAL_INPUT;
136
0
  }
137
0
  CERTIssuerAndSN issuerSN;
138
0
  issuerSN.serialNumber.len = serialNumberLen;
139
0
  issuerSN.serialNumber.data = BitwiseCast<unsigned char*, const char*>(reader);
140
0
  reader += serialNumberLen;
141
0
  issuerSN.derIssuer.len = issuerLen;
142
0
  issuerSN.derIssuer.data = BitwiseCast<unsigned char*, const char*>(reader);
143
0
  reader += issuerLen;
144
0
  MOZ_ASSERT(reader == decoded.EndReading());
145
0
146
0
  cert.reset(CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN));
147
0
  return NS_OK;
148
0
}
149
150
SECStatus
151
collect_certs(void *arg, SECItem **certs, int numcerts)
152
0
{
153
0
  CERTDERCerts *collectArgs;
154
0
  SECItem *cert;
155
0
  SECStatus rv;
156
0
157
0
  collectArgs = (CERTDERCerts *)arg;
158
0
159
0
  collectArgs->numcerts = numcerts;
160
0
  collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
161
0
                                           sizeof(SECItem) * numcerts);
162
0
  if (!collectArgs->rawCerts)
163
0
    return(SECFailure);
164
0
165
0
  cert = collectArgs->rawCerts;
166
0
167
0
  while ( numcerts-- ) {
168
0
    rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
169
0
    if ( rv == SECFailure )
170
0
      return(SECFailure);
171
0
    cert++;
172
0
    certs++;
173
0
  }
174
0
175
0
  return (SECSuccess);
176
0
}
177
178
CERTDERCerts*
179
nsNSSCertificateDB::getCertsFromPackage(const UniquePLArenaPool& arena,
180
                                        uint8_t* data, uint32_t length)
181
0
{
182
0
  CERTDERCerts* collectArgs = PORT_ArenaZNew(arena.get(), CERTDERCerts);
183
0
  if (!collectArgs) {
184
0
    return nullptr;
185
0
  }
186
0
187
0
  collectArgs->arena = arena.get();
188
0
  if (CERT_DecodeCertPackage(BitwiseCast<char*, uint8_t*>(data), length,
189
0
                             collect_certs, collectArgs) != SECSuccess) {
190
0
    return nullptr;
191
0
  }
192
0
193
0
  return collectArgs;
194
0
}
195
196
// When using the sql-backed softoken, trust settings are authenticated using a
197
// key in the secret database. Thus, if the user has a password, we need to
198
// authenticate to the token in order to be able to change trust settings.
199
SECStatus
200
ChangeCertTrustWithPossibleAuthentication(const UniqueCERTCertificate& cert,
201
                                          CERTCertTrust& trust, void* ctx)
202
0
{
203
0
  MOZ_ASSERT(cert, "cert must be non-null");
204
0
  if (!cert) {
205
0
    PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
206
0
    return SECFailure;
207
0
  }
208
0
  // NSS ignores the first argument to CERT_ChangeCertTrust
209
0
  SECStatus srv = CERT_ChangeCertTrust(nullptr, cert.get(), &trust);
210
0
  if (srv == SECSuccess || PR_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
211
0
    return srv;
212
0
  }
213
0
  if (cert->slot) {
214
0
    // If this certificate is on an external PKCS#11 token, we have to
215
0
    // authenticate to that token.
216
0
    srv = PK11_Authenticate(cert->slot, PR_TRUE, ctx);
217
0
  } else {
218
0
    // Otherwise, the certificate is on the internal module.
219
0
    UniquePK11SlotInfo internalSlot(PK11_GetInternalKeySlot());
220
0
    srv = PK11_Authenticate(internalSlot.get(), PR_TRUE, ctx);
221
0
  }
222
0
  if (srv != SECSuccess) {
223
0
    return srv;
224
0
  }
225
0
  return CERT_ChangeCertTrust(nullptr, cert.get(), &trust);
226
0
}
227
228
static nsresult
229
ImportCertsIntoPermanentStorage(const UniqueCERTCertList& certChain)
230
0
{
231
0
  bool encounteredFailure = false;
232
0
  PRErrorCode savedErrorCode = 0;
233
0
  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
234
0
  for (CERTCertListNode* chainNode = CERT_LIST_HEAD(certChain);
235
0
       !CERT_LIST_END(chainNode, certChain);
236
0
       chainNode = CERT_LIST_NEXT(chainNode)) {
237
0
    UniquePORTString nickname(CERT_MakeCANickname(chainNode->cert));
238
0
    SECStatus srv = PK11_ImportCert(slot.get(), chainNode->cert,
239
0
                                    CK_INVALID_HANDLE, nickname.get(),
240
0
                                    false); // this parameter is ignored by NSS
241
0
    if (srv != SECSuccess) {
242
0
      encounteredFailure = true;
243
0
      savedErrorCode = PR_GetError();
244
0
    }
245
0
  }
246
0
247
0
  if (encounteredFailure) {
248
0
    return GetXPCOMFromNSSError(savedErrorCode);
249
0
  }
250
0
251
0
  return NS_OK;
252
0
}
253
254
nsresult
255
nsNSSCertificateDB::handleCACertDownload(NotNull<nsIArray*> x509Certs,
256
                                         nsIInterfaceRequestor *ctx)
257
0
{
258
0
  // First thing we have to do is figure out which certificate we're
259
0
  // gonna present to the user.  The CA may have sent down a list of
260
0
  // certs which may or may not be a chained list of certs.  Until
261
0
  // the day we can design some solid UI for the general case, we'll
262
0
  // code to the > 90% case.  That case is where a CA sends down a
263
0
  // list that is a hierarchy whose root is either the first or
264
0
  // the last cert.  What we're gonna do is compare the first
265
0
  // 2 entries, if the second was signed by the first, we assume
266
0
  // the root cert is the first cert and display it.  Otherwise,
267
0
  // we compare the last 2 entries, if the second to last cert was
268
0
  // signed by the last cert, then we assume the last cert is the
269
0
  // root and display it.
270
0
271
0
  uint32_t numCerts;
272
0
273
0
  x509Certs->GetLength(&numCerts);
274
0
  MOZ_ASSERT(numCerts > 0, "Didn't get any certs to import.");
275
0
  if (numCerts == 0)
276
0
    return NS_OK; // Nothing to import, so nothing to do.
277
0
278
0
  nsCOMPtr<nsIX509Cert> certToShow;
279
0
  uint32_t selCertIndex;
280
0
  if (numCerts == 1) {
281
0
    // There's only one cert, so let's show it.
282
0
    selCertIndex = 0;
283
0
    certToShow = do_QueryElementAt(x509Certs, selCertIndex);
284
0
  } else {
285
0
    nsCOMPtr<nsIX509Cert> cert0;    // first cert
286
0
    nsCOMPtr<nsIX509Cert> cert1;    // second cert
287
0
    nsCOMPtr<nsIX509Cert> certn_2;  // second to last cert
288
0
    nsCOMPtr<nsIX509Cert> certn_1;  // last cert
289
0
290
0
    cert0 = do_QueryElementAt(x509Certs, 0);
291
0
    cert1 = do_QueryElementAt(x509Certs, 1);
292
0
    certn_2 = do_QueryElementAt(x509Certs, numCerts-2);
293
0
    certn_1 = do_QueryElementAt(x509Certs, numCerts-1);
294
0
295
0
    nsAutoString cert0SubjectName;
296
0
    nsAutoString cert1IssuerName;
297
0
    nsAutoString certn_2IssuerName;
298
0
    nsAutoString certn_1SubjectName;
299
0
300
0
    cert0->GetSubjectName(cert0SubjectName);
301
0
    cert1->GetIssuerName(cert1IssuerName);
302
0
    certn_2->GetIssuerName(certn_2IssuerName);
303
0
    certn_1->GetSubjectName(certn_1SubjectName);
304
0
305
0
    if (cert1IssuerName.Equals(cert0SubjectName)) {
306
0
      // In this case, the first cert in the list signed the second,
307
0
      // so the first cert is the root.  Let's display it.
308
0
      selCertIndex = 0;
309
0
      certToShow = cert0;
310
0
    } else
311
0
    if (certn_2IssuerName.Equals(certn_1SubjectName)) {
312
0
      // In this case the last cert has signed the second to last cert.
313
0
      // The last cert is the root, so let's display it.
314
0
      selCertIndex = numCerts-1;
315
0
      certToShow = certn_1;
316
0
    } else {
317
0
      // It's not a chain, so let's just show the first one in the
318
0
      // downloaded list.
319
0
      selCertIndex = 0;
320
0
      certToShow = cert0;
321
0
    }
322
0
  }
323
0
324
0
  if (!certToShow)
325
0
    return NS_ERROR_FAILURE;
326
0
327
0
  nsCOMPtr<nsICertificateDialogs> dialogs;
328
0
  nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs),
329
0
                                NS_GET_IID(nsICertificateDialogs),
330
0
                                NS_CERTIFICATEDIALOGS_CONTRACTID);
331
0
  if (NS_FAILED(rv)) {
332
0
    return rv;
333
0
  }
334
0
335
0
  UniqueCERTCertificate tmpCert(certToShow->GetCert());
336
0
  if (!tmpCert) {
337
0
    return NS_ERROR_FAILURE;
338
0
  }
339
0
340
0
  if (!CERT_IsCACert(tmpCert.get(), nullptr)) {
341
0
    DisplayCertificateAlert(ctx, "NotACACert", certToShow);
342
0
    return NS_ERROR_FAILURE;
343
0
  }
344
0
345
0
  if (tmpCert->isperm) {
346
0
    DisplayCertificateAlert(ctx, "CaCertExists", certToShow);
347
0
    return NS_ERROR_FAILURE;
348
0
  }
349
0
350
0
  uint32_t trustBits;
351
0
  bool allows;
352
0
  rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows);
353
0
  if (NS_FAILED(rv))
354
0
    return rv;
355
0
356
0
  if (!allows)
357
0
    return NS_ERROR_NOT_AVAILABLE;
358
0
359
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("trust is %d\n", trustBits));
360
0
  UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get()));
361
0
362
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Created nick \"%s\"\n", nickname.get()));
363
0
364
0
  nsNSSCertTrust trust;
365
0
  trust.SetValidCA();
366
0
  trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL),
367
0
                   !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL));
368
0
369
0
  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
370
0
  SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE,
371
0
                                  nickname.get(),
372
0
                                  false); // this parameter is ignored by NSS
373
0
  if (srv != SECSuccess) {
374
0
    return MapSECStatus(srv);
375
0
  }
376
0
  srv = ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(),
377
0
                                                  ctx);
378
0
  if (srv != SECSuccess) {
379
0
    return MapSECStatus(srv);
380
0
  }
381
0
382
0
  // Import additional delivered certificates that can be verified.
383
0
384
0
  // build a CertList for filtering
385
0
  UniqueCERTCertList certList(CERT_NewCertList());
386
0
  if (!certList) {
387
0
    return NS_ERROR_FAILURE;
388
0
  }
389
0
390
0
  // get all remaining certs into temp store
391
0
392
0
  for (uint32_t i=0; i<numCerts; i++) {
393
0
    if (i == selCertIndex) {
394
0
      // we already processed that one
395
0
      continue;
396
0
    }
397
0
398
0
    nsCOMPtr<nsIX509Cert> remainingCert = do_QueryElementAt(x509Certs, i);
399
0
    if (!remainingCert) {
400
0
      continue;
401
0
    }
402
0
403
0
    UniqueCERTCertificate tmpCert2(remainingCert->GetCert());
404
0
    if (!tmpCert2) {
405
0
      continue;  // Let's try to import the rest of 'em
406
0
    }
407
0
408
0
    if (CERT_AddCertToListTail(certList.get(), tmpCert2.get()) != SECSuccess) {
409
0
      continue;
410
0
    }
411
0
412
0
    Unused << tmpCert2.release();
413
0
  }
414
0
415
0
  return ImportCertsIntoPermanentStorage(certList);
416
0
}
417
418
NS_IMETHODIMP
419
nsNSSCertificateDB::ImportCertificates(uint8_t* data, uint32_t length,
420
                                       uint32_t type,
421
                                       nsIInterfaceRequestor* ctx)
422
0
{
423
0
  // We currently only handle CA certificates.
424
0
  if (type != nsIX509Cert::CA_CERT) {
425
0
    return NS_ERROR_FAILURE;
426
0
  }
427
0
428
0
  UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
429
0
  if (!arena) {
430
0
    return NS_ERROR_OUT_OF_MEMORY;
431
0
  }
432
0
433
0
  CERTDERCerts* certCollection = getCertsFromPackage(arena, data, length);
434
0
  if (!certCollection) {
435
0
    return NS_ERROR_FAILURE;
436
0
  }
437
0
438
0
  nsCOMPtr<nsIMutableArray> array = nsArrayBase::Create();
439
0
  if (!array) {
440
0
    return NS_ERROR_FAILURE;
441
0
  }
442
0
443
0
  // Now let's create some certs to work with
444
0
  for (int i = 0; i < certCollection->numcerts; i++) {
445
0
    SECItem* currItem = &certCollection->rawCerts[i];
446
0
    nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::ConstructFromDER(
447
0
      BitwiseCast<char*, unsigned char*>(currItem->data), currItem->len);
448
0
    if (!cert) {
449
0
      return NS_ERROR_FAILURE;
450
0
    }
451
0
    nsresult rv = array->AppendElement(cert);
452
0
    if (NS_FAILED(rv)) {
453
0
      return rv;
454
0
    }
455
0
  }
456
0
457
0
  return handleCACertDownload(WrapNotNull(array), ctx);
458
0
}
459
460
/**
461
 * Decodes a given array of DER-encoded certificates into temporary storage.
462
 *
463
 * @param numcerts
464
 *        Size of the |certs| array.
465
 * @param certs
466
 *        Pointer to array of certs to decode.
467
 * @param temporaryCerts
468
 *        List of decoded certificates.
469
 */
470
static nsresult
471
ImportCertsIntoTempStorage(int numcerts, SECItem* certs,
472
                   /*out*/ const UniqueCERTCertList& temporaryCerts)
473
0
{
474
0
  NS_ENSURE_ARG_MIN(numcerts, 1);
475
0
  NS_ENSURE_ARG_POINTER(certs);
476
0
  NS_ENSURE_ARG_POINTER(temporaryCerts);
477
0
478
0
  // CERT_ImportCerts() expects an array of *pointers* to SECItems, so we have
479
0
  // to convert |certs| to such a format first.
480
0
  SECItem** ptrArray =
481
0
    static_cast<SECItem**>(PORT_Alloc(sizeof(SECItem*) * numcerts));
482
0
  if (!ptrArray) {
483
0
    return NS_ERROR_OUT_OF_MEMORY;
484
0
  }
485
0
486
0
  for (int i = 0; i < numcerts; i++) {
487
0
    ptrArray[i] = &certs[i];
488
0
  }
489
0
490
0
  CERTCertificate** importedCerts = nullptr;
491
0
  SECStatus srv = CERT_ImportCerts(CERT_GetDefaultCertDB(),
492
0
                                   certUsageAnyCA, // this argument is ignored
493
0
                                   numcerts, ptrArray, &importedCerts, false,
494
0
                                   false, // this argument is ignored
495
0
                                   nullptr);
496
0
  PORT_Free(ptrArray);
497
0
  ptrArray = nullptr;
498
0
  if (srv != SECSuccess) {
499
0
    return NS_ERROR_FAILURE;
500
0
  }
501
0
502
0
  for (int i = 0; i < numcerts; i++) {
503
0
    if (!importedCerts[i]) {
504
0
      continue;
505
0
    }
506
0
507
0
    UniqueCERTCertificate cert(CERT_DupCertificate(importedCerts[i]));
508
0
    if (!cert) {
509
0
      continue;
510
0
    }
511
0
512
0
    if (CERT_AddCertToListTail(temporaryCerts.get(), cert.get()) == SECSuccess) {
513
0
      Unused << cert.release();
514
0
    }
515
0
  }
516
0
517
0
  CERT_DestroyCertArray(importedCerts, numcerts);
518
0
519
0
  return NS_OK;
520
0
}
521
522
NS_IMETHODIMP
523
nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data, uint32_t length,
524
                                           nsIInterfaceRequestor* ctx)
525
0
{
526
0
  UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
527
0
  if (!arena) {
528
0
    return NS_ERROR_OUT_OF_MEMORY;
529
0
  }
530
0
531
0
  CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length);
532
0
  if (!certCollection) {
533
0
    return NS_ERROR_FAILURE;
534
0
  }
535
0
536
0
  UniqueCERTCertList temporaryCerts(CERT_NewCertList());
537
0
  if (!temporaryCerts) {
538
0
    return NS_ERROR_FAILURE;
539
0
  }
540
0
541
0
  nsresult rv = ImportCertsIntoTempStorage(certCollection->numcerts,
542
0
                                           certCollection->rawCerts,
543
0
                                           temporaryCerts);
544
0
  if (NS_FAILED(rv)) {
545
0
    return rv;
546
0
  }
547
0
548
0
  return ImportCertsIntoPermanentStorage(temporaryCerts);
549
0
}
550
551
nsresult
552
nsNSSCertificateDB::ImportCACerts(int numCACerts, SECItem* caCerts,
553
                                  nsIInterfaceRequestor* ctx)
554
0
{
555
0
  UniqueCERTCertList temporaryCerts(CERT_NewCertList());
556
0
  if (!temporaryCerts) {
557
0
    return NS_ERROR_FAILURE;
558
0
  }
559
0
560
0
  nsresult rv = ImportCertsIntoTempStorage(numCACerts, caCerts, temporaryCerts);
561
0
  if (NS_FAILED(rv)) {
562
0
    return rv;
563
0
  }
564
0
565
0
  return ImportCertsIntoPermanentStorage(temporaryCerts);
566
0
}
567
568
void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx,
569
                                                 const char *stringID,
570
                                                 nsIX509Cert *certToShow)
571
0
{
572
0
  if (!NS_IsMainThread()) {
573
0
    NS_ERROR("nsNSSCertificateDB::DisplayCertificateAlert called off the main thread");
574
0
    return;
575
0
  }
576
0
577
0
  nsCOMPtr<nsIInterfaceRequestor> my_ctx = ctx;
578
0
  if (!my_ctx) {
579
0
    my_ctx = new PipUIContext();
580
0
  }
581
0
582
0
  // This shall be replaced by embedding ovverridable prompts
583
0
  // as discussed in bug 310446, and should make use of certToShow.
584
0
585
0
  nsAutoString tmpMessage;
586
0
  GetPIPNSSBundleString(stringID, tmpMessage);
587
0
  nsCOMPtr<nsIPrompt> prompt(do_GetInterface(my_ctx));
588
0
  if (!prompt) {
589
0
    return;
590
0
  }
591
0
592
0
  prompt->Alert(nullptr, tmpMessage.get());
593
0
}
594
595
NS_IMETHODIMP
596
nsNSSCertificateDB::ImportUserCertificate(uint8_t* data, uint32_t length,
597
                                          nsIInterfaceRequestor* ctx)
598
0
{
599
0
  if (!NS_IsMainThread()) {
600
0
    NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread");
601
0
    return NS_ERROR_NOT_SAME_THREAD;
602
0
  }
603
0
604
0
  UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
605
0
  if (!arena) {
606
0
    return NS_ERROR_OUT_OF_MEMORY;
607
0
  }
608
0
609
0
  CERTDERCerts* collectArgs = getCertsFromPackage(arena, data, length);
610
0
  if (!collectArgs) {
611
0
    return NS_ERROR_FAILURE;
612
0
  }
613
0
614
0
  UniqueCERTCertificate cert(
615
0
    CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
616
0
                            nullptr, false, true));
617
0
  if (!cert) {
618
0
    return NS_ERROR_FAILURE;
619
0
  }
620
0
621
0
  UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert.get(), nullptr, ctx));
622
0
  if (!slot) {
623
0
    nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
624
0
    DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow);
625
0
    return NS_ERROR_FAILURE;
626
0
  }
627
0
  slot = nullptr;
628
0
629
0
  /* pick a nickname for the cert */
630
0
  nsAutoCString nickname;
631
0
  if (cert->nickname) {
632
0
    nickname = cert->nickname;
633
0
  } else {
634
0
    get_default_nickname(cert.get(), ctx, nickname);
635
0
  }
636
0
637
0
  /* user wants to import the cert */
638
0
  slot.reset(PK11_ImportCertForKey(cert.get(), nickname.get(), ctx));
639
0
  if (!slot) {
640
0
    return NS_ERROR_FAILURE;
641
0
  }
642
0
  slot = nullptr;
643
0
644
0
  {
645
0
    nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
646
0
    DisplayCertificateAlert(ctx, "UserCertImported", certToShow);
647
0
  }
648
0
649
0
  nsresult rv = NS_OK;
650
0
  int numCACerts = collectArgs->numcerts - 1;
651
0
  if (numCACerts) {
652
0
    SECItem* caCerts = collectArgs->rawCerts + 1;
653
0
    rv = ImportCACerts(numCACerts, caCerts, ctx);
654
0
  }
655
0
656
0
  nsCOMPtr<nsIObserverService> observerService =
657
0
    mozilla::services::GetObserverService();
658
0
  if (observerService) {
659
0
    observerService->NotifyObservers(nullptr, "psm:user-certificate-added", nullptr);
660
0
  }
661
0
662
0
  return rv;
663
0
}
664
665
NS_IMETHODIMP
666
nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
667
0
{
668
0
  NS_ENSURE_ARG_POINTER(aCert);
669
0
  UniqueCERTCertificate cert(aCert->GetCert());
670
0
  if (!cert) {
671
0
    return NS_ERROR_FAILURE;
672
0
  }
673
0
  SECStatus srv = SECSuccess;
674
0
675
0
  uint32_t certType;
676
0
  aCert->GetCertType(&certType);
677
0
  if (NS_FAILED(aCert->MarkForPermDeletion()))
678
0
  {
679
0
    return NS_ERROR_FAILURE;
680
0
  }
681
0
682
0
  if (cert->slot && certType != nsIX509Cert::USER_CERT) {
683
0
    // To delete a cert of a slot (builtin, most likely), mark it as
684
0
    // completely untrusted.  This way we keep a copy cached in the
685
0
    // local database, and next time we try to load it off of the
686
0
    // external token/slot, we'll know not to trust it.  We don't
687
0
    // want to do that with user certs, because a user may  re-store
688
0
    // the cert onto the card again at which point we *will* want to
689
0
    // trust that cert if it chains up properly.
690
0
    nsNSSCertTrust trust(0, 0);
691
0
    srv = ChangeCertTrustWithPossibleAuthentication(cert, trust.GetTrust(),
692
0
                                                    nullptr);
693
0
  }
694
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("cert deleted: %d", srv));
695
0
696
0
  nsCOMPtr<nsIObserverService> observerService =
697
0
    mozilla::services::GetObserverService();
698
0
  if (observerService) {
699
0
    observerService->NotifyObservers(nullptr, "psm:user-certificate-deleted", nullptr);
700
0
  }
701
0
702
0
  return (srv) ? NS_ERROR_FAILURE : NS_OK;
703
0
}
704
705
NS_IMETHODIMP
706
nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
707
                                 uint32_t type,
708
                                 uint32_t trusted)
709
0
{
710
0
  NS_ENSURE_ARG_POINTER(cert);
711
0
  nsNSSCertTrust trust;
712
0
  switch (type) {
713
0
    case nsIX509Cert::CA_CERT:
714
0
      trust.SetValidCA();
715
0
      trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL),
716
0
                       !!(trusted & nsIX509CertDB::TRUSTED_EMAIL));
717
0
      break;
718
0
    case nsIX509Cert::SERVER_CERT:
719
0
      trust.SetValidPeer();
720
0
      trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, false);
721
0
      break;
722
0
    case nsIX509Cert::EMAIL_CERT:
723
0
      trust.SetValidPeer();
724
0
      trust.AddPeerTrust(false, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL));
725
0
      break;
726
0
    default:
727
0
      // Ignore any other type of certificate (including invalid types).
728
0
      return NS_OK;
729
0
  }
730
0
731
0
  UniqueCERTCertificate nsscert(cert->GetCert());
732
0
  SECStatus srv = ChangeCertTrustWithPossibleAuthentication(nsscert,
733
0
                                                            trust.GetTrust(),
734
0
                                                            nullptr);
735
0
  return MapSECStatus(srv);
736
0
}
737
738
NS_IMETHODIMP
739
nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert,
740
                                  uint32_t certType,
741
                                  uint32_t trustType,
742
                                  bool *_isTrusted)
743
0
{
744
0
  NS_ENSURE_ARG_POINTER(_isTrusted);
745
0
  *_isTrusted = false;
746
0
747
0
  nsresult rv = BlockUntilLoadableRootsLoaded();
748
0
  if (NS_FAILED(rv)) {
749
0
    return rv;
750
0
  }
751
0
752
0
  SECStatus srv;
753
0
  UniqueCERTCertificate nsscert(cert->GetCert());
754
0
  CERTCertTrust nsstrust;
755
0
  srv = CERT_GetCertTrust(nsscert.get(), &nsstrust);
756
0
  if (srv != SECSuccess)
757
0
    return NS_ERROR_FAILURE;
758
0
759
0
  nsNSSCertTrust trust(&nsstrust);
760
0
  if (certType == nsIX509Cert::CA_CERT) {
761
0
    if (trustType & nsIX509CertDB::TRUSTED_SSL) {
762
0
      *_isTrusted = trust.HasTrustedCA(true, false);
763
0
    } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
764
0
      *_isTrusted = trust.HasTrustedCA(false, true);
765
0
    } else {
766
0
      return NS_ERROR_FAILURE;
767
0
    }
768
0
  } else if (certType == nsIX509Cert::SERVER_CERT) {
769
0
    if (trustType & nsIX509CertDB::TRUSTED_SSL) {
770
0
      *_isTrusted = trust.HasTrustedPeer(true, false);
771
0
    } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
772
0
      *_isTrusted = trust.HasTrustedPeer(false, true);
773
0
    } else {
774
0
      return NS_ERROR_FAILURE;
775
0
    }
776
0
  } else if (certType == nsIX509Cert::EMAIL_CERT) {
777
0
    if (trustType & nsIX509CertDB::TRUSTED_SSL) {
778
0
      *_isTrusted = trust.HasTrustedPeer(true, false);
779
0
    } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
780
0
      *_isTrusted = trust.HasTrustedPeer(false, true);
781
0
    } else {
782
0
      return NS_ERROR_FAILURE;
783
0
    }
784
0
  } /* user: ignore */
785
0
  return NS_OK;
786
0
}
787
788
789
NS_IMETHODIMP
790
nsNSSCertificateDB::ImportCertsFromFile(nsIFile* aFile, uint32_t aType)
791
0
{
792
0
  NS_ENSURE_ARG(aFile);
793
0
  switch (aType) {
794
0
    case nsIX509Cert::CA_CERT:
795
0
    case nsIX509Cert::EMAIL_CERT:
796
0
      // good
797
0
      break;
798
0
799
0
    default:
800
0
      // not supported (yet)
801
0
      return NS_ERROR_FAILURE;
802
0
  }
803
0
804
0
  PRFileDesc* fd = nullptr;
805
0
  nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
806
0
  if (NS_FAILED(rv)) {
807
0
    return rv;
808
0
  }
809
0
  if (!fd) {
810
0
    return NS_ERROR_FAILURE;
811
0
  }
812
0
813
0
  PRFileInfo fileInfo;
814
0
  if (PR_GetOpenFileInfo(fd, &fileInfo) != PR_SUCCESS) {
815
0
    return NS_ERROR_FAILURE;
816
0
  }
817
0
818
0
  auto buf = MakeUnique<unsigned char[]>(fileInfo.size);
819
0
  int32_t bytesObtained = PR_Read(fd, buf.get(), fileInfo.size);
820
0
  PR_Close(fd);
821
0
822
0
  if (bytesObtained != fileInfo.size) {
823
0
    return NS_ERROR_FAILURE;
824
0
  }
825
0
826
0
  nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
827
0
828
0
  switch (aType) {
829
0
    case nsIX509Cert::CA_CERT:
830
0
      return ImportCertificates(buf.get(), bytesObtained, aType, cxt);
831
0
    case nsIX509Cert::EMAIL_CERT:
832
0
      return ImportEmailCertificate(buf.get(), bytesObtained, cxt);
833
0
    default:
834
0
      MOZ_ASSERT(false, "Unsupported type should have been filtered out");
835
0
      break;
836
0
  }
837
0
838
0
  return NS_ERROR_FAILURE;
839
0
}
840
841
NS_IMETHODIMP
842
nsNSSCertificateDB::ImportPKCS12File(nsIFile* aFile, const nsAString& aPassword,
843
                                     uint32_t* aError)
844
0
{
845
0
  if (!NS_IsMainThread()) {
846
0
    return NS_ERROR_NOT_SAME_THREAD;
847
0
  }
848
0
  nsresult rv = BlockUntilLoadableRootsLoaded();
849
0
  if (NS_FAILED(rv)) {
850
0
    return rv;
851
0
  }
852
0
853
0
  NS_ENSURE_ARG(aFile);
854
0
  nsPKCS12Blob blob;
855
0
  rv = blob.ImportFromFile(aFile, aPassword, *aError);
856
0
  nsCOMPtr<nsIObserverService> observerService =
857
0
    mozilla::services::GetObserverService();
858
0
  if (NS_SUCCEEDED(rv) && observerService) {
859
0
    observerService->NotifyObservers(nullptr, "psm:user-certificate-added", nullptr);
860
0
  }
861
0
862
0
  return rv;
863
0
}
864
865
NS_IMETHODIMP
866
nsNSSCertificateDB::ExportPKCS12File(nsIFile* aFile, uint32_t aCount,
867
                                     nsIX509Cert** aCerts,
868
                                     const nsAString& aPassword,
869
                                     uint32_t* aError)
870
0
{
871
0
  if (!NS_IsMainThread()) {
872
0
    return NS_ERROR_NOT_SAME_THREAD;
873
0
  }
874
0
  nsresult rv = BlockUntilLoadableRootsLoaded();
875
0
  if (NS_FAILED(rv)) {
876
0
    return rv;
877
0
  }
878
0
879
0
  NS_ENSURE_ARG(aFile);
880
0
  if (aCount == 0) {
881
0
    return NS_OK;
882
0
  }
883
0
  nsPKCS12Blob blob;
884
0
  return blob.ExportToFile(aFile, aCerts, aCount, aPassword, *aError);
885
0
}
886
887
NS_IMETHODIMP
888
nsNSSCertificateDB::ConstructX509FromBase64(const nsACString& base64,
889
                                    /*out*/ nsIX509Cert** _retval)
890
0
{
891
0
  if (!_retval) {
892
0
    return NS_ERROR_INVALID_POINTER;
893
0
  }
894
0
895
0
  // Base64Decode() doesn't consider a zero length input as an error, and just
896
0
  // returns the empty string. We don't want this behavior, so the below check
897
0
  // catches this case.
898
0
  if (base64.Length() < 1) {
899
0
    return NS_ERROR_ILLEGAL_VALUE;
900
0
  }
901
0
902
0
  nsAutoCString certDER;
903
0
  nsresult rv = Base64Decode(base64, certDER);
904
0
  if (NS_FAILED(rv)) {
905
0
    return rv;
906
0
  }
907
0
908
0
  return ConstructX509(certDER, _retval);
909
0
}
910
911
NS_IMETHODIMP
912
nsNSSCertificateDB::ConstructX509(const nsACString& certDER,
913
                                  nsIX509Cert** _retval)
914
0
{
915
0
  if (NS_WARN_IF(!_retval)) {
916
0
    return NS_ERROR_INVALID_POINTER;
917
0
  }
918
0
919
0
  SECItem certData;
920
0
  certData.type = siDERCertBuffer;
921
0
  certData.data = BitwiseCast<unsigned char*, const char*>(certDER.BeginReading());
922
0
  certData.len = certDER.Length();
923
0
924
0
  UniqueCERTCertificate cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
925
0
                                                     &certData, nullptr,
926
0
                                                     false, true));
927
0
  if (!cert)
928
0
    return (PORT_GetError() == SEC_ERROR_NO_MEMORY)
929
0
      ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_FAILURE;
930
0
931
0
  nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
932
0
  if (!nssCert) {
933
0
    return NS_ERROR_OUT_OF_MEMORY;
934
0
  }
935
0
  nssCert.forget(_retval);
936
0
  return NS_OK;
937
0
}
938
939
void
940
nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert,
941
                                         nsIInterfaceRequestor* ctx,
942
                                         nsCString &nickname)
943
0
{
944
0
  nickname.Truncate();
945
0
946
0
  CK_OBJECT_HANDLE keyHandle;
947
0
948
0
  if (NS_FAILED(BlockUntilLoadableRootsLoaded())) {
949
0
    return;
950
0
  }
951
0
952
0
  CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
953
0
  nsAutoCString username;
954
0
  UniquePORTString tempCN(CERT_GetCommonName(&cert->subject));
955
0
  if (tempCN) {
956
0
    username = tempCN.get();
957
0
  }
958
0
959
0
  nsAutoCString caname;
960
0
  UniquePORTString tempIssuerOrg(CERT_GetOrgName(&cert->issuer));
961
0
  if (tempIssuerOrg) {
962
0
    caname = tempIssuerOrg.get();
963
0
  }
964
0
965
0
  nsAutoString tmpNickFmt;
966
0
  GetPIPNSSBundleString("nick_template", tmpNickFmt);
967
0
  NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt);
968
0
969
0
  nsAutoCString baseName;
970
0
  baseName.AppendPrintf(nickFmt.get(), username.get(), caname.get());
971
0
  if (baseName.IsEmpty()) {
972
0
    return;
973
0
  }
974
0
975
0
  nickname = baseName;
976
0
977
0
  /*
978
0
   * We need to see if the private key exists on a token, if it does
979
0
   * then we need to check for nicknames that already exist on the smart
980
0
   * card.
981
0
   */
982
0
  UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx));
983
0
  if (!slot)
984
0
    return;
985
0
986
0
  if (!PK11_IsInternal(slot.get())) {
987
0
    nsAutoCString tmp;
988
0
    tmp.AppendPrintf("%s:%s", PK11_GetTokenName(slot.get()), baseName.get());
989
0
    if (tmp.IsEmpty()) {
990
0
      nickname.Truncate();
991
0
      return;
992
0
    }
993
0
    baseName = tmp;
994
0
    nickname = baseName;
995
0
  }
996
0
997
0
  int count = 1;
998
0
  while (true) {
999
0
    if ( count > 1 ) {
1000
0
      nsAutoCString tmp;
1001
0
      tmp.AppendPrintf("%s #%d", baseName.get(), count);
1002
0
      if (tmp.IsEmpty()) {
1003
0
        nickname.Truncate();
1004
0
        return;
1005
0
      }
1006
0
      nickname = tmp;
1007
0
    }
1008
0
1009
0
    UniqueCERTCertificate dummycert;
1010
0
1011
0
    if (PK11_IsInternal(slot.get())) {
1012
0
      /* look up the nickname to make sure it isn't in use already */
1013
0
      dummycert.reset(CERT_FindCertByNickname(defaultcertdb, nickname.get()));
1014
0
    } else {
1015
0
      // Check the cert against others that already live on the smart card.
1016
0
      dummycert.reset(PK11_FindCertFromNickname(nickname.get(), ctx));
1017
0
      if (dummycert) {
1018
0
  // Make sure the subject names are different.
1019
0
  if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
1020
0
  {
1021
0
    /*
1022
0
     * There is another certificate with the same nickname and
1023
0
     * the same subject name on the smart card, so let's use this
1024
0
     * nickname.
1025
0
     */
1026
0
    dummycert = nullptr;
1027
0
  }
1028
0
      }
1029
0
    }
1030
0
    if (!dummycert) {
1031
0
      break;
1032
0
    }
1033
0
    count++;
1034
0
  }
1035
0
}
1036
1037
NS_IMETHODIMP
1038
nsNSSCertificateDB::AddCertFromBase64(const nsACString& aBase64,
1039
                                      const nsACString& aTrust,
1040
                                      nsIX509Cert** addedCertificate)
1041
0
{
1042
0
  MOZ_ASSERT(addedCertificate);
1043
0
  if (!addedCertificate) {
1044
0
    return NS_ERROR_INVALID_ARG;
1045
0
  }
1046
0
  *addedCertificate = nullptr;
1047
0
1048
0
  nsNSSCertTrust trust;
1049
0
  if (CERT_DecodeTrustString(&trust.GetTrust(), PromiseFlatCString(aTrust).get())
1050
0
        != SECSuccess) {
1051
0
    return NS_ERROR_FAILURE;
1052
0
  }
1053
0
1054
0
  nsCOMPtr<nsIX509Cert> newCert;
1055
0
  nsresult rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert));
1056
0
  if (NS_FAILED(rv)) {
1057
0
    return rv;
1058
0
  }
1059
0
1060
0
  UniqueCERTCertificate tmpCert(newCert->GetCert());
1061
0
  if (!tmpCert) {
1062
0
    return NS_ERROR_FAILURE;
1063
0
  }
1064
0
1065
0
  // If there's already a certificate that matches this one in the database, we
1066
0
  // still want to set its trust to the given value.
1067
0
  if (tmpCert->isperm) {
1068
0
    rv = SetCertTrustFromString(newCert, aTrust);
1069
0
    if (NS_FAILED(rv)) {
1070
0
      return rv;
1071
0
    }
1072
0
    newCert.forget(addedCertificate);
1073
0
    return NS_OK;
1074
0
  }
1075
0
1076
0
  UniquePORTString nickname(CERT_MakeCANickname(tmpCert.get()));
1077
0
1078
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Created nick \"%s\"\n", nickname.get()));
1079
0
1080
0
  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
1081
0
  SECStatus srv = PK11_ImportCert(slot.get(), tmpCert.get(), CK_INVALID_HANDLE,
1082
0
                                  nickname.get(),
1083
0
                                  false); // this parameter is ignored by NSS
1084
0
  if (srv != SECSuccess) {
1085
0
    return MapSECStatus(srv);
1086
0
  }
1087
0
  srv = ChangeCertTrustWithPossibleAuthentication(tmpCert, trust.GetTrust(),
1088
0
                                                  nullptr);
1089
0
  if (srv != SECSuccess) {
1090
0
    return MapSECStatus(srv);
1091
0
  }
1092
0
  newCert.forget(addedCertificate);
1093
0
  return NS_OK;
1094
0
}
1095
1096
NS_IMETHODIMP
1097
nsNSSCertificateDB::AddCert(const nsACString& aCertDER,
1098
                            const nsACString& aTrust,
1099
                            nsIX509Cert** addedCertificate)
1100
0
{
1101
0
  nsCString base64;
1102
0
  nsresult rv = Base64Encode(aCertDER, base64);
1103
0
  NS_ENSURE_SUCCESS(rv, rv);
1104
0
  return AddCertFromBase64(base64, aTrust, addedCertificate);
1105
0
}
1106
1107
NS_IMETHODIMP
1108
nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert* cert,
1109
                                           const nsACString& trustString)
1110
0
{
1111
0
  NS_ENSURE_ARG(cert);
1112
0
1113
0
  CERTCertTrust trust;
1114
0
  SECStatus srv = CERT_DecodeTrustString(&trust,
1115
0
                                         PromiseFlatCString(trustString).get());
1116
0
  if (srv != SECSuccess) {
1117
0
    return MapSECStatus(srv);
1118
0
  }
1119
0
  UniqueCERTCertificate nssCert(cert->GetCert());
1120
0
1121
0
  srv = ChangeCertTrustWithPossibleAuthentication(nssCert, trust, nullptr);
1122
0
  return MapSECStatus(srv);
1123
0
}
1124
1125
NS_IMETHODIMP
1126
nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval)
1127
0
{
1128
0
  nsresult rv = BlockUntilLoadableRootsLoaded();
1129
0
  if (NS_FAILED(rv)) {
1130
0
    return rv;
1131
0
  }
1132
0
1133
0
  rv = CheckForSmartCardChanges();
1134
0
  if (NS_FAILED(rv)) {
1135
0
    return rv;
1136
0
  }
1137
0
1138
0
  nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
1139
0
  nsCOMPtr<nsIX509CertList> nssCertList;
1140
0
  UniqueCERTCertList certList(PK11_ListCerts(PK11CertListUnique, ctx));
1141
0
1142
0
  // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine.
1143
0
  // (returns an empty list)
1144
0
  nssCertList = new nsNSSCertList(std::move(certList));
1145
0
1146
0
  nssCertList.forget(_retval);
1147
0
  return NS_OK;
1148
0
}
1149
1150
NS_IMETHODIMP
1151
nsNSSCertificateDB::GetEnterpriseRoots(nsIX509CertList** enterpriseRoots)
1152
0
{
1153
0
  MOZ_ASSERT(NS_IsMainThread());
1154
0
  if (!NS_IsMainThread()) {
1155
0
    return NS_ERROR_NOT_SAME_THREAD;
1156
0
  }
1157
0
1158
0
  NS_ENSURE_ARG_POINTER(enterpriseRoots);
1159
0
1160
#ifdef XP_WIN
1161
  nsCOMPtr<nsINSSComponent> psm(do_GetService(PSM_COMPONENT_CONTRACTID));
1162
  if (!psm) {
1163
    return NS_ERROR_FAILURE;
1164
  }
1165
  return psm->GetEnterpriseRoots(enterpriseRoots);
1166
#else
1167
0
  return NS_ERROR_NOT_IMPLEMENTED;
1168
0
#endif
1169
0
}
1170
1171
nsresult
1172
VerifyCertAtTime(nsIX509Cert* aCert,
1173
                 int64_t /*SECCertificateUsage*/ aUsage,
1174
                 uint32_t aFlags,
1175
                 const nsACString& aHostname,
1176
                 mozilla::pkix::Time aTime,
1177
                 nsIX509CertList** aVerifiedChain,
1178
                 bool* aHasEVPolicy,
1179
                 int32_t* /*PRErrorCode*/ _retval)
1180
0
{
1181
0
  NS_ENSURE_ARG_POINTER(aCert);
1182
0
  NS_ENSURE_ARG_POINTER(aHasEVPolicy);
1183
0
  NS_ENSURE_ARG_POINTER(aVerifiedChain);
1184
0
  NS_ENSURE_ARG_POINTER(_retval);
1185
0
1186
0
  *aVerifiedChain = nullptr;
1187
0
  *aHasEVPolicy = false;
1188
0
  *_retval = PR_UNKNOWN_ERROR;
1189
0
1190
0
  UniqueCERTCertificate nssCert(aCert->GetCert());
1191
0
  if (!nssCert) {
1192
0
    return NS_ERROR_INVALID_ARG;
1193
0
  }
1194
0
1195
0
  RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
1196
0
  NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
1197
0
1198
0
  UniqueCERTCertList resultChain;
1199
0
  SECOidTag evOidPolicy;
1200
0
  mozilla::pkix::Result result;
1201
0
1202
0
  if (!aHostname.IsVoid() && aUsage == certificateUsageSSLServer) {
1203
0
    result = certVerifier->VerifySSLServerCert(nssCert,
1204
0
                                               nullptr, // stapledOCSPResponse
1205
0
                                               nullptr, // sctsFromTLSExtension
1206
0
                                               aTime,
1207
0
                                               nullptr, // Assume no context
1208
0
                                               aHostname,
1209
0
                                               resultChain,
1210
0
                                               false, // don't save intermediates
1211
0
                                               aFlags,
1212
0
                                               OriginAttributes(),
1213
0
                                               &evOidPolicy);
1214
0
  } else {
1215
0
    const nsCString& flatHostname = PromiseFlatCString(aHostname);
1216
0
    result = certVerifier->VerifyCert(nssCert.get(), aUsage, aTime,
1217
0
                                      nullptr, // Assume no context
1218
0
                                      aHostname.IsVoid() ? nullptr
1219
0
                                                         : flatHostname.get(),
1220
0
                                      resultChain,
1221
0
                                      aFlags,
1222
0
                                      nullptr, // stapledOCSPResponse
1223
0
                                      nullptr, // sctsFromTLSExtension
1224
0
                                      OriginAttributes(),
1225
0
                                      &evOidPolicy);
1226
0
  }
1227
0
1228
0
  nsCOMPtr<nsIX509CertList> nssCertList;
1229
0
  // This adopts the list
1230
0
  nssCertList = new nsNSSCertList(std::move(resultChain));
1231
0
  NS_ENSURE_TRUE(nssCertList, NS_ERROR_FAILURE);
1232
0
1233
0
  *_retval = mozilla::pkix::MapResultToPRErrorCode(result);
1234
0
  if (result == mozilla::pkix::Success && evOidPolicy != SEC_OID_UNKNOWN) {
1235
0
    *aHasEVPolicy = true;
1236
0
  }
1237
0
  nssCertList.forget(aVerifiedChain);
1238
0
1239
0
  return NS_OK;
1240
0
}
1241
1242
class VerifyCertAtTimeTask final : public CryptoTask
1243
{
1244
public:
1245
  VerifyCertAtTimeTask(nsIX509Cert* aCert, int64_t aUsage, uint32_t aFlags,
1246
                       const nsACString& aHostname, uint64_t aTime,
1247
                       nsICertVerificationCallback* aCallback)
1248
    : mCert(aCert)
1249
    , mUsage(aUsage)
1250
    , mFlags(aFlags)
1251
    , mHostname(aHostname)
1252
    , mTime(aTime)
1253
    , mCallback(new nsMainThreadPtrHolder<nsICertVerificationCallback>(
1254
        "nsICertVerificationCallback", aCallback))
1255
    , mPRErrorCode(SEC_ERROR_LIBRARY_FAILURE)
1256
    , mVerifiedCertList(nullptr)
1257
    , mHasEVPolicy(false)
1258
0
  {
1259
0
  }
1260
1261
private:
1262
  virtual nsresult CalculateResult() override
1263
0
  {
1264
0
    nsCOMPtr<nsIX509CertDB> certDB = do_GetService(NS_X509CERTDB_CONTRACTID);
1265
0
    if (!certDB) {
1266
0
      return NS_ERROR_FAILURE;
1267
0
    }
1268
0
    return VerifyCertAtTime(mCert, mUsage, mFlags, mHostname,
1269
0
                            mozilla::pkix::TimeFromEpochInSeconds(mTime),
1270
0
                            getter_AddRefs(mVerifiedCertList),
1271
0
                            &mHasEVPolicy, &mPRErrorCode);
1272
0
  }
1273
1274
  virtual void CallCallback(nsresult rv) override
1275
0
  {
1276
0
    if (NS_FAILED(rv)) {
1277
0
      Unused << mCallback->VerifyCertFinished(SEC_ERROR_LIBRARY_FAILURE,
1278
0
                                              nullptr, false);
1279
0
    } else {
1280
0
      Unused << mCallback->VerifyCertFinished(mPRErrorCode, mVerifiedCertList,
1281
0
                                              mHasEVPolicy);
1282
0
    }
1283
0
  }
1284
1285
  nsCOMPtr<nsIX509Cert> mCert;
1286
  int64_t mUsage;
1287
  uint32_t mFlags;
1288
  nsCString mHostname;
1289
  uint64_t mTime;
1290
  nsMainThreadPtrHandle<nsICertVerificationCallback> mCallback;
1291
  int32_t mPRErrorCode;
1292
  nsCOMPtr<nsIX509CertList> mVerifiedCertList;
1293
  bool mHasEVPolicy;
1294
};
1295
1296
NS_IMETHODIMP
1297
nsNSSCertificateDB::AsyncVerifyCertAtTime(nsIX509Cert* aCert,
1298
                                          int64_t /*SECCertificateUsage*/ aUsage,
1299
                                          uint32_t aFlags,
1300
                                          const nsACString& aHostname,
1301
                                          uint64_t aTime,
1302
                                          nsICertVerificationCallback* aCallback)
1303
0
{
1304
0
  RefPtr<VerifyCertAtTimeTask> task(new VerifyCertAtTimeTask(aCert, aUsage,
1305
0
                                                             aFlags, aHostname,
1306
0
                                                             aTime, aCallback));
1307
0
  return task->Dispatch("VerifyCert");
1308
0
}
1309
1310
NS_IMETHODIMP
1311
nsNSSCertificateDB::ClearOCSPCache()
1312
0
{
1313
0
  RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
1314
0
  NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
1315
0
  certVerifier->ClearOCSPCache();
1316
0
  return NS_OK;
1317
0
}