mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 20:17:37 +00:00
1871 lines
50 KiB
C++
1871 lines
50 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is the Netscape security libraries.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2000
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Ian McGreer <mcgreer@netscape.com>
|
|
* Javier Delgadillo <javi@netscape.com>
|
|
* Kai Engert <kengert@redhat.com>
|
|
* Jesper Kristensen <mail@jesperkristensen.dk>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "prmem.h"
|
|
#include "prerror.h"
|
|
#include "prprf.h"
|
|
|
|
#include "nsNSSComponent.h" // for PIPNSS string bundle calls.
|
|
#include "nsNSSCleaner.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIMutableArray.h"
|
|
#include "nsNSSCertificate.h"
|
|
#include "nsNSSCertValidity.h"
|
|
#include "nsPKCS12Blob.h"
|
|
#include "nsPK11TokenDB.h"
|
|
#include "nsIX509Cert.h"
|
|
#include "nsIX509Cert3.h"
|
|
#include "nsISMimeCert.h"
|
|
#include "nsNSSASN1Object.h"
|
|
#include "nsString.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsReadableUtils.h"
|
|
#include "nsIURI.h"
|
|
#include "nsTime.h"
|
|
#include "nsIProxyObjectManager.h"
|
|
#include "nsCRT.h"
|
|
#include "nsAutoLock.h"
|
|
#include "nsUsageArrayHelper.h"
|
|
#include "nsICertificateDialogs.h"
|
|
#include "nsNSSCertHelper.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsUnicharUtils.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsCertVerificationThread.h"
|
|
#include "nsIObjectOutputStream.h"
|
|
#include "nsIObjectInputStream.h"
|
|
#include "nsIProgrammingLanguage.h"
|
|
|
|
#include "nspr.h"
|
|
extern "C" {
|
|
#include "pk11func.h"
|
|
#include "certdb.h"
|
|
#include "cert.h"
|
|
#include "secerr.h"
|
|
#include "nssb64.h"
|
|
#include "secasn1.h"
|
|
#include "secder.h"
|
|
}
|
|
#include "ssl.h"
|
|
#include "ocsp.h"
|
|
#include "plbase64.h"
|
|
#include "cms.h"
|
|
#include "cert.h"
|
|
|
|
#ifdef PR_LOGGING
|
|
extern PRLogModuleInfo* gPIPNSSLog;
|
|
#endif
|
|
|
|
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|
|
|
NSSCleanupAutoPtrClass(CERTCertificateList, CERT_DestroyCertificateList)
|
|
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
|
|
NSSCleanupAutoPtrClass(NSSCMSMessage, NSS_CMSMessage_Destroy)
|
|
NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, PR_FALSE)
|
|
NSSCleanupAutoPtrClass(NSSCMSSignedData, NSS_CMSSignedData_Destroy)
|
|
NSSCleanupAutoPtrClass(PK11SlotList, PK11_FreeSlotList)
|
|
|
|
// This is being stored in an PRUint32 that can otherwise
|
|
// only take values from nsIX509Cert's list of cert types.
|
|
// As nsIX509Cert is frozen, we choose a value not contained
|
|
// in the list to mean not yet initialized.
|
|
#define CERT_TYPE_NOT_YET_INITIALIZED (1 << 30)
|
|
|
|
/* nsNSSCertificate */
|
|
|
|
NS_IMPL_THREADSAFE_ISUPPORTS7(nsNSSCertificate, nsIX509Cert,
|
|
nsIX509Cert2,
|
|
nsIX509Cert3,
|
|
nsIIdentityInfo,
|
|
nsISMimeCert,
|
|
nsISerializable,
|
|
nsIClassInfo)
|
|
|
|
nsNSSCertificate*
|
|
nsNSSCertificate::ConstructFromDER(char *certDER, int derLen)
|
|
{
|
|
nsNSSCertificate* newObject = new nsNSSCertificate();
|
|
if (!newObject->InitFromDER(certDER, derLen)) {
|
|
delete newObject;
|
|
newObject = nsnull;
|
|
}
|
|
|
|
return newObject;
|
|
}
|
|
|
|
PRBool
|
|
nsNSSCertificate::InitFromDER(char *certDER, int derLen)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return PR_FALSE;
|
|
|
|
if (!certDER || !derLen)
|
|
return PR_FALSE;
|
|
|
|
CERTCertificate *aCert = CERT_DecodeCertFromPackage(certDER, derLen);
|
|
|
|
if (!aCert)
|
|
return PR_FALSE;
|
|
|
|
if(aCert->dbhandle == nsnull)
|
|
{
|
|
aCert->dbhandle = CERT_GetDefaultCertDB();
|
|
}
|
|
|
|
mCert = aCert;
|
|
return PR_TRUE;
|
|
}
|
|
|
|
nsNSSCertificate::nsNSSCertificate(CERTCertificate *cert) :
|
|
mCert(nsnull),
|
|
mPermDelete(PR_FALSE),
|
|
mCertType(CERT_TYPE_NOT_YET_INITIALIZED),
|
|
mCachedEVStatus(ev_status_unknown)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return;
|
|
|
|
if (cert)
|
|
mCert = CERT_DupCertificate(cert);
|
|
}
|
|
|
|
nsNSSCertificate::nsNSSCertificate() :
|
|
mCert(nsnull),
|
|
mPermDelete(PR_FALSE),
|
|
mCertType(CERT_TYPE_NOT_YET_INITIALIZED),
|
|
mCachedEVStatus(ev_status_unknown)
|
|
{
|
|
}
|
|
|
|
nsNSSCertificate::~nsNSSCertificate()
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return;
|
|
|
|
destructorSafeDestroyNSSReference();
|
|
shutdown(calledFromObject);
|
|
}
|
|
|
|
void nsNSSCertificate::virtualDestroyNSSReference()
|
|
{
|
|
destructorSafeDestroyNSSReference();
|
|
}
|
|
|
|
void nsNSSCertificate::destructorSafeDestroyNSSReference()
|
|
{
|
|
if (isAlreadyShutDown())
|
|
return;
|
|
|
|
if (mPermDelete) {
|
|
if (mCertType == nsNSSCertificate::USER_CERT) {
|
|
nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
|
|
PK11_DeleteTokenCertAndKey(mCert, cxt);
|
|
} else if (!PK11_IsReadOnly(mCert->slot)) {
|
|
// If the list of built-ins does contain a non-removable
|
|
// copy of this certificate, our call will not remove
|
|
// the certificate permanently, but rather remove all trust.
|
|
SEC_DeletePermCertificate(mCert);
|
|
}
|
|
}
|
|
|
|
if (mCert) {
|
|
CERT_DestroyCertificate(mCert);
|
|
mCert = nsnull;
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::GetCertType(PRUint32 *aCertType)
|
|
{
|
|
if (mCertType == CERT_TYPE_NOT_YET_INITIALIZED) {
|
|
// only determine cert type once and cache it
|
|
mCertType = getCertType(mCert);
|
|
}
|
|
*aCertType = mCertType;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIsSelfSigned(PRBool *aIsSelfSigned)
|
|
{
|
|
NS_ENSURE_ARG(aIsSelfSigned);
|
|
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
*aIsSelfSigned = mCert->isRoot;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::MarkForPermDeletion()
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
// make sure user is logged in to the token
|
|
nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
|
|
|
|
if (PK11_NeedLogin(mCert->slot)
|
|
&& !PK11_NeedUserInit(mCert->slot)
|
|
&& !PK11_IsInternal(mCert->slot))
|
|
{
|
|
if (SECSuccess != PK11_Authenticate(mCert->slot, PR_TRUE, ctx))
|
|
{
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
|
|
mPermDelete = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
GetKeyUsagesString(CERTCertificate *cert, nsINSSComponent *nssComponent,
|
|
nsString &text)
|
|
{
|
|
text.Truncate();
|
|
|
|
SECItem keyUsageItem;
|
|
keyUsageItem.data = NULL;
|
|
|
|
SECStatus srv;
|
|
|
|
/* There is no extension, v1 or v2 certificate */
|
|
if (!cert->extensions)
|
|
return NS_OK;
|
|
|
|
|
|
srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
|
|
if (srv == SECFailure) {
|
|
if (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND)
|
|
return NS_OK;
|
|
else
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
unsigned char keyUsage = keyUsageItem.data[0];
|
|
nsAutoString local;
|
|
nsresult rv;
|
|
const PRUnichar *comma = NS_LITERAL_STRING(",").get();
|
|
|
|
if (keyUsage & KU_DIGITAL_SIGNATURE) {
|
|
rv = nssComponent->GetPIPNSSBundleString("CertDumpKUSign", local);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
if (!text.IsEmpty()) text.Append(comma);
|
|
text.Append(local.get());
|
|
}
|
|
}
|
|
if (keyUsage & KU_NON_REPUDIATION) {
|
|
rv = nssComponent->GetPIPNSSBundleString("CertDumpKUNonRep", local);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
if (!text.IsEmpty()) text.Append(comma);
|
|
text.Append(local.get());
|
|
}
|
|
}
|
|
if (keyUsage & KU_KEY_ENCIPHERMENT) {
|
|
rv = nssComponent->GetPIPNSSBundleString("CertDumpKUEnc", local);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
if (!text.IsEmpty()) text.Append(comma);
|
|
text.Append(local.get());
|
|
}
|
|
}
|
|
if (keyUsage & KU_DATA_ENCIPHERMENT) {
|
|
rv = nssComponent->GetPIPNSSBundleString("CertDumpKUDEnc", local);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
if (!text.IsEmpty()) text.Append(comma);
|
|
text.Append(local.get());
|
|
}
|
|
}
|
|
if (keyUsage & KU_KEY_AGREEMENT) {
|
|
rv = nssComponent->GetPIPNSSBundleString("CertDumpKUKA", local);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
if (!text.IsEmpty()) text.Append(comma);
|
|
text.Append(local.get());
|
|
}
|
|
}
|
|
if (keyUsage & KU_KEY_CERT_SIGN) {
|
|
rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCertSign", local);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
if (!text.IsEmpty()) text.Append(comma);
|
|
text.Append(local.get());
|
|
}
|
|
}
|
|
if (keyUsage & KU_CRL_SIGN) {
|
|
rv = nssComponent->GetPIPNSSBundleString("CertDumpKUCRLSign", local);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
if (!text.IsEmpty()) text.Append(comma);
|
|
text.Append(local.get());
|
|
}
|
|
}
|
|
|
|
PORT_Free (keyUsageItem.data);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::FormatUIStrings(const nsAutoString &nickname, nsAutoString &nickWithSerial, nsAutoString &details)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
|
|
if (NS_FAILED(rv) || !nssComponent) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIX509Cert> x509Proxy;
|
|
NS_GetProxyForObject( NS_PROXY_TO_MAIN_THREAD,
|
|
NS_GET_IID(nsIX509Cert),
|
|
static_cast<nsIX509Cert*>(this),
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(x509Proxy));
|
|
|
|
if (!x509Proxy) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
else {
|
|
rv = NS_OK;
|
|
|
|
nsAutoString info;
|
|
nsAutoString temp1;
|
|
|
|
nickWithSerial.Append(nickname);
|
|
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedFor", info))) {
|
|
details.Append(info);
|
|
details.Append(PRUnichar(' '));
|
|
if (NS_SUCCEEDED(x509Proxy->GetSubjectName(temp1)) && !temp1.IsEmpty()) {
|
|
details.Append(temp1);
|
|
}
|
|
details.Append(PRUnichar('\n'));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(x509Proxy->GetSerialNumber(temp1)) && !temp1.IsEmpty()) {
|
|
details.AppendLiteral(" ");
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", info))) {
|
|
details.Append(info);
|
|
details.AppendLiteral(": ");
|
|
}
|
|
details.Append(temp1);
|
|
|
|
nickWithSerial.AppendLiteral(" [");
|
|
nickWithSerial.Append(temp1);
|
|
nickWithSerial.Append(PRUnichar(']'));
|
|
|
|
details.Append(PRUnichar('\n'));
|
|
}
|
|
|
|
|
|
{
|
|
nsCOMPtr<nsIX509CertValidity> validity;
|
|
nsCOMPtr<nsIX509CertValidity> originalValidity;
|
|
rv = x509Proxy->GetValidity(getter_AddRefs(originalValidity));
|
|
if (NS_SUCCEEDED(rv) && originalValidity) {
|
|
NS_GetProxyForObject( NS_PROXY_TO_MAIN_THREAD,
|
|
NS_GET_IID(nsIX509CertValidity),
|
|
originalValidity,
|
|
NS_PROXY_SYNC | NS_PROXY_ALWAYS,
|
|
getter_AddRefs(validity));
|
|
}
|
|
|
|
if (validity) {
|
|
details.AppendLiteral(" ");
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoValid", info))) {
|
|
details.Append(info);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(validity->GetNotBeforeLocalTime(temp1)) && !temp1.IsEmpty()) {
|
|
details.Append(PRUnichar(' '));
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoFrom", info))) {
|
|
details.Append(info);
|
|
details.Append(PRUnichar(' '));
|
|
}
|
|
details.Append(temp1);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(validity->GetNotAfterLocalTime(temp1)) && !temp1.IsEmpty()) {
|
|
details.Append(PRUnichar(' '));
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoTo", info))) {
|
|
details.Append(info);
|
|
details.Append(PRUnichar(' '));
|
|
}
|
|
details.Append(temp1);
|
|
}
|
|
|
|
details.Append(PRUnichar('\n'));
|
|
}
|
|
}
|
|
|
|
PRUint32 tempInt = 0;
|
|
if (NS_SUCCEEDED(x509Proxy->GetUsagesString(PR_FALSE, &tempInt, temp1)) && !temp1.IsEmpty()) {
|
|
details.AppendLiteral(" ");
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoPurposes", info))) {
|
|
details.Append(info);
|
|
details.AppendLiteral(": ");
|
|
}
|
|
details.Append(temp1);
|
|
details.Append(PRUnichar('\n'));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(GetKeyUsagesString(mCert, nssComponent, temp1)) && !temp1.IsEmpty()) {
|
|
details.AppendLiteral(" ");
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertDumpKeyUsage", info))) {
|
|
details.Append(info);
|
|
details.AppendLiteral(": ");
|
|
}
|
|
details.Append(temp1);
|
|
details.Append(PRUnichar('\n'));
|
|
}
|
|
|
|
nsAutoString firstEmail;
|
|
const char *aWalkAddr;
|
|
for (aWalkAddr = CERT_GetFirstEmailAddress(mCert)
|
|
;
|
|
aWalkAddr
|
|
;
|
|
aWalkAddr = CERT_GetNextEmailAddress(mCert, aWalkAddr))
|
|
{
|
|
NS_ConvertUTF8toUTF16 email(aWalkAddr);
|
|
if (email.IsEmpty())
|
|
continue;
|
|
|
|
if (firstEmail.IsEmpty()) {
|
|
/*
|
|
* If the first email address from the subject DN is also present
|
|
* in the subjectAltName extension, GetEmailAddresses() will return
|
|
* it twice (as received from NSS). Remember the first address so that
|
|
* we can filter out duplicates later on.
|
|
*/
|
|
firstEmail = email;
|
|
|
|
details.AppendLiteral(" ");
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoEmail", info))) {
|
|
details.Append(info);
|
|
details.AppendLiteral(": ");
|
|
}
|
|
details.Append(email);
|
|
}
|
|
else {
|
|
// Append current address if it's different from the first one.
|
|
if (!firstEmail.Equals(email)) {
|
|
details.AppendLiteral(", ");
|
|
details.Append(email);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!firstEmail.IsEmpty()) {
|
|
// We got at least one email address, so we want a newline
|
|
details.Append(PRUnichar('\n'));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoIssuedBy", info))) {
|
|
details.Append(info);
|
|
details.Append(PRUnichar(' '));
|
|
|
|
if (NS_SUCCEEDED(x509Proxy->GetIssuerName(temp1)) && !temp1.IsEmpty()) {
|
|
details.Append(temp1);
|
|
}
|
|
|
|
details.Append(PRUnichar('\n'));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString("CertInfoStoredIn", info))) {
|
|
details.Append(info);
|
|
details.Append(PRUnichar(' '));
|
|
|
|
if (NS_SUCCEEDED(x509Proxy->GetTokenName(temp1)) && !temp1.IsEmpty()) {
|
|
details.Append(temp1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
the above produces the following output:
|
|
|
|
Issued to: $subjectName
|
|
Serial number: $serialNumber
|
|
Valid from: $starting_date to $expiration_date
|
|
Purposes: $purposes
|
|
Certificate Key usage: $usages
|
|
Email: $address(es)
|
|
Issued by: $issuerName
|
|
Stored in: $token
|
|
*/
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
/* readonly attribute string dbKey; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetDbKey(char * *aDbKey)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
SECItem key;
|
|
|
|
NS_ENSURE_ARG(aDbKey);
|
|
*aDbKey = nsnull;
|
|
key.len = NS_NSS_LONG*4+mCert->serialNumber.len+mCert->derIssuer.len;
|
|
key.data = (unsigned char *)nsMemory::Alloc(key.len);
|
|
if (!key.data)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
NS_NSS_PUT_LONG(0,key.data); // later put moduleID
|
|
NS_NSS_PUT_LONG(0,&key.data[NS_NSS_LONG]); // later put slotID
|
|
NS_NSS_PUT_LONG(mCert->serialNumber.len,&key.data[NS_NSS_LONG*2]);
|
|
NS_NSS_PUT_LONG(mCert->derIssuer.len,&key.data[NS_NSS_LONG*3]);
|
|
memcpy(&key.data[NS_NSS_LONG*4], mCert->serialNumber.data,
|
|
mCert->serialNumber.len);
|
|
memcpy(&key.data[NS_NSS_LONG*4+mCert->serialNumber.len],
|
|
mCert->derIssuer.data, mCert->derIssuer.len);
|
|
|
|
*aDbKey = NSSBase64_EncodeItem(nsnull, nsnull, 0, &key);
|
|
nsMemory::Free(key.data); // SECItem is a 'c' type without a destrutor
|
|
return (*aDbKey) ? NS_OK : NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* readonly attribute string windowTitle; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetWindowTitle(char * *aWindowTitle)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
NS_ENSURE_ARG(aWindowTitle);
|
|
if (mCert) {
|
|
if (mCert->nickname) {
|
|
*aWindowTitle = PL_strdup(mCert->nickname);
|
|
} else {
|
|
*aWindowTitle = CERT_GetCommonName(&mCert->subject);
|
|
if (!*aWindowTitle) {
|
|
if (mCert->subjectName) {
|
|
*aWindowTitle = PL_strdup(mCert->subjectName);
|
|
} else if (mCert->emailAddr) {
|
|
*aWindowTitle = PL_strdup(mCert->emailAddr);
|
|
} else {
|
|
*aWindowTitle = PL_strdup("");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
NS_ERROR("Somehow got nsnull for mCertificate in nsNSSCertificate.");
|
|
*aWindowTitle = nsnull;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetNickname(nsAString &aNickname)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
if (mCert->nickname) {
|
|
CopyUTF8toUTF16(mCert->nickname, aNickname);
|
|
} else {
|
|
nsresult rv;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv) || !nssComponent) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nssComponent->GetPIPNSSBundleString("CertNoNickname", aNickname);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetEmailAddress(nsAString &aEmailAddress)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
if (mCert->emailAddr) {
|
|
CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
|
|
} else {
|
|
nsresult rv;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv) || !nssComponent) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nssComponent->GetPIPNSSBundleString("CertNoEmailAddress", aEmailAddress);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetEmailAddresses(PRUint32 *aLength, PRUnichar*** aAddresses)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
NS_ENSURE_ARG(aLength);
|
|
NS_ENSURE_ARG(aAddresses);
|
|
|
|
*aLength = 0;
|
|
|
|
const char *aAddr;
|
|
for (aAddr = CERT_GetFirstEmailAddress(mCert)
|
|
;
|
|
aAddr
|
|
;
|
|
aAddr = CERT_GetNextEmailAddress(mCert, aAddr))
|
|
{
|
|
++(*aLength);
|
|
}
|
|
|
|
*aAddresses = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * (*aLength));
|
|
if (!*aAddresses)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
PRUint32 iAddr;
|
|
for (aAddr = CERT_GetFirstEmailAddress(mCert), iAddr = 0
|
|
;
|
|
aAddr
|
|
;
|
|
aAddr = CERT_GetNextEmailAddress(mCert, aAddr), ++iAddr)
|
|
{
|
|
(*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr));
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::ContainsEmailAddress(const nsAString &aEmailAddress, PRBool *result)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
NS_ENSURE_ARG(result);
|
|
*result = PR_FALSE;
|
|
|
|
const char *aAddr = nsnull;
|
|
for (aAddr = CERT_GetFirstEmailAddress(mCert)
|
|
;
|
|
aAddr
|
|
;
|
|
aAddr = CERT_GetNextEmailAddress(mCert, aAddr))
|
|
{
|
|
NS_ConvertUTF8toUTF16 certAddr(aAddr);
|
|
ToLowerCase(certAddr);
|
|
|
|
nsAutoString testAddr(aEmailAddress);
|
|
ToLowerCase(testAddr);
|
|
|
|
if (certAddr == testAddr)
|
|
{
|
|
*result = PR_TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetCommonName(nsAString &aCommonName)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aCommonName.Truncate();
|
|
if (mCert) {
|
|
char *commonName = CERT_GetCommonName(&mCert->subject);
|
|
if (commonName) {
|
|
aCommonName = NS_ConvertUTF8toUTF16(commonName);
|
|
PORT_Free(commonName);
|
|
} /*else {
|
|
*aCommonName = ToNewUnicode(NS_LITERAL_STRING("<not set>")),
|
|
}*/
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetOrganization(nsAString &aOrganization)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aOrganization.Truncate();
|
|
if (mCert) {
|
|
char *organization = CERT_GetOrgName(&mCert->subject);
|
|
if (organization) {
|
|
aOrganization = NS_ConvertUTF8toUTF16(organization);
|
|
PORT_Free(organization);
|
|
} /*else {
|
|
*aOrganization = ToNewUnicode(NS_LITERAL_STRING("<not set>")),
|
|
}*/
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerCommonName(nsAString &aCommonName)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aCommonName.Truncate();
|
|
if (mCert) {
|
|
char *commonName = CERT_GetCommonName(&mCert->issuer);
|
|
if (commonName) {
|
|
aCommonName = NS_ConvertUTF8toUTF16(commonName);
|
|
PORT_Free(commonName);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerOrganization(nsAString &aOrganization)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aOrganization.Truncate();
|
|
if (mCert) {
|
|
char *organization = CERT_GetOrgName(&mCert->issuer);
|
|
if (organization) {
|
|
aOrganization = NS_ConvertUTF8toUTF16(organization);
|
|
PORT_Free(organization);
|
|
} else {
|
|
return GetIssuerCommonName(aOrganization);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerOrganizationUnit(nsAString &aOrganizationUnit)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aOrganizationUnit.Truncate();
|
|
if (mCert) {
|
|
char *organizationUnit = CERT_GetOrgUnitName(&mCert->issuer);
|
|
if (organizationUnit) {
|
|
aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit);
|
|
PORT_Free(organizationUnit);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute nsIX509Cert issuer; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuer(nsIX509Cert * *aIssuer)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
NS_ENSURE_ARG(aIssuer);
|
|
*aIssuer = nsnull;
|
|
CERTCertificate *issuer;
|
|
issuer = CERT_FindCertIssuer(mCert, PR_Now(), certUsageSSLClient);
|
|
if (issuer) {
|
|
nsCOMPtr<nsIX509Cert> cert = new nsNSSCertificate(issuer);
|
|
*aIssuer = cert;
|
|
NS_ADDREF(*aIssuer);
|
|
CERT_DestroyCertificate(issuer);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetOrganizationalUnit(nsAString &aOrganizationalUnit)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aOrganizationalUnit.Truncate();
|
|
if (mCert) {
|
|
char *orgunit = CERT_GetOrgUnitName(&mCert->subject);
|
|
if (orgunit) {
|
|
aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit);
|
|
PORT_Free(orgunit);
|
|
} /*else {
|
|
*aOrganizationalUnit = ToNewUnicode(NS_LITERAL_STRING("<not set>")),
|
|
}*/
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/*
|
|
* nsIEnumerator getChain();
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetChain(nsIArray **_rvChain)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
NS_ENSURE_ARG(_rvChain);
|
|
nsresult rv;
|
|
/* Get the cert chain from NSS */
|
|
CERTCertList *nssChain = NULL;
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname));
|
|
nssChain = CERT_GetCertChainFromCert(mCert, PR_Now(), certUsageSSLClient);
|
|
if (!nssChain)
|
|
return NS_ERROR_FAILURE;
|
|
/* enumerate the chain for scripting purposes */
|
|
nsCOMPtr<nsIMutableArray> array =
|
|
do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
|
|
if (NS_FAILED(rv)) {
|
|
goto done;
|
|
}
|
|
CERTCertListNode *node;
|
|
for (node = CERT_LIST_HEAD(nssChain);
|
|
!CERT_LIST_END(node, nssChain);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("adding %s to chain\n", node->cert->nickname));
|
|
nsCOMPtr<nsIX509Cert> cert = new nsNSSCertificate(node->cert);
|
|
array->AppendElement(cert, PR_FALSE);
|
|
}
|
|
*_rvChain = array;
|
|
NS_IF_ADDREF(*_rvChain);
|
|
rv = NS_OK;
|
|
done:
|
|
if (nssChain)
|
|
CERT_DestroyCertList(nssChain);
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetAllTokenNames(PRUint32 *aLength, PRUnichar*** aTokenNames)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
NS_ENSURE_ARG(aLength);
|
|
NS_ENSURE_ARG(aTokenNames);
|
|
*aLength = 0;
|
|
*aTokenNames = NULL;
|
|
|
|
/* Get the slots from NSS */
|
|
PK11SlotList *slots = NULL;
|
|
PK11SlotListCleaner slotCleaner(slots);
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting slots for \"%s\"\n", mCert->nickname));
|
|
slots = PK11_GetAllSlotsForCert(mCert, NULL);
|
|
if (!slots) {
|
|
if (PORT_GetError() == SEC_ERROR_NO_TOKEN)
|
|
return NS_OK; // List of slots is empty, return empty array
|
|
else
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* read the token names from slots */
|
|
PK11SlotListElement *le;
|
|
|
|
for (le = slots->head; le; le = le->next) {
|
|
++(*aLength);
|
|
}
|
|
|
|
*aTokenNames = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * (*aLength));
|
|
if (!*aTokenNames) {
|
|
*aLength = 0;
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
PRUint32 iToken;
|
|
for (le = slots->head, iToken = 0; le; le = le->next, ++iToken) {
|
|
char *token = PK11_GetTokenName(le->slot);
|
|
(*aTokenNames)[iToken] = ToNewUnicode(NS_ConvertUTF8toUTF16(token));
|
|
if (!(*aTokenNames)[iToken]) {
|
|
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iToken, *aTokenNames);
|
|
*aLength = 0;
|
|
*aTokenNames = NULL;
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSubjectName(nsAString &_subjectName)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
_subjectName.Truncate();
|
|
if (mCert->subjectName) {
|
|
_subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName);
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerName(nsAString &_issuerName)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
_issuerName.Truncate();
|
|
if (mCert->issuerName) {
|
|
_issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName);
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSerialNumber(nsAString &_serialNumber)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
_serialNumber.Truncate();
|
|
char *tmpstr = CERT_Hexify(&mCert->serialNumber, 1);
|
|
if (tmpstr) {
|
|
_serialNumber = NS_ConvertASCIItoUTF16(tmpstr);
|
|
PORT_Free(tmpstr);
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSha1Fingerprint(nsAString &_sha1Fingerprint)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
_sha1Fingerprint.Truncate();
|
|
unsigned char fingerprint[20];
|
|
SECItem fpItem;
|
|
memset(fingerprint, 0, sizeof fingerprint);
|
|
PK11_HashBuf(SEC_OID_SHA1, fingerprint,
|
|
mCert->derCert.data, mCert->derCert.len);
|
|
fpItem.data = fingerprint;
|
|
fpItem.len = SHA1_LENGTH;
|
|
char *fpStr = CERT_Hexify(&fpItem, 1);
|
|
if (fpStr) {
|
|
_sha1Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
|
|
PORT_Free(fpStr);
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetMd5Fingerprint(nsAString &_md5Fingerprint)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
_md5Fingerprint.Truncate();
|
|
unsigned char fingerprint[20];
|
|
SECItem fpItem;
|
|
memset(fingerprint, 0, sizeof fingerprint);
|
|
PK11_HashBuf(SEC_OID_MD5, fingerprint,
|
|
mCert->derCert.data, mCert->derCert.len);
|
|
fpItem.data = fingerprint;
|
|
fpItem.len = MD5_LENGTH;
|
|
char *fpStr = CERT_Hexify(&fpItem, 1);
|
|
if (fpStr) {
|
|
_md5Fingerprint = NS_ConvertASCIItoUTF16(fpStr);
|
|
PORT_Free(fpStr);
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetTokenName(nsAString &aTokenName)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aTokenName.Truncate();
|
|
if (mCert) {
|
|
// HACK alert
|
|
// When the trust of a builtin cert is modified, NSS copies it into the
|
|
// cert db. At this point, it is now "managed" by the user, and should
|
|
// not be listed with the builtins. However, in the collection code
|
|
// used by PK11_ListCerts, the cert is found in the temp db, where it
|
|
// has been loaded from the token. Though the trust is correct (grabbed
|
|
// from the cert db), the source is wrong. I believe this is a safe
|
|
// way to work around this.
|
|
if (mCert->slot) {
|
|
char *token = PK11_GetTokenName(mCert->slot);
|
|
if (token) {
|
|
aTokenName = NS_ConvertUTF8toUTF16(token);
|
|
}
|
|
} else {
|
|
nsresult rv;
|
|
nsAutoString tok;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
rv = nssComponent->GetPIPNSSBundleString("InternalToken", tok);
|
|
if (NS_SUCCEEDED(rv))
|
|
aTokenName = tok;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetRawDER(PRUint32 *aLength, PRUint8 **aArray)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
if (mCert) {
|
|
*aArray = (PRUint8*)nsMemory::Alloc(mCert->derCert.len);
|
|
if (*aArray) {
|
|
memcpy(*aArray, mCert->derCert.data, mCert->derCert.len);
|
|
*aLength = mCert->derCert.len;
|
|
return NS_OK;
|
|
}
|
|
}
|
|
*aLength = 0;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::ExportAsCMS(PRUint32 chainMode,
|
|
PRUint32 *aLength, PRUint8 **aArray)
|
|
{
|
|
NS_ENSURE_ARG(aLength);
|
|
NS_ENSURE_ARG(aArray);
|
|
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
if (!mCert)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
switch (chainMode) {
|
|
case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly:
|
|
case nsIX509Cert3::CMS_CHAIN_MODE_CertChain:
|
|
case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot:
|
|
break;
|
|
default:
|
|
return NS_ERROR_INVALID_ARG;
|
|
};
|
|
|
|
PLArenaPool *arena = PORT_NewArena(1024);
|
|
PLArenaPoolCleanerFalseParam arenaCleaner(arena);
|
|
if (!arena) {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
|
("nsNSSCertificate::ExportAsCMS - out of memory\n"));
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
NSSCMSMessage *cmsg = NSS_CMSMessage_Create(nsnull);
|
|
NSSCMSMessageCleaner cmsgCleaner(cmsg);
|
|
if (!cmsg) {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
|
("nsNSSCertificate::ExportAsCMS - can't create CMS message\n"));
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
/*
|
|
* first, create SignedData with the certificate only (no chain)
|
|
*/
|
|
NSSCMSSignedData *sigd = NSS_CMSSignedData_CreateCertsOnly(cmsg, mCert, PR_FALSE);
|
|
NSSCMSSignedDataCleaner sigdCleaner(sigd);
|
|
if (!sigd) {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
|
("nsNSSCertificate::ExportAsCMS - can't create SignedData\n"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us
|
|
* to specify the inclusion of the root, but CERT_CertChainFromCert() does.
|
|
* Since CERT_CertChainFromCert() also includes the certificate itself,
|
|
* we have to start at the issuing cert (to avoid duplicate certs
|
|
* in the SignedData).
|
|
*/
|
|
if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain ||
|
|
chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) {
|
|
CERTCertificate *issuerCert = CERT_FindCertIssuer(mCert, PR_Now(), certUsageAnyCA);
|
|
CERTCertificateCleaner issuerCertCleaner(issuerCert);
|
|
/*
|
|
* the issuerCert of a self signed root is the cert itself,
|
|
* so make sure we're not adding duplicates, again
|
|
*/
|
|
if (issuerCert && issuerCert != mCert) {
|
|
PRBool includeRoot =
|
|
(chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot);
|
|
CERTCertificateList *certChain = CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot);
|
|
CERTCertificateListCleaner certChainCleaner(certChain);
|
|
if (certChain) {
|
|
if (NSS_CMSSignedData_AddCertList(sigd, certChain) == SECSuccess) {
|
|
certChainCleaner.detach();
|
|
}
|
|
else {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
|
("nsNSSCertificate::ExportAsCMS - can't add chain\n"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
else {
|
|
/* try to add the issuerCert, at least */
|
|
if (NSS_CMSSignedData_AddCertificate(sigd, issuerCert)
|
|
== SECSuccess) {
|
|
issuerCertCleaner.detach();
|
|
}
|
|
else {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
|
("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
|
|
if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)
|
|
== SECSuccess) {
|
|
sigdCleaner.detach();
|
|
}
|
|
else {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
|
("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
SECItem certP7 = { siBuffer, nsnull, 0 };
|
|
NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(cmsg, nsnull, nsnull, &certP7, arena,
|
|
nsnull, nsnull, nsnull, nsnull, nsnull,
|
|
nsnull);
|
|
if (!ecx) {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
|
("nsNSSCertificate::ExportAsCMS - can't create encoder context\n"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
|
("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n"));
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
*aArray = (PRUint8*)nsMemory::Alloc(certP7.len);
|
|
if (!*aArray)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
memcpy(*aArray, certP7.data, certP7.len);
|
|
*aLength = certP7.len;
|
|
return NS_OK;
|
|
}
|
|
|
|
CERTCertificate *
|
|
nsNSSCertificate::GetCert()
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return nsnull;
|
|
|
|
return (mCert) ? CERT_DupCertificate(mCert) : nsnull;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetValidity(nsIX509CertValidity **aValidity)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
NS_ENSURE_ARG(aValidity);
|
|
nsX509CertValidity *validity = new nsX509CertValidity(mCert);
|
|
if (nsnull == validity)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF(validity);
|
|
*aValidity = static_cast<nsIX509CertValidity*>(validity);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::VerifyForUsage(PRUint32 usage, PRUint32 *verificationResult)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
NS_ENSURE_ARG(verificationResult);
|
|
|
|
SECCertificateUsage nss_usage;
|
|
|
|
switch (usage)
|
|
{
|
|
case CERT_USAGE_SSLClient:
|
|
nss_usage = certificateUsageSSLClient;
|
|
break;
|
|
|
|
case CERT_USAGE_SSLServer:
|
|
nss_usage = certificateUsageSSLServer;
|
|
break;
|
|
|
|
case CERT_USAGE_SSLServerWithStepUp:
|
|
nss_usage = certificateUsageSSLServerWithStepUp;
|
|
break;
|
|
|
|
case CERT_USAGE_SSLCA:
|
|
nss_usage = certificateUsageSSLCA;
|
|
break;
|
|
|
|
case CERT_USAGE_EmailSigner:
|
|
nss_usage = certificateUsageEmailSigner;
|
|
break;
|
|
|
|
case CERT_USAGE_EmailRecipient:
|
|
nss_usage = certificateUsageEmailRecipient;
|
|
break;
|
|
|
|
case CERT_USAGE_ObjectSigner:
|
|
nss_usage = certificateUsageObjectSigner;
|
|
break;
|
|
|
|
case CERT_USAGE_UserCertImport:
|
|
nss_usage = certificateUsageUserCertImport;
|
|
break;
|
|
|
|
case CERT_USAGE_VerifyCA:
|
|
nss_usage = certificateUsageVerifyCA;
|
|
break;
|
|
|
|
case CERT_USAGE_ProtectedObjectSigner:
|
|
nss_usage = certificateUsageProtectedObjectSigner;
|
|
break;
|
|
|
|
case CERT_USAGE_StatusResponder:
|
|
nss_usage = certificateUsageStatusResponder;
|
|
break;
|
|
|
|
case CERT_USAGE_AnyCA:
|
|
nss_usage = certificateUsageAnyCA;
|
|
break;
|
|
|
|
default:
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
|
|
|
|
if (CERT_VerifyCertificateNow(defaultcertdb, mCert, PR_TRUE,
|
|
nss_usage, NULL, NULL) == SECSuccess)
|
|
{
|
|
*verificationResult = VERIFIED_OK;
|
|
}
|
|
else
|
|
{
|
|
int err = PR_GetError();
|
|
|
|
// this list was cloned from verifyFailed
|
|
|
|
switch (err)
|
|
{
|
|
case SEC_ERROR_INADEQUATE_KEY_USAGE:
|
|
case SEC_ERROR_INADEQUATE_CERT_TYPE:
|
|
*verificationResult = USAGE_NOT_ALLOWED;
|
|
break;
|
|
|
|
case SEC_ERROR_REVOKED_CERTIFICATE:
|
|
*verificationResult = CERT_REVOKED;
|
|
break;
|
|
|
|
case SEC_ERROR_EXPIRED_CERTIFICATE:
|
|
*verificationResult = CERT_EXPIRED;
|
|
break;
|
|
|
|
case SEC_ERROR_UNTRUSTED_CERT:
|
|
*verificationResult = CERT_NOT_TRUSTED;
|
|
break;
|
|
|
|
case SEC_ERROR_UNTRUSTED_ISSUER:
|
|
*verificationResult = ISSUER_NOT_TRUSTED;
|
|
break;
|
|
|
|
case SEC_ERROR_UNKNOWN_ISSUER:
|
|
*verificationResult = ISSUER_UNKNOWN;
|
|
break;
|
|
|
|
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
|
*verificationResult = INVALID_CA;
|
|
break;
|
|
|
|
case SEC_ERROR_CERT_USAGES_INVALID:
|
|
default:
|
|
*verificationResult = NOT_VERIFIED_UNKNOWN;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetUsagesArray(PRBool ignoreOcsp,
|
|
PRUint32 *_verified,
|
|
PRUint32 *_count,
|
|
PRUnichar ***_usages)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
nsresult rv;
|
|
const int max_usages = 13;
|
|
PRUnichar *tmpUsages[max_usages];
|
|
const char *suffix = "";
|
|
PRUint32 tmpCount;
|
|
nsUsageArrayHelper uah(mCert);
|
|
rv = uah.GetUsagesArray(suffix, ignoreOcsp, max_usages, _verified, &tmpCount, tmpUsages);
|
|
NS_ENSURE_SUCCESS(rv,rv);
|
|
if (tmpCount > 0) {
|
|
*_usages = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * tmpCount);
|
|
if (!*_usages)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
for (PRUint32 i=0; i<tmpCount; i++) {
|
|
(*_usages)[i] = tmpUsages[i];
|
|
}
|
|
*_count = tmpCount;
|
|
return NS_OK;
|
|
}
|
|
*_usages = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *));
|
|
if (!*_usages)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
*_count = 0;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::RequestUsagesArrayAsync(nsICertVerificationListener *aResultListener)
|
|
{
|
|
if (!aResultListener)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCertVerificationJob *job = new nsCertVerificationJob;
|
|
if (!job)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
job->mCert = this;
|
|
job->mListener = aResultListener;
|
|
|
|
nsresult rv = nsCertVerificationThread::addJob(job);
|
|
if (NS_FAILED(rv))
|
|
delete job;
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetUsagesString(PRBool ignoreOcsp,
|
|
PRUint32 *_verified,
|
|
nsAString &_usages)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
nsresult rv;
|
|
const int max_usages = 13;
|
|
PRUnichar *tmpUsages[max_usages];
|
|
const char *suffix = "_p";
|
|
PRUint32 tmpCount;
|
|
nsUsageArrayHelper uah(mCert);
|
|
rv = uah.GetUsagesArray(suffix, ignoreOcsp, max_usages, _verified, &tmpCount, tmpUsages);
|
|
NS_ENSURE_SUCCESS(rv,rv);
|
|
_usages.Truncate();
|
|
for (PRUint32 i=0; i<tmpCount; i++) {
|
|
if (i>0) _usages.AppendLiteral(",");
|
|
_usages.Append(tmpUsages[i]);
|
|
nsMemory::Free(tmpUsages[i]);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
#if defined(DEBUG_javi) || defined(DEBUG_jgmyers)
|
|
void
|
|
DumpASN1Object(nsIASN1Object *object, unsigned int level)
|
|
{
|
|
nsAutoString dispNameU, dispValU;
|
|
unsigned int i;
|
|
nsCOMPtr<nsIMutableArray> asn1Objects;
|
|
nsCOMPtr<nsISupports> isupports;
|
|
nsCOMPtr<nsIASN1Object> currObject;
|
|
PRBool processObjects;
|
|
PRUint32 numObjects;
|
|
|
|
for (i=0; i<level; i++)
|
|
printf (" ");
|
|
|
|
object->GetDisplayName(dispNameU);
|
|
nsCOMPtr<nsIASN1Sequence> sequence(do_QueryInterface(object));
|
|
if (sequence) {
|
|
printf ("%s ", NS_ConvertUTF16toUTF8(dispNameU).get());
|
|
sequence->GetIsValidContainer(&processObjects);
|
|
if (processObjects) {
|
|
printf("\n");
|
|
sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
asn1Objects->GetLength(&numObjects);
|
|
for (i=0; i<numObjects;i++) {
|
|
asn1Objects->QueryElementAt(i, NS_GET_IID(nsISupports), getter_AddRefs(currObject));
|
|
DumpASN1Object(currObject, level+1);
|
|
}
|
|
} else {
|
|
object->GetDisplayValue(dispValU);
|
|
printf("= %s\n", NS_ConvertUTF16toUTF8(dispValU).get());
|
|
}
|
|
} else {
|
|
object->GetDisplayValue(dispValU);
|
|
printf("%s = %s\n",NS_ConvertUTF16toUTF8(dispNameU).get(),
|
|
NS_ConvertUTF16toUTF8(dispValU).get());
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* readonly attribute nsIASN1Object ASN1Structure; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetASN1Structure(nsIASN1Object * *aASN1Structure)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
nsresult rv = NS_OK;
|
|
NS_ENSURE_ARG_POINTER(aASN1Structure);
|
|
if (mASN1Structure == nsnull) {
|
|
// First create the recursive structure os ASN1Objects
|
|
// which tells us the layout of the cert.
|
|
rv = CreateASN1Struct();
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
#ifdef DEBUG_javi
|
|
DumpASN1Object(mASN1Structure, 0);
|
|
#endif
|
|
}
|
|
*aASN1Structure = mASN1Structure;
|
|
NS_IF_ADDREF(*aASN1Structure);
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::Equals(nsIX509Cert *other, PRBool *result)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
NS_ENSURE_ARG(other);
|
|
NS_ENSURE_ARG(result);
|
|
|
|
nsCOMPtr<nsIX509Cert2> other2 = do_QueryInterface(other);
|
|
if (!other2)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
CERTCertificate *cert = other2->GetCert();
|
|
*result = (mCert == cert);
|
|
if (cert) {
|
|
CERT_DestroyCertificate(cert);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::SaveSMimeProfile()
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
if (isAlreadyShutDown())
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
if (SECSuccess != CERT_SaveSMimeProfile(mCert, nsnull, nsnull))
|
|
return NS_ERROR_FAILURE;
|
|
else
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
char* nsNSSCertificate::defaultServerNickname(CERTCertificate* cert)
|
|
{
|
|
nsNSSShutDownPreventionLock locker;
|
|
char* nickname = nsnull;
|
|
int count;
|
|
PRBool conflict;
|
|
char* servername = nsnull;
|
|
|
|
servername = CERT_GetCommonName(&cert->subject);
|
|
if (!servername) {
|
|
// Certs without common names are strange, but they do exist...
|
|
// Let's try to use another string for the nickname
|
|
servername = CERT_GetOrgUnitName(&cert->subject);
|
|
if (!servername) {
|
|
servername = CERT_GetOrgName(&cert->subject);
|
|
if (!servername) {
|
|
servername = CERT_GetLocalityName(&cert->subject);
|
|
if (!servername) {
|
|
servername = CERT_GetStateName(&cert->subject);
|
|
if (!servername) {
|
|
servername = CERT_GetCountryName(&cert->subject);
|
|
if (!servername) {
|
|
// We tried hard, there is nothing more we can do.
|
|
// A cert without any names doesn't really make sense.
|
|
return nsnull;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
count = 1;
|
|
while (1) {
|
|
if (count == 1) {
|
|
nickname = PR_smprintf("%s", servername);
|
|
}
|
|
else {
|
|
nickname = PR_smprintf("%s #%d", servername, count);
|
|
}
|
|
if (nickname == NULL) {
|
|
break;
|
|
}
|
|
|
|
conflict = SEC_CertNicknameConflict(nickname, &cert->derSubject,
|
|
cert->dbhandle);
|
|
if (!conflict) {
|
|
break;
|
|
}
|
|
PR_Free(nickname);
|
|
count++;
|
|
}
|
|
PR_FREEIF(servername);
|
|
return nickname;
|
|
}
|
|
|
|
NS_IMPL_THREADSAFE_ISUPPORTS1(nsNSSCertList, nsIX509CertList)
|
|
|
|
nsNSSCertList::nsNSSCertList(CERTCertList *certList, PRBool adopt)
|
|
{
|
|
if (certList) {
|
|
if (adopt) {
|
|
mCertList = certList;
|
|
} else {
|
|
mCertList = DupCertList(certList);
|
|
}
|
|
} else {
|
|
mCertList = CERT_NewCertList();
|
|
}
|
|
}
|
|
|
|
nsNSSCertList::~nsNSSCertList()
|
|
{
|
|
if (mCertList) {
|
|
CERT_DestroyCertList(mCertList);
|
|
}
|
|
}
|
|
|
|
/* void addCert (in nsIX509Cert cert); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertList::AddCert(nsIX509Cert *aCert)
|
|
{
|
|
/* This should be a query interface, but currently this his how the
|
|
* rest of PSM is working */
|
|
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
|
|
CERTCertificate *cert;
|
|
|
|
cert = nssCert->GetCert();
|
|
if (cert == nsnull) {
|
|
NS_ERROR("Somehow got nsnull for mCertificate in nsNSSCertificate.");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
if (mCertList == nsnull) {
|
|
NS_ERROR("Somehow got nsnull for mCertList in nsNSSCertList.");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
CERT_AddCertToListTail(mCertList,cert);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void deleteCert (in nsIX509Cert cert); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertList::DeleteCert(nsIX509Cert *aCert)
|
|
{
|
|
/* This should be a query interface, but currently this his how the
|
|
* rest of PSM is working */
|
|
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
|
|
CERTCertificate *cert = nssCert->GetCert();
|
|
CERTCertListNode *node;
|
|
|
|
if (cert == nsnull) {
|
|
NS_ERROR("Somehow got nsnull for mCertificate in nsNSSCertificate.");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
if (mCertList == nsnull) {
|
|
NS_ERROR("Somehow got nsnull for mCertList in nsNSSCertList.");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
for (node = CERT_LIST_HEAD(mCertList); !CERT_LIST_END(node,mCertList);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
if (node->cert == cert) {
|
|
CERT_RemoveCertListNode(node);
|
|
return NS_OK;
|
|
}
|
|
}
|
|
return NS_OK; /* should we fail if we couldn't find it? */
|
|
}
|
|
|
|
CERTCertList *
|
|
nsNSSCertList::DupCertList(CERTCertList *aCertList)
|
|
{
|
|
if (!aCertList)
|
|
return nsnull;
|
|
|
|
CERTCertList *newList = CERT_NewCertList();
|
|
|
|
if (newList == nsnull) {
|
|
return nsnull;
|
|
}
|
|
|
|
CERTCertListNode *node;
|
|
for (node = CERT_LIST_HEAD(aCertList); !CERT_LIST_END(node, aCertList);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
CERTCertificate *cert = CERT_DupCertificate(node->cert);
|
|
CERT_AddCertToListTail(newList, cert);
|
|
}
|
|
return newList;
|
|
}
|
|
|
|
void *
|
|
nsNSSCertList::GetRawCertList()
|
|
{
|
|
return mCertList;
|
|
}
|
|
|
|
/* nsISimpleEnumerator getEnumerator (); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertList::GetEnumerator(nsISimpleEnumerator **_retval)
|
|
{
|
|
nsCOMPtr<nsISimpleEnumerator> enumerator = new nsNSSCertListEnumerator(mCertList);
|
|
if (!enumerator) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
*_retval = enumerator;
|
|
NS_ADDREF(*_retval);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMPL_THREADSAFE_ISUPPORTS1(nsNSSCertListEnumerator,
|
|
nsISimpleEnumerator)
|
|
|
|
nsNSSCertListEnumerator::nsNSSCertListEnumerator(CERTCertList *certList)
|
|
{
|
|
mCertList = nsNSSCertList::DupCertList(certList);
|
|
}
|
|
|
|
nsNSSCertListEnumerator::~nsNSSCertListEnumerator()
|
|
{
|
|
if (mCertList) {
|
|
CERT_DestroyCertList(mCertList);
|
|
}
|
|
}
|
|
|
|
/* boolean hasMoreElements (); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertListEnumerator::HasMoreElements(PRBool *_retval)
|
|
{
|
|
NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
|
|
|
|
*_retval = !CERT_LIST_EMPTY(mCertList);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* nsISupports getNext(); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertListEnumerator::GetNext(nsISupports **_retval)
|
|
{
|
|
NS_ENSURE_TRUE(mCertList, NS_ERROR_FAILURE);
|
|
|
|
CERTCertListNode *node = CERT_LIST_HEAD(mCertList);
|
|
if (CERT_LIST_END(node, mCertList)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIX509Cert> nssCert = new nsNSSCertificate(node->cert);
|
|
if (!nssCert) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
*_retval = nssCert;
|
|
NS_ADDREF(*_retval);
|
|
|
|
CERT_RemoveCertListNode(node);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::Write(nsIObjectOutputStream* aStream)
|
|
{
|
|
NS_ENSURE_STATE(mCert);
|
|
nsresult rv = aStream->Write32(mCert->derCert.len);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
return aStream->WriteByteArray(mCert->derCert.data, mCert->derCert.len);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::Read(nsIObjectInputStream* aStream)
|
|
{
|
|
NS_ENSURE_STATE(!mCert);
|
|
|
|
PRUint32 len;
|
|
nsresult rv = aStream->Read32(&len);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
nsXPIDLCString str;
|
|
rv = aStream->ReadBytes(len, getter_Copies(str));
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
if (!InitFromDER(const_cast<char*>(str.get()), len)) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetInterfaces(PRUint32 *count, nsIID * **array)
|
|
{
|
|
*count = 0;
|
|
*array = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
|
|
{
|
|
*_retval = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetContractID(char * *aContractID)
|
|
{
|
|
*aContractID = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetClassDescription(char * *aClassDescription)
|
|
{
|
|
*aClassDescription = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetClassID(nsCID * *aClassID)
|
|
{
|
|
*aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
|
|
if (!*aClassID)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
return GetClassIDNoAlloc(*aClassID);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
|
|
{
|
|
*aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetFlags(PRUint32 *aFlags)
|
|
{
|
|
*aFlags = nsIClassInfo::THREADSAFE;
|
|
return NS_OK;
|
|
}
|
|
|
|
static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
|
|
{
|
|
*aClassIDNoAlloc = kNSSCertificateCID;
|
|
return NS_OK;
|
|
}
|