Bug 452390 Tracemonkey will crash if the compiler doesn't have FASTCALL r=danderson
[wine-gecko.git] / security / manager / ssl / src / nsNSSCertificateDB.cpp
blob66f899b14e2e8ab54550f53779703b166d82725b
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Ian McGreer <mcgreer@netscape.com>
23 * Javier Delgadillo <javi@netscape.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsNSSComponent.h"
40 #include "nsNSSCertificateDB.h"
41 #include "nsCOMPtr.h"
42 #include "nsNSSCertificate.h"
43 #include "nsNSSHelper.h"
44 #include "nsNSSCertHelper.h"
45 #include "nsNSSCertCache.h"
46 #include "nsCRT.h"
47 #include "nsICertificateDialogs.h"
48 #include "nsNSSCertTrust.h"
49 #include "nsILocalFile.h"
50 #include "nsPKCS12Blob.h"
51 #include "nsPK11TokenDB.h"
52 #include "nsOCSPResponder.h"
53 #include "nsReadableUtils.h"
54 #include "nsIMutableArray.h"
55 #include "nsArrayUtils.h"
56 #include "nsNSSShutDown.h"
57 #include "nsIPrefService.h"
58 #include "nsIPrefBranch.h"
59 #include "nsComponentManagerUtils.h"
60 #include "nsIPrompt.h"
61 #include "nsIProxyObjectManager.h"
62 #include "nsProxiedService.h"
64 #include "nspr.h"
65 extern "C" {
66 #include "pk11func.h"
67 #include "certdb.h"
68 #include "cert.h"
69 #include "secerr.h"
70 #include "nssb64.h"
71 #include "secasn1.h"
72 #include "secder.h"
74 #include "ssl.h"
75 #include "ocsp.h"
76 #include "plbase64.h"
78 #ifdef PR_LOGGING
79 extern PRLogModuleInfo* gPIPNSSLog;
80 #endif
82 #include "nsNSSCleaner.h"
83 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
84 NSSCleanupAutoPtrClass(CERTCertList, CERT_DestroyCertList)
85 NSSCleanupAutoPtrClass(CERTCertificateList, CERT_DestroyCertificateList)
86 NSSCleanupAutoPtrClass(PK11SlotInfo, PK11_FreeSlot)
88 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
91 NS_IMPL_THREADSAFE_ISUPPORTS2(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2)
93 nsNSSCertificateDB::nsNSSCertificateDB()
97 nsNSSCertificateDB::~nsNSSCertificateDB()
101 NS_IMETHODIMP
102 nsNSSCertificateDB::FindCertByNickname(nsISupports *aToken,
103 const nsAString &nickname,
104 nsIX509Cert **_rvCert)
106 nsNSSShutDownPreventionLock locker;
107 CERTCertificate *cert = NULL;
108 char *asciiname = NULL;
109 NS_ConvertUTF16toUTF8 aUtf8Nickname(nickname);
110 asciiname = const_cast<char*>(aUtf8Nickname.get());
111 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));
112 #if 0
113 // what it should be, but for now...
114 if (aToken) {
115 cert = PK11_FindCertFromNickname(asciiname, NULL);
116 } else {
117 cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname);
119 #endif
120 cert = PK11_FindCertFromNickname(asciiname, NULL);
121 if (!cert) {
122 cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname);
124 if (cert) {
125 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n"));
126 nsCOMPtr<nsIX509Cert> pCert = new nsNSSCertificate(cert);
127 CERT_DestroyCertificate(cert);
128 *_rvCert = pCert;
129 NS_ADDREF(*_rvCert);
130 return NS_OK;
132 *_rvCert = nsnull;
133 return NS_ERROR_FAILURE;
136 NS_IMETHODIMP
137 nsNSSCertificateDB::FindCertByDBKey(const char *aDBkey, nsISupports *aToken,
138 nsIX509Cert **_cert)
140 nsNSSShutDownPreventionLock locker;
141 SECItem keyItem = {siBuffer, nsnull, 0};
142 SECItem *dummy;
143 CERTIssuerAndSN issuerSN;
144 unsigned long moduleID,slotID;
145 *_cert = nsnull;
146 if (!aDBkey || !*aDBkey)
147 return NS_ERROR_INVALID_ARG;
149 dummy = NSSBase64_DecodeBuffer(nsnull, &keyItem, aDBkey,
150 (PRUint32)PL_strlen(aDBkey));
151 if (!dummy || keyItem.len < NS_NSS_LONG*4) {
152 PR_FREEIF(keyItem.data);
153 return NS_ERROR_INVALID_ARG;
156 CERTCertificate *cert;
157 // someday maybe we can speed up the search using the moduleID and slotID
158 moduleID = NS_NSS_GET_LONG(keyItem.data);
159 slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]);
161 // build the issuer/SN structure
162 issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]);
163 issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]);
164 if (issuerSN.serialNumber.len == 0 || issuerSN.derIssuer.len == 0
165 || issuerSN.serialNumber.len + issuerSN.derIssuer.len
166 != keyItem.len - NS_NSS_LONG*4) {
167 PR_FREEIF(keyItem.data);
168 return NS_ERROR_INVALID_ARG;
170 issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4];
171 issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG*4+
172 issuerSN.serialNumber.len];
174 cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN);
175 PR_FREEIF(keyItem.data);
176 if (cert) {
177 nsNSSCertificate *nssCert = new nsNSSCertificate(cert);
178 CERT_DestroyCertificate(cert);
179 if (nssCert == nsnull)
180 return NS_ERROR_OUT_OF_MEMORY;
181 NS_ADDREF(nssCert);
182 *_cert = static_cast<nsIX509Cert*>(nssCert);
184 return NS_OK;
187 NS_IMETHODIMP
188 nsNSSCertificateDB::FindCertNicknames(nsISupports *aToken,
189 PRUint32 aType,
190 PRUint32 *_count,
191 PRUnichar ***_certNames)
193 nsNSSShutDownPreventionLock locker;
194 nsresult rv = NS_ERROR_FAILURE;
196 * obtain the cert list from NSS
198 CERTCertList *certList = NULL;
199 PK11CertListType pk11type;
200 #if 0
201 // this would seem right, but it didn't work...
202 // oh, I know why - bonks out on internal slot certs
203 if (aType == nsIX509Cert::USER_CERT)
204 pk11type = PK11CertListUser;
205 else
206 #endif
207 pk11type = PK11CertListUnique;
208 certList = PK11_ListCerts(pk11type, NULL);
209 if (!certList)
210 goto cleanup;
212 * get list of cert names from list of certs
213 * XXX also cull the list (NSS only distinguishes based on user/non-user
215 getCertNames(certList, aType, _count, _certNames);
216 rv = NS_OK;
218 * finish up
220 cleanup:
221 if (certList)
222 CERT_DestroyCertList(certList);
223 return rv;
226 SECStatus PR_CALLBACK
227 collect_certs(void *arg, SECItem **certs, int numcerts)
229 CERTDERCerts *collectArgs;
230 SECItem *cert;
231 SECStatus rv;
233 collectArgs = (CERTDERCerts *)arg;
235 collectArgs->numcerts = numcerts;
236 collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
237 sizeof(SECItem) * numcerts);
238 if ( collectArgs->rawCerts == NULL )
239 return(SECFailure);
241 cert = collectArgs->rawCerts;
243 while ( numcerts-- ) {
244 rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
245 if ( rv == SECFailure )
246 return(SECFailure);
247 cert++;
248 certs++;
251 return (SECSuccess);
254 CERTDERCerts*
255 nsNSSCertificateDB::getCertsFromPackage(PRArenaPool *arena, PRUint8 *data,
256 PRUint32 length)
258 nsNSSShutDownPreventionLock locker;
259 CERTDERCerts *collectArgs =
260 (CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts));
261 if ( collectArgs == nsnull )
262 return nsnull;
264 collectArgs->arena = arena;
265 SECStatus sec_rv = CERT_DecodeCertPackage(reinterpret_cast<char *>(data),
266 length, collect_certs,
267 (void *)collectArgs);
268 if (sec_rv != SECSuccess)
269 return nsnull;
271 return collectArgs;
274 nsresult
275 nsNSSCertificateDB::handleCACertDownload(nsIArray *x509Certs,
276 nsIInterfaceRequestor *ctx)
278 // First thing we have to do is figure out which certificate we're
279 // gonna present to the user. The CA may have sent down a list of
280 // certs which may or may not be a chained list of certs. Until
281 // the day we can design some solid UI for the general case, we'll
282 // code to the > 90% case. That case is where a CA sends down a
283 // list that is a hierarchy whose root is either the first or
284 // the last cert. What we're gonna do is compare the first
285 // 2 entries, if the second was signed by the first, we assume
286 // the root cert is the first cert and display it. Otherwise,
287 // we compare the last 2 entries, if the second to last cert was
288 // signed by the last cert, then we assume the last cert is the
289 // root and display it.
291 nsNSSShutDownPreventionLock locker;
293 PRUint32 numCerts;
295 x509Certs->GetLength(&numCerts);
296 NS_ASSERTION(numCerts > 0, "Didn't get any certs to import.");
297 if (numCerts == 0)
298 return NS_OK; // Nothing to import, so nothing to do.
300 nsCOMPtr<nsIX509Cert> certToShow;
301 nsCOMPtr<nsISupports> isupports;
302 PRUint32 selCertIndex;
303 if (numCerts == 1) {
304 // There's only one cert, so let's show it.
305 selCertIndex = 0;
306 certToShow = do_QueryElementAt(x509Certs, selCertIndex);
307 } else {
308 nsCOMPtr<nsIX509Cert> cert0; // first cert
309 nsCOMPtr<nsIX509Cert> cert1; // second cert
310 nsCOMPtr<nsIX509Cert> certn_2; // second to last cert
311 nsCOMPtr<nsIX509Cert> certn_1; // last cert
313 cert0 = do_QueryElementAt(x509Certs, 0);
314 cert1 = do_QueryElementAt(x509Certs, 1);
315 certn_2 = do_QueryElementAt(x509Certs, numCerts-2);
316 certn_1 = do_QueryElementAt(x509Certs, numCerts-1);
318 nsXPIDLString cert0SubjectName;
319 nsXPIDLString cert1IssuerName;
320 nsXPIDLString certn_2IssuerName;
321 nsXPIDLString certn_1SubjectName;
323 cert0->GetSubjectName(cert0SubjectName);
324 cert1->GetIssuerName(cert1IssuerName);
325 certn_2->GetIssuerName(certn_2IssuerName);
326 certn_1->GetSubjectName(certn_1SubjectName);
328 if (cert1IssuerName.Equals(cert0SubjectName)) {
329 // In this case, the first cert in the list signed the second,
330 // so the first cert is the root. Let's display it.
331 selCertIndex = 0;
332 certToShow = cert0;
333 } else
334 if (certn_2IssuerName.Equals(certn_1SubjectName)) {
335 // In this case the last cert has signed the second to last cert.
336 // The last cert is the root, so let's display it.
337 selCertIndex = numCerts-1;
338 certToShow = certn_1;
339 } else {
340 // It's not a chain, so let's just show the first one in the
341 // downloaded list.
342 selCertIndex = 0;
343 certToShow = cert0;
347 if (!certToShow)
348 return NS_ERROR_FAILURE;
350 nsCOMPtr<nsICertificateDialogs> dialogs;
351 nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs),
352 NS_GET_IID(nsICertificateDialogs),
353 NS_CERTIFICATEDIALOGS_CONTRACTID);
355 if (NS_FAILED(rv))
356 return rv;
358 SECItem der;
359 rv=certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data);
361 if (NS_FAILED(rv))
362 return rv;
364 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));
365 CERTCertificate *tmpCert;
366 CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
367 tmpCert = CERT_FindCertByDERCert(certdb, &der);
368 if (!tmpCert) {
369 tmpCert = CERT_NewTempCertificate(certdb, &der,
370 nsnull, PR_FALSE, PR_TRUE);
372 nsMemory::Free(der.data);
373 der.data = nsnull;
374 der.len = 0;
376 if (!tmpCert) {
377 NS_ERROR("Couldn't create cert from DER blob\n");
378 return NS_ERROR_FAILURE;
381 CERTCertificateCleaner tmpCertCleaner(tmpCert);
383 if (!CERT_IsCACert(tmpCert, NULL)) {
384 DisplayCertificateAlert(ctx, "NotACACert", certToShow);
385 return NS_ERROR_FAILURE;
388 if (tmpCert->isperm) {
389 DisplayCertificateAlert(ctx, "CaCertExists", certToShow);
390 return NS_ERROR_FAILURE;
393 PRUint32 trustBits;
394 PRBool allows;
395 rv = dialogs->ConfirmDownloadCACert(ctx, certToShow, &trustBits, &allows);
396 if (NS_FAILED(rv))
397 return rv;
399 if (!allows)
400 return NS_ERROR_NOT_AVAILABLE;
402 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits));
403 nsXPIDLCString nickname;
404 nickname.Adopt(CERT_MakeCANickname(tmpCert));
406 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));
408 nsNSSCertTrust trust;
409 trust.SetValidCA();
410 trust.AddCATrust(!!(trustBits & nsIX509CertDB::TRUSTED_SSL),
411 !!(trustBits & nsIX509CertDB::TRUSTED_EMAIL),
412 !!(trustBits & nsIX509CertDB::TRUSTED_OBJSIGN));
414 SECStatus srv = CERT_AddTempCertToPerm(tmpCert,
415 const_cast<char*>(nickname.get()),
416 trust.GetTrust());
418 if (srv != SECSuccess)
419 return NS_ERROR_FAILURE;
421 // Import additional delivered certificates that can be verified.
423 // build a CertList for filtering
424 CERTCertList *certList = CERT_NewCertList();
425 if (certList == NULL) {
426 return NS_ERROR_FAILURE;
429 CERTCertListCleaner listCleaner(certList);
431 // get all remaining certs into temp store
433 for (PRUint32 i=0; i<numCerts; i++) {
434 if (i == selCertIndex) {
435 // we already processed that one
436 continue;
439 certToShow = do_QueryElementAt(x509Certs, i);
440 certToShow->GetRawDER(&der.len, (PRUint8 **)&der.data);
442 CERTCertificate *tmpCert2 =
443 CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE);
445 nsMemory::Free(der.data);
446 der.data = nsnull;
447 der.len = 0;
449 if (!tmpCert2) {
450 NS_ASSERTION(0, "Couldn't create temp cert from DER blob\n");
451 continue; // Let's try to import the rest of 'em
454 CERT_AddCertToListTail(certList, tmpCert2);
457 return ImportValidCACertsInList(certList, ctx);
461 * [noscript] void importCertificates(in charPtr data, in unsigned long length,
462 * in unsigned long type,
463 * in nsIInterfaceRequestor ctx);
465 NS_IMETHODIMP
466 nsNSSCertificateDB::ImportCertificates(PRUint8 * data, PRUint32 length,
467 PRUint32 type,
468 nsIInterfaceRequestor *ctx)
471 nsNSSShutDownPreventionLock locker;
472 nsresult nsrv;
474 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
475 if (!arena)
476 return NS_ERROR_OUT_OF_MEMORY;
478 CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length);
479 if (!certCollection) {
480 PORT_FreeArena(arena, PR_FALSE);
481 return NS_ERROR_FAILURE;
483 nsCOMPtr<nsIMutableArray> array =
484 do_CreateInstance(NS_ARRAY_CONTRACTID, &nsrv);
485 if (NS_FAILED(nsrv)) {
486 PORT_FreeArena(arena, PR_FALSE);
487 return nsrv;
490 // Now let's create some certs to work with
491 nsCOMPtr<nsIX509Cert> x509Cert;
492 nsNSSCertificate *nssCert;
493 SECItem *currItem;
494 for (int i=0; i<certCollection->numcerts; i++) {
495 currItem = &certCollection->rawCerts[i];
496 nssCert = nsNSSCertificate::ConstructFromDER((char*)currItem->data, currItem->len);
497 if (!nssCert)
498 return NS_ERROR_FAILURE;
499 x509Cert = do_QueryInterface((nsIX509Cert*)nssCert);
500 array->AppendElement(x509Cert, PR_FALSE);
502 switch (type) {
503 case nsIX509Cert::CA_CERT:
504 nsrv = handleCACertDownload(array, ctx);
505 break;
506 default:
507 // We only deal with import CA certs in this method currently.
508 nsrv = NS_ERROR_FAILURE;
509 break;
511 PORT_FreeArena(arena, PR_FALSE);
512 return nsrv;
517 * [noscript] void importEmailCertificates(in charPtr data, in unsigned long length,
518 * in nsIInterfaceRequestor ctx);
520 NS_IMETHODIMP
521 nsNSSCertificateDB::ImportEmailCertificate(PRUint8 * data, PRUint32 length,
522 nsIInterfaceRequestor *ctx)
525 nsNSSShutDownPreventionLock locker;
526 SECStatus srv = SECFailure;
527 nsresult nsrv = NS_OK;
528 CERTCertDBHandle *certdb;
529 CERTCertificate **certArray = NULL;
530 CERTCertList *certList = NULL;
531 CERTCertListNode *node;
532 PRTime now;
533 SECCertUsage certusage;
534 SECItem **rawArray;
535 int numcerts;
536 int i;
538 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
539 if (!arena)
540 return NS_ERROR_OUT_OF_MEMORY;
542 CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length);
543 if (!certCollection) {
544 PORT_FreeArena(arena, PR_FALSE);
545 return NS_ERROR_FAILURE;
548 certdb = CERT_GetDefaultCertDB();
549 certusage = certUsageEmailRecipient;
551 numcerts = certCollection->numcerts;
553 rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
554 if ( !rawArray ) {
555 nsrv = NS_ERROR_FAILURE;
556 goto loser;
559 for (i=0; i < numcerts; i++) {
560 rawArray[i] = &certCollection->rawCerts[i];
563 srv = CERT_ImportCerts(certdb, certusage, numcerts, rawArray,
564 &certArray, PR_FALSE, PR_FALSE, NULL);
566 PORT_Free(rawArray);
567 rawArray = NULL;
569 if (srv != SECSuccess) {
570 nsrv = NS_ERROR_FAILURE;
571 goto loser;
574 // build a CertList for filtering
575 certList = CERT_NewCertList();
576 if (certList == NULL) {
577 nsrv = NS_ERROR_FAILURE;
578 goto loser;
580 for (i=0; i < numcerts; i++) {
581 CERTCertificate *cert = certArray[i];
582 if (cert)
583 cert = CERT_DupCertificate(cert);
584 if (cert)
585 CERT_AddCertToListTail(certList, cert);
588 /* go down the remaining list of certs and verify that they have
589 * valid chains, then import them.
591 now = PR_Now();
592 for (node = CERT_LIST_HEAD(certList);
593 !CERT_LIST_END(node,certList);
594 node = CERT_LIST_NEXT(node)) {
596 bool alert_and_skip = false;
598 if (!node->cert) {
599 continue;
602 if (CERT_VerifyCert(certdb, node->cert,
603 PR_TRUE, certusage, now, ctx, NULL) != SECSuccess) {
604 alert_and_skip = true;
607 CERTCertificateList *certChain = nsnull;
608 CERTCertificateListCleaner chainCleaner(certChain);
610 if (!alert_and_skip) {
611 certChain = CERT_CertChainFromCert(node->cert, certusage, PR_FALSE);
612 if (!certChain) {
613 alert_and_skip = true;
617 if (alert_and_skip) {
618 nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(node->cert);
619 DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow);
620 continue;
624 * CertChain returns an array of SECItems, import expects an array of
625 * SECItem pointers. Create the SECItem Pointers from the array of
626 * SECItems.
628 rawArray = (SECItem **) PORT_Alloc(certChain->len * sizeof(SECItem *));
629 if (!rawArray) {
630 continue;
632 for (i=0; i < certChain->len; i++) {
633 rawArray[i] = &certChain->certs[i];
635 CERT_ImportCerts(certdb, certusage, certChain->len,
636 rawArray, NULL, PR_TRUE, PR_FALSE, NULL);
638 CERT_SaveSMimeProfile(node->cert, NULL, NULL);
640 PORT_Free(rawArray);
643 loser:
644 if (certArray) {
645 CERT_DestroyCertArray(certArray, numcerts);
647 if (certList) {
648 CERT_DestroyCertList(certList);
650 if (arena)
651 PORT_FreeArena(arena, PR_TRUE);
652 return nsrv;
655 NS_IMETHODIMP
656 nsNSSCertificateDB::ImportServerCertificate(PRUint8 * data, PRUint32 length,
657 nsIInterfaceRequestor *ctx)
660 nsNSSShutDownPreventionLock locker;
661 SECStatus srv = SECFailure;
662 nsresult nsrv = NS_OK;
663 CERTCertificate * cert;
664 SECItem **rawCerts = nsnull;
665 int numcerts;
666 int i;
667 nsNSSCertTrust trust;
668 char *serverNickname = nsnull;
670 PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
671 if (!arena)
672 return NS_ERROR_OUT_OF_MEMORY;
674 CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length);
675 if (!certCollection) {
676 PORT_FreeArena(arena, PR_FALSE);
677 return NS_ERROR_FAILURE;
679 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts,
680 (char *)NULL, PR_FALSE, PR_TRUE);
681 if (!cert) {
682 nsrv = NS_ERROR_FAILURE;
683 goto loser;
685 numcerts = certCollection->numcerts;
686 rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
687 if ( !rawCerts ) {
688 nsrv = NS_ERROR_FAILURE;
689 goto loser;
692 for ( i = 0; i < numcerts; i++ ) {
693 rawCerts[i] = &certCollection->rawCerts[i];
696 serverNickname = nsNSSCertificate::defaultServerNickname(cert);
697 srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageSSLServer,
698 numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE,
699 serverNickname);
700 PR_FREEIF(serverNickname);
701 if ( srv != SECSuccess ) {
702 nsrv = NS_ERROR_FAILURE;
703 goto loser;
706 trust.SetValidServerPeer();
707 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, trust.GetTrust());
708 if ( srv != SECSuccess ) {
709 nsrv = NS_ERROR_FAILURE;
710 goto loser;
712 loser:
713 PORT_Free(rawCerts);
714 if (cert)
715 CERT_DestroyCertificate(cert);
716 if (arena)
717 PORT_FreeArena(arena, PR_TRUE);
718 return nsrv;
721 nsresult
722 nsNSSCertificateDB::ImportValidCACerts(int numCACerts, SECItem *CACerts, nsIInterfaceRequestor *ctx)
724 CERTCertList *certList = NULL;
725 SECItem **rawArray;
727 // build a CertList for filtering
728 certList = CERT_NewCertList();
729 if (certList == NULL) {
730 return NS_ERROR_FAILURE;
733 CERTCertListCleaner listCleaner(certList);
735 // get all certs into temp store
736 SECStatus srv = SECFailure;
737 CERTCertificate **certArray = NULL;
739 rawArray = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numCACerts);
740 if ( !rawArray ) {
741 return NS_ERROR_FAILURE;
744 for (int i=0; i < numCACerts; i++) {
745 rawArray[i] = &CACerts[i];
748 srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, numCACerts, rawArray,
749 &certArray, PR_FALSE, PR_TRUE, NULL);
751 PORT_Free(rawArray);
752 rawArray = NULL;
754 if (srv != SECSuccess) {
755 return NS_ERROR_FAILURE;
758 for (int i2=0; i2 < numCACerts; i2++) {
759 CERTCertificate *cacert = certArray[i2];
760 if (cacert)
761 cacert = CERT_DupCertificate(cacert);
762 if (cacert)
763 CERT_AddCertToListTail(certList, cacert);
766 CERT_DestroyCertArray(certArray, numCACerts);
768 return ImportValidCACertsInList(certList, ctx);
771 nsresult
772 nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx)
774 SECItem **rawArray;
776 /* filter out the certs we don't want */
777 SECStatus srv = CERT_FilterCertListByUsage(certList, certUsageAnyCA, PR_TRUE);
778 if (srv != SECSuccess) {
779 return NS_ERROR_FAILURE;
782 /* go down the remaining list of certs and verify that they have
783 * valid chains, if yes, then import.
785 PRTime now = PR_Now();
786 CERTCertListNode *node;
787 for (node = CERT_LIST_HEAD(certList);
788 !CERT_LIST_END(node,certList);
789 node = CERT_LIST_NEXT(node)) {
791 bool alert_and_skip = false;
793 if (CERT_VerifyCert(CERT_GetDefaultCertDB(), node->cert,
794 PR_TRUE, certUsageVerifyCA, now, ctx, NULL) != SECSuccess) {
795 alert_and_skip = true;
798 CERTCertificateList *certChain = nsnull;
799 CERTCertificateListCleaner chainCleaner(certChain);
801 if (!alert_and_skip) {
802 certChain = CERT_CertChainFromCert(node->cert, certUsageAnyCA, PR_FALSE);
803 if (!certChain) {
804 alert_and_skip = true;
808 if (alert_and_skip) {
809 nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(node->cert);
810 DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow);
811 continue;
815 * CertChain returns an array of SECItems, import expects an array of
816 * SECItem pointers. Create the SECItem Pointers from the array of
817 * SECItems.
819 rawArray = (SECItem **) PORT_Alloc(certChain->len * sizeof(SECItem *));
820 if (!rawArray) {
821 continue;
823 for (int i=0; i < certChain->len; i++) {
824 rawArray[i] = &certChain->certs[i];
826 CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageAnyCA, certChain->len,
827 rawArray, NULL, PR_TRUE, PR_TRUE, NULL);
829 PORT_Free(rawArray);
832 return NS_OK;
835 void nsNSSCertificateDB::DisplayCertificateAlert(nsIInterfaceRequestor *ctx,
836 const char *stringID,
837 nsIX509Cert *certToShow)
839 nsPSMUITracker tracker;
840 if (!tracker.isUIForbidden()) {
842 nsCOMPtr<nsIInterfaceRequestor> my_cxt = ctx;
843 if (!my_cxt)
844 my_cxt = new PipUIContext();
846 // This shall be replaced by embedding ovverridable prompts
847 // as discussed in bug 310446, and should make use of certToShow.
849 nsresult rv;
850 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
851 if (NS_SUCCEEDED(rv)) {
852 nsAutoString tmpMessage;
853 nssComponent->GetPIPNSSBundleString(stringID, tmpMessage);
855 // The interface requestor object may not be safe, so proxy the call to get
856 // the nsIPrompt.
858 nsCOMPtr<nsIInterfaceRequestor> proxiedCallbacks;
859 NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
860 NS_GET_IID(nsIInterfaceRequestor),
861 my_cxt,
862 NS_PROXY_SYNC,
863 getter_AddRefs(proxiedCallbacks));
865 nsCOMPtr<nsIPrompt> prompt (do_GetInterface(proxiedCallbacks));
866 if (!prompt)
867 return;
869 // Finally, get a proxy for the nsIPrompt
871 nsCOMPtr<nsIPrompt> proxyPrompt;
872 NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
873 NS_GET_IID(nsIPrompt),
874 prompt,
875 NS_PROXY_SYNC,
876 getter_AddRefs(proxyPrompt));
878 proxyPrompt->Alert(nsnull, tmpMessage.get());
884 NS_IMETHODIMP
885 nsNSSCertificateDB::ImportUserCertificate(PRUint8 *data, PRUint32 length, nsIInterfaceRequestor *ctx)
887 nsNSSShutDownPreventionLock locker;
888 PK11SlotInfo *slot;
889 nsCAutoString nickname;
890 nsresult rv = NS_ERROR_FAILURE;
891 int numCACerts;
892 SECItem *CACerts;
893 CERTDERCerts * collectArgs;
894 PRArenaPool *arena;
895 CERTCertificate * cert=NULL;
897 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
898 if ( arena == NULL ) {
899 goto loser;
902 collectArgs = getCertsFromPackage(arena, data, length);
903 if (!collectArgs) {
904 goto loser;
907 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
908 (char *)NULL, PR_FALSE, PR_TRUE);
909 if (!cert) {
910 goto loser;
913 slot = PK11_KeyForCertExists(cert, NULL, ctx);
914 if ( slot == NULL ) {
915 nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert);
916 DisplayCertificateAlert(ctx, "UserCertIgnoredNoPrivateKey", certToShow);
917 goto loser;
919 PK11_FreeSlot(slot);
921 /* pick a nickname for the cert */
922 if (cert->nickname) {
923 /* sigh, we need a call to look up other certs with this subject and
924 * identify nicknames from them. We can no longer walk down internal
925 * database structures rjr */
926 nickname = cert->nickname;
928 else {
929 get_default_nickname(cert, ctx, nickname);
932 /* user wants to import the cert */
934 char *cast_const_away = const_cast<char*>(nickname.get());
935 slot = PK11_ImportCertForKey(cert, cast_const_away, ctx);
937 if (!slot) {
938 goto loser;
940 PK11_FreeSlot(slot);
943 nsCOMPtr<nsIX509Cert> certToShow = new nsNSSCertificate(cert);
944 DisplayCertificateAlert(ctx, "UserCertImported", certToShow);
946 rv = NS_OK;
948 numCACerts = collectArgs->numcerts - 1;
949 if (numCACerts) {
950 CACerts = collectArgs->rawCerts+1;
951 rv = ImportValidCACerts(numCACerts, CACerts, ctx);
954 loser:
955 if (arena) {
956 PORT_FreeArena(arena, PR_FALSE);
958 if ( cert ) {
959 CERT_DestroyCertificate(cert);
961 return rv;
965 * void deleteCertificate(in nsIX509Cert aCert);
967 NS_IMETHODIMP
968 nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
970 nsNSSShutDownPreventionLock locker;
971 nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
972 CERTCertificate *cert = nssCert->GetCert();
973 if (!cert) return NS_ERROR_FAILURE;
974 CERTCertificateCleaner certCleaner(cert);
975 SECStatus srv = SECSuccess;
977 PRUint32 certType;
978 nssCert->GetCertType(&certType);
979 if (NS_FAILED(nssCert->MarkForPermDeletion()))
981 return NS_ERROR_FAILURE;
984 if (cert->slot && certType != nsIX509Cert::USER_CERT) {
985 // To delete a cert of a slot (builtin, most likely), mark it as
986 // completely untrusted. This way we keep a copy cached in the
987 // local database, and next time we try to load it off of the
988 // external token/slot, we'll know not to trust it. We don't
989 // want to do that with user certs, because a user may re-store
990 // the cert onto the card again at which point we *will* want to
991 // trust that cert if it chains up properly.
992 nsNSSCertTrust trust(0, 0, 0);
993 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
994 cert, trust.GetTrust());
996 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv));
997 return (srv) ? NS_ERROR_FAILURE : NS_OK;
1001 * void setCertTrust(in nsIX509Cert cert,
1002 * in unsigned long type,
1003 * in unsigned long trust);
1005 NS_IMETHODIMP
1006 nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
1007 PRUint32 type,
1008 PRUint32 trusted)
1010 nsNSSShutDownPreventionLock locker;
1011 SECStatus srv;
1012 nsNSSCertTrust trust;
1013 nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
1014 if (!pipCert)
1015 return NS_ERROR_FAILURE;
1016 CERTCertificate *nsscert = pipCert->GetCert();
1017 CERTCertificateCleaner certCleaner(nsscert);
1018 if (type == nsIX509Cert::CA_CERT) {
1019 // always start with untrusted and move up
1020 trust.SetValidCA();
1021 trust.AddCATrust(!!(trusted & nsIX509CertDB::TRUSTED_SSL),
1022 !!(trusted & nsIX509CertDB::TRUSTED_EMAIL),
1023 !!(trusted & nsIX509CertDB::TRUSTED_OBJSIGN));
1024 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
1025 nsscert,
1026 trust.GetTrust());
1027 } else if (type == nsIX509Cert::SERVER_CERT) {
1028 // always start with untrusted and move up
1029 trust.SetValidPeer();
1030 trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0);
1031 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
1032 nsscert,
1033 trust.GetTrust());
1034 } else if (type == nsIX509Cert::EMAIL_CERT) {
1035 // always start with untrusted and move up
1036 trust.SetValidPeer();
1037 trust.AddPeerTrust(0, !!(trusted & nsIX509CertDB::TRUSTED_EMAIL), 0);
1038 srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
1039 nsscert,
1040 trust.GetTrust());
1041 } else {
1042 // ignore user certs
1043 return NS_OK;
1045 return (srv) ? NS_ERROR_FAILURE : NS_OK;
1048 NS_IMETHODIMP
1049 nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert,
1050 PRUint32 certType,
1051 PRUint32 trustType,
1052 PRBool *_isTrusted)
1054 NS_ENSURE_ARG_POINTER(_isTrusted);
1055 *_isTrusted = PR_FALSE;
1057 nsNSSShutDownPreventionLock locker;
1058 SECStatus srv;
1059 nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
1060 CERTCertificate *nsscert = pipCert->GetCert();
1061 CERTCertTrust nsstrust;
1062 srv = CERT_GetCertTrust(nsscert, &nsstrust);
1063 if (srv != SECSuccess)
1064 return NS_ERROR_FAILURE;
1066 nsNSSCertTrust trust(&nsstrust);
1067 CERT_DestroyCertificate(nsscert);
1068 if (certType == nsIX509Cert::CA_CERT) {
1069 if (trustType & nsIX509CertDB::TRUSTED_SSL) {
1070 *_isTrusted = trust.HasTrustedCA(PR_TRUE, PR_FALSE, PR_FALSE);
1071 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
1072 *_isTrusted = trust.HasTrustedCA(PR_FALSE, PR_TRUE, PR_FALSE);
1073 } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
1074 *_isTrusted = trust.HasTrustedCA(PR_FALSE, PR_FALSE, PR_TRUE);
1075 } else {
1076 return NS_ERROR_FAILURE;
1078 } else if (certType == nsIX509Cert::SERVER_CERT) {
1079 if (trustType & nsIX509CertDB::TRUSTED_SSL) {
1080 *_isTrusted = trust.HasTrustedPeer(PR_TRUE, PR_FALSE, PR_FALSE);
1081 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
1082 *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_TRUE, PR_FALSE);
1083 } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
1084 *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_FALSE, PR_TRUE);
1085 } else {
1086 return NS_ERROR_FAILURE;
1088 } else if (certType == nsIX509Cert::EMAIL_CERT) {
1089 if (trustType & nsIX509CertDB::TRUSTED_SSL) {
1090 *_isTrusted = trust.HasTrustedPeer(PR_TRUE, PR_FALSE, PR_FALSE);
1091 } else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
1092 *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_TRUE, PR_FALSE);
1093 } else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
1094 *_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_FALSE, PR_TRUE);
1095 } else {
1096 return NS_ERROR_FAILURE;
1098 } /* user: ignore */
1099 return NS_OK;
1103 NS_IMETHODIMP
1104 nsNSSCertificateDB::ImportCertsFromFile(nsISupports *aToken,
1105 nsILocalFile *aFile,
1106 PRUint32 aType)
1108 NS_ENSURE_ARG(aFile);
1109 switch (aType) {
1110 case nsIX509Cert::CA_CERT:
1111 case nsIX509Cert::EMAIL_CERT:
1112 case nsIX509Cert::SERVER_CERT:
1113 // good
1114 break;
1116 default:
1117 // not supported (yet)
1118 return NS_ERROR_FAILURE;
1121 nsresult rv;
1122 PRFileDesc *fd = nsnull;
1124 rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
1126 if (NS_FAILED(rv))
1127 return rv;
1129 if (!fd)
1130 return NS_ERROR_FAILURE;
1132 PRFileInfo file_info;
1133 if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &file_info))
1134 return NS_ERROR_FAILURE;
1136 unsigned char *buf = new unsigned char[file_info.size];
1137 if (!buf)
1138 return NS_ERROR_OUT_OF_MEMORY;
1140 PRInt32 bytes_obtained = PR_Read(fd, buf, file_info.size);
1141 PR_Close(fd);
1143 if (bytes_obtained != file_info.size)
1144 rv = NS_ERROR_FAILURE;
1145 else {
1146 nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
1148 switch (aType) {
1149 case nsIX509Cert::CA_CERT:
1150 rv = ImportCertificates(buf, bytes_obtained, aType, cxt);
1151 break;
1153 case nsIX509Cert::SERVER_CERT:
1154 rv = ImportServerCertificate(buf, bytes_obtained, cxt);
1155 break;
1157 case nsIX509Cert::EMAIL_CERT:
1158 rv = ImportEmailCertificate(buf, bytes_obtained, cxt);
1159 break;
1161 default:
1162 break;
1166 delete [] buf;
1167 return rv;
1170 NS_IMETHODIMP
1171 nsNSSCertificateDB::ImportPKCS12File(nsISupports *aToken,
1172 nsILocalFile *aFile)
1174 NS_ENSURE_ARG(aFile);
1175 nsPKCS12Blob blob;
1176 nsCOMPtr<nsIPK11Token> token = do_QueryInterface(aToken);
1177 if (token) {
1178 blob.SetToken(token);
1180 return blob.ImportFromFile(aFile);
1183 NS_IMETHODIMP
1184 nsNSSCertificateDB::ExportPKCS12File(nsISupports *aToken,
1185 nsILocalFile *aFile,
1186 PRUint32 count,
1187 nsIX509Cert **certs)
1188 //const PRUnichar **aCertNames)
1190 nsNSSShutDownPreventionLock locker;
1191 NS_ENSURE_ARG(aFile);
1192 nsPKCS12Blob blob;
1193 if (count == 0) return NS_OK;
1194 nsCOMPtr<nsIPK11Token> localRef;
1195 if (!aToken) {
1196 PK11SlotInfo *keySlot = PK11_GetInternalKeySlot();
1197 NS_ASSERTION(keySlot,"Failed to get the internal key slot");
1198 localRef = new nsPK11Token(keySlot);
1199 PK11_FreeSlot(keySlot);
1201 else {
1202 localRef = do_QueryInterface(aToken);
1204 blob.SetToken(localRef);
1205 //blob.LoadCerts(aCertNames, count);
1206 //return blob.ExportToFile(aFile);
1207 return blob.ExportToFile(aFile, certs, count);
1211 static SECStatus PR_CALLBACK
1212 GetOCSPResponders (CERTCertificate *aCert,
1213 SECItem *aDBKey,
1214 void *aArg)
1216 nsIMutableArray *array = static_cast<nsIMutableArray*>(aArg);
1217 PRUnichar* nn = nsnull;
1218 PRUnichar* url = nsnull;
1219 char *serviceURL = nsnull;
1220 char *nickname = nsnull;
1221 PRUint32 i, count;
1222 nsresult rv;
1224 // Are we interested in this cert //
1225 if (!nsOCSPResponder::IncludeCert(aCert)) {
1226 return SECSuccess;
1229 // Get the AIA and nickname //
1230 serviceURL = CERT_GetOCSPAuthorityInfoAccessLocation(aCert);
1231 if (serviceURL) {
1232 url = ToNewUnicode(NS_ConvertUTF8toUTF16(serviceURL));
1233 PORT_Free(serviceURL);
1236 nickname = aCert->nickname;
1237 nn = ToNewUnicode(NS_ConvertUTF8toUTF16(nickname));
1239 nsCOMPtr<nsIOCSPResponder> new_entry = new nsOCSPResponder(nn, url);
1240 nsMemory::Free(nn);
1241 nsMemory::Free(url);
1243 // Sort the items according to nickname //
1244 rv = array->GetLength(&count);
1245 for (i=0; i < count; ++i) {
1246 nsCOMPtr<nsIOCSPResponder> entry = do_QueryElementAt(array, i);
1247 if (nsOCSPResponder::CompareEntries(new_entry, entry) < 0) {
1248 array->InsertElementAt(new_entry, i, PR_FALSE);
1249 break;
1252 if (i == count) {
1253 array->AppendElement(new_entry, PR_FALSE);
1255 return SECSuccess;
1261 * getOCSPResponders
1263 * Export a set of certs and keys from the database to a PKCS#12 file.
1265 NS_IMETHODIMP
1266 nsNSSCertificateDB::GetOCSPResponders(nsIArray ** aResponders)
1268 nsNSSShutDownPreventionLock locker;
1269 SECStatus sec_rv;
1270 nsCOMPtr<nsIMutableArray> respondersArray =
1271 do_CreateInstance(NS_ARRAY_CONTRACTID);
1272 if (!respondersArray) {
1273 return NS_ERROR_OUT_OF_MEMORY;
1276 sec_rv = PK11_TraverseSlotCerts(::GetOCSPResponders,
1277 respondersArray,
1278 nsnull);
1279 if (sec_rv != SECSuccess) {
1280 goto loser;
1283 *aResponders = respondersArray;
1284 NS_IF_ADDREF(*aResponders);
1285 return NS_OK;
1286 loser:
1287 return NS_ERROR_FAILURE;
1291 * NSS Helper Routines (private to nsNSSCertificateDB)
1294 #define DELIM '\001'
1297 * GetSortedNameList
1299 * Converts a CERTCertList to a list of certificate names
1301 void
1302 nsNSSCertificateDB::getCertNames(CERTCertList *certList,
1303 PRUint32 type,
1304 PRUint32 *_count,
1305 PRUnichar ***_certNames)
1307 nsNSSShutDownPreventionLock locker;
1308 nsresult rv;
1309 CERTCertListNode *node;
1310 PRUint32 numcerts = 0, i=0;
1311 PRUnichar **tmpArray = NULL;
1312 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("List of certs %d:\n", type));
1313 for (node = CERT_LIST_HEAD(certList);
1314 !CERT_LIST_END(node, certList);
1315 node = CERT_LIST_NEXT(node)) {
1316 if (getCertType(node->cert) == type) {
1317 numcerts++;
1320 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("num certs: %d\n", numcerts));
1321 int nc = (numcerts == 0) ? 1 : numcerts;
1322 tmpArray = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nc);
1323 if (numcerts == 0) goto finish;
1324 for (node = CERT_LIST_HEAD(certList);
1325 !CERT_LIST_END(node, certList);
1326 node = CERT_LIST_NEXT(node)) {
1327 if (getCertType(node->cert) == type) {
1328 nsNSSCertificate pipCert(node->cert);
1329 char *dbkey = NULL;
1330 char *namestr = NULL;
1331 nsAutoString certstr;
1332 rv = pipCert.GetDbKey(&dbkey);
1333 nsAutoString keystr = NS_ConvertASCIItoUTF16(dbkey);
1334 PR_FREEIF(dbkey);
1335 if (type == nsIX509Cert::EMAIL_CERT) {
1336 namestr = node->cert->emailAddr;
1337 } else {
1338 namestr = node->cert->nickname;
1339 if (namestr) {
1340 char *sc = strchr(namestr, ':');
1341 if (sc) *sc = DELIM;
1344 if (!namestr) namestr = "";
1345 nsAutoString certname = NS_ConvertASCIItoUTF16(namestr);
1346 certstr.Append(PRUnichar(DELIM));
1347 certstr += certname;
1348 certstr.Append(PRUnichar(DELIM));
1349 certstr += keystr;
1350 tmpArray[i++] = ToNewUnicode(certstr);
1353 finish:
1354 *_count = numcerts;
1355 *_certNames = tmpArray;
1358 /* somewhat follows logic of cert_list_include_cert from PSM 1.x */
1361 NS_IMETHODIMP
1362 nsNSSCertificateDB::GetIsOcspOn(PRBool *aOcspOn)
1364 nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
1366 PRInt32 ocspEnabled;
1367 pref->GetIntPref("security.OCSP.enabled", &ocspEnabled);
1368 *aOcspOn = ( ocspEnabled == 0 ) ? PR_FALSE : PR_TRUE;
1369 return NS_OK;
1372 /* nsIX509Cert getDefaultEmailEncryptionCert (); */
1373 NS_IMETHODIMP
1374 nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509Cert **_retval)
1376 if (!_retval)
1377 return NS_ERROR_FAILURE;
1379 *_retval = 0;
1381 if (aNickname.IsEmpty())
1382 return NS_OK;
1384 nsNSSShutDownPreventionLock locker;
1385 nsresult rv = NS_OK;
1386 CERTCertificate *cert = 0;
1387 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
1388 nsNSSCertificate *nssCert = nsnull;
1389 char *asciiname = NULL;
1390 NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname);
1391 asciiname = const_cast<char*>(aUtf8Nickname.get());
1393 /* Find a good cert in the user's database */
1394 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname,
1395 certUsageEmailRecipient, PR_TRUE, ctx);
1397 if (!cert) { goto loser; }
1399 nssCert = new nsNSSCertificate(cert);
1400 if (nssCert == nsnull) {
1401 rv = NS_ERROR_OUT_OF_MEMORY;
1403 NS_ADDREF(nssCert);
1405 *_retval = static_cast<nsIX509Cert*>(nssCert);
1407 loser:
1408 if (cert) CERT_DestroyCertificate(cert);
1409 return rv;
1412 /* nsIX509Cert getDefaultEmailSigningCert (); */
1413 NS_IMETHODIMP
1414 nsNSSCertificateDB::FindEmailSigningCert(const nsAString &aNickname, nsIX509Cert **_retval)
1416 if (!_retval)
1417 return NS_ERROR_FAILURE;
1419 *_retval = 0;
1421 if (aNickname.IsEmpty())
1422 return NS_OK;
1424 nsNSSShutDownPreventionLock locker;
1425 nsresult rv = NS_OK;
1426 CERTCertificate *cert = 0;
1427 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
1428 nsNSSCertificate *nssCert = nsnull;
1429 char *asciiname = NULL;
1430 NS_ConvertUTF16toUTF8 aUtf8Nickname(aNickname);
1431 asciiname = const_cast<char*>(aUtf8Nickname.get());
1433 /* Find a good cert in the user's database */
1434 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname,
1435 certUsageEmailSigner, PR_TRUE, ctx);
1437 if (!cert) { goto loser; }
1439 nssCert = new nsNSSCertificate(cert);
1440 if (nssCert == nsnull) {
1441 rv = NS_ERROR_OUT_OF_MEMORY;
1443 NS_ADDREF(nssCert);
1445 *_retval = static_cast<nsIX509Cert*>(nssCert);
1447 loser:
1448 if (cert) CERT_DestroyCertificate(cert);
1449 return rv;
1452 NS_IMETHODIMP
1453 nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEmailAddress, nsIX509Cert **_retval)
1455 nsNSSShutDownPreventionLock locker;
1456 CERTCertificate *any_cert = CERT_FindCertByNicknameOrEmailAddr(CERT_GetDefaultCertDB(), (char*)aEmailAddress);
1457 if (!any_cert)
1458 return NS_ERROR_FAILURE;
1460 CERTCertificateCleaner certCleaner(any_cert);
1462 // any_cert now contains a cert with the right subject, but it might not have the correct usage
1463 CERTCertList *certlist = CERT_CreateSubjectCertList(
1464 nsnull, CERT_GetDefaultCertDB(), &any_cert->derSubject, PR_Now(), PR_TRUE);
1465 if (!certlist)
1466 return NS_ERROR_FAILURE;
1468 CERTCertListCleaner listCleaner(certlist);
1470 if (SECSuccess != CERT_FilterCertListByUsage(certlist, certUsageEmailRecipient, PR_FALSE))
1471 return NS_ERROR_FAILURE;
1473 if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist))
1474 return NS_ERROR_FAILURE;
1476 nsNSSCertificate *nssCert = new nsNSSCertificate(CERT_LIST_HEAD(certlist)->cert);
1477 if (!nssCert)
1478 return NS_ERROR_OUT_OF_MEMORY;
1480 NS_ADDREF(nssCert);
1481 *_retval = static_cast<nsIX509Cert*>(nssCert);
1482 return NS_OK;
1485 /* nsIX509Cert constructX509FromBase64 (in string base64); */
1486 NS_IMETHODIMP
1487 nsNSSCertificateDB::ConstructX509FromBase64(const char * base64, nsIX509Cert **_retval)
1489 if (!_retval) {
1490 return NS_ERROR_FAILURE;
1493 nsNSSShutDownPreventionLock locker;
1494 PRUint32 len = PL_strlen(base64);
1495 int adjust = 0;
1497 /* Compute length adjustment */
1498 if (base64[len-1] == '=') {
1499 adjust++;
1500 if (base64[len-2] == '=') adjust++;
1503 nsresult rv = NS_OK;
1504 char *certDER = 0;
1505 PRInt32 lengthDER = 0;
1507 certDER = PL_Base64Decode(base64, len, NULL);
1508 if (!certDER || !*certDER) {
1509 rv = NS_ERROR_ILLEGAL_VALUE;
1511 else {
1512 lengthDER = (len*3)/4 - adjust;
1514 SECItem secitem_cert;
1515 secitem_cert.type = siDERCertBuffer;
1516 secitem_cert.data = (unsigned char*)certDER;
1517 secitem_cert.len = lengthDER;
1519 CERTCertificate *cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert, nsnull, PR_FALSE, PR_TRUE);
1521 if (!cert) {
1522 rv = NS_ERROR_FAILURE;
1524 else {
1525 nsNSSCertificate *nsNSS = new nsNSSCertificate(cert);
1526 if (!nsNSS) {
1527 rv = NS_ERROR_OUT_OF_MEMORY;
1529 else {
1530 nsresult rv = nsNSS->QueryInterface(NS_GET_IID(nsIX509Cert), (void**)_retval);
1532 if (NS_SUCCEEDED(rv) && *_retval) {
1533 NS_ADDREF(*_retval);
1536 NS_RELEASE(nsNSS);
1538 CERT_DestroyCertificate(cert);
1542 if (certDER) {
1543 nsCRT::free(certDER);
1545 return rv;
1548 void
1549 nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert,
1550 nsIInterfaceRequestor* ctx,
1551 nsCString &nickname)
1553 nickname.Truncate();
1555 nsNSSShutDownPreventionLock locker;
1556 nsresult rv;
1557 CK_OBJECT_HANDLE keyHandle;
1559 CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
1560 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
1561 if (NS_FAILED(rv))
1562 return;
1564 nsCAutoString username;
1565 char *temp_un = CERT_GetCommonName(&cert->subject);
1566 if (temp_un) {
1567 username = temp_un;
1568 PORT_Free(temp_un);
1569 temp_un = nsnull;
1572 nsCAutoString caname;
1573 char *temp_ca = CERT_GetOrgName(&cert->issuer);
1574 if (temp_ca) {
1575 caname = temp_ca;
1576 PORT_Free(temp_ca);
1577 temp_ca = nsnull;
1580 nsAutoString tmpNickFmt;
1581 nssComponent->GetPIPNSSBundleString("nick_template", tmpNickFmt);
1582 NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt);
1584 nsCAutoString baseName;
1585 char *temp_nn = PR_smprintf(nickFmt.get(), username.get(), caname.get());
1586 if (!temp_nn) {
1587 return;
1588 } else {
1589 baseName = temp_nn;
1590 PR_smprintf_free(temp_nn);
1591 temp_nn = nsnull;
1594 nickname = baseName;
1597 * We need to see if the private key exists on a token, if it does
1598 * then we need to check for nicknames that already exist on the smart
1599 * card.
1601 PK11SlotInfo *slot = PK11_KeyForCertExists(cert, &keyHandle, ctx);
1602 PK11SlotInfoCleaner slotCleaner(slot);
1603 if (!slot)
1604 return;
1606 if (!PK11_IsInternal(slot)) {
1607 char *tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), baseName.get());
1608 if (!tmp) {
1609 nickname.Truncate();
1610 return;
1612 baseName = tmp;
1613 PR_smprintf_free(tmp);
1615 nickname = baseName;
1618 int count = 1;
1619 while (true) {
1620 if ( count > 1 ) {
1621 char *tmp = PR_smprintf("%s #%d", baseName.get(), count);
1622 if (!tmp) {
1623 nickname.Truncate();
1624 return;
1626 nickname = tmp;
1627 PR_smprintf_free(tmp);
1630 CERTCertificate *dummycert = nsnull;
1631 CERTCertificateCleaner dummycertCleaner(dummycert);
1633 if (PK11_IsInternal(slot)) {
1634 /* look up the nickname to make sure it isn't in use already */
1635 dummycert = CERT_FindCertByNickname(defaultcertdb, nickname.get());
1637 } else {
1639 * Check the cert against others that already live on the smart
1640 * card.
1642 dummycert = PK11_FindCertFromNickname(nickname.get(), ctx);
1643 if (dummycert != NULL) {
1645 * Make sure the subject names are different.
1647 if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
1650 * There is another certificate with the same nickname and
1651 * the same subject name on the smart card, so let's use this
1652 * nickname.
1654 CERT_DestroyCertificate(dummycert);
1655 dummycert = NULL;
1659 if (!dummycert)
1660 break;
1662 count++;
1666 NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName)
1668 NS_ENSURE_ARG_POINTER(aBase64);
1669 nsCOMPtr <nsIX509Cert> newCert;
1671 nsNSSCertTrust trust;
1673 // need to calculate the trust bits from the aTrust string.
1674 nsresult rv = CERT_DecodeTrustString(trust.GetTrust(), /* this is const, but not declared that way */(char *) aTrust);
1675 NS_ENSURE_SUCCESS(rv, rv); // if bad trust passed in, return error.
1678 rv = ConstructX509FromBase64(aBase64, getter_AddRefs(newCert));
1679 NS_ENSURE_SUCCESS(rv, rv);
1681 SECItem der;
1682 rv = newCert->GetRawDER(&der.len, (PRUint8 **)&der.data);
1683 NS_ENSURE_SUCCESS(rv, rv);
1685 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));
1686 CERTCertificate *tmpCert;
1687 CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
1688 tmpCert = CERT_FindCertByDERCert(certdb, &der);
1689 if (!tmpCert)
1690 tmpCert = CERT_NewTempCertificate(certdb, &der,
1691 nsnull, PR_FALSE, PR_TRUE);
1692 nsMemory::Free(der.data);
1693 der.data = nsnull;
1694 der.len = 0;
1696 if (!tmpCert) {
1697 NS_ASSERTION(0,"Couldn't create cert from DER blob\n");
1698 return NS_ERROR_FAILURE;
1701 if (tmpCert->isperm) {
1702 CERT_DestroyCertificate(tmpCert);
1703 return NS_OK;
1706 CERTCertificateCleaner tmpCertCleaner(tmpCert);
1708 nsXPIDLCString nickname;
1709 nickname.Adopt(CERT_MakeCANickname(tmpCert));
1711 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));
1713 SECStatus srv = CERT_AddTempCertToPerm(tmpCert,
1714 const_cast<char*>(nickname.get()),
1715 trust.GetTrust());
1718 return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
1721 NS_IMETHODIMP
1722 nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval)
1724 CERTCertList *certList;
1726 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
1727 nsCOMPtr<nsIX509CertList> nssCertList;
1728 certList = PK11_ListCerts(PK11CertListUnique, ctx);
1730 // nsNSSCertList 1) adopts certList, and 2) handles the NULL case fine.
1731 // (returns an empty list)
1732 nssCertList = new nsNSSCertList(certList, PR_TRUE);
1733 if (!nssCertList) { return NS_ERROR_OUT_OF_MEMORY; }
1735 *_retval = nssCertList;
1736 NS_ADDREF(*_retval);
1737 return NS_OK;