2017-04-19 07:56:45 +00:00
|
|
|
/* 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;
|
|
|
|
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;
|
|
|
|
SECStatus status;
|
|
|
|
PKIX_Boolean certEqual = PKIX_FALSE;
|
|
|
|
PKIX_Boolean certInHash = PKIX_FALSE;
|
|
|
|
void* wincx = NULL;
|
|
|
|
|
|
|
|
PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifySignature");
|
|
|
|
PKIX_NULLCHECK_THREE(cert, cert->nssCert, pubKey);
|
|
|
|
|
|
|
|
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(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) ||
|
2020-01-24 01:47:36 +00:00
|
|
|
(requiredUsages & certificateUsageSSLServerWithStepUp) ||
|
|
|
|
(requiredUsages & certificateUsageIPsec));
|
2017-04-19 07:56:45 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|