r=javi sr=alecf git-svn-id: svn://10.0.0.236/trunk@120930 18797224-902f-48f8-a5cc-f745e15eee43
4751 lines
143 KiB
C++
4751 lines
143 KiB
C++
/*
|
|
* 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 Netscape are
|
|
* Copyright (C) 2000 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Ian McGreer <mcgreer@netscape.com>
|
|
* Javier Delgadillo <javi@netscape.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the
|
|
* terms of the GNU General Public License Version 2 or later (the
|
|
* "GPL"), in which case the provisions of the GPL are applicable
|
|
* instead of those above. If you wish to allow use of your
|
|
* version of this file only under the terms of the GPL and not to
|
|
* allow others to use your version of this file under the MPL,
|
|
* indicate your decision by deleting the provisions above and
|
|
* replace them with the notice and other provisions required by
|
|
* the GPL. If you do not delete the provisions above, a recipient
|
|
* may use your version of this file under either the MPL or the
|
|
* GPL.
|
|
*
|
|
*/
|
|
|
|
#include "prmem.h"
|
|
#include "prerror.h"
|
|
#include "prprf.h"
|
|
|
|
#include "nsNSSComponent.h" // for PIPNSS string bundle calls.
|
|
#include "nsCOMPtr.h"
|
|
#include "nsISupportsArray.h"
|
|
#include "nsILocalFile.h"
|
|
#include "nsNSSCertificate.h"
|
|
#include "nsPKCS12Blob.h"
|
|
#include "nsPK11TokenDB.h"
|
|
#include "nsIX509Cert.h"
|
|
#include "nsINSSDialogs.h"
|
|
#include "nsNSSASN1Object.h"
|
|
#include "nsString.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsReadableUtils.h"
|
|
#include "nsIDateTimeFormat.h"
|
|
#include "nsDateTimeFormatCID.h"
|
|
#include "nsILocaleService.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIWindowWatcher.h"
|
|
#include "nsIPrompt.h"
|
|
#include "nsTime.h"
|
|
#include "nsIProxyObjectManager.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 "nsNSSCleaner.h"
|
|
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
|
|
NSSCleanupAutoPtrClass(CERTCertList, CERT_DestroyCertList)
|
|
|
|
#ifdef PR_LOGGING
|
|
extern PRLogModuleInfo* gPIPNSSLog;
|
|
#endif
|
|
|
|
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|
static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
|
|
static NS_DEFINE_CID(kLocaleServiceCID, NS_LOCALESERVICE_CID);
|
|
|
|
/*
|
|
* nsNSSCertTrust
|
|
*
|
|
* Class for maintaining trust flags for an NSS certificate.
|
|
*/
|
|
class nsNSSCertTrust
|
|
{
|
|
public:
|
|
nsNSSCertTrust();
|
|
nsNSSCertTrust(unsigned int ssl, unsigned int email, unsigned int objsign);
|
|
nsNSSCertTrust(CERTCertTrust *t);
|
|
virtual ~nsNSSCertTrust();
|
|
|
|
/* query */
|
|
PRBool HasAnyCA();
|
|
PRBool HasAnyUser();
|
|
PRBool HasCA(PRBool checkSSL = PR_TRUE,
|
|
PRBool checkEmail = PR_TRUE,
|
|
PRBool checkObjSign = PR_TRUE);
|
|
PRBool HasPeer(PRBool checkSSL = PR_TRUE,
|
|
PRBool checkEmail = PR_TRUE,
|
|
PRBool checkObjSign = PR_TRUE);
|
|
PRBool HasUser(PRBool checkSSL = PR_TRUE,
|
|
PRBool checkEmail = PR_TRUE,
|
|
PRBool checkObjSign = PR_TRUE);
|
|
PRBool HasTrustedCA(PRBool checkSSL = PR_TRUE,
|
|
PRBool checkEmail = PR_TRUE,
|
|
PRBool checkObjSign = PR_TRUE);
|
|
PRBool HasTrustedPeer(PRBool checkSSL = PR_TRUE,
|
|
PRBool checkEmail = PR_TRUE,
|
|
PRBool checkObjSign = PR_TRUE);
|
|
|
|
/* common defaults */
|
|
/* equivalent to "c,c,c" */
|
|
void SetValidCA();
|
|
/* equivalent to "C,C,C" */
|
|
void SetTrustedServerCA();
|
|
/* equivalent to "CT,CT,CT" */
|
|
void SetTrustedCA();
|
|
/* equivalent to "p,p,p" */
|
|
void SetValidPeer();
|
|
/* equivalent to "P,P,P" */
|
|
void SetTrustedPeer();
|
|
/* equivalent to "u,u,u" */
|
|
void SetUser();
|
|
|
|
/* general setters */
|
|
/* read: "p, P, c, C, T, u, w" */
|
|
void SetSSLTrust(PRBool peer, PRBool tPeer,
|
|
PRBool ca, PRBool tCA, PRBool tClientCA,
|
|
PRBool user, PRBool warn);
|
|
|
|
void SetEmailTrust(PRBool peer, PRBool tPeer,
|
|
PRBool ca, PRBool tCA, PRBool tClientCA,
|
|
PRBool user, PRBool warn);
|
|
|
|
void SetObjSignTrust(PRBool peer, PRBool tPeer,
|
|
PRBool ca, PRBool tCA, PRBool tClientCA,
|
|
PRBool user, PRBool warn);
|
|
|
|
/* set c <--> CT */
|
|
void AddCATrust(PRBool ssl, PRBool email, PRBool objSign);
|
|
/* set p <--> P */
|
|
void AddPeerTrust(PRBool ssl, PRBool email, PRBool objSign);
|
|
|
|
/* get it (const?) (shallow?) */
|
|
CERTCertTrust * GetTrust() { return &mTrust; }
|
|
|
|
private:
|
|
void addTrust(unsigned int *t, unsigned int v);
|
|
void removeTrust(unsigned int *t, unsigned int v);
|
|
PRBool hasTrust(unsigned int t, unsigned int v);
|
|
CERTCertTrust mTrust;
|
|
};
|
|
|
|
void
|
|
nsNSSCertTrust::AddCATrust(PRBool ssl, PRBool email, PRBool objSign)
|
|
{
|
|
if (ssl) {
|
|
addTrust(&mTrust.sslFlags, CERTDB_TRUSTED_CA);
|
|
addTrust(&mTrust.sslFlags, CERTDB_TRUSTED_CLIENT_CA);
|
|
}
|
|
if (email) {
|
|
addTrust(&mTrust.emailFlags, CERTDB_TRUSTED_CA);
|
|
addTrust(&mTrust.emailFlags, CERTDB_TRUSTED_CLIENT_CA);
|
|
}
|
|
if (objSign) {
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_TRUSTED_CA);
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_TRUSTED_CLIENT_CA);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::AddPeerTrust(PRBool ssl, PRBool email, PRBool objSign)
|
|
{
|
|
if (ssl)
|
|
addTrust(&mTrust.sslFlags, CERTDB_TRUSTED);
|
|
if (email)
|
|
addTrust(&mTrust.emailFlags, CERTDB_TRUSTED);
|
|
if (objSign)
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_TRUSTED);
|
|
}
|
|
|
|
nsNSSCertTrust::nsNSSCertTrust()
|
|
{
|
|
memset(&mTrust, 0, sizeof(CERTCertTrust));
|
|
}
|
|
|
|
nsNSSCertTrust::nsNSSCertTrust(unsigned int ssl,
|
|
unsigned int email,
|
|
unsigned int objsign)
|
|
{
|
|
memset(&mTrust, 0, sizeof(CERTCertTrust));
|
|
addTrust(&mTrust.sslFlags, ssl);
|
|
addTrust(&mTrust.emailFlags, email);
|
|
addTrust(&mTrust.objectSigningFlags, objsign);
|
|
}
|
|
|
|
nsNSSCertTrust::nsNSSCertTrust(CERTCertTrust *t)
|
|
{
|
|
if (t)
|
|
memcpy(&mTrust, t, sizeof(CERTCertTrust));
|
|
else
|
|
memset(&mTrust, 0, sizeof(CERTCertTrust));
|
|
}
|
|
|
|
nsNSSCertTrust::~nsNSSCertTrust()
|
|
{
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::SetSSLTrust(PRBool peer, PRBool tPeer,
|
|
PRBool ca, PRBool tCA, PRBool tClientCA,
|
|
PRBool user, PRBool warn)
|
|
{
|
|
mTrust.sslFlags = 0;
|
|
if (peer || tPeer)
|
|
addTrust(&mTrust.sslFlags, CERTDB_VALID_PEER);
|
|
if (tPeer)
|
|
addTrust(&mTrust.sslFlags, CERTDB_TRUSTED);
|
|
if (ca || tCA)
|
|
addTrust(&mTrust.sslFlags, CERTDB_VALID_CA);
|
|
if (tClientCA)
|
|
addTrust(&mTrust.sslFlags, CERTDB_TRUSTED_CLIENT_CA);
|
|
if (tCA)
|
|
addTrust(&mTrust.sslFlags, CERTDB_TRUSTED_CA);
|
|
if (user)
|
|
addTrust(&mTrust.sslFlags, CERTDB_USER);
|
|
if (warn)
|
|
addTrust(&mTrust.sslFlags, CERTDB_SEND_WARN);
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::SetEmailTrust(PRBool peer, PRBool tPeer,
|
|
PRBool ca, PRBool tCA, PRBool tClientCA,
|
|
PRBool user, PRBool warn)
|
|
{
|
|
mTrust.emailFlags = 0;
|
|
if (peer || tPeer)
|
|
addTrust(&mTrust.emailFlags, CERTDB_VALID_PEER);
|
|
if (tPeer)
|
|
addTrust(&mTrust.emailFlags, CERTDB_TRUSTED);
|
|
if (ca || tCA)
|
|
addTrust(&mTrust.emailFlags, CERTDB_VALID_CA);
|
|
if (tClientCA)
|
|
addTrust(&mTrust.emailFlags, CERTDB_TRUSTED_CLIENT_CA);
|
|
if (tCA)
|
|
addTrust(&mTrust.emailFlags, CERTDB_TRUSTED_CA);
|
|
if (user)
|
|
addTrust(&mTrust.emailFlags, CERTDB_USER);
|
|
if (warn)
|
|
addTrust(&mTrust.emailFlags, CERTDB_SEND_WARN);
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::SetObjSignTrust(PRBool peer, PRBool tPeer,
|
|
PRBool ca, PRBool tCA, PRBool tClientCA,
|
|
PRBool user, PRBool warn)
|
|
{
|
|
mTrust.objectSigningFlags = 0;
|
|
if (peer || tPeer)
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_VALID_PEER);
|
|
if (tPeer)
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_TRUSTED);
|
|
if (ca || tCA)
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_VALID_CA);
|
|
if (tClientCA)
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_TRUSTED_CLIENT_CA);
|
|
if (tCA)
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_TRUSTED_CA);
|
|
if (user)
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_USER);
|
|
if (warn)
|
|
addTrust(&mTrust.objectSigningFlags, CERTDB_SEND_WARN);
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::SetValidCA()
|
|
{
|
|
SetSSLTrust(PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetEmailTrust(PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetObjSignTrust(PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::SetTrustedServerCA()
|
|
{
|
|
SetSSLTrust(PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_TRUE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetEmailTrust(PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_TRUE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetObjSignTrust(PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_TRUE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::SetTrustedCA()
|
|
{
|
|
SetSSLTrust(PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_TRUE, PR_TRUE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetEmailTrust(PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_TRUE, PR_TRUE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetObjSignTrust(PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_TRUE, PR_TRUE,
|
|
PR_FALSE, PR_FALSE);
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::SetValidPeer()
|
|
{
|
|
SetSSLTrust(PR_TRUE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetEmailTrust(PR_TRUE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetObjSignTrust(PR_TRUE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::SetTrustedPeer()
|
|
{
|
|
SetSSLTrust(PR_TRUE, PR_TRUE,
|
|
PR_FALSE, PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetEmailTrust(PR_TRUE, PR_TRUE,
|
|
PR_FALSE, PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
SetObjSignTrust(PR_TRUE, PR_TRUE,
|
|
PR_FALSE, PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE);
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::SetUser()
|
|
{
|
|
SetSSLTrust(PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_FALSE);
|
|
SetEmailTrust(PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_FALSE);
|
|
SetObjSignTrust(PR_FALSE, PR_FALSE,
|
|
PR_FALSE, PR_FALSE, PR_FALSE,
|
|
PR_TRUE, PR_FALSE);
|
|
}
|
|
|
|
PRBool
|
|
nsNSSCertTrust::HasAnyCA()
|
|
{
|
|
if (hasTrust(mTrust.sslFlags, CERTDB_VALID_CA) ||
|
|
hasTrust(mTrust.emailFlags, CERTDB_VALID_CA) ||
|
|
hasTrust(mTrust.objectSigningFlags, CERTDB_VALID_CA))
|
|
return PR_TRUE;
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool
|
|
nsNSSCertTrust::HasCA(PRBool checkSSL,
|
|
PRBool checkEmail,
|
|
PRBool checkObjSign)
|
|
{
|
|
if (checkSSL && !hasTrust(mTrust.sslFlags, CERTDB_VALID_CA))
|
|
return PR_FALSE;
|
|
if (checkEmail && !hasTrust(mTrust.emailFlags, CERTDB_VALID_CA))
|
|
return PR_FALSE;
|
|
if (checkObjSign && !hasTrust(mTrust.objectSigningFlags, CERTDB_VALID_CA))
|
|
return PR_FALSE;
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRBool
|
|
nsNSSCertTrust::HasPeer(PRBool checkSSL,
|
|
PRBool checkEmail,
|
|
PRBool checkObjSign)
|
|
{
|
|
if (checkSSL && !hasTrust(mTrust.sslFlags, CERTDB_VALID_PEER))
|
|
return PR_FALSE;
|
|
if (checkEmail && !hasTrust(mTrust.emailFlags, CERTDB_VALID_PEER))
|
|
return PR_FALSE;
|
|
if (checkObjSign && !hasTrust(mTrust.objectSigningFlags, CERTDB_VALID_PEER))
|
|
return PR_FALSE;
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRBool
|
|
nsNSSCertTrust::HasAnyUser()
|
|
{
|
|
if (hasTrust(mTrust.sslFlags, CERTDB_USER) ||
|
|
hasTrust(mTrust.emailFlags, CERTDB_USER) ||
|
|
hasTrust(mTrust.objectSigningFlags, CERTDB_USER))
|
|
return PR_TRUE;
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool
|
|
nsNSSCertTrust::HasUser(PRBool checkSSL,
|
|
PRBool checkEmail,
|
|
PRBool checkObjSign)
|
|
{
|
|
if (checkSSL && !hasTrust(mTrust.sslFlags, CERTDB_USER))
|
|
return PR_FALSE;
|
|
if (checkEmail && !hasTrust(mTrust.emailFlags, CERTDB_USER))
|
|
return PR_FALSE;
|
|
if (checkObjSign && !hasTrust(mTrust.objectSigningFlags, CERTDB_USER))
|
|
return PR_FALSE;
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRBool
|
|
nsNSSCertTrust::HasTrustedCA(PRBool checkSSL,
|
|
PRBool checkEmail,
|
|
PRBool checkObjSign)
|
|
{
|
|
if (checkSSL && !(hasTrust(mTrust.sslFlags, CERTDB_TRUSTED_CA) ||
|
|
hasTrust(mTrust.sslFlags, CERTDB_TRUSTED_CLIENT_CA)))
|
|
return PR_FALSE;
|
|
if (checkEmail && !(hasTrust(mTrust.emailFlags, CERTDB_TRUSTED_CA) ||
|
|
hasTrust(mTrust.emailFlags, CERTDB_TRUSTED_CLIENT_CA)))
|
|
return PR_FALSE;
|
|
if (checkObjSign &&
|
|
!(hasTrust(mTrust.objectSigningFlags, CERTDB_TRUSTED_CA) ||
|
|
hasTrust(mTrust.objectSigningFlags, CERTDB_TRUSTED_CLIENT_CA)))
|
|
return PR_FALSE;
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRBool
|
|
nsNSSCertTrust::HasTrustedPeer(PRBool checkSSL,
|
|
PRBool checkEmail,
|
|
PRBool checkObjSign)
|
|
{
|
|
if (checkSSL && !(hasTrust(mTrust.sslFlags, CERTDB_TRUSTED)))
|
|
return PR_FALSE;
|
|
if (checkEmail && !(hasTrust(mTrust.emailFlags, CERTDB_TRUSTED)))
|
|
return PR_FALSE;
|
|
if (checkObjSign &&
|
|
!(hasTrust(mTrust.objectSigningFlags, CERTDB_TRUSTED)))
|
|
return PR_FALSE;
|
|
return PR_TRUE;
|
|
}
|
|
|
|
void
|
|
nsNSSCertTrust::addTrust(unsigned int *t, unsigned int v)
|
|
{
|
|
*t |= v;
|
|
}
|
|
|
|
PRBool
|
|
nsNSSCertTrust::hasTrust(unsigned int t, unsigned int v)
|
|
{
|
|
return (t & v);
|
|
}
|
|
|
|
/* Header file */
|
|
class nsX509CertValidity : public nsIX509CertValidity
|
|
{
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIX509CERTVALIDITY
|
|
|
|
nsX509CertValidity();
|
|
nsX509CertValidity(CERTCertificate *cert);
|
|
virtual ~nsX509CertValidity();
|
|
/* additional members */
|
|
|
|
private:
|
|
PRTime mNotBefore, mNotAfter;
|
|
PRBool mTimesInitialized;
|
|
};
|
|
|
|
/* Implementation file */
|
|
NS_IMPL_THREADSAFE_ISUPPORTS1(nsX509CertValidity, nsIX509CertValidity)
|
|
|
|
nsX509CertValidity::nsX509CertValidity() : mTimesInitialized(PR_FALSE)
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
/* member initializers and constructor code */
|
|
}
|
|
|
|
nsX509CertValidity::nsX509CertValidity(CERTCertificate *cert) :
|
|
mTimesInitialized(PR_FALSE)
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
if (cert) {
|
|
SECStatus rv = CERT_GetCertTimes(cert, &mNotBefore, &mNotAfter);
|
|
if (rv == SECSuccess)
|
|
mTimesInitialized = PR_TRUE;
|
|
}
|
|
}
|
|
|
|
nsX509CertValidity::~nsX509CertValidity()
|
|
{
|
|
/* destructor code */
|
|
}
|
|
|
|
/* readonly attribute PRTime notBefore; */
|
|
NS_IMETHODIMP nsX509CertValidity::GetNotBefore(PRTime *aNotBefore)
|
|
{
|
|
NS_ENSURE_ARG(aNotBefore);
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
if (mTimesInitialized) {
|
|
*aNotBefore = mNotBefore;
|
|
rv = NS_OK;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/* readonly attribute PRTime notBeforeLocalTime; */
|
|
NS_IMETHODIMP nsX509CertValidity::GetNotBeforeLocalTime(PRUnichar **aNotBeforeLocalTime)
|
|
{
|
|
NS_ENSURE_ARG(aNotBeforeLocalTime);
|
|
|
|
if (!mTimesInitialized)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIDateTimeFormat> dateFormatter =
|
|
do_CreateInstance(kDateTimeFormatCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsAutoString date;
|
|
PRExplodedTime explodedTime;
|
|
PR_ExplodeTime(mNotBefore, PR_LocalTimeParameters, &explodedTime);
|
|
dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSecondsForce24Hour,
|
|
&explodedTime, date);
|
|
*aNotBeforeLocalTime = ToNewUnicode(date);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute PRTime notBeforeGMT; */
|
|
NS_IMETHODIMP nsX509CertValidity::GetNotBeforeGMT(PRUnichar **aNotBeforeGMT)
|
|
{
|
|
NS_ENSURE_ARG(aNotBeforeGMT);
|
|
|
|
if (!mTimesInitialized)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIDateTimeFormat> dateFormatter =
|
|
do_CreateInstance(kDateTimeFormatCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsAutoString date;
|
|
PRExplodedTime explodedTime;
|
|
PR_ExplodeTime(mNotBefore, PR_GMTParameters, &explodedTime);
|
|
dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSecondsForce24Hour,
|
|
&explodedTime, date);
|
|
*aNotBeforeGMT = ToNewUnicode(date);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute PRTime notAfter; */
|
|
NS_IMETHODIMP nsX509CertValidity::GetNotAfter(PRTime *aNotAfter)
|
|
{
|
|
NS_ENSURE_ARG(aNotAfter);
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
if (mTimesInitialized) {
|
|
*aNotAfter = mNotAfter;
|
|
rv = NS_OK;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/* readonly attribute PRTime notAfterLocalTime; */
|
|
NS_IMETHODIMP nsX509CertValidity::GetNotAfterLocalTime(PRUnichar **aNotAfterLocaltime)
|
|
{
|
|
NS_ENSURE_ARG(aNotAfterLocaltime);
|
|
|
|
if (!mTimesInitialized)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIDateTimeFormat> dateFormatter =
|
|
do_CreateInstance(kDateTimeFormatCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsAutoString date;
|
|
PRExplodedTime explodedTime;
|
|
PR_ExplodeTime(mNotAfter, PR_LocalTimeParameters, &explodedTime);
|
|
dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSecondsForce24Hour,
|
|
&explodedTime, date);
|
|
*aNotAfterLocaltime = ToNewUnicode(date);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute PRTime notAfterGMT; */
|
|
NS_IMETHODIMP nsX509CertValidity::GetNotAfterGMT(PRUnichar **aNotAfterGMT)
|
|
{
|
|
NS_ENSURE_ARG(aNotAfterGMT);
|
|
|
|
if (!mTimesInitialized)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIDateTimeFormat> dateFormatter =
|
|
do_CreateInstance(kDateTimeFormatCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsAutoString date;
|
|
PRExplodedTime explodedTime;
|
|
PR_ExplodeTime(mNotAfter, PR_GMTParameters, &explodedTime);
|
|
dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSecondsForce24Hour,
|
|
&explodedTime, date);
|
|
*aNotAfterGMT = ToNewUnicode(date);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* nsNSSCertificate */
|
|
|
|
NS_IMPL_THREADSAFE_ISUPPORTS1(nsNSSCertificate, nsIX509Cert)
|
|
|
|
nsNSSCertificate*
|
|
nsNSSCertificate::ConstructFromDER(char *certDER, int derLen)
|
|
{
|
|
if (!certDER || !derLen)
|
|
return nsnull;
|
|
|
|
CERTCertificate *aCert = CERT_DecodeCertFromPackage(certDER, derLen);
|
|
|
|
if (!aCert)
|
|
return nsnull;
|
|
|
|
if(aCert->dbhandle == nsnull)
|
|
{
|
|
aCert->dbhandle = CERT_GetDefaultCertDB();
|
|
}
|
|
|
|
// We don't want the new NSS cert to be dupped, therefore we create our instance
|
|
// with a NULL pointer first, and set the contained cert later.
|
|
|
|
nsNSSCertificate *newObject = new nsNSSCertificate(nsnull);
|
|
|
|
if (!newObject)
|
|
{
|
|
CERT_DestroyCertificate(aCert);
|
|
return nsnull;
|
|
}
|
|
|
|
newObject->mCert = aCert;
|
|
return newObject;
|
|
}
|
|
|
|
nsNSSCertificate::nsNSSCertificate(CERTCertificate *cert) :
|
|
mPermDelete(PR_FALSE),
|
|
mCertType(nsIX509Cert::UNKNOWN_CERT)
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
|
|
if (cert)
|
|
mCert = CERT_DupCertificate(cert);
|
|
else
|
|
mCert = nsnull;
|
|
}
|
|
|
|
nsNSSCertificate::~nsNSSCertificate()
|
|
{
|
|
if (mPermDelete) {
|
|
if (mCertType == nsNSSCertificate::USER_CERT) {
|
|
nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
|
|
PK11_DeleteTokenCertAndKey(mCert, cxt);
|
|
} else
|
|
#ifdef NSS_3_4
|
|
if (!PK11_IsReadOnly(mCert->slot))
|
|
#else
|
|
if (!mCert->slot)
|
|
#endif
|
|
{
|
|
// If the cert isn't a user cert and it is on an external token,
|
|
// then we'll just leave it as untrusted, but won't delete it
|
|
// from the cert db.
|
|
SEC_DeletePermCertificate(mCert);
|
|
}
|
|
} else {
|
|
if (mCert)
|
|
CERT_DestroyCertificate(mCert);
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::SetCertType(PRUint32 aCertType)
|
|
{
|
|
mCertType = aCertType;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::GetCertType(PRUint32 *aCertType)
|
|
{
|
|
*aCertType = mCertType;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::MarkForPermDeletion()
|
|
{
|
|
mPermDelete = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::FormatUIStrings(const nsAutoString &nickname, nsAutoString &nickWithSerial, nsAutoString &details)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv));
|
|
|
|
if (NS_FAILED(rv) || !proxyman) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
|
|
|
|
if (NS_FAILED(rv) || !nssComponent) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIX509Cert> x509 = do_QueryInterface(this);
|
|
if (!x509) {
|
|
return NS_ERROR_NO_INTERFACE;
|
|
}
|
|
|
|
nsCOMPtr<nsIX509Cert> x509Proxy;
|
|
proxyman->GetProxyForObject( NS_UI_THREAD_EVENTQ,
|
|
nsIX509Cert::GetIID(),
|
|
x509,
|
|
PROXY_SYNC | PROXY_ALWAYS,
|
|
getter_AddRefs(x509Proxy));
|
|
|
|
if (!x509Proxy) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
else {
|
|
rv = NS_OK;
|
|
|
|
nsAutoString info;
|
|
PRUnichar *temp1 = 0;
|
|
|
|
nickWithSerial.Append(nickname);
|
|
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertInfoIssuedFor").get(), info))) {
|
|
details.Append(info);
|
|
details.Append(NS_LITERAL_STRING("\n"));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(x509Proxy->GetSubjectName(&temp1)) && temp1 && nsCharTraits<PRUnichar>::length(temp1)) {
|
|
details.Append(NS_LITERAL_STRING(" "));
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSubject").get(), info))) {
|
|
details.Append(info);
|
|
details.Append(NS_LITERAL_STRING(": "));
|
|
}
|
|
details.Append(temp1);
|
|
nsMemory::Free(temp1);
|
|
details.Append(NS_LITERAL_STRING("\n"));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(x509Proxy->GetSerialNumber(&temp1)) && temp1 && nsCharTraits<PRUnichar>::length(temp1)) {
|
|
details.Append(NS_LITERAL_STRING(" "));
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSerialNo").get(), info))) {
|
|
details.Append(info);
|
|
details.Append(NS_LITERAL_STRING(": "));
|
|
}
|
|
details.Append(temp1);
|
|
|
|
nickWithSerial.Append(NS_LITERAL_STRING(" ["));
|
|
nickWithSerial.Append(temp1);
|
|
nickWithSerial.Append(NS_LITERAL_STRING("]"));
|
|
|
|
nsMemory::Free(temp1);
|
|
details.Append(NS_LITERAL_STRING("\n"));
|
|
}
|
|
|
|
|
|
{
|
|
nsCOMPtr<nsIX509CertValidity> validity;
|
|
nsCOMPtr<nsIX509CertValidity> originalValidity;
|
|
rv = x509Proxy->GetValidity(getter_AddRefs(originalValidity));
|
|
if (NS_SUCCEEDED(rv) && originalValidity) {
|
|
proxyman->GetProxyForObject( NS_UI_THREAD_EVENTQ,
|
|
nsIX509CertValidity::GetIID(),
|
|
originalValidity,
|
|
PROXY_SYNC | PROXY_ALWAYS,
|
|
getter_AddRefs(validity));
|
|
}
|
|
|
|
if (validity) {
|
|
details.Append(NS_LITERAL_STRING(" "));
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertInfoValid").get(), info))) {
|
|
details.Append(info);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(validity->GetNotBeforeLocalTime(&temp1)) && temp1 && nsCharTraits<PRUnichar>::length(temp1)) {
|
|
details.Append(NS_LITERAL_STRING(" "));
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertInfoFrom").get(), info))) {
|
|
details.Append(info);
|
|
}
|
|
details.Append(NS_LITERAL_STRING(" "));
|
|
details.Append(temp1);
|
|
nsMemory::Free(temp1);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(validity->GetNotAfterLocalTime(&temp1)) && temp1 && nsCharTraits<PRUnichar>::length(temp1)) {
|
|
details.Append(NS_LITERAL_STRING(" "));
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertInfoTo").get(), info))) {
|
|
details.Append(info);
|
|
}
|
|
details.Append(NS_LITERAL_STRING(" "));
|
|
details.Append(temp1);
|
|
nsMemory::Free(temp1);
|
|
}
|
|
|
|
details.Append(NS_LITERAL_STRING("\n"));
|
|
}
|
|
}
|
|
|
|
PRUint32 tempInt = 0;
|
|
if (NS_SUCCEEDED(x509Proxy->GetPurposes(&tempInt, &temp1)) && temp1 && nsCharTraits<PRUnichar>::length(temp1)) {
|
|
details.Append(NS_LITERAL_STRING(" "));
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertInfoPurposes").get(), info))) {
|
|
details.Append(info);
|
|
}
|
|
details.Append(NS_LITERAL_STRING(": "));
|
|
details.Append(temp1);
|
|
nsMemory::Free(temp1);
|
|
details.Append(NS_LITERAL_STRING("\n"));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertInfoIssuedBy").get(), info))) {
|
|
details.Append(info);
|
|
details.Append(NS_LITERAL_STRING("\n"));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(x509Proxy->GetIssuerName(&temp1)) && temp1 && nsCharTraits<PRUnichar>::length(temp1)) {
|
|
details.Append(NS_LITERAL_STRING(" "));
|
|
if (NS_SUCCEEDED(nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSubject").get(), info))) {
|
|
details.Append(info);
|
|
details.Append(NS_LITERAL_STRING(": "));
|
|
}
|
|
details.Append(temp1);
|
|
nsMemory::Free(temp1);
|
|
details.Append(NS_LITERAL_STRING("\n"));
|
|
}
|
|
|
|
/*
|
|
the above produces output the following output:
|
|
|
|
Issued to:
|
|
Subject: $subjectName
|
|
Serial number: $serialNumber
|
|
Valid from: $starting_date to $expriation_date
|
|
Purposes: $purposes
|
|
Issued by:
|
|
Subject: $issuerName
|
|
*/
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
|
|
#ifdef NSS_3_4
|
|
#define NS_NSS_LONG 4
|
|
#define NS_NSS_GET_LONG(x) ((((unsigned long)((x)[0])) << 24) | \
|
|
(((unsigned long)((x)[1])) << 16) | \
|
|
(((unsigned long)((x)[2])) << 8) | \
|
|
((unsigned long)((x)[3])) )
|
|
#define NS_NSS_PUT_LONG(src,dest) (dest)[0] = (((src) >> 24) & 0xff); \
|
|
(dest)[1] = (((src) >> 16) & 0xff); \
|
|
(dest)[2] = (((src) >> 8) & 0xff); \
|
|
(dest)[3] = ((src) & 0xff);
|
|
#endif
|
|
|
|
|
|
/* readonly attribute string dbKey; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetDbKey(char * *aDbKey)
|
|
{
|
|
SECItem key;
|
|
|
|
NS_ENSURE_ARG(aDbKey);
|
|
*aDbKey = nsnull;
|
|
#ifdef NSS_3_4
|
|
key.len = NS_NSS_LONG*4+mCert->serialNumber.len+mCert->derIssuer.len;
|
|
key.data = (unsigned char *)nsMemory::Alloc(key.len);
|
|
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);
|
|
#else
|
|
SECStatus srv;
|
|
srv = CERT_KeyFromIssuerAndSN(mCert->arena, &mCert->derIssuer,
|
|
&mCert->serialNumber, &key);
|
|
if (srv != SECSuccess) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
#endif
|
|
|
|
*aDbKey = NSSBase64_EncodeItem(nsnull, nsnull, 0, &key);
|
|
#ifdef NSS_3_4
|
|
nsMemory::Free(key.data); // SECItem is a 'c' type without a destrutor
|
|
#endif
|
|
return (*aDbKey) ? NS_OK : NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* readonly attribute string windowTitle; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetWindowTitle(char * *aWindowTitle)
|
|
{
|
|
NS_ENSURE_ARG(aWindowTitle);
|
|
if (mCert) {
|
|
if (mCert->nickname) {
|
|
*aWindowTitle = PL_strdup(mCert->nickname);
|
|
} else {
|
|
*aWindowTitle = CERT_GetCommonName(&mCert->subject);
|
|
if (!*aWindowTitle) {
|
|
*aWindowTitle = PL_strdup(mCert->subjectName);
|
|
}
|
|
}
|
|
} else {
|
|
NS_ASSERTION(0,"Somehow got nsnull for mCertificate in nsNSSCertificate.");
|
|
*aWindowTitle = nsnull;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute wstring nickname; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetNickname(PRUnichar **_nickname)
|
|
{
|
|
NS_ENSURE_ARG(_nickname);
|
|
const char *nickname = (mCert->nickname) ? mCert->nickname : "(no nickname)";
|
|
*_nickname = ToNewUnicode(nsDependentCString(nickname));
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute wstring emailAddress; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetEmailAddress(PRUnichar **_emailAddress)
|
|
{
|
|
NS_ENSURE_ARG(_emailAddress);
|
|
const char *email = (mCert->emailAddr) ? mCert->emailAddr : "(no email address)";
|
|
*_emailAddress = ToNewUnicode(nsDependentCString(email));
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetCommonName(PRUnichar **aCommonName)
|
|
{
|
|
NS_ENSURE_ARG(aCommonName);
|
|
*aCommonName = nsnull;
|
|
if (mCert) {
|
|
char *commonName = CERT_GetCommonName(&mCert->subject);
|
|
if (commonName) {
|
|
*aCommonName = ToNewUnicode(nsDependentCString(commonName));
|
|
} /*else {
|
|
*aCommonName = ToNewUnicode(NS_LITERAL_STRING("<not set>")),
|
|
}*/
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetOrganization(PRUnichar **aOrganization)
|
|
{
|
|
NS_ENSURE_ARG(aOrganization);
|
|
*aOrganization = nsnull;
|
|
if (mCert) {
|
|
char *organization = CERT_GetOrgName(&mCert->subject);
|
|
if (organization) {
|
|
*aOrganization = ToNewUnicode(nsDependentCString(organization));
|
|
} /*else {
|
|
*aOrganization = ToNewUnicode(NS_LITERAL_STRING("<not set>")),
|
|
}*/
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerCommonName(PRUnichar **aCommonName)
|
|
{
|
|
NS_ENSURE_ARG(aCommonName);
|
|
*aCommonName = nsnull;
|
|
if (mCert) {
|
|
char *commonName = CERT_GetCommonName(&mCert->issuer);
|
|
if (commonName) {
|
|
*aCommonName = ToNewUnicode(nsDependentCString(commonName));
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerOrganization(PRUnichar **aOrganization)
|
|
{
|
|
NS_ENSURE_ARG(aOrganization);
|
|
*aOrganization = nsnull;
|
|
if (mCert) {
|
|
char *organization = CERT_GetOrgName(&mCert->issuer);
|
|
if (organization) {
|
|
*aOrganization = ToNewUnicode(nsDependentCString(organization));
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerOrganizationUnit(PRUnichar **aOrganizationUnit)
|
|
{
|
|
NS_ENSURE_ARG(aOrganizationUnit);
|
|
*aOrganizationUnit = nsnull;
|
|
if (mCert) {
|
|
char *organizationUnit = CERT_GetOrgUnitName(&mCert->issuer);
|
|
if (organizationUnit) {
|
|
*aOrganizationUnit = ToNewUnicode(nsDependentCString(organizationUnit));
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute nsIX509Cert issuer; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuer(nsIX509Cert * *aIssuer)
|
|
{
|
|
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(PRUnichar **aOrganizationalUnit)
|
|
{
|
|
NS_ENSURE_ARG(aOrganizationalUnit);
|
|
*aOrganizationalUnit = nsnull;
|
|
if (mCert) {
|
|
char *orgunit = CERT_GetOrgUnitName(&mCert->subject);
|
|
if (orgunit) {
|
|
*aOrganizationalUnit = ToNewUnicode(nsDependentCString(orgunit));
|
|
} /*else {
|
|
*aOrganizationalUnit = ToNewUnicode(NS_LITERAL_STRING("<not set>")),
|
|
}*/
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/*
|
|
* nsIEnumerator getChain();
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetChain(nsISupportsArray **_rvChain)
|
|
{
|
|
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));
|
|
// XXX This function is buggy - if it can't find the issuer, it crashes
|
|
// on a null pointer. Will have to wait until it is fixed in NSS.
|
|
#ifdef NSS_CHAIN_BUG_FIXED
|
|
nssChain = CERT_GetCertChainFromCert(mCert, PR_Now(), certUsageSSLClient);
|
|
if (!nssChain)
|
|
return NS_ERROR_FAILURE;
|
|
/* enumerate the chain for scripting purposes */
|
|
nsCOMPtr<nsISupportsArray> array;
|
|
rv = NS_NewISupportsArray(getter_AddRefs(array));
|
|
if (NS_FAILED(rv)) {
|
|
goto done;
|
|
}
|
|
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);
|
|
}
|
|
#else // workaround here
|
|
CERTCertificate *cert = nsnull;
|
|
/* enumerate the chain for scripting purposes */
|
|
nsCOMPtr<nsISupportsArray> array;
|
|
rv = NS_NewISupportsArray(getter_AddRefs(array));
|
|
if (NS_FAILED(rv)) {
|
|
goto done;
|
|
}
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting chain for \"%s\"\n", mCert->nickname));
|
|
cert = CERT_DupCertificate(mCert);
|
|
while (cert) {
|
|
nsCOMPtr<nsIX509Cert> pipCert = new nsNSSCertificate(cert);
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("adding %s to chain\n", cert->nickname));
|
|
array->AppendElement(pipCert);
|
|
PRBool wantToBreak = PR_FALSE;
|
|
CERTCertificate *next_cert = nsnull;
|
|
if (SECITEM_CompareItem(&cert->derIssuer, &cert->derSubject) == SECEqual) {
|
|
wantToBreak = PR_TRUE;
|
|
}
|
|
else {
|
|
next_cert = CERT_FindCertIssuer(cert, PR_Now(), certUsageSSLClient);
|
|
}
|
|
CERT_DestroyCertificate(cert);
|
|
if (wantToBreak) {
|
|
break;
|
|
}
|
|
cert = next_cert;
|
|
}
|
|
#endif // NSS_CHAIN_BUG_FIXED
|
|
*_rvChain = array;
|
|
NS_IF_ADDREF(*_rvChain);
|
|
rv = NS_OK;
|
|
done:
|
|
if (nssChain)
|
|
CERT_DestroyCertList(nssChain);
|
|
return rv;
|
|
}
|
|
|
|
/* readonly attribute wstring subjectName; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSubjectName(PRUnichar **_subjectName)
|
|
{
|
|
NS_ENSURE_ARG(_subjectName);
|
|
*_subjectName = nsnull;
|
|
if (mCert->subjectName) {
|
|
*_subjectName = ToNewUnicode(nsDependentCString(mCert->subjectName));
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* readonly attribute wstring issuerName; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuerName(PRUnichar **_issuerName)
|
|
{
|
|
NS_ENSURE_ARG(_issuerName);
|
|
*_issuerName = nsnull;
|
|
if (mCert->issuerName) {
|
|
*_issuerName = ToNewUnicode(nsDependentCString(mCert->issuerName));
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* readonly attribute wstring serialNumber; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSerialNumber(PRUnichar **_serialNumber)
|
|
{
|
|
NS_ENSURE_ARG(_serialNumber);
|
|
*_serialNumber = nsnull;
|
|
nsXPIDLCString tmpstr; tmpstr.Adopt(CERT_Hexify(&mCert->serialNumber, 1));
|
|
if (tmpstr.get()) {
|
|
*_serialNumber = ToNewUnicode(tmpstr);
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* readonly attribute wstring rsaPubModulus; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetRsaPubModulus(PRUnichar **_rsaPubModulus)
|
|
{
|
|
NS_ENSURE_ARG(_rsaPubModulus);
|
|
*_rsaPubModulus = nsnull;
|
|
//nsXPIDLCString tmpstr; tmpstr.Adopt(CERT_Hexify(&mCert->serialNumber, 1));
|
|
NS_NAMED_LITERAL_CSTRING(tmpstr, "not yet implemented");
|
|
if (tmpstr.get()) {
|
|
*_rsaPubModulus = ToNewUnicode(tmpstr);
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* readonly attribute wstring sha1Fingerprint; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetSha1Fingerprint(PRUnichar **_sha1Fingerprint)
|
|
{
|
|
NS_ENSURE_ARG(_sha1Fingerprint);
|
|
*_sha1Fingerprint = nsnull;
|
|
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;
|
|
nsXPIDLCString fpStr; fpStr.Adopt(CERT_Hexify(&fpItem, 1));
|
|
if (fpStr.get()) {
|
|
*_sha1Fingerprint = ToNewUnicode(fpStr);
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* readonly attribute wstring md5Fingerprint; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetMd5Fingerprint(PRUnichar **_md5Fingerprint)
|
|
{
|
|
NS_ENSURE_ARG(_md5Fingerprint);
|
|
*_md5Fingerprint = nsnull;
|
|
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;
|
|
nsXPIDLCString fpStr; fpStr.Adopt(CERT_Hexify(&fpItem, 1));
|
|
if (fpStr.get()) {
|
|
*_md5Fingerprint = ToNewUnicode(fpStr);
|
|
return NS_OK;
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* readonly attribute wstring issuedDate; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetIssuedDate(PRUnichar **_issuedDate)
|
|
{
|
|
NS_ENSURE_ARG(_issuedDate);
|
|
*_issuedDate = nsnull;
|
|
nsresult rv;
|
|
PRTime beforeTime;
|
|
nsCOMPtr<nsIX509CertValidity> validity;
|
|
rv = this->GetValidity(getter_AddRefs(validity));
|
|
if (NS_FAILED(rv)) return rv;
|
|
rv = validity->GetNotBefore(&beforeTime);
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsCOMPtr<nsIDateTimeFormat> dateFormatter =
|
|
do_CreateInstance(kDateTimeFormatCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsAutoString date;
|
|
dateFormatter->FormatPRTime(nsnull, kDateFormatShort, kTimeFormatNone,
|
|
beforeTime, date);
|
|
*_issuedDate = ToNewUnicode(date);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute wstring expiresDate; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetExpiresDate(PRUnichar **_expiresDate)
|
|
{
|
|
NS_ENSURE_ARG(_expiresDate);
|
|
*_expiresDate = nsnull;
|
|
nsresult rv;
|
|
PRTime afterTime;
|
|
nsCOMPtr<nsIX509CertValidity> validity;
|
|
rv = this->GetValidity(getter_AddRefs(validity));
|
|
if (NS_FAILED(rv)) return rv;
|
|
rv = validity->GetNotAfter(&afterTime);
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsCOMPtr<nsIDateTimeFormat> dateFormatter =
|
|
do_CreateInstance(kDateTimeFormatCID, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsAutoString date;
|
|
dateFormatter->FormatPRTime(nsnull, kDateFormatShort, kTimeFormatNone,
|
|
afterTime, date);
|
|
*_expiresDate = ToNewUnicode(date);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetTokenName(PRUnichar **aTokenName)
|
|
{
|
|
NS_ENSURE_ARG(aTokenName);
|
|
*aTokenName = nsnull;
|
|
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.
|
|
#ifdef NSS_3_4
|
|
// This is not a problem in NSS 3.4, & mCert->slot is always set
|
|
if (mCert->slot) {
|
|
#else
|
|
if (mCert->slot && !mCert->isperm) {
|
|
#endif
|
|
char *token = PK11_GetTokenName(mCert->slot);
|
|
if (token) {
|
|
*aTokenName = ToNewUnicode(nsDependentCString(token));
|
|
}
|
|
} else {
|
|
nsresult rv;
|
|
nsAutoString tok;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(
|
|
do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
rv = nssComponent->GetPIPNSSBundleString(
|
|
NS_LITERAL_STRING("InternalToken").get(), tok);
|
|
if (NS_SUCCEEDED(rv))
|
|
*aTokenName = ToNewUnicode(tok);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetUsesOCSP(PRBool *aUsesOCSP)
|
|
{
|
|
nsCOMPtr<nsIPref> prefService = do_GetService(NS_PREF_CONTRACTID);
|
|
|
|
PRInt32 ocspEnabled;
|
|
prefService->GetIntPref("security.OCSP.enabled", &ocspEnabled);
|
|
if (ocspEnabled == 2) {
|
|
*aUsesOCSP = PR_TRUE;
|
|
} else if (ocspEnabled == 1) {
|
|
nsXPIDLCString ocspLocation;
|
|
ocspLocation.Adopt(CERT_GetOCSPAuthorityInfoAccessLocation(mCert));
|
|
*aUsesOCSP = (ocspLocation) ? PR_TRUE : PR_FALSE;
|
|
} else {
|
|
*aUsesOCSP = PR_FALSE;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/* [noscript] long getRawDER (out charPtr result) */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetRawDER(char **result, PRUint32 *_retval)
|
|
{
|
|
if (mCert) {
|
|
*result = (char *)mCert->derCert.data;
|
|
*_retval = mCert->derCert.len;
|
|
return NS_OK;
|
|
}
|
|
*_retval = 0;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
CERTCertificate *
|
|
nsNSSCertificate::GetCert()
|
|
{
|
|
return (mCert) ? CERT_DupCertificate(mCert) : nsnull;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetValidity(nsIX509CertValidity **aValidity)
|
|
{
|
|
NS_ENSURE_ARG(aValidity);
|
|
nsX509CertValidity *validity = new nsX509CertValidity(mCert);
|
|
if (nsnull == validity)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF(validity);
|
|
*aValidity = NS_STATIC_CAST(nsIX509CertValidity*, validity);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::VerifyForUsage(PRUint32 usage, PRUint32 *verificationResult)
|
|
{
|
|
NS_ENSURE_ARG(verificationResult);
|
|
|
|
SECCertUsage nss_usage;
|
|
|
|
switch (usage)
|
|
{
|
|
case CERT_USAGE_SSLClient:
|
|
nss_usage = certUsageSSLClient;
|
|
break;
|
|
|
|
case CERT_USAGE_SSLServer:
|
|
nss_usage = certUsageSSLServer;
|
|
break;
|
|
|
|
case CERT_USAGE_SSLServerWithStepUp:
|
|
nss_usage = certUsageSSLServerWithStepUp;
|
|
break;
|
|
|
|
case CERT_USAGE_SSLCA:
|
|
nss_usage = certUsageSSLCA;
|
|
break;
|
|
|
|
case CERT_USAGE_EmailSigner:
|
|
nss_usage = certUsageEmailSigner;
|
|
break;
|
|
|
|
case CERT_USAGE_EmailRecipient:
|
|
nss_usage = certUsageEmailRecipient;
|
|
break;
|
|
|
|
case CERT_USAGE_ObjectSigner:
|
|
nss_usage = certUsageObjectSigner;
|
|
break;
|
|
|
|
case CERT_USAGE_UserCertImport:
|
|
nss_usage = certUsageUserCertImport;
|
|
break;
|
|
|
|
case CERT_USAGE_VerifyCA:
|
|
nss_usage = certUsageVerifyCA;
|
|
break;
|
|
|
|
case CERT_USAGE_ProtectedObjectSigner:
|
|
nss_usage = certUsageProtectedObjectSigner;
|
|
break;
|
|
|
|
case CERT_USAGE_StatusResponder:
|
|
nss_usage = certUsageStatusResponder;
|
|
break;
|
|
|
|
case CERT_USAGE_AnyCA:
|
|
nss_usage = certUsageAnyCA;
|
|
break;
|
|
|
|
default:
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
|
|
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
nss_usage, 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;
|
|
}
|
|
|
|
|
|
PRBool
|
|
nsNSSCertificate::verifyFailed(PRUint32 *_verified)
|
|
{
|
|
SECCertUsage certUsage;
|
|
switch (nsNSSCertificateDB::getCertType(mCert)) {
|
|
case EMAIL_CERT: /* fall through */
|
|
case USER_CERT: certUsage = certUsageEmailRecipient; break;
|
|
case CA_CERT: certUsage = certUsageSSLCA; break;
|
|
// Chances are if we don't know the cert type, it's because
|
|
// of an SSL site we're visiting.
|
|
default:
|
|
case SERVER_CERT: certUsage = certUsageSSLServer; break;
|
|
}
|
|
CERT_VerifyCertNow(CERT_GetDefaultCertDB(), mCert, PR_TRUE, certUsage, NULL);
|
|
int err = PR_GetError();
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("not verified because: %d\n", err));
|
|
switch (err) {
|
|
/* For these cases, verify only failed for the particular usage */
|
|
case SEC_ERROR_INADEQUATE_KEY_USAGE:
|
|
case SEC_ERROR_INADEQUATE_CERT_TYPE:
|
|
return PR_FALSE;
|
|
/* These are the cases that have individual error messages */
|
|
case SEC_ERROR_REVOKED_CERTIFICATE:
|
|
*_verified = nsNSSCertificate::CERT_REVOKED; break;
|
|
case SEC_ERROR_EXPIRED_CERTIFICATE:
|
|
*_verified = nsNSSCertificate::CERT_EXPIRED; break;
|
|
case SEC_ERROR_UNTRUSTED_CERT:
|
|
*_verified = nsNSSCertificate::CERT_NOT_TRUSTED; break;
|
|
case SEC_ERROR_UNTRUSTED_ISSUER:
|
|
*_verified = nsNSSCertificate::ISSUER_NOT_TRUSTED; break;
|
|
case SEC_ERROR_UNKNOWN_ISSUER:
|
|
*_verified = nsNSSCertificate::ISSUER_UNKNOWN; break;
|
|
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
|
// XXX are there other error for this?
|
|
*_verified = nsNSSCertificate::INVALID_CA; break;
|
|
case SEC_ERROR_CERT_USAGES_INVALID: // XXX what is this?
|
|
// there are some OCSP errors from PSM 1.x to add here
|
|
default:
|
|
*_verified = nsNSSCertificate::NOT_VERIFIED_UNKNOWN; break;
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::GetUsageArray(char *suffix,
|
|
PRUint32 *_verified,
|
|
PRUint32 *_count,
|
|
PRUnichar **tmpUsages)
|
|
{
|
|
nsresult rv;
|
|
int tmpCount = 0;
|
|
|
|
CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageSSLClient, NULL) == SECSuccess) {
|
|
// add client to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifySSLClient"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageSSLServer, NULL) == SECSuccess) {
|
|
// add server to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifySSLServer"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageSSLServerWithStepUp, NULL) == SECSuccess) {
|
|
// add stepup to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifySSLStepUp"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageEmailSigner, NULL) == SECSuccess) {
|
|
// add signer to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifyEmailSigner"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageEmailRecipient, NULL) == SECSuccess) {
|
|
// add recipient to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifyEmailRecip"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageObjectSigner, NULL) == SECSuccess) {
|
|
// add objsigner to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifyObjSign"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
#if 0
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageProtectedObjectSigner, NULL) == SECSuccess) {
|
|
// add protected objsigner to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifyProtectObjSign"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageUserCertImport, NULL) == SECSuccess) {
|
|
// add user import to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifyUserImport"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
#endif
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageSSLCA, NULL) == SECSuccess) {
|
|
// add SSL CA to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifySSLCA"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
#if 0
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageVerifyCA, NULL) == SECSuccess) {
|
|
// add verify CA to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifyCAVerifier"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
#endif
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageStatusResponder, NULL) == SECSuccess) {
|
|
// add status responder to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifyStatusResponder"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
#if 0
|
|
if (CERT_VerifyCertNow(defaultcertdb, mCert, PR_TRUE,
|
|
certUsageAnyCA, NULL) == SECSuccess) {
|
|
// add any CA to usage
|
|
nsAutoString verifyDesc;
|
|
nsAutoString typestr(NS_LITERAL_STRING("VerifyAnyCA"));
|
|
typestr.AppendWithConversion(suffix);
|
|
rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
|
|
tmpUsages[tmpCount++] = ToNewUnicode(verifyDesc);
|
|
}
|
|
#endif
|
|
if (tmpCount == 0) {
|
|
verifyFailed(_verified);
|
|
} else {
|
|
*_count = tmpCount;
|
|
*_verified = nsNSSCertificate::VERIFIED_OK;
|
|
}
|
|
*_count = tmpCount;
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult
|
|
GetIntValue(SECItem *versionItem,
|
|
unsigned long *version)
|
|
{
|
|
SECStatus srv;
|
|
|
|
srv = SEC_ASN1DecodeInteger(versionItem,version);
|
|
if (srv != SECSuccess) {
|
|
NS_ASSERTION(0,"Could not decode version of cert");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult
|
|
ProcessVersion(SECItem *versionItem,
|
|
nsINSSComponent *nssComponent,
|
|
nsIASN1PrintableItem **retItem)
|
|
{
|
|
nsresult rv;
|
|
nsString text;
|
|
nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
|
|
if (printableItem == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpVersion").get(),
|
|
text);
|
|
rv = printableItem->SetDisplayName(text.get());
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
// Now to figure out what version this certificate is.
|
|
unsigned long version;
|
|
|
|
if (versionItem->data) {
|
|
rv = GetIntValue(versionItem, &version);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
} else {
|
|
// If there is no version present in the cert, then rfc2459
|
|
// says we default to v1 (0)
|
|
version = 0;
|
|
}
|
|
|
|
switch (version){
|
|
case 0:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpVersion1").get(),
|
|
text);
|
|
break;
|
|
case 1:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpVersion2").get(),
|
|
text);
|
|
break;
|
|
case 2:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpVersion3").get(),
|
|
text);
|
|
break;
|
|
default:
|
|
NS_ASSERTION(0,"Bad value for cert version");
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
rv = printableItem->SetDisplayValue(text.get());
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
*retItem = printableItem;
|
|
NS_ADDREF(*retItem);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
ProcessSerialNumberDER(SECItem *serialItem,
|
|
nsINSSComponent *nssComponent,
|
|
nsIASN1PrintableItem **retItem)
|
|
{
|
|
nsresult rv;
|
|
nsString text;
|
|
nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
|
|
|
|
if (printableItem == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSerialNo").get(),
|
|
text);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
rv = printableItem->SetDisplayName(text.get());
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
nsXPIDLCString serialNumber;
|
|
serialNumber.Adopt(CERT_Hexify(serialItem, 1));
|
|
if (serialNumber == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
rv = printableItem->SetDisplayValue(NS_ConvertASCIItoUCS2(serialNumber).get());
|
|
*retItem = printableItem;
|
|
NS_ADDREF(*retItem);
|
|
return rv;
|
|
}
|
|
|
|
static nsresult
|
|
GetDefaultOIDFormat(SECItem *oid,
|
|
nsString &outString)
|
|
{
|
|
char buf[300];
|
|
unsigned int len;
|
|
int written;
|
|
|
|
unsigned long val = oid->data[0];
|
|
unsigned int i = val % 40;
|
|
val /= 40;
|
|
written = PR_snprintf(buf, 300, "%lu %u ", val, i);
|
|
if (written < 0)
|
|
return NS_ERROR_FAILURE;
|
|
len = written;
|
|
|
|
val = 0;
|
|
for (i = 1; i < oid->len; ++i) {
|
|
// In this loop, we have to parse a DER formatted
|
|
// If the first bit is a 1, then the integer is
|
|
// represented by more than one byte. If the
|
|
// first bit is set then we continue on and add
|
|
// the values of the later bytes until we get
|
|
// a byte without the first bit set.
|
|
unsigned long j;
|
|
|
|
j = oid->data[i];
|
|
val = (val << 7) | (j & 0x7f);
|
|
if (j & 0x80)
|
|
continue;
|
|
written = PR_snprintf(&buf[len], sizeof(buf)-len, "%lu ", val);
|
|
if (written < 0)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
len += written;
|
|
NS_ASSERTION(len < sizeof(buf), "OID data to big to display in 300 chars.");
|
|
val = 0;
|
|
}
|
|
|
|
outString = NS_ConvertASCIItoUCS2(buf).get();
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult
|
|
GetOIDText(SECItem *oid, nsINSSComponent *nssComponent, nsString &text)
|
|
{
|
|
nsresult rv;
|
|
SECOidTag oidTag = SECOID_FindOIDTag(oid);
|
|
|
|
switch (oidTag) {
|
|
case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpMD2WithRSA").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpMD5WithRSA").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSHA1WithRSA").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_AVA_COUNTRY_NAME:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVACountry").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_AVA_COMMON_NAME:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVACN").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVAOU").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_AVA_ORGANIZATION_NAME:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVAOrg").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_AVA_LOCALITY:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVALocality").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_AVA_DN_QUALIFIER:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVADN").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_AVA_DC:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVADC").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_AVA_STATE_OR_PROVINCE:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAVAState").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_PKCS1_RSA_ENCRYPTION:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpRSAEncr").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_X509_KEY_USAGE:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKeyUsage").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_NS_CERT_EXT_CERT_TYPE:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCertType").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_X509_AUTH_KEY_ID:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAuthKeyID").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_RFC1274_UID:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpUserID").get(),
|
|
text);
|
|
break;
|
|
case SEC_OID_PKCS9_EMAIL_ADDRESS:
|
|
rv = nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpPK9Email").get(),
|
|
text);
|
|
break;
|
|
default:
|
|
rv = GetDefaultOIDFormat(oid, text);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
const PRUnichar *params[1] = {text.get()};
|
|
nsXPIDLString text2;
|
|
rv = nssComponent->PIPBundleFormatStringFromName(NS_LITERAL_STRING("CertDumpDefOID").get(),
|
|
params, 1,
|
|
getter_Copies(text2));
|
|
text = text2;
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
#define SEPARATOR "\n"
|
|
|
|
static nsresult
|
|
ProcessRawBytes(SECItem *data, nsString &text)
|
|
{
|
|
// This function is used to display some DER bytes
|
|
// that we have not added support for decoding.
|
|
// It prints the value of the byte out into a
|
|
// string that can later be displayed as a byte
|
|
// string. We place a new line after 24 bytes
|
|
// to break up extermaly long sequence of bytes.
|
|
PRUint32 i;
|
|
char buffer[5];
|
|
for (i=0; i<data->len; i++) {
|
|
PR_snprintf(buffer, 5, "%02x ", data->data[i]);
|
|
text.Append(NS_ConvertASCIItoUCS2(buffer).get());
|
|
if ((i+1)%16 == 0) {
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
#ifdef NSS_3_4
|
|
#define __WRAPPER_SEC_ASN1DecodeItem_Param3(p) SEC_ASN1_GET(p)
|
|
#else
|
|
#define __WRAPPER_SEC_ASN1DecodeItem_Param3(p) p
|
|
#endif
|
|
|
|
static nsresult
|
|
ProcessNSCertTypeExtensions(SECItem *extData,
|
|
nsString &text,
|
|
nsINSSComponent *nssComponent)
|
|
{
|
|
SECItem decoded;
|
|
decoded.data = nsnull;
|
|
decoded.len = 0;
|
|
SEC_ASN1DecodeItem(nsnull, &decoded,
|
|
__WRAPPER_SEC_ASN1DecodeItem_Param3(SEC_BitStringTemplate), extData);
|
|
unsigned char nsCertType = decoded.data[0];
|
|
nsString local;
|
|
nsMemory::Free(decoded.data);
|
|
if (nsCertType & NS_CERT_TYPE_SSL_CLIENT) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifySSLClient").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (nsCertType & NS_CERT_TYPE_SSL_SERVER) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifySSLServer").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (nsCertType & NS_CERT_TYPE_EMAIL) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCertTypeEmail").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifyObjSign").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (nsCertType & NS_CERT_TYPE_SSL_CA) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifySSLCA").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (nsCertType & NS_CERT_TYPE_EMAIL_CA) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpEmailCA").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING_CA) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("VerifyObjSign").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult
|
|
ProcessKeyUsageExtension(SECItem *extData, nsString &text,
|
|
nsINSSComponent *nssComponent)
|
|
{
|
|
SECItem decoded;
|
|
decoded.data = nsnull;
|
|
decoded.len = 0;
|
|
SEC_ASN1DecodeItem(nsnull, &decoded,
|
|
__WRAPPER_SEC_ASN1DecodeItem_Param3(SEC_BitStringTemplate), extData);
|
|
unsigned char keyUsage = decoded.data[0];
|
|
nsString local;
|
|
nsMemory::Free(decoded.data);
|
|
if (keyUsage & KU_DIGITAL_SIGNATURE) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUSign").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (keyUsage & KU_NON_REPUDIATION) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUNonRep").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (keyUsage & KU_KEY_ENCIPHERMENT) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUEnc").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (keyUsage & KU_DATA_ENCIPHERMENT) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUDEnc").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (keyUsage & KU_KEY_AGREEMENT) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUKA").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (keyUsage & KU_KEY_CERT_SIGN) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUCertSign").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
if (keyUsage & KU_CRL_SIGN) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpKUCRLSign").get(),
|
|
local);
|
|
text.Append(local.get());
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult
|
|
ProcessExtensionData(SECOidTag oidTag, SECItem *extData,
|
|
nsString &text, nsINSSComponent *nssComponent)
|
|
{
|
|
nsresult rv;
|
|
switch (oidTag) {
|
|
case SEC_OID_NS_CERT_EXT_CERT_TYPE:
|
|
rv = ProcessNSCertTypeExtensions(extData, text, nssComponent);
|
|
break;
|
|
case SEC_OID_X509_KEY_USAGE:
|
|
rv = ProcessKeyUsageExtension(extData, text, nssComponent);
|
|
break;
|
|
default:
|
|
rv = ProcessRawBytes(extData, text);
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
static nsresult
|
|
ProcessSingleExtension(CERTCertExtension *extension,
|
|
nsINSSComponent *nssComponent,
|
|
nsIASN1PrintableItem **retExtension)
|
|
{
|
|
nsString text;
|
|
GetOIDText(&extension->id, nssComponent, text);
|
|
nsCOMPtr<nsIASN1PrintableItem>extensionItem = new nsNSSASN1PrintableItem();
|
|
if (extensionItem == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
extensionItem->SetDisplayName(text.get());
|
|
SECOidTag oidTag = SECOID_FindOIDTag(&extension->id);
|
|
text.Truncate();
|
|
if (extension->critical.data != nsnull) {
|
|
if (extension->critical.data[0]) {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCritical").get(),
|
|
text);
|
|
} else {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpNonCritical").get(),
|
|
text);
|
|
}
|
|
} else {
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpNonCritical").get(),
|
|
text);
|
|
}
|
|
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
|
|
nsresult rv = ProcessExtensionData(oidTag, &extension->value, text,
|
|
nssComponent);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
extensionItem->SetDisplayValue(text.get());
|
|
*retExtension = extensionItem;
|
|
NS_ADDREF(*retExtension);
|
|
return NS_OK;
|
|
}
|
|
|
|
#ifdef DEBUG_javi
|
|
void
|
|
DumpASN1Object(nsIASN1Object *object, unsigned int level)
|
|
{
|
|
PRUnichar *dispNameU, *dispValU;
|
|
unsigned int i;
|
|
nsCOMPtr<nsISupportsArray> 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_ConvertUCS2toUTF8(dispNameU).get());
|
|
sequence->GetProcessObjects(&processObjects);
|
|
if (processObjects) {
|
|
printf("\n");
|
|
sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
asn1Objects->Count(&numObjects);
|
|
for (i=0; i<numObjects;i++) {
|
|
isupports = dont_AddRef(asn1Objects->ElementAt(i));
|
|
currObject = do_QueryInterface(isupports);
|
|
DumpASN1Object(currObject, level+1);
|
|
}
|
|
} else {
|
|
object->GetDisplayValue(&dispValU);
|
|
printf("= %s\n", NS_ConvertUCS2toUTF8(dispValU).get());
|
|
PR_Free(dispValU);
|
|
}
|
|
} else {
|
|
object->GetDisplayValue(&dispValU);
|
|
printf("%s = %s\n",NS_ConvertUCS2toUTF8(dispNameU).get(),
|
|
NS_ConvertUCS2toUTF8(dispValU).get());
|
|
PR_Free(dispValU);
|
|
}
|
|
PR_Free(dispNameU);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* void getUsages(out PRUint32 verified,
|
|
* out PRUint32 count,
|
|
* [retval, array, size_is(count)] out wstring usages);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetUsages(PRUint32 *_verified,
|
|
PRUint32 *_count,
|
|
PRUnichar ***_usages)
|
|
{
|
|
nsresult rv;
|
|
PRUnichar *tmpUsages[13];
|
|
char *suffix = "";
|
|
PRUint32 tmpCount;
|
|
rv = GetUsageArray(suffix, _verified, &tmpCount, tmpUsages);
|
|
if (tmpCount > 0) {
|
|
*_usages = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * tmpCount);
|
|
for (PRUint32 i=0; i<tmpCount; i++) {
|
|
(*_usages)[i] = tmpUsages[i];
|
|
}
|
|
*_count = tmpCount;
|
|
return NS_OK;
|
|
}
|
|
*_usages = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *));
|
|
*_count = 0;
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void getPurposes(out PRUint32 verified, out wstring purposes); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetPurposes(PRUint32 *_verified,
|
|
PRUnichar **_purposes)
|
|
{
|
|
nsresult rv;
|
|
PRUnichar *tmpUsages[13];
|
|
char *suffix = "_p";
|
|
PRUint32 tmpCount;
|
|
rv = GetUsageArray(suffix, _verified, &tmpCount, tmpUsages);
|
|
nsAutoString porpoises;
|
|
for (PRUint32 i=0; i<tmpCount; i++) {
|
|
if (i>0) porpoises.Append(NS_LITERAL_STRING(","));
|
|
porpoises.Append(tmpUsages[i]);
|
|
nsMemory::Free(tmpUsages[i]);
|
|
}
|
|
if (_purposes != NULL) { // skip it for verify-only
|
|
*_purposes = ToNewUnicode(porpoises);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void view (); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::View()
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsICertificateDialogs> certDialogs;
|
|
rv = ::getNSSDialogs(getter_AddRefs(certDialogs),
|
|
NS_GET_IID(nsICertificateDialogs));
|
|
return certDialogs->ViewCert(this);
|
|
}
|
|
|
|
static nsresult
|
|
ProcessSECAlgorithmID(SECAlgorithmID *algID,
|
|
nsINSSComponent *nssComponent,
|
|
nsIASN1Sequence **retSequence)
|
|
{
|
|
nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence();
|
|
if (sequence == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
*retSequence = nsnull;
|
|
nsString text;
|
|
GetOIDText(&algID->algorithm, nssComponent, text);
|
|
if (!algID->parameters.len || algID->parameters.data[0] == nsIASN1Object::ASN1_NULL) {
|
|
sequence->SetDisplayValue(text.get());
|
|
sequence->SetProcessObjects(PR_FALSE);
|
|
} else {
|
|
nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
|
|
printableItem->SetDisplayValue(text.get());
|
|
nsCOMPtr<nsISupportsArray>asn1Objects;
|
|
sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
asn1Objects->AppendElement(printableItem);
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpAlgID").get(),
|
|
text);
|
|
printableItem->SetDisplayName(text.get());
|
|
printableItem = new nsNSSASN1PrintableItem();
|
|
asn1Objects->AppendElement(printableItem);
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpParams").get(),
|
|
text);
|
|
printableItem->SetDisplayName(text.get());
|
|
ProcessRawBytes(&algID->parameters,text);
|
|
printableItem->SetDisplayValue(text.get());
|
|
}
|
|
*retSequence = sequence;
|
|
NS_ADDREF(*retSequence);
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult
|
|
ProcessTime(PRTime dispTime, const PRUnichar *displayName,
|
|
nsIASN1Sequence *parentSequence)
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsIDateTimeFormat> dateFormatter =
|
|
do_CreateInstance(kDateTimeFormatCID, &rv);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
nsString text;
|
|
nsString tempString;
|
|
|
|
PRExplodedTime explodedTime;
|
|
PR_ExplodeTime(dispTime, PR_LocalTimeParameters, &explodedTime);
|
|
|
|
dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSecondsForce24Hour,
|
|
&explodedTime, tempString);
|
|
|
|
text.Append(tempString);
|
|
text.Append(NS_LITERAL_STRING("\n("));
|
|
|
|
PRExplodedTime explodedTimeGMT;
|
|
PR_ExplodeTime(dispTime, PR_GMTParameters, &explodedTimeGMT);
|
|
|
|
dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSecondsForce24Hour,
|
|
&explodedTimeGMT, tempString);
|
|
|
|
text.Append(tempString);
|
|
text.Append(NS_LITERAL_STRING(" GMT)"));
|
|
|
|
nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
|
|
if (printableItem == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
printableItem->SetDisplayValue(text.get());
|
|
printableItem->SetDisplayName(displayName);
|
|
nsCOMPtr<nsISupportsArray> asn1Objects;
|
|
parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
asn1Objects->AppendElement(printableItem);
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult
|
|
ProcessSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki,
|
|
nsIASN1Sequence *parentSequence,
|
|
nsINSSComponent *nssComponent)
|
|
{
|
|
nsCOMPtr<nsIASN1Sequence> spkiSequence = new nsNSSASN1Sequence();
|
|
|
|
if (spkiSequence == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsString text;
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSPKI").get(),
|
|
text);
|
|
spkiSequence->SetDisplayName(text.get());
|
|
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSPKIAlg").get(),
|
|
text);
|
|
nsCOMPtr<nsIASN1Sequence> sequenceItem;
|
|
nsresult rv = ProcessSECAlgorithmID(&spki->algorithm, nssComponent,
|
|
getter_AddRefs(sequenceItem));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
sequenceItem->SetDisplayName(text.get());
|
|
nsCOMPtr<nsISupportsArray> asn1Objects;
|
|
spkiSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
asn1Objects->AppendElement(sequenceItem);
|
|
|
|
// The subjectPublicKey field is encoded as a bit string.
|
|
// ProcessRawBytes expects the lenght to be in bytes, so
|
|
// let's convert the lenght into a temporary SECItem.
|
|
SECItem data;
|
|
data.data = spki->subjectPublicKey.data;
|
|
data.len = spki->subjectPublicKey.len / 8;
|
|
text.Truncate();
|
|
ProcessRawBytes(&data, text);
|
|
nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
|
|
if (printableItem == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
printableItem->SetDisplayValue(text.get());
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSubjPubKey").get(),
|
|
text);
|
|
printableItem->SetDisplayName(text.get());
|
|
asn1Objects->AppendElement(printableItem);
|
|
|
|
parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
asn1Objects->AppendElement(spkiSequence);
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult
|
|
ProcessExtensions(CERTCertExtension **extensions,
|
|
nsIASN1Sequence *parentSequence,
|
|
nsINSSComponent *nssComponent)
|
|
{
|
|
nsCOMPtr<nsIASN1Sequence> extensionSequence = new nsNSSASN1Sequence;
|
|
if (extensionSequence == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsString text;
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpExtensions").get(),
|
|
text);
|
|
extensionSequence->SetDisplayName(text.get());
|
|
PRInt32 i;
|
|
nsresult rv;
|
|
nsCOMPtr<nsIASN1PrintableItem> newExtension;
|
|
nsCOMPtr<nsISupportsArray> asn1Objects;
|
|
extensionSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
for (i=0; extensions[i] != nsnull; i++) {
|
|
rv = ProcessSingleExtension(extensions[i], nssComponent,
|
|
getter_AddRefs(newExtension));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
asn1Objects->AppendElement(newExtension);
|
|
}
|
|
parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
asn1Objects->AppendElement(extensionSequence);
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsresult
|
|
ProcessName(CERTName *name, nsINSSComponent *nssComponent, PRUnichar **value)
|
|
{
|
|
CERTRDN** rdns;
|
|
CERTRDN** rdn;
|
|
CERTAVA** avas;
|
|
CERTAVA* ava;
|
|
SECItem *decodeItem = nsnull;
|
|
nsString finalString;
|
|
|
|
rdns = name->rdns;
|
|
|
|
nsString type;
|
|
nsresult rv;
|
|
const PRUnichar *params[2];
|
|
nsString avavalue;
|
|
nsXPIDLString temp;
|
|
CERTRDN **lastRdn;
|
|
lastRdn = rdns;
|
|
|
|
|
|
/* find last RDN */
|
|
lastRdn = rdns;
|
|
while (*lastRdn) lastRdn++;
|
|
// The above whille loop will put us at the last member
|
|
// of the array which is a NULL pointer. So let's back
|
|
// up one spot so that we have the last non-NULL entry in
|
|
// the array in preparation for traversing the
|
|
// RDN's (Relative Distinguished Name) in reverse oder.
|
|
lastRdn--;
|
|
|
|
/*
|
|
* Loop over name contents in _reverse_ RDN order appending to string
|
|
* When building the Ascii string, NSS loops over these entries in
|
|
* reverse order, so I will as well. The difference is that NSS
|
|
* will always place them in a one line string separated by commas,
|
|
* where I want each entry on a single line. I can't just use a comma
|
|
* as my delimitter because it is a valid character to have in the
|
|
* value portion of the AVA and could cause trouble when parsing.
|
|
*/
|
|
for (rdn = lastRdn; rdn >= rdns; rdn--) {
|
|
avas = (*rdn)->avas;
|
|
while ((ava = *avas++) != 0) {
|
|
rv = GetOIDText(&ava->type, nssComponent, type);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
//This function returns a string in UTF8 format.
|
|
decodeItem = CERT_DecodeAVAValue(&ava->value);
|
|
if(!decodeItem) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
avavalue.AssignWithConversion((char*)decodeItem->data, decodeItem->len);
|
|
|
|
SECITEM_FreeItem(decodeItem, PR_TRUE);
|
|
params[0] = type.get();
|
|
params[1] = avavalue.get();
|
|
nssComponent->PIPBundleFormatStringFromName(NS_LITERAL_STRING("AVATemplate").get(),
|
|
params, 2,
|
|
getter_Copies(temp));
|
|
finalString += temp + NS_LITERAL_STRING("\n");
|
|
}
|
|
}
|
|
*value = ToNewUnicode(finalString);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::CreateTBSCertificateASN1Struct(nsIASN1Sequence **retSequence,
|
|
nsINSSComponent *nssComponent)
|
|
{
|
|
//
|
|
// TBSCertificate ::= SEQUENCE {
|
|
// version [0] EXPLICIT Version DEFAULT v1,
|
|
// serialNumber CertificateSerialNumber,
|
|
// signature AlgorithmIdentifier,
|
|
// issuer Name,
|
|
// validity Validity,
|
|
// subject Name,
|
|
// subjectPublicKeyInfo SubjectPublicKeyInfo,
|
|
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
|
|
// -- If present, version shall be v2 or v3
|
|
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
|
|
// -- If present, version shall be v2 or v3
|
|
// extensions [3] EXPLICIT Extensions OPTIONAL
|
|
// -- If present, version shall be v3
|
|
// }
|
|
//
|
|
// This is the ASN1 structure we should be dealing with at this point.
|
|
// The code in this method will assert this is the structure we're dealing
|
|
// and then add more user friendly text for that field.
|
|
nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence();
|
|
if (sequence == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsString text;
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCertificate").get(),
|
|
text);
|
|
sequence->SetDisplayName(text.get());
|
|
nsCOMPtr<nsIASN1PrintableItem> printableItem;
|
|
|
|
nsCOMPtr<nsISupportsArray> asn1Objects;
|
|
sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
|
|
nsresult rv = ProcessVersion(&mCert->version, nssComponent,
|
|
getter_AddRefs(printableItem));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
asn1Objects->AppendElement(printableItem);
|
|
|
|
rv = ProcessSerialNumberDER(&mCert->serialNumber, nssComponent,
|
|
getter_AddRefs(printableItem));
|
|
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
asn1Objects->AppendElement(printableItem);
|
|
|
|
nsCOMPtr<nsIASN1Sequence> algID;
|
|
rv = ProcessSECAlgorithmID(&mCert->signature,
|
|
nssComponent, getter_AddRefs(algID));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSigAlg").get(),
|
|
text);
|
|
algID->SetDisplayName(text.get());
|
|
asn1Objects->AppendElement(algID);
|
|
|
|
nsXPIDLString value;
|
|
ProcessName(&mCert->issuer, nssComponent, getter_Copies(value));
|
|
|
|
printableItem = new nsNSSASN1PrintableItem();
|
|
if (printableItem == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
printableItem->SetDisplayValue(value);
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpIssuer").get(),
|
|
text);
|
|
printableItem->SetDisplayName(text.get());
|
|
asn1Objects->AppendElement(printableItem);
|
|
|
|
nsCOMPtr<nsIASN1Sequence> validitySequence = new nsNSSASN1Sequence();
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpValidity").get(),
|
|
text);
|
|
validitySequence->SetDisplayName(text.get());
|
|
asn1Objects->AppendElement(validitySequence);
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpNotBefore").get(),
|
|
text);
|
|
nsCOMPtr<nsIX509CertValidity> validityData;
|
|
GetValidity(getter_AddRefs(validityData));
|
|
PRTime notBefore, notAfter;
|
|
|
|
validityData->GetNotBefore(¬Before);
|
|
validityData->GetNotAfter(¬After);
|
|
validityData = 0;
|
|
rv = ProcessTime(notBefore, text.get(), validitySequence);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpNotAfter").get(),
|
|
text);
|
|
rv = ProcessTime(notAfter, text.get(), validitySequence);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSubject").get(),
|
|
text);
|
|
|
|
printableItem = new nsNSSASN1PrintableItem();
|
|
if (printableItem == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
printableItem->SetDisplayName(text.get());
|
|
ProcessName(&mCert->subject, nssComponent,getter_Copies(value));
|
|
printableItem->SetDisplayValue(value);
|
|
asn1Objects->AppendElement(printableItem);
|
|
|
|
rv = ProcessSubjectPublicKeyInfo(&mCert->subjectPublicKeyInfo, sequence,
|
|
nssComponent);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
SECItem data;
|
|
// Is there an issuerUniqueID?
|
|
if (mCert->issuerID.data != nsnull) {
|
|
// The issuerID is encoded as a bit string.
|
|
// The function ProcessRawBytes expects the
|
|
// length to be in bytes, so let's convert the
|
|
// length in a temporary SECItem
|
|
data.data = mCert->issuerID.data;
|
|
data.len = mCert->issuerID.len / 8;
|
|
|
|
ProcessRawBytes(&data, text);
|
|
printableItem = new nsNSSASN1PrintableItem();
|
|
if (printableItem == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
printableItem->SetDisplayValue(text.get());
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpIssuerUniqueID").get(),
|
|
text);
|
|
printableItem->SetDisplayName(text.get());
|
|
asn1Objects->AppendElement(printableItem);
|
|
}
|
|
|
|
if (mCert->subjectID.data) {
|
|
// The subjectID is encoded as a bit string.
|
|
// The function ProcessRawBytes expects the
|
|
// length to be in bytes, so let's convert the
|
|
// length in a temporary SECItem
|
|
data.data = mCert->issuerID.data;
|
|
data.len = mCert->issuerID.len / 8;
|
|
|
|
ProcessRawBytes(&data, text);
|
|
printableItem = new nsNSSASN1PrintableItem();
|
|
if (printableItem == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
printableItem->SetDisplayValue(text.get());
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSubjectUniqueID").get(),
|
|
text);
|
|
printableItem->SetDisplayName(text.get());
|
|
asn1Objects->AppendElement(printableItem);
|
|
|
|
}
|
|
if (mCert->extensions) {
|
|
rv = ProcessExtensions(mCert->extensions, sequence, nssComponent);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
}
|
|
*retSequence = sequence;
|
|
NS_ADDREF(*retSequence);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificate::CreateASN1Struct()
|
|
{
|
|
nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence();
|
|
|
|
mASN1Structure = sequence;
|
|
if (mASN1Structure == nsnull) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
nsCOMPtr<nsISupportsArray> asn1Objects;
|
|
sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
|
|
nsXPIDLCString title;
|
|
GetWindowTitle(getter_Copies(title));
|
|
|
|
mASN1Structure->SetDisplayName(NS_ConvertASCIItoUCS2(title).get());
|
|
// This sequence will be contain the tbsCertificate, signatureAlgorithm,
|
|
// and signatureValue.
|
|
nsresult rv;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
rv = CreateTBSCertificateASN1Struct(getter_AddRefs(sequence),
|
|
nssComponent);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
asn1Objects->AppendElement(sequence);
|
|
nsCOMPtr<nsIASN1Sequence> algID;
|
|
|
|
rv = ProcessSECAlgorithmID(&mCert->signatureWrap.signatureAlgorithm,
|
|
nssComponent, getter_AddRefs(algID));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
nsString text;
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpSigAlg").get(),
|
|
text);
|
|
algID->SetDisplayName(text.get());
|
|
asn1Objects->AppendElement(algID);
|
|
nsCOMPtr<nsIASN1PrintableItem>printableItem = new nsNSSASN1PrintableItem();
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CertDumpCertSig").get(),
|
|
text);
|
|
printableItem->SetDisplayName(text.get());
|
|
// The signatureWrap is encoded as a bit string.
|
|
// The function ProcessRawBytes expects the
|
|
// length to be in bytes, so let's convert the
|
|
// length in a temporary SECItem
|
|
SECItem temp;
|
|
temp.data = mCert->signatureWrap.signature.data;
|
|
temp.len = mCert->signatureWrap.signature.len / 8;
|
|
text.Truncate();
|
|
ProcessRawBytes(&temp,text);
|
|
printableItem->SetDisplayValue(text.get());
|
|
asn1Objects->AppendElement(printableItem);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute nsIASN1Object ASN1Structure; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificate::GetASN1Structure(nsIASN1Object * *aASN1Structure)
|
|
{
|
|
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::IsSameCert(nsIX509Cert *other, PRBool *result)
|
|
{
|
|
NS_ENSURE_ARG(other);
|
|
NS_ENSURE_ARG(result);
|
|
|
|
nsNSSCertificate *other2 = NS_STATIC_CAST(nsNSSCertificate*, other);
|
|
if (!other2)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
*result = (mCert == other2->mCert);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
/* nsNSSCertificateDB */
|
|
|
|
NS_IMPL_ISUPPORTS1(nsNSSCertificateDB, nsIX509CertDB)
|
|
|
|
nsNSSCertificateDB::nsNSSCertificateDB()
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
}
|
|
|
|
nsNSSCertificateDB::~nsNSSCertificateDB()
|
|
{
|
|
}
|
|
|
|
/* nsIX509Cert getCertByNickname(in nsIPK11Token aToken,
|
|
* in wstring aNickname);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetCertByNickname(nsIPK11Token *aToken,
|
|
const PRUnichar *nickname,
|
|
nsIX509Cert **_rvCert)
|
|
{
|
|
CERTCertificate *cert = NULL;
|
|
char *asciiname = NULL;
|
|
NS_ConvertUCS2toUTF8 aUtf8Nickname(nickname);
|
|
asciiname = NS_CONST_CAST(char*, aUtf8Nickname.get());
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Getting \"%s\"\n", asciiname));
|
|
#if 0
|
|
// what it should be, but for now...
|
|
if (aToken) {
|
|
cert = PK11_FindCertFromNickname(asciiname, NULL);
|
|
} else {
|
|
cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname);
|
|
}
|
|
#endif
|
|
cert = PK11_FindCertFromNickname(asciiname, NULL);
|
|
if (!cert) {
|
|
cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), asciiname);
|
|
}
|
|
if (cert) {
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("got it\n"));
|
|
nsCOMPtr<nsIX509Cert> pCert = new nsNSSCertificate(cert);
|
|
*_rvCert = pCert;
|
|
NS_ADDREF(*_rvCert);
|
|
return NS_OK;
|
|
}
|
|
*_rvCert = nsnull;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/* nsIX509Cert getCertByDBKey(in string aDBkey, in nsIPK11Token aToken); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetCertByDBKey(const char *aDBkey, nsIPK11Token *aToken,
|
|
nsIX509Cert **_cert)
|
|
{
|
|
SECItem keyItem = {siBuffer, nsnull, 0};
|
|
SECItem *dummy;
|
|
#ifdef NSS_3_4
|
|
CERTIssuerAndSN issuerSN;
|
|
unsigned long moduleID,slotID;
|
|
#endif
|
|
*_cert = nsnull;
|
|
if (!aDBkey) return NS_ERROR_FAILURE;
|
|
dummy = NSSBase64_DecodeBuffer(nsnull, &keyItem, aDBkey,
|
|
(PRUint32)PL_strlen(aDBkey));
|
|
#ifdef NSS_3_4
|
|
// the future is now, the cert is not longer loaded into temp db's forn now
|
|
// just fail
|
|
CERTCertificate *cert;
|
|
|
|
// someday maybe we can speed up the search using the moduleID and slotID
|
|
moduleID = NS_NSS_GET_LONG(keyItem.data);
|
|
slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]);
|
|
|
|
// build the issuer/SN structure
|
|
issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]);
|
|
issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]);
|
|
issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4];
|
|
issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG*4+
|
|
issuerSN.serialNumber.len];
|
|
|
|
cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN);
|
|
#else
|
|
// In the future, this should actually look on the token. But for now,
|
|
// take it for granted that the cert has been loaded into the temp db.
|
|
CERTCertificate *cert = CERT_FindCertByKey(CERT_GetDefaultCertDB(),
|
|
&keyItem);
|
|
#endif
|
|
PR_FREEIF(keyItem.data);
|
|
if (cert) {
|
|
nsNSSCertificate *nssCert = new nsNSSCertificate(cert);
|
|
if (nssCert == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
NS_ADDREF(nssCert);
|
|
*_cert = NS_STATIC_CAST(nsIX509Cert*, nssCert);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
/*
|
|
* void getCertNicknames(in nsIPK11Token aToken,
|
|
* in unsigned long aType,
|
|
* out unsigned long count,
|
|
* [array, size_is(count)] out wstring certNameList);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetCertNicknames(nsIPK11Token *aToken,
|
|
PRUint32 aType,
|
|
PRUint32 *_count,
|
|
PRUnichar ***_certNames)
|
|
{
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
/*
|
|
* obtain the cert list from NSS
|
|
*/
|
|
CERTCertList *certList = NULL;
|
|
PK11CertListType pk11type;
|
|
#if 0
|
|
// this would seem right, but it didn't work...
|
|
// oh, I know why - bonks out on internal slot certs
|
|
if (aType == nsIX509Cert::USER_CERT)
|
|
pk11type = PK11CertListUser;
|
|
else
|
|
#endif
|
|
pk11type = PK11CertListUnique;
|
|
certList = PK11_ListCerts(pk11type, NULL);
|
|
if (!certList)
|
|
goto cleanup;
|
|
/*
|
|
* get list of cert names from list of certs
|
|
* XXX also cull the list (NSS only distinguishes based on user/non-user
|
|
*/
|
|
getCertNames(certList, aType, _count, _certNames);
|
|
rv = NS_OK;
|
|
/*
|
|
* finish up
|
|
*/
|
|
cleanup:
|
|
if (certList)
|
|
CERT_DestroyCertList(certList);
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* [noscript] unsigned long getCertsByType(in unsigned long aType,
|
|
* in nsCertCompareFunc aCertCmpFn,
|
|
* out nsISupportsArray certs);
|
|
*/
|
|
PRBool
|
|
nsNSSCertificateDB::GetCertsByType(PRUint32 aType,
|
|
nsCertCompareFunc aCertCmpFn,
|
|
nsISupportsArray **_certs)
|
|
{
|
|
CERTCertList *certList = NULL;
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("GetCertsByType"));
|
|
nsCOMPtr<nsISupportsArray> certarray;
|
|
nsresult rv = NS_NewISupportsArray(getter_AddRefs(certarray));
|
|
if (NS_FAILED(rv)) return PR_FALSE;
|
|
nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
|
|
#ifdef NSS_3_4
|
|
if (aType == nsIX509Cert::USER_CERT) {
|
|
certList = PK11_ListCerts(PK11CertListUser, cxt);
|
|
} else if (aType == nsIX509Cert::CA_CERT) {
|
|
certList = PK11_ListCerts(PK11CertListCA, cxt); /* or RootUnique? */
|
|
} else {
|
|
certList = PK11_ListCerts(PK11CertListUnique, cxt);
|
|
}
|
|
#else
|
|
certList = PK11_ListCerts(PK11CertListUnique, cxt);
|
|
#endif
|
|
CERTCertListNode *node;
|
|
int i, count = 0;
|
|
for (node = CERT_LIST_HEAD(certList);
|
|
!CERT_LIST_END(node, certList);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
if (getCertType(node->cert) == aType) {
|
|
|
|
// Work around bug 138626.
|
|
|
|
PRBool deleted = PR_FALSE;
|
|
|
|
{
|
|
SECItem key;
|
|
key.len = NS_NSS_LONG*4+node->cert->serialNumber.len+node->cert->derIssuer.len;
|
|
key.data = (unsigned char *)nsMemory::Alloc(key.len);
|
|
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(node->cert->serialNumber.len,&key.data[NS_NSS_LONG*2]);
|
|
NS_NSS_PUT_LONG(node->cert->derIssuer.len,&key.data[NS_NSS_LONG*3]);
|
|
memcpy(&key.data[NS_NSS_LONG*4],node->cert->serialNumber.data,
|
|
node->cert->serialNumber.len);
|
|
memcpy(&key.data[NS_NSS_LONG*4+node->cert->serialNumber.len],
|
|
node->cert->derIssuer.data, node->cert->derIssuer.len);
|
|
|
|
SECItem &keyItem = key;
|
|
|
|
CERTIssuerAndSN issuerSN;
|
|
unsigned long moduleID,slotID;
|
|
|
|
// someday maybe we can speed up the search using the moduleID and slotID
|
|
moduleID = NS_NSS_GET_LONG(keyItem.data);
|
|
slotID = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG]);
|
|
|
|
// build the issuer/SN structure
|
|
issuerSN.serialNumber.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*2]);
|
|
issuerSN.derIssuer.len = NS_NSS_GET_LONG(&keyItem.data[NS_NSS_LONG*3]);
|
|
issuerSN.serialNumber.data= &keyItem.data[NS_NSS_LONG*4];
|
|
issuerSN.derIssuer.data= &keyItem.data[NS_NSS_LONG*4+
|
|
issuerSN.serialNumber.len];
|
|
|
|
CERTCertificate *cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerSN);
|
|
|
|
nsMemory::Free(key.data); // SECItem is a 'c' type without a destrutor
|
|
|
|
if (!cert)
|
|
{
|
|
deleted = PR_TRUE;
|
|
}
|
|
else
|
|
{
|
|
CERT_DestroyCertificate(cert);
|
|
}
|
|
}
|
|
|
|
if (deleted)
|
|
continue;
|
|
|
|
nsCOMPtr<nsIX509Cert> pipCert = new nsNSSCertificate(node->cert);
|
|
if (pipCert) {
|
|
for (i=0; i<count; i++) {
|
|
nsCOMPtr<nsISupports> isupport =
|
|
getter_AddRefs(certarray->ElementAt(i));
|
|
nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(isupport);
|
|
if ((*aCertCmpFn)(pipCert, cert) < 0) {
|
|
certarray->InsertElementAt(pipCert, i);
|
|
break;
|
|
}
|
|
}
|
|
if (i == count) certarray->AppendElement(pipCert);
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
*_certs = certarray;
|
|
NS_ADDREF(*_certs);
|
|
if (certList)
|
|
CERT_DestroyCertList(certList);
|
|
return PR_TRUE;
|
|
}
|
|
|
|
SECStatus PR_CALLBACK
|
|
collect_certs(void *arg, SECItem **certs, int numcerts)
|
|
{
|
|
CERTDERCerts *collectArgs;
|
|
SECItem *cert;
|
|
SECStatus rv;
|
|
|
|
collectArgs = (CERTDERCerts *)arg;
|
|
|
|
collectArgs->numcerts = numcerts;
|
|
collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
|
|
sizeof(SECItem) * numcerts);
|
|
if ( collectArgs->rawCerts == NULL )
|
|
return(SECFailure);
|
|
|
|
cert = collectArgs->rawCerts;
|
|
|
|
while ( numcerts-- ) {
|
|
rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
|
|
if ( rv == SECFailure )
|
|
return(SECFailure);
|
|
cert++;
|
|
certs++;
|
|
}
|
|
|
|
return (SECSuccess);
|
|
}
|
|
|
|
CERTDERCerts*
|
|
nsNSSCertificateDB::getCertsFromPackage(PRArenaPool *arena, char *data,
|
|
PRUint32 length)
|
|
{
|
|
CERTDERCerts *collectArgs =
|
|
(CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts));
|
|
if ( collectArgs == nsnull )
|
|
return nsnull;
|
|
|
|
collectArgs->arena = arena;
|
|
SECStatus sec_rv = CERT_DecodeCertPackage(data, length, collect_certs,
|
|
(void *)collectArgs);
|
|
if (sec_rv != SECSuccess)
|
|
return nsnull;
|
|
|
|
return collectArgs;
|
|
}
|
|
|
|
nsresult
|
|
nsNSSCertificateDB::handleCACertDownload(nsISupportsArray *x509Certs,
|
|
nsIInterfaceRequestor *ctx)
|
|
{
|
|
// First thing we have to do is figure out which certificate we're
|
|
// gonna present to the user. The CA may have sent down a list of
|
|
// certs which may or may not be a chained list of certs. Until
|
|
// the day we can design some solid UI for the general case, we'll
|
|
// code to the > 90% case. That case is where a CA sends down a
|
|
// list that is a chain up to its root in either ascending or
|
|
// descending order. What we're gonna do is compare the first
|
|
// 2 entries, if the first was signed by the second, we assume
|
|
// the leaf cert is the first cert and display it. If the second
|
|
// cert was signed by the first cert, then we assume the first cert
|
|
// is the root and the last cert in the array is the leaf. In this
|
|
// case we display the last cert.
|
|
PRUint32 numCerts;
|
|
|
|
x509Certs->Count(&numCerts);
|
|
NS_ASSERTION(numCerts > 0, "Didn't get any certs to import.");
|
|
if (numCerts == 0)
|
|
return NS_OK; // Nothing to import, so nothing to do.
|
|
|
|
nsCOMPtr<nsIX509Cert> certToShow;
|
|
nsCOMPtr<nsISupports> isupports;
|
|
PRUint32 selCertIndex;
|
|
if (numCerts == 1) {
|
|
// There's only one cert, so let's show it.
|
|
selCertIndex = 0;
|
|
isupports = dont_AddRef(x509Certs->ElementAt(selCertIndex));
|
|
certToShow = do_QueryInterface(isupports);
|
|
} else {
|
|
nsCOMPtr<nsIX509Cert> cert0;
|
|
nsCOMPtr<nsIX509Cert> cert1;
|
|
|
|
isupports = dont_AddRef(x509Certs->ElementAt(0));
|
|
cert0 = do_QueryInterface(isupports);
|
|
|
|
isupports = dont_AddRef(x509Certs->ElementAt(1));
|
|
cert1 = do_QueryInterface(isupports);
|
|
|
|
nsXPIDLString cert0SubjectName;
|
|
nsXPIDLString cert0IssuerName;
|
|
nsXPIDLString cert1SubjectName;
|
|
nsXPIDLString cert1IssuerName;
|
|
|
|
cert0->GetIssuerName(getter_Copies(cert0IssuerName));
|
|
cert0->GetSubjectName(getter_Copies(cert0SubjectName));
|
|
|
|
cert1->GetIssuerName(getter_Copies(cert1IssuerName));
|
|
cert1->GetSubjectName(getter_Copies(cert1SubjectName));
|
|
|
|
if (nsCRT::strcmp(cert1IssuerName.get(), cert0SubjectName.get()) == 0) {
|
|
// In this case, the first cert in the list signed the second,
|
|
// so the first cert is the root. Let's display the last cert
|
|
// in the list.
|
|
selCertIndex = numCerts-1;
|
|
isupports = dont_AddRef(x509Certs->ElementAt(selCertIndex));
|
|
certToShow = do_QueryInterface(isupports);
|
|
} else
|
|
if (nsCRT::strcmp(cert0IssuerName.get(), cert1SubjectName.get()) == 0) {
|
|
// In this case the second cert has signed the first cert. The
|
|
// first cert is the leaf, so let's display it.
|
|
selCertIndex = 0;
|
|
certToShow = cert0;
|
|
} else {
|
|
// It's not a chain, so let's just show the first one in the
|
|
// downloaded list.
|
|
selCertIndex = 0;
|
|
certToShow = cert0;
|
|
}
|
|
}
|
|
|
|
if (!certToShow)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsICertificateDialogs> dialogs;
|
|
nsresult rv = ::getNSSDialogs(getter_AddRefs(dialogs),
|
|
NS_GET_IID(nsICertificateDialogs));
|
|
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
SECItem der;
|
|
rv=certToShow->GetRawDER((char **)&der.data, &der.len);
|
|
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));
|
|
CERTCertificate *tmpCert;
|
|
CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
|
|
#ifdef NSS_3_4
|
|
PRBool isperm = PR_TRUE;
|
|
tmpCert = CERT_FindCertByDERCert(certdb, &der);
|
|
if (!tmpCert) {
|
|
isperm = PR_FALSE;
|
|
tmpCert = CERT_NewTempCertificate(certdb, &der,
|
|
nsnull, PR_FALSE, PR_TRUE);
|
|
}
|
|
#else
|
|
tmpCert = CERT_NewTempCertificate(certdb, &der,
|
|
nsnull, PR_FALSE, PR_TRUE);
|
|
#endif
|
|
if (!tmpCert) {
|
|
NS_ASSERTION(0,"Couldn't create cert from DER blob\n");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
CERTCertificateCleaner tmpCertCleaner(tmpCert);
|
|
|
|
PRBool canceled;
|
|
#ifdef NSS_3_4
|
|
if (isperm) {
|
|
#else
|
|
if (tmpCert->isperm) {
|
|
#endif
|
|
dialogs->CACertExists(ctx, &canceled);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
PRUint32 trustBits;
|
|
rv = dialogs->DownloadCACert(ctx, certToShow, &trustBits, &canceled);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (canceled)
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits));
|
|
nsXPIDLCString nickname;
|
|
nickname.Adopt(CERT_MakeCANickname(tmpCert));
|
|
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));
|
|
|
|
nsNSSCertTrust trust;
|
|
trust.SetValidCA();
|
|
trust.AddCATrust(trustBits & nsIX509CertDB::TRUSTED_SSL,
|
|
trustBits & nsIX509CertDB::TRUSTED_EMAIL,
|
|
trustBits & nsIX509CertDB::TRUSTED_OBJSIGN);
|
|
|
|
SECStatus srv = CERT_AddTempCertToPerm(tmpCert,
|
|
NS_CONST_CAST(char*,nickname.get()),
|
|
trust.GetTrust());
|
|
|
|
if (srv != SECSuccess)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// Now it's time to add the rest of the certs we just downloaded.
|
|
// Since we didn't prompt the user about any of these certs, we
|
|
// won't set any trust bits for them.
|
|
nsNSSCertTrust defaultTrust;
|
|
defaultTrust.SetValidCA();
|
|
defaultTrust.AddCATrust(0,0,0);
|
|
for (PRUint32 i=0; i<numCerts; i++) {
|
|
if (i == selCertIndex)
|
|
continue;
|
|
|
|
isupports = dont_AddRef(x509Certs->ElementAt(i));
|
|
certToShow = do_QueryInterface(isupports);
|
|
certToShow->GetRawDER((char **)&der.data, &der.len);
|
|
|
|
CERTCertificate *tmpCert2 =
|
|
CERT_NewTempCertificate(certdb, &der, nsnull, PR_FALSE, PR_TRUE);
|
|
|
|
if (!tmpCert2) {
|
|
NS_ASSERTION(0, "Couldn't create temp cert from DER blob\n");
|
|
continue; // Let's try to import the rest of 'em
|
|
}
|
|
nickname.Adopt(CERT_MakeCANickname(tmpCert2));
|
|
CERT_AddTempCertToPerm(tmpCert2, NS_CONST_CAST(char*,nickname.get()),
|
|
defaultTrust.GetTrust());
|
|
CERT_DestroyCertificate(tmpCert2);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/*
|
|
* [noscript] void importCertificates(in charPtr data, in unsigned long length,
|
|
* in unsigned long type,
|
|
* in nsIInterfaceRequestor ctx);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::ImportCertificates(char * data, PRUint32 length,
|
|
PRUint32 type,
|
|
nsIInterfaceRequestor *ctx)
|
|
|
|
{
|
|
SECStatus srv = SECFailure;
|
|
nsresult nsrv;
|
|
|
|
PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if (!arena)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length);
|
|
if (!certCollection) {
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nsCOMPtr<nsISupportsArray> array;
|
|
nsresult rv = NS_NewISupportsArray(getter_AddRefs(array));
|
|
if (NS_FAILED(rv)) {
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
return rv;
|
|
}
|
|
|
|
// Now let's create some certs to work with
|
|
nsCOMPtr<nsIX509Cert> x509Cert;
|
|
nsNSSCertificate *nssCert;
|
|
SECItem *currItem;
|
|
for (int i=0; i<certCollection->numcerts; i++) {
|
|
currItem = &certCollection->rawCerts[i];
|
|
nssCert = nsNSSCertificate::ConstructFromDER((char*)currItem->data, currItem->len);
|
|
if (!nssCert)
|
|
return NS_ERROR_FAILURE;
|
|
x509Cert = do_QueryInterface(nssCert);
|
|
array->AppendElement(x509Cert);
|
|
}
|
|
switch (type) {
|
|
case nsIX509Cert::CA_CERT:
|
|
nsrv = handleCACertDownload(array, ctx);
|
|
break;
|
|
default:
|
|
// We only deal with import CA certs in this method currently.
|
|
nsrv = NS_ERROR_FAILURE;
|
|
break;
|
|
}
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
if (srv != SECSuccess && nsrv == NS_OK)
|
|
nsrv = NS_ERROR_FAILURE;
|
|
return nsrv;
|
|
}
|
|
|
|
/*
|
|
* [noscript] void importEmailCertificates(in charPtr data, in unsigned long length,
|
|
* in nsIInterfaceRequestor ctx);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::ImportEmailCertificate(char * data, PRUint32 length,
|
|
nsIInterfaceRequestor *ctx)
|
|
|
|
{
|
|
SECStatus srv = SECFailure;
|
|
nsresult nsrv = NS_OK;
|
|
CERTCertificate * cert;
|
|
SECItem **rawCerts;
|
|
int numcerts;
|
|
int i;
|
|
|
|
PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if (!arena)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
CERTDERCerts *certCollection = getCertsFromPackage(arena, data, length);
|
|
if (!certCollection) {
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certCollection->rawCerts,
|
|
(char *)NULL, PR_FALSE, PR_TRUE);
|
|
if (!cert) {
|
|
nsrv = NS_ERROR_FAILURE;
|
|
goto loser;
|
|
}
|
|
numcerts = certCollection->numcerts;
|
|
rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
|
|
if ( !rawCerts ) {
|
|
nsrv = NS_ERROR_FAILURE;
|
|
goto loser;
|
|
}
|
|
|
|
for ( i = 0; i < numcerts; i++ ) {
|
|
rawCerts[i] = &certCollection->rawCerts[i];
|
|
}
|
|
|
|
srv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageEmailSigner,
|
|
numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE,
|
|
NULL);
|
|
if ( srv != SECSuccess ) {
|
|
nsrv = NS_ERROR_FAILURE;
|
|
goto loser;
|
|
}
|
|
srv = CERT_SaveSMimeProfile(cert, NULL, NULL);
|
|
PORT_Free(rawCerts);
|
|
loser:
|
|
if (arena)
|
|
PORT_FreeArena(arena, PR_TRUE);
|
|
return nsrv;
|
|
}
|
|
|
|
char *
|
|
default_nickname(CERTCertificate *cert, nsIInterfaceRequestor* ctx)
|
|
{
|
|
nsresult rv;
|
|
char *username = NULL;
|
|
char *caname = NULL;
|
|
char *nickname = NULL;
|
|
char *tmp = NULL;
|
|
int count;
|
|
char *nickFmt=NULL, *nickFmtWithNum = NULL;
|
|
CERTCertificate *dummycert;
|
|
PK11SlotInfo *slot=NULL;
|
|
CK_OBJECT_HANDLE keyHandle;
|
|
nsAutoString tmpNickFmt;
|
|
nsAutoString tmpNickFmtWithNum;
|
|
|
|
CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv)) goto loser;
|
|
|
|
username = CERT_GetCommonName(&cert->subject);
|
|
if ( username == NULL )
|
|
username = PL_strdup("");
|
|
|
|
if ( username == NULL )
|
|
goto loser;
|
|
|
|
caname = CERT_GetOrgName(&cert->issuer);
|
|
if ( caname == NULL )
|
|
caname = PL_strdup("");
|
|
|
|
if ( caname == NULL )
|
|
goto loser;
|
|
|
|
count = 1;
|
|
nssComponent->GetPIPNSSBundleString(
|
|
NS_LITERAL_STRING("nick_template").get(),
|
|
tmpNickFmt);
|
|
nickFmt = ToNewUTF8String(tmpNickFmt);
|
|
|
|
nssComponent->GetPIPNSSBundleString(
|
|
NS_LITERAL_STRING("nick_template_with_num").get(),
|
|
tmpNickFmtWithNum);
|
|
nickFmtWithNum = ToNewUTF8String(tmpNickFmtWithNum);
|
|
|
|
|
|
nickname = PR_smprintf(nickFmt, username, caname);
|
|
/*
|
|
* We need to see if the private key exists on a token, if it does
|
|
* then we need to check for nicknames that already exist on the smart
|
|
* card.
|
|
*/
|
|
slot = PK11_KeyForCertExists(cert, &keyHandle, ctx);
|
|
if (slot == NULL) {
|
|
goto loser;
|
|
}
|
|
if (!PK11_IsInternal(slot)) {
|
|
tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), nickname);
|
|
PR_Free(nickname);
|
|
nickname = tmp;
|
|
tmp = NULL;
|
|
}
|
|
tmp = nickname;
|
|
while ( 1 ) {
|
|
if ( count > 1 ) {
|
|
nickname = PR_smprintf("%s #%d", tmp, count);
|
|
}
|
|
|
|
if ( nickname == NULL )
|
|
goto loser;
|
|
|
|
if (PK11_IsInternal(slot)) {
|
|
/* look up the nickname to make sure it isn't in use already */
|
|
dummycert = CERT_FindCertByNickname(defaultcertdb, nickname);
|
|
|
|
} else {
|
|
/*
|
|
* Check the cert against others that already live on the smart
|
|
* card.
|
|
*/
|
|
dummycert = PK11_FindCertFromNickname(nickname, ctx);
|
|
if (dummycert != NULL) {
|
|
/*
|
|
* Make sure the subject names are different.
|
|
*/
|
|
if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
|
|
{
|
|
/*
|
|
* There is another certificate with the same nickname and
|
|
* the same subject name on the smart card, so let's use this
|
|
* nickname.
|
|
*/
|
|
CERT_DestroyCertificate(dummycert);
|
|
dummycert = NULL;
|
|
}
|
|
}
|
|
}
|
|
if ( dummycert == NULL )
|
|
goto done;
|
|
|
|
/* found a cert, destroy it and loop */
|
|
CERT_DestroyCertificate(dummycert);
|
|
if (tmp != nickname) PR_Free(nickname);
|
|
count++;
|
|
} /* end of while(1) */
|
|
|
|
loser:
|
|
if ( nickname ) {
|
|
PR_Free(nickname);
|
|
}
|
|
nickname = NULL;
|
|
done:
|
|
if ( caname ) {
|
|
PR_Free(caname);
|
|
}
|
|
if ( username ) {
|
|
PR_Free(username);
|
|
}
|
|
if (slot != NULL) {
|
|
PK11_FreeSlot(slot);
|
|
if (nickname != NULL) {
|
|
tmp = nickname;
|
|
nickname = strchr(tmp, ':');
|
|
if (nickname != NULL) {
|
|
nickname++;
|
|
nickname = PL_strdup(nickname);
|
|
PR_Free(tmp);
|
|
tmp = nsnull;
|
|
} else {
|
|
nickname = tmp;
|
|
tmp = NULL;
|
|
}
|
|
}
|
|
}
|
|
PR_FREEIF(tmp);
|
|
return(nickname);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::ImportUserCertificate(char *data, PRUint32 length, nsIInterfaceRequestor *ctx)
|
|
{
|
|
PK11SlotInfo *slot;
|
|
char * nickname = NULL;
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
int numCACerts;
|
|
SECItem *CACerts;
|
|
CERTDERCerts * collectArgs;
|
|
PRArenaPool *arena;
|
|
CERTCertificate * cert=NULL;
|
|
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if ( arena == NULL ) {
|
|
goto loser;
|
|
}
|
|
|
|
collectArgs = getCertsFromPackage(arena, data, length);
|
|
if (!collectArgs) {
|
|
goto loser;
|
|
}
|
|
|
|
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), collectArgs->rawCerts,
|
|
(char *)NULL, PR_FALSE, PR_TRUE);
|
|
if (!cert) {
|
|
goto loser;
|
|
}
|
|
|
|
slot = PK11_KeyForCertExists(cert, NULL, ctx);
|
|
if ( slot == NULL ) {
|
|
goto loser;
|
|
}
|
|
PK11_FreeSlot(slot);
|
|
|
|
/* pick a nickname for the cert */
|
|
#ifdef NSS_3_4
|
|
if (cert->nickname) {
|
|
/* sigh, we need a call to look up other certs with this subject and
|
|
* identify nicknames from them. We can no longer walk down internal
|
|
* database structures rjr */
|
|
nickname = cert->nickname;
|
|
}
|
|
#else
|
|
if (cert->subjectList && cert->subjectList->entry &&
|
|
cert->subjectList->entry->nickname) {
|
|
nickname = cert->subjectList->entry->nickname;
|
|
}
|
|
#endif
|
|
else {
|
|
nickname = default_nickname(cert, ctx);
|
|
}
|
|
|
|
/* user wants to import the cert */
|
|
slot = PK11_ImportCertForKey(cert, nickname, ctx);
|
|
if (!slot) {
|
|
goto loser;
|
|
}
|
|
PK11_FreeSlot(slot);
|
|
numCACerts = collectArgs->numcerts - 1;
|
|
|
|
if (numCACerts) {
|
|
CACerts = collectArgs->rawCerts+1;
|
|
if ( ! CERT_ImportCAChain(CACerts, numCACerts, certUsageUserCertImport) ) {
|
|
rv = NS_OK;
|
|
}
|
|
}
|
|
|
|
loser:
|
|
if (arena) {
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
}
|
|
if ( cert ) {
|
|
CERT_DestroyCertificate(cert);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* void deleteCertificate(in nsIX509Cert aCert);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
|
|
{
|
|
nsNSSCertificate *nssCert = NS_STATIC_CAST(nsNSSCertificate*, aCert);
|
|
CERTCertificate *cert = nssCert->GetCert();
|
|
if (!cert) return NS_ERROR_FAILURE;
|
|
SECStatus srv = SECSuccess;
|
|
|
|
PRUint32 certType = getCertType(cert);
|
|
nssCert->SetCertType(certType);
|
|
nssCert->MarkForPermDeletion();
|
|
|
|
if (cert->slot && certType != nsIX509Cert::USER_CERT) {
|
|
// To delete a cert of a slot (builtin, most likely), mark it as
|
|
// completely untrusted. This way we keep a copy cached in the
|
|
// local database, and next time we try to load it off of the
|
|
// external token/slot, we'll know not to trust it. We don't
|
|
// want to do that with user certs, because a user may re-store
|
|
// the cert onto the card again at which point we *will* want to
|
|
// trust that cert if it chains up properly.
|
|
nsNSSCertTrust trust(0, 0, 0);
|
|
srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
|
|
cert, trust.GetTrust());
|
|
}
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("cert deleted: %d", srv));
|
|
return (srv) ? NS_ERROR_FAILURE : NS_OK;
|
|
}
|
|
|
|
/*
|
|
* void setCertTrust(in nsIX509Cert cert,
|
|
* in unsigned long type,
|
|
* in unsigned long trust);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
|
|
PRUint32 type,
|
|
PRUint32 trusted)
|
|
{
|
|
SECStatus srv;
|
|
nsNSSCertTrust trust;
|
|
nsNSSCertificate *pipCert = NS_STATIC_CAST(nsNSSCertificate *, cert);
|
|
CERTCertificate *nsscert = pipCert->GetCert();
|
|
if (type == nsIX509Cert::CA_CERT) {
|
|
// always start with untrusted and move up
|
|
trust.SetValidCA();
|
|
trust.AddCATrust(trusted & nsIX509CertDB::TRUSTED_SSL,
|
|
trusted & nsIX509CertDB::TRUSTED_EMAIL,
|
|
trusted & nsIX509CertDB::TRUSTED_OBJSIGN);
|
|
srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
|
|
nsscert,
|
|
trust.GetTrust());
|
|
} else if (type == nsIX509Cert::SERVER_CERT) {
|
|
// always start with untrusted and move up
|
|
trust.SetValidPeer();
|
|
trust.AddPeerTrust(trusted & nsIX509CertDB::TRUSTED_SSL, 0, 0);
|
|
srv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
|
|
nsscert,
|
|
trust.GetTrust());
|
|
} else {
|
|
// ignore user and email certs
|
|
return NS_OK;
|
|
}
|
|
return (srv) ? NS_ERROR_FAILURE : NS_OK;
|
|
}
|
|
|
|
/*
|
|
* boolean getCertTrust(in nsIX509Cert cert,
|
|
* in unsigned long certType,
|
|
* in unsigned long trustType);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetCertTrust(nsIX509Cert *cert,
|
|
PRUint32 certType,
|
|
PRUint32 trustType,
|
|
PRBool *_isTrusted)
|
|
{
|
|
SECStatus srv;
|
|
nsNSSCertificate *pipCert = NS_STATIC_CAST(nsNSSCertificate *, cert);
|
|
CERTCertificate *nsscert = pipCert->GetCert();
|
|
CERTCertTrust nsstrust;
|
|
srv = CERT_GetCertTrust(nsscert, &nsstrust);
|
|
nsNSSCertTrust trust(&nsstrust);
|
|
if (certType == nsIX509Cert::CA_CERT) {
|
|
if (trustType & nsIX509CertDB::TRUSTED_SSL) {
|
|
*_isTrusted = trust.HasTrustedCA(PR_TRUE, PR_FALSE, PR_FALSE);
|
|
} else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
|
|
*_isTrusted = trust.HasTrustedCA(PR_FALSE, PR_TRUE, PR_FALSE);
|
|
} else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
|
|
*_isTrusted = trust.HasTrustedCA(PR_FALSE, PR_FALSE, PR_TRUE);
|
|
} else {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
} else if (certType == nsIX509Cert::SERVER_CERT) {
|
|
if (trustType & nsIX509CertDB::TRUSTED_SSL) {
|
|
*_isTrusted = trust.HasTrustedPeer(PR_TRUE, PR_FALSE, PR_FALSE);
|
|
} else if (trustType & nsIX509CertDB::TRUSTED_EMAIL) {
|
|
*_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_TRUE, PR_FALSE);
|
|
} else if (trustType & nsIX509CertDB::TRUSTED_OBJSIGN) {
|
|
*_isTrusted = trust.HasTrustedPeer(PR_FALSE, PR_FALSE, PR_TRUE);
|
|
} else {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
} /* user or email, ignore */
|
|
return NS_OK;
|
|
}
|
|
|
|
/*
|
|
* void importPKCS12File(in nsIPK11Token aToken,
|
|
* in nsILocalFile aFile);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::ImportPKCS12File(nsIPK11Token *aToken,
|
|
nsILocalFile *aFile)
|
|
{
|
|
NS_ENSURE_ARG(aFile);
|
|
nsPKCS12Blob blob;
|
|
blob.SetToken(aToken);
|
|
return blob.ImportFromFile(aFile);
|
|
}
|
|
|
|
/*
|
|
* void exportPKCS12File(in nsIPK11Token aToken,
|
|
* in nsILocalFile aFile,
|
|
* in PRUint32 count,
|
|
* [array, size_is(count)] in wstring aCertNames);
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::ExportPKCS12File(nsIPK11Token *aToken,
|
|
nsILocalFile *aFile,
|
|
PRUint32 count,
|
|
nsIX509Cert **certs)
|
|
//const PRUnichar **aCertNames)
|
|
{
|
|
NS_ENSURE_ARG(aFile);
|
|
nsPKCS12Blob blob;
|
|
if (count == 0) return NS_OK;
|
|
nsCOMPtr<nsIPK11Token> localRef;
|
|
if (!aToken) {
|
|
PK11SlotInfo *keySlot = PK11_GetInternalKeySlot();
|
|
NS_ASSERTION(keySlot,"Failed to get the internal key slot");
|
|
localRef = new nsPK11Token(keySlot);
|
|
PK11_FreeSlot(keySlot);
|
|
aToken = localRef;
|
|
}
|
|
blob.SetToken(aToken);
|
|
//blob.LoadCerts(aCertNames, count);
|
|
//return blob.ExportToFile(aFile);
|
|
return blob.ExportToFile(aFile, certs, count);
|
|
}
|
|
|
|
/* Header file */
|
|
class nsOCSPResponder : public nsIOCSPResponder
|
|
{
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIOCSPRESPONDER
|
|
|
|
nsOCSPResponder();
|
|
nsOCSPResponder(const PRUnichar*, const PRUnichar*);
|
|
virtual ~nsOCSPResponder();
|
|
/* additional members */
|
|
static PRInt32 CmpCAName(nsIOCSPResponder *a, nsIOCSPResponder *b);
|
|
static PRInt32 CompareEntries(nsIOCSPResponder *a, nsIOCSPResponder *b);
|
|
static PRBool IncludeCert(CERTCertificate *aCert);
|
|
private:
|
|
nsString mCA;
|
|
nsString mURL;
|
|
};
|
|
|
|
/* Implementation file */
|
|
NS_IMPL_ISUPPORTS1(nsOCSPResponder, nsIOCSPResponder)
|
|
|
|
nsOCSPResponder::nsOCSPResponder()
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
/* member initializers and constructor code */
|
|
}
|
|
|
|
nsOCSPResponder::nsOCSPResponder(const PRUnichar * aCA, const PRUnichar * aURL)
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
mCA.Assign(aCA);
|
|
mURL.Assign(aURL);
|
|
}
|
|
|
|
nsOCSPResponder::~nsOCSPResponder()
|
|
{
|
|
/* destructor code */
|
|
}
|
|
|
|
/* readonly attribute */
|
|
NS_IMETHODIMP nsOCSPResponder::GetResponseSigner(PRUnichar** aCA)
|
|
{
|
|
NS_ENSURE_ARG(aCA);
|
|
*aCA = ToNewUnicode(mCA);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute */
|
|
NS_IMETHODIMP nsOCSPResponder::GetServiceURL(PRUnichar** aURL)
|
|
{
|
|
NS_ENSURE_ARG(aURL);
|
|
*aURL = ToNewUnicode(mURL);
|
|
return NS_OK;
|
|
}
|
|
|
|
PRBool nsOCSPResponder::IncludeCert(CERTCertificate *aCert)
|
|
{
|
|
CERTCertTrust *trust;
|
|
char *nickname;
|
|
|
|
trust = aCert->trust;
|
|
nickname = aCert->nickname;
|
|
|
|
PR_ASSERT(trust != nsnull);
|
|
|
|
// Check that trust is non-null //
|
|
if (trust == nsnull) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
if ( ( ( trust->sslFlags & CERTDB_INVISIBLE_CA ) ||
|
|
(trust->emailFlags & CERTDB_INVISIBLE_CA ) ||
|
|
(trust->objectSigningFlags & CERTDB_INVISIBLE_CA ) ) ||
|
|
nickname == NULL) {
|
|
return PR_FALSE;
|
|
}
|
|
if ((trust->sslFlags & CERTDB_VALID_CA) ||
|
|
(trust->emailFlags & CERTDB_VALID_CA) ||
|
|
(trust->objectSigningFlags & CERTDB_VALID_CA)) {
|
|
return PR_TRUE;
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
// CmpByCAName
|
|
//
|
|
// Compare two responders their token name. Returns -1, 0, 1 as
|
|
// in strcmp. No token name (null) is treated as >.
|
|
PRInt32 nsOCSPResponder::CmpCAName(nsIOCSPResponder *a, nsIOCSPResponder *b)
|
|
{
|
|
PRInt32 cmp1;
|
|
nsXPIDLString aTok, bTok;
|
|
a->GetResponseSigner(getter_Copies(aTok));
|
|
b->GetResponseSigner(getter_Copies(bTok));
|
|
if (aTok != nsnull && bTok != nsnull) {
|
|
cmp1 = Compare(aTok, bTok);
|
|
} else {
|
|
cmp1 = (aTok == nsnull) ? 1 : -1;
|
|
}
|
|
return cmp1;
|
|
}
|
|
|
|
// ocsp_compare_entries
|
|
//
|
|
// Compare two responders. Returns -1, 0, 1 as
|
|
// in strcmp. Entries with urls come before those without urls.
|
|
PRInt32 nsOCSPResponder::CompareEntries(nsIOCSPResponder *a, nsIOCSPResponder *b)
|
|
{
|
|
nsXPIDLString aURL, bURL;
|
|
nsAutoString aURLAuto, bURLAuto;
|
|
|
|
a->GetServiceURL(getter_Copies(aURL));
|
|
aURLAuto.Assign(aURL);
|
|
b->GetServiceURL(getter_Copies(bURL));
|
|
bURLAuto.Assign(bURL);
|
|
|
|
if (aURLAuto.Length() > 0 ) {
|
|
if (bURLAuto.Length() > 0) {
|
|
return nsOCSPResponder::CmpCAName(a, b);
|
|
} else {
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (bURLAuto.Length() > 0) {
|
|
return 1;
|
|
} else {
|
|
return nsOCSPResponder::CmpCAName(a, b);
|
|
}
|
|
}
|
|
}
|
|
|
|
static SECStatus PR_CALLBACK
|
|
GetOCSPResponders (CERTCertificate *aCert,
|
|
SECItem *aDBKey,
|
|
void *aArg)
|
|
{
|
|
nsISupportsArray *array = NS_STATIC_CAST(nsISupportsArray*, aArg);
|
|
PRUnichar* nn = nsnull;
|
|
PRUnichar* url = nsnull;
|
|
char *serviceURL = nsnull;
|
|
char *nickname = nsnull;
|
|
PRUint32 i, count;
|
|
nsresult rv;
|
|
|
|
// Are we interested in this cert //
|
|
if (!nsOCSPResponder::IncludeCert(aCert)) {
|
|
return SECSuccess;
|
|
}
|
|
|
|
// Get the AIA and nickname //
|
|
serviceURL = CERT_GetOCSPAuthorityInfoAccessLocation(aCert);
|
|
if (serviceURL) {
|
|
url = ToNewUnicode(nsDependentCString(serviceURL));
|
|
}
|
|
|
|
nickname = aCert->nickname;
|
|
nn = ToNewUnicode(nsDependentCString(nickname));
|
|
|
|
nsCOMPtr<nsIOCSPResponder> new_entry = new nsOCSPResponder(nn, url);
|
|
|
|
// Sort the items according to nickname //
|
|
rv = array->Count(&count);
|
|
for (i=0; i < count; ++i) {
|
|
nsCOMPtr<nsISupports> isupport = getter_AddRefs(array->ElementAt(i));
|
|
nsCOMPtr<nsIOCSPResponder> entry = do_QueryInterface(isupport);
|
|
if (nsOCSPResponder::CompareEntries(new_entry, entry) < 0) {
|
|
array->InsertElementAt(new_entry, i);
|
|
break;
|
|
}
|
|
}
|
|
if (i == count) {
|
|
array->AppendElement(new_entry);
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
/*
|
|
* getOCSPResponders
|
|
*
|
|
* Export a set of certs and keys from the database to a PKCS#12 file.
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetOCSPResponders(nsISupportsArray ** aResponders)
|
|
{
|
|
SECStatus sec_rv;
|
|
nsCOMPtr<nsISupportsArray> respondersArray;
|
|
nsresult rv = NS_NewISupportsArray(getter_AddRefs(respondersArray));
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
#ifdef NSS_3_4
|
|
sec_rv = PK11_TraverseSlotCerts(::GetOCSPResponders,
|
|
respondersArray,
|
|
nsnull);
|
|
#else
|
|
sec_rv = SEC_TraversePermCerts(CERT_GetDefaultCertDB(),
|
|
::GetOCSPResponders,
|
|
respondersArray);
|
|
if (sec_rv == SECSuccess) {
|
|
sec_rv = PK11_TraverseSlotCerts(::GetOCSPResponders,
|
|
respondersArray,
|
|
nsnull);
|
|
}
|
|
#endif
|
|
if (sec_rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
*aResponders = respondersArray;
|
|
NS_IF_ADDREF(*aResponders);
|
|
return NS_OK;
|
|
loser:
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* NSS Helper Routines (private to nsNSSCertificateDB)
|
|
*/
|
|
|
|
#define DELIM '\001'
|
|
|
|
/*
|
|
* GetSortedNameList
|
|
*
|
|
* Converts a CERTCertList to a list of certificate names
|
|
*/
|
|
void
|
|
nsNSSCertificateDB::getCertNames(CERTCertList *certList,
|
|
PRUint32 type,
|
|
PRUint32 *_count,
|
|
PRUnichar ***_certNames)
|
|
{
|
|
nsresult rv;
|
|
CERTCertListNode *node;
|
|
PRUint32 numcerts = 0, i=0;
|
|
PRUnichar **tmpArray = NULL;
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("List of certs %d:\n", type));
|
|
for (node = CERT_LIST_HEAD(certList);
|
|
!CERT_LIST_END(node, certList);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
if (getCertType(node->cert) == type) {
|
|
numcerts++;
|
|
}
|
|
}
|
|
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("num certs: %d\n", numcerts));
|
|
int nc = (numcerts == 0) ? 1 : numcerts;
|
|
tmpArray = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nc);
|
|
if (numcerts == 0) goto finish;
|
|
for (node = CERT_LIST_HEAD(certList);
|
|
!CERT_LIST_END(node, certList);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
if (getCertType(node->cert) == type) {
|
|
nsNSSCertificate pipCert(node->cert);
|
|
char *dbkey = NULL;
|
|
char *namestr = NULL;
|
|
nsAutoString certstr;
|
|
rv = pipCert.GetDbKey(&dbkey);
|
|
nsAutoString keystr = NS_ConvertASCIItoUCS2(dbkey);
|
|
PR_FREEIF(dbkey);
|
|
if (type == nsIX509Cert::EMAIL_CERT) {
|
|
namestr = node->cert->emailAddr;
|
|
} else {
|
|
namestr = node->cert->nickname;
|
|
char *sc = strchr(namestr, ':');
|
|
if (sc) *sc = DELIM;
|
|
}
|
|
nsAutoString certname = NS_ConvertASCIItoUCS2(namestr);
|
|
certstr.Append(PRUnichar(DELIM));
|
|
certstr += certname;
|
|
certstr.Append(PRUnichar(DELIM));
|
|
certstr += keystr;
|
|
tmpArray[i++] = ToNewUnicode(certstr);
|
|
}
|
|
}
|
|
finish:
|
|
*_count = numcerts;
|
|
*_certNames = tmpArray;
|
|
}
|
|
|
|
/* somewhat follows logic of cert_list_include_cert from PSM 1.x */
|
|
PRUint32
|
|
nsNSSCertificateDB::getCertType(CERTCertificate *cert)
|
|
{
|
|
char *nick = cert->nickname;
|
|
char *email = cert->emailAddr;
|
|
nsNSSCertTrust trust(cert->trust);
|
|
/*
|
|
fprintf(stderr, "====> nick: %s email: %s has-any-user: %d hash-any-ca: %d has-peer100: %d has-peer001: %d\n",
|
|
nick, email, (nick) ? trust.HasAnyUser() : 0, (nick) ? trust.HasAnyCA() : 0, (nick) ? trust.HasPeer(PR_TRUE, PR_FALSE, PR_FALSE) : 0,
|
|
(email) ? trust.HasPeer(PR_FALSE, PR_TRUE, PR_FALSE) : 0 );
|
|
*/
|
|
if (nick) {
|
|
if (trust.HasAnyUser())
|
|
return nsIX509Cert::USER_CERT;
|
|
if (trust.HasAnyCA() || CERT_IsCACert(cert,NULL))
|
|
return nsIX509Cert::CA_CERT;
|
|
if (trust.HasPeer(PR_TRUE, PR_FALSE, PR_FALSE))
|
|
return nsIX509Cert::SERVER_CERT;
|
|
}
|
|
if (email && trust.HasPeer(PR_FALSE, PR_TRUE, PR_FALSE))
|
|
return nsIX509Cert::EMAIL_CERT;
|
|
return nsIX509Cert::UNKNOWN_CERT;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::ImportCrl (char *aData, PRUint32 aLength, nsIURI * aURI, PRUint32 aType, PRBool doSilentDonwload, const PRUnichar* crlKey)
|
|
{
|
|
nsresult rv;
|
|
PRArenaPool *arena = NULL;
|
|
CERTCertificate *caCert;
|
|
SECItem derName = { siBuffer, NULL, 0 };
|
|
SECItem derCrl;
|
|
CERTSignedData sd;
|
|
SECStatus sec_rv;
|
|
CERTSignedCrl *crl;
|
|
nsCAutoString url;
|
|
nsCOMPtr<nsICrlEntry> crlEntry;
|
|
PRBool importSuccessful;
|
|
PRInt32 errorCode;
|
|
nsString errorMessage;
|
|
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
aURI->GetSpec(url);
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if (!arena) {
|
|
goto loser;
|
|
}
|
|
memset(&sd, 0, sizeof(sd));
|
|
|
|
derCrl.data = (unsigned char*)aData;
|
|
derCrl.len = aLength;
|
|
sec_rv = CERT_KeyFromDERCrl(arena, &derCrl, &derName);
|
|
if (sec_rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
caCert = CERT_FindCertByName(CERT_GetDefaultCertDB(), &derName);
|
|
if (!caCert) {
|
|
if (aType == SEC_KRL_TYPE){
|
|
goto loser;
|
|
}
|
|
} else {
|
|
sec_rv = SEC_ASN1DecodeItem(arena,
|
|
&sd, __WRAPPER_SEC_ASN1DecodeItem_Param3(CERT_SignedDataTemplate),
|
|
&derCrl);
|
|
if (sec_rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
sec_rv = CERT_VerifySignedData(&sd, caCert, PR_Now(),
|
|
nsnull);
|
|
if (sec_rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
}
|
|
|
|
crl = SEC_NewCrl(CERT_GetDefaultCertDB(), (char*)url.get(), &derCrl,
|
|
aType);
|
|
|
|
if (!crl) {
|
|
goto loser;
|
|
}
|
|
|
|
crlEntry = new nsCrlEntry(crl);
|
|
SSL_ClearSessionCache();
|
|
SEC_DestroyCrl(crl);
|
|
|
|
importSuccessful = PR_TRUE;
|
|
goto done;
|
|
|
|
loser:
|
|
importSuccessful = PR_FALSE;
|
|
errorCode = PR_GetError();
|
|
switch (errorCode) {
|
|
case SEC_ERROR_CRL_EXPIRED:
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CrlImportFailureExpired").get(), errorMessage);
|
|
break;
|
|
|
|
case SEC_ERROR_CRL_BAD_SIGNATURE:
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CrlImportFailureBadSignature").get(), errorMessage);
|
|
break;
|
|
|
|
case SEC_ERROR_CRL_INVALID:
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CrlImportFailureInvalid").get(), errorMessage);
|
|
break;
|
|
|
|
case SEC_ERROR_OLD_CRL:
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CrlImportFailureOld").get(), errorMessage);
|
|
break;
|
|
|
|
case SEC_ERROR_CRL_NOT_YET_VALID:
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CrlImportFailureNotYetValid").get(), errorMessage);
|
|
break;
|
|
|
|
default:
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CrlImportFailureReasonUnknown").get(), errorMessage);
|
|
errorMessage.AppendInt(errorCode,16);
|
|
break;
|
|
}
|
|
|
|
done:
|
|
|
|
if(!doSilentDonwload){
|
|
if (!importSuccessful){
|
|
nsString message;
|
|
nsString temp;
|
|
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
|
|
nsCOMPtr<nsIPrompt> prompter;
|
|
if (wwatch){
|
|
wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CrlImportFailure1").get(), message);
|
|
message.Append(NS_LITERAL_STRING("\n").get());
|
|
message.Append(errorMessage);
|
|
nssComponent->GetPIPNSSBundleString(NS_LITERAL_STRING("CrlImportFailure2").get(), temp);
|
|
message.Append(NS_LITERAL_STRING("\n").get());
|
|
message.Append(temp);
|
|
|
|
if(prompter)
|
|
prompter->Alert(0, message.get());
|
|
}
|
|
} else {
|
|
nsCOMPtr<nsICertificateDialogs> certDialogs;
|
|
rv = ::getNSSDialogs(getter_AddRefs(certDialogs), NS_GET_IID(nsICertificateDialogs));
|
|
nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
|
|
certDialogs->CrlImportStatusDialog(cxt, crlEntry);
|
|
}
|
|
} else {
|
|
if(crlKey == nsnull){
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID,&rv);
|
|
if (NS_FAILED(rv)){
|
|
return rv;
|
|
}
|
|
|
|
nsCAutoString updateErrCntPrefStr(CRL_AUTOUPDATE_ERRCNT_PREF);
|
|
updateErrCntPrefStr.AppendWithConversion(crlKey);
|
|
if(importSuccessful){
|
|
PRUnichar *updateTime;
|
|
nsCAutoString updateTimeStr;
|
|
PRUnichar *updateURL;
|
|
nsCAutoString updateURLStr;
|
|
PRInt32 timingTypePref;
|
|
double dayCnt;
|
|
char *dayCntStr;
|
|
nsCAutoString updateTypePrefStr(CRL_AUTOUPDATE_TIMIINGTYPE_PREF);
|
|
nsCAutoString updateTimePrefStr(CRL_AUTOUPDATE_TIME_PREF);
|
|
nsCAutoString updateUrlPrefStr(CRL_AUTOUPDATE_URL_PREF);
|
|
nsCAutoString updateDayCntPrefStr(CRL_AUTOUPDATE_DAYCNT_PREF);
|
|
nsCAutoString updateFreqCntPrefStr(CRL_AUTOUPDATE_FREQCNT_PREF);
|
|
updateTypePrefStr.AppendWithConversion(crlKey);
|
|
updateTimePrefStr.AppendWithConversion(crlKey);
|
|
updateUrlPrefStr.AppendWithConversion(crlKey);
|
|
updateDayCntPrefStr.AppendWithConversion(crlKey);
|
|
updateFreqCntPrefStr.AppendWithConversion(crlKey);
|
|
|
|
pref->GetIntPref(updateTypePrefStr.get(),&timingTypePref);
|
|
|
|
//Compute and update the next download instant
|
|
if(timingTypePref == nsCrlEntry::TYPE_AUTOUPDATE_TIME_BASED){
|
|
pref->GetCharPref(updateDayCntPrefStr.get(),&dayCntStr);
|
|
}else{
|
|
pref->GetCharPref(updateFreqCntPrefStr.get(),&dayCntStr);
|
|
}
|
|
dayCnt = atof(dayCntStr);
|
|
nsMemory::Free(dayCntStr);
|
|
|
|
PRBool toBeRescheduled = PR_FALSE;
|
|
if(NS_SUCCEEDED(crlEntry->ComputeNextAutoUpdateTime(timingTypePref,dayCnt,&updateTime))){
|
|
updateTimeStr.AssignWithConversion(updateTime);
|
|
nsMemory::Free(updateTime);
|
|
pref->SetCharPref(updateTimePrefStr.get(),updateTimeStr.get());
|
|
//Now, check if this update time is already in the past. This would
|
|
//imply we have downloaded the same crl, or there is something wrong
|
|
//with the next update date. We will not reschedule this crl in this
|
|
//session anymore - or else, we land into a loop. It would anyway be
|
|
//imported once the browser is restarted.
|
|
PRTime nextTime;
|
|
PR_ParseTimeString(updateTimeStr.get(),PR_TRUE, &nextTime);
|
|
if(LL_CMP(nextTime, > , PR_Now())){
|
|
toBeRescheduled = PR_TRUE;
|
|
}
|
|
}
|
|
|
|
//Update the url to download from, next time
|
|
crlEntry->GetLastFetchURL(&updateURL);
|
|
updateURLStr.AssignWithConversion(updateURL);
|
|
nsMemory::Free(updateURL);
|
|
pref->SetCharPref(updateUrlPrefStr.get(),updateURLStr.get());
|
|
|
|
pref->SetIntPref(updateErrCntPrefStr.get(),0);
|
|
pref->SavePrefFile(nsnull);
|
|
|
|
if(toBeRescheduled == PR_TRUE){
|
|
nsAutoString hashKey(crlKey);
|
|
nssComponent->RemoveCrlFromList(hashKey);
|
|
nssComponent->DefineNextTimer();
|
|
}
|
|
|
|
} else{
|
|
PRInt32 errCnt;
|
|
nsCAutoString errMsg;
|
|
nsCAutoString updateErrDetailPrefStr(CRL_AUTOUPDATE_ERRDETAIL_PREF);
|
|
updateErrDetailPrefStr.AppendWithConversion(crlKey);
|
|
errMsg.AssignWithConversion(errorMessage.get());
|
|
rv = pref->GetIntPref(updateErrCntPrefStr.get(),&errCnt);
|
|
if( (NS_FAILED(rv)) || (errCnt ==0)){
|
|
pref->SetIntPref(updateErrCntPrefStr.get(),1);
|
|
}else{
|
|
pref->SetIntPref(updateErrCntPrefStr.get(),errCnt+1);
|
|
}
|
|
pref->SetCharPref(updateErrDetailPrefStr.get(),errMsg.get());
|
|
pref->SavePrefFile(nsnull);
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* Implementation file */
|
|
NS_IMPL_ISUPPORTS1(nsCrlEntry, nsICrlEntry)
|
|
|
|
nsCrlEntry::nsCrlEntry()
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
/* member initializers and constructor code */
|
|
}
|
|
|
|
nsCrlEntry::nsCrlEntry(const PRUnichar * aOrg, const PRUnichar * aOrgUnit,
|
|
const PRUnichar * aLastUpdateLocale, const PRUnichar * aNextUpdateLocale,
|
|
PRTime aLastUpdate, PRTime aNextUpdate, const PRUnichar *aNameInDb,
|
|
const PRUnichar *aLastFetchURL)
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
mOrg.Assign(aOrg);
|
|
mOrgUnit.Assign(aOrgUnit);
|
|
mLastUpdateLocale.Assign(aLastUpdateLocale);
|
|
mNextUpdateLocale.Assign(aNextUpdateLocale);
|
|
mLastUpdate = aLastUpdate;
|
|
mNextUpdate = aNextUpdate;
|
|
mNameInDb.Assign(aNameInDb);
|
|
mLastFetchURL.Assign(aLastFetchURL);
|
|
}
|
|
|
|
|
|
nsCrlEntry::nsCrlEntry(CERTSignedCrl *signedCrl)
|
|
{
|
|
NS_INIT_ISUPPORTS();
|
|
|
|
CERTCrl *crl = &(signedCrl->crl);
|
|
nsAutoString org;
|
|
nsAutoString orgUnit;
|
|
nsAutoString nameInDb;
|
|
nsAutoString nextUpdateLocale;
|
|
nsAutoString lastUpdateLocale;
|
|
nsAutoString lastFetchURL;
|
|
PRTime lastUpdate;
|
|
PRTime nextUpdate;
|
|
SECStatus sec_rv;
|
|
|
|
// Get the information we need here //
|
|
char * o = CERT_GetOrgName(&(crl->name));
|
|
if (o) {
|
|
org = NS_ConvertASCIItoUCS2(o);
|
|
PORT_Free(o);
|
|
}
|
|
|
|
char * ou = CERT_GetOrgUnitName(&(crl->name));
|
|
if (ou) {
|
|
orgUnit = NS_ConvertASCIItoUCS2(ou);
|
|
//At present, the ou is being used as the unique key - but this
|
|
//would change, one support for delta crls come in.
|
|
nameInDb = orgUnit;
|
|
PORT_Free(ou);
|
|
}
|
|
|
|
nsCOMPtr<nsIDateTimeFormat> dateFormatter = do_CreateInstance(kDateTimeFormatCID);
|
|
|
|
// Last Update time
|
|
if (crl->lastUpdate.len) {
|
|
sec_rv = DER_UTCTimeToTime(&lastUpdate, &(crl->lastUpdate));
|
|
if (sec_rv == SECSuccess && dateFormatter) {
|
|
dateFormatter->FormatPRTime(nsnull, kDateFormatShort, kTimeFormatNone,
|
|
lastUpdate, lastUpdateLocale);
|
|
}
|
|
}
|
|
|
|
if (crl->nextUpdate.len) {
|
|
// Next update time
|
|
sec_rv = DER_UTCTimeToTime(&nextUpdate, &(crl->nextUpdate));
|
|
if (sec_rv == SECSuccess && dateFormatter) {
|
|
dateFormatter->FormatPRTime(nsnull, kDateFormatShort, kTimeFormatNone,
|
|
nextUpdate, nextUpdateLocale);
|
|
}
|
|
}
|
|
|
|
char * url = signedCrl->url;
|
|
if(url) {
|
|
lastFetchURL = NS_ConvertASCIItoUCS2(url);
|
|
}
|
|
|
|
mOrg.Assign(org.get());
|
|
mOrgUnit.Assign(orgUnit.get());
|
|
mLastUpdateLocale.Assign(lastUpdateLocale.get());
|
|
mNextUpdateLocale.Assign(nextUpdateLocale.get());
|
|
mLastUpdate = lastUpdate;
|
|
mNextUpdate = nextUpdate;
|
|
mNameInDb.Assign(nameInDb.get());
|
|
mLastFetchURL.Assign(lastFetchURL.get());
|
|
|
|
}
|
|
|
|
nsCrlEntry::~nsCrlEntry()
|
|
{
|
|
/* destructor code */
|
|
}
|
|
|
|
/* readonly attribute */
|
|
NS_IMETHODIMP nsCrlEntry::GetOrg(PRUnichar** aOrg)
|
|
{
|
|
NS_ENSURE_ARG(aOrg);
|
|
*aOrg = ToNewUnicode(mOrg);
|
|
return NS_OK;
|
|
}
|
|
|
|
/* readonly attribute */
|
|
NS_IMETHODIMP nsCrlEntry::GetOrgUnit(PRUnichar** aOrgUnit)
|
|
{
|
|
NS_ENSURE_ARG(aOrgUnit);
|
|
*aOrgUnit = ToNewUnicode(mOrgUnit);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsCrlEntry::GetLastUpdateLocale(PRUnichar** aLastUpdateLocale)
|
|
{
|
|
NS_ENSURE_ARG(aLastUpdateLocale);
|
|
*aLastUpdateLocale = ToNewUnicode(mLastUpdateLocale);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsCrlEntry::GetNextUpdateLocale(PRUnichar** aNextUpdateLocale)
|
|
{
|
|
NS_ENSURE_ARG(aNextUpdateLocale);
|
|
*aNextUpdateLocale = ToNewUnicode(mNextUpdateLocale);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
/* readonly attribute */
|
|
NS_IMETHODIMP nsCrlEntry::GetNameInDb(PRUnichar** aNameInDb)
|
|
{
|
|
NS_ENSURE_ARG(aNameInDb);
|
|
*aNameInDb = ToNewUnicode(mNameInDb);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsCrlEntry::GetLastFetchURL(PRUnichar** aLastFetchURL)
|
|
{
|
|
NS_ENSURE_ARG(aLastFetchURL);
|
|
*aLastFetchURL = ToNewUnicode(mLastFetchURL);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsCrlEntry::ComputeNextAutoUpdateTime(PRUint32 autoUpdateType, double dayCnt, PRUnichar **nextAutoUpdate)
|
|
{
|
|
|
|
PRTime microsecInDayCnt;
|
|
PRTime now = PR_Now();
|
|
PRTime tempTime;
|
|
PRInt64 diff = 0;
|
|
PRInt64 secsInDay = 86400UL;
|
|
PRInt64 temp;
|
|
PRInt64 cycleCnt = 0;
|
|
PRInt64 secsInDayCnt;
|
|
PRFloat64 tmpData;
|
|
|
|
LL_L2F(tmpData,secsInDay);
|
|
LL_MUL(tmpData,dayCnt,tmpData);
|
|
LL_F2L(secsInDayCnt,tmpData);
|
|
LL_MUL(microsecInDayCnt, secsInDayCnt, PR_USEC_PER_SEC);
|
|
|
|
switch (autoUpdateType) {
|
|
case nsCrlEntry::TYPE_AUTOUPDATE_FREQ_BASED:
|
|
LL_SUB(diff, now, mLastUpdate); //diff is the no of micro sec between now and last update
|
|
LL_DIV(cycleCnt, diff, microsecInDayCnt); //temp is the number of full cycles from lst update
|
|
LL_MOD(temp, diff, microsecInDayCnt);
|
|
if(!(LL_IS_ZERO(temp))) {
|
|
LL_ADD(cycleCnt,cycleCnt,1); //no of complete cycles till next autoupdate instant
|
|
}
|
|
LL_MUL(temp,cycleCnt,microsecInDayCnt); //micro secs from last update
|
|
LL_ADD(tempTime, mLastUpdate, temp);
|
|
break;
|
|
case nsCrlEntry::TYPE_AUTOUPDATE_TIME_BASED:
|
|
LL_SUB(tempTime, mNextUpdate, microsecInDayCnt);
|
|
break;
|
|
default:
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
//Now, a basic constraing is that the next auto update date can never be after
|
|
//next update, if one is defined
|
|
if(LL_CMP(mNextUpdate , > , 0 )) {
|
|
if(LL_CMP(tempTime , > , mNextUpdate)) {
|
|
tempTime = mNextUpdate;
|
|
}
|
|
}
|
|
|
|
nsAutoString nextAutoUpdateDate;
|
|
PRExplodedTime explodedTime;
|
|
nsresult rv;
|
|
nsCOMPtr<nsIDateTimeFormat> dateFormatter = do_CreateInstance(kDateTimeFormatCID, &rv);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
PR_ExplodeTime(tempTime, PR_GMTParameters, &explodedTime);
|
|
dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSeconds,
|
|
&explodedTime, nextAutoUpdateDate);
|
|
*nextAutoUpdate = ToNewUnicode(nextAutoUpdateDate);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::UpdateCRLFromURL( const PRUnichar *url, const PRUnichar* key, PRBool *res)
|
|
{
|
|
nsresult rv;
|
|
nsAutoString downloadUrl(url);
|
|
nsAutoString dbKey(key);
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if(NS_FAILED(rv)){
|
|
*res = PR_FALSE;
|
|
return rv;
|
|
}
|
|
|
|
rv = nssComponent->DownloadCRLDirectly(downloadUrl, dbKey);
|
|
if(NS_FAILED(rv)){
|
|
*res = PR_FALSE;
|
|
} else {
|
|
*res = PR_TRUE;
|
|
}
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::RescheduleCRLAutoUpdate(void)
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if(NS_FAILED(rv)){
|
|
return rv;
|
|
}
|
|
rv = nssComponent->DefineNextTimer();
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* getCRLs
|
|
*
|
|
* Export a set of certs and keys from the database to a PKCS#12 file.
|
|
*/
|
|
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetCrls(nsISupportsArray ** aCrls)
|
|
{
|
|
SECStatus sec_rv;
|
|
CERTCrlHeadNode *head = nsnull;
|
|
CERTCrlNode *node = nsnull;
|
|
nsCOMPtr<nsISupportsArray> crlsArray;
|
|
nsresult rv;
|
|
rv = NS_NewISupportsArray(getter_AddRefs(crlsArray));
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
// Get the list of certs //
|
|
sec_rv = SEC_LookupCrls(CERT_GetDefaultCertDB(), &head, -1);
|
|
if (sec_rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (head) {
|
|
for (node=head->first; node != nsnull; node = node->next) {
|
|
|
|
nsCOMPtr<nsICrlEntry> entry = new nsCrlEntry((node->crl));
|
|
crlsArray->AppendElement(entry);
|
|
}
|
|
PORT_FreeArena(head->arena, PR_FALSE);
|
|
}
|
|
|
|
*aCrls = crlsArray;
|
|
NS_IF_ADDREF(*aCrls);
|
|
return NS_OK;
|
|
loser:
|
|
return NS_ERROR_FAILURE;;
|
|
}
|
|
|
|
/*
|
|
* deletetCrl
|
|
*
|
|
* Delete a Crl entry from the cert db.
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::DeleteCrl(PRUint32 aCrlIndex)
|
|
{
|
|
CERTSignedCrl *realCrl = nsnull;
|
|
CERTCrlHeadNode *head = nsnull;
|
|
CERTCrlNode *node = nsnull;
|
|
SECStatus sec_rv;
|
|
PRUint32 i;
|
|
|
|
// Get the list of certs //
|
|
sec_rv = SEC_LookupCrls(CERT_GetDefaultCertDB(), &head, -1);
|
|
if (sec_rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (head) {
|
|
for (i = 0, node=head->first; node != nsnull; i++, node = node->next) {
|
|
if (i != aCrlIndex) {
|
|
continue;
|
|
}
|
|
realCrl = SEC_FindCrlByName(CERT_GetDefaultCertDB(), &(node->crl->crl.derName), node->type);
|
|
SEC_DeletePermCRL(realCrl);
|
|
SEC_DestroyCrl(realCrl);
|
|
SSL_ClearSessionCache();
|
|
}
|
|
PORT_FreeArena(head->arena, PR_FALSE);
|
|
}
|
|
return NS_OK;
|
|
loser:
|
|
return NS_ERROR_FAILURE;;
|
|
}
|
|
|
|
/* readonly attribute boolean ocspOn; */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetOcspOn(PRBool *aOcspOn)
|
|
{
|
|
nsCOMPtr<nsIPref> prefService = do_GetService(NS_PREF_CONTRACTID);
|
|
|
|
PRInt32 ocspEnabled;
|
|
prefService->GetIntPref("security.OCSP.enabled", &ocspEnabled);
|
|
*aOcspOn = ( ocspEnabled == 0 ) ? PR_FALSE : PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void disableOCSP (); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::DisableOCSP()
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
return nssComponent->DisableOCSP();
|
|
}
|
|
|
|
/* void enableOCSP (); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::EnableOCSP()
|
|
{
|
|
nsresult rv;
|
|
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
return nssComponent->EnableOCSP();
|
|
}
|
|
|
|
/* nsIX509Cert getDefaultEmailEncryptionCert (); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetEmailEncryptionCert(const PRUnichar* aNickname, nsIX509Cert **_retval)
|
|
{
|
|
if (!aNickname || !_retval)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
*_retval = 0;
|
|
|
|
nsDependentString aDepNickname(aNickname);
|
|
if (aDepNickname.IsEmpty())
|
|
return NS_OK;
|
|
|
|
nsresult rv = NS_OK;
|
|
CERTCertificate *cert = 0;
|
|
nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
|
|
nsNSSCertificate *nssCert = nsnull;
|
|
char *asciiname = NULL;
|
|
NS_ConvertUCS2toUTF8 aUtf8Nickname(aDepNickname);
|
|
asciiname = NS_CONST_CAST(char*, aUtf8Nickname.get());
|
|
|
|
/* Find a good cert in the user's database */
|
|
cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname,
|
|
certUsageEmailRecipient, PR_TRUE, ctx);
|
|
|
|
if (!cert) { goto loser; }
|
|
|
|
nssCert = new nsNSSCertificate(cert);
|
|
if (nssCert == nsnull) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
NS_ADDREF(nssCert);
|
|
|
|
*_retval = NS_STATIC_CAST(nsIX509Cert*, nssCert);
|
|
|
|
loser:
|
|
if (cert) CERT_DestroyCertificate(cert);
|
|
return rv;
|
|
}
|
|
|
|
/* nsIX509Cert getDefaultEmailSigningCert (); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetEmailSigningCert(const PRUnichar* aNickname, nsIX509Cert **_retval)
|
|
{
|
|
if (!aNickname || !_retval)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
*_retval = 0;
|
|
|
|
nsDependentString aDepNickname(aNickname);
|
|
if (aDepNickname.IsEmpty())
|
|
return NS_OK;
|
|
|
|
nsresult rv = NS_OK;
|
|
CERTCertificate *cert = 0;
|
|
nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
|
|
nsNSSCertificate *nssCert = nsnull;
|
|
char *asciiname = NULL;
|
|
NS_ConvertUCS2toUTF8 aUtf8Nickname(aDepNickname);
|
|
asciiname = NS_CONST_CAST(char*, aUtf8Nickname.get());
|
|
|
|
/* Find a good cert in the user's database */
|
|
cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), asciiname,
|
|
certUsageEmailSigner, PR_TRUE, ctx);
|
|
|
|
if (!cert) { goto loser; }
|
|
|
|
nssCert = new nsNSSCertificate(cert);
|
|
if (nssCert == nsnull) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
NS_ADDREF(nssCert);
|
|
|
|
*_retval = NS_STATIC_CAST(nsIX509Cert*, nssCert);
|
|
|
|
loser:
|
|
if (cert) CERT_DestroyCertificate(cert);
|
|
return rv;
|
|
}
|
|
|
|
/* nsIX509Cert getCertByEmailAddress (in nsIPK11Token aToken, in wstring aEmailAddress); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::GetCertByEmailAddress(nsIPK11Token *aToken, const char *aEmailAddress, nsIX509Cert **_retval)
|
|
{
|
|
#ifdef NSS_3_4
|
|
CERTCertificate *any_cert = CERT_FindCertByNicknameOrEmailAddr(CERT_GetDefaultCertDB(), (char*)aEmailAddress);
|
|
if (!any_cert)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
CERTCertificateCleaner certCleaner(any_cert);
|
|
|
|
// any_cert now contains a cert with the right subject, but it might not have the correct usage
|
|
CERTCertList *certlist = CERT_CreateSubjectCertList(
|
|
nsnull, CERT_GetDefaultCertDB(), &any_cert->derSubject, PR_Now(), PR_TRUE);
|
|
if (!certlist)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
CERTCertListCleaner listCleaner(certlist);
|
|
|
|
if (SECSuccess != CERT_FilterCertListByUsage(certlist, certUsageEmailRecipient, PR_FALSE))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (CERT_LIST_END(CERT_LIST_HEAD(certlist), certlist))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsNSSCertificate *nssCert = new nsNSSCertificate(CERT_LIST_HEAD(certlist)->cert);
|
|
if (!nssCert)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF(nssCert);
|
|
*_retval = NS_STATIC_CAST(nsIX509Cert*, nssCert);
|
|
return NS_OK;
|
|
#else
|
|
CERTCertList *certList = nsnull;
|
|
SECStatus sec_rv;
|
|
nsresult rv = NS_OK;
|
|
|
|
certList = CERT_CreateEmailAddrCertList(nsnull, CERT_GetDefaultCertDB(),
|
|
(char*)aEmailAddress, PR_Now(), PR_TRUE);
|
|
|
|
if (certList == nsnull) {
|
|
rv = NS_ERROR_FAILURE;
|
|
goto loser;
|
|
}
|
|
|
|
sec_rv = CERT_FilterCertListByUsage(certList, certUsageEmailRecipient, PR_FALSE);
|
|
|
|
if (!CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
|
|
nsNSSCertificate *nssCert = new nsNSSCertificate(CERT_LIST_HEAD(certList)->cert);
|
|
if (nssCert == nsnull) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
goto loser;
|
|
}
|
|
NS_ADDREF(nssCert);
|
|
*_retval = NS_STATIC_CAST(nsIX509Cert*, nssCert);
|
|
}
|
|
loser:
|
|
if (certList) {
|
|
CERT_DestroyCertList(certList);
|
|
}
|
|
|
|
return rv;
|
|
#endif
|
|
}
|
|
|
|
/* nsIX509Cert constructX509FromBase64 (in string base64); */
|
|
NS_IMETHODIMP
|
|
nsNSSCertificateDB::ConstructX509FromBase64(const char * base64, nsIX509Cert **_retval)
|
|
{
|
|
if (!_retval) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
PRUint32 len = PL_strlen(base64);
|
|
int adjust = 0;
|
|
|
|
/* Compute length adjustment */
|
|
if (base64[len-1] == '=') {
|
|
adjust++;
|
|
if (base64[len-2] == '=') adjust++;
|
|
}
|
|
|
|
nsresult rv = NS_OK;
|
|
char *certDER = 0;
|
|
PRInt32 lengthDER = 0;
|
|
|
|
certDER = PL_Base64Decode(base64, len, NULL);
|
|
if (!certDER || !*certDER) {
|
|
rv = NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
else {
|
|
lengthDER = (len*3)/4 - adjust;
|
|
|
|
SECItem secitem_cert;
|
|
secitem_cert.type = siDERCertBuffer;
|
|
secitem_cert.data = (unsigned char*)certDER;
|
|
secitem_cert.len = lengthDER;
|
|
|
|
CERTCertificate *cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert, nsnull, PR_FALSE, PR_TRUE);
|
|
|
|
if (!cert) {
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
else {
|
|
nsNSSCertificate *nsNSS = new nsNSSCertificate(cert);
|
|
if (!nsNSS) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
else {
|
|
nsresult rv = nsNSS->QueryInterface(NS_GET_IID(nsIX509Cert), (void**)_retval);
|
|
|
|
if (NS_SUCCEEDED(rv) && *_retval) {
|
|
NS_ADDREF(*_retval);
|
|
}
|
|
|
|
NS_RELEASE(nsNSS);
|
|
}
|
|
CERT_DestroyCertificate(cert);
|
|
}
|
|
}
|
|
|
|
if (certDER) {
|
|
nsCRT::free(certDER);
|
|
}
|
|
return rv;
|
|
}
|