security/manager/ssl/src/nsNSSCertificateDB.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:284e0b8561dd
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 // XXX: This must be done prior to including cert.h (directly or indirectly).
6 // CERT_AddTempCertToPerm is exposed as __CERT_AddTempCertToPerm, but it is
7 // only exported so PSM can use it for this specific purpose.
8 #define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
9
10 #include "nsNSSComponent.h"
11 #include "nsNSSCertificateDB.h"
12
13 #include "CertVerifier.h"
14 #include "ExtendedValidation.h"
15 #include "NSSCertDBTrustDomain.h"
16 #include "pkix/pkixtypes.h"
17 #include "nsNSSComponent.h"
18 #include "mozilla/Base64.h"
19 #include "nsCOMPtr.h"
20 #include "nsNSSCertificate.h"
21 #include "nsNSSHelper.h"
22 #include "nsNSSCertHelper.h"
23 #include "nsNSSCertCache.h"
24 #include "nsCRT.h"
25 #include "nsICertificateDialogs.h"
26 #include "nsNSSCertTrust.h"
27 #include "nsIFile.h"
28 #include "nsPKCS12Blob.h"
29 #include "nsPK11TokenDB.h"
30 #include "nsReadableUtils.h"
31 #include "nsIMutableArray.h"
32 #include "nsArrayUtils.h"
33 #include "nsNSSShutDown.h"
34 #include "nsIPrefService.h"
35 #include "nsIPrefBranch.h"
36 #include "nsComponentManagerUtils.h"
37 #include "nsIPrompt.h"
38 #include "nsThreadUtils.h"
39 #include "nsIObserverService.h"
40 #include "nsRecentBadCerts.h"
41 #include "SharedSSLState.h"
42
43 #include "nspr.h"
44 #include "certdb.h"
45 #include "secerr.h"
46 #include "nssb64.h"
47 #include "secasn1.h"
48 #include "secder.h"
49 #include "ssl.h"
50 #include "ocsp.h"
51 #include "plbase64.h"
52
53 using namespace mozilla;
54 using namespace mozilla::psm;
55 using mozilla::psm::SharedSSLState;
56
57 #ifdef PR_LOGGING
58 extern PRLogModuleInfo* gPIPNSSLog;
59 #endif
60
61 static nsresult
62 attemptToLogInWithDefaultPassword()
63 {
64 #ifdef NSS_DISABLE_DBM
65 // The SQL NSS DB requires the user to be authenticated to set certificate
66 // trust settings, even if the user's password is empty. To maintain
67 // compatibility with the DBM-based database, try to log in with the
68 // default empty password. This will allow, at least, tests that need to
69 // change certificate trust to pass on all platforms. TODO(bug 978120): Do
70 // proper testing and/or implement a better solution so that we are confident
71 // that this does the correct thing outside of xpcshell tests too.
72 ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
73 if (!slot) {
74 return MapSECStatus(SECFailure);
75 }
76 if (PK11_NeedUserInit(slot)) {
77 // Ignore the return value. Presumably PK11_InitPin will fail if the user
78 // has a non-default password.
79 (void) PK11_InitPin(slot, nullptr, nullptr);
80 }
81 #endif
82
83 return NS_OK;
84 }
85
86 NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2)
87
88 nsNSSCertificateDB::nsNSSCertificateDB()
89 : mBadCertsLock("nsNSSCertificateDB::mBadCertsLock")
90 {
91 SharedSSLState::NoteCertDBServiceInstantiated();
92 }
93
94 nsNSSCertificateDB::~nsNSSCertificateDB()
95 {
96 nsNSSShutDownPreventionLock locker;
97 if (isAlreadyShutDown()) {
98 return;
99 }
100
101 shutdown(calledFromObject);
102 }
103
104 NS_IMETHODIMP
105 nsNSSCertificateDB::FindCertByNickname(nsISupports *aToken,
106 const nsAString &nickname,
107 nsIX509Cert **_rvCert)
108 {
109 NS_ENSURE_ARG_POINTER(_rvCert);
110 *_rvCert = nullptr;
111
112 nsNSSShutDownPreventionLock locker;
113 if (isAlreadyShutDown()) {
114 return NS_ERROR_NOT_AVAILABLE;
115 }
116 mozilla::pkix::ScopedCERTCertificate cert;
117 char *asciiname = nullptr;
118 NS_ConvertUTF16toUTF8 aUtf8Nickname(nickname);
119 asciiname = const_cast<char*>(aUtf8Nickname.get());
120 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));
121 cert = PK11_FindCertFromNickname(asciiname, nullptr);
122 if (!cert) {
123 cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname);
124 }
125 if (cert) {
126 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n"));
127 nsCOMPtr<nsIX509Cert> pCert = nsNSSCertificate::Create(cert.get());
128 if (pCert) {
129 pCert.forget(_rvCert);
130 return NS_OK;
131 }
132 }
133 return NS_ERROR_FAILURE;
134 }
135
136 NS_IMETHODIMP
137 nsNSSCertificateDB::FindCertByDBKey(const char *aDBkey, nsISupports *aToken,
138 nsIX509Cert **_cert)
139 {
140 NS_ENSURE_ARG_POINTER(aDBkey);
141 NS_ENSURE_ARG(aDBkey[0]);
142 NS_ENSURE_ARG_POINTER(_cert);
143 *_cert = nullptr;
144
145 nsNSSShutDownPreventionLock locker;
146 if (isAlreadyShutDown()) {
147 return NS_ERROR_NOT_AVAILABLE;
148 }
149
150 SECItem keyItem = {siBuffer, nullptr, 0};
151 SECItem *dummy;
152 CERTIssuerAndSN issuerSN;
153 //unsigned long moduleID,slotID;
154
155 dummy = NSSBase64_DecodeBuffer(nullptr, &keyItem, aDBkey,
156 (uint32_t)strlen(aDBkey));
157 if (!dummy || keyItem.len < NS_NSS_LONG*4) {
158 PR_FREEIF(keyItem.data);
159 return NS_ERROR_INVALID_ARG;
160 }
161
162 mozilla::pkix::ScopedCERTCertificate cert;
163 // someday maybe we can speed up the search using the moduleID and slotID
164 // moduleID = NS_NSS_GET_LONG(keyItem.data);
165 // slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]);
166
167 // build the issuer/SN structure
168 issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]);
169 issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]);
170 if (issuerSN.serialNumber.len == 0 || issuerSN.derIssuer.len == 0
171 || issuerSN.serialNumber.len + issuerSN.derIssuer.len
172 != keyItem.len - NS_NSS_LONG*4) {
173 PR_FREEIF(keyItem.data);
174 return NS_ERROR_INVALID_ARG;
175 }
176 issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4];
177 issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG*4+
178 issuerSN.serialNumber.len];
179
180 cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN);
181 PR_FREEIF(keyItem.data);
182 if (cert) {
183 nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
184 if (!nssCert)
185 return NS_ERROR_OUT_OF_MEMORY;
186 nssCert.forget(_cert);
187 }
188 return NS_OK;
189 }
190
191 NS_IMETHODIMP
192 nsNSSCertificateDB::FindCertNicknames(nsISupports *aToken,
193 uint32_t aType,
194 uint32_t *_count,
195 char16_t ***_certNames)
196 {
197 nsNSSShutDownPreventionLock locker;
198 if (isAlreadyShutDown()) {
199 return NS_ERROR_NOT_AVAILABLE;
200 }
201
202 nsresult rv = NS_ERROR_FAILURE;
203 /*
204 * obtain the cert list from NSS
205 */
206 mozilla::pkix::ScopedCERTCertList certList;
207 certList = PK11_ListCerts(PK11CertListUnique, nullptr);
208 if (!certList)
209 goto cleanup;
210 /*
211 * get list of cert names from list of certs
212 * XXX also cull the list (NSS only distinguishes based on user/non-user
213 */
214 getCertNames(certList.get(), aType, _count, _certNames, locker);
215 rv = NS_OK;
216 /*
217 * finish up
218 */
219 cleanup:
220 return rv;
221 }
222
223 SECStatus
224 collect_certs(void *arg, SECItem **certs, int numcerts)
225 {
226 CERTDERCerts *collectArgs;
227 SECItem *cert;
228 SECStatus rv;
229
230 collectArgs = (CERTDERCerts *)arg;
231
232 collectArgs->numcerts = numcerts;
233 collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
234 sizeof(SECItem) * numcerts);
235 if (!collectArgs->rawCerts)
236 return(SECFailure);
237
238 cert = collectArgs->rawCerts;
239
240 while ( numcerts-- ) {
241 rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
242 if ( rv == SECFailure )
243 return(SECFailure);
244 cert++;
245 certs++;
246 }
247
248 return (SECSuccess);
249 }
250
251 CERTDERCerts*
252 nsNSSCertificateDB::getCertsFromPackage(PLArenaPool *arena, uint8_t *data,
253 uint32_t length,
254 const nsNSSShutDownPreventionLock &/*proofOfLock*/)
255 {
256 CERTDERCerts *collectArgs =
257 (CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts));
258 if (!collectArgs)
259 return nullptr;
260
261 collectArgs->arena = arena;
262 SECStatus sec_rv = CERT_DecodeCertPackage(reinterpret_cast<char *>(data),
263 length, collect_certs,
264 (void *)collectArgs);
265 if (sec_rv != SECSuccess)
266 return nullptr;
267
268 return collectArgs;
269 }
270
271 nsresult
272 nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs,
273 nsIInterfaceRequestor *ctx,
274 const nsNSSShutDownPreventionLock &proofOfLock)
275 {
276 // First thing we have to do is figure out which certificate we're
277 // gonna present to the user. The CA may have sent down a list of
278 // certs which may or may not be a chained list of certs. Until
279 // the day we can design some solid UI for the general case, we'll
280 // code to the > 90% case. That case is where a CA sends down a
281 // list that is a hierarchy whose root is either the first or
282 // the last cert. What we're gonna do is compare the first
283 // 2 entries, if the second was signed by the first, we assume
284 // the root cert is the first cert and display it. Otherwise,
285 // we compare the last 2 entries, if the second to last cert was
286 // signed by the last cert, then we assume the last cert is the
287 // root and display it.
288
289 uint32_t numCerts;
290
291 x509Certs->GetLength(&numCerts);
292 NS_ASSERTION(numCerts > 0, "Didn't get any certs to import.");
293 if (numCerts == 0)
294 return NS_OK; // Nothing to import, so nothing to do.
295
296 nsCOMPtr<nsIX509Cert> certToShow;
297 nsCOMPtr<nsISupports> isupports;
298 uint32_t selCertIndex;
299 if (numCerts == 1) {
300 // There's only one cert, so let's show it.
301 selCertIndex = 0;
302 certToShow = do_QueryElementAt(x509Certs, selCertIndex);
303 } else {
304 nsCOMPtr<nsIX509Cert> cert0; // first cert
305 nsCOMPtr<nsIX509Cert> cert1; // second cert
306 nsCOMPtr<nsIX509Cert> certn_2; // second to last cert
307 nsCOMPtr<nsIX509Cert> certn_1; // last cert
308
309 cert0 = do_QueryElementAt(x509Certs, 0);
310 cert1 = do_QueryElementAt(x509Certs, 1);
311 certn_2 = do_QueryElementAt(x509Certs, numCerts-2);
312 certn_1 = do_QueryElementAt(x509Certs, numCerts-1);
313
314 nsXPIDLString cert0SubjectName;
315 nsXPIDLString cert1IssuerName;
316 nsXPIDLString certn_2IssuerName;
317 nsXPIDLString certn_1SubjectName;
318
319 cert0->GetSubjectName(cert0SubjectName);
320 cert1->GetIssuerName(cert1IssuerName);
321 certn_2->GetIssuerName(certn_2IssuerName);
322 certn_1->GetSubjectName(certn_1SubjectName);
323
324 if (cert1IssuerName.Equals(cert0SubjectName)) {
325 // In this case, the first cert in the list signed the second,
326 // so the first cert is the root. Let's display it.
327 selCertIndex = 0;
328 certToShow = cert0;
329 } else
330 if (certn_2IssuerName.Equals(certn_1SubjectName)) {
331 // In this case the last cert has signed the second to last cert.
332 // The last cert is the root, so let's display it.
333 selCertIndex = numCerts-1;
334 certToShow = certn_1;
335 } else {
336 // It's not a chain, so let's just show the first one in the
337 // downloaded list.
338 selCertIndex = 0;
339 certToShow = cert0;
340 }
341 }
342
343 if (!certToShow)
344 return NS_ERROR_FAILURE;
345
346 nsCOMPtr<nsICertificateDialogs> dialogs;
347 nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs),
348 NS_GET_IID(nsICertificateDialogs),
349 NS_CERTIFICATEDIALOGS_CONTRACTID);
350
351 if (NS_FAILED(rv))
352 return rv;
353
354 SECItem der;
355 rv=certToShow->GetRawDER(&der.len, (uint8_t **)&der.data);
356
357 if (NS_FAILED(rv))
358 return rv;
359
360 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));
361 mozilla::pkix::ScopedCERTCertificate tmpCert;
362 CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
363 tmpCert = CERT_FindCertByDERCert(certdb, &der);
364 if (!tmpCert) {
365 tmpCert = CERT_NewTempCertificate(certdb, &der,
366 nullptr, false, true);
367 }
368 nsMemory::Free(der.data);
369 der.data = nullptr;
370 der.len = 0;
371
372 if (!tmpCert) {
373 NS_ERROR("Couldn't create cert from DER blob");
374 return NS_ERROR_FAILURE;
375 }
376
377 if (!CERT_IsCACert(tmpCert.get(), nullptr)) {
378 DisplayCertificateAlert(ctx, "NotACACert", certToShow, proofOfLock);
379 return NS_ERROR_FAILURE;
380 }
381
382 if (tmpCert->isperm) {
383 DisplayCertificateAlert(ctx, "CaCertExists", certToShow, proofOfLock);
384 return NS_ERROR_FAILURE;
385 }
386
387 uint32_t trustBits;
388 bool allows;
389 rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows);
390 if (NS_FAILED(rv))
391 return rv;
392
393 if (!allows)
394 return NS_ERROR_NOT_AVAILABLE;
395
396 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits));
397 nsXPIDLCString nickname;
398 nickname.Adopt(CERT_MakeCANickname(tmpCert.get()));
399
400 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));
401
402 nsNSSCertTrust trust;
403 trust.SetValidCA();
404 trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL),
405 !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL),
406 !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN));
407
408 SECStatus srv = __CERT_AddTempCertToPerm(tmpCert.get(),
409 const_cast<char*>(nickname.get()),
410 trust.GetTrust());
411
412 if (srv != SECSuccess)
413 return NS_ERROR_FAILURE;
414
415 // Import additional delivered certificates that can be verified.
416
417 // build a CertList for filtering
418 mozilla::pkix::ScopedCERTCertList certList(CERT_NewCertList());
419 if (!certList) {
420 return NS_ERROR_FAILURE;
421 }
422
423 // get all remaining certs into temp store
424
425 for (uint32_t i=0; i<numCerts; i++) {
426 if (i == selCertIndex) {
427 // we already processed that one
428 continue;
429 }
430
431 certToShow = do_QueryElementAt(x509Certs, i);
432 certToShow->GetRawDER(&der.len, (uint8_t **)&der.data);
433
434 CERTCertificate *tmpCert2 =
435 CERT_NewTempCertificate(certdb, &der, nullptr, false, true);
436
437 nsMemory::Free(der.data);
438 der.data = nullptr;
439 der.len = 0;
440
441 if (!tmpCert2) {
442 NS_ERROR("Couldn't create temp cert from DER blob");
443 continue; // Let's try to import the rest of 'em
444 }
445
446 CERT_AddCertToListTail(certList.get(), tmpCert2);
447 }
448
449 return ImportValidCACertsInList(certList.get(), ctx, proofOfLock);
450 }
451
452 /*
453 * [noscript] void importCertificates(in charPtr data, in unsigned long length,
454 * in unsigned long type,
455 * in nsIInterfaceRequestor ctx);
456 */
457 NS_IMETHODIMP
458 nsNSSCertificateDB::ImportCertificates(uint8_t * data, uint32_t length,
459 uint32_t type,
460 nsIInterfaceRequestor *ctx)
461
462 {
463 nsNSSShutDownPreventionLock locker;
464 if (isAlreadyShutDown()) {
465 return NS_ERROR_NOT_AVAILABLE;
466 }
467
468 nsresult nsrv;
469
470 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
471 if (!arena)
472 return NS_ERROR_OUT_OF_MEMORY;
473
474 CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
475 if (!certCollection) {
476 PORT_FreeArena(arena, false);
477 return NS_ERROR_FAILURE;
478 }
479 nsCOMPtr<nsIMutableArray> array =
480 do_CreateInstance(NS_ARRAY_CONTRACTID, &nsrv);
481 if (NS_FAILED(nsrv)) {
482 PORT_FreeArena(arena, false);
483 return nsrv;
484 }
485
486 // Now let's create some certs to work with
487 nsCOMPtr<nsIX509Cert> x509Cert;
488 nsNSSCertificate *nssCert;
489 SECItem *currItem;
490 for (int i=0; i<certCollection->numcerts; i++) {
491 currItem = &certCollection->rawCerts[i];
492 nssCert = nsNSSCertificate::ConstructFromDER((char*)currItem->data, currItem->len);
493 if (!nssCert)
494 return NS_ERROR_FAILURE;
495 x509Cert = do_QueryInterface((nsIX509Cert*)nssCert);
496 array->AppendElement(x509Cert, false);
497 }
498 switch (type) {
499 case nsIX509Cert::CA_CERT:
500 nsrv = handleCACertDownload(array, ctx, locker);
501 break;
502 default:
503 // We only deal with import CA certs in this method currently.
504 nsrv = NS_ERROR_FAILURE;
505 break;
506 }
507 PORT_FreeArena(arena, false);
508 return nsrv;
509 }
510
511 static
512 SECStatus
513 ImportCertsIntoPermanentStorage(
514 const mozilla::pkix::ScopedCERTCertList& certChain,
515 const SECCertUsage usage, const PRBool caOnly)
516 {
517 CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
518
519 int chainLen = 0;
520 for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain);
521 !CERT_LIST_END(chainNode, certChain);
522 chainNode = CERT_LIST_NEXT(chainNode)) {
523 chainLen++;
524 }
525
526 SECItem **rawArray;
527 rawArray = (SECItem **) PORT_Alloc(chainLen * sizeof(SECItem *));
528 if (!rawArray) {
529 return SECFailure;
530 }
531
532 int i = 0;
533 for (CERTCertListNode *chainNode = CERT_LIST_HEAD(certChain);
534 !CERT_LIST_END(chainNode, certChain);
535 chainNode = CERT_LIST_NEXT(chainNode), i++) {
536 rawArray[i] = &chainNode->cert->derCert;
537 }
538 SECStatus srv = CERT_ImportCerts(certdb, usage, chainLen, rawArray,
539 nullptr, true, caOnly, nullptr);
540
541 PORT_Free(rawArray);
542 return srv;
543 }
544
545
546 /*
547 * [noscript] void importEmailCertificates(in charPtr data, in unsigned long length,
548 * in nsIInterfaceRequestor ctx);
549 */
550 NS_IMETHODIMP
551 nsNSSCertificateDB::ImportEmailCertificate(uint8_t * data, uint32_t length,
552 nsIInterfaceRequestor *ctx)
553
554 {
555 nsNSSShutDownPreventionLock locker;
556 if (isAlreadyShutDown()) {
557 return NS_ERROR_NOT_AVAILABLE;
558 }
559
560 SECStatus srv = SECFailure;
561 nsresult nsrv = NS_OK;
562 CERTCertDBHandle *certdb;
563 CERTCertificate **certArray = nullptr;
564 mozilla::pkix::ScopedCERTCertList certList;
565 CERTCertListNode *node;
566 SECItem **rawArray;
567 int numcerts;
568 int i;
569
570 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
571 if (!arena)
572 return NS_ERROR_OUT_OF_MEMORY;
573
574 CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
575 if (!certCollection) {
576 PORT_FreeArena(arena, false);
577 return NS_ERROR_FAILURE;
578 }
579
580 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
581 NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
582
583 certdb = CERT_GetDefaultCertDB();
584 const PRTime now = PR_Now();
585
586 numcerts = certCollection->numcerts;
587
588 rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
589 if ( !rawArray ) {
590 nsrv = NS_ERROR_FAILURE;
591 goto loser;
592 }
593
594 for (i=0; i < numcerts; i++) {
595 rawArray[i] = &certCollection->rawCerts[i];
596 }
597
598 srv = CERT_ImportCerts(certdb, certUsageEmailRecipient, numcerts, rawArray,
599 &certArray, false, false, nullptr);
600
601 PORT_Free(rawArray);
602 rawArray = nullptr;
603
604 if (srv != SECSuccess) {
605 nsrv = NS_ERROR_FAILURE;
606 goto loser;
607 }
608
609 // build a CertList for filtering
610 certList = CERT_NewCertList();
611 if (!certList) {
612 nsrv = NS_ERROR_FAILURE;
613 goto loser;
614 }
615 for (i=0; i < numcerts; i++) {
616 CERTCertificate *cert = certArray[i];
617 if (cert)
618 cert = CERT_DupCertificate(cert);
619 if (cert)
620 CERT_AddCertToListTail(certList.get(), cert);
621 }
622
623 /* go down the remaining list of certs and verify that they have
624 * valid chains, then import them.
625 */
626
627 for (node = CERT_LIST_HEAD(certList);
628 !CERT_LIST_END(node,certList);
629 node = CERT_LIST_NEXT(node)) {
630
631 if (!node->cert) {
632 continue;
633 }
634
635 mozilla::pkix::ScopedCERTCertList certChain;
636
637 SECStatus rv = certVerifier->VerifyCert(node->cert,
638 certificateUsageEmailRecipient,
639 now, ctx, nullptr, 0,
640 nullptr, &certChain);
641
642 if (rv != SECSuccess) {
643 nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
644 DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, locker);
645 continue;
646 }
647 rv = ImportCertsIntoPermanentStorage(certChain, certUsageEmailRecipient,
648 false);
649 if (rv != SECSuccess) {
650 goto loser;
651 }
652 CERT_SaveSMimeProfile(node->cert, nullptr, nullptr);
653
654 }
655
656 loser:
657 if (certArray) {
658 CERT_DestroyCertArray(certArray, numcerts);
659 }
660 if (arena)
661 PORT_FreeArena(arena, true);
662 return nsrv;
663 }
664
665 NS_IMETHODIMP
666 nsNSSCertificateDB::ImportServerCertificate(uint8_t * data, uint32_t length,
667 nsIInterfaceRequestor *ctx)
668
669 {
670 nsNSSShutDownPreventionLock locker;
671 if (isAlreadyShutDown()) {
672 return NS_ERROR_NOT_AVAILABLE;
673 }
674
675 SECStatus srv = SECFailure;
676 nsresult nsrv = NS_OK;
677 mozilla::pkix::ScopedCERTCertificate cert;
678 SECItem **rawCerts = nullptr;
679 int numcerts;
680 int i;
681 nsNSSCertTrust trust;
682 char *serverNickname = nullptr;
683
684 PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
685 if (!arena)
686 return NS_ERROR_OUT_OF_MEMORY;
687
688 CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length, locker);
689 if (!certCollection) {
690 PORT_FreeArena(arena, false);
691 return NS_ERROR_FAILURE;
692 }
693 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts,
694 nullptr, false, true);
695 if (!cert) {
696 nsrv = NS_ERROR_FAILURE;
697 goto loser;
698 }
699 numcerts = certCollection->numcerts;
700 rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
701 if ( !rawCerts ) {
702 nsrv = NS_ERROR_FAILURE;
703 goto loser;
704 }
705
706 for ( i = 0; i < numcerts; i++ ) {
707 rawCerts[i] = &certCollection->rawCerts[i];
708 }
709
710 serverNickname = DefaultServerNicknameForCert(cert.get());
711 srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageSSLServer,
712 numcerts, rawCerts, nullptr, true, false,
713 serverNickname);
714 PR_FREEIF(serverNickname);
715 if ( srv != SECSuccess ) {
716 nsrv = NS_ERROR_FAILURE;
717 goto loser;
718 }
719
720 trust.SetValidServerPeer();
721 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert.get(),
722 trust.GetTrust());
723 if ( srv != SECSuccess ) {
724 nsrv = NS_ERROR_FAILURE;
725 goto loser;
726 }
727 loser:
728 PORT_Free(rawCerts);
729 if (arena)
730 PORT_FreeArena(arena, true);
731 return nsrv;
732 }
733
734 nsresult
735 nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem *CACerts, nsIInterfaceRequestor *ctx, const nsNSSShutDownPreventionLock &proofOfLock)
736 {
737 ScopedCERTCertList certList;
738 SECItem **rawArray;
739
740 // build a CertList for filtering
741 certList = CERT_NewCertList();
742 if (!certList) {
743 return NS_ERROR_FAILURE;
744 }
745
746 // get all certs into temp store
747 SECStatus srv = SECFailure;
748 CERTCertificate **certArray = nullptr;
749
750 rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numCACerts);
751 if ( !rawArray ) {
752 return NS_ERROR_FAILURE;
753 }
754
755 for (int i=0; i < numCACerts; i++) {
756 rawArray[i] = &CACerts[i];
757 }
758
759 srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, numCACerts, rawArray,
760 &certArray, false, true, nullptr);
761
762 PORT_Free(rawArray);
763 rawArray = nullptr;
764
765 if (srv != SECSuccess) {
766 return NS_ERROR_FAILURE;
767 }
768
769 for (int i2=0; i2 < numCACerts; i2++) {
770 CERTCertificate *cacert = certArray[i2];
771 if (cacert)
772 cacert = CERT_DupCertificate(cacert);
773 if (cacert)
774 CERT_AddCertToListTail(certList, cacert);
775 }
776
777 CERT_DestroyCertArray(certArray, numCACerts);
778
779 return ImportValidCACertsInList(certList, ctx, proofOfLock);
780 }
781
782 nsresult
783 nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx,
784 const nsNSSShutDownPreventionLock &proofOfLock)
785 {
786 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
787 if (!certVerifier)
788 return NS_ERROR_UNEXPECTED;
789
790 /* filter out the certs we don't want */
791 SECStatus srv = CERT_FilterCertListByUsage(certList, certUsageAnyCA, true);
792 if (srv != SECSuccess) {
793 return NS_ERROR_FAILURE;
794 }
795
796 /* go down the remaining list of certs and verify that they have
797 * valid chains, if yes, then import.
798 */
799 CERTCertListNode *node;
800
801 for (node = CERT_LIST_HEAD(certList);
802 !CERT_LIST_END(node,certList);
803 node = CERT_LIST_NEXT(node)) {
804 mozilla::pkix::ScopedCERTCertList certChain;
805 SECStatus rv = certVerifier->VerifyCert(node->cert,
806 certificateUsageVerifyCA,
807 PR_Now(), ctx, nullptr, 0, nullptr,
808 &certChain);
809 if (rv != SECSuccess) {
810 nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(node->cert);
811 DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, proofOfLock);
812 continue;
813 }
814
815 rv = ImportCertsIntoPermanentStorage(certChain, certUsageAnyCA, true);
816 if (rv != SECSuccess) {
817 return NS_ERROR_FAILURE;
818 }
819 }
820
821 return NS_OK;
822 }
823
824 void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx,
825 const char *stringID,
826 nsIX509Cert *certToShow,
827 const nsNSSShutDownPreventionLock &/*proofOfLock*/)
828 {
829 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
830
831 if (!NS_IsMainThread()) {
832 NS_ERROR("nsNSSCertificateDB::DisplayCertificateAlert called off the main thread");
833 return;
834 }
835
836 nsPSMUITracker tracker;
837 if (!tracker.isUIForbidden()) {
838
839 nsCOMPtr<nsIInterfaceRequestor> my_ctx = ctx;
840 if (!my_ctx)
841 my_ctx = new PipUIContext();
842
843 // This shall be replaced by embedding ovverridable prompts
844 // as discussed in bug 310446, and should make use of certToShow.
845
846 nsresult rv;
847 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
848 if (NS_SUCCEEDED(rv)) {
849 nsAutoString tmpMessage;
850 nssComponent->GetPIPNSSBundleString(stringID, tmpMessage);
851
852 nsCOMPtr<nsIPrompt> prompt (do_GetInterface(my_ctx));
853 if (!prompt)
854 return;
855
856 prompt->Alert(nullptr, tmpMessage.get());
857 }
858 }
859 }
860
861
862 NS_IMETHODIMP
863 nsNSSCertificateDB::ImportUserCertificate(uint8_t *data, uint32_t length, nsIInterfaceRequestor *ctx)
864 {
865 if (!NS_IsMainThread()) {
866 NS_ERROR("nsNSSCertificateDB::ImportUserCertificate called off the main thread");
867 return NS_ERROR_NOT_SAME_THREAD;
868 }
869
870 nsNSSShutDownPreventionLock locker;
871 if (isAlreadyShutDown()) {
872 return NS_ERROR_NOT_AVAILABLE;
873 }
874
875 ScopedPK11SlotInfo slot;
876 nsAutoCString nickname;
877 nsresult rv = NS_ERROR_FAILURE;
878 int numCACerts;
879 SECItem *CACerts;
880 CERTDERCerts * collectArgs;
881 PLArenaPool *arena;
882 mozilla::pkix::ScopedCERTCertificate cert;
883
884 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
885 if (!arena) {
886 goto loser;
887 }
888
889 collectArgs = getCertsFromPackage(arena, data, length, locker);
890 if (!collectArgs) {
891 goto loser;
892 }
893
894 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
895 nullptr, false, true);
896 if (!cert) {
897 goto loser;
898 }
899
900 slot = PK11_KeyForCertExists(cert.get(), nullptr, ctx);
901 if (!slot) {
902 nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
903 DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow, locker);
904 goto loser;
905 }
906 slot = nullptr;
907
908 /* pick a nickname for the cert */
909 if (cert->nickname) {
910 /* sigh, we need a call to look up other certs with this subject and
911 * identify nicknames from them. We can no longer walk down internal
912 * database structures rjr */
913 nickname = cert->nickname;
914 }
915 else {
916 get_default_nickname(cert.get(), ctx, nickname, locker);
917 }
918
919 /* user wants to import the cert */
920 {
921 char *cast_const_away = const_cast<char*>(nickname.get());
922 slot = PK11_ImportCertForKey(cert.get(), cast_const_away, ctx);
923 }
924 if (!slot) {
925 goto loser;
926 }
927 slot = nullptr;
928
929 {
930 nsCOMPtr<nsIX509Cert> certToShow = nsNSSCertificate::Create(cert.get());
931 DisplayCertificateAlert(ctx, "UserCertImported", certToShow, locker);
932 }
933 rv = NS_OK;
934
935 numCACerts = collectArgs->numcerts - 1;
936 if (numCACerts) {
937 CACerts = collectArgs->rawCerts+1;
938 rv = ImportValidCACerts(numCACerts, CACerts, ctx, locker);
939 }
940
941 loser:
942 if (arena) {
943 PORT_FreeArena(arena, false);
944 }
945 return rv;
946 }
947
948 /*
949 * void deleteCertificate(in nsIX509Cert aCert);
950 */
951 NS_IMETHODIMP
952 nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
953 {
954 nsNSSShutDownPreventionLock locker;
955 if (isAlreadyShutDown()) {
956 return NS_ERROR_NOT_AVAILABLE;
957 }
958 nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
959 mozilla::pkix::ScopedCERTCertificate cert(nssCert->GetCert());
960 if (!cert) return NS_ERROR_FAILURE;
961 SECStatus srv = SECSuccess;
962
963 uint32_t certType;
964 nssCert->GetCertType(&certType);
965 if (NS_FAILED(nssCert->MarkForPermDeletion()))
966 {
967 return NS_ERROR_FAILURE;
968 }
969
970 if (cert->slot && certType != nsIX509Cert::USER_CERT) {
971 // To delete a cert of a slot (builtin, most likely), mark it as
972 // completely untrusted. This way we keep a copy cached in the
973 // local database, and next time we try to load it off of the
974 // external token/slot, we'll know not to trust it. We don't
975 // want to do that with user certs, because a user may re-store
976 // the cert onto the card again at which point we *will* want to
977 // trust that cert if it chains up properly.
978 nsNSSCertTrust trust(0, 0, 0);
979 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
980 cert.get(), trust.GetTrust());
981 }
982 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv));
983 return (srv) ? NS_ERROR_FAILURE : NS_OK;
984 }
985
986 /*
987 * void setCertTrust(in nsIX509Cert cert,
988 * in unsigned long type,
989 * in unsigned long trust);
990 */
991 NS_IMETHODIMP
992 nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
993 uint32_t type,
994 uint32_t trusted)
995 {
996 nsNSSShutDownPreventionLock locker;
997 if (isAlreadyShutDown()) {
998 return NS_ERROR_NOT_AVAILABLE;
999 }
1000 nsNSSCertTrust trust;
1001 nsresult rv;
1002 nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert, &rv);
1003 if (!pipCert) {
1004 return rv;
1005 }
1006 mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
1007
1008 rv = attemptToLogInWithDefaultPassword();
1009 if (NS_WARN_IF(rv != NS_OK)) {
1010 return rv;
1011 }
1012
1013 SECStatus srv;
1014 if (type == nsIX509Cert::CA_CERT) {
1015 // always start with untrusted and move up
1016 trust.SetValidCA();
1017 trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL),
1018 !!(trusted & nsIX509CertDB::TRUSTED_EMAIL),
1019 !!(trusted & nsIX509CertDB::TRUSTED_OBJSIGN));
1020 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
1021 nsscert.get(),
1022 trust.GetTrust());
1023 } else if (type == nsIX509Cert::SERVER_CERT) {
1024 // always start with untrusted and move up
1025 trust.SetValidPeer();
1026 trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0);
1027 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
1028 nsscert.get(),
1029 trust.GetTrust());
1030 } else if (type == nsIX509Cert::EMAIL_CERT) {
1031 // always start with untrusted and move up
1032 trust.SetValidPeer();
1033 trust.AddPeerTrust(0, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), 0);
1034 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
1035 nsscert.get(),
1036 trust.GetTrust());
1037 } else {
1038 // ignore user certs
1039 return NS_OK;
1040 }
1041 return MapSECStatus(srv);
1042 }
1043
1044 NS_IMETHODIMP
1045 nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert,
1046 uint32_t certType,
1047 uint32_t trustType,
1048 bool *_isTrusted)
1049 {
1050 NS_ENSURE_ARG_POINTER(_isTrusted);
1051 *_isTrusted = false;
1052
1053 nsNSSShutDownPreventionLock locker;
1054 if (isAlreadyShutDown()) {
1055 return NS_ERROR_NOT_AVAILABLE;
1056 }
1057 SECStatus srv;
1058 nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
1059 mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
1060 CERTCertTrust nsstrust;
1061 srv = CERT_GetCertTrust(nsscert.get(), &nsstrust);
1062 if (srv != SECSuccess)
1063 return NS_ERROR_FAILURE;
1064
1065 nsNSSCertTrust trust(&nsstrust);
1066 if (certType == nsIX509Cert::CA_CERT) {
1067 if (trustType & nsIX509CertDB::TRUSTED_SSL) {
1068 *_isTrusted = trust.HasTrustedCA(true, false, false);
1069 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
1070 *_isTrusted = trust.HasTrustedCA(false, true, false);
1071 } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
1072 *_isTrusted = trust.HasTrustedCA(false, false, true);
1073 } else {
1074 return NS_ERROR_FAILURE;
1075 }
1076 } else if (certType == nsIX509Cert::SERVER_CERT) {
1077 if (trustType & nsIX509CertDB::TRUSTED_SSL) {
1078 *_isTrusted = trust.HasTrustedPeer(true, false, false);
1079 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
1080 *_isTrusted = trust.HasTrustedPeer(false, true, false);
1081 } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
1082 *_isTrusted = trust.HasTrustedPeer(false, false, true);
1083 } else {
1084 return NS_ERROR_FAILURE;
1085 }
1086 } else if (certType == nsIX509Cert::EMAIL_CERT) {
1087 if (trustType & nsIX509CertDB::TRUSTED_SSL) {
1088 *_isTrusted = trust.HasTrustedPeer(true, false, false);
1089 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
1090 *_isTrusted = trust.HasTrustedPeer(false, true, false);
1091 } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
1092 *_isTrusted = trust.HasTrustedPeer(false, false, true);
1093 } else {
1094 return NS_ERROR_FAILURE;
1095 }
1096 } /* user: ignore */
1097 return NS_OK;
1098 }
1099
1100
1101 NS_IMETHODIMP
1102 nsNSSCertificateDB::ImportCertsFromFile(nsISupports *aToken,
1103 nsIFile *aFile,
1104 uint32_t aType)
1105 {
1106 nsNSSShutDownPreventionLock locker;
1107 if (isAlreadyShutDown()) {
1108 return NS_ERROR_NOT_AVAILABLE;
1109 }
1110
1111 NS_ENSURE_ARG(aFile);
1112 switch (aType) {
1113 case nsIX509Cert::CA_CERT:
1114 case nsIX509Cert::EMAIL_CERT:
1115 case nsIX509Cert::SERVER_CERT:
1116 // good
1117 break;
1118
1119 default:
1120 // not supported (yet)
1121 return NS_ERROR_FAILURE;
1122 }
1123
1124 nsresult rv;
1125 PRFileDesc *fd = nullptr;
1126
1127 rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
1128
1129 if (NS_FAILED(rv))
1130 return rv;
1131
1132 if (!fd)
1133 return NS_ERROR_FAILURE;
1134
1135 PRFileInfo file_info;
1136 if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &file_info))
1137 return NS_ERROR_FAILURE;
1138
1139 unsigned char *buf = new unsigned char[file_info.size];
1140
1141 int32_t bytes_obtained = PR_Read(fd, buf, file_info.size);
1142 PR_Close(fd);
1143
1144 if (bytes_obtained != file_info.size)
1145 rv = NS_ERROR_FAILURE;
1146 else {
1147 nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
1148
1149 switch (aType) {
1150 case nsIX509Cert::CA_CERT:
1151 rv = ImportCertificates(buf, bytes_obtained, aType, cxt);
1152 break;
1153
1154 case nsIX509Cert::SERVER_CERT:
1155 rv = ImportServerCertificate(buf, bytes_obtained, cxt);
1156 break;
1157
1158 case nsIX509Cert::EMAIL_CERT:
1159 rv = ImportEmailCertificate(buf, bytes_obtained, cxt);
1160 break;
1161
1162 default:
1163 break;
1164 }
1165 }
1166
1167 delete [] buf;
1168 return rv;
1169 }
1170
1171 NS_IMETHODIMP
1172 nsNSSCertificateDB::ImportPKCS12File(nsISupports *aToken,
1173 nsIFile *aFile)
1174 {
1175 nsNSSShutDownPreventionLock locker;
1176 if (isAlreadyShutDown()) {
1177 return NS_ERROR_NOT_AVAILABLE;
1178 }
1179
1180 NS_ENSURE_ARG(aFile);
1181 nsPKCS12Blob blob;
1182 nsCOMPtr<nsIPK11Token> token = do_QueryInterface(aToken);
1183 if (token) {
1184 blob.SetToken(token);
1185 }
1186 return blob.ImportFromFile(aFile);
1187 }
1188
1189 NS_IMETHODIMP
1190 nsNSSCertificateDB::ExportPKCS12File(nsISupports *aToken,
1191 nsIFile *aFile,
1192 uint32_t count,
1193 nsIX509Cert **certs)
1194 //const char16_t **aCertNames)
1195 {
1196 nsNSSShutDownPreventionLock locker;
1197 if (isAlreadyShutDown()) {
1198 return NS_ERROR_NOT_AVAILABLE;
1199 }
1200
1201 NS_ENSURE_ARG(aFile);
1202 nsPKCS12Blob blob;
1203 if (count == 0) return NS_OK;
1204 nsCOMPtr<nsIPK11Token> localRef;
1205 if (!aToken) {
1206 ScopedPK11SlotInfo keySlot(PK11_GetInternalKeySlot());
1207 NS_ASSERTION(keySlot,"Failed to get the internal key slot");
1208 localRef = new nsPK11Token(keySlot);
1209 }
1210 else {
1211 localRef = do_QueryInterface(aToken);
1212 }
1213 blob.SetToken(localRef);
1214 //blob.LoadCerts(aCertNames, count);
1215 //return blob.ExportToFile(aFile);
1216 return blob.ExportToFile(aFile, certs, count);
1217 }
1218
1219 /*
1220 * NSS Helper Routines (private to nsNSSCertificateDB)
1221 */
1222
1223 #define DELIM '\001'
1224
1225 /*
1226 * GetSortedNameList
1227 *
1228 * Converts a CERTCertList to a list of certificate names
1229 */
1230 void
1231 nsNSSCertificateDB::getCertNames(CERTCertList *certList,
1232 uint32_t type,
1233 uint32_t *_count,
1234 char16_t ***_certNames,
1235 const nsNSSShutDownPreventionLock &/*proofOfLock*/)
1236 {
1237 CERTCertListNode *node;
1238 uint32_t numcerts = 0, i=0;
1239 char16_t **tmpArray = nullptr;
1240
1241 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("List of certs %d:\n", type));
1242 for (node = CERT_LIST_HEAD(certList);
1243 !CERT_LIST_END(node, certList);
1244 node = CERT_LIST_NEXT(node)) {
1245 if (getCertType(node->cert) == type) {
1246 numcerts++;
1247 }
1248 }
1249 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("num certs: %d\n", numcerts));
1250 int nc = (numcerts == 0) ? 1 : numcerts;
1251 tmpArray = (char16_t **)nsMemory::Alloc(sizeof(char16_t *) * nc);
1252 if (numcerts == 0) goto finish;
1253 for (node = CERT_LIST_HEAD(certList);
1254 !CERT_LIST_END(node, certList);
1255 node = CERT_LIST_NEXT(node)) {
1256 if (getCertType(node->cert) == type) {
1257 nsNSSCertificate pipCert(node->cert);
1258 char *dbkey = nullptr;
1259 char *namestr = nullptr;
1260 nsAutoString certstr;
1261 pipCert.GetDbKey(&dbkey);
1262 nsAutoString keystr = NS_ConvertASCIItoUTF16(dbkey);
1263 PR_FREEIF(dbkey);
1264 if (type == nsIX509Cert::EMAIL_CERT) {
1265 namestr = node->cert->emailAddr;
1266 } else {
1267 namestr = node->cert->nickname;
1268 if (namestr) {
1269 char *sc = strchr(namestr, ':');
1270 if (sc) *sc = DELIM;
1271 }
1272 }
1273 nsAutoString certname = NS_ConvertASCIItoUTF16(namestr ? namestr : "");
1274 certstr.Append(char16_t(DELIM));
1275 certstr += certname;
1276 certstr.Append(char16_t(DELIM));
1277 certstr += keystr;
1278 tmpArray[i++] = ToNewUnicode(certstr);
1279 }
1280 }
1281 finish:
1282 *_count = numcerts;
1283 *_certNames = tmpArray;
1284 }
1285
1286 /* nsIX509Cert getDefaultEmailEncryptionCert (); */
1287 NS_IMETHODIMP
1288 nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509Cert **_retval)
1289 {
1290 NS_ENSURE_ARG_POINTER(_retval);
1291 *_retval = nullptr;
1292
1293 if (aNickname.IsEmpty())
1294 return NS_OK;
1295
1296 nsNSSShutDownPreventionLock locker;
1297 if (isAlreadyShutDown()) {
1298 return NS_ERROR_NOT_AVAILABLE;
1299 }
1300
1301 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
1302 char *asciiname = nullptr;
1303 NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname);
1304 asciiname = const_cast<char*>(aUtf8Nickname.get());
1305
1306 /* Find a good cert in the user's database */
1307 mozilla::pkix::ScopedCERTCertificate cert;
1308 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname,
1309 certUsageEmailRecipient, true, ctx);
1310 if (!cert) {
1311 return NS_OK;
1312 }
1313
1314 nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
1315 if (!nssCert) {
1316 return NS_ERROR_OUT_OF_MEMORY;
1317 }
1318 nssCert.forget(_retval);
1319 return NS_OK;
1320 }
1321
1322 /* nsIX509Cert getDefaultEmailSigningCert (); */
1323 NS_IMETHODIMP
1324 nsNSSCertificateDB::FindEmailSigningCert(const nsAString &aNickname, nsIX509Cert **_retval)
1325 {
1326 NS_ENSURE_ARG_POINTER(_retval);
1327 *_retval = nullptr;
1328
1329 if (aNickname.IsEmpty())
1330 return NS_OK;
1331
1332 nsNSSShutDownPreventionLock locker;
1333 if (isAlreadyShutDown()) {
1334 return NS_ERROR_NOT_AVAILABLE;
1335 }
1336
1337 mozilla::pkix::ScopedCERTCertificate cert;
1338 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
1339 char *asciiname = nullptr;
1340 NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname);
1341 asciiname = const_cast<char*>(aUtf8Nickname.get());
1342
1343 /* Find a good cert in the user's database */
1344 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname,
1345 certUsageEmailSigner, true, ctx);
1346 if (!cert) {
1347 return NS_OK;
1348 }
1349
1350 nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
1351 if (!nssCert) {
1352 return NS_ERROR_OUT_OF_MEMORY;
1353 }
1354 nssCert.forget(_retval);
1355 return NS_OK;
1356 }
1357
1358 NS_IMETHODIMP
1359 nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEmailAddress, nsIX509Cert **_retval)
1360 {
1361 nsNSSShutDownPreventionLock locker;
1362 if (isAlreadyShutDown()) {
1363 return NS_ERROR_NOT_AVAILABLE;
1364 }
1365
1366 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
1367 NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
1368
1369 ScopedCERTCertList certlist(
1370 PK11_FindCertsFromEmailAddress(aEmailAddress, nullptr));
1371 if (!certlist)
1372 return NS_ERROR_FAILURE;
1373
1374 // certlist now contains certificates with the right email address,
1375 // but they might not have the correct usage or might even be invalid
1376
1377 if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist))
1378 return NS_ERROR_FAILURE; // no certs found
1379
1380 CERTCertListNode *node;
1381 // search for a valid certificate
1382 for (node = CERT_LIST_HEAD(certlist);
1383 !CERT_LIST_END(node, certlist);
1384 node = CERT_LIST_NEXT(node)) {
1385
1386 SECStatus srv = certVerifier->VerifyCert(node->cert,
1387 certificateUsageEmailRecipient,
1388 PR_Now(), nullptr /*XXX pinarg*/,
1389 nullptr /*hostname*/);
1390 if (srv == SECSuccess) {
1391 break;
1392 }
1393 }
1394
1395 if (CERT_LIST_END(node, certlist)) {
1396 // no valid cert found
1397 return NS_ERROR_FAILURE;
1398 }
1399
1400 // node now contains the first valid certificate with correct usage
1401 nsNSSCertificate *nssCert = nsNSSCertificate::Create(node->cert);
1402 if (!nssCert)
1403 return NS_ERROR_OUT_OF_MEMORY;
1404
1405 NS_ADDREF(nssCert);
1406 *_retval = static_cast<nsIX509Cert*>(nssCert);
1407 return NS_OK;
1408 }
1409
1410 /* nsIX509Cert constructX509FromBase64 (in string base64); */
1411 NS_IMETHODIMP
1412 nsNSSCertificateDB::ConstructX509FromBase64(const char *base64,
1413 nsIX509Cert **_retval)
1414 {
1415 nsNSSShutDownPreventionLock locker;
1416 if (isAlreadyShutDown()) {
1417 return NS_ERROR_NOT_AVAILABLE;
1418 }
1419 if (NS_WARN_IF(!_retval)) {
1420 return NS_ERROR_INVALID_POINTER;
1421 }
1422
1423 // sure would be nice to have a smart pointer class for PL_ allocations
1424 // unfortunately, we cannot distinguish out-of-memory from bad-input here
1425 uint32_t len = base64 ? strlen(base64) : 0;
1426 char *certDER = PL_Base64Decode(base64, len, nullptr);
1427 if (!certDER)
1428 return NS_ERROR_ILLEGAL_VALUE;
1429 if (!*certDER) {
1430 PL_strfree(certDER);
1431 return NS_ERROR_ILLEGAL_VALUE;
1432 }
1433
1434 // If we get to this point, we know we had well-formed base64 input;
1435 // therefore the input string cannot have been less than two
1436 // characters long. Compute the unpadded length of the decoded data.
1437 uint32_t lengthDER = (len * 3) / 4;
1438 if (base64[len-1] == '=') {
1439 lengthDER--;
1440 if (base64[len-2] == '=')
1441 lengthDER--;
1442 }
1443
1444 nsresult rv = ConstructX509(certDER, lengthDER, _retval);
1445 PL_strfree(certDER);
1446 return rv;
1447 }
1448
1449 /* nsIX509Cert constructX509 (in string certDER, unsigned long len); */
1450 NS_IMETHODIMP
1451 nsNSSCertificateDB::ConstructX509(const char* certDER,
1452 uint32_t lengthDER,
1453 nsIX509Cert** _retval)
1454 {
1455 nsNSSShutDownPreventionLock locker;
1456 if (isAlreadyShutDown()) {
1457 return NS_ERROR_NOT_AVAILABLE;
1458 }
1459 if (NS_WARN_IF(!_retval)) {
1460 return NS_ERROR_INVALID_POINTER;
1461 }
1462
1463 SECItem secitem_cert;
1464 secitem_cert.type = siDERCertBuffer;
1465 secitem_cert.data = (unsigned char*)certDER;
1466 secitem_cert.len = lengthDER;
1467
1468 mozilla::pkix::ScopedCERTCertificate cert;
1469 cert =
1470 CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert,
1471 nullptr, false, true);
1472 if (!cert)
1473 return (PORT_GetError() == SEC_ERROR_NO_MEMORY)
1474 ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_FAILURE;
1475
1476 nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(cert.get());
1477 if (!nssCert) {
1478 return NS_ERROR_OUT_OF_MEMORY;
1479 }
1480 nssCert.forget(_retval);
1481 return NS_OK;
1482 }
1483
1484 void
1485 nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert,
1486 nsIInterfaceRequestor* ctx,
1487 nsCString &nickname,
1488 const nsNSSShutDownPreventionLock &/*proofOfLock*/)
1489 {
1490 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
1491
1492 nickname.Truncate();
1493
1494 nsresult rv;
1495 CK_OBJECT_HANDLE keyHandle;
1496
1497 CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
1498 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
1499 if (NS_FAILED(rv))
1500 return;
1501
1502 nsAutoCString username;
1503 char *temp_un = CERT_GetCommonName(&cert->subject);
1504 if (temp_un) {
1505 username = temp_un;
1506 PORT_Free(temp_un);
1507 temp_un = nullptr;
1508 }
1509
1510 nsAutoCString caname;
1511 char *temp_ca = CERT_GetOrgName(&cert->issuer);
1512 if (temp_ca) {
1513 caname = temp_ca;
1514 PORT_Free(temp_ca);
1515 temp_ca = nullptr;
1516 }
1517
1518 nsAutoString tmpNickFmt;
1519 nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt);
1520 NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt);
1521
1522 nsAutoCString baseName;
1523 char *temp_nn = PR_smprintf(nickFmt.get(), username.get(), caname.get());
1524 if (!temp_nn) {
1525 return;
1526 } else {
1527 baseName = temp_nn;
1528 PR_smprintf_free(temp_nn);
1529 temp_nn = nullptr;
1530 }
1531
1532 nickname = baseName;
1533
1534 /*
1535 * We need to see if the private key exists on a token, if it does
1536 * then we need to check for nicknames that already exist on the smart
1537 * card.
1538 */
1539 ScopedPK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx));
1540 if (!slot)
1541 return;
1542
1543 if (!PK11_IsInternal(slot)) {
1544 char *tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), baseName.get());
1545 if (!tmp) {
1546 nickname.Truncate();
1547 return;
1548 }
1549 baseName = tmp;
1550 PR_smprintf_free(tmp);
1551
1552 nickname = baseName;
1553 }
1554
1555 int count = 1;
1556 while (true) {
1557 if ( count > 1 ) {
1558 char *tmp = PR_smprintf("%s #%d", baseName.get(), count);
1559 if (!tmp) {
1560 nickname.Truncate();
1561 return;
1562 }
1563 nickname = tmp;
1564 PR_smprintf_free(tmp);
1565 }
1566
1567 mozilla::pkix::ScopedCERTCertificate dummycert;
1568
1569 if (PK11_IsInternal(slot)) {
1570 /* look up the nickname to make sure it isn't in use already */
1571 dummycert = CERT_FindCertByNickname(defaultcertdb, nickname.get());
1572
1573 } else {
1574 /*
1575 * Check the cert against others that already live on the smart
1576 * card.
1577 */
1578 dummycert = PK11_FindCertFromNickname(nickname.get(), ctx);
1579 if (dummycert) {
1580 /*
1581 * Make sure the subject names are different.
1582 */
1583 if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
1584 {
1585 /*
1586 * There is another certificate with the same nickname and
1587 * the same subject name on the smart card, so let's use this
1588 * nickname.
1589 */
1590 dummycert = nullptr;
1591 }
1592 }
1593 }
1594 if (!dummycert)
1595 break;
1596
1597 count++;
1598 }
1599 }
1600
1601 NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName)
1602 {
1603 NS_ENSURE_ARG_POINTER(aBase64);
1604 nsCOMPtr <nsIX509Cert> newCert;
1605
1606 nsNSSShutDownPreventionLock locker;
1607 if (isAlreadyShutDown()) {
1608 return NS_ERROR_NOT_AVAILABLE;
1609 }
1610
1611 nsNSSCertTrust trust;
1612
1613 // need to calculate the trust bits from the aTrust string.
1614 SECStatus stat = CERT_DecodeTrustString(trust.GetTrust(),
1615 /* this is const, but not declared that way */(char *) aTrust);
1616 NS_ENSURE_STATE(stat == SECSuccess); // if bad trust passed in, return error.
1617
1618
1619 nsresult rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert));
1620 NS_ENSURE_SUCCESS(rv, rv);
1621
1622 SECItem der;
1623 rv = newCert->GetRawDER(&der.len, (uint8_t **)&der.data);
1624 NS_ENSURE_SUCCESS(rv, rv);
1625
1626 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));
1627 CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
1628 mozilla::pkix::ScopedCERTCertificate tmpCert(CERT_FindCertByDERCert(certdb, &der));
1629 if (!tmpCert)
1630 tmpCert = CERT_NewTempCertificate(certdb, &der,
1631 nullptr, false, true);
1632 nsMemory::Free(der.data);
1633 der.data = nullptr;
1634 der.len = 0;
1635
1636 if (!tmpCert) {
1637 NS_ERROR("Couldn't create cert from DER blob");
1638 return MapSECStatus(SECFailure);
1639 }
1640
1641 if (tmpCert->isperm) {
1642 return NS_OK;
1643 }
1644
1645 nsXPIDLCString nickname;
1646 nickname.Adopt(CERT_MakeCANickname(tmpCert.get()));
1647
1648 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));
1649
1650 rv = attemptToLogInWithDefaultPassword();
1651 if (NS_WARN_IF(rv != NS_OK)) {
1652 return rv;
1653 }
1654
1655 SECStatus srv = __CERT_AddTempCertToPerm(tmpCert.get(),
1656 const_cast<char*>(nickname.get()),
1657 trust.GetTrust());
1658 return MapSECStatus(srv);
1659 }
1660
1661 NS_IMETHODIMP
1662 nsNSSCertificateDB::AddCert(const nsACString & aCertDER, const char *aTrust,
1663 const char *aName)
1664 {
1665 nsCString base64;
1666 nsresult rv = Base64Encode(aCertDER, base64);
1667 NS_ENSURE_SUCCESS(rv, rv);
1668 return AddCertFromBase64(base64.get(), aTrust, aName);
1669 }
1670
1671 NS_IMETHODIMP
1672 nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert3* cert,
1673 const char* trustString)
1674 {
1675 CERTCertTrust trust;
1676
1677 // need to calculate the trust bits from the aTrust string.
1678 SECStatus srv = CERT_DecodeTrustString(&trust,
1679 const_cast<char *>(trustString));
1680 if (srv != SECSuccess) {
1681 return MapSECStatus(SECFailure);
1682 }
1683 mozilla::pkix::ScopedCERTCertificate nssCert(cert->GetCert());
1684
1685 nsresult rv = attemptToLogInWithDefaultPassword();
1686 if (NS_WARN_IF(rv != NS_OK)) {
1687 return rv;
1688 }
1689
1690 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), nssCert.get(), &trust);
1691 return MapSECStatus(srv);
1692 }
1693
1694 NS_IMETHODIMP
1695 nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval)
1696 {
1697 nsNSSShutDownPreventionLock locker;
1698 if (isAlreadyShutDown()) {
1699 return NS_ERROR_NOT_AVAILABLE;
1700 }
1701
1702 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
1703 nsCOMPtr<nsIX509CertList> nssCertList;
1704 mozilla::pkix::ScopedCERTCertList certList(
1705 PK11_ListCerts(PK11CertListUnique, ctx));
1706
1707 // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine.
1708 // (returns an empty list)
1709 nssCertList = new nsNSSCertList(certList, locker);
1710
1711 *_retval = nssCertList;
1712 NS_ADDREF(*_retval);
1713 return NS_OK;
1714 }
1715
1716 NS_IMETHODIMP
1717 nsNSSCertificateDB::GetRecentBadCerts(bool isPrivate, nsIRecentBadCerts** result)
1718 {
1719 nsNSSShutDownPreventionLock locker;
1720 if (isAlreadyShutDown()) {
1721 return NS_ERROR_NOT_AVAILABLE;
1722 }
1723
1724 MutexAutoLock lock(mBadCertsLock);
1725 if (isPrivate) {
1726 if (!mPrivateRecentBadCerts) {
1727 mPrivateRecentBadCerts = new nsRecentBadCerts;
1728 }
1729 NS_ADDREF(*result = mPrivateRecentBadCerts);
1730 } else {
1731 if (!mPublicRecentBadCerts) {
1732 mPublicRecentBadCerts = new nsRecentBadCerts;
1733 }
1734 NS_ADDREF(*result = mPublicRecentBadCerts);
1735 }
1736 return NS_OK;
1737 }
1738
1739 NS_IMETHODIMP
1740 nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert,
1741 int64_t /*SECCertificateUsage*/ aUsage,
1742 uint32_t aFlags,
1743 nsIX509CertList** verifiedChain,
1744 bool* aHasEVPolicy,
1745 int32_t* /*PRErrorCode*/ _retval )
1746 {
1747 NS_ENSURE_ARG_POINTER(aCert);
1748 NS_ENSURE_ARG_POINTER(aHasEVPolicy);
1749 NS_ENSURE_ARG_POINTER(verifiedChain);
1750 NS_ENSURE_ARG_POINTER(_retval);
1751
1752 *verifiedChain = nullptr;
1753 *aHasEVPolicy = false;
1754 *_retval = PR_UNKNOWN_ERROR;
1755
1756 nsNSSShutDownPreventionLock locker;
1757 if (isAlreadyShutDown()) {
1758 return NS_ERROR_NOT_AVAILABLE;
1759 }
1760
1761 #ifndef MOZ_NO_EV_CERTS
1762 EnsureIdentityInfoLoaded();
1763 #endif
1764
1765 nsCOMPtr<nsIX509Cert2> x509Cert = do_QueryInterface(aCert);
1766 if (!x509Cert) {
1767 return NS_ERROR_INVALID_ARG;
1768 }
1769 ScopedCERTCertificate nssCert(x509Cert->GetCert());
1770
1771 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
1772 NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
1773
1774 mozilla::pkix::ScopedCERTCertList resultChain;
1775 SECOidTag evOidPolicy;
1776 SECStatus srv;
1777
1778 srv = certVerifier->VerifyCert(nssCert,
1779 aUsage, PR_Now(),
1780 nullptr, // Assume no context
1781 nullptr, // hostname
1782 aFlags,
1783 nullptr, // stapledOCSPResponse
1784 &resultChain,
1785 &evOidPolicy);
1786
1787 PRErrorCode error = PR_GetError();
1788
1789 nsCOMPtr<nsIX509CertList> nssCertList;
1790 // This adopts the list
1791 nssCertList = new nsNSSCertList(resultChain, locker);
1792 NS_ENSURE_TRUE(nssCertList, NS_ERROR_FAILURE);
1793
1794 if (srv == SECSuccess) {
1795 if (evOidPolicy != SEC_OID_UNKNOWN) {
1796 *aHasEVPolicy = true;
1797 }
1798 *_retval = 0;
1799 } else {
1800 NS_ENSURE_TRUE(evOidPolicy == SEC_OID_UNKNOWN, NS_ERROR_FAILURE);
1801 NS_ENSURE_TRUE(error != 0, NS_ERROR_FAILURE);
1802 *_retval = error;
1803 }
1804 nssCertList.forget(verifiedChain);
1805
1806 return NS_OK;
1807 }
1808
1809 NS_IMETHODIMP
1810 nsNSSCertificateDB::ClearOCSPCache()
1811 {
1812 nsNSSShutDownPreventionLock locker;
1813 if (isAlreadyShutDown()) {
1814 return NS_ERROR_NOT_AVAILABLE;
1815 }
1816
1817 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
1818 NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
1819 if (certVerifier->mImplementation == CertVerifier::mozillapkix) {
1820 certVerifier->ClearOCSPCache();
1821 } else {
1822 SECStatus srv = CERT_ClearOCSPCache();
1823 if (srv != SECSuccess) {
1824 return MapSECStatus(srv);
1825 }
1826 }
1827
1828 return NS_OK;
1829 }

mercurial