/* 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),
¬BeforeString,
plContext),
PKIX_DATETOSTRINGHELPERFAILED);
/* Validity: NotAfter */
PKIX_CHECK(pkix_pl_Date_ToString_Helper
(&(cert->nssCert->validity.notAfter),
¬AfterString,
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;
--> --------------------
--> maximum size reached
--> --------------------