security/manager/ssl/src/nsNSSCertificate.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:05c8948a0e50
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsNSSCertificate.h"
7
8 #include "prmem.h"
9 #include "prerror.h"
10 #include "prprf.h"
11 #include "CertVerifier.h"
12 #include "ExtendedValidation.h"
13 #include "pkix/pkixtypes.h"
14 #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
15 #include "nsNSSCleaner.h"
16 #include "nsCOMPtr.h"
17 #include "nsIMutableArray.h"
18 #include "nsNSSCertValidity.h"
19 #include "nsPKCS12Blob.h"
20 #include "nsPK11TokenDB.h"
21 #include "nsIX509Cert.h"
22 #include "nsIX509Cert3.h"
23 #include "nsISMimeCert.h"
24 #include "nsNSSASN1Object.h"
25 #include "nsString.h"
26 #include "nsXPIDLString.h"
27 #include "nsReadableUtils.h"
28 #include "nsIURI.h"
29 #include "nsCRT.h"
30 #include "nsUsageArrayHelper.h"
31 #include "nsICertificateDialogs.h"
32 #include "nsNSSCertHelper.h"
33 #include "nsISupportsPrimitives.h"
34 #include "nsUnicharUtils.h"
35 #include "nsThreadUtils.h"
36 #include "nsCertVerificationThread.h"
37 #include "nsIObjectOutputStream.h"
38 #include "nsIObjectInputStream.h"
39 #include "nsIProgrammingLanguage.h"
40 #include "nsXULAppAPI.h"
41 #include "ScopedNSSTypes.h"
42 #include "nsProxyRelease.h"
43 #include "mozilla/Base64.h"
44
45 #include "nspr.h"
46 #include "certdb.h"
47 #include "secerr.h"
48 #include "nssb64.h"
49 #include "secasn1.h"
50 #include "secder.h"
51 #include "ssl.h"
52 #include "ocsp.h"
53 #include "plbase64.h"
54
55 using namespace mozilla;
56 using namespace mozilla::psm;
57
58 #ifdef PR_LOGGING
59 extern PRLogModuleInfo* gPIPNSSLog;
60 #endif
61
62 NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
63
64 // This is being stored in an uint32_t that can otherwise
65 // only take values from nsIX509Cert's list of cert types.
66 // As nsIX509Cert is frozen, we choose a value not contained
67 // in the list to mean not yet initialized.
68 #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
69
70 NS_IMPL_ISUPPORTS(nsNSSCertificate,
71 nsIX509Cert,
72 nsIX509Cert2,
73 nsIX509Cert3,
74 nsIIdentityInfo,
75 nsISMimeCert,
76 nsISerializable,
77 nsIClassInfo)
78
79 /*static*/ nsNSSCertificate*
80 nsNSSCertificate::Create(CERTCertificate* cert, SECOidTag* evOidPolicy)
81 {
82 if (GeckoProcessType_Default != XRE_GetProcessType()) {
83 NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
84 return nullptr;
85 }
86 if (cert)
87 return new nsNSSCertificate(cert, evOidPolicy);
88 else
89 return new nsNSSCertificate();
90 }
91
92 nsNSSCertificate*
93 nsNSSCertificate::ConstructFromDER(char* certDER, int derLen)
94 {
95 // On non-chrome process prevent instantiation
96 if (GeckoProcessType_Default != XRE_GetProcessType())
97 return nullptr;
98
99 nsNSSCertificate* newObject = nsNSSCertificate::Create();
100 if (newObject && !newObject->InitFromDER(certDER, derLen)) {
101 delete newObject;
102 newObject = nullptr;
103 }
104
105 return newObject;
106 }
107
108 bool
109 nsNSSCertificate::InitFromDER(char* certDER, int derLen)
110 {
111 nsNSSShutDownPreventionLock locker;
112 if (isAlreadyShutDown())
113 return false;
114
115 if (!certDER || !derLen)
116 return false;
117
118 CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen);
119
120 if (!aCert)
121 return false;
122
123 if (!aCert->dbhandle)
124 {
125 aCert->dbhandle = CERT_GetDefaultCertDB();
126 }
127
128 mCert = aCert;
129 return true;
130 }
131
132 nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert,
133 SECOidTag* evOidPolicy)
134 : mCert(nullptr)
135 , mPermDelete(false)
136 , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
137 , mCachedEVStatus(ev_status_unknown)
138 {
139 #if defined(DEBUG)
140 if (GeckoProcessType_Default != XRE_GetProcessType())
141 NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
142 #endif
143
144 nsNSSShutDownPreventionLock locker;
145 if (isAlreadyShutDown())
146 return;
147
148 if (cert) {
149 mCert = CERT_DupCertificate(cert);
150 if (evOidPolicy) {
151 if (*evOidPolicy == SEC_OID_UNKNOWN) {
152 mCachedEVStatus = ev_status_invalid;
153 }
154 else {
155 mCachedEVStatus = ev_status_valid;
156 }
157 mCachedEVOidTag = *evOidPolicy;
158 }
159 }
160 }
161
162 nsNSSCertificate::nsNSSCertificate() :
163 mCert(nullptr),
164 mPermDelete(false),
165 mCertType(CERT_TYPE_NOT_YET_INITIALIZED),
166 mCachedEVStatus(ev_status_unknown)
167 {
168 if (GeckoProcessType_Default != XRE_GetProcessType())
169 NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!");
170 }
171
172 nsNSSCertificate::~nsNSSCertificate()
173 {
174 nsNSSShutDownPreventionLock locker;
175 if (isAlreadyShutDown()) {
176 return;
177 }
178 destructorSafeDestroyNSSReference();
179 shutdown(calledFromObject);
180 }
181
182 void nsNSSCertificate::virtualDestroyNSSReference()
183 {
184 destructorSafeDestroyNSSReference();
185 }
186
187 void nsNSSCertificate::destructorSafeDestroyNSSReference()
188 {
189 if (mPermDelete) {
190 if (mCertType == nsNSSCertificate::USER_CERT) {
191 nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
192 PK11_DeleteTokenCertAndKey(mCert.get(), cxt);
193 } else if (!PK11_IsReadOnly(mCert->slot)) {
194 // If the list of built-ins does contain a non-removable
195 // copy of this certificate, our call will not remove
196 // the certificate permanently, but rather remove all trust.
197 SEC_DeletePermCertificate(mCert.get());
198 }
199 }
200
201 mCert = nullptr;
202 }
203
204 nsresult
205 nsNSSCertificate::GetCertType(uint32_t* aCertType)
206 {
207 if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) {
208 // only determine cert type once and cache it
209 mCertType = getCertType(mCert.get());
210 }
211 *aCertType = mCertType;
212 return NS_OK;
213 }
214
215 NS_IMETHODIMP
216 nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned)
217 {
218 NS_ENSURE_ARG(aIsSelfSigned);
219
220 nsNSSShutDownPreventionLock locker;
221 if (isAlreadyShutDown())
222 return NS_ERROR_NOT_AVAILABLE;
223
224 *aIsSelfSigned = mCert->isRoot;
225 return NS_OK;
226 }
227
228 nsresult
229 nsNSSCertificate::MarkForPermDeletion()
230 {
231 nsNSSShutDownPreventionLock locker;
232 if (isAlreadyShutDown())
233 return NS_ERROR_NOT_AVAILABLE;
234
235 // make sure user is logged in to the token
236 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
237
238 if (PK11_NeedLogin(mCert->slot)
239 && !PK11_NeedUserInit(mCert->slot)
240 && !PK11_IsInternal(mCert->slot))
241 {
242 if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx))
243 {
244 return NS_ERROR_FAILURE;
245 }
246 }
247
248 mPermDelete = true;
249 return NS_OK;
250 }
251
252 nsresult
253 GetKeyUsagesString(CERTCertificate* cert, nsINSSComponent* nssComponent,
254 nsString& text)
255 {
256 text.Truncate();
257
258 SECItem keyUsageItem;
259 keyUsageItem.data = nullptr;
260
261 SECStatus srv;
262
263 // There is no extension, v1 or v2 certificate
264 if (!cert->extensions)
265 return NS_OK;
266
267
268 srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
269 if (srv == SECFailure) {
270 if (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND)
271 return NS_OK;
272 else
273 return NS_ERROR_FAILURE;
274 }
275
276 unsigned char keyUsage = keyUsageItem.data[0];
277 nsAutoString local;
278 nsresult rv;
279 const char16_t comma = ',';
280
281 if (keyUsage & KU_DIGITAL_SIGNATURE) {
282 rv = nssComponent->GetPIPNSSBundleString("CertDumpKUSign", local);
283 if (NS_SUCCEEDED(rv)) {
284 if (!text.IsEmpty()) text.Append(comma);
285 text.Append(local.get());
286 }
287 }
288 if (keyUsage & KU_NON_REPUDIATION) {
289 rv = nssComponent->GetPIPNSSBundleString("CertDumpKUNonRep", local);
290 if (NS_SUCCEEDED(rv)) {
291 if (!text.IsEmpty()) text.Append(comma);
292 text.Append(local.get());
293 }
294 }
295 if (keyUsage & KU_KEY_ENCIPHERMENT) {
296 rv = nssComponent->GetPIPNSSBundleString("CertDumpKUEnc", local);
297 if (NS_SUCCEEDED(rv)) {
298 if (!text.IsEmpty()) text.Append(comma);
299 text.Append(local.get());
300 }
301 }
302 if (keyUsage & KU_DATA_ENCIPHERMENT) {
303 rv = nssComponent->GetPIPNSSBundleString("CertDumpKUDEnc", local);
304 if (NS_SUCCEEDED(rv)) {
305 if (!text.IsEmpty()) text.Append(comma);
306 text.Append(local.get());
307 }
308 }
309 if (keyUsage & KU_KEY_AGREEMENT) {
310 rv = nssComponent->GetPIPNSSBundleString("CertDumpKUKA", local);
311 if (NS_SUCCEEDED(rv)) {
312 if (!text.IsEmpty()) text.Append(comma);
313 text.Append(local.get());
314 }
315 }
316 if (keyUsage & KU_KEY_CERT_SIGN) {
317 rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCertSign", local);
318 if (NS_SUCCEEDED(rv)) {
319 if (!text.IsEmpty()) text.Append(comma);
320 text.Append(local.get());
321 }
322 }
323 if (keyUsage & KU_CRL_SIGN) {
324 rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCRLSign", local);
325 if (NS_SUCCEEDED(rv)) {
326 if (!text.IsEmpty()) text.Append(comma);
327 text.Append(local.get());
328 }
329 }
330
331 PORT_Free (keyUsageItem.data);
332 return NS_OK;
333 }
334
335 nsresult
336 nsNSSCertificate::FormatUIStrings(const nsAutoString& nickname,
337 nsAutoString& nickWithSerial,
338 nsAutoString& details)
339 {
340 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
341
342 if (!NS_IsMainThread()) {
343 NS_ERROR("nsNSSCertificate::FormatUIStrings called off the main thread");
344 return NS_ERROR_NOT_SAME_THREAD;
345 }
346
347 nsresult rv = NS_OK;
348
349 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
350
351 if (NS_FAILED(rv) || !nssComponent) {
352 return NS_ERROR_FAILURE;
353 }
354
355 nsAutoString info;
356 nsAutoString temp1;
357
358 nickWithSerial.Append(nickname);
359
360 if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedFor", info))) {
361 details.Append(info);
362 details.Append(char16_t(' '));
363 if (NS_SUCCEEDED(GetSubjectName(temp1)) && !temp1.IsEmpty()) {
364 details.Append(temp1);
365 }
366 details.Append(char16_t('\n'));
367 }
368
369 if (NS_SUCCEEDED(GetSerialNumber(temp1)) && !temp1.IsEmpty()) {
370 details.AppendLiteral(" ");
371 if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", info))) {
372 details.Append(info);
373 details.AppendLiteral(": ");
374 }
375 details.Append(temp1);
376
377 nickWithSerial.AppendLiteral(" [");
378 nickWithSerial.Append(temp1);
379 nickWithSerial.Append(char16_t(']'));
380
381 details.Append(char16_t('\n'));
382 }
383
384 nsCOMPtr<nsIX509CertValidity> validity;
385 rv = GetValidity(getter_AddRefs(validity));
386 if (NS_SUCCEEDED(rv) && validity) {
387 details.AppendLiteral(" ");
388 if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoValid", info))) {
389 details.Append(info);
390 }
391
392 if (NS_SUCCEEDED(validity->GetNotBeforeLocalTime(temp1)) && !temp1.IsEmpty()) {
393 details.Append(char16_t(' '));
394 if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoFrom", info))) {
395 details.Append(info);
396 details.Append(char16_t(' '));
397 }
398 details.Append(temp1);
399 }
400
401 if (NS_SUCCEEDED(validity->GetNotAfterLocalTime(temp1)) && !temp1.IsEmpty()) {
402 details.Append(char16_t(' '));
403 if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoTo", info))) {
404 details.Append(info);
405 details.Append(char16_t(' '));
406 }
407 details.Append(temp1);
408 }
409
410 details.Append(char16_t('\n'));
411 }
412
413 if (NS_SUCCEEDED(GetKeyUsagesString(mCert.get(), nssComponent, temp1)) &&
414 !temp1.IsEmpty()) {
415 details.AppendLiteral(" ");
416 if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpKeyUsage", info))) {
417 details.Append(info);
418 details.AppendLiteral(": ");
419 }
420 details.Append(temp1);
421 details.Append(char16_t('\n'));
422 }
423
424 nsAutoString firstEmail;
425 const char* aWalkAddr;
426 for (aWalkAddr = CERT_GetFirstEmailAddress(mCert.get())
427 ;
428 aWalkAddr
429 ;
430 aWalkAddr = CERT_GetNextEmailAddress(mCert.get(), aWalkAddr))
431 {
432 NS_ConvertUTF8toUTF16 email(aWalkAddr);
433 if (email.IsEmpty())
434 continue;
435
436 if (firstEmail.IsEmpty()) {
437 // If the first email address from the subject DN is also present
438 // in the subjectAltName extension, GetEmailAddresses() will return
439 // it twice (as received from NSS). Remember the first address so that
440 // we can filter out duplicates later on.
441 firstEmail = email;
442
443 details.AppendLiteral(" ");
444 if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoEmail", info))) {
445 details.Append(info);
446 details.AppendLiteral(": ");
447 }
448 details.Append(email);
449 }
450 else {
451 // Append current address if it's different from the first one.
452 if (!firstEmail.Equals(email)) {
453 details.AppendLiteral(", ");
454 details.Append(email);
455 }
456 }
457 }
458
459 if (!firstEmail.IsEmpty()) {
460 // We got at least one email address, so we want a newline
461 details.Append(char16_t('\n'));
462 }
463
464 if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedBy", info))) {
465 details.Append(info);
466 details.Append(char16_t(' '));
467
468 if (NS_SUCCEEDED(GetIssuerName(temp1)) && !temp1.IsEmpty()) {
469 details.Append(temp1);
470 }
471
472 details.Append(char16_t('\n'));
473 }
474
475 if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoStoredIn", info))) {
476 details.Append(info);
477 details.Append(char16_t(' '));
478
479 if (NS_SUCCEEDED(GetTokenName(temp1)) && !temp1.IsEmpty()) {
480 details.Append(temp1);
481 }
482 }
483
484 // the above produces the following output:
485 //
486 // Issued to: $subjectName
487 // Serial number: $serialNumber
488 // Valid from: $starting_date to $expiration_date
489 // Certificate Key usage: $usages
490 // Email: $address(es)
491 // Issued by: $issuerName
492 // Stored in: $token
493
494 return rv;
495 }
496
497 NS_IMETHODIMP
498 nsNSSCertificate::GetDbKey(char** aDbKey)
499 {
500 nsNSSShutDownPreventionLock locker;
501 if (isAlreadyShutDown())
502 return NS_ERROR_NOT_AVAILABLE;
503
504 SECItem key;
505
506 NS_ENSURE_ARG(aDbKey);
507 *aDbKey = nullptr;
508 key.len = NS_NSS_LONG*4+mCert->serialNumber.len+mCert->derIssuer.len;
509 key.data = (unsigned char*) nsMemory::Alloc(key.len);
510 if (!key.data)
511 return NS_ERROR_OUT_OF_MEMORY;
512 NS_NSS_PUT_LONG(0,key.data); // later put moduleID
513 NS_NSS_PUT_LONG(0,&key.data[NS_NSS_LONG]); // later put slotID
514 NS_NSS_PUT_LONG(mCert->serialNumber.len,&key.data[NS_NSS_LONG*2]);
515 NS_NSS_PUT_LONG(mCert->derIssuer.len,&key.data[NS_NSS_LONG*3]);
516 memcpy(&key.data[NS_NSS_LONG*4], mCert->serialNumber.data,
517 mCert->serialNumber.len);
518 memcpy(&key.data[NS_NSS_LONG*4+mCert->serialNumber.len],
519 mCert->derIssuer.data, mCert->derIssuer.len);
520
521 *aDbKey = NSSBase64_EncodeItem(nullptr, nullptr, 0, &key);
522 nsMemory::Free(key.data); // SECItem is a 'c' type without a destrutor
523 return (*aDbKey) ? NS_OK : NS_ERROR_FAILURE;
524 }
525
526 NS_IMETHODIMP
527 nsNSSCertificate::GetWindowTitle(char** aWindowTitle)
528 {
529 nsNSSShutDownPreventionLock locker;
530 if (isAlreadyShutDown())
531 return NS_ERROR_NOT_AVAILABLE;
532
533 NS_ENSURE_ARG(aWindowTitle);
534 if (mCert) {
535 if (mCert->nickname) {
536 *aWindowTitle = PL_strdup(mCert->nickname);
537 } else {
538 *aWindowTitle = CERT_GetCommonName(&mCert->subject);
539 if (!*aWindowTitle) {
540 if (mCert->subjectName) {
541 *aWindowTitle = PL_strdup(mCert->subjectName);
542 } else if (mCert->emailAddr) {
543 *aWindowTitle = PL_strdup(mCert->emailAddr);
544 } else {
545 *aWindowTitle = PL_strdup("");
546 }
547 }
548 }
549 } else {
550 NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
551 *aWindowTitle = nullptr;
552 }
553 return NS_OK;
554 }
555
556 NS_IMETHODIMP
557 nsNSSCertificate::GetNickname(nsAString& aNickname)
558 {
559 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
560
561 nsNSSShutDownPreventionLock locker;
562 if (isAlreadyShutDown())
563 return NS_ERROR_NOT_AVAILABLE;
564
565 if (mCert->nickname) {
566 CopyUTF8toUTF16(mCert->nickname, aNickname);
567 } else {
568 nsresult rv;
569 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
570 if (NS_FAILED(rv) || !nssComponent) {
571 return NS_ERROR_FAILURE;
572 }
573 nssComponent->GetPIPNSSBundleString("CertNoNickname", aNickname);
574 }
575 return NS_OK;
576 }
577
578 NS_IMETHODIMP
579 nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
580 {
581 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
582
583 nsNSSShutDownPreventionLock locker;
584 if (isAlreadyShutDown())
585 return NS_ERROR_NOT_AVAILABLE;
586
587 if (mCert->emailAddr) {
588 CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
589 } else {
590 nsresult rv;
591 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
592 if (NS_FAILED(rv) || !nssComponent) {
593 return NS_ERROR_FAILURE;
594 }
595 nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
596 }
597 return NS_OK;
598 }
599
600 NS_IMETHODIMP
601 nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses)
602 {
603 nsNSSShutDownPreventionLock locker;
604 if (isAlreadyShutDown())
605 return NS_ERROR_NOT_AVAILABLE;
606
607 NS_ENSURE_ARG(aLength);
608 NS_ENSURE_ARG(aAddresses);
609
610 *aLength = 0;
611
612 const char* aAddr;
613 for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
614 ;
615 aAddr
616 ;
617 aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
618 {
619 ++(*aLength);
620 }
621
622 *aAddresses = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength));
623 if (!*aAddresses)
624 return NS_ERROR_OUT_OF_MEMORY;
625
626 uint32_t iAddr;
627 for (aAddr = CERT_GetFirstEmailAddress(mCert.get()), iAddr = 0
628 ;
629 aAddr
630 ;
631 aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr), ++iAddr)
632 {
633 (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr));
634 }
635
636 return NS_OK;
637 }
638
639 NS_IMETHODIMP
640 nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
641 bool* result)
642 {
643 nsNSSShutDownPreventionLock locker;
644 if (isAlreadyShutDown())
645 return NS_ERROR_NOT_AVAILABLE;
646
647 NS_ENSURE_ARG(result);
648 *result = false;
649
650 const char* aAddr = nullptr;
651 for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
652 ;
653 aAddr
654 ;
655 aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
656 {
657 NS_ConvertUTF8toUTF16 certAddr(aAddr);
658 ToLowerCase(certAddr);
659
660 nsAutoString testAddr(aEmailAddress);
661 ToLowerCase(testAddr);
662
663 if (certAddr == testAddr)
664 {
665 *result = true;
666 break;
667 }
668
669 }
670
671 return NS_OK;
672 }
673
674 NS_IMETHODIMP
675 nsNSSCertificate::GetCommonName(nsAString& aCommonName)
676 {
677 nsNSSShutDownPreventionLock locker;
678 if (isAlreadyShutDown())
679 return NS_ERROR_NOT_AVAILABLE;
680
681 aCommonName.Truncate();
682 if (mCert) {
683 char* commonName = CERT_GetCommonName(&mCert->subject);
684 if (commonName) {
685 aCommonName = NS_ConvertUTF8toUTF16(commonName);
686 PORT_Free(commonName);
687 }
688 }
689 return NS_OK;
690 }
691
692 NS_IMETHODIMP
693 nsNSSCertificate::GetOrganization(nsAString& aOrganization)
694 {
695 nsNSSShutDownPreventionLock locker;
696 if (isAlreadyShutDown())
697 return NS_ERROR_NOT_AVAILABLE;
698
699 aOrganization.Truncate();
700 if (mCert) {
701 char* organization = CERT_GetOrgName(&mCert->subject);
702 if (organization) {
703 aOrganization = NS_ConvertUTF8toUTF16(organization);
704 PORT_Free(organization);
705 }
706 }
707 return NS_OK;
708 }
709
710 NS_IMETHODIMP
711 nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName)
712 {
713 nsNSSShutDownPreventionLock locker;
714 if (isAlreadyShutDown())
715 return NS_ERROR_NOT_AVAILABLE;
716
717 aCommonName.Truncate();
718 if (mCert) {
719 char* commonName = CERT_GetCommonName(&mCert->issuer);
720 if (commonName) {
721 aCommonName = NS_ConvertUTF8toUTF16(commonName);
722 PORT_Free(commonName);
723 }
724 }
725 return NS_OK;
726 }
727
728 NS_IMETHODIMP
729 nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization)
730 {
731 nsNSSShutDownPreventionLock locker;
732 if (isAlreadyShutDown())
733 return NS_ERROR_NOT_AVAILABLE;
734
735 aOrganization.Truncate();
736 if (mCert) {
737 char* organization = CERT_GetOrgName(&mCert->issuer);
738 if (organization) {
739 aOrganization = NS_ConvertUTF8toUTF16(organization);
740 PORT_Free(organization);
741 } else {
742 return GetIssuerCommonName(aOrganization);
743 }
744 }
745 return NS_OK;
746 }
747
748 NS_IMETHODIMP
749 nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit)
750 {
751 nsNSSShutDownPreventionLock locker;
752 if (isAlreadyShutDown())
753 return NS_ERROR_NOT_AVAILABLE;
754
755 aOrganizationUnit.Truncate();
756 if (mCert) {
757 char* organizationUnit = CERT_GetOrgUnitName(&mCert->issuer);
758 if (organizationUnit) {
759 aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit);
760 PORT_Free(organizationUnit);
761 }
762 }
763 return NS_OK;
764 }
765
766 NS_IMETHODIMP
767 nsNSSCertificate::GetIssuer(nsIX509Cert** aIssuer)
768 {
769 nsNSSShutDownPreventionLock locker;
770 if (isAlreadyShutDown())
771 return NS_ERROR_NOT_AVAILABLE;
772
773 NS_ENSURE_ARG(aIssuer);
774 *aIssuer = nullptr;
775
776 nsCOMPtr<nsIArray> chain;
777 nsresult rv;
778 rv = GetChain(getter_AddRefs(chain));
779 NS_ENSURE_SUCCESS(rv, rv);
780 uint32_t length;
781 if (!chain || NS_FAILED(chain->GetLength(&length)) || length == 0) {
782 return NS_ERROR_UNEXPECTED;
783 }
784 if (length == 1) { // No known issuer
785 return NS_OK;
786 }
787 nsCOMPtr<nsIX509Cert> cert;
788 chain->QueryElementAt(1, NS_GET_IID(nsIX509Cert), getter_AddRefs(cert));
789 if (!cert) {
790 return NS_ERROR_UNEXPECTED;
791 }
792 *aIssuer = cert;
793 NS_ADDREF(*aIssuer);
794 return NS_OK;
795 }
796
797 NS_IMETHODIMP
798 nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit)
799 {
800 nsNSSShutDownPreventionLock locker;
801 if (isAlreadyShutDown())
802 return NS_ERROR_NOT_AVAILABLE;
803
804 aOrganizationalUnit.Truncate();
805 if (mCert) {
806 char* orgunit = CERT_GetOrgUnitName(&mCert->subject);
807 if (orgunit) {
808 aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit);
809 PORT_Free(orgunit);
810 }
811 }
812 return NS_OK;
813 }
814
815 NS_IMETHODIMP
816 nsNSSCertificate::GetChain(nsIArray** _rvChain)
817 {
818 nsNSSShutDownPreventionLock locker;
819 if (isAlreadyShutDown())
820 return NS_ERROR_NOT_AVAILABLE;
821
822 NS_ENSURE_ARG(_rvChain);
823 nsresult rv;
824 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname));
825
826 ::mozilla::pkix::ScopedCERTCertList nssChain;
827 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
828 NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
829
830 // We want to test all usages, but we start with server because most of the
831 // time Firefox users care about server certs.
832 certVerifier->VerifyCert(mCert.get(),
833 certificateUsageSSLServer, PR_Now(),
834 nullptr, /*XXX fixme*/
835 nullptr, /* hostname */
836 CertVerifier::FLAG_LOCAL_ONLY,
837 nullptr, /* stapledOCSPResponse */
838 &nssChain);
839 // This is the whitelist of all non-SSLServer usages that are supported by
840 // verifycert.
841 const int otherUsagesToTest = certificateUsageSSLClient |
842 certificateUsageSSLCA |
843 certificateUsageEmailSigner |
844 certificateUsageEmailRecipient |
845 certificateUsageObjectSigner |
846 certificateUsageStatusResponder;
847 for (int usage = certificateUsageSSLClient;
848 usage < certificateUsageAnyCA && !nssChain;
849 usage = usage << 1) {
850 if ((usage & otherUsagesToTest) == 0) {
851 continue;
852 }
853 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
854 ("pipnss: PKIX attempting chain(%d) for '%s'\n",
855 usage, mCert->nickname));
856 certVerifier->VerifyCert(mCert.get(),
857 usage, PR_Now(),
858 nullptr, /*XXX fixme*/
859 nullptr, /*hostname*/
860 CertVerifier::FLAG_LOCAL_ONLY,
861 nullptr, /* stapledOCSPResponse */
862 &nssChain);
863 }
864
865 if (!nssChain) {
866 // There is not verified path for the chain, howeever we still want to
867 // present to the user as much of a possible chain as possible, in the case
868 // where there was a problem with the cert or the issuers.
869 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
870 ("pipnss: getchain :CertVerify failed to get chain for '%s'\n",
871 mCert->nickname));
872 nssChain = CERT_GetCertChainFromCert(mCert.get(), PR_Now(),
873 certUsageSSLClient);
874 }
875
876 if (!nssChain) {
877 return NS_ERROR_FAILURE;
878 }
879
880 // enumerate the chain for scripting purposes
881 nsCOMPtr<nsIMutableArray> array =
882 do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
883 if (NS_FAILED(rv)) {
884 goto done;
885 }
886 CERTCertListNode* node;
887 for (node = CERT_LIST_HEAD(nssChain.get());
888 !CERT_LIST_END(node, nssChain.get());
889 node = CERT_LIST_NEXT(node)) {
890 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
891 ("adding %s to chain\n", node->cert->nickname));
892 nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
893 array->AppendElement(cert, false);
894 }
895 *_rvChain = array;
896 NS_IF_ADDREF(*_rvChain);
897 rv = NS_OK;
898 done:
899 return rv;
900 }
901
902 NS_IMETHODIMP
903 nsNSSCertificate::GetAllTokenNames(uint32_t* aLength, char16_t*** aTokenNames)
904 {
905 nsNSSShutDownPreventionLock locker;
906 if (isAlreadyShutDown())
907 return NS_ERROR_NOT_AVAILABLE;
908
909 NS_ENSURE_ARG(aLength);
910 NS_ENSURE_ARG(aTokenNames);
911 *aLength = 0;
912 *aTokenNames = nullptr;
913
914 // Get the slots from NSS
915 ScopedPK11SlotList slots;
916 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting slots for \"%s\"\n", mCert->nickname));
917 slots = PK11_GetAllSlotsForCert(mCert.get(), nullptr);
918 if (!slots) {
919 if (PORT_GetError() == SEC_ERROR_NO_TOKEN)
920 return NS_OK; // List of slots is empty, return empty array
921 else
922 return NS_ERROR_FAILURE;
923 }
924
925 // read the token names from slots
926 PK11SlotListElement* le;
927
928 for (le = slots->head; le; le = le->next) {
929 ++(*aLength);
930 }
931
932 *aTokenNames = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength));
933 if (!*aTokenNames) {
934 *aLength = 0;
935 return NS_ERROR_OUT_OF_MEMORY;
936 }
937
938 uint32_t iToken;
939 for (le = slots->head, iToken = 0; le; le = le->next, ++iToken) {
940 char* token = PK11_GetTokenName(le->slot);
941 (*aTokenNames)[iToken] = ToNewUnicode(NS_ConvertUTF8toUTF16(token));
942 if (!(*aTokenNames)[iToken]) {
943 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iToken, *aTokenNames);
944 *aLength = 0;
945 *aTokenNames = nullptr;
946 return NS_ERROR_OUT_OF_MEMORY;
947 }
948 }
949
950 return NS_OK;
951 }
952
953 NS_IMETHODIMP
954 nsNSSCertificate::GetSubjectName(nsAString& _subjectName)
955 {
956 nsNSSShutDownPreventionLock locker;
957 if (isAlreadyShutDown())
958 return NS_ERROR_NOT_AVAILABLE;
959
960 _subjectName.Truncate();
961 if (mCert->subjectName) {
962 _subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName);
963 return NS_OK;
964 }
965 return NS_ERROR_FAILURE;
966 }
967
968 NS_IMETHODIMP
969 nsNSSCertificate::GetIssuerName(nsAString& _issuerName)
970 {
971 nsNSSShutDownPreventionLock locker;
972 if (isAlreadyShutDown())
973 return NS_ERROR_NOT_AVAILABLE;
974
975 _issuerName.Truncate();
976 if (mCert->issuerName) {
977 _issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName);
978 return NS_OK;
979 }
980 return NS_ERROR_FAILURE;
981 }
982
983 NS_IMETHODIMP
984 nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber)
985 {
986 nsNSSShutDownPreventionLock locker;
987 if (isAlreadyShutDown())
988 return NS_ERROR_NOT_AVAILABLE;
989
990 _serialNumber.Truncate();
991 char* tmpstr = CERT_Hexify(&mCert->serialNumber, 1);
992 if (tmpstr) {
993 _serialNumber = NS_ConvertASCIItoUTF16(tmpstr);
994 PORT_Free(tmpstr);
995 return NS_OK;
996 }
997 return NS_ERROR_FAILURE;
998 }
999
1000 NS_IMETHODIMP
1001 nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
1002 {
1003 nsNSSShutDownPreventionLock locker;
1004 if (isAlreadyShutDown())
1005 return NS_ERROR_NOT_AVAILABLE;
1006
1007 _sha1Fingerprint.Truncate();
1008 unsigned char fingerprint[20];
1009 SECItem fpItem;
1010 memset(fingerprint, 0, sizeof fingerprint);
1011 PK11_HashBuf(SEC_OID_SHA1, fingerprint,
1012 mCert->derCert.data, mCert->derCert.len);
1013 fpItem.data = fingerprint;
1014 fpItem.len = SHA1_LENGTH;
1015 char* fpStr = CERT_Hexify(&fpItem, 1);
1016 if (fpStr) {
1017 _sha1Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
1018 PORT_Free(fpStr);
1019 return NS_OK;
1020 }
1021 return NS_ERROR_FAILURE;
1022 }
1023
1024 NS_IMETHODIMP
1025 nsNSSCertificate::GetMd5Fingerprint(nsAString& _md5Fingerprint)
1026 {
1027 nsNSSShutDownPreventionLock locker;
1028 if (isAlreadyShutDown())
1029 return NS_ERROR_NOT_AVAILABLE;
1030
1031 _md5Fingerprint.Truncate();
1032 unsigned char fingerprint[20];
1033 SECItem fpItem;
1034 memset(fingerprint, 0, sizeof fingerprint);
1035 PK11_HashBuf(SEC_OID_MD5, fingerprint,
1036 mCert->derCert.data, mCert->derCert.len);
1037 fpItem.data = fingerprint;
1038 fpItem.len = MD5_LENGTH;
1039 char* fpStr = CERT_Hexify(&fpItem, 1);
1040 if (fpStr) {
1041 _md5Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
1042 PORT_Free(fpStr);
1043 return NS_OK;
1044 }
1045 return NS_ERROR_FAILURE;
1046 }
1047
1048 NS_IMETHODIMP
1049 nsNSSCertificate::GetTokenName(nsAString& aTokenName)
1050 {
1051 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
1052
1053 nsNSSShutDownPreventionLock locker;
1054 if (isAlreadyShutDown())
1055 return NS_ERROR_NOT_AVAILABLE;
1056
1057 aTokenName.Truncate();
1058 if (mCert) {
1059 // HACK alert
1060 // When the trust of a builtin cert is modified, NSS copies it into the
1061 // cert db. At this point, it is now "managed" by the user, and should
1062 // not be listed with the builtins. However, in the collection code
1063 // used by PK11_ListCerts, the cert is found in the temp db, where it
1064 // has been loaded from the token. Though the trust is correct (grabbed
1065 // from the cert db), the source is wrong. I believe this is a safe
1066 // way to work around this.
1067 if (mCert->slot) {
1068 char* token = PK11_GetTokenName(mCert->slot);
1069 if (token) {
1070 aTokenName = NS_ConvertUTF8toUTF16(token);
1071 }
1072 } else {
1073 nsresult rv;
1074 nsAutoString tok;
1075 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
1076 if (NS_FAILED(rv)) return rv;
1077 rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok);
1078 if (NS_SUCCEEDED(rv))
1079 aTokenName = tok;
1080 }
1081 }
1082 return NS_OK;
1083 }
1084
1085 NS_IMETHODIMP
1086 nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest)
1087 {
1088 nsNSSShutDownPreventionLock locker;
1089 if (isAlreadyShutDown()) {
1090 return NS_ERROR_NOT_AVAILABLE;
1091 }
1092
1093 aSha256SPKIDigest.Truncate();
1094 Digest digest;
1095 nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data,
1096 mCert->derPublicKey.len);
1097 if (NS_WARN_IF(NS_FAILED(rv))) {
1098 return rv;
1099 }
1100 rv = Base64Encode(nsDependentCSubstring(
1101 reinterpret_cast<const char*> (digest.get().data),
1102 digest.get().len),
1103 aSha256SPKIDigest);
1104 if (NS_WARN_IF(NS_FAILED(rv))) {
1105 return rv;
1106 }
1107 return NS_OK;
1108 }
1109
1110 NS_IMETHODIMP
1111 nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray)
1112 {
1113 nsNSSShutDownPreventionLock locker;
1114 if (isAlreadyShutDown())
1115 return NS_ERROR_NOT_AVAILABLE;
1116
1117 if (mCert) {
1118 *aArray = (uint8_t*)nsMemory::Alloc(mCert->derCert.len);
1119 if (*aArray) {
1120 memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
1121 *aLength = mCert->derCert.len;
1122 return NS_OK;
1123 }
1124 }
1125 *aLength = 0;
1126 return NS_ERROR_FAILURE;
1127 }
1128
1129 NS_IMETHODIMP
1130 nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
1131 uint32_t* aLength, uint8_t** aArray)
1132 {
1133 NS_ENSURE_ARG(aLength);
1134 NS_ENSURE_ARG(aArray);
1135
1136 nsNSSShutDownPreventionLock locker;
1137 if (isAlreadyShutDown())
1138 return NS_ERROR_NOT_AVAILABLE;
1139
1140 if (!mCert)
1141 return NS_ERROR_FAILURE;
1142
1143 switch (chainMode) {
1144 case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly:
1145 case nsIX509Cert3::CMS_CHAIN_MODE_CertChain:
1146 case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot:
1147 break;
1148 default:
1149 return NS_ERROR_INVALID_ARG;
1150 };
1151
1152 PLArenaPool* arena = PORT_NewArena(1024);
1153 PLArenaPoolCleanerFalseParam arenaCleaner(arena);
1154 if (!arena) {
1155 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1156 ("nsNSSCertificate::ExportAsCMS - out of memory\n"));
1157 return NS_ERROR_OUT_OF_MEMORY;
1158 }
1159
1160 ScopedNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr));
1161 if (!cmsg) {
1162 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1163 ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n"));
1164 return NS_ERROR_OUT_OF_MEMORY;
1165 }
1166
1167 // first, create SignedData with the certificate only (no chain)
1168 ScopedNSSCMSSignedData sigd(
1169 NSS_CMSSignedData_CreateCertsOnly(cmsg, mCert.get(), false));
1170 if (!sigd) {
1171 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1172 ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n"));
1173 return NS_ERROR_FAILURE;
1174 }
1175
1176 // Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us
1177 // to specify the inclusion of the root, but CERT_CertChainFromCert() does.
1178 // Since CERT_CertChainFromCert() also includes the certificate itself,
1179 // we have to start at the issuing cert (to avoid duplicate certs
1180 // in the SignedData).
1181 if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain ||
1182 chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) {
1183 ScopedCERTCertificate issuerCert(
1184 CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA));
1185 // the issuerCert of a self signed root is the cert itself,
1186 // so make sure we're not adding duplicates, again
1187 if (issuerCert && issuerCert != mCert.get()) {
1188 bool includeRoot =
1189 (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot);
1190 ScopedCERTCertificateList certChain(
1191 CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot));
1192 if (certChain) {
1193 if (NSS_CMSSignedData_AddCertList(sigd, certChain) == SECSuccess) {
1194 certChain.forget();
1195 }
1196 else {
1197 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1198 ("nsNSSCertificate::ExportAsCMS - can't add chain\n"));
1199 return NS_ERROR_FAILURE;
1200 }
1201 }
1202 else {
1203 // try to add the issuerCert, at least
1204 if (NSS_CMSSignedData_AddCertificate(sigd, issuerCert)
1205 == SECSuccess) {
1206 issuerCert.forget();
1207 }
1208 else {
1209 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1210 ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n"));
1211 return NS_ERROR_FAILURE;
1212 }
1213 }
1214 }
1215 }
1216
1217 NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
1218 if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)
1219 == SECSuccess) {
1220 sigd.forget();
1221 }
1222 else {
1223 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1224 ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n"));
1225 return NS_ERROR_FAILURE;
1226 }
1227
1228 SECItem certP7 = { siBuffer, nullptr, 0 };
1229 NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg, nullptr, nullptr,
1230 &certP7, arena, nullptr,
1231 nullptr, nullptr, nullptr,
1232 nullptr, nullptr);
1233 if (!ecx) {
1234 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1235 ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n"));
1236 return NS_ERROR_FAILURE;
1237 }
1238
1239 if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
1240 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1241 ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n"));
1242 return NS_ERROR_FAILURE;
1243 }
1244
1245 *aArray = (uint8_t*)nsMemory::Alloc(certP7.len);
1246 if (!*aArray)
1247 return NS_ERROR_OUT_OF_MEMORY;
1248
1249 memcpy(*aArray, certP7.data, certP7.len);
1250 *aLength = certP7.len;
1251 return NS_OK;
1252 }
1253
1254 CERTCertificate*
1255 nsNSSCertificate::GetCert()
1256 {
1257 nsNSSShutDownPreventionLock locker;
1258 if (isAlreadyShutDown())
1259 return nullptr;
1260
1261 return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr;
1262 }
1263
1264 NS_IMETHODIMP
1265 nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity)
1266 {
1267 nsNSSShutDownPreventionLock locker;
1268 if (isAlreadyShutDown())
1269 return NS_ERROR_NOT_AVAILABLE;
1270
1271 NS_ENSURE_ARG(aValidity);
1272 nsX509CertValidity* validity = new nsX509CertValidity(mCert.get());
1273
1274 NS_ADDREF(validity);
1275 *aValidity = static_cast<nsIX509CertValidity*>(validity);
1276 return NS_OK;
1277 }
1278
1279 NS_IMETHODIMP
1280 nsNSSCertificate::GetUsagesArray(bool localOnly,
1281 uint32_t* _verified,
1282 uint32_t* _count,
1283 char16_t*** _usages)
1284 {
1285 nsNSSShutDownPreventionLock locker;
1286 if (isAlreadyShutDown())
1287 return NS_ERROR_NOT_AVAILABLE;
1288
1289 nsresult rv;
1290 const int max_usages = 13;
1291 char16_t* tmpUsages[max_usages];
1292 const char* suffix = "";
1293 uint32_t tmpCount;
1294 nsUsageArrayHelper uah(mCert.get());
1295 rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount,
1296 tmpUsages);
1297 NS_ENSURE_SUCCESS(rv,rv);
1298 if (tmpCount > 0) {
1299 *_usages = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * tmpCount);
1300 if (!*_usages)
1301 return NS_ERROR_OUT_OF_MEMORY;
1302 for (uint32_t i=0; i<tmpCount; i++) {
1303 (*_usages)[i] = tmpUsages[i];
1304 }
1305 *_count = tmpCount;
1306 return NS_OK;
1307 }
1308 *_usages = (char16_t**) nsMemory::Alloc(sizeof(char16_t*));
1309 if (!*_usages)
1310 return NS_ERROR_OUT_OF_MEMORY;
1311 *_count = 0;
1312 return NS_OK;
1313 }
1314
1315 NS_IMETHODIMP
1316 nsNSSCertificate::RequestUsagesArrayAsync(
1317 nsICertVerificationListener* aResultListener)
1318 {
1319 NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD);
1320
1321 if (!aResultListener)
1322 return NS_ERROR_FAILURE;
1323
1324 nsCertVerificationJob* job = new nsCertVerificationJob;
1325
1326 job->mCert = this;
1327 job->mListener =
1328 new nsMainThreadPtrHolder<nsICertVerificationListener>(aResultListener);
1329
1330 nsresult rv = nsCertVerificationThread::addJob(job);
1331 if (NS_FAILED(rv))
1332 delete job;
1333
1334 return rv;
1335 }
1336
1337 NS_IMETHODIMP
1338 nsNSSCertificate::GetUsagesString(bool localOnly, uint32_t* _verified,
1339 nsAString& _usages)
1340 {
1341 nsNSSShutDownPreventionLock locker;
1342 if (isAlreadyShutDown())
1343 return NS_ERROR_NOT_AVAILABLE;
1344
1345 nsresult rv;
1346 const int max_usages = 13;
1347 char16_t* tmpUsages[max_usages];
1348 const char* suffix = "_p";
1349 uint32_t tmpCount;
1350 nsUsageArrayHelper uah(mCert.get());
1351 rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount,
1352 tmpUsages);
1353 NS_ENSURE_SUCCESS(rv,rv);
1354 _usages.Truncate();
1355 for (uint32_t i=0; i<tmpCount; i++) {
1356 if (i>0) _usages.AppendLiteral(",");
1357 _usages.Append(tmpUsages[i]);
1358 nsMemory::Free(tmpUsages[i]);
1359 }
1360 return NS_OK;
1361 }
1362
1363 #if defined(DEBUG_javi) || defined(DEBUG_jgmyers)
1364 void
1365 DumpASN1Object(nsIASN1Object* object, unsigned int level)
1366 {
1367 nsAutoString dispNameU, dispValU;
1368 unsigned int i;
1369 nsCOMPtr<nsIMutableArray> asn1Objects;
1370 nsCOMPtr<nsISupports> isupports;
1371 nsCOMPtr<nsIASN1Object> currObject;
1372 bool processObjects;
1373 uint32_t numObjects;
1374
1375 for (i=0; i<level; i++)
1376 printf (" ");
1377
1378 object->GetDisplayName(dispNameU);
1379 nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object));
1380 if (sequence) {
1381 printf ("%s ", NS_ConvertUTF16toUTF8(dispNameU).get());
1382 sequence->GetIsValidContainer(&processObjects);
1383 if (processObjects) {
1384 printf("\n");
1385 sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1386 asn1Objects->GetLength(&numObjects);
1387 for (i=0; i<numObjects;i++) {
1388 asn1Objects->QueryElementAt(i, NS_GET_IID(nsISupports),
1389 getter_AddRefs(currObject));
1390 DumpASN1Object(currObject, level+1);
1391 }
1392 } else {
1393 object->GetDisplayValue(dispValU);
1394 printf("= %s\n", NS_ConvertUTF16toUTF8(dispValU).get());
1395 }
1396 } else {
1397 object->GetDisplayValue(dispValU);
1398 printf("%s = %s\n",NS_ConvertUTF16toUTF8(dispNameU).get(),
1399 NS_ConvertUTF16toUTF8(dispValU).get());
1400 }
1401 }
1402 #endif
1403
1404 NS_IMETHODIMP
1405 nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure)
1406 {
1407 nsNSSShutDownPreventionLock locker;
1408 nsresult rv = NS_OK;
1409 NS_ENSURE_ARG_POINTER(aASN1Structure);
1410 // First create the recursive structure os ASN1Objects
1411 // which tells us the layout of the cert.
1412 rv = CreateASN1Struct(aASN1Structure);
1413 if (NS_FAILED(rv)) {
1414 return rv;
1415 }
1416 #ifdef DEBUG_javi
1417 DumpASN1Object(*aASN1Structure, 0);
1418 #endif
1419 return rv;
1420 }
1421
1422 NS_IMETHODIMP
1423 nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
1424 {
1425 nsNSSShutDownPreventionLock locker;
1426 if (isAlreadyShutDown())
1427 return NS_ERROR_NOT_AVAILABLE;
1428
1429 NS_ENSURE_ARG(other);
1430 NS_ENSURE_ARG(result);
1431
1432 nsCOMPtr<nsIX509Cert2> other2 = do_QueryInterface(other);
1433 if (!other2)
1434 return NS_ERROR_FAILURE;
1435
1436 ScopedCERTCertificate cert(other2->GetCert());
1437 *result = (mCert.get() == cert.get());
1438 return NS_OK;
1439 }
1440
1441 NS_IMETHODIMP
1442 nsNSSCertificate::SaveSMimeProfile()
1443 {
1444 nsNSSShutDownPreventionLock locker;
1445 if (isAlreadyShutDown())
1446 return NS_ERROR_NOT_AVAILABLE;
1447
1448 if (SECSuccess != CERT_SaveSMimeProfile(mCert.get(), nullptr, nullptr))
1449 return NS_ERROR_FAILURE;
1450 else
1451 return NS_OK;
1452 }
1453
1454 #ifndef MOZ_NO_EV_CERTS
1455
1456 nsresult
1457 nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
1458 {
1459 nsNSSShutDownPreventionLock locker;
1460 if (isAlreadyShutDown())
1461 return NS_ERROR_NOT_AVAILABLE;
1462
1463 EnsureIdentityInfoLoaded();
1464
1465 RefPtr<mozilla::psm::SharedCertVerifier>
1466 certVerifier(mozilla::psm::GetDefaultCertVerifier());
1467 NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
1468
1469 validEV = false;
1470 resultOidTag = SEC_OID_UNKNOWN;
1471
1472 uint32_t flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY |
1473 mozilla::psm::CertVerifier::FLAG_MUST_BE_EV;
1474 SECStatus rv = certVerifier->VerifyCert(mCert.get(),
1475 certificateUsageSSLServer, PR_Now(),
1476 nullptr /* XXX pinarg */,
1477 nullptr /* hostname */,
1478 flags, nullptr /* stapledOCSPResponse */ , nullptr, &resultOidTag);
1479
1480 if (rv != SECSuccess) {
1481 resultOidTag = SEC_OID_UNKNOWN;
1482 }
1483 if (resultOidTag != SEC_OID_UNKNOWN) {
1484 validEV = true;
1485 }
1486 return NS_OK;
1487 }
1488
1489 nsresult
1490 nsNSSCertificate::getValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
1491 {
1492 if (mCachedEVStatus != ev_status_unknown) {
1493 validEV = (mCachedEVStatus == ev_status_valid);
1494 if (validEV) {
1495 resultOidTag = mCachedEVOidTag;
1496 }
1497 return NS_OK;
1498 }
1499
1500 nsresult rv = hasValidEVOidTag(resultOidTag, validEV);
1501 if (NS_SUCCEEDED(rv)) {
1502 if (validEV) {
1503 mCachedEVOidTag = resultOidTag;
1504 }
1505 mCachedEVStatus = validEV ? ev_status_valid : ev_status_invalid;
1506 }
1507 return rv;
1508 }
1509
1510 #endif // MOZ_NO_EV_CERTS
1511
1512 NS_IMETHODIMP
1513 nsNSSCertificate::GetIsExtendedValidation(bool* aIsEV)
1514 {
1515 #ifdef MOZ_NO_EV_CERTS
1516 *aIsEV = false;
1517 return NS_OK;
1518 #else
1519 nsNSSShutDownPreventionLock locker;
1520 if (isAlreadyShutDown()) {
1521 return NS_ERROR_NOT_AVAILABLE;
1522 }
1523
1524 NS_ENSURE_ARG(aIsEV);
1525 *aIsEV = false;
1526
1527 if (mCachedEVStatus != ev_status_unknown) {
1528 *aIsEV = (mCachedEVStatus == ev_status_valid);
1529 return NS_OK;
1530 }
1531
1532 SECOidTag oid_tag;
1533 return getValidEVOidTag(oid_tag, *aIsEV);
1534 #endif
1535 }
1536
1537 NS_IMETHODIMP
1538 nsNSSCertificate::GetValidEVPolicyOid(nsACString& outDottedOid)
1539 {
1540 outDottedOid.Truncate();
1541
1542 #ifndef MOZ_NO_EV_CERTS
1543 nsNSSShutDownPreventionLock locker;
1544 if (isAlreadyShutDown()) {
1545 return NS_ERROR_NOT_AVAILABLE;
1546 }
1547
1548 SECOidTag oid_tag;
1549 bool valid;
1550 nsresult rv = getValidEVOidTag(oid_tag, valid);
1551 if (NS_FAILED(rv)) {
1552 return rv;
1553 }
1554
1555 if (valid) {
1556 SECOidData* oid_data = SECOID_FindOIDByTag(oid_tag);
1557 if (!oid_data) {
1558 return NS_ERROR_FAILURE;
1559 }
1560
1561 char* oid_str = CERT_GetOidString(&oid_data->oid);
1562 if (!oid_str) {
1563 return NS_ERROR_FAILURE;
1564 }
1565
1566 outDottedOid.Assign(oid_str);
1567 PR_smprintf_free(oid_str);
1568 }
1569 #endif
1570
1571 return NS_OK;
1572 }
1573
1574 NS_IMPL_ISUPPORTS(nsNSSCertList, nsIX509CertList)
1575
1576 nsNSSCertList::nsNSSCertList(mozilla::pkix::ScopedCERTCertList& certList,
1577 const nsNSSShutDownPreventionLock& proofOfLock)
1578 {
1579 if (certList) {
1580 mCertList = certList.release();
1581 } else {
1582 mCertList = CERT_NewCertList();
1583 }
1584 }
1585
1586 nsNSSCertList::nsNSSCertList()
1587 {
1588 mCertList = CERT_NewCertList();
1589 }
1590
1591 nsNSSCertList::~nsNSSCertList()
1592 {
1593 nsNSSShutDownPreventionLock locker;
1594 if (isAlreadyShutDown()) {
1595 return;
1596 }
1597 destructorSafeDestroyNSSReference();
1598 shutdown(calledFromObject);
1599 }
1600
1601 void nsNSSCertList::virtualDestroyNSSReference()
1602 {
1603 destructorSafeDestroyNSSReference();
1604 }
1605
1606 void nsNSSCertList::destructorSafeDestroyNSSReference()
1607 {
1608 if (mCertList) {
1609 mCertList = nullptr;
1610 }
1611 }
1612
1613 NS_IMETHODIMP
1614 nsNSSCertList::AddCert(nsIX509Cert* aCert)
1615 {
1616 nsNSSShutDownPreventionLock locker;
1617 if (isAlreadyShutDown()) {
1618 return NS_ERROR_NOT_AVAILABLE;
1619 }
1620 nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
1621 CERTCertificate* cert;
1622
1623 cert = nssCert->GetCert();
1624 if (!cert) {
1625 NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
1626 return NS_ERROR_FAILURE;
1627 }
1628
1629 if (!mCertList) {
1630 NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
1631 return NS_ERROR_FAILURE;
1632 }
1633 // XXX: check return value!
1634 CERT_AddCertToListTail(mCertList.get(), cert);
1635 return NS_OK;
1636 }
1637
1638 NS_IMETHODIMP
1639 nsNSSCertList::DeleteCert(nsIX509Cert* aCert)
1640 {
1641 nsNSSShutDownPreventionLock locker;
1642 if (isAlreadyShutDown()) {
1643 return NS_ERROR_NOT_AVAILABLE;
1644 }
1645 nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
1646 CERTCertificate* cert = nssCert->GetCert();
1647 CERTCertListNode* node;
1648
1649 if (!cert) {
1650 NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
1651 return NS_ERROR_FAILURE;
1652 }
1653
1654 if (!mCertList) {
1655 NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
1656 return NS_ERROR_FAILURE;
1657 }
1658
1659 for (node = CERT_LIST_HEAD(mCertList.get());
1660 !CERT_LIST_END(node, mCertList.get()); node = CERT_LIST_NEXT(node)) {
1661 if (node->cert == cert) {
1662 CERT_RemoveCertListNode(node);
1663 return NS_OK;
1664 }
1665 }
1666 return NS_OK; // XXX Should we fail if we couldn't find it?
1667 }
1668
1669 CERTCertList*
1670 nsNSSCertList::DupCertList(CERTCertList* aCertList,
1671 const nsNSSShutDownPreventionLock& /*proofOfLock*/)
1672 {
1673 if (!aCertList)
1674 return nullptr;
1675
1676 CERTCertList* newList = CERT_NewCertList();
1677
1678 if (!newList) {
1679 return nullptr;
1680 }
1681
1682 CERTCertListNode* node;
1683 for (node = CERT_LIST_HEAD(aCertList); !CERT_LIST_END(node, aCertList);
1684 node = CERT_LIST_NEXT(node)) {
1685 CERTCertificate* cert = CERT_DupCertificate(node->cert);
1686 CERT_AddCertToListTail(newList, cert);
1687 }
1688 return newList;
1689 }
1690
1691 void*
1692 nsNSSCertList::GetRawCertList()
1693 {
1694 // This function should only be called after adquiring a
1695 // nsNSSShutDownPreventionLock
1696 return mCertList.get();
1697 }
1698
1699 NS_IMETHODIMP
1700 nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
1701 {
1702 nsNSSShutDownPreventionLock locker;
1703 if (isAlreadyShutDown()) {
1704 return NS_ERROR_NOT_AVAILABLE;
1705 }
1706 nsCOMPtr<nsISimpleEnumerator> enumerator =
1707 new nsNSSCertListEnumerator(mCertList.get(), locker);
1708
1709 *_retval = enumerator;
1710 NS_ADDREF(*_retval);
1711 return NS_OK;
1712 }
1713
1714 NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
1715
1716 nsNSSCertListEnumerator::nsNSSCertListEnumerator(
1717 CERTCertList* certList, const nsNSSShutDownPreventionLock& proofOfLock)
1718 {
1719 mCertList = nsNSSCertList::DupCertList(certList, proofOfLock);
1720 }
1721
1722 nsNSSCertListEnumerator::~nsNSSCertListEnumerator()
1723 {
1724 nsNSSShutDownPreventionLock locker;
1725 if (isAlreadyShutDown()) {
1726 return;
1727 }
1728 destructorSafeDestroyNSSReference();
1729 shutdown(calledFromObject);
1730 }
1731
1732 void nsNSSCertListEnumerator::virtualDestroyNSSReference()
1733 {
1734 destructorSafeDestroyNSSReference();
1735 }
1736
1737 void nsNSSCertListEnumerator::destructorSafeDestroyNSSReference()
1738 {
1739 if (mCertList) {
1740 mCertList = nullptr;
1741 }
1742 }
1743
1744 NS_IMETHODIMP
1745 nsNSSCertListEnumerator::HasMoreElements(bool* _retval)
1746 {
1747 nsNSSShutDownPreventionLock locker;
1748 if (isAlreadyShutDown()) {
1749 return NS_ERROR_NOT_AVAILABLE;
1750 }
1751
1752 NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
1753
1754 *_retval = !CERT_LIST_EMPTY(mCertList);
1755 return NS_OK;
1756 }
1757
1758 NS_IMETHODIMP
1759 nsNSSCertListEnumerator::GetNext(nsISupports** _retval)
1760 {
1761 nsNSSShutDownPreventionLock locker;
1762 if (isAlreadyShutDown()) {
1763 return NS_ERROR_NOT_AVAILABLE;
1764 }
1765
1766 NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
1767
1768 CERTCertListNode* node = CERT_LIST_HEAD(mCertList);
1769 if (CERT_LIST_END(node, mCertList)) {
1770 return NS_ERROR_FAILURE;
1771 }
1772
1773 nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert);
1774 if (!nssCert) {
1775 return NS_ERROR_OUT_OF_MEMORY;
1776 }
1777
1778 *_retval = nssCert;
1779 NS_ADDREF(*_retval);
1780
1781 CERT_RemoveCertListNode(node);
1782 return NS_OK;
1783 }
1784
1785 // NB: This serialization must match that of nsNSSCertificateFakeTransport.
1786 NS_IMETHODIMP
1787 nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
1788 {
1789 NS_ENSURE_STATE(mCert);
1790 nsresult rv = aStream->Write32(static_cast<uint32_t>(mCachedEVStatus));
1791 if (NS_FAILED(rv)) {
1792 return rv;
1793 }
1794 rv = aStream->Write32(mCert->derCert.len);
1795 if (NS_FAILED(rv)) {
1796 return rv;
1797 }
1798 return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len);
1799 }
1800
1801 NS_IMETHODIMP
1802 nsNSSCertificate::Read(nsIObjectInputStream* aStream)
1803 {
1804 NS_ENSURE_STATE(!mCert);
1805
1806 uint32_t cachedEVStatus;
1807 nsresult rv = aStream->Read32(&cachedEVStatus);
1808 if (NS_FAILED(rv)) {
1809 return rv;
1810 }
1811 if (cachedEVStatus == static_cast<uint32_t>(ev_status_unknown)) {
1812 mCachedEVStatus = ev_status_unknown;
1813 } else if (cachedEVStatus == static_cast<uint32_t>(ev_status_valid)) {
1814 mCachedEVStatus = ev_status_valid;
1815 } else if (cachedEVStatus == static_cast<uint32_t>(ev_status_invalid)) {
1816 mCachedEVStatus = ev_status_invalid;
1817 } else {
1818 return NS_ERROR_UNEXPECTED;
1819 }
1820
1821 uint32_t len;
1822 rv = aStream->Read32(&len);
1823 if (NS_FAILED(rv)) {
1824 return rv;
1825 }
1826
1827 nsXPIDLCString str;
1828 rv = aStream->ReadBytes(len, getter_Copies(str));
1829 if (NS_FAILED(rv)) {
1830 return rv;
1831 }
1832
1833 if (!InitFromDER(const_cast<char*>(str.get()), len)) {
1834 return NS_ERROR_UNEXPECTED;
1835 }
1836
1837 return NS_OK;
1838 }
1839
1840 NS_IMETHODIMP
1841 nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array)
1842 {
1843 *count = 0;
1844 *array = nullptr;
1845 return NS_OK;
1846 }
1847
1848 NS_IMETHODIMP
1849 nsNSSCertificate::GetHelperForLanguage(uint32_t language,
1850 nsISupports** _retval)
1851 {
1852 *_retval = nullptr;
1853 return NS_OK;
1854 }
1855
1856 NS_IMETHODIMP
1857 nsNSSCertificate::GetContractID(char** aContractID)
1858 {
1859 *aContractID = nullptr;
1860 return NS_OK;
1861 }
1862
1863 NS_IMETHODIMP
1864 nsNSSCertificate::GetClassDescription(char** aClassDescription)
1865 {
1866 *aClassDescription = nullptr;
1867 return NS_OK;
1868 }
1869
1870 NS_IMETHODIMP
1871 nsNSSCertificate::GetClassID(nsCID** aClassID)
1872 {
1873 *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
1874 if (!*aClassID)
1875 return NS_ERROR_OUT_OF_MEMORY;
1876 return GetClassIDNoAlloc(*aClassID);
1877 }
1878
1879 NS_IMETHODIMP
1880 nsNSSCertificate::GetImplementationLanguage(uint32_t* aImplementationLanguage)
1881 {
1882 *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
1883 return NS_OK;
1884 }
1885
1886 NS_IMETHODIMP
1887 nsNSSCertificate::GetFlags(uint32_t* aFlags)
1888 {
1889 *aFlags = nsIClassInfo::THREADSAFE;
1890 return NS_OK;
1891 }
1892
1893 NS_IMETHODIMP
1894 nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
1895 {
1896 static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
1897
1898 *aClassIDNoAlloc = kNSSCertificateCID;
1899 return NS_OK;
1900 }

mercurial