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 "nsPK11TokenDB.h"
30 : #include "nsPKCS12Blob.h"
31 : #include "nsProxyRelease.h"
32 : #include "nsReadableUtils.h"
33 : #include "nsString.h"
34 : #include "nsThreadUtils.h"
35 : #include "nsUnicharUtils.h"
36 : #include "nspr.h"
37 : #include "pkix/pkixnss.h"
38 : #include "pkix/pkixtypes.h"
39 : #include "pkix/Result.h"
40 : #include "prerror.h"
41 : #include "secasn1.h"
42 : #include "secder.h"
43 : #include "secerr.h"
44 : #include "ssl.h"
45 :
46 : #ifdef XP_WIN
47 : #include <winsock.h> // for htonl
48 : #endif
49 :
50 : using namespace mozilla;
51 : using namespace mozilla::psm;
52 :
53 : extern LazyLogModule gPIPNSSLog;
54 :
55 : // This is being stored in an uint32_t that can otherwise
56 : // only take values from nsIX509Cert's list of cert types.
57 : // As nsIX509Cert is frozen, we choose a value not contained
58 : // in the list to mean not yet initialized.
59 : #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
60 :
61 76 : NS_IMPL_ISUPPORTS(nsNSSCertificate,
62 : nsIX509Cert,
63 : nsISerializable,
64 : nsIClassInfo)
65 :
66 : /*static*/ nsNSSCertificate*
67 6 : nsNSSCertificate::Create(CERTCertificate* cert)
68 : {
69 6 : if (cert)
70 0 : return new nsNSSCertificate(cert);
71 : else
72 0 : return new nsNSSCertificate();
73 : }
74 :
75 : nsNSSCertificate*
76 0 : nsNSSCertificate::ConstructFromDER(char* certDER, int derLen)
77 : {
78 0 : nsNSSCertificate* newObject = nsNSSCertificate::Create();
79 0 : if (newObject && !newObject->InitFromDER(certDER, derLen)) {
80 0 : delete newObject;
81 : newObject = nullptr;
82 : }
83 :
84 0 : return newObject;
85 : }
86 :
87 : bool
88 0 : nsNSSCertificate::InitFromDER(char* certDER, int derLen)
89 : {
90 0 : if (!certDER || !derLen)
91 : return false;
92 :
93 0 : CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen);
94 :
95 0 : if (!aCert)
96 : return false;
97 :
98 0 : if (!aCert->dbhandle)
99 : {
100 0 : aCert->dbhandle = CERT_GetDefaultCertDB();
101 : }
102 :
103 0 : mCert.reset(aCert);
104 0 : GetSubjectAltNames();
105 0 : return true;
106 : }
107 :
108 0 : nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert)
109 : : mCert(nullptr)
110 : , mPermDelete(false)
111 : , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
112 42 : , mSubjectAltNames()
113 : {
114 6 : if (cert) {
115 0 : mCert.reset(CERT_DupCertificate(cert));
116 6 : GetSubjectAltNames();
117 : }
118 0 : }
119 :
120 0 : nsNSSCertificate::nsNSSCertificate()
121 : : mCert(nullptr)
122 : , mPermDelete(false)
123 : , mCertType(CERT_TYPE_NOT_YET_INITIALIZED)
124 0 : , mSubjectAltNames()
125 : {
126 0 : }
127 :
128 18 : nsNSSCertificate::~nsNSSCertificate()
129 : {
130 6 : if (mPermDelete) {
131 0 : if (mCertType == nsNSSCertificate::USER_CERT) {
132 0 : nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
133 0 : PK11_DeleteTokenCertAndKey(mCert.get(), cxt);
134 0 : } else if (mCert->slot && !PK11_IsReadOnly(mCert->slot)) {
135 : // If the list of built-ins does contain a non-removable
136 : // copy of this certificate, our call will not remove
137 : // the certificate permanently, but rather remove all trust.
138 0 : SEC_DeletePermCertificate(mCert.get());
139 : }
140 : }
141 0 : }
142 :
143 : nsresult
144 0 : nsNSSCertificate::GetCertType(uint32_t* aCertType)
145 : {
146 0 : if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) {
147 : // only determine cert type once and cache it
148 0 : mCertType = getCertType(mCert.get());
149 : }
150 0 : *aCertType = mCertType;
151 0 : return NS_OK;
152 : }
153 :
154 : NS_IMETHODIMP
155 0 : nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned)
156 : {
157 0 : NS_ENSURE_ARG(aIsSelfSigned);
158 :
159 0 : *aIsSelfSigned = mCert->isRoot;
160 0 : return NS_OK;
161 : }
162 :
163 : NS_IMETHODIMP
164 1 : nsNSSCertificate::GetIsBuiltInRoot(bool* aIsBuiltInRoot)
165 : {
166 1 : NS_ENSURE_ARG(aIsBuiltInRoot);
167 :
168 2 : pkix::Result rv = IsCertBuiltInRoot(mCert.get(), *aIsBuiltInRoot);
169 0 : if (rv != pkix::Result::Success) {
170 : return NS_ERROR_FAILURE;
171 : }
172 0 : return NS_OK;
173 : }
174 :
175 : nsresult
176 0 : nsNSSCertificate::MarkForPermDeletion()
177 : {
178 : // make sure user is logged in to the token
179 0 : nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
180 :
181 0 : if (mCert->slot && PK11_NeedLogin(mCert->slot) &&
182 0 : !PK11_NeedUserInit(mCert->slot) && !PK11_IsInternal(mCert->slot)) {
183 0 : if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx)) {
184 : return NS_ERROR_FAILURE;
185 : }
186 : }
187 :
188 0 : mPermDelete = true;
189 0 : return NS_OK;
190 : }
191 :
192 : /**
193 : * Appends a pipnss bundle string to the given string.
194 : *
195 : * @param bundleKey Key for the string to append.
196 : * @param currentText The text to append to, using commas as separators.
197 : */
198 : template<size_t N>
199 : void
200 0 : AppendBundleStringCommaSeparated(const char (&bundleKey)[N],
201 : /*in/out*/ nsAString& currentText)
202 : {
203 0 : nsAutoString bundleString;
204 0 : nsresult rv = GetPIPNSSBundleString(bundleKey, bundleString);
205 0 : if (NS_FAILED(rv)) {
206 0 : return;
207 : }
208 :
209 0 : if (!currentText.IsEmpty()) {
210 0 : currentText.Append(',');
211 : }
212 0 : currentText.Append(bundleString);
213 : }
214 :
215 : NS_IMETHODIMP
216 0 : nsNSSCertificate::GetKeyUsages(nsAString& text)
217 : {
218 0 : text.Truncate();
219 :
220 0 : if (!mCert) {
221 : return NS_ERROR_FAILURE;
222 : }
223 :
224 0 : if (!mCert->extensions) {
225 : return NS_OK;
226 : }
227 :
228 0 : ScopedAutoSECItem keyUsageItem;
229 0 : if (CERT_FindKeyUsageExtension(mCert.get(), &keyUsageItem) != SECSuccess) {
230 0 : return PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND ? NS_OK
231 : : NS_ERROR_FAILURE;
232 : }
233 :
234 0 : unsigned char keyUsage = 0;
235 0 : if (keyUsageItem.len) {
236 0 : keyUsage = keyUsageItem.data[0];
237 : }
238 :
239 0 : if (keyUsage & KU_DIGITAL_SIGNATURE) {
240 0 : AppendBundleStringCommaSeparated("CertDumpKUSign", text);
241 : }
242 0 : if (keyUsage & KU_NON_REPUDIATION) {
243 0 : AppendBundleStringCommaSeparated("CertDumpKUNonRep", text);
244 : }
245 0 : if (keyUsage & KU_KEY_ENCIPHERMENT) {
246 0 : AppendBundleStringCommaSeparated("CertDumpKUEnc", text);
247 : }
248 0 : if (keyUsage & KU_DATA_ENCIPHERMENT) {
249 0 : AppendBundleStringCommaSeparated("CertDumpKUDEnc", text);
250 : }
251 0 : if (keyUsage & KU_KEY_AGREEMENT) {
252 0 : AppendBundleStringCommaSeparated("CertDumpKUKA", text);
253 : }
254 0 : if (keyUsage & KU_KEY_CERT_SIGN) {
255 0 : AppendBundleStringCommaSeparated("CertDumpKUCertSign", text);
256 : }
257 0 : if (keyUsage & KU_CRL_SIGN) {
258 0 : AppendBundleStringCommaSeparated("CertDumpKUCRLSign", text);
259 : }
260 :
261 : return NS_OK;
262 : }
263 :
264 : NS_IMETHODIMP
265 0 : nsNSSCertificate::GetDbKey(nsACString& aDbKey)
266 : {
267 0 : return GetDbKey(mCert, aDbKey);
268 : }
269 :
270 : nsresult
271 0 : nsNSSCertificate::GetDbKey(const UniqueCERTCertificate& cert, nsACString& aDbKey)
272 : {
273 : static_assert(sizeof(uint64_t) == 8, "type size sanity check");
274 : static_assert(sizeof(uint32_t) == 4, "type size sanity check");
275 : // The format of the key is the base64 encoding of the following:
276 : // 4 bytes: {0, 0, 0, 0} (this was intended to be the module ID, but it was
277 : // never implemented)
278 : // 4 bytes: {0, 0, 0, 0} (this was intended to be the slot ID, but it was
279 : // never implemented)
280 : // 4 bytes: <serial number length in big-endian order>
281 : // 4 bytes: <DER-encoded issuer distinguished name length in big-endian order>
282 : // n bytes: <bytes of serial number>
283 : // m bytes: <DER-encoded issuer distinguished name>
284 0 : nsAutoCString buf;
285 0 : const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0};
286 0 : buf.Append(leadingZeroes, sizeof(leadingZeroes));
287 0 : uint32_t serialNumberLen = htonl(cert->serialNumber.len);
288 0 : buf.Append(BitwiseCast<const char*, const uint32_t*>(&serialNumberLen),
289 0 : sizeof(uint32_t));
290 0 : uint32_t issuerLen = htonl(cert->derIssuer.len);
291 0 : buf.Append(BitwiseCast<const char*, const uint32_t*>(&issuerLen),
292 0 : sizeof(uint32_t));
293 0 : buf.Append(BitwiseCast<char*, unsigned char*>(cert->serialNumber.data),
294 0 : cert->serialNumber.len);
295 0 : buf.Append(BitwiseCast<char*, unsigned char*>(cert->derIssuer.data),
296 0 : cert->derIssuer.len);
297 :
298 0 : return Base64Encode(buf, aDbKey);
299 : }
300 :
301 : NS_IMETHODIMP
302 0 : nsNSSCertificate::GetDisplayName(nsAString& aDisplayName)
303 : {
304 0 : aDisplayName.Truncate();
305 :
306 0 : MOZ_ASSERT(mCert, "mCert should not be null in GetDisplayName");
307 0 : if (!mCert) {
308 : return NS_ERROR_FAILURE;
309 : }
310 :
311 0 : UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
312 0 : UniquePORTString organizationalUnitName(CERT_GetOrgUnitName(&mCert->subject));
313 0 : UniquePORTString organizationName(CERT_GetOrgName(&mCert->subject));
314 :
315 : bool isBuiltInRoot;
316 0 : nsresult rv = GetIsBuiltInRoot(&isBuiltInRoot);
317 0 : if (NS_FAILED(rv)) {
318 : return rv;
319 : }
320 :
321 : // Only use the nickname for built-in roots where we already have a hard-coded
322 : // reasonable display name (unfortunately we have to strip off the leading
323 : // slot identifier followed by a ':'). Otherwise, attempt to use the following
324 : // in order:
325 : // - the common name, if present
326 : // - an organizational unit name, if present
327 : // - an organization name, if present
328 : // - the entire subject distinguished name, if non-empty
329 : // - an email address, if one can be found
330 : // In the unlikely event that none of these fields are present and non-empty
331 : // (the subject really shouldn't be empty), an empty string is returned.
332 0 : nsAutoCString builtInRootNickname;
333 0 : if (isBuiltInRoot) {
334 0 : nsAutoCString fullNickname(mCert->nickname);
335 0 : int32_t index = fullNickname.Find(":");
336 0 : if (index != kNotFound) {
337 : // Substring will gracefully handle the case where index is the last
338 : // character in the string (that is, if the nickname is just
339 : // "Builtin Object Token:"). In that case, we'll get an empty string.
340 0 : builtInRootNickname = Substring(fullNickname,
341 0 : AssertedCast<uint32_t>(index + 1));
342 : }
343 : }
344 : const char* nameOptions[] = {
345 0 : builtInRootNickname.get(),
346 0 : commonName.get(),
347 0 : organizationalUnitName.get(),
348 0 : organizationName.get(),
349 0 : mCert->subjectName,
350 0 : mCert->emailAddr
351 0 : };
352 :
353 0 : for (auto nameOption : nameOptions) {
354 0 : if (nameOption) {
355 0 : size_t len = strlen(nameOption);
356 0 : if (len > 0) {
357 0 : LossyUTF8ToUTF16(nameOption, len, aDisplayName);
358 0 : return NS_OK;
359 : }
360 : }
361 : }
362 :
363 : return NS_OK;
364 : }
365 :
366 : NS_IMETHODIMP
367 0 : nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
368 : {
369 0 : if (mCert->emailAddr) {
370 0 : LossyUTF8ToUTF16(mCert->emailAddr, strlen(mCert->emailAddr), aEmailAddress);
371 : } else {
372 0 : GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
373 : }
374 0 : return NS_OK;
375 : }
376 :
377 : NS_IMETHODIMP
378 0 : nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses)
379 : {
380 0 : NS_ENSURE_ARG(aLength);
381 0 : NS_ENSURE_ARG(aAddresses);
382 :
383 0 : *aLength = 0;
384 :
385 0 : for (const char* aAddr = CERT_GetFirstEmailAddress(mCert.get());
386 0 : aAddr;
387 0 : aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) {
388 0 : ++(*aLength);
389 : }
390 :
391 0 : *aAddresses = (char16_t**) moz_xmalloc(sizeof(char16_t*) * (*aLength));
392 0 : if (!*aAddresses) {
393 : return NS_ERROR_OUT_OF_MEMORY;
394 : }
395 :
396 0 : uint32_t iAddr = 0;
397 0 : for (const char* aAddr = CERT_GetFirstEmailAddress(mCert.get());
398 0 : aAddr;
399 0 : aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) {
400 0 : (*aAddresses)[iAddr] = ToNewUnicode(nsDependentCString(aAddr));
401 0 : iAddr++;
402 : }
403 :
404 : return NS_OK;
405 : }
406 :
407 : NS_IMETHODIMP
408 0 : nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
409 : bool* result)
410 : {
411 0 : NS_ENSURE_ARG(result);
412 0 : *result = false;
413 :
414 0 : for (const char* aAddr = CERT_GetFirstEmailAddress(mCert.get());
415 0 : aAddr;
416 0 : aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) {
417 0 : nsAutoString certAddr;
418 0 : LossyUTF8ToUTF16(aAddr, strlen(aAddr), certAddr);
419 0 : ToLowerCase(certAddr);
420 :
421 0 : nsAutoString testAddr(aEmailAddress);
422 0 : ToLowerCase(testAddr);
423 :
424 0 : if (certAddr == testAddr) {
425 0 : *result = true;
426 0 : break;
427 : }
428 : }
429 :
430 : return NS_OK;
431 : }
432 :
433 : NS_IMETHODIMP
434 0 : nsNSSCertificate::GetCommonName(nsAString& aCommonName)
435 : {
436 0 : aCommonName.Truncate();
437 0 : if (mCert) {
438 0 : UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
439 0 : if (commonName) {
440 0 : LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
441 : }
442 : }
443 0 : return NS_OK;
444 : }
445 :
446 : NS_IMETHODIMP
447 0 : nsNSSCertificate::GetOrganization(nsAString& aOrganization)
448 : {
449 0 : aOrganization.Truncate();
450 0 : if (mCert) {
451 0 : UniquePORTString organization(CERT_GetOrgName(&mCert->subject));
452 0 : if (organization) {
453 0 : LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
454 0 : aOrganization);
455 : }
456 : }
457 0 : return NS_OK;
458 : }
459 :
460 : NS_IMETHODIMP
461 0 : nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName)
462 : {
463 0 : aCommonName.Truncate();
464 0 : if (mCert) {
465 0 : UniquePORTString commonName(CERT_GetCommonName(&mCert->issuer));
466 0 : if (commonName) {
467 0 : LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
468 : }
469 : }
470 0 : return NS_OK;
471 : }
472 :
473 : NS_IMETHODIMP
474 0 : nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization)
475 : {
476 0 : aOrganization.Truncate();
477 0 : if (mCert) {
478 0 : UniquePORTString organization(CERT_GetOrgName(&mCert->issuer));
479 0 : if (organization) {
480 0 : LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
481 0 : aOrganization);
482 : }
483 : }
484 0 : return NS_OK;
485 : }
486 :
487 : NS_IMETHODIMP
488 0 : nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit)
489 : {
490 0 : aOrganizationUnit.Truncate();
491 0 : if (mCert) {
492 0 : UniquePORTString organizationUnit(CERT_GetOrgUnitName(&mCert->issuer));
493 0 : if (organizationUnit) {
494 0 : LossyUTF8ToUTF16(organizationUnit.get(), strlen(organizationUnit.get()),
495 0 : aOrganizationUnit);
496 : }
497 : }
498 0 : return NS_OK;
499 : }
500 :
501 : NS_IMETHODIMP
502 0 : nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit)
503 : {
504 0 : aOrganizationalUnit.Truncate();
505 0 : if (mCert) {
506 0 : UniquePORTString orgunit(CERT_GetOrgUnitName(&mCert->subject));
507 0 : if (orgunit) {
508 0 : LossyUTF8ToUTF16(orgunit.get(), strlen(orgunit.get()),
509 0 : aOrganizationalUnit);
510 : }
511 : }
512 0 : return NS_OK;
513 : }
514 :
515 : NS_IMETHODIMP
516 0 : nsNSSCertificate::GetSubjectName(nsAString& _subjectName)
517 : {
518 0 : _subjectName.Truncate();
519 0 : if (mCert->subjectName) {
520 0 : LossyUTF8ToUTF16(mCert->subjectName, strlen(mCert->subjectName),
521 0 : _subjectName);
522 : }
523 0 : return NS_OK;
524 : }
525 :
526 : // Reads dNSName and iPAddress entries encountered in the subject alternative
527 : // name extension of the certificate and stores them in mSubjectAltNames.
528 : void
529 0 : nsNSSCertificate::GetSubjectAltNames()
530 : {
531 6 : mSubjectAltNames.clear();
532 :
533 0 : ScopedAutoSECItem altNameExtension;
534 12 : SECStatus rv = CERT_FindCertExtension(mCert.get(),
535 : SEC_OID_X509_SUBJECT_ALT_NAME,
536 0 : &altNameExtension);
537 0 : if (rv != SECSuccess) {
538 : return;
539 : }
540 0 : UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
541 1 : if (!arena) {
542 : return;
543 : }
544 1 : CERTGeneralName* sanNameList(CERT_DecodeAltNameExtension(arena.get(),
545 1 : &altNameExtension));
546 0 : if (!sanNameList) {
547 : return;
548 : }
549 :
550 : CERTGeneralName* current = sanNameList;
551 : do {
552 2 : nsAutoString name;
553 0 : switch (current->type) {
554 : case certDNSName:
555 : {
556 1 : nsDependentCSubstring nameFromCert(BitwiseCast<char*, unsigned char*>(
557 : current->name.other.data),
558 0 : current->name.other.len);
559 : // dNSName fields are defined as type IA5String and thus should
560 : // be limited to ASCII characters.
561 0 : if (IsASCII(nameFromCert)) {
562 0 : name.Assign(NS_ConvertASCIItoUTF16(nameFromCert));
563 0 : mSubjectAltNames.push_back(name);
564 : }
565 : }
566 1 : break;
567 :
568 : case certIPAddress:
569 : {
570 : char buf[INET6_ADDRSTRLEN];
571 : PRNetAddr addr;
572 0 : if (current->name.other.len == 4) {
573 0 : addr.inet.family = PR_AF_INET;
574 0 : memcpy(&addr.inet.ip, current->name.other.data,
575 0 : current->name.other.len);
576 0 : PR_NetAddrToString(&addr, buf, sizeof(buf));
577 0 : name.AssignASCII(buf);
578 0 : } else if (current->name.other.len == 16) {
579 0 : addr.ipv6.family = PR_AF_INET6;
580 0 : memcpy(&addr.ipv6.ip, current->name.other.data,
581 0 : current->name.other.len);
582 0 : PR_NetAddrToString(&addr, buf, sizeof(buf));
583 0 : name.AssignASCII(buf);
584 : } else {
585 : /* invalid IP address */
586 : }
587 0 : if (!name.IsEmpty()) {
588 0 : mSubjectAltNames.push_back(name);
589 : }
590 : break;
591 : }
592 :
593 : default: // all other types of names are ignored
594 : break;
595 : }
596 1 : current = CERT_GetNextGeneralName(current);
597 1 : } while (current != sanNameList); // double linked
598 :
599 : return;
600 : }
601 :
602 : NS_IMETHODIMP
603 0 : nsNSSCertificate::GetSubjectAltNames(nsAString& _subjectAltNames)
604 : {
605 0 : _subjectAltNames.Truncate();
606 :
607 0 : for (auto altName : mSubjectAltNames) {
608 0 : if (!_subjectAltNames.IsEmpty()) {
609 0 : _subjectAltNames.Append(',');
610 : }
611 0 : _subjectAltNames.Append(altName);
612 : }
613 0 : return NS_OK;
614 : }
615 :
616 : NS_IMETHODIMP
617 0 : nsNSSCertificate::GetIssuerName(nsAString& _issuerName)
618 : {
619 0 : _issuerName.Truncate();
620 0 : if (mCert->issuerName) {
621 0 : LossyUTF8ToUTF16(mCert->issuerName, strlen(mCert->issuerName), _issuerName);
622 : }
623 0 : return NS_OK;
624 : }
625 :
626 : NS_IMETHODIMP
627 0 : nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber)
628 : {
629 0 : _serialNumber.Truncate();
630 0 : UniquePORTString tmpstr(CERT_Hexify(&mCert->serialNumber, 1));
631 0 : if (tmpstr) {
632 0 : _serialNumber = NS_ConvertASCIItoUTF16(tmpstr.get());
633 0 : return NS_OK;
634 : }
635 : return NS_ERROR_FAILURE;
636 : }
637 :
638 : nsresult
639 1 : nsNSSCertificate::GetCertificateHash(nsAString& aFingerprint, SECOidTag aHashAlg)
640 : {
641 1 : aFingerprint.Truncate();
642 1 : Digest digest;
643 2 : nsresult rv = digest.DigestBuf(aHashAlg, mCert->derCert.data,
644 0 : mCert->derCert.len);
645 1 : if (NS_FAILED(rv)) {
646 : return rv;
647 : }
648 :
649 : // CERT_Hexify's second argument is an int that is interpreted as a boolean
650 0 : UniquePORTString fpStr(CERT_Hexify(const_cast<SECItem*>(&digest.get()), 1));
651 1 : if (!fpStr) {
652 : return NS_ERROR_FAILURE;
653 : }
654 :
655 1 : aFingerprint.AssignASCII(fpStr.get());
656 0 : return NS_OK;
657 : }
658 :
659 : NS_IMETHODIMP
660 0 : nsNSSCertificate::GetSha256Fingerprint(nsAString& aSha256Fingerprint)
661 : {
662 0 : return GetCertificateHash(aSha256Fingerprint, SEC_OID_SHA256);
663 : }
664 :
665 : NS_IMETHODIMP
666 0 : nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint)
667 : {
668 0 : return GetCertificateHash(_sha1Fingerprint, SEC_OID_SHA1);
669 : }
670 :
671 : NS_IMETHODIMP
672 0 : nsNSSCertificate::GetTokenName(nsAString& aTokenName)
673 : {
674 0 : MOZ_ASSERT(mCert);
675 0 : if (!mCert) {
676 : return NS_ERROR_FAILURE;
677 : }
678 0 : UniquePK11SlotInfo internalSlot(PK11_GetInternalSlot());
679 0 : if (!internalSlot) {
680 : return NS_ERROR_FAILURE;
681 : }
682 : nsCOMPtr<nsIPK11Token> token(
683 0 : new nsPK11Token(mCert->slot ? mCert->slot : internalSlot.get()));
684 0 : nsAutoCString tmp;
685 0 : nsresult rv = token->GetTokenName(tmp);
686 0 : if (NS_FAILED(rv)) {
687 : return rv;
688 : }
689 0 : aTokenName.Assign(NS_ConvertUTF8toUTF16(tmp));
690 0 : return NS_OK;
691 : }
692 :
693 : NS_IMETHODIMP
694 0 : nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest)
695 : {
696 0 : aSha256SPKIDigest.Truncate();
697 0 : Digest digest;
698 0 : nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data,
699 0 : mCert->derPublicKey.len);
700 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
701 : return rv;
702 : }
703 0 : rv = Base64Encode(nsDependentCSubstring(
704 0 : BitwiseCast<char*, unsigned char*>(digest.get().data),
705 0 : digest.get().len),
706 0 : aSha256SPKIDigest);
707 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
708 : return rv;
709 : }
710 0 : return NS_OK;
711 : }
712 :
713 : NS_IMETHODIMP
714 0 : nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray)
715 : {
716 0 : if (mCert) {
717 0 : *aArray = (uint8_t*)moz_xmalloc(mCert->derCert.len);
718 0 : if (*aArray) {
719 0 : memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
720 0 : *aLength = mCert->derCert.len;
721 0 : return NS_OK;
722 : }
723 : }
724 0 : *aLength = 0;
725 0 : return NS_ERROR_FAILURE;
726 : }
727 :
728 : CERTCertificate*
729 0 : nsNSSCertificate::GetCert()
730 : {
731 0 : return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr;
732 : }
733 :
734 : NS_IMETHODIMP
735 0 : nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity)
736 : {
737 0 : NS_ENSURE_ARG(aValidity);
738 :
739 0 : if (!mCert) {
740 : return NS_ERROR_FAILURE;
741 : }
742 :
743 0 : nsCOMPtr<nsIX509CertValidity> validity = new nsX509CertValidity(mCert);
744 0 : validity.forget(aValidity);
745 : return NS_OK;
746 : }
747 :
748 : NS_IMETHODIMP
749 0 : nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure)
750 : {
751 0 : NS_ENSURE_ARG_POINTER(aASN1Structure);
752 0 : if (!NS_IsMainThread()) {
753 : return NS_ERROR_NOT_SAME_THREAD;
754 : }
755 0 : return CreateASN1Struct(aASN1Structure);
756 : }
757 :
758 : NS_IMETHODIMP
759 0 : nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
760 : {
761 0 : NS_ENSURE_ARG(other);
762 0 : NS_ENSURE_ARG(result);
763 :
764 0 : UniqueCERTCertificate cert(other->GetCert());
765 0 : *result = (mCert.get() == cert.get());
766 : return NS_OK;
767 : }
768 :
769 : namespace mozilla {
770 :
771 : // TODO(bug 1036065): It seems like we only construct CERTCertLists for the
772 : // purpose of constructing nsNSSCertLists, so maybe we should change this
773 : // function to output an nsNSSCertList instead.
774 : SECStatus
775 0 : ConstructCERTCertListFromReversedDERArray(
776 : const mozilla::pkix::DERArray& certArray,
777 : /*out*/ UniqueCERTCertList& certList)
778 : {
779 2 : certList = UniqueCERTCertList(CERT_NewCertList());
780 1 : if (!certList) {
781 : return SECFailure;
782 : }
783 :
784 1 : CERTCertDBHandle* certDB(CERT_GetDefaultCertDB()); // non-owning
785 :
786 1 : size_t numCerts = certArray.GetLength();
787 0 : for (size_t i = 0; i < numCerts; ++i) {
788 0 : SECItem certDER(UnsafeMapInputToSECItem(*certArray.GetDER(i)));
789 : UniqueCERTCertificate cert(CERT_NewTempCertificate(certDB, &certDER,
790 0 : nullptr, false, true));
791 0 : if (!cert) {
792 0 : return SECFailure;
793 : }
794 : // certArray is ordered with the root first, but we want the resulting
795 : // certList to have the root last.
796 6 : if (CERT_AddCertToListHead(certList.get(), cert.get()) != SECSuccess) {
797 : return SECFailure;
798 : }
799 3 : Unused << cert.release(); // cert is now owned by certList.
800 : }
801 :
802 : return SECSuccess;
803 : }
804 :
805 : } // namespace mozilla
806 :
807 : NS_IMPL_CLASSINFO(nsNSSCertList,
808 : nullptr,
809 : // inferred from nsIX509Cert
810 : nsIClassInfo::THREADSAFE,
811 : NS_X509CERTLIST_CID)
812 :
813 0 : NS_IMPL_ISUPPORTS_CI(nsNSSCertList,
814 : nsIX509CertList,
815 : nsISerializable)
816 :
817 0 : nsNSSCertList::nsNSSCertList(UniqueCERTCertList certList)
818 : {
819 1 : if (certList) {
820 1 : mCertList = std::move(certList);
821 : } else {
822 0 : mCertList = UniqueCERTCertList(CERT_NewCertList());
823 : }
824 1 : }
825 :
826 0 : nsNSSCertList::nsNSSCertList()
827 : {
828 0 : mCertList = UniqueCERTCertList(CERT_NewCertList());
829 0 : }
830 :
831 : nsNSSCertList*
832 0 : nsNSSCertList::GetCertList()
833 : {
834 0 : return this;
835 : }
836 :
837 : NS_IMETHODIMP
838 0 : nsNSSCertList::AddCert(nsIX509Cert* aCert)
839 : {
840 : // We need an owning handle when calling nsIX509Cert::GetCert().
841 0 : UniqueCERTCertificate cert(aCert->GetCert());
842 0 : if (!cert) {
843 0 : NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
844 0 : return NS_ERROR_FAILURE;
845 : }
846 :
847 0 : if (!mCertList) {
848 0 : NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList.");
849 0 : return NS_ERROR_FAILURE;
850 : }
851 0 : if (CERT_AddCertToListTail(mCertList.get(), cert.get()) != SECSuccess) {
852 : return NS_ERROR_OUT_OF_MEMORY;
853 : }
854 0 : Unused << cert.release(); // Ownership transferred to the cert list.
855 0 : return NS_OK;
856 : }
857 :
858 : UniqueCERTCertList
859 3 : nsNSSCertList::DupCertList(const UniqueCERTCertList& certList)
860 : {
861 3 : if (!certList) {
862 0 : return nullptr;
863 : }
864 :
865 9 : UniqueCERTCertList newList(CERT_NewCertList());
866 3 : if (!newList) {
867 0 : return nullptr;
868 : }
869 :
870 1 : for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
871 11 : !CERT_LIST_END(node, certList);
872 8 : node = CERT_LIST_NEXT(node)) {
873 0 : UniqueCERTCertificate cert(CERT_DupCertificate(node->cert));
874 1 : if (!cert) {
875 0 : return nullptr;
876 : }
877 :
878 16 : if (CERT_AddCertToListTail(newList.get(), cert.get()) != SECSuccess) {
879 0 : return nullptr;
880 : }
881 :
882 8 : Unused << cert.release(); // Ownership transferred to the cert list.
883 : }
884 : return newList;
885 : }
886 :
887 : CERTCertList*
888 0 : nsNSSCertList::GetRawCertList()
889 : {
890 0 : return mCertList.get();
891 : }
892 :
893 : NS_IMETHODIMP
894 0 : nsNSSCertList::AsPKCS7Blob(/*out*/ nsACString& result)
895 : {
896 0 : MOZ_ASSERT(mCertList);
897 0 : if (!mCertList) {
898 : return NS_ERROR_FAILURE;
899 : }
900 :
901 0 : UniqueNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr));
902 0 : if (!cmsg) {
903 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
904 : ("nsNSSCertList::AsPKCS7Blob - can't create CMS message"));
905 : return NS_ERROR_OUT_OF_MEMORY;
906 : }
907 :
908 0 : UniqueNSSCMSSignedData sigd(nullptr);
909 0 : nsresult rv = ForEachCertificateInChain(
910 : [&cmsg, &sigd] (nsCOMPtr<nsIX509Cert> aCert, bool /*unused*/,
911 0 : /*out*/ bool& /*unused*/) {
912 : // We need an owning handle when calling nsIX509Cert::GetCert().
913 0 : UniqueCERTCertificate nssCert(aCert->GetCert());
914 0 : if (!sigd) {
915 0 : sigd.reset(NSS_CMSSignedData_CreateCertsOnly(cmsg.get(), nssCert.get(),
916 0 : false));
917 0 : if (!sigd) {
918 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
919 : ("nsNSSCertList::AsPKCS7Blob - can't create SignedData"));
920 : return NS_ERROR_FAILURE;
921 : }
922 0 : } else if (NSS_CMSSignedData_AddCertificate(sigd.get(), nssCert.get())
923 : != SECSuccess) {
924 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
925 : ("nsNSSCertList::AsPKCS7Blob - can't add cert"));
926 : return NS_ERROR_FAILURE;
927 : }
928 : return NS_OK;
929 0 : });
930 0 : if (NS_FAILED(rv)) {
931 : return rv;
932 : }
933 :
934 0 : NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg.get());
935 0 : if (NSS_CMSContentInfo_SetContent_SignedData(cmsg.get(), cinfo, sigd.get())
936 : != SECSuccess) {
937 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
938 : ("nsNSSCertList::AsPKCS7Blob - can't attach SignedData"));
939 : return NS_ERROR_FAILURE;
940 : }
941 : // cmsg owns sigd now.
942 0 : Unused << sigd.release();
943 :
944 0 : UniquePLArenaPool arena(PORT_NewArena(1024));
945 0 : if (!arena) {
946 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
947 : ("nsNSSCertList::AsPKCS7Blob - out of memory"));
948 : return NS_ERROR_OUT_OF_MEMORY;
949 : }
950 :
951 0 : SECItem certP7 = { siBuffer, nullptr, 0 };
952 0 : NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg.get(), nullptr, nullptr,
953 : &certP7, arena.get(), nullptr,
954 : nullptr, nullptr, nullptr,
955 0 : nullptr, nullptr);
956 0 : if (!ecx) {
957 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
958 : ("nsNSSCertList::AsPKCS7Blob - can't create encoder"));
959 : return NS_ERROR_FAILURE;
960 : }
961 :
962 0 : if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
963 0 : MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
964 : ("nsNSSCertList::AsPKCS7Blob - failed to add encoded data"));
965 : return NS_ERROR_FAILURE;
966 : }
967 :
968 0 : result.Assign(nsDependentCSubstring(reinterpret_cast<const char*>(certP7.data),
969 0 : certP7.len));
970 0 : return NS_OK;
971 : }
972 :
973 : NS_IMETHODIMP
974 0 : nsNSSCertList::Write(nsIObjectOutputStream* aStream)
975 : {
976 0 : NS_ENSURE_STATE(mCertList);
977 0 : nsresult rv = NS_OK;
978 :
979 : // First, enumerate the certs to get the length of the list
980 0 : uint32_t certListLen = 0;
981 0 : CERTCertListNode* node = nullptr;
982 0 : for (node = CERT_LIST_HEAD(mCertList);
983 0 : !CERT_LIST_END(node, mCertList);
984 0 : node = CERT_LIST_NEXT(node), ++certListLen) {
985 : }
986 :
987 : // Write the length of the list
988 0 : rv = aStream->Write32(certListLen);
989 :
990 : // Repeat the loop, and serialize each certificate
991 0 : node = nullptr;
992 0 : for (node = CERT_LIST_HEAD(mCertList);
993 0 : !CERT_LIST_END(node, mCertList);
994 0 : node = CERT_LIST_NEXT(node))
995 : {
996 0 : nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
997 0 : if (!cert) {
998 : rv = NS_ERROR_OUT_OF_MEMORY;
999 0 : break;
1000 : }
1001 :
1002 0 : nsCOMPtr<nsISerializable> serializableCert = do_QueryInterface(cert);
1003 0 : rv = aStream->WriteCompoundObject(serializableCert, NS_GET_IID(nsIX509Cert), true);
1004 0 : if (NS_FAILED(rv)) {
1005 : break;
1006 : }
1007 : }
1008 :
1009 : return rv;
1010 : }
1011 :
1012 : NS_IMETHODIMP
1013 0 : nsNSSCertList::Read(nsIObjectInputStream* aStream)
1014 : {
1015 0 : NS_ENSURE_STATE(mCertList);
1016 0 : nsresult rv = NS_OK;
1017 :
1018 : uint32_t certListLen;
1019 0 : rv = aStream->Read32(&certListLen);
1020 0 : if (NS_FAILED(rv)) {
1021 : return rv;
1022 : }
1023 :
1024 0 : for(uint32_t i = 0; i < certListLen; ++i) {
1025 0 : nsCOMPtr<nsISupports> certSupports;
1026 0 : rv = aStream->ReadObject(true, getter_AddRefs(certSupports));
1027 0 : if (NS_FAILED(rv)) {
1028 : break;
1029 : }
1030 :
1031 0 : nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports);
1032 0 : rv = AddCert(cert);
1033 0 : if (NS_FAILED(rv)) {
1034 : break;
1035 : }
1036 : }
1037 :
1038 : return rv;
1039 : }
1040 :
1041 : NS_IMETHODIMP
1042 0 : nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
1043 : {
1044 2 : if (!mCertList) {
1045 : return NS_ERROR_FAILURE;
1046 : }
1047 :
1048 : nsCOMPtr<nsISimpleEnumerator> enumerator =
1049 2 : new nsNSSCertListEnumerator(mCertList);
1050 :
1051 0 : enumerator.forget(_retval);
1052 : return NS_OK;
1053 : }
1054 :
1055 : NS_IMETHODIMP
1056 0 : nsNSSCertList::Equals(nsIX509CertList* other, bool* result)
1057 : {
1058 0 : NS_ENSURE_ARG(result);
1059 0 : *result = true;
1060 :
1061 : nsresult rv;
1062 :
1063 0 : nsCOMPtr<nsISimpleEnumerator> selfEnumerator;
1064 0 : rv = GetEnumerator(getter_AddRefs(selfEnumerator));
1065 0 : if (NS_FAILED(rv)) {
1066 : return rv;
1067 : }
1068 :
1069 0 : nsCOMPtr<nsISimpleEnumerator> otherEnumerator;
1070 0 : rv = other->GetEnumerator(getter_AddRefs(otherEnumerator));
1071 0 : if (NS_FAILED(rv)) {
1072 : return rv;
1073 : }
1074 :
1075 0 : nsCOMPtr<nsISupports> selfSupports;
1076 0 : nsCOMPtr<nsISupports> otherSupports;
1077 0 : while (NS_SUCCEEDED(selfEnumerator->GetNext(getter_AddRefs(selfSupports)))) {
1078 0 : if (NS_SUCCEEDED(otherEnumerator->GetNext(getter_AddRefs(otherSupports)))) {
1079 0 : nsCOMPtr<nsIX509Cert> selfCert = do_QueryInterface(selfSupports);
1080 0 : nsCOMPtr<nsIX509Cert> otherCert = do_QueryInterface(otherSupports);
1081 :
1082 0 : bool certsEqual = false;
1083 0 : rv = selfCert->Equals(otherCert, &certsEqual);
1084 0 : if (NS_FAILED(rv)) {
1085 0 : return rv;
1086 : }
1087 0 : if (!certsEqual) {
1088 0 : *result = false;
1089 0 : break;
1090 : }
1091 : } else {
1092 : // other is shorter than self
1093 0 : *result = false;
1094 0 : break;
1095 : }
1096 : }
1097 :
1098 : // Make sure self is the same length as other
1099 0 : bool otherHasMore = false;
1100 0 : rv = otherEnumerator->HasMoreElements(&otherHasMore);
1101 0 : if (NS_FAILED(rv)) {
1102 : return rv;
1103 : }
1104 0 : if (otherHasMore) {
1105 0 : *result = false;
1106 : }
1107 :
1108 : return NS_OK;
1109 : }
1110 :
1111 : nsresult
1112 1 : nsNSSCertList::ForEachCertificateInChain(ForEachCertOperation& aOperation)
1113 : {
1114 1 : nsCOMPtr<nsISimpleEnumerator> chainElt;
1115 1 : nsresult rv = GetEnumerator(getter_AddRefs(chainElt));
1116 1 : if (NS_FAILED(rv)) {
1117 : return rv;
1118 : }
1119 :
1120 : // Each chain may have multiple certificates.
1121 1 : bool hasMore = false;
1122 1 : rv = chainElt->HasMoreElements(&hasMore);
1123 1 : if (NS_FAILED(rv)) {
1124 : return rv;
1125 : }
1126 :
1127 0 : if (!hasMore) {
1128 : return NS_OK; // Empty lists are fine
1129 : }
1130 :
1131 1 : do {
1132 5 : nsCOMPtr<nsISupports> certSupports;
1133 6 : rv = chainElt->GetNext(getter_AddRefs(certSupports));
1134 3 : if (NS_FAILED(rv)) {
1135 1 : return rv;
1136 : }
1137 :
1138 0 : nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports, &rv);
1139 3 : if (NS_FAILED(rv)) {
1140 0 : return rv;
1141 : }
1142 :
1143 3 : rv = chainElt->HasMoreElements(&hasMore);
1144 3 : if (NS_FAILED(rv)) {
1145 : return rv;
1146 : }
1147 :
1148 0 : bool continueLoop = true;
1149 0 : rv = aOperation(cert, hasMore, continueLoop);
1150 3 : if (NS_FAILED(rv) || !continueLoop) {
1151 : return rv;
1152 : }
1153 : } while (hasMore);
1154 :
1155 : return NS_OK;
1156 : }
1157 :
1158 : nsresult
1159 0 : nsNSSCertList::SegmentCertificateChain(/* out */ nsCOMPtr<nsIX509Cert>& aRoot,
1160 : /* out */ nsCOMPtr<nsIX509CertList>& aIntermediates,
1161 : /* out */ nsCOMPtr<nsIX509Cert>& aEndEntity)
1162 : {
1163 0 : if (aRoot || aIntermediates || aEndEntity) {
1164 : // All passed-in nsCOMPtrs should be empty for the state machine to work
1165 : return NS_ERROR_UNEXPECTED;
1166 : }
1167 :
1168 0 : aIntermediates = new nsNSSCertList();
1169 :
1170 0 : nsresult rv = ForEachCertificateInChain(
1171 : [&aRoot, &aIntermediates, &aEndEntity] (nsCOMPtr<nsIX509Cert> aCert,
1172 0 : bool hasMore, bool& aContinue) {
1173 0 : if (!aEndEntity) {
1174 : // This is the end entity
1175 0 : aEndEntity = aCert;
1176 0 : } else if (!hasMore) {
1177 : // This is the root
1178 0 : aRoot = aCert;
1179 : } else {
1180 : // One of (potentially many) intermediates
1181 0 : if (NS_FAILED(aIntermediates->AddCert(aCert))) {
1182 : return NS_ERROR_OUT_OF_MEMORY;
1183 : }
1184 : }
1185 :
1186 : return NS_OK;
1187 0 : });
1188 :
1189 0 : if (NS_FAILED(rv)) {
1190 : return rv;
1191 : }
1192 :
1193 0 : if (!aRoot || !aEndEntity) {
1194 : // No self-signed (or empty) chains allowed
1195 : return NS_ERROR_INVALID_ARG;
1196 : }
1197 :
1198 0 : return NS_OK;
1199 : }
1200 :
1201 : nsresult
1202 0 : nsNSSCertList::GetRootCertificate(/* out */ nsCOMPtr<nsIX509Cert>& aRoot)
1203 : {
1204 0 : if (aRoot) {
1205 : return NS_ERROR_UNEXPECTED;
1206 : }
1207 0 : CERTCertListNode* rootNode = CERT_LIST_TAIL(mCertList);
1208 2 : if (!rootNode) {
1209 : return NS_ERROR_UNEXPECTED;
1210 : }
1211 4 : if (CERT_LIST_END(rootNode, mCertList)) {
1212 : // Empty list, leave aRoot empty
1213 : return NS_OK;
1214 : }
1215 : // Duplicates the certificate
1216 2 : aRoot = nsNSSCertificate::Create(rootNode->cert);
1217 2 : if (!aRoot) {
1218 : return NS_ERROR_OUT_OF_MEMORY;
1219 : }
1220 2 : return NS_OK;
1221 : }
1222 :
1223 14 : NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
1224 :
1225 1 : nsNSSCertListEnumerator::nsNSSCertListEnumerator(
1226 4 : const UniqueCERTCertList& certList)
1227 : {
1228 0 : MOZ_ASSERT(certList);
1229 1 : mCertList = nsNSSCertList::DupCertList(certList);
1230 0 : }
1231 :
1232 : NS_IMETHODIMP
1233 0 : nsNSSCertListEnumerator::HasMoreElements(bool* _retval)
1234 : {
1235 8 : NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
1236 :
1237 0 : *_retval = !CERT_LIST_EMPTY(mCertList);
1238 4 : return NS_OK;
1239 : }
1240 :
1241 : NS_IMETHODIMP
1242 0 : nsNSSCertListEnumerator::GetNext(nsISupports** _retval)
1243 : {
1244 6 : NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
1245 :
1246 0 : CERTCertListNode* node = CERT_LIST_HEAD(mCertList);
1247 6 : if (CERT_LIST_END(node, mCertList)) {
1248 : return NS_ERROR_FAILURE;
1249 : }
1250 :
1251 0 : nsCOMPtr<nsIX509Cert> nssCert = nsNSSCertificate::Create(node->cert);
1252 0 : if (!nssCert) {
1253 : return NS_ERROR_OUT_OF_MEMORY;
1254 : }
1255 :
1256 0 : nssCert.forget(_retval);
1257 :
1258 3 : CERT_RemoveCertListNode(node);
1259 0 : return NS_OK;
1260 : }
1261 :
1262 : NS_IMETHODIMP
1263 0 : nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
1264 : {
1265 0 : NS_ENSURE_STATE(mCert);
1266 : // This field used to be the cached EV status, but it is no longer necessary.
1267 0 : nsresult rv = aStream->Write32(0);
1268 0 : if (NS_FAILED(rv)) {
1269 : return rv;
1270 : }
1271 0 : rv = aStream->Write32(mCert->derCert.len);
1272 0 : if (NS_FAILED(rv)) {
1273 : return rv;
1274 : }
1275 0 : return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len);
1276 : }
1277 :
1278 : NS_IMETHODIMP
1279 0 : nsNSSCertificate::Read(nsIObjectInputStream* aStream)
1280 : {
1281 0 : NS_ENSURE_STATE(!mCert);
1282 :
1283 : // This field is no longer used.
1284 : uint32_t unusedCachedEVStatus;
1285 0 : nsresult rv = aStream->Read32(&unusedCachedEVStatus);
1286 0 : if (NS_FAILED(rv)) {
1287 : return rv;
1288 : }
1289 :
1290 : uint32_t len;
1291 0 : rv = aStream->Read32(&len);
1292 0 : if (NS_FAILED(rv)) {
1293 : return rv;
1294 : }
1295 :
1296 0 : nsCString str;
1297 0 : rv = aStream->ReadBytes(len, getter_Copies(str));
1298 0 : if (NS_FAILED(rv)) {
1299 : return rv;
1300 : }
1301 :
1302 0 : if (!InitFromDER(const_cast<char*>(str.get()), len)) {
1303 : return NS_ERROR_UNEXPECTED;
1304 : }
1305 :
1306 0 : return NS_OK;
1307 : }
1308 :
1309 : NS_IMETHODIMP
1310 0 : nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array)
1311 : {
1312 0 : *count = 0;
1313 0 : *array = nullptr;
1314 0 : return NS_OK;
1315 : }
1316 :
1317 : NS_IMETHODIMP
1318 0 : nsNSSCertificate::GetScriptableHelper(nsIXPCScriptable** _retval)
1319 : {
1320 0 : *_retval = nullptr;
1321 0 : return NS_OK;
1322 : }
1323 :
1324 : NS_IMETHODIMP
1325 0 : nsNSSCertificate::GetContractID(nsACString& aContractID)
1326 : {
1327 0 : aContractID.SetIsVoid(true);
1328 0 : return NS_OK;
1329 : }
1330 :
1331 : NS_IMETHODIMP
1332 0 : nsNSSCertificate::GetClassDescription(nsACString& aClassDescription)
1333 : {
1334 0 : aClassDescription.SetIsVoid(true);
1335 0 : return NS_OK;
1336 : }
1337 :
1338 : NS_IMETHODIMP
1339 0 : nsNSSCertificate::GetClassID(nsCID** aClassID)
1340 : {
1341 0 : *aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
1342 0 : if (!*aClassID)
1343 : return NS_ERROR_OUT_OF_MEMORY;
1344 0 : return GetClassIDNoAlloc(*aClassID);
1345 : }
1346 :
1347 : NS_IMETHODIMP
1348 0 : nsNSSCertificate::GetFlags(uint32_t* aFlags)
1349 : {
1350 0 : *aFlags = nsIClassInfo::THREADSAFE;
1351 0 : return NS_OK;
1352 : }
1353 :
1354 : NS_IMETHODIMP
1355 0 : nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
1356 : {
1357 : static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
1358 :
1359 0 : *aClassIDNoAlloc = kNSSCertificateCID;
1360 0 : return NS_OK;
1361 : }
|