Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* pkix_pl_cert.c
*
* Certificate Object Functions
*
*/
#include "pkix_pl_cert.h"
extern PKIX_PL_HashTable *cachedCertSigTable;
/* --Private-Cert-Functions------------------------------------- */
/*
* FUNCTION: pkix_pl_Cert_IsExtensionCritical
* DESCRIPTION:
*
* Checks the Cert specified by "cert" to determine whether the extension
* whose tag is the UInt32 value given by "tag" is marked as a critical
* extension, and stores the result in "pCritical".
*
* Tags are the index into the table "oids" of SECOidData defined in the
* file secoid.c. Constants, such as SEC_OID_X509_CERTIFICATE_POLICIES, are
* are defined in secoidt.h for most of the table entries.
*
* If the specified tag is invalid (not in the list of tags) or if the
* extension is not found in the certificate, PKIX_FALSE is stored.
*
* PARAMETERS
* "cert"
* Address of Cert whose extensions are to be examined. Must be non-NULL.
* "tag"
* The UInt32 value of the tag for the extension whose criticality is
* to be determined
* "pCritical"
* Address where the Boolean value will be stored. Must be non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
static PKIX_Error *
pkix_pl_Cert_IsExtensionCritical(
PKIX_PL_Cert *cert,
PKIX_UInt32 tag,
PKIX_Boolean *pCritical,
void *plContext)
{
PKIX_Boolean criticality = PKIX_FALSE;
CERTCertExtension **extensions = NULL;
SECStatus rv;
PKIX_ENTER(CERT, "pkix_pl_Cert_IsExtensionCritical");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCritical);
extensions = cert->nssCert->extensions;
PKIX_NULLCHECK_ONE(extensions);
PKIX_CERT_DEBUG("\t\tCalling CERT_GetExtenCriticality).\n");
rv = CERT_GetExtenCriticality(extensions, tag, &criticality);
if (SECSuccess == rv) {
*pCritical = criticality;
} else {
*pCritical = PKIX_FALSE;
}
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_DecodePolicyInfo
* DESCRIPTION:
*
* Decodes the contents of the CertificatePolicy extension in the
* CERTCertificate pointed to by "nssCert", to create a List of
* CertPolicyInfos, which is stored at the address "pCertPolicyInfos".
* A CERTCertificate contains the DER representation of the Cert.
* If this certificate does not have a CertificatePolicy extension,
* NULL will be stored. If a List is returned, it will be immutable.
*
* PARAMETERS
* "nssCert"
* Address of the Cert data whose extension is to be examined. Must be
* non-NULL.
* "pCertPolicyInfos"
* Address where the List of CertPolicyInfos will be stored. Must be
* non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Cert Error if the function fails in a non-fatal way.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
static PKIX_Error *
pkix_pl_Cert_DecodePolicyInfo(
CERTCertificate *nssCert,
PKIX_List **pCertPolicyInfos,
void *plContext)
{
SECStatus rv;
SECItem encodedCertPolicyInfo;
/* Allocated in the arena; freed in CERT_Destroy... */
CERTCertificatePolicies *certPol = NULL;
CERTPolicyInfo **policyInfos = NULL;
/* Holder for the return value */
PKIX_List *infos = NULL;
PKIX_PL_OID *pkixOID = NULL;
PKIX_List *qualifiers = NULL;
PKIX_PL_CertPolicyInfo *certPolicyInfo = NULL;
PKIX_PL_CertPolicyQualifier *certPolicyQualifier = NULL;
PKIX_PL_ByteArray *qualifierArray = NULL;
PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyInfo");
PKIX_NULLCHECK_TWO(nssCert, pCertPolicyInfos);
/* get PolicyInfo as a SECItem */
PKIX_CERT_DEBUG("\t\tCERT_FindCertExtension).\n");
rv = CERT_FindCertExtension
(nssCert,
SEC_OID_X509_CERTIFICATE_POLICIES,
&encodedCertPolicyInfo);
if (SECSuccess != rv) {
*pCertPolicyInfos = NULL;
goto cleanup;
}
/* translate PolicyInfo to CERTCertificatePolicies */
PKIX_CERT_DEBUG("\t\tCERT_DecodeCertificatePoliciesExtension).\n");
certPol = CERT_DecodeCertificatePoliciesExtension
(&encodedCertPolicyInfo);
PORT_Free(encodedCertPolicyInfo.data);
if (NULL == certPol) {
PKIX_ERROR(PKIX_CERTDECODECERTIFICATEPOLICIESEXTENSIONFAILED);
}
/*
* Check whether there are any policyInfos, so we can
* avoid creating an unnecessary List
*/
policyInfos = certPol->policyInfos;
if (!policyInfos) {
*pCertPolicyInfos = NULL;
goto cleanup;
}
/* create a List of CertPolicyInfo Objects */
PKIX_CHECK(PKIX_List_Create(&infos, plContext),
PKIX_LISTCREATEFAILED);
/*
* Traverse the CERTCertificatePolicies structure,
* building each PKIX_PL_CertPolicyInfo object in turn
*/
while (*policyInfos != NULL) {
CERTPolicyInfo *policyInfo = *policyInfos;
CERTPolicyQualifier **policyQualifiers =
policyInfo->policyQualifiers;
if (policyQualifiers) {
/* create a PKIX_List of PKIX_PL_CertPolicyQualifiers */
PKIX_CHECK(PKIX_List_Create(&qualifiers, plContext),
PKIX_LISTCREATEFAILED);
while (*policyQualifiers != NULL) {
CERTPolicyQualifier *policyQualifier =
*policyQualifiers;
/* create the qualifier's OID object */
PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
(&policyQualifier->qualifierID,
&pkixOID, plContext),
PKIX_OIDCREATEFAILED);
/* create qualifier's ByteArray object */
PKIX_CHECK(PKIX_PL_ByteArray_Create
(policyQualifier->qualifierValue.data,
policyQualifier->qualifierValue.len,
&qualifierArray,
plContext),
PKIX_BYTEARRAYCREATEFAILED);
/* create a CertPolicyQualifier object */
PKIX_CHECK(pkix_pl_CertPolicyQualifier_Create
(pkixOID,
qualifierArray,
&certPolicyQualifier,
plContext),
PKIX_CERTPOLICYQUALIFIERCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(qualifiers,
(PKIX_PL_Object *)certPolicyQualifier,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_DECREF(pkixOID);
PKIX_DECREF(qualifierArray);
PKIX_DECREF(certPolicyQualifier);
policyQualifiers++;
}
PKIX_CHECK(PKIX_List_SetImmutable
(qualifiers, plContext),
PKIX_LISTSETIMMUTABLEFAILED);
}
/*
* Create an OID object pkixOID from policyInfo->policyID.
* (The CERTPolicyInfo structure has an oid field, but it
* is of type SECOidTag. This function wants a SECItem.)
*/
PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
(&policyInfo->policyID, &pkixOID, plContext),
PKIX_OIDCREATEFAILED);
/* Create a CertPolicyInfo object */
PKIX_CHECK(pkix_pl_CertPolicyInfo_Create
(pkixOID, qualifiers, &certPolicyInfo, plContext),
PKIX_CERTPOLICYINFOCREATEFAILED);
/* Append the new CertPolicyInfo object to the list */
PKIX_CHECK(PKIX_List_AppendItem
(infos, (PKIX_PL_Object *)certPolicyInfo, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_DECREF(pkixOID);
PKIX_DECREF(qualifiers);
PKIX_DECREF(certPolicyInfo);
policyInfos++;
}
/*
* If there were no policies, we went straight to
* cleanup, so we don't have to NULLCHECK infos.
*/
PKIX_CHECK(PKIX_List_SetImmutable(infos, plContext),
PKIX_LISTSETIMMUTABLEFAILED);
*pCertPolicyInfos = infos;
infos = NULL;
cleanup:
if (certPol) {
PKIX_CERT_DEBUG
("\t\tCalling CERT_DestroyCertificatePoliciesExtension).\n");
CERT_DestroyCertificatePoliciesExtension(certPol);
}
PKIX_DECREF(infos);
PKIX_DECREF(pkixOID);
PKIX_DECREF(qualifiers);
PKIX_DECREF(certPolicyInfo);
PKIX_DECREF(certPolicyQualifier);
PKIX_DECREF(qualifierArray);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_DecodePolicyMapping
* DESCRIPTION:
*
* Decodes the contents of the PolicyMapping extension of the CERTCertificate
* pointed to by "nssCert", storing the resulting List of CertPolicyMaps at
* the address pointed to by "pCertPolicyMaps". If this certificate does not
* have a PolicyMapping extension, NULL will be stored. If a List is returned,
* it will be immutable.
*
* PARAMETERS
* "nssCert"
* Address of the Cert data whose extension is to be examined. Must be
* non-NULL.
* "pCertPolicyMaps"
* Address where the List of CertPolicyMaps will be stored. Must be
* non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Cert Error if the function fails in a non-fatal way.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
static PKIX_Error *
pkix_pl_Cert_DecodePolicyMapping(
CERTCertificate *nssCert,
PKIX_List **pCertPolicyMaps,
void *plContext)
{
SECStatus rv;
SECItem encodedCertPolicyMaps;
/* Allocated in the arena; freed in CERT_Destroy... */
CERTCertificatePolicyMappings *certPolMaps = NULL;
CERTPolicyMap **policyMaps = NULL;
/* Holder for the return value */
PKIX_List *maps = NULL;
PKIX_PL_OID *issuerDomainOID = NULL;
PKIX_PL_OID *subjectDomainOID = NULL;
PKIX_PL_CertPolicyMap *certPolicyMap = NULL;
PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyMapping");
PKIX_NULLCHECK_TWO(nssCert, pCertPolicyMaps);
/* get PolicyMappings as a SECItem */
PKIX_CERT_DEBUG("\t\tCERT_FindCertExtension).\n");
rv = CERT_FindCertExtension
(nssCert, SEC_OID_X509_POLICY_MAPPINGS, &encodedCertPolicyMaps);
if (SECSuccess != rv) {
*pCertPolicyMaps = NULL;
goto cleanup;
}
/* translate PolicyMaps to CERTCertificatePolicyMappings */
certPolMaps = CERT_DecodePolicyMappingsExtension
(&encodedCertPolicyMaps);
PORT_Free(encodedCertPolicyMaps.data);
if (!certPolMaps) {
PKIX_ERROR(PKIX_CERTDECODEPOLICYMAPPINGSEXTENSIONFAILED);
}
PKIX_NULLCHECK_ONE(certPolMaps->policyMaps);
policyMaps = certPolMaps->policyMaps;
/* create a List of CertPolicyMap Objects */
PKIX_CHECK(PKIX_List_Create(&maps, plContext),
PKIX_LISTCREATEFAILED);
/*
* Traverse the CERTCertificatePolicyMappings structure,
* building each CertPolicyMap object in turn
*/
do {
CERTPolicyMap *policyMap = *policyMaps;
/* create the OID for the issuer Domain Policy */
PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
(&policyMap->issuerDomainPolicy,
&issuerDomainOID, plContext),
PKIX_OIDCREATEFAILED);
/* create the OID for the subject Domain Policy */
PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
(&policyMap->subjectDomainPolicy,
&subjectDomainOID, plContext),
PKIX_OIDCREATEFAILED);
/* create the CertPolicyMap */
PKIX_CHECK(pkix_pl_CertPolicyMap_Create
(issuerDomainOID,
subjectDomainOID,
&certPolicyMap,
plContext),
PKIX_CERTPOLICYMAPCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(maps, (PKIX_PL_Object *)certPolicyMap, plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_DECREF(issuerDomainOID);
PKIX_DECREF(subjectDomainOID);
PKIX_DECREF(certPolicyMap);
policyMaps++;
} while (*policyMaps != NULL);
PKIX_CHECK(PKIX_List_SetImmutable(maps, plContext),
PKIX_LISTSETIMMUTABLEFAILED);
*pCertPolicyMaps = maps;
maps = NULL;
cleanup:
if (certPolMaps) {
PKIX_CERT_DEBUG
("\t\tCalling CERT_DestroyPolicyMappingsExtension).\n");
CERT_DestroyPolicyMappingsExtension(certPolMaps);
}
PKIX_DECREF(maps);
PKIX_DECREF(issuerDomainOID);
PKIX_DECREF(subjectDomainOID);
PKIX_DECREF(certPolicyMap);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_DecodePolicyConstraints
* DESCRIPTION:
*
* Decodes the contents of the PolicyConstraints extension in the
* CERTCertificate pointed to by "nssCert", to obtain SkipCerts values
* which are stored at the addresses "pExplicitPolicySkipCerts" and
* "pInhibitMappingSkipCerts", respectively. If this certificate does
* not have an PolicyConstraints extension, or if either of the optional
* components is not supplied, this function stores a value of -1 for any
* missing component.
*
* PARAMETERS
* "nssCert"
* Address of the Cert data whose extension is to be examined. Must be
* non-NULL.
* "pExplicitPolicySkipCerts"
* Address where the SkipCert value for the requireExplicitPolicy
* component will be stored. Must be non-NULL.
* "pInhibitMappingSkipCerts"
* Address where the SkipCert value for the inhibitPolicyMapping
* component will be stored. Must be non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Cert Error if the function fails in a non-fatal way.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
static PKIX_Error *
pkix_pl_Cert_DecodePolicyConstraints(
CERTCertificate *nssCert,
PKIX_Int32 *pExplicitPolicySkipCerts,
PKIX_Int32 *pInhibitMappingSkipCerts,
void *plContext)
{
CERTCertificatePolicyConstraints policyConstraints;
SECStatus rv;
SECItem encodedCertPolicyConstraints;
PKIX_Int32 explicitPolicySkipCerts = -1;
PKIX_Int32 inhibitMappingSkipCerts = -1;
PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyConstraints");
PKIX_NULLCHECK_THREE
(nssCert, pExplicitPolicySkipCerts, pInhibitMappingSkipCerts);
/* get the two skipCert values as SECItems */
PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n");
rv = CERT_FindCertExtension
(nssCert,
SEC_OID_X509_POLICY_CONSTRAINTS,
&encodedCertPolicyConstraints);
if (rv == SECSuccess) {
policyConstraints.explicitPolicySkipCerts.data =
(unsigned char *)&explicitPolicySkipCerts;
policyConstraints.inhibitMappingSkipCerts.data =
(unsigned char *)&inhibitMappingSkipCerts;
/* translate DER to CERTCertificatePolicyConstraints */
rv = CERT_DecodePolicyConstraintsExtension
(&policyConstraints, &encodedCertPolicyConstraints);
PORT_Free(encodedCertPolicyConstraints.data);
if (rv != SECSuccess) {
PKIX_ERROR
(PKIX_CERTDECODEPOLICYCONSTRAINTSEXTENSIONFAILED);
}
}
*pExplicitPolicySkipCerts = explicitPolicySkipCerts;
*pInhibitMappingSkipCerts = inhibitMappingSkipCerts;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_DecodeInhibitAnyPolicy
* DESCRIPTION:
*
* Decodes the contents of the InhibitAnyPolicy extension in the
* CERTCertificate pointed to by "nssCert", to obtain a SkipCerts value,
* which is stored at the address "pSkipCerts". If this certificate does
* not have an InhibitAnyPolicy extension, -1 will be stored.
*
* PARAMETERS
* "nssCert"
* Address of the Cert data whose InhibitAnyPolicy extension is to be
* processed. Must be non-NULL.
* "pSkipCerts"
* Address where the SkipCert value from the InhibitAnyPolicy extension
* will be stored. Must be non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Cert Error if the function fails in a non-fatal way.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
PKIX_Error *
pkix_pl_Cert_DecodeInhibitAnyPolicy(
CERTCertificate *nssCert,
PKIX_Int32 *pSkipCerts,
void *plContext)
{
CERTCertificateInhibitAny inhibitAny;
SECStatus rv;
SECItem encodedCertInhibitAny;
PKIX_Int32 skipCerts = -1;
PKIX_ENTER(CERT, "pkix_pl_Cert_DecodeInhibitAnyPolicy");
PKIX_NULLCHECK_TWO(nssCert, pSkipCerts);
/* get InhibitAny as a SECItem */
PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n");
rv = CERT_FindCertExtension
(nssCert, SEC_OID_X509_INHIBIT_ANY_POLICY, &encodedCertInhibitAny);
if (rv == SECSuccess) {
inhibitAny.inhibitAnySkipCerts.data =
(unsigned char *)&skipCerts;
/* translate DER to CERTCertificateInhibitAny */
rv = CERT_DecodeInhibitAnyExtension
(&inhibitAny, &encodedCertInhibitAny);
PORT_Free(encodedCertInhibitAny.data);
if (rv != SECSuccess) {
PKIX_ERROR(PKIX_CERTDECODEINHIBITANYEXTENSIONFAILED);
}
}
*pSkipCerts = skipCerts;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_GetNssSubjectAltNames
* DESCRIPTION:
*
* Retrieves the Subject Alternative Names of the certificate specified by
* "cert" and stores it at "pNssSubjAltNames". If the Subject Alternative
* Name extension is not present, NULL is returned at "pNssSubjAltNames".
* If the Subject Alternative Names has not been previously decoded, it is
* decoded here with lock on the "cert" unless the flag "hasLock" indicates
* the lock had been obtained at a higher call level.
*
* PARAMETERS
* "cert"
* Address of the certificate whose Subject Alternative Names extensions
* is retrieved. Must be non-NULL.
* "hasLock"
* Boolean indicates caller has acquired a lock.
* Must be non-NULL.
* "pNssSubjAltNames"
* Address where the returned Subject Alternative Names will be stored.
* Must be non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Cert Error if the function fails in a non-fatal way.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
static PKIX_Error *
pkix_pl_Cert_GetNssSubjectAltNames(
PKIX_PL_Cert *cert,
PKIX_Boolean hasLock,
CERTGeneralName **pNssSubjAltNames,
void *plContext)
{
CERTCertificate *nssCert = NULL;
CERTGeneralName *nssOriginalAltName = NULL;
PLArenaPool *arena = NULL;
SECItem altNameExtension = {siBuffer, NULL, 0};
SECStatus rv = SECFailure;
PKIX_ENTER(CERT, "pkix_pl_Cert_GetNssSubjectAltNames");
PKIX_NULLCHECK_THREE(cert, pNssSubjAltNames, cert->nssCert);
nssCert = cert->nssCert;
if ((cert->nssSubjAltNames == NULL) && (!cert->subjAltNamesAbsent)){
if (!hasLock) {
PKIX_OBJECT_LOCK(cert);
}
if ((cert->nssSubjAltNames == NULL) &&
(!cert->subjAltNamesAbsent)){
PKIX_PL_NSSCALLRV(CERT, rv, CERT_FindCertExtension,
(nssCert,
SEC_OID_X509_SUBJECT_ALT_NAME,
&altNameExtension));
if (rv != SECSuccess) {
*pNssSubjAltNames = NULL;
cert->subjAltNamesAbsent = PKIX_TRUE;
goto cleanup;
}
if (cert->arenaNameConstraints == NULL) {
PKIX_PL_NSSCALLRV(CERT, arena, PORT_NewArena,
(DER_DEFAULT_CHUNKSIZE));
if (arena == NULL) {
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
cert->arenaNameConstraints = arena;
}
PKIX_PL_NSSCALLRV
(CERT,
nssOriginalAltName,
(CERTGeneralName *) CERT_DecodeAltNameExtension,
(cert->arenaNameConstraints, &altNameExtension));
PKIX_PL_NSSCALL(CERT, PORT_Free, (altNameExtension.data));
if (nssOriginalAltName == NULL) {
PKIX_ERROR(PKIX_CERTDECODEALTNAMEEXTENSIONFAILED);
}
cert->nssSubjAltNames = nssOriginalAltName;
}
if (!hasLock) {
PKIX_OBJECT_UNLOCK(cert);
}
}
*pNssSubjAltNames = cert->nssSubjAltNames;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_CheckExtendKeyUsage
* DESCRIPTION:
*
* For each of the ON bit in "requiredExtendedKeyUsages" that represents its
* SECCertUsageEnum type, this function checks "cert"'s certType (extended
* key usage) and key usage with what is required for SECCertUsageEnum type.
*
* PARAMETERS
* "cert"
* Address of the certificate whose Extended Key Usage extensions
* is retrieved. Must be non-NULL.
* "requiredExtendedKeyUsages"
* An unsigned integer, its bit location is ON based on the required key
* usage value representing in SECCertUsageEnum.
* "pPass"
* Address where the return value, indicating key usage check passed, is
* stored. Must be non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Cert Error if the function fails in a non-fatal way.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
PKIX_Error *
pkix_pl_Cert_CheckExtendedKeyUsage(
PKIX_PL_Cert *cert,
PKIX_UInt32 requiredExtendedKeyUsages,
PKIX_Boolean *pPass,
void *plContext)
{
PKIX_PL_CertBasicConstraints *basicConstraints = NULL;
PKIX_UInt32 certType = 0;
PKIX_UInt32 requiredKeyUsage = 0;
PKIX_UInt32 requiredCertType = 0;
PKIX_UInt32 requiredExtendedKeyUsage = 0;
PKIX_UInt32 i;
PKIX_Boolean isCA = PKIX_FALSE;
SECStatus rv = SECFailure;
PKIX_ENTER(CERT, "pkix_pl_Cert_CheckExtendKeyUsage");
PKIX_NULLCHECK_THREE(cert, pPass, cert->nssCert);
*pPass = PKIX_FALSE;
PKIX_CERT_DEBUG("\t\tCalling cert_GetCertType).\n");
cert_GetCertType(cert->nssCert);
certType = cert->nssCert->nsCertType;
PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints
(cert,
&basicConstraints,
plContext),
PKIX_CERTGETBASICCONSTRAINTFAILED);
if (basicConstraints != NULL) {
PKIX_CHECK(PKIX_PL_BasicConstraints_GetCAFlag
(basicConstraints, &isCA, plContext),
PKIX_BASICCONSTRAINTSGETCAFLAGFAILED);
}
i = 0;
while (requiredExtendedKeyUsages != 0) {
/* Find the bit location of the right-most non-zero bit */
while (requiredExtendedKeyUsages != 0) {
if (((1 << i) & requiredExtendedKeyUsages) != 0) {
requiredExtendedKeyUsage = 1 << i;
break;
}
i++;
}
requiredExtendedKeyUsages ^= requiredExtendedKeyUsage;
requiredExtendedKeyUsage = i;
PKIX_PL_NSSCALLRV(CERT, rv, CERT_KeyUsageAndTypeForCertUsage,
(requiredExtendedKeyUsage,
isCA,
&requiredKeyUsage,
&requiredCertType));
if (!(certType & requiredCertType)) {
goto cleanup;
}
PKIX_PL_NSSCALLRV(CERT, rv, CERT_CheckKeyUsage,
(cert->nssCert, requiredKeyUsage));
if (rv != SECSuccess) {
goto cleanup;
}
i++;
}
*pPass = PKIX_TRUE;
cleanup:
PKIX_DECREF(basicConstraints);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_ToString_Helper
* DESCRIPTION:
*
* Helper function that creates a string representation of the Cert pointed
* to by "cert" and stores it at "pString", where the value of
* "partialString" determines whether a full or partial representation of
* the Cert is stored.
*
* PARAMETERS
* "cert"
* Address of Cert whose string representation is desired.
* Must be non-NULL.
* "partialString"
* Boolean indicating whether a partial Cert representation is desired.
* "pString"
* Address where object pointer will be stored. Must be non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Cert Error if the function fails in a non-fatal way.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
PKIX_Error *
pkix_pl_Cert_ToString_Helper(
PKIX_PL_Cert *cert,
PKIX_Boolean partialString,
PKIX_PL_String **pString,
void *plContext)
{
PKIX_PL_String *certString = NULL;
char *asciiFormat = NULL;
PKIX_PL_String *formatString = NULL;
PKIX_UInt32 certVersion;
PKIX_PL_BigInt *certSN = NULL;
PKIX_PL_String *certSNString = NULL;
PKIX_PL_X500Name *certIssuer = NULL;
PKIX_PL_String *certIssuerString = NULL;
PKIX_PL_X500Name *certSubject = NULL;
PKIX_PL_String *certSubjectString = NULL;
PKIX_PL_String *notBeforeString = NULL;
PKIX_PL_String *notAfterString = NULL;
PKIX_List *subjAltNames = NULL;
PKIX_PL_String *subjAltNamesString = NULL;
PKIX_PL_ByteArray *authKeyId = NULL;
PKIX_PL_String *authKeyIdString = NULL;
PKIX_PL_ByteArray *subjKeyId = NULL;
PKIX_PL_String *subjKeyIdString = NULL;
PKIX_PL_PublicKey *nssPubKey = NULL;
PKIX_PL_String *nssPubKeyString = NULL;
PKIX_List *critExtOIDs = NULL;
PKIX_PL_String *critExtOIDsString = NULL;
PKIX_List *extKeyUsages = NULL;
PKIX_PL_String *extKeyUsagesString = NULL;
PKIX_PL_CertBasicConstraints *basicConstraint = NULL;
PKIX_PL_String *certBasicConstraintsString = NULL;
PKIX_List *policyInfo = NULL;
PKIX_PL_String *certPolicyInfoString = NULL;
PKIX_List *certPolicyMappings = NULL;
PKIX_PL_String *certPolicyMappingsString = NULL;
PKIX_Int32 certExplicitPolicy = 0;
PKIX_Int32 certInhibitMapping = 0;
PKIX_Int32 certInhibitAnyPolicy = 0;
PKIX_PL_CertNameConstraints *nameConstraints = NULL;
PKIX_PL_String *nameConstraintsString = NULL;
PKIX_List *authorityInfoAccess = NULL;
PKIX_PL_String *authorityInfoAccessString = NULL;
PKIX_List *subjectInfoAccess = NULL;
PKIX_PL_String *subjectInfoAccessString = NULL;
PKIX_ENTER(CERT, "pkix_pl_Cert_ToString_Helper");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pString);
/*
* XXX Add to this format as certificate components are developed.
*/
if (partialString){
asciiFormat =
"\t[Issuer: %s\n"
"\t Subject: %s]";
} else {
asciiFormat =
"[\n"
"\tVersion: v%d\n"
"\tSerialNumber: %s\n"
"\tIssuer: %s\n"
"\tSubject: %s\n"
"\tValidity: [From: %s\n"
"\t To: %s]\n"
"\tSubjectAltNames: %s\n"
"\tAuthorityKeyId: %s\n"
"\tSubjectKeyId: %s\n"
"\tSubjPubKeyAlgId: %s\n"
"\tCritExtOIDs: %s\n"
"\tExtKeyUsages: %s\n"
"\tBasicConstraint: %s\n"
"\tCertPolicyInfo: %s\n"
"\tPolicyMappings: %s\n"
"\tExplicitPolicy: %d\n"
"\tInhibitMapping: %d\n"
"\tInhibitAnyPolicy:%d\n"
"\tNameConstraints: %s\n"
"\tAuthorityInfoAccess: %s\n"
"\tSubjectInfoAccess: %s\n"
"\tCacheFlag: %d\n"
"]\n";
}
PKIX_CHECK(PKIX_PL_String_Create
(PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext),
PKIX_STRINGCREATEFAILED);
/* Issuer */
PKIX_CHECK(PKIX_PL_Cert_GetIssuer
(cert, &certIssuer, plContext),
PKIX_CERTGETISSUERFAILED);
PKIX_CHECK(PKIX_PL_Object_ToString
((PKIX_PL_Object *)certIssuer, &certIssuerString, plContext),
PKIX_X500NAMETOSTRINGFAILED);
/* Subject */
PKIX_CHECK(PKIX_PL_Cert_GetSubject(cert, &certSubject, plContext),
PKIX_CERTGETSUBJECTFAILED);
PKIX_TOSTRING(certSubject, &certSubjectString, plContext,
PKIX_X500NAMETOSTRINGFAILED);
if (partialString){
PKIX_CHECK(PKIX_PL_Sprintf
(&certString,
plContext,
formatString,
certIssuerString,
certSubjectString),
PKIX_SPRINTFFAILED);
*pString = certString;
goto cleanup;
}
/* Version */
PKIX_CHECK(PKIX_PL_Cert_GetVersion(cert, &certVersion, plContext),
PKIX_CERTGETVERSIONFAILED);
/* SerialNumber */
PKIX_CHECK(PKIX_PL_Cert_GetSerialNumber(cert, &certSN, plContext),
PKIX_CERTGETSERIALNUMBERFAILED);
PKIX_CHECK(PKIX_PL_Object_ToString
((PKIX_PL_Object *)certSN, &certSNString, plContext),
PKIX_BIGINTTOSTRINGFAILED);
/* Validity: NotBefore */
PKIX_CHECK(pkix_pl_Date_ToString_Helper
(&(cert->nssCert->validity.notBefore),
&notBeforeString,
plContext),
PKIX_DATETOSTRINGHELPERFAILED);
/* Validity: NotAfter */
PKIX_CHECK(pkix_pl_Date_ToString_Helper
(&(cert->nssCert->validity.notAfter),
&notAfterString,
plContext),
PKIX_DATETOSTRINGHELPERFAILED);
/* SubjectAltNames */
PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames
(cert, &subjAltNames, plContext),
PKIX_CERTGETSUBJECTALTNAMESFAILED);
PKIX_TOSTRING(subjAltNames, &subjAltNamesString, plContext,
PKIX_LISTTOSTRINGFAILED);
/* AuthorityKeyIdentifier */
PKIX_CHECK(PKIX_PL_Cert_GetAuthorityKeyIdentifier
(cert, &authKeyId, plContext),
PKIX_CERTGETAUTHORITYKEYIDENTIFIERFAILED);
PKIX_TOSTRING(authKeyId, &authKeyIdString, plContext,
PKIX_BYTEARRAYTOSTRINGFAILED);
/* SubjectKeyIdentifier */
PKIX_CHECK(PKIX_PL_Cert_GetSubjectKeyIdentifier
(cert, &subjKeyId, plContext),
PKIX_CERTGETSUBJECTKEYIDENTIFIERFAILED);
PKIX_TOSTRING(subjKeyId, &subjKeyIdString, plContext,
PKIX_BYTEARRAYTOSTRINGFAILED);
/* SubjectPublicKey */
PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
(cert, &nssPubKey, plContext),
PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
PKIX_CHECK(PKIX_PL_Object_ToString
((PKIX_PL_Object *)nssPubKey, &nssPubKeyString, plContext),
PKIX_PUBLICKEYTOSTRINGFAILED);
/* CriticalExtensionOIDs */
PKIX_CHECK(PKIX_PL_Cert_GetCriticalExtensionOIDs
(cert, &critExtOIDs, plContext),
PKIX_CERTGETCRITICALEXTENSIONOIDSFAILED);
PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext,
PKIX_LISTTOSTRINGFAILED);
/* ExtendedKeyUsages */
PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage
(cert, &extKeyUsages, plContext),
PKIX_CERTGETEXTENDEDKEYUSAGEFAILED);
PKIX_TOSTRING(extKeyUsages, &extKeyUsagesString, plContext,
PKIX_LISTTOSTRINGFAILED);
/* CertBasicConstraints */
PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints
(cert, &basicConstraint, plContext),
PKIX_CERTGETBASICCONSTRAINTSFAILED);
PKIX_TOSTRING(basicConstraint, &certBasicConstraintsString, plContext,
PKIX_CERTBASICCONSTRAINTSTOSTRINGFAILED);
/* CertPolicyInfo */
PKIX_CHECK(PKIX_PL_Cert_GetPolicyInformation
(cert, &policyInfo, plContext),
PKIX_CERTGETPOLICYINFORMATIONFAILED);
PKIX_TOSTRING(policyInfo, &certPolicyInfoString, plContext,
PKIX_LISTTOSTRINGFAILED);
/* Advanced Policies */
PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappings
(cert, &certPolicyMappings, plContext),
PKIX_CERTGETPOLICYMAPPINGSFAILED);
PKIX_TOSTRING(certPolicyMappings, &certPolicyMappingsString, plContext,
PKIX_LISTTOSTRINGFAILED);
PKIX_CHECK(PKIX_PL_Cert_GetRequireExplicitPolicy
(cert, &certExplicitPolicy, plContext),
PKIX_CERTGETREQUIREEXPLICITPOLICYFAILED);
PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappingInhibited
(cert, &certInhibitMapping, plContext),
PKIX_CERTGETPOLICYMAPPINGINHIBITEDFAILED);
PKIX_CHECK(PKIX_PL_Cert_GetInhibitAnyPolicy
(cert, &certInhibitAnyPolicy, plContext),
PKIX_CERTGETINHIBITANYPOLICYFAILED);
/* Name Constraints */
PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints
(cert, &nameConstraints, plContext),
PKIX_CERTGETNAMECONSTRAINTSFAILED);
PKIX_TOSTRING(nameConstraints, &nameConstraintsString, plContext,
PKIX_LISTTOSTRINGFAILED);
/* Authority Information Access */
PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
(cert, &authorityInfoAccess, plContext),
PKIX_CERTGETAUTHORITYINFOACCESSFAILED);
PKIX_TOSTRING(authorityInfoAccess, &authorityInfoAccessString, plContext,
PKIX_LISTTOSTRINGFAILED);
/* Subject Information Access */
PKIX_CHECK(PKIX_PL_Cert_GetSubjectInfoAccess
(cert, &subjectInfoAccess, plContext),
PKIX_CERTGETSUBJECTINFOACCESSFAILED);
PKIX_TOSTRING(subjectInfoAccess, &subjectInfoAccessString, plContext,
PKIX_LISTTOSTRINGFAILED);
PKIX_CHECK(PKIX_PL_Sprintf
(&certString,
plContext,
formatString,
certVersion + 1,
certSNString,
certIssuerString,
certSubjectString,
notBeforeString,
notAfterString,
subjAltNamesString,
authKeyIdString,
subjKeyIdString,
nssPubKeyString,
critExtOIDsString,
extKeyUsagesString,
certBasicConstraintsString,
certPolicyInfoString,
certPolicyMappingsString,
certExplicitPolicy, /* an Int32, not a String */
certInhibitMapping, /* an Int32, not a String */
certInhibitAnyPolicy, /* an Int32, not a String */
nameConstraintsString,
authorityInfoAccessString,
subjectInfoAccessString,
cert->cacheFlag), /* a boolean */
PKIX_SPRINTFFAILED);
*pString = certString;
cleanup:
PKIX_DECREF(certSN);
PKIX_DECREF(certSNString);
PKIX_DECREF(certIssuer);
PKIX_DECREF(certIssuerString);
PKIX_DECREF(certSubject);
PKIX_DECREF(certSubjectString);
PKIX_DECREF(notBeforeString);
PKIX_DECREF(notAfterString);
PKIX_DECREF(subjAltNames);
PKIX_DECREF(subjAltNamesString);
PKIX_DECREF(authKeyId);
PKIX_DECREF(authKeyIdString);
PKIX_DECREF(subjKeyId);
PKIX_DECREF(subjKeyIdString);
PKIX_DECREF(nssPubKey);
PKIX_DECREF(nssPubKeyString);
PKIX_DECREF(critExtOIDs);
PKIX_DECREF(critExtOIDsString);
PKIX_DECREF(extKeyUsages);
PKIX_DECREF(extKeyUsagesString);
PKIX_DECREF(basicConstraint);
PKIX_DECREF(certBasicConstraintsString);
PKIX_DECREF(policyInfo);
PKIX_DECREF(certPolicyInfoString);
PKIX_DECREF(certPolicyMappings);
PKIX_DECREF(certPolicyMappingsString);
PKIX_DECREF(nameConstraints);
PKIX_DECREF(nameConstraintsString);
PKIX_DECREF(authorityInfoAccess);
PKIX_DECREF(authorityInfoAccessString);
PKIX_DECREF(subjectInfoAccess);
PKIX_DECREF(subjectInfoAccessString);
PKIX_DECREF(formatString);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_Destroy
* (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_Cert_Destroy(
PKIX_PL_Object *object,
void *plContext)
{
PKIX_PL_Cert *cert = NULL;
PKIX_ENTER(CERT, "pkix_pl_Cert_Destroy");
PKIX_NULLCHECK_ONE(object);
PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext),
PKIX_OBJECTNOTCERT);
cert = (PKIX_PL_Cert*)object;
PKIX_DECREF(cert->subject);
PKIX_DECREF(cert->issuer);
PKIX_DECREF(cert->subjAltNames);
PKIX_DECREF(cert->publicKeyAlgId);
PKIX_DECREF(cert->publicKey);
PKIX_DECREF(cert->serialNumber);
PKIX_DECREF(cert->critExtOids);
PKIX_DECREF(cert->authKeyId);
PKIX_DECREF(cert->subjKeyId);
PKIX_DECREF(cert->extKeyUsages);
PKIX_DECREF(cert->certBasicConstraints);
PKIX_DECREF(cert->certPolicyInfos);
PKIX_DECREF(cert->certPolicyMappings);
PKIX_DECREF(cert->nameConstraints);
PKIX_DECREF(cert->store);
PKIX_DECREF(cert->authorityInfoAccess);
PKIX_DECREF(cert->subjectInfoAccess);
PKIX_DECREF(cert->crldpList);
if (cert->arenaNameConstraints){
/* This arena was allocated for SubjectAltNames */
PKIX_PL_NSSCALL(CERT, PORT_FreeArena,
(cert->arenaNameConstraints, PR_FALSE));
cert->arenaNameConstraints = NULL;
cert->nssSubjAltNames = NULL;
}
CERT_DestroyCertificate(cert->nssCert);
cert->nssCert = NULL;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_ToString
* (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_Cert_ToString(
PKIX_PL_Object *object,
PKIX_PL_String **pString,
void *plContext)
{
PKIX_PL_String *certString = NULL;
PKIX_PL_Cert *pkixCert = NULL;
PKIX_ENTER(CERT, "pkix_pl_Cert_toString");
PKIX_NULLCHECK_TWO(object, pString);
PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext),
PKIX_OBJECTNOTCERT);
pkixCert = (PKIX_PL_Cert *)object;
PKIX_CHECK(pkix_pl_Cert_ToString_Helper
(pkixCert, PKIX_FALSE, &certString, plContext),
PKIX_CERTTOSTRINGHELPERFAILED);
*pString = certString;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_Hashcode
* (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_Cert_Hashcode(
PKIX_PL_Object *object,
PKIX_UInt32 *pHashcode,
void *plContext)
{
PKIX_PL_Cert *pkixCert = NULL;
CERTCertificate *nssCert = NULL;
unsigned char *derBytes = NULL;
PKIX_UInt32 derLength;
PKIX_UInt32 certHash;
PKIX_ENTER(CERT, "pkix_pl_Cert_Hashcode");
PKIX_NULLCHECK_TWO(object, pHashcode);
PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext),
PKIX_OBJECTNOTCERT);
pkixCert = (PKIX_PL_Cert *)object;
nssCert = pkixCert->nssCert;
derBytes = (nssCert->derCert).data;
derLength = (nssCert->derCert).len;
PKIX_CHECK(pkix_hash(derBytes, derLength, &certHash, plContext),
PKIX_HASHFAILED);
*pHashcode = certHash;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_Equals
* (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_Cert_Equals(
PKIX_PL_Object *firstObject,
PKIX_PL_Object *secondObject,
PKIX_Boolean *pResult,
void *plContext)
{
CERTCertificate *firstCert = NULL;
CERTCertificate *secondCert = NULL;
PKIX_UInt32 secondType;
PKIX_Boolean cmpResult;
PKIX_ENTER(CERT, "pkix_pl_Cert_Equals");
PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
/* test that firstObject is a Cert */
PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CERT_TYPE, plContext),
PKIX_FIRSTOBJECTNOTCERT);
/*
* Since we know firstObject is a Cert, if both references are
* identical, they must be equal
*/
if (firstObject == secondObject){
*pResult = PKIX_TRUE;
goto cleanup;
}
/*
* If secondObject isn't a Cert, we don't throw an error.
* We simply return a Boolean result of FALSE
*/
*pResult = PKIX_FALSE;
PKIX_CHECK(PKIX_PL_Object_GetType
(secondObject, &secondType, plContext),
PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
if (secondType != PKIX_CERT_TYPE) goto cleanup;
firstCert = ((PKIX_PL_Cert *)firstObject)->nssCert;
secondCert = ((PKIX_PL_Cert *)secondObject)->nssCert;
PKIX_NULLCHECK_TWO(firstCert, secondCert);
/* CERT_CompareCerts does byte comparison on DER encodings of certs */
PKIX_CERT_DEBUG("\t\tCalling CERT_CompareCerts).\n");
cmpResult = CERT_CompareCerts(firstCert, secondCert);
*pResult = cmpResult;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_RegisterSelf
* DESCRIPTION:
* Registers PKIX_CERT_TYPE and its related functions with systemClasses[]
* THREAD SAFETY:
* Not Thread Safe - for performance and complexity reasons
*
* Since this function is only called by PKIX_PL_Initialize, which should
* only be called once, it is acceptable that this function is not
* thread-safe.
*/
PKIX_Error *
pkix_pl_Cert_RegisterSelf(void *plContext)
{
extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
pkix_ClassTable_Entry entry;
PKIX_ENTER(CERT, "pkix_pl_Cert_RegisterSelf");
entry.description = "Cert";
entry.objCounter = 0;
entry.typeObjectSize = sizeof(PKIX_PL_Cert);
entry.destructor = pkix_pl_Cert_Destroy;
entry.equalsFunction = pkix_pl_Cert_Equals;
entry.hashcodeFunction = pkix_pl_Cert_Hashcode;
entry.toStringFunction = pkix_pl_Cert_ToString;
entry.comparator = NULL;
entry.duplicateFunction = pkix_duplicateImmutable;
systemClasses[PKIX_CERT_TYPE] = entry;
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_CreateWithNSSCert
* DESCRIPTION:
*
* Creates a new certificate using the CERTCertificate pointed to by "nssCert"
* and stores it at "pCert". Once created, a Cert is immutable.
*
* This function is primarily used as a convenience function for the
* performance tests that have easy access to a CERTCertificate.
*
* PARAMETERS:
* "nssCert"
* Address of CERTCertificate representing the NSS certificate.
* Must be non-NULL.
* "pCert"
* Address where object pointer will be stored. Must be non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Cert Error if the function fails in a non-fatal way.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
PKIX_Error *
pkix_pl_Cert_CreateWithNSSCert(
CERTCertificate *nssCert,
PKIX_PL_Cert **pCert,
void *plContext)
{
PKIX_PL_Cert *cert = NULL;
PKIX_ENTER(CERT, "pkix_pl_Cert_CreateWithNSSCert");
PKIX_NULLCHECK_TWO(pCert, nssCert);
/* create a PKIX_PL_Cert object */
PKIX_CHECK(PKIX_PL_Object_Alloc
(PKIX_CERT_TYPE,
sizeof (PKIX_PL_Cert),
(PKIX_PL_Object **)&cert,
plContext),
PKIX_COULDNOTCREATEOBJECT);
/* populate the nssCert field */
cert->nssCert = nssCert;
/* initialize remaining fields */
/*
* Fields ending with Absent are initialized to PKIX_FALSE so that the
* first time we need the value we will look for it. If we find it is
* actually absent, the flag will at that time be set to PKIX_TRUE to
* prevent searching for it later.
* Fields ending with Processed are those where a value is defined
* for the Absent case, and a value of zero is possible. When the
* flag is still true we have to look for the field, set the default
* value if necessary, and set the Processed flag to PKIX_TRUE.
*/
cert->subject = NULL;
cert->issuer = NULL;
cert->subjAltNames = NULL;
cert->subjAltNamesAbsent = PKIX_FALSE;
cert->publicKeyAlgId = NULL;
cert->publicKey = NULL;
cert->serialNumber = NULL;
cert->critExtOids = NULL;
cert->subjKeyId = NULL;
cert->subjKeyIdAbsent = PKIX_FALSE;
cert->authKeyId = NULL;
cert->authKeyIdAbsent = PKIX_FALSE;
cert->extKeyUsages = NULL;
cert->extKeyUsagesAbsent = PKIX_FALSE;
cert->certBasicConstraints = NULL;
cert->basicConstraintsAbsent = PKIX_FALSE;
cert->certPolicyInfos = NULL;
cert->policyInfoAbsent = PKIX_FALSE;
cert->policyMappingsAbsent = PKIX_FALSE;
cert->certPolicyMappings = NULL;
cert->policyConstraintsProcessed = PKIX_FALSE;
cert->policyConstraintsExplicitPolicySkipCerts = 0;
cert->policyConstraintsInhibitMappingSkipCerts = 0;
cert->inhibitAnyPolicyProcessed = PKIX_FALSE;
cert->inhibitAnySkipCerts = 0;
cert->nameConstraints = NULL;
cert->nameConstraintsAbsent = PKIX_FALSE;
cert->arenaNameConstraints = NULL;
cert->nssSubjAltNames = NULL;
cert->cacheFlag = PKIX_FALSE;
cert->store = NULL;
cert->authorityInfoAccess = NULL;
cert->subjectInfoAccess = NULL;
cert->isUserTrustAnchor = PKIX_FALSE;
cert->crldpList = NULL;
*pCert = cert;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: pkix_pl_Cert_CreateToList
* DESCRIPTION:
*
* Creates a new certificate using the DER-encoding pointed to by "derCertItem"
* and appends it to the list pointed to by "certList". If Cert creation fails,
* the function returns with certList unchanged, but any decoding Error is
* discarded.
*
* PARAMETERS:
* "derCertItem"
* Address of SECItem containing the DER representation of a certificate.
* Must be non-NULL.
* "certList"
* Address of List to which the Cert will be appended, if successfully
* created. May be empty, but must be non-NULL.
* "plContext"
* Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Cert Error if the function fails in a non-fatal way.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
PKIX_Error *
pkix_pl_Cert_CreateToList(
SECItem *derCertItem,
PKIX_List *certList,
void *plContext)
{
CERTCertificate *nssCert = NULL;
PKIX_PL_Cert *cert = NULL;
CERTCertDBHandle *handle;
PKIX_ENTER(CERT, "pkix_pl_Cert_CreateToList");
PKIX_NULLCHECK_TWO(derCertItem, certList);
handle = CERT_GetDefaultCertDB();
nssCert = CERT_NewTempCertificate(handle, derCertItem,
/* nickname */ NULL,
/* isPerm */ PR_FALSE,
/* copyDer */ PR_TRUE);
if (!nssCert) {
goto cleanup;
}
PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert
(nssCert, &cert, plContext),
PKIX_CERTCREATEWITHNSSCERTFAILED);
nssCert = NULL;
PKIX_CHECK(PKIX_List_AppendItem
(certList, (PKIX_PL_Object *) cert, plContext),
PKIX_LISTAPPENDITEMFAILED);
cleanup:
if (nssCert) {
CERT_DestroyCertificate(nssCert);
}
PKIX_DECREF(cert);
PKIX_RETURN(CERT);
}
/* --Public-Functions------------------------------------------------------- */
/*
* FUNCTION: PKIX_PL_Cert_Create (see comments in pkix_pl_pki.h)
* XXX We may want to cache the cert after parsing it, so it can be reused
* XXX Are the NSS/NSPR functions thread safe
*/
PKIX_Error *
PKIX_PL_Cert_Create(
PKIX_PL_ByteArray *byteArray,
PKIX_PL_Cert **pCert,
void *plContext)
{
CERTCertificate *nssCert = NULL;
SECItem *derCertItem = NULL;
void *derBytes = NULL;
PKIX_UInt32 derLength;
PKIX_PL_Cert *cert = NULL;
CERTCertDBHandle *handle;
PKIX_ENTER(CERT, "PKIX_PL_Cert_Create");
PKIX_NULLCHECK_TWO(pCert, byteArray);
PKIX_CHECK(PKIX_PL_ByteArray_GetPointer
(byteArray, &derBytes, plContext),
PKIX_BYTEARRAYGETPOINTERFAILED);
PKIX_CHECK(PKIX_PL_ByteArray_GetLength
(byteArray, &derLength, plContext),
PKIX_BYTEARRAYGETLENGTHFAILED);
derCertItem = SECITEM_AllocItem(NULL, NULL, derLength);
if (derCertItem == NULL){
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
(void) PORT_Memcpy(derCertItem->data, derBytes, derLength);
/*
* setting copyDER to true forces NSS to make its own copy of the DER,
* allowing us to free our copy without worrying about whether NSS
* is still using it
*/
handle = CERT_GetDefaultCertDB();
nssCert = CERT_NewTempCertificate(handle, derCertItem,
/* nickname */ NULL,
/* isPerm */ PR_FALSE,
/* copyDer */ PR_TRUE);
if (!nssCert){
PKIX_ERROR(PKIX_CERTDECODEDERCERTIFICATEFAILED);
}
PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert
(nssCert, &cert, plContext),
PKIX_CERTCREATEWITHNSSCERTFAILED);
*pCert = cert;
cleanup:
if (derCertItem){
SECITEM_FreeItem(derCertItem, PKIX_TRUE);
}
if (nssCert && PKIX_ERROR_RECEIVED){
PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyCertificate).\n");
CERT_DestroyCertificate(nssCert);
nssCert = NULL;
}
PKIX_FREE(derBytes);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_CreateFromCERTCertificate
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_CreateFromCERTCertificate(
const CERTCertificate *nssCert,
PKIX_PL_Cert **pCert,
void *plContext)
{
void *buf = NULL;
PKIX_UInt32 len;
PKIX_PL_ByteArray *byteArray = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_CreateWithNssCert");
PKIX_NULLCHECK_TWO(pCert, nssCert);
buf = (void*)nssCert->derCert.data;
len = nssCert->derCert.len;
PKIX_CHECK(
PKIX_PL_ByteArray_Create(buf, len, &byteArray, plContext),
PKIX_BYTEARRAYCREATEFAILED);
PKIX_CHECK(
PKIX_PL_Cert_Create(byteArray, pCert, plContext),
PKIX_CERTCREATEWITHNSSCERTFAILED);
#ifdef PKIX_UNDEF
/* will be tested and used as a patch for bug 391612 */
nssCert = CERT_DupCertificate(nssInCert);
PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert
(nssCert, &cert, plContext),
PKIX_CERTCREATEWITHNSSCERTFAILED);
#endif /* PKIX_UNDEF */
cleanup:
#ifdef PKIX_UNDEF
if (nssCert && PKIX_ERROR_RECEIVED){
PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyCertificate).\n");
CERT_DestroyCertificate(nssCert);
nssCert = NULL;
}
#endif /* PKIX_UNDEF */
PKIX_DECREF(byteArray);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetVersion (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetVersion(
PKIX_PL_Cert *cert,
PKIX_UInt32 *pVersion,
void *plContext)
{
CERTCertificate *nssCert = NULL;
PKIX_UInt32 myVersion = 0; /* v1 */
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetVersion");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pVersion);
nssCert = cert->nssCert;
if (nssCert->version.len != 0) {
myVersion = *(nssCert->version.data);
}
if (myVersion > 2){
PKIX_ERROR(PKIX_VERSIONVALUEMUSTBEV1V2ORV3);
}
*pVersion = myVersion;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetSerialNumber (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetSerialNumber(
PKIX_PL_Cert *cert,
PKIX_PL_BigInt **pSerialNumber,
void *plContext)
{
CERTCertificate *nssCert = NULL;
SECItem serialNumItem;
PKIX_PL_BigInt *serialNumber = NULL;
char *bytes = NULL;
PKIX_UInt32 length;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSerialNumber");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSerialNumber);
if (cert->serialNumber == NULL){
PKIX_OBJECT_LOCK(cert);
if (cert->serialNumber == NULL){
nssCert = cert->nssCert;
serialNumItem = nssCert->serialNumber;
length = serialNumItem.len;
bytes = (char *)serialNumItem.data;
PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes
(bytes, length, &serialNumber, plContext),
PKIX_BIGINTCREATEWITHBYTESFAILED);
/* save a cached copy in case it is asked for again */
cert->serialNumber = serialNumber;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->serialNumber);
*pSerialNumber = cert->serialNumber;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetSubject (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetSubject(
PKIX_PL_Cert *cert,
PKIX_PL_X500Name **pCertSubject,
void *plContext)
{
PKIX_PL_X500Name *pkixSubject = NULL;
CERTName *subjName = NULL;
SECItem *derSubjName = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubject");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCertSubject);
/* if we don't have a cached copy from before, we create one */
if (cert->subject == NULL){
PKIX_OBJECT_LOCK(cert);
if (cert->subject == NULL){
subjName = &cert->nssCert->subject;
derSubjName = &cert->nssCert->derSubject;
/* if there is no subject name */
if (derSubjName->data == NULL) {
pkixSubject = NULL;
} else {
PKIX_CHECK(PKIX_PL_X500Name_CreateFromCERTName
(derSubjName, subjName, &pkixSubject,
plContext),
PKIX_X500NAMECREATEFROMCERTNAMEFAILED);
}
/* save a cached copy in case it is asked for again */
cert->subject = pkixSubject;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->subject);
*pCertSubject = cert->subject;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetIssuer (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetIssuer(
PKIX_PL_Cert *cert,
PKIX_PL_X500Name **pCertIssuer,
void *plContext)
{
PKIX_PL_X500Name *pkixIssuer = NULL;
SECItem *derIssuerName = NULL;
CERTName *issuerName = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetIssuer");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCertIssuer);
/* if we don't have a cached copy from before, we create one */
if (cert->issuer == NULL){
PKIX_OBJECT_LOCK(cert);
if (cert->issuer == NULL){
issuerName = &cert->nssCert->issuer;
derIssuerName = &cert->nssCert->derIssuer;
/* if there is no subject name */
PKIX_CHECK(PKIX_PL_X500Name_CreateFromCERTName
(derIssuerName, issuerName,
&pkixIssuer, plContext),
PKIX_X500NAMECREATEFROMCERTNAMEFAILED);
/* save a cached copy in case it is asked for again */
cert->issuer = pkixIssuer;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->issuer);
*pCertIssuer = cert->issuer;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetSubjectAltNames (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetSubjectAltNames(
PKIX_PL_Cert *cert,
PKIX_List **pSubjectAltNames, /* list of PKIX_PL_GeneralName */
void *plContext)
{
PKIX_PL_GeneralName *pkixAltName = NULL;
PKIX_List *altNamesList = NULL;
CERTGeneralName *nssOriginalAltName = NULL;
CERTGeneralName *nssTempAltName = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectAltNames");
PKIX_NULLCHECK_TWO(cert, pSubjectAltNames);
/* if we don't have a cached copy from before, we create one */
if ((cert->subjAltNames == NULL) && (!cert->subjAltNamesAbsent)){
PKIX_OBJECT_LOCK(cert);
if ((cert->subjAltNames == NULL) &&
(!cert->subjAltNamesAbsent)){
PKIX_CHECK(pkix_pl_Cert_GetNssSubjectAltNames
(cert,
PKIX_TRUE,
&nssOriginalAltName,
plContext),
PKIX_CERTGETNSSSUBJECTALTNAMESFAILED);
if (nssOriginalAltName == NULL) {
cert->subjAltNamesAbsent = PKIX_TRUE;
pSubjectAltNames = NULL;
goto cleanup;
}
nssTempAltName = nssOriginalAltName;
PKIX_CHECK(PKIX_List_Create(&altNamesList, plContext),
PKIX_LISTCREATEFAILED);
do {
PKIX_CHECK(pkix_pl_GeneralName_Create
(nssTempAltName, &pkixAltName, plContext),
PKIX_GENERALNAMECREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(altNamesList,
(PKIX_PL_Object *)pkixAltName,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_DECREF(pkixAltName);
PKIX_CERT_DEBUG
("\t\tCalling CERT_GetNextGeneralName).\n");
nssTempAltName = CERT_GetNextGeneralName
(nssTempAltName);
} while (nssTempAltName != nssOriginalAltName);
/* save a cached copy in case it is asked for again */
cert->subjAltNames = altNamesList;
PKIX_CHECK(PKIX_List_SetImmutable
(cert->subjAltNames, plContext),
PKIX_LISTSETIMMUTABLEFAILED);
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->subjAltNames);
*pSubjectAltNames = cert->subjAltNames;
cleanup:
PKIX_DECREF(pkixAltName);
if (PKIX_ERROR_RECEIVED){
PKIX_DECREF(altNamesList);
}
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetAllSubjectNames (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetAllSubjectNames(
PKIX_PL_Cert *cert,
PKIX_List **pAllSubjectNames, /* list of PKIX_PL_GeneralName */
void *plContext)
{
CERTGeneralName *nssOriginalSubjectName = NULL;
CERTGeneralName *nssTempSubjectName = NULL;
PKIX_List *allSubjectNames = NULL;
PKIX_PL_GeneralName *pkixSubjectName = NULL;
PLArenaPool *arena = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetAllSubjectNames");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pAllSubjectNames);
if (cert->nssCert->subjectName == NULL){
/* if there is no subject DN, just get altnames */
PKIX_CHECK(pkix_pl_Cert_GetNssSubjectAltNames
(cert,
PKIX_FALSE, /* hasLock */
&nssOriginalSubjectName,
plContext),
PKIX_CERTGETNSSSUBJECTALTNAMESFAILED);
} else { /* get subject DN and altnames */
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
/* This NSS call returns both Subject and Subject Alt Names */
PKIX_CERT_DEBUG("\t\tCalling CERT_GetCertificateNames\n");
nssOriginalSubjectName =
CERT_GetCertificateNames(cert->nssCert, arena);
}
if (nssOriginalSubjectName == NULL) {
pAllSubjectNames = NULL;
goto cleanup;
}
nssTempSubjectName = nssOriginalSubjectName;
PKIX_CHECK(PKIX_List_Create(&allSubjectNames, plContext),
PKIX_LISTCREATEFAILED);
do {
PKIX_CHECK(pkix_pl_GeneralName_Create
(nssTempSubjectName, &pkixSubjectName, plContext),
PKIX_GENERALNAMECREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(allSubjectNames,
(PKIX_PL_Object *)pkixSubjectName,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_DECREF(pkixSubjectName);
PKIX_CERT_DEBUG
("\t\tCalling CERT_GetNextGeneralName).\n");
nssTempSubjectName = CERT_GetNextGeneralName
(nssTempSubjectName);
} while (nssTempSubjectName != nssOriginalSubjectName);
*pAllSubjectNames = allSubjectNames;
cleanup:
if (PKIX_ERROR_RECEIVED){
PKIX_DECREF(allSubjectNames);
}
if (arena){
PORT_FreeArena(arena, PR_FALSE);
}
PKIX_DECREF(pkixSubjectName);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetSubjectPublicKeyAlgId
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetSubjectPublicKeyAlgId(
PKIX_PL_Cert *cert,
PKIX_PL_OID **pSubjKeyAlgId,
void *plContext)
{
PKIX_PL_OID *pubKeyAlgId = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectPublicKeyAlgId");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSubjKeyAlgId);
/* if we don't have a cached copy from before, we create one */
if (cert->publicKeyAlgId == NULL){
PKIX_OBJECT_LOCK(cert);
if (cert->publicKeyAlgId == NULL){
CERTCertificate *nssCert = cert->nssCert;
SECAlgorithmID *algorithm;
SECItem *algBytes;
algorithm = &nssCert->subjectPublicKeyInfo.algorithm;
algBytes = &algorithm->algorithm;
if (!algBytes->data || !algBytes->len) {
PKIX_ERROR_FATAL(PKIX_ALGORITHMBYTESLENGTH0);
}
PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
(algBytes, &pubKeyAlgId, plContext),
PKIX_OIDCREATEFAILED);
/* save a cached copy in case it is asked for again */
cert->publicKeyAlgId = pubKeyAlgId;
pubKeyAlgId = NULL;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->publicKeyAlgId);
*pSubjKeyAlgId = cert->publicKeyAlgId;
cleanup:
PKIX_DECREF(pubKeyAlgId);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetSubjectPublicKey (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetSubjectPublicKey(
PKIX_PL_Cert *cert,
PKIX_PL_PublicKey **pPublicKey,
void *plContext)
{
PKIX_PL_PublicKey *pkixPubKey = NULL;
SECStatus rv;
CERTSubjectPublicKeyInfo *from = NULL;
CERTSubjectPublicKeyInfo *to = NULL;
SECItem *fromItem = NULL;
SECItem *toItem = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectPublicKey");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pPublicKey);
/* if we don't have a cached copy from before, we create one */
if (cert->publicKey == NULL){
PKIX_OBJECT_LOCK(cert);
if (cert->publicKey == NULL){
/* create a PKIX_PL_PublicKey object */
PKIX_CHECK(PKIX_PL_Object_Alloc
(PKIX_PUBLICKEY_TYPE,
sizeof (PKIX_PL_PublicKey),
(PKIX_PL_Object **)&pkixPubKey,
plContext),
PKIX_COULDNOTCREATEOBJECT);
/* initialize fields */
pkixPubKey->nssSPKI = NULL;
/* populate the SPKI field */
PKIX_CHECK(PKIX_PL_Malloc
(sizeof (CERTSubjectPublicKeyInfo),
(void **)&pkixPubKey->nssSPKI,
plContext),
PKIX_MALLOCFAILED);
to = pkixPubKey->nssSPKI;
from = &cert->nssCert->subjectPublicKeyInfo;
PKIX_NULLCHECK_TWO(to, from);
PKIX_CERT_DEBUG
("\t\tCalling SECOID_CopyAlgorithmID).\n");
rv = SECOID_CopyAlgorithmID
(NULL, &to->algorithm, &from->algorithm);
if (rv != SECSuccess) {
PKIX_ERROR(PKIX_SECOIDCOPYALGORITHMIDFAILED);
}
/*
* NSS stores the length of subjectPublicKey in bits.
* Therefore, we use that length converted to bytes
* using ((length+7)>>3) before calling PORT_Memcpy
* in order to avoid "read from uninitialized memory"
* errors.
*/
toItem = &to->subjectPublicKey;
fromItem = &from->subjectPublicKey;
PKIX_NULLCHECK_TWO(toItem, fromItem);
toItem->type = fromItem->type;
toItem->data =
(unsigned char*) PORT_ZAlloc(fromItem->len);
if (!toItem->data){
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
(void) PORT_Memcpy(toItem->data,
fromItem->data,
(fromItem->len + 7)>>3);
toItem->len = fromItem->len;
/* save a cached copy in case it is asked for again */
cert->publicKey = pkixPubKey;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->publicKey);
*pPublicKey = cert->publicKey;
cleanup:
if (PKIX_ERROR_RECEIVED && pkixPubKey){
PKIX_DECREF(pkixPubKey);
cert->publicKey = NULL;
}
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetCriticalExtensionOIDs
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetCriticalExtensionOIDs(
PKIX_PL_Cert *cert,
PKIX_List **pList, /* list of PKIX_PL_OID */
void *plContext)
{
PKIX_List *oidsList = NULL;
CERTCertExtension **extensions = NULL;
CERTCertificate *nssCert = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetCriticalExtensionOIDs");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pList);
/* if we don't have a cached copy from before, we create one */
if (cert->critExtOids == NULL) {
PKIX_OBJECT_LOCK(cert);
if (cert->critExtOids == NULL) {
nssCert = cert->nssCert;
/*
* ASN.1 for Extension
*
* Extension ::= SEQUENCE {
* extnID OBJECT IDENTIFIER,
* critical BOOLEAN DEFAULT FALSE,
* extnValue OCTET STRING }
*
*/
extensions = nssCert->extensions;
PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs
(extensions, &oidsList, plContext),
PKIX_GETCRITICALEXTENSIONOIDSFAILED);
/* save a cached copy in case it is asked for again */
cert->critExtOids = oidsList;
}
PKIX_OBJECT_UNLOCK(cert);
}
/* We should return a copy of the List since this list changes */
PKIX_DUPLICATE(cert->critExtOids, pList, plContext,
PKIX_OBJECTDUPLICATELISTFAILED);
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetAuthorityKeyIdentifier
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetAuthorityKeyIdentifier(
PKIX_PL_Cert *cert,
PKIX_PL_ByteArray **pAuthKeyId,
void *plContext)
{
PKIX_PL_ByteArray *authKeyId = NULL;
CERTCertificate *nssCert = NULL;
CERTAuthKeyID *authKeyIdExtension = NULL;
PLArenaPool *arena = NULL;
SECItem retItem;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetAuthorityKeyIdentifier");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pAuthKeyId);
/* if we don't have a cached copy from before, we create one */
if ((cert->authKeyId == NULL) && (!cert->authKeyIdAbsent)){
PKIX_OBJECT_LOCK(cert);
if ((cert->authKeyId == NULL) && (!cert->authKeyIdAbsent)){
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
nssCert = cert->nssCert;
authKeyIdExtension =
CERT_FindAuthKeyIDExten(arena, nssCert);
if (authKeyIdExtension == NULL){
cert->authKeyIdAbsent = PKIX_TRUE;
*pAuthKeyId = NULL;
goto cleanup;
}
retItem = authKeyIdExtension->keyID;
if (retItem.len == 0){
cert->authKeyIdAbsent = PKIX_TRUE;
*pAuthKeyId = NULL;
goto cleanup;
}
PKIX_CHECK(PKIX_PL_ByteArray_Create
(retItem.data,
retItem.len,
&authKeyId,
plContext),
PKIX_BYTEARRAYCREATEFAILED);
/* save a cached copy in case it is asked for again */
cert->authKeyId = authKeyId;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->authKeyId);
*pAuthKeyId = cert->authKeyId;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
if (arena){
PORT_FreeArena(arena, PR_FALSE);
}
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetSubjectKeyIdentifier
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetSubjectKeyIdentifier(
PKIX_PL_Cert *cert,
PKIX_PL_ByteArray **pSubjKeyId,
void *plContext)
{
PKIX_PL_ByteArray *subjKeyId = NULL;
CERTCertificate *nssCert = NULL;
SECItem *retItem = NULL;
SECStatus status;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectKeyIdentifier");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSubjKeyId);
/* if we don't have a cached copy from before, we create one */
if ((cert->subjKeyId == NULL) && (!cert->subjKeyIdAbsent)){
PKIX_OBJECT_LOCK(cert);
if ((cert->subjKeyId == NULL) && (!cert->subjKeyIdAbsent)){
retItem = SECITEM_AllocItem(NULL, NULL, 0);
if (retItem == NULL){
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
nssCert = cert->nssCert;
status = CERT_FindSubjectKeyIDExtension
(nssCert, retItem);
if (status != SECSuccess) {
cert->subjKeyIdAbsent = PKIX_TRUE;
*pSubjKeyId = NULL;
goto cleanup;
}
PKIX_CHECK(PKIX_PL_ByteArray_Create
(retItem->data,
retItem->len,
&subjKeyId,
plContext),
PKIX_BYTEARRAYCREATEFAILED);
/* save a cached copy in case it is asked for again */
cert->subjKeyId = subjKeyId;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->subjKeyId);
*pSubjKeyId = cert->subjKeyId;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
if (retItem){
SECITEM_FreeItem(retItem, PKIX_TRUE);
}
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetExtendedKeyUsage (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetExtendedKeyUsage(
PKIX_PL_Cert *cert,
PKIX_List **pKeyUsage, /* list of PKIX_PL_OID */
void *plContext)
{
CERTOidSequence *extKeyUsage = NULL;
CERTCertificate *nssCert = NULL;
PKIX_PL_OID *pkixOID = NULL;
PKIX_List *oidsList = NULL;
SECItem **oids = NULL;
SECItem encodedExtKeyUsage;
SECStatus rv;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetExtendedKeyUsage");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pKeyUsage);
/* if we don't have a cached copy from before, we create one */
if ((cert->extKeyUsages == NULL) && (!cert->extKeyUsagesAbsent)){
PKIX_OBJECT_LOCK(cert);
if ((cert->extKeyUsages == NULL) &&
(!cert->extKeyUsagesAbsent)){
nssCert = cert->nssCert;
rv = CERT_FindCertExtension
(nssCert, SEC_OID_X509_EXT_KEY_USAGE,
&encodedExtKeyUsage);
if (rv != SECSuccess){
cert->extKeyUsagesAbsent = PKIX_TRUE;
*pKeyUsage = NULL;
goto cleanup;
}
extKeyUsage =
CERT_DecodeOidSequence(&encodedExtKeyUsage);
if (extKeyUsage == NULL){
PKIX_ERROR(PKIX_CERTDECODEOIDSEQUENCEFAILED);
}
PORT_Free(encodedExtKeyUsage.data);
oids = extKeyUsage->oids;
if (!oids){
/* no extended key usage extensions found */
cert->extKeyUsagesAbsent = PKIX_TRUE;
*pKeyUsage = NULL;
goto cleanup;
}
PKIX_CHECK(PKIX_List_Create(&oidsList, plContext),
PKIX_LISTCREATEFAILED);
while (*oids){
SECItem *oid = *oids++;
PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
(oid, &pkixOID, plContext),
PKIX_OIDCREATEFAILED);
PKIX_CHECK(PKIX_List_AppendItem
(oidsList,
(PKIX_PL_Object *)pkixOID,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_DECREF(pkixOID);
}
PKIX_CHECK(PKIX_List_SetImmutable
(oidsList, plContext),
PKIX_LISTSETIMMUTABLEFAILED);
/* save a cached copy in case it is asked for again */
cert->extKeyUsages = oidsList;
oidsList = NULL;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->extKeyUsages);
*pKeyUsage = cert->extKeyUsages;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_DECREF(pkixOID);
PKIX_DECREF(oidsList);
CERT_DestroyOidSequence(extKeyUsage);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetBasicConstraints
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetBasicConstraints(
PKIX_PL_Cert *cert,
PKIX_PL_CertBasicConstraints **pBasicConstraints,
void *plContext)
{
CERTCertificate *nssCert = NULL;
CERTBasicConstraints nssBasicConstraint;
SECStatus rv;
PKIX_PL_CertBasicConstraints *basic;
PKIX_Int32 pathLen = 0;
PKIX_Boolean isCA = PKIX_FALSE;
enum {
realBC, synthBC, absentBC
} constraintSource = absentBC;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetBasicConstraints");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pBasicConstraints);
/* if we don't have a cached copy from before, we create one */
if ((cert->certBasicConstraints == NULL) &&
(!cert->basicConstraintsAbsent)) {
PKIX_OBJECT_LOCK(cert);
if ((cert->certBasicConstraints == NULL) &&
(!cert->basicConstraintsAbsent)) {
nssCert = cert->nssCert;
PKIX_CERT_DEBUG(
"\t\tCalling Cert_FindBasicConstraintExten\n");
rv = CERT_FindBasicConstraintExten
(nssCert, &nssBasicConstraint);
if (rv == SECSuccess) {
constraintSource = realBC;
}
if (constraintSource == absentBC) {
/* can we deduce it's a CA and create a
synthetic constraint?
*/
CERTCertTrust trust;
rv = CERT_GetCertTrust(nssCert, &trust);
if (rv == SECSuccess) {
int anyWantedFlag = CERTDB_TRUSTED_CA | CERTDB_VALID_CA;
if ((trust.sslFlags & anyWantedFlag)
|| (trust.emailFlags & anyWantedFlag)
|| (trust.objectSigningFlags & anyWantedFlag)) {
constraintSource = synthBC;
}
}
}
if (constraintSource == absentBC) {
cert->basicConstraintsAbsent = PKIX_TRUE;
*pBasicConstraints = NULL;
goto cleanup;
}
}
if (constraintSource == synthBC) {
isCA = PKIX_TRUE;
pathLen = PKIX_UNLIMITED_PATH_CONSTRAINT;
} else {
isCA = (nssBasicConstraint.isCA)?PKIX_TRUE:PKIX_FALSE;
/* The pathLen has meaning only for CAs */
if (isCA) {
if (CERT_UNLIMITED_PATH_CONSTRAINT ==
nssBasicConstraint.pathLenConstraint) {
pathLen = PKIX_UNLIMITED_PATH_CONSTRAINT;
} else {
pathLen = nssBasicConstraint.pathLenConstraint;
}
}
}
PKIX_CHECK(pkix_pl_CertBasicConstraints_Create
(isCA, pathLen, &basic, plContext),
PKIX_CERTBASICCONSTRAINTSCREATEFAILED);
/* save a cached copy in case it is asked for again */
cert->certBasicConstraints = basic;
}
PKIX_INCREF(cert->certBasicConstraints);
*pBasicConstraints = cert->certBasicConstraints;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetPolicyInformation
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetPolicyInformation(
PKIX_PL_Cert *cert,
PKIX_List **pPolicyInfo,
void *plContext)
{
PKIX_List *policyList = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetPolicyInformation");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pPolicyInfo);
/* if we don't have a cached copy from before, we create one */
if ((cert->certPolicyInfos == NULL) &&
(!cert->policyInfoAbsent)) {
PKIX_OBJECT_LOCK(cert);
if ((cert->certPolicyInfos == NULL) &&
(!cert->policyInfoAbsent)) {
PKIX_CHECK(pkix_pl_Cert_DecodePolicyInfo
(cert->nssCert, &policyList, plContext),
PKIX_CERTDECODEPOLICYINFOFAILED);
if (!policyList) {
cert->policyInfoAbsent = PKIX_TRUE;
*pPolicyInfo = NULL;
goto cleanup;
}
}
PKIX_OBJECT_UNLOCK(cert);
/* save a cached copy in case it is asked for again */
cert->certPolicyInfos = policyList;
policyList = NULL;
}
PKIX_INCREF(cert->certPolicyInfos);
*pPolicyInfo = cert->certPolicyInfos;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_DECREF(policyList);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetPolicyMappings (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetPolicyMappings(
PKIX_PL_Cert *cert,
PKIX_List **pPolicyMappings, /* list of PKIX_PL_CertPolicyMap */
void *plContext)
{
PKIX_List *policyMappings = NULL; /* list of PKIX_PL_CertPolicyMap */
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetPolicyMappings");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pPolicyMappings);
/* if we don't have a cached copy from before, we create one */
if (!(cert->certPolicyMappings) && !(cert->policyMappingsAbsent)) {
PKIX_OBJECT_LOCK(cert);
if (!(cert->certPolicyMappings) &&
!(cert->policyMappingsAbsent)) {
PKIX_CHECK(pkix_pl_Cert_DecodePolicyMapping
(cert->nssCert, &policyMappings, plContext),
PKIX_CERTDECODEPOLICYMAPPINGFAILED);
if (!policyMappings) {
cert->policyMappingsAbsent = PKIX_TRUE;
*pPolicyMappings = NULL;
goto cleanup;
}
}
PKIX_OBJECT_UNLOCK(cert);
/* save a cached copy in case it is asked for again */
cert->certPolicyMappings = policyMappings;
policyMappings = NULL;
}
PKIX_INCREF(cert->certPolicyMappings);
*pPolicyMappings = cert->certPolicyMappings;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_DECREF(policyMappings);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetRequireExplicitPolicy
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetRequireExplicitPolicy(
PKIX_PL_Cert *cert,
PKIX_Int32 *pSkipCerts,
void *plContext)
{
PKIX_Int32 explicitPolicySkipCerts = 0;
PKIX_Int32 inhibitMappingSkipCerts = 0;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetRequireExplicitPolicy");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSkipCerts);
if (!(cert->policyConstraintsProcessed)) {
PKIX_OBJECT_LOCK(cert);
if (!(cert->policyConstraintsProcessed)) {
/*
* If we can't process it now, we probably will be
* unable to process it later. Set the default value.
*/
cert->policyConstraintsProcessed = PKIX_TRUE;
cert->policyConstraintsExplicitPolicySkipCerts = -1;
cert->policyConstraintsInhibitMappingSkipCerts = -1;
PKIX_CHECK(pkix_pl_Cert_DecodePolicyConstraints
(cert->nssCert,
&explicitPolicySkipCerts,
&inhibitMappingSkipCerts,
plContext),
PKIX_CERTDECODEPOLICYCONSTRAINTSFAILED);
cert->policyConstraintsExplicitPolicySkipCerts =
explicitPolicySkipCerts;
cert->policyConstraintsInhibitMappingSkipCerts =
inhibitMappingSkipCerts;
}
PKIX_OBJECT_UNLOCK(cert);
}
*pSkipCerts = cert->policyConstraintsExplicitPolicySkipCerts;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetPolicyMappingInhibited
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetPolicyMappingInhibited(
PKIX_PL_Cert *cert,
PKIX_Int32 *pSkipCerts,
void *plContext)
{
PKIX_Int32 explicitPolicySkipCerts = 0;
PKIX_Int32 inhibitMappingSkipCerts = 0;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetPolicyMappingInhibited");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSkipCerts);
if (!(cert->policyConstraintsProcessed)) {
PKIX_OBJECT_LOCK(cert);
if (!(cert->policyConstraintsProcessed)) {
/*
* If we can't process it now, we probably will be
* unable to process it later. Set the default value.
*/
cert->policyConstraintsProcessed = PKIX_TRUE;
cert->policyConstraintsExplicitPolicySkipCerts = -1;
cert->policyConstraintsInhibitMappingSkipCerts = -1;
PKIX_CHECK(pkix_pl_Cert_DecodePolicyConstraints
(cert->nssCert,
&explicitPolicySkipCerts,
&inhibitMappingSkipCerts,
plContext),
PKIX_CERTDECODEPOLICYCONSTRAINTSFAILED);
cert->policyConstraintsExplicitPolicySkipCerts =
explicitPolicySkipCerts;
cert->policyConstraintsInhibitMappingSkipCerts =
inhibitMappingSkipCerts;
}
PKIX_OBJECT_UNLOCK(cert);
}
*pSkipCerts = cert->policyConstraintsInhibitMappingSkipCerts;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetInhibitAnyPolicy (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetInhibitAnyPolicy(
PKIX_PL_Cert *cert,
PKIX_Int32 *pSkipCerts,
void *plContext)
{
PKIX_Int32 skipCerts = 0;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetInhibitAnyPolicy");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSkipCerts);
if (!(cert->inhibitAnyPolicyProcessed)) {
PKIX_OBJECT_LOCK(cert);
if (!(cert->inhibitAnyPolicyProcessed)) {
/*
* If we can't process it now, we probably will be
* unable to process it later. Set the default value.
*/
cert->inhibitAnyPolicyProcessed = PKIX_TRUE;
cert->inhibitAnySkipCerts = -1;
PKIX_CHECK(pkix_pl_Cert_DecodeInhibitAnyPolicy
(cert->nssCert, &skipCerts, plContext),
PKIX_CERTDECODEINHIBITANYPOLICYFAILED);
cert->inhibitAnySkipCerts = skipCerts;
}
PKIX_OBJECT_UNLOCK(cert);
}
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
*pSkipCerts = cert->inhibitAnySkipCerts;
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_AreCertPoliciesCritical
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_AreCertPoliciesCritical(
PKIX_PL_Cert *cert,
PKIX_Boolean *pCritical,
void *plContext)
{
PKIX_Boolean criticality = PKIX_FALSE;
PKIX_ENTER(CERT, "PKIX_PL_Cert_AreCertPoliciesCritical");
PKIX_NULLCHECK_TWO(cert, pCritical);
PKIX_CHECK(pkix_pl_Cert_IsExtensionCritical(
cert,
SEC_OID_X509_CERTIFICATE_POLICIES,
&criticality,
plContext),
PKIX_CERTISEXTENSIONCRITICALFAILED);
*pCritical = criticality;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_VerifySignature (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_VerifySignature(
PKIX_PL_Cert *cert,
PKIX_PL_PublicKey *pubKey,
void *plContext)
{
CERTCertificate *nssCert = NULL;
SECKEYPublicKey *nssPubKey = NULL;
CERTSignedData *tbsCert = NULL;
PKIX_PL_Cert *cachedCert = NULL;
PKIX_Error *verifySig = NULL;
PKIX_Error *cachedSig = NULL;
PKIX_Error *checkSig = NULL;
SECStatus status;
PKIX_Boolean certEqual = PKIX_FALSE;
PKIX_Boolean certInHash = PKIX_FALSE;
PKIX_Boolean checkCertSig = PKIX_TRUE;
void* wincx = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifySignature");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pubKey);
/* if the cert check flag is off, skip the check */
checkSig = pkix_pl_NssContext_GetCertSignatureCheck(
(PKIX_PL_NssContext *)plContext, &checkCertSig);
if ((checkCertSig == PKIX_FALSE) && (checkSig == NULL)) {
goto cleanup;
}
verifySig = PKIX_PL_HashTable_Lookup
(cachedCertSigTable,
(PKIX_PL_Object *) pubKey,
(PKIX_PL_Object **) &cachedCert,
plContext);
if (cachedCert != NULL && verifySig == NULL) {
/* Cached Signature Table lookup succeed */
PKIX_EQUALS(cert, cachedCert, &certEqual, plContext,
PKIX_OBJECTEQUALSFAILED);
if (certEqual == PKIX_TRUE) {
goto cleanup;
}
/* Different PubKey may hash to same value, skip add */
certInHash = PKIX_TRUE;
}
nssCert = cert->nssCert;
tbsCert = &nssCert->signatureWrap;
PKIX_CERT_DEBUG("\t\tCalling SECKEY_ExtractPublicKey).\n");
nssPubKey = SECKEY_ExtractPublicKey(pubKey->nssSPKI);
if (!nssPubKey){
PKIX_ERROR(PKIX_SECKEYEXTRACTPUBLICKEYFAILED);
}
PKIX_CERT_DEBUG("\t\tCalling CERT_VerifySignedDataWithPublicKey).\n");
PKIX_CHECK(pkix_pl_NssContext_GetWincx
((PKIX_PL_NssContext *)plContext, &wincx),
PKIX_NSSCONTEXTGETWINCXFAILED);
status = CERT_VerifySignedDataWithPublicKey(tbsCert, nssPubKey, wincx);
if (status != SECSuccess) {
if (PORT_GetError() != SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) {
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
}
PKIX_ERROR(PKIX_SIGNATUREDIDNOTVERIFYWITHTHEPUBLICKEY);
}
if (certInHash == PKIX_FALSE) {
cachedSig = PKIX_PL_HashTable_Add
(cachedCertSigTable,
(PKIX_PL_Object *) pubKey,
(PKIX_PL_Object *) cert,
plContext);
if (cachedSig != NULL) {
PKIX_DEBUG("PKIX_PL_HashTable_Add skipped: entry existed\n");
}
}
cleanup:
if (nssPubKey){
PKIX_CERT_DEBUG("\t\tCalling SECKEY_DestroyPublicKey).\n");
SECKEY_DestroyPublicKey(nssPubKey);
}
PKIX_DECREF(cachedCert);
PKIX_DECREF(checkSig);
PKIX_DECREF(verifySig);
PKIX_DECREF(cachedSig);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_CheckValidity (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_CheckValidity(
PKIX_PL_Cert *cert,
PKIX_PL_Date *date,
void *plContext)
{
SECCertTimeValidity val;
PRTime timeToCheck;
PKIX_Boolean allowOverride;
SECCertificateUsage requiredUsages;
PKIX_ENTER(CERT, "PKIX_PL_Cert_CheckValidity");
PKIX_NULLCHECK_ONE(cert);
/* if the caller supplies a date, we use it; else, use current time */
if (date != NULL){
PKIX_CHECK(pkix_pl_Date_GetPRTime
(date, &timeToCheck, plContext),
PKIX_DATEGETPRTIMEFAILED);
} else {
timeToCheck = PR_Now();
}
requiredUsages = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
allowOverride =
(PRBool)((requiredUsages & certificateUsageSSLServer) ||
(requiredUsages & certificateUsageSSLServerWithStepUp) ||
(requiredUsages & certificateUsageIPsec));
val = CERT_CheckCertValidTimes(cert->nssCert, timeToCheck, allowOverride);
if (val != secCertTimeValid){
PKIX_ERROR(PKIX_CERTCHECKCERTVALIDTIMESFAILED);
}
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetValidityNotAfter (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetValidityNotAfter(
PKIX_PL_Cert *cert,
PKIX_PL_Date **pDate,
void *plContext)
{
PRTime prtime;
SECStatus rv = SECFailure;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetValidityNotAfter");
PKIX_NULLCHECK_TWO(cert, pDate);
PKIX_DATE_DEBUG("\t\tCalling DER_DecodeTimeChoice).\n");
rv = DER_DecodeTimeChoice(&prtime, &(cert->nssCert->validity.notAfter));
if (rv != SECSuccess){
PKIX_ERROR(PKIX_DERDECODETIMECHOICEFAILED);
}
PKIX_CHECK(pkix_pl_Date_CreateFromPRTime
(prtime, pDate, plContext),
PKIX_DATECREATEFROMPRTIMEFAILED);
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_VerifyCertAndKeyType (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_VerifyCertAndKeyType(
PKIX_PL_Cert *cert,
PKIX_Boolean isChainCert,
void *plContext)
{
PKIX_PL_CertBasicConstraints *basicConstraints = NULL;
SECCertificateUsage certificateUsage;
SECCertUsage certUsage = 0;
unsigned int requiredKeyUsage;
unsigned int requiredCertType;
unsigned int certType;
SECStatus rv = SECSuccess;
PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifyCertType");
PKIX_NULLCHECK_TWO(cert, plContext);
certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
/* ensure we obtained a single usage bit only */
PORT_Assert(!(certificateUsage & (certificateUsage - 1)));
/* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */
while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; }
/* check key usage and netscape cert type */
cert_GetCertType(cert->nssCert);
certType = cert->nssCert->nsCertType;
if (isChainCert ||
(certUsage != certUsageVerifyCA && certUsage != certUsageAnyCA)) {
rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, isChainCert,
&requiredKeyUsage,
&requiredCertType);
if (rv == SECFailure) {
PKIX_ERROR(PKIX_UNSUPPORTEDCERTUSAGE);
}
} else {
/* use this key usage and cert type for certUsageAnyCA and
* certUsageVerifyCA. */
requiredKeyUsage = KU_KEY_CERT_SIGN;
requiredCertType = NS_CERT_TYPE_CA;
}
if (CERT_CheckKeyUsage(cert->nssCert, requiredKeyUsage) != SECSuccess) {
PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED);
}
if (!(certType & requiredCertType)) {
PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED);
}
cleanup:
PKIX_DECREF(basicConstraints);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_VerifyKeyUsage (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_VerifyKeyUsage(
PKIX_PL_Cert *cert,
PKIX_UInt32 keyUsage,
void *plContext)
{
CERTCertificate *nssCert = NULL;
PKIX_UInt32 nssKeyUsage = 0;
SECStatus status;
PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifyKeyUsage");
PKIX_NULLCHECK_TWO(cert, cert->nssCert);
nssCert = cert->nssCert;
/* if cert doesn't have keyUsage extension, all keyUsages are valid */
if (!nssCert->keyUsagePresent){
goto cleanup;
}
if (keyUsage & PKIX_DIGITAL_SIGNATURE){
nssKeyUsage = nssKeyUsage | KU_DIGITAL_SIGNATURE;
}
if (keyUsage & PKIX_NON_REPUDIATION){
nssKeyUsage = nssKeyUsage | KU_NON_REPUDIATION;
}
if (keyUsage & PKIX_KEY_ENCIPHERMENT){
nssKeyUsage = nssKeyUsage | KU_KEY_ENCIPHERMENT;
}
if (keyUsage & PKIX_DATA_ENCIPHERMENT){
nssKeyUsage = nssKeyUsage | KU_DATA_ENCIPHERMENT;
}
if (keyUsage & PKIX_KEY_AGREEMENT){
nssKeyUsage = nssKeyUsage | KU_KEY_AGREEMENT;
}
if (keyUsage & PKIX_KEY_CERT_SIGN){
nssKeyUsage = nssKeyUsage | KU_KEY_CERT_SIGN;
}
if (keyUsage & PKIX_CRL_SIGN){
nssKeyUsage = nssKeyUsage | KU_CRL_SIGN;
}
if (keyUsage & PKIX_ENCIPHER_ONLY){
nssKeyUsage = nssKeyUsage | 0x01;
}
if (keyUsage & PKIX_DECIPHER_ONLY){
/* XXX we should support this once it is fixed in NSS */
PKIX_ERROR(PKIX_DECIPHERONLYKEYUSAGENOTSUPPORTED);
}
status = CERT_CheckKeyUsage(nssCert, nssKeyUsage);
if (status != SECSuccess) {
PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED);
}
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetNameConstraints
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetNameConstraints(
PKIX_PL_Cert *cert,
PKIX_PL_CertNameConstraints **pNameConstraints,
void *plContext)
{
PKIX_PL_CertNameConstraints *nameConstraints = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetNameConstraints");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pNameConstraints);
/* if we don't have a cached copy from before, we create one */
if (cert->nameConstraints == NULL && !cert->nameConstraintsAbsent) {
PKIX_OBJECT_LOCK(cert);
if (cert->nameConstraints == NULL &&
!cert->nameConstraintsAbsent) {
PKIX_CHECK(pkix_pl_CertNameConstraints_Create
(cert->nssCert, &nameConstraints, plContext),
PKIX_CERTNAMECONSTRAINTSCREATEFAILED);
if (nameConstraints == NULL) {
cert->nameConstraintsAbsent = PKIX_TRUE;
}
cert->nameConstraints = nameConstraints;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->nameConstraints);
*pNameConstraints = cert->nameConstraints;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_CheckNameConstraints
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_CheckNameConstraints(
PKIX_PL_Cert *cert,
PKIX_PL_CertNameConstraints *nameConstraints,
PKIX_Boolean treatCommonNameAsDNSName,
void *plContext)
{
PKIX_Boolean checkPass = PKIX_TRUE;
CERTGeneralName *nssSubjectNames = NULL;
PLArenaPool *arena = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_CheckNameConstraints");
PKIX_NULLCHECK_ONE(cert);
if (nameConstraints != NULL) {
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
/* only check common Name if the usage requires it */
if (treatCommonNameAsDNSName) {
SECCertificateUsage certificateUsage;
certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
if ((certificateUsage != certificateUsageSSLServer) &&
(certificateUsage != certificateUsageIPsec)) {
treatCommonNameAsDNSName = PKIX_FALSE;
}
}
/* This NSS call returns Subject Alt Names. If
* treatCommonNameAsDNSName is true, it also returns the
* Subject Common Name
*/
PKIX_CERT_DEBUG
("\t\tCalling CERT_GetConstrainedCertificateNames\n");
nssSubjectNames = CERT_GetConstrainedCertificateNames
(cert->nssCert, arena, treatCommonNameAsDNSName);
PKIX_CHECK(pkix_pl_CertNameConstraints_CheckNameSpaceNssNames
(nssSubjectNames,
nameConstraints,
&checkPass,
plContext),
PKIX_CERTNAMECONSTRAINTSCHECKNAMESPACENSSNAMESFAILED);
if (checkPass != PKIX_TRUE) {
PKIX_ERROR(PKIX_CERTFAILEDNAMECONSTRAINTSCHECKING);
}
}
cleanup:
if (arena){
PORT_FreeArena(arena, PR_FALSE);
}
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_MergeNameConstraints
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_MergeNameConstraints(
PKIX_PL_CertNameConstraints *firstNC,
PKIX_PL_CertNameConstraints *secondNC,
PKIX_PL_CertNameConstraints **pResultNC,
void *plContext)
{
PKIX_PL_CertNameConstraints *mergedNC = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_MergeNameConstraints");
PKIX_NULLCHECK_TWO(firstNC, pResultNC);
if (secondNC == NULL) {
PKIX_INCREF(firstNC);
*pResultNC = firstNC;
goto cleanup;
}
PKIX_CHECK(pkix_pl_CertNameConstraints_Merge
(firstNC, secondNC, &mergedNC, plContext),
PKIX_CERTNAMECONSTRAINTSMERGEFAILED);
*pResultNC = mergedNC;
cleanup:
PKIX_RETURN(CERT);
}
/*
* Find out the state of the NSS trust bits for the requested usage.
* Returns SECFailure if the cert is explicitly distrusted.
* Returns SECSuccess if the cert can be used to form a chain (normal case),
* or it is explicitly trusted. The trusted bool is set to true if it is
* explicitly trusted.
*/
static SECStatus
pkix_pl_Cert_GetTrusted(void *plContext,
PKIX_PL_Cert *cert,
PKIX_Boolean *trusted,
PKIX_Boolean isCA)
{
SECStatus rv;
CERTCertificate *nssCert = NULL;
SECCertUsage certUsage = 0;
SECCertificateUsage certificateUsage;
SECTrustType trustType;
unsigned int trustFlags;
unsigned int requiredFlags;
CERTCertTrust trust;
*trusted = PKIX_FALSE;
/* no key usage information */
if (plContext == NULL) {
return SECSuccess;
}
certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
/* ensure we obtained a single usage bit only */
PORT_Assert(!(certificateUsage & (certificateUsage - 1)));
/* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */
while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; }
nssCert = cert->nssCert;
if (!isCA) {
PRBool prTrusted;
unsigned int failedFlags;
rv = cert_CheckLeafTrust(nssCert, certUsage,
&failedFlags, &prTrusted);
*trusted = (PKIX_Boolean) prTrusted;
return rv;
}
rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
&trustType);
if (rv != SECSuccess) {
return SECSuccess;
}
rv = CERT_GetCertTrust(nssCert, &trust);
if (rv != SECSuccess) {
return SECSuccess;
}
trustFlags = SEC_GET_TRUST_FLAGS(&trust, trustType);
/* normally trustTypeNone usages accept any of the given trust bits
* being on as acceptable. If any are distrusted (and none are trusted),
* then we will also distrust the cert */
if ((trustFlags == 0) && (trustType == trustTypeNone)) {
trustFlags = trust.sslFlags | trust.emailFlags |
trust.objectSigningFlags;
}
if ((trustFlags & requiredFlags) == requiredFlags) {
*trusted = PKIX_TRUE;
return SECSuccess;
}
if ((trustFlags & CERTDB_TERMINAL_RECORD) &&
((trustFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED)) == 0)) {
return SECFailure;
}
return SECSuccess;
}
/*
* FUNCTION: PKIX_PL_Cert_IsCertTrusted
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_IsCertTrusted(
PKIX_PL_Cert *cert,
PKIX_PL_TrustAnchorMode trustAnchorMode,
PKIX_Boolean *pTrusted,
void *plContext)
{
PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
PKIX_Boolean trusted = PKIX_FALSE;
SECStatus rv = SECFailure;
PKIX_ENTER(CERT, "PKIX_PL_Cert_IsCertTrusted");
PKIX_NULLCHECK_TWO(cert, pTrusted);
/* Call GetTrusted first to see if we are going to distrust the
* certificate */
rv = pkix_pl_Cert_GetTrusted(plContext, cert, &trusted, PKIX_TRUE);
if (rv != SECSuccess) {
/* Failure means the cert is explicitly distrusted,
* let the next level know not to use it. */
*pTrusted = PKIX_FALSE;
PKIX_ERROR(PKIX_CERTISCERTTRUSTEDFAILED);
}
if (trustAnchorMode == PKIX_PL_TrustAnchorMode_Exclusive ||
(trustAnchorMode == PKIX_PL_TrustAnchorMode_Additive &&
cert->isUserTrustAnchor)) {
/* Use the trust anchor's |trusted| value */
*pTrusted = cert->isUserTrustAnchor;
goto cleanup;
}
/* no key usage information or store is not trusted */
if (plContext == NULL || cert->store == NULL) {
*pTrusted = PKIX_FALSE;
goto cleanup;
}
PKIX_CHECK(PKIX_CertStore_GetTrustCallback
(cert->store, &trustCallback, plContext),
PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
PKIX_CHECK_ONLY_FATAL(trustCallback
(cert->store, cert, &trusted, plContext),
PKIX_CHECKTRUSTCALLBACKFAILED);
/* allow trust store to override if we can trust the trust
* bits */
if (PKIX_ERROR_RECEIVED || (trusted == PKIX_FALSE)) {
*pTrusted = PKIX_FALSE;
goto cleanup;
}
*pTrusted = trusted;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_IsLeafCertTrusted
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_IsLeafCertTrusted(
PKIX_PL_Cert *cert,
PKIX_Boolean *pTrusted,
void *plContext)
{
SECStatus rv;
PKIX_ENTER(CERT, "PKIX_PL_Cert_IsLeafCertTrusted");
PKIX_NULLCHECK_TWO(cert, pTrusted);
*pTrusted = PKIX_FALSE;
rv = pkix_pl_Cert_GetTrusted(plContext, cert, pTrusted, PKIX_FALSE);
if (rv != SECSuccess) {
/* Failure means the cert is explicitly distrusted,
* let the next level know not to use it. */
*pTrusted = PKIX_FALSE;
PKIX_ERROR(PKIX_CERTISCERTTRUSTEDFAILED);
}
cleanup:
PKIX_RETURN(CERT);
}
/* FUNCTION: PKIX_PL_Cert_SetAsTrustAnchor */
PKIX_Error*
PKIX_PL_Cert_SetAsTrustAnchor(PKIX_PL_Cert *cert,
void *plContext)
{
PKIX_ENTER(CERT, "PKIX_PL_Cert_SetAsTrustAnchor");
PKIX_NULLCHECK_ONE(cert);
cert->isUserTrustAnchor = PKIX_TRUE;
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetCacheFlag (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetCacheFlag(
PKIX_PL_Cert *cert,
PKIX_Boolean *pCacheFlag,
void *plContext)
{
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetCacheFlag");
PKIX_NULLCHECK_TWO(cert, pCacheFlag);
*pCacheFlag = cert->cacheFlag;
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_SetCacheFlag (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_SetCacheFlag(
PKIX_PL_Cert *cert,
PKIX_Boolean cacheFlag,
void *plContext)
{
PKIX_ENTER(CERT, "PKIX_PL_Cert_SetCacheFlag");
PKIX_NULLCHECK_ONE(cert);
cert->cacheFlag = cacheFlag;
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetTrustCertStore (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetTrustCertStore(
PKIX_PL_Cert *cert,
PKIX_CertStore **pTrustCertStore,
void *plContext)
{
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetTrustCertStore");
PKIX_NULLCHECK_TWO(cert, pTrustCertStore);
PKIX_INCREF(cert->store);
*pTrustCertStore = cert->store;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_SetTrustCertStore (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_SetTrustCertStore(
PKIX_PL_Cert *cert,
PKIX_CertStore *trustCertStore,
void *plContext)
{
PKIX_ENTER(CERT, "PKIX_PL_Cert_SetTrustCertStore");
PKIX_NULLCHECK_TWO(cert, trustCertStore);
PKIX_INCREF(trustCertStore);
cert->store = trustCertStore;
cleanup:
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetAuthorityInfoAccess
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetAuthorityInfoAccess(
PKIX_PL_Cert *cert,
PKIX_List **pAiaList, /* of PKIX_PL_InfoAccess */
void *plContext)
{
PKIX_List *aiaList = NULL; /* of PKIX_PL_InfoAccess */
SECItem *encodedAIA = NULL;
CERTAuthInfoAccess **aia = NULL;
PLArenaPool *arena = NULL;
SECStatus rv;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetAuthorityInfoAccess");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pAiaList);
/* if we don't have a cached copy from before, we create one */
if (cert->authorityInfoAccess == NULL) {
PKIX_OBJECT_LOCK(cert);
if (cert->authorityInfoAccess == NULL) {
PKIX_PL_NSSCALLRV(CERT, encodedAIA, SECITEM_AllocItem,
(NULL, NULL, 0));
if (encodedAIA == NULL) {
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
PKIX_PL_NSSCALLRV(CERT, rv, CERT_FindCertExtension,
(cert->nssCert,
SEC_OID_X509_AUTH_INFO_ACCESS,
encodedAIA));
if (rv == SECFailure) {
goto cleanup;
}
PKIX_PL_NSSCALLRV(CERT, arena, PORT_NewArena,
(DER_DEFAULT_CHUNKSIZE));
if (arena == NULL) {
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
PKIX_PL_NSSCALLRV
(CERT, aia, CERT_DecodeAuthInfoAccessExtension,
(arena, encodedAIA));
PKIX_CHECK(pkix_pl_InfoAccess_CreateList
(aia, &aiaList, plContext),
PKIX_INFOACCESSCREATELISTFAILED);
cert->authorityInfoAccess = aiaList;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->authorityInfoAccess);
*pAiaList = cert->authorityInfoAccess;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
if (arena != NULL) {
PORT_FreeArena(arena, PR_FALSE);
}
if (encodedAIA != NULL) {
SECITEM_FreeItem(encodedAIA, PR_TRUE);
}
PKIX_RETURN(CERT);
}
/* XXX Following defines belongs to NSS */
static const unsigned char siaOIDString[] = {0x2b, 0x06, 0x01, 0x05, 0x05,
0x07, 0x01, 0x0b};
#define OI(x) { siDEROID, (unsigned char *)x, sizeof x }
/*
* FUNCTION: PKIX_PL_Cert_GetSubjectInfoAccess
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetSubjectInfoAccess(
PKIX_PL_Cert *cert,
PKIX_List **pSiaList, /* of PKIX_PL_InfoAccess */
void *plContext)
{
PKIX_List *siaList; /* of PKIX_PL_InfoAccess */
SECItem siaOID = OI(siaOIDString);
SECItem *encodedSubjInfoAccess = NULL;
CERTAuthInfoAccess **subjInfoAccess = NULL;
PLArenaPool *arena = NULL;
SECStatus rv;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectInfoAccess");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSiaList);
/* XXX
* Codes to deal with SubjectInfoAccess OID should be moved to
* NSS soon. I implemented them here so we don't touch NSS
* source tree, from JP's suggestion.
*/
/* if we don't have a cached copy from before, we create one */
if (cert->subjectInfoAccess == NULL) {
PKIX_OBJECT_LOCK(cert);
if (cert->subjectInfoAccess == NULL) {
encodedSubjInfoAccess = SECITEM_AllocItem(NULL, NULL, 0);
if (encodedSubjInfoAccess == NULL) {
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
PKIX_CERT_DEBUG
("\t\tCalling CERT_FindCertExtensionByOID).\n");
rv = CERT_FindCertExtensionByOID
(cert->nssCert, &siaOID, encodedSubjInfoAccess);
if (rv == SECFailure) {
goto cleanup;
}
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
PKIX_ERROR(PKIX_OUTOFMEMORY);
}
/* XXX
* Decode Subject Information Access -
* since its type is the same as Authority Information
* Access, reuse the call. NSS- change name to avoid
* confusion.
*/
PKIX_CERT_DEBUG
("\t\tCalling CERT_DecodeAuthInfoAccessExtension).\n");
subjInfoAccess = CERT_DecodeAuthInfoAccessExtension
(arena, encodedSubjInfoAccess);
PKIX_CHECK(pkix_pl_InfoAccess_CreateList
(subjInfoAccess, &siaList, plContext),
PKIX_INFOACCESSCREATELISTFAILED);
cert->subjectInfoAccess = siaList;
}
PKIX_OBJECT_UNLOCK(cert);
}
PKIX_INCREF(cert->subjectInfoAccess);
*pSiaList = cert->subjectInfoAccess;
cleanup:
PKIX_OBJECT_UNLOCK(lockedObject);
if (arena != NULL) {
PORT_FreeArena(arena, PR_FALSE);
}
if (encodedSubjInfoAccess != NULL) {
SECITEM_FreeItem(encodedSubjInfoAccess, PR_TRUE);
}
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetCrlDp
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetCrlDp(
PKIX_PL_Cert *cert,
PKIX_List **pDpList,
void *plContext)
{
PKIX_UInt32 dpIndex = 0;
pkix_pl_CrlDp *dp = NULL;
CERTCrlDistributionPoints *dpoints = NULL;
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetCrlDp");
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pDpList);
/* if we don't have a cached copy from before, we create one */
if (cert->crldpList == NULL) {
PKIX_OBJECT_LOCK(cert);
if (cert->crldpList != NULL) {
goto cleanup;
}
PKIX_CHECK(PKIX_List_Create(&cert->crldpList, plContext),
PKIX_LISTCREATEFAILED);
dpoints = CERT_FindCRLDistributionPoints(cert->nssCert);
if (!dpoints || !dpoints->distPoints) {
goto cleanup;
}
for (;dpoints->distPoints[dpIndex];dpIndex++) {
PKIX_CHECK(
pkix_pl_CrlDp_Create(dpoints->distPoints[dpIndex],
&cert->nssCert->issuer,
&dp, plContext),
PKIX_CRLDPCREATEFAILED);
/* Create crldp list in reverse order in attempt to get
* to the whole crl first. */
PKIX_CHECK(
PKIX_List_InsertItem(cert->crldpList, 0,
(PKIX_PL_Object*)dp,
plContext),
PKIX_LISTAPPENDITEMFAILED);
PKIX_DECREF(dp);
}
}
cleanup:
PKIX_INCREF(cert->crldpList);
*pDpList = cert->crldpList;
PKIX_OBJECT_UNLOCK(lockedObject);
PKIX_DECREF(dp);
PKIX_RETURN(CERT);
}
/*
* FUNCTION: PKIX_PL_Cert_GetCERTCertificate
* (see comments in pkix_pl_pki.h)
*/
PKIX_Error *
PKIX_PL_Cert_GetCERTCertificate(
PKIX_PL_Cert *cert,
CERTCertificate **pnssCert,
void *plContext)
{
PKIX_ENTER(CERT, "PKIX_PL_Cert_GetNssCert");
PKIX_NULLCHECK_TWO(cert, pnssCert);
*pnssCert = CERT_DupCertificate(cert->nssCert);
PKIX_RETURN(CERT);
}