michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsNSSCertificate.h" michael@0: michael@0: #include "prmem.h" michael@0: #include "prerror.h" michael@0: #include "prprf.h" michael@0: #include "CertVerifier.h" michael@0: #include "ExtendedValidation.h" michael@0: #include "pkix/pkixtypes.h" michael@0: #include "nsNSSComponent.h" // for PIPNSS string bundle calls. michael@0: #include "nsNSSCleaner.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIMutableArray.h" michael@0: #include "nsNSSCertValidity.h" michael@0: #include "nsPKCS12Blob.h" michael@0: #include "nsPK11TokenDB.h" michael@0: #include "nsIX509Cert.h" michael@0: #include "nsIX509Cert3.h" michael@0: #include "nsISMimeCert.h" michael@0: #include "nsNSSASN1Object.h" michael@0: #include "nsString.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsIURI.h" michael@0: #include "nsCRT.h" michael@0: #include "nsUsageArrayHelper.h" michael@0: #include "nsICertificateDialogs.h" michael@0: #include "nsNSSCertHelper.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: #include "nsUnicharUtils.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsCertVerificationThread.h" michael@0: #include "nsIObjectOutputStream.h" michael@0: #include "nsIObjectInputStream.h" michael@0: #include "nsIProgrammingLanguage.h" michael@0: #include "nsXULAppAPI.h" michael@0: #include "ScopedNSSTypes.h" michael@0: #include "nsProxyRelease.h" michael@0: #include "mozilla/Base64.h" michael@0: michael@0: #include "nspr.h" michael@0: #include "certdb.h" michael@0: #include "secerr.h" michael@0: #include "nssb64.h" michael@0: #include "secasn1.h" michael@0: #include "secder.h" michael@0: #include "ssl.h" michael@0: #include "ocsp.h" michael@0: #include "plbase64.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::psm; michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gPIPNSSLog; michael@0: #endif michael@0: michael@0: NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false) michael@0: michael@0: // This is being stored in an uint32_t that can otherwise michael@0: // only take values from nsIX509Cert's list of cert types. michael@0: // As nsIX509Cert is frozen, we choose a value not contained michael@0: // in the list to mean not yet initialized. michael@0: #define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30) michael@0: michael@0: NS_IMPL_ISUPPORTS(nsNSSCertificate, michael@0: nsIX509Cert, michael@0: nsIX509Cert2, michael@0: nsIX509Cert3, michael@0: nsIIdentityInfo, michael@0: nsISMimeCert, michael@0: nsISerializable, michael@0: nsIClassInfo) michael@0: michael@0: /*static*/ nsNSSCertificate* michael@0: nsNSSCertificate::Create(CERTCertificate* cert, SECOidTag* evOidPolicy) michael@0: { michael@0: if (GeckoProcessType_Default != XRE_GetProcessType()) { michael@0: NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!"); michael@0: return nullptr; michael@0: } michael@0: if (cert) michael@0: return new nsNSSCertificate(cert, evOidPolicy); michael@0: else michael@0: return new nsNSSCertificate(); michael@0: } michael@0: michael@0: nsNSSCertificate* michael@0: nsNSSCertificate::ConstructFromDER(char* certDER, int derLen) michael@0: { michael@0: // On non-chrome process prevent instantiation michael@0: if (GeckoProcessType_Default != XRE_GetProcessType()) michael@0: return nullptr; michael@0: michael@0: nsNSSCertificate* newObject = nsNSSCertificate::Create(); michael@0: if (newObject && !newObject->InitFromDER(certDER, derLen)) { michael@0: delete newObject; michael@0: newObject = nullptr; michael@0: } michael@0: michael@0: return newObject; michael@0: } michael@0: michael@0: bool michael@0: nsNSSCertificate::InitFromDER(char* certDER, int derLen) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return false; michael@0: michael@0: if (!certDER || !derLen) michael@0: return false; michael@0: michael@0: CERTCertificate* aCert = CERT_DecodeCertFromPackage(certDER, derLen); michael@0: michael@0: if (!aCert) michael@0: return false; michael@0: michael@0: if (!aCert->dbhandle) michael@0: { michael@0: aCert->dbhandle = CERT_GetDefaultCertDB(); michael@0: } michael@0: michael@0: mCert = aCert; michael@0: return true; michael@0: } michael@0: michael@0: nsNSSCertificate::nsNSSCertificate(CERTCertificate* cert, michael@0: SECOidTag* evOidPolicy) michael@0: : mCert(nullptr) michael@0: , mPermDelete(false) michael@0: , mCertType(CERT_TYPE_NOT_YET_INITIALIZED) michael@0: , mCachedEVStatus(ev_status_unknown) michael@0: { michael@0: #if defined(DEBUG) michael@0: if (GeckoProcessType_Default != XRE_GetProcessType()) michael@0: NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!"); michael@0: #endif michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return; michael@0: michael@0: if (cert) { michael@0: mCert = CERT_DupCertificate(cert); michael@0: if (evOidPolicy) { michael@0: if (*evOidPolicy == SEC_OID_UNKNOWN) { michael@0: mCachedEVStatus = ev_status_invalid; michael@0: } michael@0: else { michael@0: mCachedEVStatus = ev_status_valid; michael@0: } michael@0: mCachedEVOidTag = *evOidPolicy; michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsNSSCertificate::nsNSSCertificate() : michael@0: mCert(nullptr), michael@0: mPermDelete(false), michael@0: mCertType(CERT_TYPE_NOT_YET_INITIALIZED), michael@0: mCachedEVStatus(ev_status_unknown) michael@0: { michael@0: if (GeckoProcessType_Default != XRE_GetProcessType()) michael@0: NS_ERROR("Trying to initialize nsNSSCertificate in a non-chrome process!"); michael@0: } michael@0: michael@0: nsNSSCertificate::~nsNSSCertificate() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: destructorSafeDestroyNSSReference(); michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: void nsNSSCertificate::virtualDestroyNSSReference() michael@0: { michael@0: destructorSafeDestroyNSSReference(); michael@0: } michael@0: michael@0: void nsNSSCertificate::destructorSafeDestroyNSSReference() michael@0: { michael@0: if (mPermDelete) { michael@0: if (mCertType == nsNSSCertificate::USER_CERT) { michael@0: nsCOMPtr cxt = new PipUIContext(); michael@0: PK11_DeleteTokenCertAndKey(mCert.get(), cxt); michael@0: } else if (!PK11_IsReadOnly(mCert->slot)) { michael@0: // If the list of built-ins does contain a non-removable michael@0: // copy of this certificate, our call will not remove michael@0: // the certificate permanently, but rather remove all trust. michael@0: SEC_DeletePermCertificate(mCert.get()); michael@0: } michael@0: } michael@0: michael@0: mCert = nullptr; michael@0: } michael@0: michael@0: nsresult michael@0: nsNSSCertificate::GetCertType(uint32_t* aCertType) michael@0: { michael@0: if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) { michael@0: // only determine cert type once and cache it michael@0: mCertType = getCertType(mCert.get()); michael@0: } michael@0: *aCertType = mCertType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetIsSelfSigned(bool* aIsSelfSigned) michael@0: { michael@0: NS_ENSURE_ARG(aIsSelfSigned); michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: *aIsSelfSigned = mCert->isRoot; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNSSCertificate::MarkForPermDeletion() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: // make sure user is logged in to the token michael@0: nsCOMPtr ctx = new PipUIContext(); michael@0: michael@0: if (PK11_NeedLogin(mCert->slot) michael@0: && !PK11_NeedUserInit(mCert->slot) michael@0: && !PK11_IsInternal(mCert->slot)) michael@0: { michael@0: if (SECSuccess != PK11_Authenticate(mCert->slot, true, ctx)) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: mPermDelete = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: GetKeyUsagesString(CERTCertificate* cert, nsINSSComponent* nssComponent, michael@0: nsString& text) michael@0: { michael@0: text.Truncate(); michael@0: michael@0: SECItem keyUsageItem; michael@0: keyUsageItem.data = nullptr; michael@0: michael@0: SECStatus srv; michael@0: michael@0: // There is no extension, v1 or v2 certificate michael@0: if (!cert->extensions) michael@0: return NS_OK; michael@0: michael@0: michael@0: srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem); michael@0: if (srv == SECFailure) { michael@0: if (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND) michael@0: return NS_OK; michael@0: else michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: unsigned char keyUsage = keyUsageItem.data[0]; michael@0: nsAutoString local; michael@0: nsresult rv; michael@0: const char16_t comma = ','; michael@0: michael@0: if (keyUsage & KU_DIGITAL_SIGNATURE) { michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpKUSign", local); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (!text.IsEmpty()) text.Append(comma); michael@0: text.Append(local.get()); michael@0: } michael@0: } michael@0: if (keyUsage & KU_NON_REPUDIATION) { michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpKUNonRep", local); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (!text.IsEmpty()) text.Append(comma); michael@0: text.Append(local.get()); michael@0: } michael@0: } michael@0: if (keyUsage & KU_KEY_ENCIPHERMENT) { michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpKUEnc", local); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (!text.IsEmpty()) text.Append(comma); michael@0: text.Append(local.get()); michael@0: } michael@0: } michael@0: if (keyUsage & KU_DATA_ENCIPHERMENT) { michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpKUDEnc", local); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (!text.IsEmpty()) text.Append(comma); michael@0: text.Append(local.get()); michael@0: } michael@0: } michael@0: if (keyUsage & KU_KEY_AGREEMENT) { michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpKUKA", local); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (!text.IsEmpty()) text.Append(comma); michael@0: text.Append(local.get()); michael@0: } michael@0: } michael@0: if (keyUsage & KU_KEY_CERT_SIGN) { michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCertSign", local); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (!text.IsEmpty()) text.Append(comma); michael@0: text.Append(local.get()); michael@0: } michael@0: } michael@0: if (keyUsage & KU_CRL_SIGN) { michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCRLSign", local); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (!text.IsEmpty()) text.Append(comma); michael@0: text.Append(local.get()); michael@0: } michael@0: } michael@0: michael@0: PORT_Free (keyUsageItem.data); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNSSCertificate::FormatUIStrings(const nsAutoString& nickname, michael@0: nsAutoString& nickWithSerial, michael@0: nsAutoString& details) michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: if (!NS_IsMainThread()) { michael@0: NS_ERROR("nsNSSCertificate::FormatUIStrings called off the main thread"); michael@0: return NS_ERROR_NOT_SAME_THREAD; michael@0: } michael@0: michael@0: nsresult rv = NS_OK; michael@0: michael@0: nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); michael@0: michael@0: if (NS_FAILED(rv) || !nssComponent) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsAutoString info; michael@0: nsAutoString temp1; michael@0: michael@0: nickWithSerial.Append(nickname); michael@0: michael@0: if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedFor", info))) { michael@0: details.Append(info); michael@0: details.Append(char16_t(' ')); michael@0: if (NS_SUCCEEDED(GetSubjectName(temp1)) && !temp1.IsEmpty()) { michael@0: details.Append(temp1); michael@0: } michael@0: details.Append(char16_t('\n')); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(GetSerialNumber(temp1)) && !temp1.IsEmpty()) { michael@0: details.AppendLiteral(" "); michael@0: if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", info))) { michael@0: details.Append(info); michael@0: details.AppendLiteral(": "); michael@0: } michael@0: details.Append(temp1); michael@0: michael@0: nickWithSerial.AppendLiteral(" ["); michael@0: nickWithSerial.Append(temp1); michael@0: nickWithSerial.Append(char16_t(']')); michael@0: michael@0: details.Append(char16_t('\n')); michael@0: } michael@0: michael@0: nsCOMPtr validity; michael@0: rv = GetValidity(getter_AddRefs(validity)); michael@0: if (NS_SUCCEEDED(rv) && validity) { michael@0: details.AppendLiteral(" "); michael@0: if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoValid", info))) { michael@0: details.Append(info); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(validity->GetNotBeforeLocalTime(temp1)) && !temp1.IsEmpty()) { michael@0: details.Append(char16_t(' ')); michael@0: if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoFrom", info))) { michael@0: details.Append(info); michael@0: details.Append(char16_t(' ')); michael@0: } michael@0: details.Append(temp1); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(validity->GetNotAfterLocalTime(temp1)) && !temp1.IsEmpty()) { michael@0: details.Append(char16_t(' ')); michael@0: if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoTo", info))) { michael@0: details.Append(info); michael@0: details.Append(char16_t(' ')); michael@0: } michael@0: details.Append(temp1); michael@0: } michael@0: michael@0: details.Append(char16_t('\n')); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(GetKeyUsagesString(mCert.get(), nssComponent, temp1)) && michael@0: !temp1.IsEmpty()) { michael@0: details.AppendLiteral(" "); michael@0: if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpKeyUsage", info))) { michael@0: details.Append(info); michael@0: details.AppendLiteral(": "); michael@0: } michael@0: details.Append(temp1); michael@0: details.Append(char16_t('\n')); michael@0: } michael@0: michael@0: nsAutoString firstEmail; michael@0: const char* aWalkAddr; michael@0: for (aWalkAddr = CERT_GetFirstEmailAddress(mCert.get()) michael@0: ; michael@0: aWalkAddr michael@0: ; michael@0: aWalkAddr = CERT_GetNextEmailAddress(mCert.get(), aWalkAddr)) michael@0: { michael@0: NS_ConvertUTF8toUTF16 email(aWalkAddr); michael@0: if (email.IsEmpty()) michael@0: continue; michael@0: michael@0: if (firstEmail.IsEmpty()) { michael@0: // If the first email address from the subject DN is also present michael@0: // in the subjectAltName extension, GetEmailAddresses() will return michael@0: // it twice (as received from NSS). Remember the first address so that michael@0: // we can filter out duplicates later on. michael@0: firstEmail = email; michael@0: michael@0: details.AppendLiteral(" "); michael@0: if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoEmail", info))) { michael@0: details.Append(info); michael@0: details.AppendLiteral(": "); michael@0: } michael@0: details.Append(email); michael@0: } michael@0: else { michael@0: // Append current address if it's different from the first one. michael@0: if (!firstEmail.Equals(email)) { michael@0: details.AppendLiteral(", "); michael@0: details.Append(email); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!firstEmail.IsEmpty()) { michael@0: // We got at least one email address, so we want a newline michael@0: details.Append(char16_t('\n')); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedBy", info))) { michael@0: details.Append(info); michael@0: details.Append(char16_t(' ')); michael@0: michael@0: if (NS_SUCCEEDED(GetIssuerName(temp1)) && !temp1.IsEmpty()) { michael@0: details.Append(temp1); michael@0: } michael@0: michael@0: details.Append(char16_t('\n')); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoStoredIn", info))) { michael@0: details.Append(info); michael@0: details.Append(char16_t(' ')); michael@0: michael@0: if (NS_SUCCEEDED(GetTokenName(temp1)) && !temp1.IsEmpty()) { michael@0: details.Append(temp1); michael@0: } michael@0: } michael@0: michael@0: // the above produces the following output: michael@0: // michael@0: // Issued to: $subjectName michael@0: // Serial number: $serialNumber michael@0: // Valid from: $starting_date to $expiration_date michael@0: // Certificate Key usage: $usages michael@0: // Email: $address(es) michael@0: // Issued by: $issuerName michael@0: // Stored in: $token michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetDbKey(char** aDbKey) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: SECItem key; michael@0: michael@0: NS_ENSURE_ARG(aDbKey); michael@0: *aDbKey = nullptr; michael@0: key.len = NS_NSS_LONG*4+mCert->serialNumber.len+mCert->derIssuer.len; michael@0: key.data = (unsigned char*) nsMemory::Alloc(key.len); michael@0: if (!key.data) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_NSS_PUT_LONG(0,key.data); // later put moduleID michael@0: NS_NSS_PUT_LONG(0,&key.data[NS_NSS_LONG]); // later put slotID michael@0: NS_NSS_PUT_LONG(mCert->serialNumber.len,&key.data[NS_NSS_LONG*2]); michael@0: NS_NSS_PUT_LONG(mCert->derIssuer.len,&key.data[NS_NSS_LONG*3]); michael@0: memcpy(&key.data[NS_NSS_LONG*4], mCert->serialNumber.data, michael@0: mCert->serialNumber.len); michael@0: memcpy(&key.data[NS_NSS_LONG*4+mCert->serialNumber.len], michael@0: mCert->derIssuer.data, mCert->derIssuer.len); michael@0: michael@0: *aDbKey = NSSBase64_EncodeItem(nullptr, nullptr, 0, &key); michael@0: nsMemory::Free(key.data); // SECItem is a 'c' type without a destrutor michael@0: return (*aDbKey) ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetWindowTitle(char** aWindowTitle) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: NS_ENSURE_ARG(aWindowTitle); michael@0: if (mCert) { michael@0: if (mCert->nickname) { michael@0: *aWindowTitle = PL_strdup(mCert->nickname); michael@0: } else { michael@0: *aWindowTitle = CERT_GetCommonName(&mCert->subject); michael@0: if (!*aWindowTitle) { michael@0: if (mCert->subjectName) { michael@0: *aWindowTitle = PL_strdup(mCert->subjectName); michael@0: } else if (mCert->emailAddr) { michael@0: *aWindowTitle = PL_strdup(mCert->emailAddr); michael@0: } else { michael@0: *aWindowTitle = PL_strdup(""); michael@0: } michael@0: } michael@0: } michael@0: } else { michael@0: NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate."); michael@0: *aWindowTitle = nullptr; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetNickname(nsAString& aNickname) michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if (mCert->nickname) { michael@0: CopyUTF8toUTF16(mCert->nickname, aNickname); michael@0: } else { michael@0: nsresult rv; michael@0: nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); michael@0: if (NS_FAILED(rv) || !nssComponent) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: nssComponent->GetPIPNSSBundleString("CertNoNickname", aNickname); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress) michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if (mCert->emailAddr) { michael@0: CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress); michael@0: } else { michael@0: nsresult rv; michael@0: nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); michael@0: if (NS_FAILED(rv) || !nssComponent) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: NS_ENSURE_ARG(aLength); michael@0: NS_ENSURE_ARG(aAddresses); michael@0: michael@0: *aLength = 0; michael@0: michael@0: const char* aAddr; michael@0: for (aAddr = CERT_GetFirstEmailAddress(mCert.get()) michael@0: ; michael@0: aAddr michael@0: ; michael@0: aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) michael@0: { michael@0: ++(*aLength); michael@0: } michael@0: michael@0: *aAddresses = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength)); michael@0: if (!*aAddresses) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: uint32_t iAddr; michael@0: for (aAddr = CERT_GetFirstEmailAddress(mCert.get()), iAddr = 0 michael@0: ; michael@0: aAddr michael@0: ; michael@0: aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr), ++iAddr) michael@0: { michael@0: (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr)); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress, michael@0: bool* result) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: NS_ENSURE_ARG(result); michael@0: *result = false; michael@0: michael@0: const char* aAddr = nullptr; michael@0: for (aAddr = CERT_GetFirstEmailAddress(mCert.get()) michael@0: ; michael@0: aAddr michael@0: ; michael@0: aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) michael@0: { michael@0: NS_ConvertUTF8toUTF16 certAddr(aAddr); michael@0: ToLowerCase(certAddr); michael@0: michael@0: nsAutoString testAddr(aEmailAddress); michael@0: ToLowerCase(testAddr); michael@0: michael@0: if (certAddr == testAddr) michael@0: { michael@0: *result = true; michael@0: break; michael@0: } michael@0: michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetCommonName(nsAString& aCommonName) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: aCommonName.Truncate(); michael@0: if (mCert) { michael@0: char* commonName = CERT_GetCommonName(&mCert->subject); michael@0: if (commonName) { michael@0: aCommonName = NS_ConvertUTF8toUTF16(commonName); michael@0: PORT_Free(commonName); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetOrganization(nsAString& aOrganization) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: aOrganization.Truncate(); michael@0: if (mCert) { michael@0: char* organization = CERT_GetOrgName(&mCert->subject); michael@0: if (organization) { michael@0: aOrganization = NS_ConvertUTF8toUTF16(organization); michael@0: PORT_Free(organization); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: aCommonName.Truncate(); michael@0: if (mCert) { michael@0: char* commonName = CERT_GetCommonName(&mCert->issuer); michael@0: if (commonName) { michael@0: aCommonName = NS_ConvertUTF8toUTF16(commonName); michael@0: PORT_Free(commonName); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: aOrganization.Truncate(); michael@0: if (mCert) { michael@0: char* organization = CERT_GetOrgName(&mCert->issuer); michael@0: if (organization) { michael@0: aOrganization = NS_ConvertUTF8toUTF16(organization); michael@0: PORT_Free(organization); michael@0: } else { michael@0: return GetIssuerCommonName(aOrganization); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: aOrganizationUnit.Truncate(); michael@0: if (mCert) { michael@0: char* organizationUnit = CERT_GetOrgUnitName(&mCert->issuer); michael@0: if (organizationUnit) { michael@0: aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit); michael@0: PORT_Free(organizationUnit); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetIssuer(nsIX509Cert** aIssuer) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: NS_ENSURE_ARG(aIssuer); michael@0: *aIssuer = nullptr; michael@0: michael@0: nsCOMPtr chain; michael@0: nsresult rv; michael@0: rv = GetChain(getter_AddRefs(chain)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: uint32_t length; michael@0: if (!chain || NS_FAILED(chain->GetLength(&length)) || length == 0) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: if (length == 1) { // No known issuer michael@0: return NS_OK; michael@0: } michael@0: nsCOMPtr cert; michael@0: chain->QueryElementAt(1, NS_GET_IID(nsIX509Cert), getter_AddRefs(cert)); michael@0: if (!cert) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: *aIssuer = cert; michael@0: NS_ADDREF(*aIssuer); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: aOrganizationalUnit.Truncate(); michael@0: if (mCert) { michael@0: char* orgunit = CERT_GetOrgUnitName(&mCert->subject); michael@0: if (orgunit) { michael@0: aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit); michael@0: PORT_Free(orgunit); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetChain(nsIArray** _rvChain) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: NS_ENSURE_ARG(_rvChain); michael@0: nsresult rv; michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname)); michael@0: michael@0: ::mozilla::pkix::ScopedCERTCertList nssChain; michael@0: RefPtr certVerifier(GetDefaultCertVerifier()); michael@0: NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); michael@0: michael@0: // We want to test all usages, but we start with server because most of the michael@0: // time Firefox users care about server certs. michael@0: certVerifier->VerifyCert(mCert.get(), michael@0: certificateUsageSSLServer, PR_Now(), michael@0: nullptr, /*XXX fixme*/ michael@0: nullptr, /* hostname */ michael@0: CertVerifier::FLAG_LOCAL_ONLY, michael@0: nullptr, /* stapledOCSPResponse */ michael@0: &nssChain); michael@0: // This is the whitelist of all non-SSLServer usages that are supported by michael@0: // verifycert. michael@0: const int otherUsagesToTest = certificateUsageSSLClient | michael@0: certificateUsageSSLCA | michael@0: certificateUsageEmailSigner | michael@0: certificateUsageEmailRecipient | michael@0: certificateUsageObjectSigner | michael@0: certificateUsageStatusResponder; michael@0: for (int usage = certificateUsageSSLClient; michael@0: usage < certificateUsageAnyCA && !nssChain; michael@0: usage = usage << 1) { michael@0: if ((usage & otherUsagesToTest) == 0) { michael@0: continue; michael@0: } michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("pipnss: PKIX attempting chain(%d) for '%s'\n", michael@0: usage, mCert->nickname)); michael@0: certVerifier->VerifyCert(mCert.get(), michael@0: usage, PR_Now(), michael@0: nullptr, /*XXX fixme*/ michael@0: nullptr, /*hostname*/ michael@0: CertVerifier::FLAG_LOCAL_ONLY, michael@0: nullptr, /* stapledOCSPResponse */ michael@0: &nssChain); michael@0: } michael@0: michael@0: if (!nssChain) { michael@0: // There is not verified path for the chain, howeever we still want to michael@0: // present to the user as much of a possible chain as possible, in the case michael@0: // where there was a problem with the cert or the issuers. michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("pipnss: getchain :CertVerify failed to get chain for '%s'\n", michael@0: mCert->nickname)); michael@0: nssChain = CERT_GetCertChainFromCert(mCert.get(), PR_Now(), michael@0: certUsageSSLClient); michael@0: } michael@0: michael@0: if (!nssChain) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // enumerate the chain for scripting purposes michael@0: nsCOMPtr array = michael@0: do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: goto done; michael@0: } michael@0: CERTCertListNode* node; michael@0: for (node = CERT_LIST_HEAD(nssChain.get()); michael@0: !CERT_LIST_END(node, nssChain.get()); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("adding %s to chain\n", node->cert->nickname)); michael@0: nsCOMPtr cert = nsNSSCertificate::Create(node->cert); michael@0: array->AppendElement(cert, false); michael@0: } michael@0: *_rvChain = array; michael@0: NS_IF_ADDREF(*_rvChain); michael@0: rv = NS_OK; michael@0: done: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetAllTokenNames(uint32_t* aLength, char16_t*** aTokenNames) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: NS_ENSURE_ARG(aLength); michael@0: NS_ENSURE_ARG(aTokenNames); michael@0: *aLength = 0; michael@0: *aTokenNames = nullptr; michael@0: michael@0: // Get the slots from NSS michael@0: ScopedPK11SlotList slots; michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting slots for \"%s\"\n", mCert->nickname)); michael@0: slots = PK11_GetAllSlotsForCert(mCert.get(), nullptr); michael@0: if (!slots) { michael@0: if (PORT_GetError() == SEC_ERROR_NO_TOKEN) michael@0: return NS_OK; // List of slots is empty, return empty array michael@0: else michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // read the token names from slots michael@0: PK11SlotListElement* le; michael@0: michael@0: for (le = slots->head; le; le = le->next) { michael@0: ++(*aLength); michael@0: } michael@0: michael@0: *aTokenNames = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * (*aLength)); michael@0: if (!*aTokenNames) { michael@0: *aLength = 0; michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: uint32_t iToken; michael@0: for (le = slots->head, iToken = 0; le; le = le->next, ++iToken) { michael@0: char* token = PK11_GetTokenName(le->slot); michael@0: (*aTokenNames)[iToken] = ToNewUnicode(NS_ConvertUTF8toUTF16(token)); michael@0: if (!(*aTokenNames)[iToken]) { michael@0: NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iToken, *aTokenNames); michael@0: *aLength = 0; michael@0: *aTokenNames = nullptr; michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetSubjectName(nsAString& _subjectName) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: _subjectName.Truncate(); michael@0: if (mCert->subjectName) { michael@0: _subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetIssuerName(nsAString& _issuerName) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: _issuerName.Truncate(); michael@0: if (mCert->issuerName) { michael@0: _issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetSerialNumber(nsAString& _serialNumber) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: _serialNumber.Truncate(); michael@0: char* tmpstr = CERT_Hexify(&mCert->serialNumber, 1); michael@0: if (tmpstr) { michael@0: _serialNumber = NS_ConvertASCIItoUTF16(tmpstr); michael@0: PORT_Free(tmpstr); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetSha1Fingerprint(nsAString& _sha1Fingerprint) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: _sha1Fingerprint.Truncate(); michael@0: unsigned char fingerprint[20]; michael@0: SECItem fpItem; michael@0: memset(fingerprint, 0, sizeof fingerprint); michael@0: PK11_HashBuf(SEC_OID_SHA1, fingerprint, michael@0: mCert->derCert.data, mCert->derCert.len); michael@0: fpItem.data = fingerprint; michael@0: fpItem.len = SHA1_LENGTH; michael@0: char* fpStr = CERT_Hexify(&fpItem, 1); michael@0: if (fpStr) { michael@0: _sha1Fingerprint = NS_ConvertASCIItoUTF16(fpStr); michael@0: PORT_Free(fpStr); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetMd5Fingerprint(nsAString& _md5Fingerprint) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: _md5Fingerprint.Truncate(); michael@0: unsigned char fingerprint[20]; michael@0: SECItem fpItem; michael@0: memset(fingerprint, 0, sizeof fingerprint); michael@0: PK11_HashBuf(SEC_OID_MD5, fingerprint, michael@0: mCert->derCert.data, mCert->derCert.len); michael@0: fpItem.data = fingerprint; michael@0: fpItem.len = MD5_LENGTH; michael@0: char* fpStr = CERT_Hexify(&fpItem, 1); michael@0: if (fpStr) { michael@0: _md5Fingerprint = NS_ConvertASCIItoUTF16(fpStr); michael@0: PORT_Free(fpStr); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetTokenName(nsAString& aTokenName) michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: aTokenName.Truncate(); michael@0: if (mCert) { michael@0: // HACK alert michael@0: // When the trust of a builtin cert is modified, NSS copies it into the michael@0: // cert db. At this point, it is now "managed" by the user, and should michael@0: // not be listed with the builtins. However, in the collection code michael@0: // used by PK11_ListCerts, the cert is found in the temp db, where it michael@0: // has been loaded from the token. Though the trust is correct (grabbed michael@0: // from the cert db), the source is wrong. I believe this is a safe michael@0: // way to work around this. michael@0: if (mCert->slot) { michael@0: char* token = PK11_GetTokenName(mCert->slot); michael@0: if (token) { michael@0: aTokenName = NS_ConvertUTF8toUTF16(token); michael@0: } michael@0: } else { michael@0: nsresult rv; michael@0: nsAutoString tok; michael@0: nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok); michael@0: if (NS_SUCCEEDED(rv)) michael@0: aTokenName = tok; michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: aSha256SPKIDigest.Truncate(); michael@0: Digest digest; michael@0: nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data, michael@0: mCert->derPublicKey.len); michael@0: if (NS_WARN_IF(NS_FAILED(rv))) { michael@0: return rv; michael@0: } michael@0: rv = Base64Encode(nsDependentCSubstring( michael@0: reinterpret_cast (digest.get().data), michael@0: digest.get().len), michael@0: aSha256SPKIDigest); michael@0: if (NS_WARN_IF(NS_FAILED(rv))) { michael@0: return rv; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if (mCert) { michael@0: *aArray = (uint8_t*)nsMemory::Alloc(mCert->derCert.len); michael@0: if (*aArray) { michael@0: memcpy(*aArray, mCert->derCert.data, mCert->derCert.len); michael@0: *aLength = mCert->derCert.len; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: *aLength = 0; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::ExportAsCMS(uint32_t chainMode, michael@0: uint32_t* aLength, uint8_t** aArray) michael@0: { michael@0: NS_ENSURE_ARG(aLength); michael@0: NS_ENSURE_ARG(aArray); michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if (!mCert) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: switch (chainMode) { michael@0: case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly: michael@0: case nsIX509Cert3::CMS_CHAIN_MODE_CertChain: michael@0: case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot: michael@0: break; michael@0: default: michael@0: return NS_ERROR_INVALID_ARG; michael@0: }; michael@0: michael@0: PLArenaPool* arena = PORT_NewArena(1024); michael@0: PLArenaPoolCleanerFalseParam arenaCleaner(arena); michael@0: if (!arena) { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("nsNSSCertificate::ExportAsCMS - out of memory\n")); michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: ScopedNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr)); michael@0: if (!cmsg) { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n")); michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: // first, create SignedData with the certificate only (no chain) michael@0: ScopedNSSCMSSignedData sigd( michael@0: NSS_CMSSignedData_CreateCertsOnly(cmsg, mCert.get(), false)); michael@0: if (!sigd) { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n")); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us michael@0: // to specify the inclusion of the root, but CERT_CertChainFromCert() does. michael@0: // Since CERT_CertChainFromCert() also includes the certificate itself, michael@0: // we have to start at the issuing cert (to avoid duplicate certs michael@0: // in the SignedData). michael@0: if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain || michael@0: chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) { michael@0: ScopedCERTCertificate issuerCert( michael@0: CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA)); michael@0: // the issuerCert of a self signed root is the cert itself, michael@0: // so make sure we're not adding duplicates, again michael@0: if (issuerCert && issuerCert != mCert.get()) { michael@0: bool includeRoot = michael@0: (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot); michael@0: ScopedCERTCertificateList certChain( michael@0: CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot)); michael@0: if (certChain) { michael@0: if (NSS_CMSSignedData_AddCertList(sigd, certChain) == SECSuccess) { michael@0: certChain.forget(); michael@0: } michael@0: else { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("nsNSSCertificate::ExportAsCMS - can't add chain\n")); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: else { michael@0: // try to add the issuerCert, at least michael@0: if (NSS_CMSSignedData_AddCertificate(sigd, issuerCert) michael@0: == SECSuccess) { michael@0: issuerCert.forget(); michael@0: } michael@0: else { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n")); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: NSSCMSContentInfo* cinfo = NSS_CMSMessage_GetContentInfo(cmsg); michael@0: if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) michael@0: == SECSuccess) { michael@0: sigd.forget(); michael@0: } michael@0: else { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n")); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: SECItem certP7 = { siBuffer, nullptr, 0 }; michael@0: NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg, nullptr, nullptr, michael@0: &certP7, arena, nullptr, michael@0: nullptr, nullptr, nullptr, michael@0: nullptr, nullptr); michael@0: if (!ecx) { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n")); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) { michael@0: PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, michael@0: ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n")); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: *aArray = (uint8_t*)nsMemory::Alloc(certP7.len); michael@0: if (!*aArray) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: memcpy(*aArray, certP7.data, certP7.len); michael@0: *aLength = certP7.len; michael@0: return NS_OK; michael@0: } michael@0: michael@0: CERTCertificate* michael@0: nsNSSCertificate::GetCert() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return nullptr; michael@0: michael@0: return (mCert) ? CERT_DupCertificate(mCert.get()) : nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetValidity(nsIX509CertValidity** aValidity) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: NS_ENSURE_ARG(aValidity); michael@0: nsX509CertValidity* validity = new nsX509CertValidity(mCert.get()); michael@0: michael@0: NS_ADDREF(validity); michael@0: *aValidity = static_cast(validity); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetUsagesArray(bool localOnly, michael@0: uint32_t* _verified, michael@0: uint32_t* _count, michael@0: char16_t*** _usages) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv; michael@0: const int max_usages = 13; michael@0: char16_t* tmpUsages[max_usages]; michael@0: const char* suffix = ""; michael@0: uint32_t tmpCount; michael@0: nsUsageArrayHelper uah(mCert.get()); michael@0: rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount, michael@0: tmpUsages); michael@0: NS_ENSURE_SUCCESS(rv,rv); michael@0: if (tmpCount > 0) { michael@0: *_usages = (char16_t**) nsMemory::Alloc(sizeof(char16_t*) * tmpCount); michael@0: if (!*_usages) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: for (uint32_t i=0; imCert = this; michael@0: job->mListener = michael@0: new nsMainThreadPtrHolder(aResultListener); michael@0: michael@0: nsresult rv = nsCertVerificationThread::addJob(job); michael@0: if (NS_FAILED(rv)) michael@0: delete job; michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetUsagesString(bool localOnly, uint32_t* _verified, michael@0: nsAString& _usages) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv; michael@0: const int max_usages = 13; michael@0: char16_t* tmpUsages[max_usages]; michael@0: const char* suffix = "_p"; michael@0: uint32_t tmpCount; michael@0: nsUsageArrayHelper uah(mCert.get()); michael@0: rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount, michael@0: tmpUsages); michael@0: NS_ENSURE_SUCCESS(rv,rv); michael@0: _usages.Truncate(); michael@0: for (uint32_t i=0; i0) _usages.AppendLiteral(","); michael@0: _usages.Append(tmpUsages[i]); michael@0: nsMemory::Free(tmpUsages[i]); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: #if defined(DEBUG_javi) || defined(DEBUG_jgmyers) michael@0: void michael@0: DumpASN1Object(nsIASN1Object* object, unsigned int level) michael@0: { michael@0: nsAutoString dispNameU, dispValU; michael@0: unsigned int i; michael@0: nsCOMPtr asn1Objects; michael@0: nsCOMPtr isupports; michael@0: nsCOMPtr currObject; michael@0: bool processObjects; michael@0: uint32_t numObjects; michael@0: michael@0: for (i=0; iGetDisplayName(dispNameU); michael@0: nsCOMPtr sequence(do_QueryInterface(object)); michael@0: if (sequence) { michael@0: printf ("%s ", NS_ConvertUTF16toUTF8(dispNameU).get()); michael@0: sequence->GetIsValidContainer(&processObjects); michael@0: if (processObjects) { michael@0: printf("\n"); michael@0: sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: asn1Objects->GetLength(&numObjects); michael@0: for (i=0; iQueryElementAt(i, NS_GET_IID(nsISupports), michael@0: getter_AddRefs(currObject)); michael@0: DumpASN1Object(currObject, level+1); michael@0: } michael@0: } else { michael@0: object->GetDisplayValue(dispValU); michael@0: printf("= %s\n", NS_ConvertUTF16toUTF8(dispValU).get()); michael@0: } michael@0: } else { michael@0: object->GetDisplayValue(dispValU); michael@0: printf("%s = %s\n",NS_ConvertUTF16toUTF8(dispNameU).get(), michael@0: NS_ConvertUTF16toUTF8(dispValU).get()); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetASN1Structure(nsIASN1Object** aASN1Structure) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: nsresult rv = NS_OK; michael@0: NS_ENSURE_ARG_POINTER(aASN1Structure); michael@0: // First create the recursive structure os ASN1Objects michael@0: // which tells us the layout of the cert. michael@0: rv = CreateASN1Struct(aASN1Structure); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: #ifdef DEBUG_javi michael@0: DumpASN1Object(*aASN1Structure, 0); michael@0: #endif michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::Equals(nsIX509Cert* other, bool* result) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: NS_ENSURE_ARG(other); michael@0: NS_ENSURE_ARG(result); michael@0: michael@0: nsCOMPtr other2 = do_QueryInterface(other); michael@0: if (!other2) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: ScopedCERTCertificate cert(other2->GetCert()); michael@0: *result = (mCert.get() == cert.get()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::SaveSMimeProfile() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if (SECSuccess != CERT_SaveSMimeProfile(mCert.get(), nullptr, nullptr)) michael@0: return NS_ERROR_FAILURE; michael@0: else michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifndef MOZ_NO_EV_CERTS michael@0: michael@0: nsresult michael@0: nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: EnsureIdentityInfoLoaded(); michael@0: michael@0: RefPtr michael@0: certVerifier(mozilla::psm::GetDefaultCertVerifier()); michael@0: NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); michael@0: michael@0: validEV = false; michael@0: resultOidTag = SEC_OID_UNKNOWN; michael@0: michael@0: uint32_t flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY | michael@0: mozilla::psm::CertVerifier::FLAG_MUST_BE_EV; michael@0: SECStatus rv = certVerifier->VerifyCert(mCert.get(), michael@0: certificateUsageSSLServer, PR_Now(), michael@0: nullptr /* XXX pinarg */, michael@0: nullptr /* hostname */, michael@0: flags, nullptr /* stapledOCSPResponse */ , nullptr, &resultOidTag); michael@0: michael@0: if (rv != SECSuccess) { michael@0: resultOidTag = SEC_OID_UNKNOWN; michael@0: } michael@0: if (resultOidTag != SEC_OID_UNKNOWN) { michael@0: validEV = true; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNSSCertificate::getValidEVOidTag(SECOidTag& resultOidTag, bool& validEV) michael@0: { michael@0: if (mCachedEVStatus != ev_status_unknown) { michael@0: validEV = (mCachedEVStatus == ev_status_valid); michael@0: if (validEV) { michael@0: resultOidTag = mCachedEVOidTag; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult rv = hasValidEVOidTag(resultOidTag, validEV); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: if (validEV) { michael@0: mCachedEVOidTag = resultOidTag; michael@0: } michael@0: mCachedEVStatus = validEV ? ev_status_valid : ev_status_invalid; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: #endif // MOZ_NO_EV_CERTS michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetIsExtendedValidation(bool* aIsEV) michael@0: { michael@0: #ifdef MOZ_NO_EV_CERTS michael@0: *aIsEV = false; michael@0: return NS_OK; michael@0: #else michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_ENSURE_ARG(aIsEV); michael@0: *aIsEV = false; michael@0: michael@0: if (mCachedEVStatus != ev_status_unknown) { michael@0: *aIsEV = (mCachedEVStatus == ev_status_valid); michael@0: return NS_OK; michael@0: } michael@0: michael@0: SECOidTag oid_tag; michael@0: return getValidEVOidTag(oid_tag, *aIsEV); michael@0: #endif michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetValidEVPolicyOid(nsACString& outDottedOid) michael@0: { michael@0: outDottedOid.Truncate(); michael@0: michael@0: #ifndef MOZ_NO_EV_CERTS michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: SECOidTag oid_tag; michael@0: bool valid; michael@0: nsresult rv = getValidEVOidTag(oid_tag, valid); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: if (valid) { michael@0: SECOidData* oid_data = SECOID_FindOIDByTag(oid_tag); michael@0: if (!oid_data) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: char* oid_str = CERT_GetOidString(&oid_data->oid); michael@0: if (!oid_str) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: outDottedOid.Assign(oid_str); michael@0: PR_smprintf_free(oid_str); michael@0: } michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsNSSCertList, nsIX509CertList) michael@0: michael@0: nsNSSCertList::nsNSSCertList(mozilla::pkix::ScopedCERTCertList& certList, michael@0: const nsNSSShutDownPreventionLock& proofOfLock) michael@0: { michael@0: if (certList) { michael@0: mCertList = certList.release(); michael@0: } else { michael@0: mCertList = CERT_NewCertList(); michael@0: } michael@0: } michael@0: michael@0: nsNSSCertList::nsNSSCertList() michael@0: { michael@0: mCertList = CERT_NewCertList(); michael@0: } michael@0: michael@0: nsNSSCertList::~nsNSSCertList() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: destructorSafeDestroyNSSReference(); michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: void nsNSSCertList::virtualDestroyNSSReference() michael@0: { michael@0: destructorSafeDestroyNSSReference(); michael@0: } michael@0: michael@0: void nsNSSCertList::destructorSafeDestroyNSSReference() michael@0: { michael@0: if (mCertList) { michael@0: mCertList = nullptr; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertList::AddCert(nsIX509Cert* aCert) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: nsCOMPtr nssCert = do_QueryInterface(aCert); michael@0: CERTCertificate* cert; michael@0: michael@0: cert = nssCert->GetCert(); michael@0: if (!cert) { michael@0: NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate."); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (!mCertList) { michael@0: NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList."); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: // XXX: check return value! michael@0: CERT_AddCertToListTail(mCertList.get(), cert); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertList::DeleteCert(nsIX509Cert* aCert) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: nsCOMPtr nssCert = do_QueryInterface(aCert); michael@0: CERTCertificate* cert = nssCert->GetCert(); michael@0: CERTCertListNode* node; michael@0: michael@0: if (!cert) { michael@0: NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate."); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (!mCertList) { michael@0: NS_ERROR("Somehow got nullptr for mCertList in nsNSSCertList."); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: for (node = CERT_LIST_HEAD(mCertList.get()); michael@0: !CERT_LIST_END(node, mCertList.get()); node = CERT_LIST_NEXT(node)) { michael@0: if (node->cert == cert) { michael@0: CERT_RemoveCertListNode(node); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: return NS_OK; // XXX Should we fail if we couldn't find it? michael@0: } michael@0: michael@0: CERTCertList* michael@0: nsNSSCertList::DupCertList(CERTCertList* aCertList, michael@0: const nsNSSShutDownPreventionLock& /*proofOfLock*/) michael@0: { michael@0: if (!aCertList) michael@0: return nullptr; michael@0: michael@0: CERTCertList* newList = CERT_NewCertList(); michael@0: michael@0: if (!newList) { michael@0: return nullptr; michael@0: } michael@0: michael@0: CERTCertListNode* node; michael@0: for (node = CERT_LIST_HEAD(aCertList); !CERT_LIST_END(node, aCertList); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: CERTCertificate* cert = CERT_DupCertificate(node->cert); michael@0: CERT_AddCertToListTail(newList, cert); michael@0: } michael@0: return newList; michael@0: } michael@0: michael@0: void* michael@0: nsNSSCertList::GetRawCertList() michael@0: { michael@0: // This function should only be called after adquiring a michael@0: // nsNSSShutDownPreventionLock michael@0: return mCertList.get(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: nsCOMPtr enumerator = michael@0: new nsNSSCertListEnumerator(mCertList.get(), locker); michael@0: michael@0: *_retval = enumerator; michael@0: NS_ADDREF(*_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator) michael@0: michael@0: nsNSSCertListEnumerator::nsNSSCertListEnumerator( michael@0: CERTCertList* certList, const nsNSSShutDownPreventionLock& proofOfLock) michael@0: { michael@0: mCertList = nsNSSCertList::DupCertList(certList, proofOfLock); michael@0: } michael@0: michael@0: nsNSSCertListEnumerator::~nsNSSCertListEnumerator() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: destructorSafeDestroyNSSReference(); michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: void nsNSSCertListEnumerator::virtualDestroyNSSReference() michael@0: { michael@0: destructorSafeDestroyNSSReference(); michael@0: } michael@0: michael@0: void nsNSSCertListEnumerator::destructorSafeDestroyNSSReference() michael@0: { michael@0: if (mCertList) { michael@0: mCertList = nullptr; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertListEnumerator::HasMoreElements(bool* _retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE); michael@0: michael@0: *_retval = !CERT_LIST_EMPTY(mCertList); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertListEnumerator::GetNext(nsISupports** _retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE); michael@0: michael@0: CERTCertListNode* node = CERT_LIST_HEAD(mCertList); michael@0: if (CERT_LIST_END(node, mCertList)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr nssCert = nsNSSCertificate::Create(node->cert); michael@0: if (!nssCert) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: *_retval = nssCert; michael@0: NS_ADDREF(*_retval); michael@0: michael@0: CERT_RemoveCertListNode(node); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // NB: This serialization must match that of nsNSSCertificateFakeTransport. michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::Write(nsIObjectOutputStream* aStream) michael@0: { michael@0: NS_ENSURE_STATE(mCert); michael@0: nsresult rv = aStream->Write32(static_cast(mCachedEVStatus)); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: rv = aStream->Write32(mCert->derCert.len); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::Read(nsIObjectInputStream* aStream) michael@0: { michael@0: NS_ENSURE_STATE(!mCert); michael@0: michael@0: uint32_t cachedEVStatus; michael@0: nsresult rv = aStream->Read32(&cachedEVStatus); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: if (cachedEVStatus == static_cast(ev_status_unknown)) { michael@0: mCachedEVStatus = ev_status_unknown; michael@0: } else if (cachedEVStatus == static_cast(ev_status_valid)) { michael@0: mCachedEVStatus = ev_status_valid; michael@0: } else if (cachedEVStatus == static_cast(ev_status_invalid)) { michael@0: mCachedEVStatus = ev_status_invalid; michael@0: } else { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: uint32_t len; michael@0: rv = aStream->Read32(&len); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: nsXPIDLCString str; michael@0: rv = aStream->ReadBytes(len, getter_Copies(str)); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: if (!InitFromDER(const_cast(str.get()), len)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetInterfaces(uint32_t* count, nsIID*** array) michael@0: { michael@0: *count = 0; michael@0: *array = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetHelperForLanguage(uint32_t language, michael@0: nsISupports** _retval) michael@0: { michael@0: *_retval = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetContractID(char** aContractID) michael@0: { michael@0: *aContractID = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetClassDescription(char** aClassDescription) michael@0: { michael@0: *aClassDescription = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetClassID(nsCID** aClassID) michael@0: { michael@0: *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID)); michael@0: if (!*aClassID) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: return GetClassIDNoAlloc(*aClassID); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetImplementationLanguage(uint32_t* aImplementationLanguage) michael@0: { michael@0: *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetFlags(uint32_t* aFlags) michael@0: { michael@0: *aFlags = nsIClassInfo::THREADSAFE; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsNSSCertificate::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) michael@0: { michael@0: static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID); michael@0: michael@0: *aClassIDNoAlloc = kNSSCertificateCID; michael@0: return NS_OK; michael@0: }