security/manager/ssl/src/nsNSSCertificate.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

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

mercurial