Line data Source code
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 "CertVerifier.h"
9 : #include "ExtendedValidation.h"
10 : #include "NSSCertDBTrustDomain.h"
11 : #include "certdb.h"
12 : #include "mozilla/Assertions.h"
13 : #include "mozilla/Base64.h"
14 : #include "mozilla/Casting.h"
15 : #include "mozilla/NotNull.h"
16 : #include "mozilla/Unused.h"
17 : #include "nsArray.h"
18 : #include "nsCOMPtr.h"
19 : #include "nsICertificateDialogs.h"
20 : #include "nsIClassInfoImpl.h"
21 : #include "nsIObjectInputStream.h"
22 : #include "nsIObjectOutputStream.h"
23 : #include "nsISupportsPrimitives.h"
24 : #include "nsIURI.h"
25 : #include "nsIX509Cert.h"
26 : #include "nsNSSASN1Object.h"
27 : #include "nsNSSCertHelper.h"
28 : #include "nsNSSCertValidity.h"
29 : #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
30 : #include "nsPK11TokenDB.h"
31 : #include "nsPKCS12Blob.h"
32 : #include "nsProxyRelease.h"
33 : #include "nsReadableUtils.h"
34 : #include "nsString.h"
35 : #include "nsThreadUtils.h"
36 : #include "nsUnicharUtils.h"
37 : #include "nspr.h"
38 : #include "pkix/pkixnss.h"
39 : #include "pkix/pkixtypes.h"
40 : #include "pkix/Result.h"
41 : #include "prerror.h"
42 : #include "secasn1.h"
43 : #include "secder.h"
44 : #include "secerr.h"
45 : #include "ssl.h"
46 :
47 : #ifdef XP_WIN
48 : #include <winsock.h> // for htonl
49 : #endif
50 :
51 : using namespace mozilla;
52 : using namespace mozilla::psm;
53 :
54 : extern LazyLogModule gPIPNSSLog;
55 :
56 : // This is being stored in an uint32_t that can otherwise
57 : // only take values from nsIX509Cert's list of cert types.
58 : // As nsIX509Cert is frozen, we choose a value not contained
59 : // in the list to mean not yet initialized.
60 : #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
61 :
62 0 : NS_IMPL_ISUPPORTS(nsNSSCertificate,
63 : nsIX509Cert,
64 : nsISerializable,
65 : nsIClassInfo)
66 :
67 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
68 :
69 : /*static*/ nsNSSCertificate*
70 0 : nsNSSCertificate::Create(CERTCertificate* cert)
71 : {
72 0 : if (cert)
73 0 : return new nsNSSCertificate(cert);
74 : else
75 0 : return new nsNSSCertificate();
76 : }
77 :
78 : nsNSSCertificate*
79 0 : nsNSSCertificate::ConstructFromDER(char* certDER, int derLen)
80 : {
81 0 : nsNSSCertificate* newObject = nsNSSCertificate::Create();
82 0 : if (newObject && !newObject->InitFromDER(certDER, derLen)) {
83 0 : delete newObject;
84 0 : newObject = nullptr;
85 : }
86 :
87 0 : return newObject;
88 : }
89 :
90 : bool
91 0 : nsNSSCertificate::InitFromDER(char* certDER, int derLen)
92 : {
93 0 : nsNSSShutDownPreventionLock locker;
94 0 : if (isAlreadyShutDown())
95 0 : return false;
96 :
97 0 : if (!certDER || !derLen)
98 0 : return false;
99 :
100 0 : CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen);
101 :
102 0 : if (!aCert)
103 0 : return false;
104 :
105 0 : if (!aCert->dbhandle)
106 : {
107 0 : aCert->dbhandle = CERT_GetDefaultCertDB();
108 : }
109 :
110 0 : mCert.reset(aCert);
111 0 : return true;
112 : }
113 :
114 0 : nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert)
115 : : mCert(nullptr)
116 : , mPermDelete(false)
117 0 : , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
118 : {
119 0 : nsNSSShutDownPreventionLock locker;
120 0 : if (isAlreadyShutDown())
121 0 : return;
122 :
123 0 : if (cert) {
124 0 : mCert.reset(CERT_DupCertificate(cert));
125 : }
126 : }
127 :
128 0 : nsNSSCertificate::nsNSSCertificate()
129 : : mCert(nullptr)
130 : , mPermDelete(false)
131 0 : , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
132 : {
133 0 : }
134 :
135 0 : nsNSSCertificate::~nsNSSCertificate()
136 : {
137 0 : nsNSSShutDownPreventionLock locker;
138 0 : if (isAlreadyShutDown()) {
139 0 : return;
140 : }
141 0 : destructorSafeDestroyNSSReference();
142 0 : shutdown(ShutdownCalledFrom::Object);
143 0 : }
144 :
145 0 : void nsNSSCertificate::virtualDestroyNSSReference()
146 : {
147 0 : destructorSafeDestroyNSSReference();
148 0 : }
149 :
150 0 : void nsNSSCertificate::destructorSafeDestroyNSSReference()
151 : {
152 0 : if (mPermDelete) {
153 0 : if (mCertType == nsNSSCertificate::USER_CERT) {
154 0 : nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
155 0 : PK11_DeleteTokenCertAndKey(mCert.get(), cxt);
156 0 : } else if (mCert->slot && !PK11_IsReadOnly(mCert->slot)) {
157 : // If the list of built-ins does contain a non-removable
158 : // copy of this certificate, our call will not remove
159 : // the certificate permanently, but rather remove all trust.
160 0 : SEC_DeletePermCertificate(mCert.get());
161 : }
162 : }
163 :
164 0 : mCert = nullptr;
165 0 : }
166 :
167 : nsresult
168 0 : nsNSSCertificate::GetCertType(uint32_t* aCertType)
169 : {
170 0 : if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) {
171 : // only determine cert type once and cache it
172 0 : mCertType = getCertType(mCert.get());
173 : }
174 0 : *aCertType = mCertType;
175 0 : return NS_OK;
176 : }
177 :
178 : NS_IMETHODIMP
179 0 : nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned)
180 : {
181 0 : NS_ENSURE_ARG(aIsSelfSigned);
182 :
183 0 : nsNSSShutDownPreventionLock locker;
184 0 : if (isAlreadyShutDown())
185 0 : return NS_ERROR_NOT_AVAILABLE;
186 :
187 0 : *aIsSelfSigned = mCert->isRoot;
188 0 : return NS_OK;
189 : }
190 :
191 : NS_IMETHODIMP
192 0 : nsNSSCertificate::GetIsBuiltInRoot(bool* aIsBuiltInRoot)
193 : {
194 0 : NS_ENSURE_ARG(aIsBuiltInRoot);
195 :
196 0 : nsNSSShutDownPreventionLock locker;
197 0 : if (isAlreadyShutDown()) {
198 0 : return NS_ERROR_NOT_AVAILABLE;
199 : }
200 0 : pkix::Result rv = IsCertBuiltInRoot(mCert.get(), *aIsBuiltInRoot);
201 0 : if (rv != pkix::Result::Success) {
202 0 : return NS_ERROR_FAILURE;
203 : }
204 0 : return NS_OK;
205 : }
206 :
207 : nsresult
208 0 : nsNSSCertificate::MarkForPermDeletion()
209 : {
210 0 : nsNSSShutDownPreventionLock locker;
211 0 : if (isAlreadyShutDown())
212 0 : return NS_ERROR_NOT_AVAILABLE;
213 :
214 : // make sure user is logged in to the token
215 0 : nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
216 :
217 0 : if (mCert->slot && PK11_NeedLogin(mCert->slot) &&
218 0 : !PK11_NeedUserInit(mCert->slot) && !PK11_IsInternal(mCert->slot)) {
219 0 : if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx)) {
220 0 : return NS_ERROR_FAILURE;
221 : }
222 : }
223 :
224 0 : mPermDelete = true;
225 0 : return NS_OK;
226 : }
227 :
228 : /**
229 : * Appends a pipnss bundle string to the given string.
230 : *
231 : * @param nssComponent For accessing the string bundle.
232 : * @param bundleKey Key for the string to append.
233 : * @param currentText The text to append to, using commas as separators.
234 : */
235 : template<size_t N>
236 : void
237 0 : AppendBundleString(const NotNull<nsCOMPtr<nsINSSComponent>>& nssComponent,
238 : const char (&bundleKey)[N],
239 : /*in/out*/ nsAString& currentText)
240 : {
241 0 : nsAutoString bundleString;
242 0 : nsresult rv = nssComponent->GetPIPNSSBundleString(bundleKey, bundleString);
243 0 : if (NS_FAILED(rv)) {
244 0 : return;
245 : }
246 :
247 0 : if (!currentText.IsEmpty()) {
248 0 : currentText.Append(',');
249 : }
250 0 : currentText.Append(bundleString);
251 : }
252 :
253 : NS_IMETHODIMP
254 0 : nsNSSCertificate::GetKeyUsages(nsAString& text)
255 : {
256 0 : text.Truncate();
257 :
258 0 : nsCOMPtr<nsINSSComponent> nssComponent = do_GetService(kNSSComponentCID);
259 0 : if (!nssComponent) {
260 0 : return NS_ERROR_FAILURE;
261 : }
262 :
263 0 : if (!mCert) {
264 0 : return NS_ERROR_FAILURE;
265 : }
266 :
267 0 : if (!mCert->extensions) {
268 0 : return NS_OK;
269 : }
270 :
271 0 : ScopedAutoSECItem keyUsageItem;
272 0 : if (CERT_FindKeyUsageExtension(mCert.get(), &keyUsageItem) != SECSuccess) {
273 0 : return PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND ? NS_OK
274 0 : : NS_ERROR_FAILURE;
275 : }
276 :
277 0 : unsigned char keyUsage = 0;
278 0 : if (keyUsageItem.len) {
279 0 : keyUsage = keyUsageItem.data[0];
280 : }
281 :
282 : NotNull<nsCOMPtr<nsINSSComponent>> wrappedNSSComponent =
283 0 : WrapNotNull(nssComponent);
284 0 : if (keyUsage & KU_DIGITAL_SIGNATURE) {
285 0 : AppendBundleString(wrappedNSSComponent, "CertDumpKUSign", text);
286 : }
287 0 : if (keyUsage & KU_NON_REPUDIATION) {
288 0 : AppendBundleString(wrappedNSSComponent, "CertDumpKUNonRep", text);
289 : }
290 0 : if (keyUsage & KU_KEY_ENCIPHERMENT) {
291 0 : AppendBundleString(wrappedNSSComponent, "CertDumpKUEnc", text);
292 : }
293 0 : if (keyUsage & KU_DATA_ENCIPHERMENT) {
294 0 : AppendBundleString(wrappedNSSComponent, "CertDumpKUDEnc", text);
295 : }
296 0 : if (keyUsage & KU_KEY_AGREEMENT) {
297 0 : AppendBundleString(wrappedNSSComponent, "CertDumpKUKA", text);
298 : }
299 0 : if (keyUsage & KU_KEY_CERT_SIGN) {
300 0 : AppendBundleString(wrappedNSSComponent, "CertDumpKUCertSign", text);
301 : }
302 0 : if (keyUsage & KU_CRL_SIGN) {
303 0 : AppendBundleString(wrappedNSSComponent, "CertDumpKUCRLSign", text);
304 : }
305 :
306 0 : return NS_OK;
307 : }
308 :
309 : NS_IMETHODIMP
310 0 : nsNSSCertificate::GetDbKey(nsACString& aDbKey)
311 : {
312 0 : nsNSSShutDownPreventionLock locker;
313 0 : if (isAlreadyShutDown()) {
314 0 : return NS_ERROR_NOT_AVAILABLE;
315 : }
316 0 : return GetDbKey(mCert, aDbKey);
317 : }
318 :
319 : nsresult
320 0 : nsNSSCertificate::GetDbKey(const UniqueCERTCertificate& cert, nsACString& aDbKey)
321 : {
322 : static_assert(sizeof(uint64_t) == 8, "type size sanity check");
323 : static_assert(sizeof(uint32_t) == 4, "type size sanity check");
324 : // The format of the key is the base64 encoding of the following:
325 : // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
326 : // never implemented)
327 : // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
328 : // never implemented)
329 : // 4 bytes: <serial number length in big-endian order>
330 : // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
331 : // n bytes: <bytes of serial number>
332 : // m bytes: <DER-encoded issuer distinguished name>
333 0 : nsAutoCString buf;
334 0 : const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
335 0 : buf.Append(leadingZeroes, sizeof(leadingZeroes));
336 0 : uint32_t serialNumberLen = htonl(cert->serialNumber.len);
337 0 : buf.Append(BitwiseCast<const char*, const uint32_t*>(&serialNumberLen),
338 0 : sizeof(uint32_t));
339 0 : uint32_t issuerLen = htonl(cert->derIssuer.len);
340 0 : buf.Append(BitwiseCast<const char*, const uint32_t*>(&issuerLen),
341 0 : sizeof(uint32_t));
342 0 : buf.Append(BitwiseCast<char*, unsigned char*>(cert->serialNumber.data),
343 0 : cert->serialNumber.len);
344 0 : buf.Append(BitwiseCast<char*, unsigned char*>(cert->derIssuer.data),
345 0 : cert->derIssuer.len);
346 :
347 0 : return Base64Encode(buf, aDbKey);
348 : }
349 :
350 : NS_IMETHODIMP
351 0 : nsNSSCertificate::GetDisplayName(nsAString& aDisplayName)
352 : {
353 0 : nsNSSShutDownPreventionLock locker;
354 0 : if (isAlreadyShutDown()) {
355 0 : return NS_ERROR_NOT_AVAILABLE;
356 : }
357 :
358 0 : aDisplayName.Truncate();
359 :
360 0 : MOZ_ASSERT(mCert, "mCert should not be null in GetDisplayName");
361 0 : if (!mCert) {
362 0 : return NS_ERROR_FAILURE;
363 : }
364 :
365 0 : UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
366 0 : UniquePORTString organizationalUnitName(CERT_GetOrgUnitName(&mCert->subject));
367 0 : UniquePORTString organizationName(CERT_GetOrgName(&mCert->subject));
368 :
369 : bool isBuiltInRoot;
370 0 : nsresult rv = GetIsBuiltInRoot(&isBuiltInRoot);
371 0 : if (NS_FAILED(rv)) {
372 0 : return rv;
373 : }
374 :
375 : // Only use the nickname for built-in roots where we already have a hard-coded
376 : // reasonable display name (unfortunately we have to strip off the leading
377 : // slot identifier followed by a ':'). Otherwise, attempt to use the following
378 : // in order:
379 : // - the common name, if present
380 : // - an organizational unit name, if present
381 : // - an organization name, if present
382 : // - the entire subject distinguished name, if non-empty
383 : // - an email address, if one can be found
384 : // In the unlikely event that none of these fields are present and non-empty
385 : // (the subject really shouldn't be empty), an empty string is returned.
386 0 : nsAutoCString builtInRootNickname;
387 0 : if (isBuiltInRoot) {
388 0 : nsAutoCString fullNickname(mCert->nickname);
389 0 : int32_t index = fullNickname.Find(":");
390 0 : if (index != kNotFound) {
391 : // Substring will gracefully handle the case where index is the last
392 : // character in the string (that is, if the nickname is just
393 : // "Builtin Object Token:"). In that case, we'll get an empty string.
394 0 : builtInRootNickname = Substring(fullNickname,
395 0 : AssertedCast<uint32_t>(index + 1));
396 : }
397 : }
398 : const char* nameOptions[] = {
399 0 : builtInRootNickname.get(),
400 0 : commonName.get(),
401 0 : organizationalUnitName.get(),
402 0 : organizationName.get(),
403 0 : mCert->subjectName,
404 0 : mCert->emailAddr
405 0 : };
406 :
407 0 : nsAutoCString nameOption;
408 0 : for (auto nameOptionPtr : nameOptions) {
409 0 : nameOption.Assign(nameOptionPtr);
410 0 : if (nameOption.Length() > 0 && IsUTF8(nameOption)) {
411 0 : CopyUTF8toUTF16(nameOption, aDisplayName);
412 0 : return NS_OK;
413 : }
414 : }
415 :
416 0 : return NS_OK;
417 : }
418 :
419 : NS_IMETHODIMP
420 0 : nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
421 : {
422 0 : nsNSSShutDownPreventionLock locker;
423 0 : if (isAlreadyShutDown())
424 0 : return NS_ERROR_NOT_AVAILABLE;
425 :
426 0 : if (mCert->emailAddr) {
427 0 : CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
428 : } else {
429 : nsresult rv;
430 0 : nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
431 0 : if (NS_FAILED(rv) || !nssComponent) {
432 0 : return NS_ERROR_FAILURE;
433 : }
434 0 : nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
435 : }
436 0 : return NS_OK;
437 : }
438 :
439 : NS_IMETHODIMP
440 0 : nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses)
441 : {
442 0 : nsNSSShutDownPreventionLock locker;
443 0 : if (isAlreadyShutDown())
444 0 : return NS_ERROR_NOT_AVAILABLE;
445 :
446 0 : NS_ENSURE_ARG(aLength);
447 0 : NS_ENSURE_ARG(aAddresses);
448 :
449 0 : *aLength = 0;
450 :
451 : const char* aAddr;
452 0 : for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
453 0 : ;
454 0 : aAddr
455 : ;
456 0 : aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
457 : {
458 0 : ++(*aLength);
459 : }
460 :
461 0 : *aAddresses = (char16_t**) moz_xmalloc(sizeof(char16_t*) * (*aLength));
462 0 : if (!*aAddresses)
463 0 : return NS_ERROR_OUT_OF_MEMORY;
464 :
465 : uint32_t iAddr;
466 0 : for (aAddr = CERT_GetFirstEmailAddress(mCert.get()), iAddr = 0
467 0 : ;
468 0 : aAddr
469 : ;
470 0 : aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr), ++iAddr)
471 : {
472 0 : (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr));
473 : }
474 :
475 0 : return NS_OK;
476 : }
477 :
478 : NS_IMETHODIMP
479 0 : nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
480 : bool* result)
481 : {
482 0 : nsNSSShutDownPreventionLock locker;
483 0 : if (isAlreadyShutDown())
484 0 : return NS_ERROR_NOT_AVAILABLE;
485 :
486 0 : NS_ENSURE_ARG(result);
487 0 : *result = false;
488 :
489 0 : const char* aAddr = nullptr;
490 0 : for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
491 0 : ;
492 0 : aAddr
493 : ;
494 0 : aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
495 : {
496 0 : NS_ConvertUTF8toUTF16 certAddr(aAddr);
497 0 : ToLowerCase(certAddr);
498 :
499 0 : nsAutoString testAddr(aEmailAddress);
500 0 : ToLowerCase(testAddr);
501 :
502 0 : if (certAddr == testAddr)
503 : {
504 0 : *result = true;
505 0 : break;
506 : }
507 :
508 : }
509 :
510 0 : return NS_OK;
511 : }
512 :
513 : NS_IMETHODIMP
514 0 : nsNSSCertificate::GetCommonName(nsAString& aCommonName)
515 : {
516 0 : nsNSSShutDownPreventionLock locker;
517 0 : if (isAlreadyShutDown())
518 0 : return NS_ERROR_NOT_AVAILABLE;
519 :
520 0 : aCommonName.Truncate();
521 0 : if (mCert) {
522 0 : UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
523 0 : if (commonName) {
524 0 : aCommonName = NS_ConvertUTF8toUTF16(commonName.get());
525 : }
526 : }
527 0 : return NS_OK;
528 : }
529 :
530 : NS_IMETHODIMP
531 0 : nsNSSCertificate::GetOrganization(nsAString& aOrganization)
532 : {
533 0 : nsNSSShutDownPreventionLock locker;
534 0 : if (isAlreadyShutDown())
535 0 : return NS_ERROR_NOT_AVAILABLE;
536 :
537 0 : aOrganization.Truncate();
538 0 : if (mCert) {
539 0 : UniquePORTString organization(CERT_GetOrgName(&mCert->subject));
540 0 : if (organization) {
541 0 : aOrganization = NS_ConvertUTF8toUTF16(organization.get());
542 : }
543 : }
544 0 : return NS_OK;
545 : }
546 :
547 : NS_IMETHODIMP
548 0 : nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName)
549 : {
550 0 : nsNSSShutDownPreventionLock locker;
551 0 : if (isAlreadyShutDown())
552 0 : return NS_ERROR_NOT_AVAILABLE;
553 :
554 0 : aCommonName.Truncate();
555 0 : if (mCert) {
556 0 : UniquePORTString commonName(CERT_GetCommonName(&mCert->issuer));
557 0 : if (commonName) {
558 0 : aCommonName = NS_ConvertUTF8toUTF16(commonName.get());
559 : }
560 : }
561 0 : return NS_OK;
562 : }
563 :
564 : NS_IMETHODIMP
565 0 : nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization)
566 : {
567 0 : nsNSSShutDownPreventionLock locker;
568 0 : if (isAlreadyShutDown())
569 0 : return NS_ERROR_NOT_AVAILABLE;
570 :
571 0 : aOrganization.Truncate();
572 0 : if (mCert) {
573 0 : UniquePORTString organization(CERT_GetOrgName(&mCert->issuer));
574 0 : if (organization) {
575 0 : aOrganization = NS_ConvertUTF8toUTF16(organization.get());
576 : }
577 : }
578 0 : return NS_OK;
579 : }
580 :
581 : NS_IMETHODIMP
582 0 : nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit)
583 : {
584 0 : nsNSSShutDownPreventionLock locker;
585 0 : if (isAlreadyShutDown())
586 0 : return NS_ERROR_NOT_AVAILABLE;
587 :
588 0 : aOrganizationUnit.Truncate();
589 0 : if (mCert) {
590 0 : UniquePORTString organizationUnit(CERT_GetOrgUnitName(&mCert->issuer));
591 0 : if (organizationUnit) {
592 0 : aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit.get());
593 : }
594 : }
595 0 : return NS_OK;
596 : }
597 :
598 : NS_IMETHODIMP
599 0 : nsNSSCertificate::GetIssuer(nsIX509Cert** aIssuer)
600 : {
601 0 : nsNSSShutDownPreventionLock locker;
602 0 : if (isAlreadyShutDown())
603 0 : return NS_ERROR_NOT_AVAILABLE;
604 :
605 0 : NS_ENSURE_ARG(aIssuer);
606 0 : *aIssuer = nullptr;
607 :
608 0 : nsCOMPtr<nsIArray> chain;
609 : nsresult rv;
610 0 : rv = GetChain(getter_AddRefs(chain));
611 0 : NS_ENSURE_SUCCESS(rv, rv);
612 : uint32_t length;
613 0 : if (!chain || NS_FAILED(chain->GetLength(&length)) || length == 0) {
614 0 : return NS_ERROR_UNEXPECTED;
615 : }
616 0 : if (length == 1) { // No known issuer
617 0 : return NS_OK;
618 : }
619 0 : nsCOMPtr<nsIX509Cert> cert;
620 0 : chain->QueryElementAt(1, NS_GET_IID(nsIX509Cert), getter_AddRefs(cert));
621 0 : if (!cert) {
622 0 : return NS_ERROR_UNEXPECTED;
623 : }
624 0 : cert.forget(aIssuer);
625 0 : return NS_OK;
626 : }
627 :
628 : NS_IMETHODIMP
629 0 : nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit)
630 : {
631 0 : nsNSSShutDownPreventionLock locker;
632 0 : if (isAlreadyShutDown())
633 0 : return NS_ERROR_NOT_AVAILABLE;
634 :
635 0 : aOrganizationalUnit.Truncate();
636 0 : if (mCert) {
637 0 : UniquePORTString orgunit(CERT_GetOrgUnitName(&mCert->subject));
638 0 : if (orgunit) {
639 0 : aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit.get());
640 : }
641 : }
642 0 : return NS_OK;
643 : }
644 :
645 : NS_IMETHODIMP
646 0 : nsNSSCertificate::GetChain(nsIArray** _rvChain)
647 : {
648 0 : nsNSSShutDownPreventionLock locker;
649 0 : if (isAlreadyShutDown())
650 0 : return NS_ERROR_NOT_AVAILABLE;
651 :
652 0 : NS_ENSURE_ARG(_rvChain);
653 :
654 0 : mozilla::pkix::Time now(mozilla::pkix::Now());
655 :
656 0 : RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
657 0 : NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
658 :
659 0 : UniqueCERTCertList nssChain;
660 : // We want to test all usages, but we start with server because most of the
661 : // time Firefox users care about server certs.
662 0 : if (certVerifier->VerifyCert(mCert.get(), certificateUsageSSLServer, now,
663 : nullptr, /*XXX fixme*/
664 : nullptr, /* hostname */
665 : nssChain,
666 : nullptr, // no peerCertChain
667 : CertVerifier::FLAG_LOCAL_ONLY)
668 : != mozilla::pkix::Success) {
669 0 : nssChain = nullptr;
670 : // keep going
671 : }
672 :
673 : // This is the whitelist of all non-SSLServer usages that are supported by
674 : // verifycert.
675 : const int otherUsagesToTest = certificateUsageSSLClient |
676 : certificateUsageSSLCA |
677 : certificateUsageEmailSigner |
678 : certificateUsageEmailRecipient |
679 : certificateUsageObjectSigner |
680 0 : certificateUsageStatusResponder;
681 0 : for (int usage = certificateUsageSSLClient;
682 0 : usage < certificateUsageAnyCA && !nssChain;
683 0 : usage = usage << 1) {
684 0 : if ((usage & otherUsagesToTest) == 0) {
685 0 : continue;
686 : }
687 0 : if (certVerifier->VerifyCert(mCert.get(), usage, now,
688 : nullptr, /*XXX fixme*/
689 : nullptr, /*hostname*/
690 : nssChain,
691 : nullptr, // no peerCertChain
692 : CertVerifier::FLAG_LOCAL_ONLY)
693 : != mozilla::pkix::Success) {
694 0 : nssChain = nullptr;
695 : // keep going
696 : }
697 : }
698 :
699 0 : if (!nssChain) {
700 : // There is not verified path for the chain, however we still want to
701 : // present to the user as much of a possible chain as possible, in the case
702 : // where there was a problem with the cert or the issuers.
703 0 : nssChain = UniqueCERTCertList(
704 0 : CERT_GetCertChainFromCert(mCert.get(), PR_Now(), certUsageSSLClient));
705 : }
706 0 : if (!nssChain) {
707 0 : return NS_ERROR_FAILURE;
708 : }
709 :
710 : // enumerate the chain for scripting purposes
711 0 : nsCOMPtr<nsIMutableArray> array = nsArrayBase::Create();
712 0 : if (!array) {
713 0 : return NS_ERROR_FAILURE;
714 : }
715 : CERTCertListNode* node;
716 0 : for (node = CERT_LIST_HEAD(nssChain.get());
717 0 : !CERT_LIST_END(node, nssChain.get());
718 0 : node = CERT_LIST_NEXT(node)) {
719 0 : nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
720 0 : array->AppendElement(cert, false);
721 : }
722 0 : *_rvChain = array;
723 0 : NS_IF_ADDREF(*_rvChain);
724 0 : return NS_OK;
725 : }
726 :
727 : NS_IMETHODIMP
728 0 : nsNSSCertificate::GetSubjectName(nsAString& _subjectName)
729 : {
730 0 : nsNSSShutDownPreventionLock locker;
731 0 : if (isAlreadyShutDown())
732 0 : return NS_ERROR_NOT_AVAILABLE;
733 :
734 0 : _subjectName.Truncate();
735 0 : if (mCert->subjectName) {
736 0 : _subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName);
737 : }
738 0 : return NS_OK;
739 : }
740 :
741 : NS_IMETHODIMP
742 0 : nsNSSCertificate::GetIssuerName(nsAString& _issuerName)
743 : {
744 0 : nsNSSShutDownPreventionLock locker;
745 0 : if (isAlreadyShutDown())
746 0 : return NS_ERROR_NOT_AVAILABLE;
747 :
748 0 : _issuerName.Truncate();
749 0 : if (mCert->issuerName) {
750 0 : _issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName);
751 : }
752 0 : return NS_OK;
753 : }
754 :
755 : NS_IMETHODIMP
756 0 : nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber)
757 : {
758 0 : nsNSSShutDownPreventionLock locker;
759 0 : if (isAlreadyShutDown())
760 0 : return NS_ERROR_NOT_AVAILABLE;
761 :
762 0 : _serialNumber.Truncate();
763 0 : UniquePORTString tmpstr(CERT_Hexify(&mCert->serialNumber, 1));
764 0 : if (tmpstr) {
765 0 : _serialNumber = NS_ConvertASCIItoUTF16(tmpstr.get());
766 0 : return NS_OK;
767 : }
768 0 : return NS_ERROR_FAILURE;
769 : }
770 :
771 : nsresult
772 0 : nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint, SECOidTag aHashAlg)
773 : {
774 0 : nsNSSShutDownPreventionLock locker;
775 0 : if (isAlreadyShutDown()) {
776 0 : return NS_ERROR_NOT_AVAILABLE;
777 : }
778 :
779 0 : aFingerprint.Truncate();
780 0 : Digest digest;
781 0 : nsresult rv = digest.DigestBuf(aHashAlg, mCert->derCert.data,
782 0 : mCert->derCert.len);
783 0 : if (NS_FAILED(rv)) {
784 0 : return rv;
785 : }
786 :
787 : // CERT_Hexify's second argument is an int that is interpreted as a boolean
788 0 : UniquePORTString fpStr(CERT_Hexify(const_cast<SECItem*>(&digest.get()), 1));
789 0 : if (!fpStr) {
790 0 : return NS_ERROR_FAILURE;
791 : }
792 :
793 0 : aFingerprint.AssignASCII(fpStr.get());
794 0 : return NS_OK;
795 : }
796 :
797 : NS_IMETHODIMP
798 0 : nsNSSCertificate::GetSha256Fingerprint(nsAString& aSha256Fingerprint)
799 : {
800 0 : return GetCertificateHash(aSha256Fingerprint, SEC_OID_SHA256);
801 : }
802 :
803 : NS_IMETHODIMP
804 0 : nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
805 : {
806 0 : return GetCertificateHash(_sha1Fingerprint, SEC_OID_SHA1);
807 : }
808 :
809 : NS_IMETHODIMP
810 0 : nsNSSCertificate::GetTokenName(nsAString& aTokenName)
811 : {
812 0 : nsNSSShutDownPreventionLock locker;
813 0 : if (isAlreadyShutDown())
814 0 : return NS_ERROR_NOT_AVAILABLE;
815 :
816 0 : aTokenName.Truncate();
817 0 : if (mCert) {
818 : // HACK alert
819 : // When the trust of a builtin cert is modified, NSS copies it into the
820 : // cert db. At this point, it is now "managed" by the user, and should
821 : // not be listed with the builtins. However, in the collection code
822 : // used by PK11_ListCerts, the cert is found in the temp db, where it
823 : // has been loaded from the token. Though the trust is correct (grabbed
824 : // from the cert db), the source is wrong. I believe this is a safe
825 : // way to work around this.
826 0 : if (mCert->slot) {
827 0 : char* token = PK11_GetTokenName(mCert->slot);
828 0 : if (token) {
829 0 : aTokenName = NS_ConvertUTF8toUTF16(token);
830 : }
831 : } else {
832 : nsresult rv;
833 0 : nsAutoString tok;
834 0 : nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
835 0 : if (NS_FAILED(rv)) return rv;
836 0 : rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok);
837 0 : if (NS_SUCCEEDED(rv))
838 0 : aTokenName = tok;
839 : }
840 : }
841 0 : return NS_OK;
842 : }
843 :
844 : NS_IMETHODIMP
845 0 : nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest)
846 : {
847 0 : nsNSSShutDownPreventionLock locker;
848 0 : if (isAlreadyShutDown()) {
849 0 : return NS_ERROR_NOT_AVAILABLE;
850 : }
851 :
852 0 : aSha256SPKIDigest.Truncate();
853 0 : Digest digest;
854 0 : nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data,
855 0 : mCert->derPublicKey.len);
856 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
857 0 : return rv;
858 : }
859 0 : rv = Base64Encode(nsDependentCSubstring(
860 0 : BitwiseCast<char*, unsigned char*>(digest.get().data),
861 0 : digest.get().len),
862 0 : aSha256SPKIDigest);
863 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
864 0 : return rv;
865 : }
866 0 : return NS_OK;
867 : }
868 :
869 : NS_IMETHODIMP
870 0 : nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray)
871 : {
872 0 : nsNSSShutDownPreventionLock locker;
873 0 : if (isAlreadyShutDown())
874 0 : return NS_ERROR_NOT_AVAILABLE;
875 :
876 0 : if (mCert) {
877 0 : *aArray = (uint8_t*)moz_xmalloc(mCert->derCert.len);
878 0 : if (*aArray) {
879 0 : memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
880 0 : *aLength = mCert->derCert.len;
881 0 : return NS_OK;
882 : }
883 : }
884 0 : *aLength = 0;
885 0 : return NS_ERROR_FAILURE;
886 : }
887 :
888 : NS_IMETHODIMP
889 0 : nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
890 : uint32_t* aLength, uint8_t** aArray)
891 : {
892 0 : NS_ENSURE_ARG(aLength);
893 0 : NS_ENSURE_ARG(aArray);
894 :
895 0 : nsNSSShutDownPreventionLock locker;
896 0 : if (isAlreadyShutDown())
897 0 : return NS_ERROR_NOT_AVAILABLE;
898 :
899 0 : if (!mCert)
900 0 : return NS_ERROR_FAILURE;
901 :
902 0 : switch (chainMode) {
903 : case nsIX509Cert::CMS_CHAIN_MODE_CertOnly:
904 : case nsIX509Cert::CMS_CHAIN_MODE_CertChain:
905 : case nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot:
906 0 : break;
907 : default:
908 0 : return NS_ERROR_INVALID_ARG;
909 : }
910 :
911 0 : UniqueNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr));
912 0 : if (!cmsg) {
913 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
914 : ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n"));
915 0 : return NS_ERROR_OUT_OF_MEMORY;
916 : }
917 :
918 : // first, create SignedData with the certificate only (no chain)
919 : UniqueNSSCMSSignedData sigd(
920 0 : NSS_CMSSignedData_CreateCertsOnly(cmsg.get(), mCert.get(), false));
921 0 : if (!sigd) {
922 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
923 : ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n"));
924 0 : return NS_ERROR_FAILURE;
925 : }
926 :
927 : // Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us
928 : // to specify the inclusion of the root, but CERT_CertChainFromCert() does.
929 : // Since CERT_CertChainFromCert() also includes the certificate itself,
930 : // we have to start at the issuing cert (to avoid duplicate certs
931 : // in the SignedData).
932 0 : if (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChain ||
933 : chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot) {
934 : UniqueCERTCertificate issuerCert(
935 0 : CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA));
936 : // the issuerCert of a self signed root is the cert itself,
937 : // so make sure we're not adding duplicates, again
938 0 : if (issuerCert && issuerCert != mCert) {
939 : bool includeRoot =
940 0 : (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot);
941 : UniqueCERTCertificateList certChain(
942 0 : CERT_CertChainFromCert(issuerCert.get(), certUsageAnyCA, includeRoot));
943 0 : if (certChain) {
944 0 : if (NSS_CMSSignedData_AddCertList(sigd.get(), certChain.get())
945 : == SECSuccess) {
946 0 : Unused << certChain.release();
947 : }
948 : else {
949 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
950 : ("nsNSSCertificate::ExportAsCMS - can't add chain\n"));
951 0 : return NS_ERROR_FAILURE;
952 : }
953 : }
954 : else {
955 : // try to add the issuerCert, at least
956 0 : if (NSS_CMSSignedData_AddCertificate(sigd.get(), issuerCert.get())
957 : == SECSuccess) {
958 0 : Unused << issuerCert.release();
959 : }
960 : else {
961 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
962 : ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n"));
963 0 : return NS_ERROR_FAILURE;
964 : }
965 : }
966 : }
967 : }
968 :
969 0 : NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg.get());
970 0 : if (NSS_CMSContentInfo_SetContent_SignedData(cmsg.get(), cinfo, sigd.get())
971 : == SECSuccess) {
972 0 : Unused << sigd.release();
973 : }
974 : else {
975 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
976 : ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n"));
977 0 : return NS_ERROR_FAILURE;
978 : }
979 :
980 0 : UniquePLArenaPool arena(PORT_NewArena(1024));
981 0 : if (!arena) {
982 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
983 : ("nsNSSCertificate::ExportAsCMS - out of memory\n"));
984 0 : return NS_ERROR_OUT_OF_MEMORY;
985 : }
986 :
987 0 : SECItem certP7 = { siBuffer, nullptr, 0 };
988 0 : NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg.get(), nullptr, nullptr,
989 : &certP7, arena.get(), nullptr,
990 : nullptr, nullptr, nullptr,
991 0 : nullptr, nullptr);
992 0 : if (!ecx) {
993 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
994 : ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n"));
995 0 : return NS_ERROR_FAILURE;
996 : }
997 :
998 0 : if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
999 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1000 : ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n"));
1001 0 : return NS_ERROR_FAILURE;
1002 : }
1003 :
1004 0 : *aArray = (uint8_t*)moz_xmalloc(certP7.len);
1005 0 : if (!*aArray)
1006 0 : return NS_ERROR_OUT_OF_MEMORY;
1007 :
1008 0 : memcpy(*aArray, certP7.data, certP7.len);
1009 0 : *aLength = certP7.len;
1010 0 : return NS_OK;
1011 : }
1012 :
1013 : CERTCertificate*
1014 0 : nsNSSCertificate::GetCert()
1015 : {
1016 0 : nsNSSShutDownPreventionLock locker;
1017 0 : if (isAlreadyShutDown())
1018 0 : return nullptr;
1019 :
1020 0 : return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr;
1021 : }
1022 :
1023 : NS_IMETHODIMP
1024 0 : nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity)
1025 : {
1026 0 : nsNSSShutDownPreventionLock locker;
1027 0 : if (isAlreadyShutDown())
1028 0 : return NS_ERROR_NOT_AVAILABLE;
1029 :
1030 0 : NS_ENSURE_ARG(aValidity);
1031 :
1032 0 : if (!mCert) {
1033 0 : return NS_ERROR_FAILURE;
1034 : }
1035 :
1036 0 : nsCOMPtr<nsIX509CertValidity> validity = new nsX509CertValidity(mCert);
1037 0 : validity.forget(aValidity);
1038 0 : return NS_OK;
1039 : }
1040 :
1041 : NS_IMETHODIMP
1042 0 : nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure)
1043 : {
1044 0 : NS_ENSURE_ARG_POINTER(aASN1Structure);
1045 0 : if (!NS_IsMainThread()) {
1046 0 : return NS_ERROR_NOT_SAME_THREAD;
1047 : }
1048 0 : return CreateASN1Struct(aASN1Structure);
1049 : }
1050 :
1051 : NS_IMETHODIMP
1052 0 : nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
1053 : {
1054 0 : nsNSSShutDownPreventionLock locker;
1055 0 : if (isAlreadyShutDown())
1056 0 : return NS_ERROR_NOT_AVAILABLE;
1057 :
1058 0 : NS_ENSURE_ARG(other);
1059 0 : NS_ENSURE_ARG(result);
1060 :
1061 0 : UniqueCERTCertificate cert(other->GetCert());
1062 0 : *result = (mCert.get() == cert.get());
1063 0 : return NS_OK;
1064 : }
1065 :
1066 : namespace mozilla {
1067 :
1068 : // TODO(bug 1036065): It seems like we only construct CERTCertLists for the
1069 : // purpose of constructing nsNSSCertLists, so maybe we should change this
1070 : // function to output an nsNSSCertList instead.
1071 : SECStatus
1072 0 : ConstructCERTCertListFromReversedDERArray(
1073 : const mozilla::pkix::DERArray& certArray,
1074 : /*out*/ UniqueCERTCertList& certList)
1075 : {
1076 0 : certList = UniqueCERTCertList(CERT_NewCertList());
1077 0 : if (!certList) {
1078 0 : return SECFailure;
1079 : }
1080 :
1081 0 : CERTCertDBHandle* certDB(CERT_GetDefaultCertDB()); // non-owning
1082 :
1083 0 : size_t numCerts = certArray.GetLength();
1084 0 : for (size_t i = 0; i < numCerts; ++i) {
1085 0 : SECItem certDER(UnsafeMapInputToSECItem(*certArray.GetDER(i)));
1086 : UniqueCERTCertificate cert(CERT_NewTempCertificate(certDB, &certDER,
1087 0 : nullptr, false, true));
1088 0 : if (!cert) {
1089 0 : return SECFailure;
1090 : }
1091 : // certArray is ordered with the root first, but we want the resulting
1092 : // certList to have the root last.
1093 0 : if (CERT_AddCertToListHead(certList.get(), cert.get()) != SECSuccess) {
1094 0 : return SECFailure;
1095 : }
1096 0 : Unused << cert.release(); // cert is now owned by certList.
1097 : }
1098 :
1099 0 : return SECSuccess;
1100 : }
1101 :
1102 : } // namespace mozilla
1103 :
1104 3 : NS_IMPL_CLASSINFO(nsNSSCertList,
1105 : nullptr,
1106 : // inferred from nsIX509Cert
1107 : nsIClassInfo::THREADSAFE,
1108 : NS_X509CERTLIST_CID)
1109 :
1110 0 : NS_IMPL_ISUPPORTS_CI(nsNSSCertList,
1111 : nsIX509CertList,
1112 : nsISerializable)
1113 :
1114 0 : nsNSSCertList::nsNSSCertList(UniqueCERTCertList certList,
1115 0 : const nsNSSShutDownPreventionLock& proofOfLock)
1116 : {
1117 0 : if (certList) {
1118 0 : mCertList = Move(certList);
1119 : } else {
1120 0 : mCertList = UniqueCERTCertList(CERT_NewCertList());
1121 : }
1122 0 : }
1123 :
1124 0 : nsNSSCertList::nsNSSCertList()
1125 : {
1126 0 : mCertList = UniqueCERTCertList(CERT_NewCertList());
1127 0 : }
1128 :
1129 0 : nsNSSCertList::~nsNSSCertList()
1130 : {
1131 0 : nsNSSShutDownPreventionLock locker;
1132 0 : if (isAlreadyShutDown()) {
1133 0 : return;
1134 : }
1135 0 : destructorSafeDestroyNSSReference();
1136 0 : shutdown(ShutdownCalledFrom::Object);
1137 0 : }
1138 :
1139 0 : void nsNSSCertList::virtualDestroyNSSReference()
1140 : {
1141 0 : destructorSafeDestroyNSSReference();
1142 0 : }
1143 :
1144 0 : void nsNSSCertList::destructorSafeDestroyNSSReference()
1145 : {
1146 0 : mCertList = nullptr;
1147 0 : }
1148 :
1149 : NS_IMETHODIMP
1150 0 : nsNSSCertList::AddCert(nsIX509Cert* aCert)
1151 : {
1152 0 : nsNSSShutDownPreventionLock locker;
1153 0 : if (isAlreadyShutDown()) {
1154 0 : return NS_ERROR_NOT_AVAILABLE;
1155 : }
1156 0 : CERTCertificate* cert = aCert->GetCert();
1157 0 : if (!cert) {
1158 0 : NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
1159 0 : return NS_ERROR_FAILURE;
1160 : }
1161 :
1162 0 : if (!mCertList) {
1163 0 : NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
1164 0 : return NS_ERROR_FAILURE;
1165 : }
1166 : // XXX: check return value!
1167 0 : CERT_AddCertToListTail(mCertList.get(), cert);
1168 0 : return NS_OK;
1169 : }
1170 :
1171 : NS_IMETHODIMP
1172 0 : nsNSSCertList::DeleteCert(nsIX509Cert* aCert)
1173 : {
1174 0 : nsNSSShutDownPreventionLock locker;
1175 0 : if (isAlreadyShutDown()) {
1176 0 : return NS_ERROR_NOT_AVAILABLE;
1177 : }
1178 0 : CERTCertificate* cert = aCert->GetCert();
1179 : CERTCertListNode* node;
1180 :
1181 0 : if (!cert) {
1182 0 : NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
1183 0 : return NS_ERROR_FAILURE;
1184 : }
1185 :
1186 0 : if (!mCertList) {
1187 0 : NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
1188 0 : return NS_ERROR_FAILURE;
1189 : }
1190 :
1191 0 : for (node = CERT_LIST_HEAD(mCertList.get());
1192 0 : !CERT_LIST_END(node, mCertList.get()); node = CERT_LIST_NEXT(node)) {
1193 0 : if (node->cert == cert) {
1194 0 : CERT_RemoveCertListNode(node);
1195 0 : return NS_OK;
1196 : }
1197 : }
1198 0 : return NS_OK; // XXX Should we fail if we couldn't find it?
1199 : }
1200 :
1201 : UniqueCERTCertList
1202 0 : nsNSSCertList::DupCertList(const UniqueCERTCertList& certList,
1203 : const nsNSSShutDownPreventionLock& /*proofOfLock*/)
1204 : {
1205 0 : if (!certList) {
1206 0 : return nullptr;
1207 : }
1208 :
1209 0 : UniqueCERTCertList newList(CERT_NewCertList());
1210 0 : if (!newList) {
1211 0 : return nullptr;
1212 : }
1213 :
1214 0 : for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
1215 0 : !CERT_LIST_END(node, certList);
1216 0 : node = CERT_LIST_NEXT(node)) {
1217 0 : UniqueCERTCertificate cert(CERT_DupCertificate(node->cert));
1218 0 : if (!cert) {
1219 0 : return nullptr;
1220 : }
1221 :
1222 0 : if (CERT_AddCertToListTail(newList.get(), cert.get()) != SECSuccess) {
1223 0 : return nullptr;
1224 : }
1225 :
1226 0 : Unused << cert.release(); // Ownership transferred to the cert list.
1227 : }
1228 0 : return newList;
1229 : }
1230 :
1231 : CERTCertList*
1232 0 : nsNSSCertList::GetRawCertList()
1233 : {
1234 : // This function should only be called after acquiring a
1235 : // nsNSSShutDownPreventionLock. It's difficult to enforce this in code since
1236 : // this is an implementation of an XPCOM interface function (albeit a
1237 : // C++-only one), so we acquire the (reentrant) lock and check for shutdown
1238 : // ourselves here. At the moment it appears that only nsCertTree uses this
1239 : // function. When that gets removed and replaced by a more reasonable
1240 : // implementation of the certificate manager, this function can be removed.
1241 0 : nsNSSShutDownPreventionLock locker;
1242 0 : if (isAlreadyShutDown()) {
1243 0 : return nullptr;
1244 : }
1245 0 : return mCertList.get();
1246 : }
1247 :
1248 : NS_IMETHODIMP
1249 0 : nsNSSCertList::Write(nsIObjectOutputStream* aStream)
1250 : {
1251 0 : nsNSSShutDownPreventionLock locker;
1252 0 : if (isAlreadyShutDown()) {
1253 0 : return NS_ERROR_NOT_AVAILABLE;
1254 : }
1255 :
1256 0 : NS_ENSURE_STATE(mCertList);
1257 0 : nsresult rv = NS_OK;
1258 :
1259 : // First, enumerate the certs to get the length of the list
1260 0 : uint32_t certListLen = 0;
1261 0 : CERTCertListNode* node = nullptr;
1262 0 : for (node = CERT_LIST_HEAD(mCertList);
1263 0 : !CERT_LIST_END(node, mCertList);
1264 0 : node = CERT_LIST_NEXT(node), ++certListLen) {
1265 : }
1266 :
1267 : // Write the length of the list
1268 0 : rv = aStream->Write32(certListLen);
1269 :
1270 : // Repeat the loop, and serialize each certificate
1271 0 : node = nullptr;
1272 0 : for (node = CERT_LIST_HEAD(mCertList);
1273 0 : !CERT_LIST_END(node, mCertList);
1274 0 : node = CERT_LIST_NEXT(node))
1275 : {
1276 0 : nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
1277 0 : if (!cert) {
1278 0 : rv = NS_ERROR_OUT_OF_MEMORY;
1279 0 : break;
1280 : }
1281 :
1282 0 : nsCOMPtr<nsISerializable> serializableCert = do_QueryInterface(cert);
1283 0 : rv = aStream->WriteCompoundObject(serializableCert, NS_GET_IID(nsIX509Cert), true);
1284 0 : if (NS_FAILED(rv)) {
1285 0 : break;
1286 : }
1287 : }
1288 :
1289 0 : return rv;
1290 : }
1291 :
1292 : NS_IMETHODIMP
1293 0 : nsNSSCertList::Read(nsIObjectInputStream* aStream)
1294 : {
1295 0 : nsNSSShutDownPreventionLock locker;
1296 0 : if (isAlreadyShutDown()) {
1297 0 : return NS_ERROR_NOT_AVAILABLE;
1298 : }
1299 :
1300 0 : NS_ENSURE_STATE(mCertList);
1301 0 : nsresult rv = NS_OK;
1302 :
1303 : uint32_t certListLen;
1304 0 : rv = aStream->Read32(&certListLen);
1305 0 : if (NS_FAILED(rv)) {
1306 0 : return rv;
1307 : }
1308 :
1309 0 : for(uint32_t i = 0; i < certListLen; ++i) {
1310 0 : nsCOMPtr<nsISupports> certSupports;
1311 0 : rv = aStream->ReadObject(true, getter_AddRefs(certSupports));
1312 0 : if (NS_FAILED(rv)) {
1313 0 : break;
1314 : }
1315 :
1316 0 : nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports);
1317 0 : rv = AddCert(cert);
1318 0 : if (NS_FAILED(rv)) {
1319 0 : break;
1320 : }
1321 : }
1322 :
1323 0 : return rv;
1324 : }
1325 :
1326 : NS_IMETHODIMP
1327 0 : nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
1328 : {
1329 0 : nsNSSShutDownPreventionLock locker;
1330 0 : if (isAlreadyShutDown()) {
1331 0 : return NS_ERROR_NOT_AVAILABLE;
1332 : }
1333 :
1334 0 : if (!mCertList) {
1335 0 : return NS_ERROR_FAILURE;
1336 : }
1337 :
1338 : nsCOMPtr<nsISimpleEnumerator> enumerator =
1339 0 : new nsNSSCertListEnumerator(mCertList, locker);
1340 :
1341 0 : enumerator.forget(_retval);
1342 0 : return NS_OK;
1343 : }
1344 :
1345 : NS_IMETHODIMP
1346 0 : nsNSSCertList::Equals(nsIX509CertList* other, bool* result)
1347 : {
1348 0 : nsNSSShutDownPreventionLock locker;
1349 0 : if (isAlreadyShutDown()) {
1350 0 : return NS_ERROR_NOT_AVAILABLE;
1351 : }
1352 :
1353 0 : NS_ENSURE_ARG(result);
1354 0 : *result = true;
1355 :
1356 : nsresult rv;
1357 :
1358 0 : nsCOMPtr<nsISimpleEnumerator> selfEnumerator;
1359 0 : rv = GetEnumerator(getter_AddRefs(selfEnumerator));
1360 0 : if (NS_FAILED(rv)) {
1361 0 : return rv;
1362 : }
1363 :
1364 0 : nsCOMPtr<nsISimpleEnumerator> otherEnumerator;
1365 0 : rv = other->GetEnumerator(getter_AddRefs(otherEnumerator));
1366 0 : if (NS_FAILED(rv)) {
1367 0 : return rv;
1368 : }
1369 :
1370 0 : nsCOMPtr<nsISupports> selfSupports;
1371 0 : nsCOMPtr<nsISupports> otherSupports;
1372 0 : while (NS_SUCCEEDED(selfEnumerator->GetNext(getter_AddRefs(selfSupports)))) {
1373 0 : if (NS_SUCCEEDED(otherEnumerator->GetNext(getter_AddRefs(otherSupports)))) {
1374 0 : nsCOMPtr<nsIX509Cert> selfCert = do_QueryInterface(selfSupports);
1375 0 : nsCOMPtr<nsIX509Cert> otherCert = do_QueryInterface(otherSupports);
1376 :
1377 0 : bool certsEqual = false;
1378 0 : rv = selfCert->Equals(otherCert, &certsEqual);
1379 0 : if (NS_FAILED(rv)) {
1380 0 : return rv;
1381 : }
1382 0 : if (!certsEqual) {
1383 0 : *result = false;
1384 0 : break;
1385 : }
1386 : } else {
1387 : // other is shorter than self
1388 0 : *result = false;
1389 0 : break;
1390 : }
1391 : }
1392 :
1393 : // Make sure self is the same length as other
1394 0 : bool otherHasMore = false;
1395 0 : rv = otherEnumerator->HasMoreElements(&otherHasMore);
1396 0 : if (NS_FAILED(rv)) {
1397 0 : return rv;
1398 : }
1399 0 : if (otherHasMore) {
1400 0 : *result = false;
1401 : }
1402 :
1403 0 : return NS_OK;
1404 : }
1405 :
1406 0 : NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
1407 :
1408 0 : nsNSSCertListEnumerator::nsNSSCertListEnumerator(
1409 : const UniqueCERTCertList& certList,
1410 0 : const nsNSSShutDownPreventionLock& proofOfLock)
1411 : {
1412 0 : MOZ_ASSERT(certList);
1413 0 : mCertList = nsNSSCertList::DupCertList(certList, proofOfLock);
1414 0 : }
1415 :
1416 0 : nsNSSCertListEnumerator::~nsNSSCertListEnumerator()
1417 : {
1418 0 : nsNSSShutDownPreventionLock locker;
1419 0 : if (isAlreadyShutDown()) {
1420 0 : return;
1421 : }
1422 0 : destructorSafeDestroyNSSReference();
1423 0 : shutdown(ShutdownCalledFrom::Object);
1424 0 : }
1425 :
1426 0 : void nsNSSCertListEnumerator::virtualDestroyNSSReference()
1427 : {
1428 0 : destructorSafeDestroyNSSReference();
1429 0 : }
1430 :
1431 0 : void nsNSSCertListEnumerator::destructorSafeDestroyNSSReference()
1432 : {
1433 0 : mCertList = nullptr;
1434 0 : }
1435 :
1436 : NS_IMETHODIMP
1437 0 : nsNSSCertListEnumerator::HasMoreElements(bool* _retval)
1438 : {
1439 0 : nsNSSShutDownPreventionLock locker;
1440 0 : if (isAlreadyShutDown()) {
1441 0 : return NS_ERROR_NOT_AVAILABLE;
1442 : }
1443 :
1444 0 : NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
1445 :
1446 0 : *_retval = !CERT_LIST_EMPTY(mCertList);
1447 0 : return NS_OK;
1448 : }
1449 :
1450 : NS_IMETHODIMP
1451 0 : nsNSSCertListEnumerator::GetNext(nsISupports** _retval)
1452 : {
1453 0 : nsNSSShutDownPreventionLock locker;
1454 0 : if (isAlreadyShutDown()) {
1455 0 : return NS_ERROR_NOT_AVAILABLE;
1456 : }
1457 :
1458 0 : NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
1459 :
1460 0 : CERTCertListNode* node = CERT_LIST_HEAD(mCertList);
1461 0 : if (CERT_LIST_END(node, mCertList)) {
1462 0 : return NS_ERROR_FAILURE;
1463 : }
1464 :
1465 0 : nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert);
1466 0 : if (!nssCert) {
1467 0 : return NS_ERROR_OUT_OF_MEMORY;
1468 : }
1469 :
1470 0 : nssCert.forget(_retval);
1471 :
1472 0 : CERT_RemoveCertListNode(node);
1473 0 : return NS_OK;
1474 : }
1475 :
1476 : NS_IMETHODIMP
1477 0 : nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
1478 : {
1479 0 : NS_ENSURE_STATE(mCert);
1480 : // This field used to be the cached EV status, but it is no longer necessary.
1481 0 : nsresult rv = aStream->Write32(0);
1482 0 : if (NS_FAILED(rv)) {
1483 0 : return rv;
1484 : }
1485 0 : rv = aStream->Write32(mCert->derCert.len);
1486 0 : if (NS_FAILED(rv)) {
1487 0 : return rv;
1488 : }
1489 0 : return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len);
1490 : }
1491 :
1492 : NS_IMETHODIMP
1493 0 : nsNSSCertificate::Read(nsIObjectInputStream* aStream)
1494 : {
1495 0 : NS_ENSURE_STATE(!mCert);
1496 :
1497 : // This field is no longer used.
1498 : uint32_t unusedCachedEVStatus;
1499 0 : nsresult rv = aStream->Read32(&unusedCachedEVStatus);
1500 0 : if (NS_FAILED(rv)) {
1501 0 : return rv;
1502 : }
1503 :
1504 : uint32_t len;
1505 0 : rv = aStream->Read32(&len);
1506 0 : if (NS_FAILED(rv)) {
1507 0 : return rv;
1508 : }
1509 :
1510 0 : nsXPIDLCString str;
1511 0 : rv = aStream->ReadBytes(len, getter_Copies(str));
1512 0 : if (NS_FAILED(rv)) {
1513 0 : return rv;
1514 : }
1515 :
1516 0 : if (!InitFromDER(const_cast<char*>(str.get()), len)) {
1517 0 : return NS_ERROR_UNEXPECTED;
1518 : }
1519 :
1520 0 : return NS_OK;
1521 : }
1522 :
1523 : NS_IMETHODIMP
1524 0 : nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array)
1525 : {
1526 0 : *count = 0;
1527 0 : *array = nullptr;
1528 0 : return NS_OK;
1529 : }
1530 :
1531 : NS_IMETHODIMP
1532 0 : nsNSSCertificate::GetScriptableHelper(nsIXPCScriptable** _retval)
1533 : {
1534 0 : *_retval = nullptr;
1535 0 : return NS_OK;
1536 : }
1537 :
1538 : NS_IMETHODIMP
1539 0 : nsNSSCertificate::GetContractID(char** aContractID)
1540 : {
1541 0 : *aContractID = nullptr;
1542 0 : return NS_OK;
1543 : }
1544 :
1545 : NS_IMETHODIMP
1546 0 : nsNSSCertificate::GetClassDescription(char** aClassDescription)
1547 : {
1548 0 : *aClassDescription = nullptr;
1549 0 : return NS_OK;
1550 : }
1551 :
1552 : NS_IMETHODIMP
1553 0 : nsNSSCertificate::GetClassID(nsCID** aClassID)
1554 : {
1555 0 : *aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
1556 0 : if (!*aClassID)
1557 0 : return NS_ERROR_OUT_OF_MEMORY;
1558 0 : return GetClassIDNoAlloc(*aClassID);
1559 : }
1560 :
1561 : NS_IMETHODIMP
1562 0 : nsNSSCertificate::GetFlags(uint32_t* aFlags)
1563 : {
1564 0 : *aFlags = nsIClassInfo::THREADSAFE;
1565 0 : return NS_OK;
1566 : }
1567 :
1568 : NS_IMETHODIMP
1569 0 : nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
1570 : {
1571 : static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
1572 :
1573 0 : *aClassIDNoAlloc = kNSSCertificateCID;
1574 0 : return NS_OK;
1575 : }
|