|
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 } |