summaryrefslogtreecommitdiff
path: root/mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
diff options
context:
space:
mode:
authorLorry <lorry@roadtrain.codethink.co.uk>2012-07-18 20:31:20 +0100
committerLorry <lorry@roadtrain.codethink.co.uk>2012-07-18 20:31:20 +0100
commite43ad1f4ce7f1504e6f01fc8a90d5c0398013383 (patch)
tree03504d9d81336081b899c9f34cc0f66801caf67c /mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
downloadnss-e43ad1f4ce7f1504e6f01fc8a90d5c0398013383.tar.gz
Tarball conversion
Diffstat (limited to 'mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c')
-rw-r--r--mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c3657
1 files changed, 3657 insertions, 0 deletions
diff --git a/mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
new file mode 100644
index 0000000..df5f03a
--- /dev/null
+++ b/mozilla/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
@@ -0,0 +1,3657 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the PKIX-C library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are
+ * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sun Microsystems, Inc.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * pkix_pl_cert.c
+ *
+ * Certificate Object Functions
+ *
+ */
+
+#include "pkix_pl_cert.h"
+
+extern PKIX_PL_HashTable *cachedCertSigTable;
+
+/* --Private-Cert-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Cert_IsExtensionCritical
+ * DESCRIPTION:
+ *
+ * Checks the Cert specified by "cert" to determine whether the extension
+ * whose tag is the UInt32 value given by "tag" is marked as a critical
+ * extension, and stores the result in "pCritical".
+ *
+ * Tags are the index into the table "oids" of SECOidData defined in the
+ * file secoid.c. Constants, such as SEC_OID_X509_CERTIFICATE_POLICIES, are
+ * are defined in secoidt.h for most of the table entries.
+ *
+ * If the specified tag is invalid (not in the list of tags) or if the
+ * extension is not found in the certificate, PKIX_FALSE is stored.
+ *
+ * PARAMETERS
+ * "cert"
+ * Address of Cert whose extensions are to be examined. Must be non-NULL.
+ * "tag"
+ * The UInt32 value of the tag for the extension whose criticality is
+ * to be determined
+ * "pCritical"
+ * Address where the Boolean value will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_IsExtensionCritical(
+ PKIX_PL_Cert *cert,
+ PKIX_UInt32 tag,
+ PKIX_Boolean *pCritical,
+ void *plContext)
+{
+ PKIX_Boolean criticality = PKIX_FALSE;
+ CERTCertExtension **extensions = NULL;
+ SECStatus rv;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_IsExtensionCritical");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCritical);
+
+ extensions = cert->nssCert->extensions;
+ PKIX_NULLCHECK_ONE(extensions);
+
+ PKIX_CERT_DEBUG("\t\tCalling CERT_GetExtenCriticality).\n");
+ rv = CERT_GetExtenCriticality(extensions, tag, &criticality);
+ if (SECSuccess == rv) {
+ *pCritical = criticality;
+ } else {
+ *pCritical = PKIX_FALSE;
+ }
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_DecodePolicyInfo
+ * DESCRIPTION:
+ *
+ * Decodes the contents of the CertificatePolicy extension in the
+ * CERTCertificate pointed to by "nssCert", to create a List of
+ * CertPolicyInfos, which is stored at the address "pCertPolicyInfos".
+ * A CERTCertificate contains the DER representation of the Cert.
+ * If this certificate does not have a CertificatePolicy extension,
+ * NULL will be stored. If a List is returned, it will be immutable.
+ *
+ * PARAMETERS
+ * "nssCert"
+ * Address of the Cert data whose extension is to be examined. Must be
+ * non-NULL.
+ * "pCertPolicyInfos"
+ * Address where the List of CertPolicyInfos will be stored. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_DecodePolicyInfo(
+ CERTCertificate *nssCert,
+ PKIX_List **pCertPolicyInfos,
+ void *plContext)
+{
+
+ SECStatus rv;
+ SECItem encodedCertPolicyInfo;
+
+ /* Allocated in the arena; freed in CERT_Destroy... */
+ CERTCertificatePolicies *certPol = NULL;
+ CERTPolicyInfo **policyInfos = NULL;
+
+ /* Holder for the return value */
+ PKIX_List *infos = NULL;
+
+ PKIX_PL_OID *pkixOID = NULL;
+ PKIX_List *qualifiers = NULL;
+ PKIX_PL_CertPolicyInfo *certPolicyInfo = NULL;
+ PKIX_PL_CertPolicyQualifier *certPolicyQualifier = NULL;
+ PKIX_PL_ByteArray *qualifierArray = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyInfo");
+ PKIX_NULLCHECK_TWO(nssCert, pCertPolicyInfos);
+
+ /* get PolicyInfo as a SECItem */
+ PKIX_CERT_DEBUG("\t\tCERT_FindCertExtension).\n");
+ rv = CERT_FindCertExtension
+ (nssCert,
+ SEC_OID_X509_CERTIFICATE_POLICIES,
+ &encodedCertPolicyInfo);
+ if (SECSuccess != rv) {
+ *pCertPolicyInfos = NULL;
+ goto cleanup;
+ }
+
+ /* translate PolicyInfo to CERTCertificatePolicies */
+ PKIX_CERT_DEBUG("\t\tCERT_DecodeCertificatePoliciesExtension).\n");
+ certPol = CERT_DecodeCertificatePoliciesExtension
+ (&encodedCertPolicyInfo);
+
+ PORT_Free(encodedCertPolicyInfo.data);
+
+ if (NULL == certPol) {
+ PKIX_ERROR(PKIX_CERTDECODECERTIFICATEPOLICIESEXTENSIONFAILED);
+ }
+
+ /*
+ * Check whether there are any policyInfos, so we can
+ * avoid creating an unnecessary List
+ */
+ policyInfos = certPol->policyInfos;
+ if (!policyInfos) {
+ *pCertPolicyInfos = NULL;
+ goto cleanup;
+ }
+
+ /* create a List of CertPolicyInfo Objects */
+ PKIX_CHECK(PKIX_List_Create(&infos, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /*
+ * Traverse the CERTCertificatePolicies structure,
+ * building each PKIX_PL_CertPolicyInfo object in turn
+ */
+ while (*policyInfos != NULL) {
+ CERTPolicyInfo *policyInfo = *policyInfos;
+ CERTPolicyQualifier **policyQualifiers =
+ policyInfo->policyQualifiers;
+ if (policyQualifiers) {
+ /* create a PKIX_List of PKIX_PL_CertPolicyQualifiers */
+ PKIX_CHECK(PKIX_List_Create(&qualifiers, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ while (*policyQualifiers != NULL) {
+ CERTPolicyQualifier *policyQualifier =
+ *policyQualifiers;
+
+ /* create the qualifier's OID object */
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (&policyQualifier->qualifierID,
+ &pkixOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* create qualifier's ByteArray object */
+
+ PKIX_CHECK(PKIX_PL_ByteArray_Create
+ (policyQualifier->qualifierValue.data,
+ policyQualifier->qualifierValue.len,
+ &qualifierArray,
+ plContext),
+ PKIX_BYTEARRAYCREATEFAILED);
+
+ /* create a CertPolicyQualifier object */
+
+ PKIX_CHECK(pkix_pl_CertPolicyQualifier_Create
+ (pkixOID,
+ qualifierArray,
+ &certPolicyQualifier,
+ plContext),
+ PKIX_CERTPOLICYQUALIFIERCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (qualifiers,
+ (PKIX_PL_Object *)certPolicyQualifier,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(pkixOID);
+ PKIX_DECREF(qualifierArray);
+ PKIX_DECREF(certPolicyQualifier);
+
+ policyQualifiers++;
+ }
+
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (qualifiers, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+ }
+
+
+ /*
+ * Create an OID object pkixOID from policyInfo->policyID.
+ * (The CERTPolicyInfo structure has an oid field, but it
+ * is of type SECOidTag. This function wants a SECItem.)
+ */
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (&policyInfo->policyID, &pkixOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* Create a CertPolicyInfo object */
+ PKIX_CHECK(pkix_pl_CertPolicyInfo_Create
+ (pkixOID, qualifiers, &certPolicyInfo, plContext),
+ PKIX_CERTPOLICYINFOCREATEFAILED);
+
+ /* Append the new CertPolicyInfo object to the list */
+ PKIX_CHECK(PKIX_List_AppendItem
+ (infos, (PKIX_PL_Object *)certPolicyInfo, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(pkixOID);
+ PKIX_DECREF(qualifiers);
+ PKIX_DECREF(certPolicyInfo);
+
+ policyInfos++;
+ }
+
+ /*
+ * If there were no policies, we went straight to
+ * cleanup, so we don't have to NULLCHECK infos.
+ */
+ PKIX_CHECK(PKIX_List_SetImmutable(infos, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ *pCertPolicyInfos = infos;
+ infos = NULL;
+
+cleanup:
+ if (certPol) {
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_DestroyCertificatePoliciesExtension).\n");
+ CERT_DestroyCertificatePoliciesExtension(certPol);
+ }
+
+ PKIX_DECREF(infos);
+ PKIX_DECREF(pkixOID);
+ PKIX_DECREF(qualifiers);
+ PKIX_DECREF(certPolicyInfo);
+ PKIX_DECREF(certPolicyQualifier);
+ PKIX_DECREF(qualifierArray);
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_DecodePolicyMapping
+ * DESCRIPTION:
+ *
+ * Decodes the contents of the PolicyMapping extension of the CERTCertificate
+ * pointed to by "nssCert", storing the resulting List of CertPolicyMaps at
+ * the address pointed to by "pCertPolicyMaps". If this certificate does not
+ * have a PolicyMapping extension, NULL will be stored. If a List is returned,
+ * it will be immutable.
+ *
+ * PARAMETERS
+ * "nssCert"
+ * Address of the Cert data whose extension is to be examined. Must be
+ * non-NULL.
+ * "pCertPolicyMaps"
+ * Address where the List of CertPolicyMaps will be stored. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_DecodePolicyMapping(
+ CERTCertificate *nssCert,
+ PKIX_List **pCertPolicyMaps,
+ void *plContext)
+{
+ SECStatus rv;
+ SECItem encodedCertPolicyMaps;
+
+ /* Allocated in the arena; freed in CERT_Destroy... */
+ CERTCertificatePolicyMappings *certPolMaps = NULL;
+ CERTPolicyMap **policyMaps = NULL;
+
+ /* Holder for the return value */
+ PKIX_List *maps = NULL;
+
+ PKIX_PL_OID *issuerDomainOID = NULL;
+ PKIX_PL_OID *subjectDomainOID = NULL;
+ PKIX_PL_CertPolicyMap *certPolicyMap = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyMapping");
+ PKIX_NULLCHECK_TWO(nssCert, pCertPolicyMaps);
+
+ /* get PolicyMappings as a SECItem */
+ PKIX_CERT_DEBUG("\t\tCERT_FindCertExtension).\n");
+ rv = CERT_FindCertExtension
+ (nssCert, SEC_OID_X509_POLICY_MAPPINGS, &encodedCertPolicyMaps);
+ if (SECSuccess != rv) {
+ *pCertPolicyMaps = NULL;
+ goto cleanup;
+ }
+
+ /* translate PolicyMaps to CERTCertificatePolicyMappings */
+ certPolMaps = CERT_DecodePolicyMappingsExtension
+ (&encodedCertPolicyMaps);
+
+ PORT_Free(encodedCertPolicyMaps.data);
+
+ if (!certPolMaps) {
+ PKIX_ERROR(PKIX_CERTDECODEPOLICYMAPPINGSEXTENSIONFAILED);
+ }
+
+ PKIX_NULLCHECK_ONE(certPolMaps->policyMaps);
+
+ policyMaps = certPolMaps->policyMaps;
+
+ /* create a List of CertPolicyMap Objects */
+ PKIX_CHECK(PKIX_List_Create(&maps, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /*
+ * Traverse the CERTCertificatePolicyMappings structure,
+ * building each CertPolicyMap object in turn
+ */
+ do {
+ CERTPolicyMap *policyMap = *policyMaps;
+
+ /* create the OID for the issuer Domain Policy */
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (&policyMap->issuerDomainPolicy,
+ &issuerDomainOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* create the OID for the subject Domain Policy */
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (&policyMap->subjectDomainPolicy,
+ &subjectDomainOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* create the CertPolicyMap */
+
+ PKIX_CHECK(pkix_pl_CertPolicyMap_Create
+ (issuerDomainOID,
+ subjectDomainOID,
+ &certPolicyMap,
+ plContext),
+ PKIX_CERTPOLICYMAPCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (maps, (PKIX_PL_Object *)certPolicyMap, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(issuerDomainOID);
+ PKIX_DECREF(subjectDomainOID);
+ PKIX_DECREF(certPolicyMap);
+
+ policyMaps++;
+ } while (*policyMaps != NULL);
+
+ PKIX_CHECK(PKIX_List_SetImmutable(maps, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ *pCertPolicyMaps = maps;
+ maps = NULL;
+
+cleanup:
+ if (certPolMaps) {
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_DestroyPolicyMappingsExtension).\n");
+ CERT_DestroyPolicyMappingsExtension(certPolMaps);
+ }
+
+ PKIX_DECREF(maps);
+ PKIX_DECREF(issuerDomainOID);
+ PKIX_DECREF(subjectDomainOID);
+ PKIX_DECREF(certPolicyMap);
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_DecodePolicyConstraints
+ * DESCRIPTION:
+ *
+ * Decodes the contents of the PolicyConstraints extension in the
+ * CERTCertificate pointed to by "nssCert", to obtain SkipCerts values
+ * which are stored at the addresses "pExplicitPolicySkipCerts" and
+ * "pInhibitMappingSkipCerts", respectively. If this certificate does
+ * not have an PolicyConstraints extension, or if either of the optional
+ * components is not supplied, this function stores a value of -1 for any
+ * missing component.
+ *
+ * PARAMETERS
+ * "nssCert"
+ * Address of the Cert data whose extension is to be examined. Must be
+ * non-NULL.
+ * "pExplicitPolicySkipCerts"
+ * Address where the SkipCert value for the requireExplicitPolicy
+ * component will be stored. Must be non-NULL.
+ * "pInhibitMappingSkipCerts"
+ * Address where the SkipCert value for the inhibitPolicyMapping
+ * component will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_DecodePolicyConstraints(
+ CERTCertificate *nssCert,
+ PKIX_Int32 *pExplicitPolicySkipCerts,
+ PKIX_Int32 *pInhibitMappingSkipCerts,
+ void *plContext)
+{
+ CERTCertificatePolicyConstraints policyConstraints;
+ SECStatus rv;
+ SECItem encodedCertPolicyConstraints;
+ PKIX_Int32 explicitPolicySkipCerts = -1;
+ PKIX_Int32 inhibitMappingSkipCerts = -1;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyConstraints");
+ PKIX_NULLCHECK_THREE
+ (nssCert, pExplicitPolicySkipCerts, pInhibitMappingSkipCerts);
+
+ /* get the two skipCert values as SECItems */
+ PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n");
+ rv = CERT_FindCertExtension
+ (nssCert,
+ SEC_OID_X509_POLICY_CONSTRAINTS,
+ &encodedCertPolicyConstraints);
+
+ if (rv == SECSuccess) {
+
+ policyConstraints.explicitPolicySkipCerts.data =
+ (unsigned char *)&explicitPolicySkipCerts;
+ policyConstraints.inhibitMappingSkipCerts.data =
+ (unsigned char *)&inhibitMappingSkipCerts;
+
+ /* translate DER to CERTCertificatePolicyConstraints */
+ rv = CERT_DecodePolicyConstraintsExtension
+ (&policyConstraints, &encodedCertPolicyConstraints);
+
+ PORT_Free(encodedCertPolicyConstraints.data);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR
+ (PKIX_CERTDECODEPOLICYCONSTRAINTSEXTENSIONFAILED);
+ }
+ }
+
+ *pExplicitPolicySkipCerts = explicitPolicySkipCerts;
+ *pInhibitMappingSkipCerts = inhibitMappingSkipCerts;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_DecodeInhibitAnyPolicy
+ * DESCRIPTION:
+ *
+ * Decodes the contents of the InhibitAnyPolicy extension in the
+ * CERTCertificate pointed to by "nssCert", to obtain a SkipCerts value,
+ * which is stored at the address "pSkipCerts". If this certificate does
+ * not have an InhibitAnyPolicy extension, -1 will be stored.
+ *
+ * PARAMETERS
+ * "nssCert"
+ * Address of the Cert data whose InhibitAnyPolicy extension is to be
+ * processed. Must be non-NULL.
+ * "pSkipCerts"
+ * Address where the SkipCert value from the InhibitAnyPolicy extension
+ * will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_DecodeInhibitAnyPolicy(
+ CERTCertificate *nssCert,
+ PKIX_Int32 *pSkipCerts,
+ void *plContext)
+{
+ CERTCertificateInhibitAny inhibitAny;
+ SECStatus rv;
+ SECItem encodedCertInhibitAny;
+ PKIX_Int32 skipCerts = -1;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_DecodeInhibitAnyPolicy");
+ PKIX_NULLCHECK_TWO(nssCert, pSkipCerts);
+
+ /* get InhibitAny as a SECItem */
+ PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n");
+ rv = CERT_FindCertExtension
+ (nssCert, SEC_OID_X509_INHIBIT_ANY_POLICY, &encodedCertInhibitAny);
+
+ if (rv == SECSuccess) {
+ inhibitAny.inhibitAnySkipCerts.data =
+ (unsigned char *)&skipCerts;
+
+ /* translate DER to CERTCertificateInhibitAny */
+ rv = CERT_DecodeInhibitAnyExtension
+ (&inhibitAny, &encodedCertInhibitAny);
+
+ PORT_Free(encodedCertInhibitAny.data);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_CERTDECODEINHIBITANYEXTENSIONFAILED);
+ }
+ }
+
+ *pSkipCerts = skipCerts;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_GetNssSubjectAltNames
+ * DESCRIPTION:
+ *
+ * Retrieves the Subject Alternative Names of the certificate specified by
+ * "cert" and stores it at "pNssSubjAltNames". If the Subject Alternative
+ * Name extension is not present, NULL is returned at "pNssSubjAltNames".
+ * If the Subject Alternative Names has not been previously decoded, it is
+ * decoded here with lock on the "cert" unless the flag "hasLock" indicates
+ * the lock had been obtained at a higher call level.
+ *
+ * PARAMETERS
+ * "cert"
+ * Address of the certificate whose Subject Alternative Names extensions
+ * is retrieved. Must be non-NULL.
+ * "hasLock"
+ * Boolean indicates caller has acquired a lock.
+ * Must be non-NULL.
+ * "pNssSubjAltNames"
+ * Address where the returned Subject Alternative Names will be stored.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_GetNssSubjectAltNames(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean hasLock,
+ CERTGeneralName **pNssSubjAltNames,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ CERTGeneralName *nssOriginalAltName = NULL;
+ PLArenaPool *arena = NULL;
+ SECItem altNameExtension = {siBuffer, NULL, 0};
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_GetNssSubjectAltNames");
+ PKIX_NULLCHECK_THREE(cert, pNssSubjAltNames, cert->nssCert);
+
+ nssCert = cert->nssCert;
+
+ if ((cert->nssSubjAltNames == NULL) && (!cert->subjAltNamesAbsent)){
+
+ if (!hasLock) {
+ PKIX_OBJECT_LOCK(cert);
+ }
+
+ if ((cert->nssSubjAltNames == NULL) &&
+ (!cert->subjAltNamesAbsent)){
+
+ PKIX_PL_NSSCALLRV(CERT, rv, CERT_FindCertExtension,
+ (nssCert,
+ SEC_OID_X509_SUBJECT_ALT_NAME,
+ &altNameExtension));
+
+ if (rv != SECSuccess) {
+ *pNssSubjAltNames = NULL;
+ cert->subjAltNamesAbsent = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ if (cert->arenaNameConstraints == NULL) {
+ PKIX_PL_NSSCALLRV(CERT, arena, PORT_NewArena,
+ (DER_DEFAULT_CHUNKSIZE));
+
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+ cert->arenaNameConstraints = arena;
+ }
+
+ PKIX_PL_NSSCALLRV
+ (CERT,
+ nssOriginalAltName,
+ (CERTGeneralName *) CERT_DecodeAltNameExtension,
+ (cert->arenaNameConstraints, &altNameExtension));
+
+ PKIX_PL_NSSCALL(CERT, PORT_Free, (altNameExtension.data));
+
+ if (nssOriginalAltName == NULL) {
+ PKIX_ERROR(PKIX_CERTDECODEALTNAMEEXTENSIONFAILED);
+ }
+ cert->nssSubjAltNames = nssOriginalAltName;
+
+ }
+
+ if (!hasLock) {
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+ }
+
+ *pNssSubjAltNames = cert->nssSubjAltNames;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_CheckExtendKeyUsage
+ * DESCRIPTION:
+ *
+ * For each of the ON bit in "requiredExtendedKeyUsages" that represents its
+ * SECCertUsageEnum type, this function checks "cert"'s certType (extended
+ * key usage) and key usage with what is required for SECCertUsageEnum type.
+ *
+ * PARAMETERS
+ * "cert"
+ * Address of the certificate whose Extended Key Usage extensions
+ * is retrieved. Must be non-NULL.
+ * "requiredExtendedKeyUsages"
+ * An unsigned integer, its bit location is ON based on the required key
+ * usage value representing in SECCertUsageEnum.
+ * "pPass"
+ * Address where the return value, indicating key usage check passed, is
+ * stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_CheckExtendedKeyUsage(
+ PKIX_PL_Cert *cert,
+ PKIX_UInt32 requiredExtendedKeyUsages,
+ PKIX_Boolean *pPass,
+ void *plContext)
+{
+ PKIX_PL_CertBasicConstraints *basicConstraints = NULL;
+ PKIX_UInt32 certType = 0;
+ PKIX_UInt32 requiredKeyUsage = 0;
+ PKIX_UInt32 requiredCertType = 0;
+ PKIX_UInt32 requiredExtendedKeyUsage = 0;
+ PKIX_UInt32 i;
+ PKIX_Boolean isCA = PKIX_FALSE;
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_CheckExtendKeyUsage");
+ PKIX_NULLCHECK_THREE(cert, pPass, cert->nssCert);
+
+ *pPass = PKIX_FALSE;
+
+ PKIX_CERT_DEBUG("\t\tCalling cert_GetCertType).\n");
+ cert_GetCertType(cert->nssCert);
+ certType = cert->nssCert->nsCertType;
+
+ PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints
+ (cert,
+ &basicConstraints,
+ plContext),
+ PKIX_CERTGETBASICCONSTRAINTFAILED);
+
+ if (basicConstraints != NULL) {
+ PKIX_CHECK(PKIX_PL_BasicConstraints_GetCAFlag
+ (basicConstraints, &isCA, plContext),
+ PKIX_BASICCONSTRAINTSGETCAFLAGFAILED);
+ }
+
+ i = 0;
+ while (requiredExtendedKeyUsages != 0) {
+
+ /* Find the bit location of the right-most non-zero bit */
+ while (requiredExtendedKeyUsages != 0) {
+ if (((1 << i) & requiredExtendedKeyUsages) != 0) {
+ requiredExtendedKeyUsage = 1 << i;
+ break;
+ }
+ i++;
+ }
+ requiredExtendedKeyUsages ^= requiredExtendedKeyUsage;
+
+ requiredExtendedKeyUsage = i;
+
+ PKIX_PL_NSSCALLRV(CERT, rv, CERT_KeyUsageAndTypeForCertUsage,
+ (requiredExtendedKeyUsage,
+ isCA,
+ &requiredKeyUsage,
+ &requiredCertType));
+
+ if (!(certType & requiredCertType)) {
+ goto cleanup;
+ }
+
+ PKIX_PL_NSSCALLRV(CERT, rv, CERT_CheckKeyUsage,
+ (cert->nssCert, requiredKeyUsage));
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+ i++;
+
+ }
+
+ *pPass = PKIX_TRUE;
+
+cleanup:
+ PKIX_DECREF(basicConstraints);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_ToString_Helper
+ * DESCRIPTION:
+ *
+ * Helper function that creates a string representation of the Cert pointed
+ * to by "cert" and stores it at "pString", where the value of
+ * "partialString" determines whether a full or partial representation of
+ * the Cert is stored.
+ *
+ * PARAMETERS
+ * "cert"
+ * Address of Cert whose string representation is desired.
+ * Must be non-NULL.
+ * "partialString"
+ * Boolean indicating whether a partial Cert representation is desired.
+ * "pString"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_ToString_Helper(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean partialString,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *certString = NULL;
+ char *asciiFormat = NULL;
+ PKIX_PL_String *formatString = NULL;
+ PKIX_UInt32 certVersion;
+ PKIX_PL_BigInt *certSN = NULL;
+ PKIX_PL_String *certSNString = NULL;
+ PKIX_PL_X500Name *certIssuer = NULL;
+ PKIX_PL_String *certIssuerString = NULL;
+ PKIX_PL_X500Name *certSubject = NULL;
+ PKIX_PL_String *certSubjectString = NULL;
+ PKIX_PL_String *notBeforeString = NULL;
+ PKIX_PL_String *notAfterString = NULL;
+ PKIX_List *subjAltNames = NULL;
+ PKIX_PL_String *subjAltNamesString = NULL;
+ PKIX_PL_ByteArray *authKeyId = NULL;
+ PKIX_PL_String *authKeyIdString = NULL;
+ PKIX_PL_ByteArray *subjKeyId = NULL;
+ PKIX_PL_String *subjKeyIdString = NULL;
+ PKIX_PL_PublicKey *nssPubKey = NULL;
+ PKIX_PL_String *nssPubKeyString = NULL;
+ PKIX_List *critExtOIDs = NULL;
+ PKIX_PL_String *critExtOIDsString = NULL;
+ PKIX_List *extKeyUsages = NULL;
+ PKIX_PL_String *extKeyUsagesString = NULL;
+ PKIX_PL_CertBasicConstraints *basicConstraint = NULL;
+ PKIX_PL_String *certBasicConstraintsString = NULL;
+ PKIX_List *policyInfo = NULL;
+ PKIX_PL_String *certPolicyInfoString = NULL;
+ PKIX_List *certPolicyMappings = NULL;
+ PKIX_PL_String *certPolicyMappingsString = NULL;
+ PKIX_Int32 certExplicitPolicy = 0;
+ PKIX_Int32 certInhibitMapping = 0;
+ PKIX_Int32 certInhibitAnyPolicy = 0;
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+ PKIX_PL_String *nameConstraintsString = NULL;
+ PKIX_List *authorityInfoAccess = NULL;
+ PKIX_PL_String *authorityInfoAccessString = NULL;
+ PKIX_List *subjectInfoAccess = NULL;
+ PKIX_PL_String *subjectInfoAccessString = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_ToString_Helper");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pString);
+
+ /*
+ * XXX Add to this format as certificate components are developed.
+ */
+
+ if (partialString){
+ asciiFormat =
+ "\t[Issuer: %s\n"
+ "\t Subject: %s]";
+ } else {
+ asciiFormat =
+ "[\n"
+ "\tVersion: v%d\n"
+ "\tSerialNumber: %s\n"
+ "\tIssuer: %s\n"
+ "\tSubject: %s\n"
+ "\tValidity: [From: %s\n"
+ "\t To: %s]\n"
+ "\tSubjectAltNames: %s\n"
+ "\tAuthorityKeyId: %s\n"
+ "\tSubjectKeyId: %s\n"
+ "\tSubjPubKeyAlgId: %s\n"
+ "\tCritExtOIDs: %s\n"
+ "\tExtKeyUsages: %s\n"
+ "\tBasicConstraint: %s\n"
+ "\tCertPolicyInfo: %s\n"
+ "\tPolicyMappings: %s\n"
+ "\tExplicitPolicy: %d\n"
+ "\tInhibitMapping: %d\n"
+ "\tInhibitAnyPolicy:%d\n"
+ "\tNameConstraints: %s\n"
+ "\tAuthorityInfoAccess: %s\n"
+ "\tSubjectInfoAccess: %s\n"
+ "\tCacheFlag: %d\n"
+ "]\n";
+ }
+
+
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ /* Issuer */
+ PKIX_CHECK(PKIX_PL_Cert_GetIssuer
+ (cert, &certIssuer, plContext),
+ PKIX_CERTGETISSUERFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)certIssuer, &certIssuerString, plContext),
+ PKIX_X500NAMETOSTRINGFAILED);
+
+ /* Subject */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubject(cert, &certSubject, plContext),
+ PKIX_CERTGETSUBJECTFAILED);
+
+ PKIX_TOSTRING(certSubject, &certSubjectString, plContext,
+ PKIX_X500NAMETOSTRINGFAILED);
+
+ if (partialString){
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&certString,
+ plContext,
+ formatString,
+ certIssuerString,
+ certSubjectString),
+ PKIX_SPRINTFFAILED);
+
+ *pString = certString;
+ goto cleanup;
+ }
+
+ /* Version */
+ PKIX_CHECK(PKIX_PL_Cert_GetVersion(cert, &certVersion, plContext),
+ PKIX_CERTGETVERSIONFAILED);
+
+ /* SerialNumber */
+ PKIX_CHECK(PKIX_PL_Cert_GetSerialNumber(cert, &certSN, plContext),
+ PKIX_CERTGETSERIALNUMBERFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)certSN, &certSNString, plContext),
+ PKIX_BIGINTTOSTRINGFAILED);
+
+ /* Validity: NotBefore */
+ PKIX_CHECK(pkix_pl_Date_ToString_Helper
+ (&(cert->nssCert->validity.notBefore),
+ &notBeforeString,
+ plContext),
+ PKIX_DATETOSTRINGHELPERFAILED);
+
+ /* Validity: NotAfter */
+ PKIX_CHECK(pkix_pl_Date_ToString_Helper
+ (&(cert->nssCert->validity.notAfter),
+ &notAfterString,
+ plContext),
+ PKIX_DATETOSTRINGHELPERFAILED);
+
+ /* SubjectAltNames */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames
+ (cert, &subjAltNames, plContext),
+ PKIX_CERTGETSUBJECTALTNAMESFAILED);
+
+ PKIX_TOSTRING(subjAltNames, &subjAltNamesString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* AuthorityKeyIdentifier */
+ PKIX_CHECK(PKIX_PL_Cert_GetAuthorityKeyIdentifier
+ (cert, &authKeyId, plContext),
+ PKIX_CERTGETAUTHORITYKEYIDENTIFIERFAILED);
+
+ PKIX_TOSTRING(authKeyId, &authKeyIdString, plContext,
+ PKIX_BYTEARRAYTOSTRINGFAILED);
+
+ /* SubjectKeyIdentifier */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectKeyIdentifier
+ (cert, &subjKeyId, plContext),
+ PKIX_CERTGETSUBJECTKEYIDENTIFIERFAILED);
+
+ PKIX_TOSTRING(subjKeyId, &subjKeyIdString, plContext,
+ PKIX_BYTEARRAYTOSTRINGFAILED);
+
+ /* SubjectPublicKey */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
+ (cert, &nssPubKey, plContext),
+ PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)nssPubKey, &nssPubKeyString, plContext),
+ PKIX_PUBLICKEYTOSTRINGFAILED);
+
+ /* CriticalExtensionOIDs */
+ PKIX_CHECK(PKIX_PL_Cert_GetCriticalExtensionOIDs
+ (cert, &critExtOIDs, plContext),
+ PKIX_CERTGETCRITICALEXTENSIONOIDSFAILED);
+
+ PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* ExtendedKeyUsages */
+ PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage
+ (cert, &extKeyUsages, plContext),
+ PKIX_CERTGETEXTENDEDKEYUSAGEFAILED);
+
+ PKIX_TOSTRING(extKeyUsages, &extKeyUsagesString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* CertBasicConstraints */
+ PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints
+ (cert, &basicConstraint, plContext),
+ PKIX_CERTGETBASICCONSTRAINTSFAILED);
+
+ PKIX_TOSTRING(basicConstraint, &certBasicConstraintsString, plContext,
+ PKIX_CERTBASICCONSTRAINTSTOSTRINGFAILED);
+
+ /* CertPolicyInfo */
+ PKIX_CHECK(PKIX_PL_Cert_GetPolicyInformation
+ (cert, &policyInfo, plContext),
+ PKIX_CERTGETPOLICYINFORMATIONFAILED);
+
+ PKIX_TOSTRING(policyInfo, &certPolicyInfoString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* Advanced Policies */
+ PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappings
+ (cert, &certPolicyMappings, plContext),
+ PKIX_CERTGETPOLICYMAPPINGSFAILED);
+
+ PKIX_TOSTRING(certPolicyMappings, &certPolicyMappingsString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetRequireExplicitPolicy
+ (cert, &certExplicitPolicy, plContext),
+ PKIX_CERTGETREQUIREEXPLICITPOLICYFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappingInhibited
+ (cert, &certInhibitMapping, plContext),
+ PKIX_CERTGETPOLICYMAPPINGINHIBITEDFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetInhibitAnyPolicy
+ (cert, &certInhibitAnyPolicy, plContext),
+ PKIX_CERTGETINHIBITANYPOLICYFAILED);
+
+ /* Name Constraints */
+ PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints
+ (cert, &nameConstraints, plContext),
+ PKIX_CERTGETNAMECONSTRAINTSFAILED);
+
+ PKIX_TOSTRING(nameConstraints, &nameConstraintsString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* Authority Information Access */
+ PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
+ (cert, &authorityInfoAccess, plContext),
+ PKIX_CERTGETAUTHORITYINFOACCESSFAILED);
+
+ PKIX_TOSTRING(authorityInfoAccess, &authorityInfoAccessString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* Subject Information Access */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectInfoAccess
+ (cert, &subjectInfoAccess, plContext),
+ PKIX_CERTGETSUBJECTINFOACCESSFAILED);
+
+ PKIX_TOSTRING(subjectInfoAccess, &subjectInfoAccessString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&certString,
+ plContext,
+ formatString,
+ certVersion + 1,
+ certSNString,
+ certIssuerString,
+ certSubjectString,
+ notBeforeString,
+ notAfterString,
+ subjAltNamesString,
+ authKeyIdString,
+ subjKeyIdString,
+ nssPubKeyString,
+ critExtOIDsString,
+ extKeyUsagesString,
+ certBasicConstraintsString,
+ certPolicyInfoString,
+ certPolicyMappingsString,
+ certExplicitPolicy, /* an Int32, not a String */
+ certInhibitMapping, /* an Int32, not a String */
+ certInhibitAnyPolicy, /* an Int32, not a String */
+ nameConstraintsString,
+ authorityInfoAccessString,
+ subjectInfoAccessString,
+ cert->cacheFlag), /* a boolean */
+ PKIX_SPRINTFFAILED);
+
+ *pString = certString;
+
+cleanup:
+ PKIX_DECREF(certSN);
+ PKIX_DECREF(certSNString);
+ PKIX_DECREF(certIssuer);
+ PKIX_DECREF(certIssuerString);
+ PKIX_DECREF(certSubject);
+ PKIX_DECREF(certSubjectString);
+ PKIX_DECREF(notBeforeString);
+ PKIX_DECREF(notAfterString);
+ PKIX_DECREF(subjAltNames);
+ PKIX_DECREF(subjAltNamesString);
+ PKIX_DECREF(authKeyId);
+ PKIX_DECREF(authKeyIdString);
+ PKIX_DECREF(subjKeyId);
+ PKIX_DECREF(subjKeyIdString);
+ PKIX_DECREF(nssPubKey);
+ PKIX_DECREF(nssPubKeyString);
+ PKIX_DECREF(critExtOIDs);
+ PKIX_DECREF(critExtOIDsString);
+ PKIX_DECREF(extKeyUsages);
+ PKIX_DECREF(extKeyUsagesString);
+ PKIX_DECREF(basicConstraint);
+ PKIX_DECREF(certBasicConstraintsString);
+ PKIX_DECREF(policyInfo);
+ PKIX_DECREF(certPolicyInfoString);
+ PKIX_DECREF(certPolicyMappings);
+ PKIX_DECREF(certPolicyMappingsString);
+ PKIX_DECREF(nameConstraints);
+ PKIX_DECREF(nameConstraintsString);
+ PKIX_DECREF(authorityInfoAccess);
+ PKIX_DECREF(authorityInfoAccessString);
+ PKIX_DECREF(subjectInfoAccess);
+ PKIX_DECREF(subjectInfoAccessString);
+ PKIX_DECREF(formatString);
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Cert_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Cert *cert = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext),
+ PKIX_OBJECTNOTCERT);
+
+ cert = (PKIX_PL_Cert*)object;
+
+ PKIX_DECREF(cert->subject);
+ PKIX_DECREF(cert->issuer);
+ PKIX_DECREF(cert->subjAltNames);
+ PKIX_DECREF(cert->publicKeyAlgId);
+ PKIX_DECREF(cert->publicKey);
+ PKIX_DECREF(cert->serialNumber);
+ PKIX_DECREF(cert->critExtOids);
+ PKIX_DECREF(cert->authKeyId);
+ PKIX_DECREF(cert->subjKeyId);
+ PKIX_DECREF(cert->extKeyUsages);
+ PKIX_DECREF(cert->certBasicConstraints);
+ PKIX_DECREF(cert->certPolicyInfos);
+ PKIX_DECREF(cert->certPolicyMappings);
+ PKIX_DECREF(cert->nameConstraints);
+ PKIX_DECREF(cert->store);
+ PKIX_DECREF(cert->authorityInfoAccess);
+ PKIX_DECREF(cert->subjectInfoAccess);
+ PKIX_DECREF(cert->crldpList);
+
+ if (cert->arenaNameConstraints){
+ /* This arena was allocated for SubjectAltNames */
+ PKIX_PL_NSSCALL(CERT, PORT_FreeArena,
+ (cert->arenaNameConstraints, PR_FALSE));
+
+ cert->arenaNameConstraints = NULL;
+ cert->nssSubjAltNames = NULL;
+ }
+
+ CERT_DestroyCertificate(cert->nssCert);
+ cert->nssCert = NULL;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Cert_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *certString = NULL;
+ PKIX_PL_Cert *pkixCert = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_toString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext),
+ PKIX_OBJECTNOTCERT);
+
+ pkixCert = (PKIX_PL_Cert *)object;
+
+ PKIX_CHECK(pkix_pl_Cert_ToString_Helper
+ (pkixCert, PKIX_FALSE, &certString, plContext),
+ PKIX_CERTTOSTRINGHELPERFAILED);
+
+ *pString = certString;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Cert_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_Cert *pkixCert = NULL;
+ CERTCertificate *nssCert = NULL;
+ unsigned char *derBytes = NULL;
+ PKIX_UInt32 derLength;
+ PKIX_UInt32 certHash;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext),
+ PKIX_OBJECTNOTCERT);
+
+ pkixCert = (PKIX_PL_Cert *)object;
+
+ nssCert = pkixCert->nssCert;
+ derBytes = (nssCert->derCert).data;
+ derLength = (nssCert->derCert).len;
+
+ PKIX_CHECK(pkix_hash(derBytes, derLength, &certHash, plContext),
+ PKIX_HASHFAILED);
+
+ *pHashcode = certHash;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_Cert_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Cert_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ CERTCertificate *firstCert = NULL;
+ CERTCertificate *secondCert = NULL;
+ PKIX_UInt32 secondType;
+ PKIX_Boolean cmpResult;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a Cert */
+ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CERT_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTCERT);
+
+ /*
+ * Since we know firstObject is a Cert, if both references are
+ * identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't a Cert, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_CERT_TYPE) goto cleanup;
+
+ firstCert = ((PKIX_PL_Cert *)firstObject)->nssCert;
+ secondCert = ((PKIX_PL_Cert *)secondObject)->nssCert;
+
+ PKIX_NULLCHECK_TWO(firstCert, secondCert);
+
+ /* CERT_CompareCerts does byte comparison on DER encodings of certs */
+ PKIX_CERT_DEBUG("\t\tCalling CERT_CompareCerts).\n");
+ cmpResult = CERT_CompareCerts(firstCert, secondCert);
+
+ *pResult = cmpResult;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_CERT_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_Cert_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_RegisterSelf");
+
+ entry.description = "Cert";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_Cert);
+ entry.destructor = pkix_pl_Cert_Destroy;
+ entry.equalsFunction = pkix_pl_Cert_Equals;
+ entry.hashcodeFunction = pkix_pl_Cert_Hashcode;
+ entry.toStringFunction = pkix_pl_Cert_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_CERT_TYPE] = entry;
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_CreateWithNSSCert
+ * DESCRIPTION:
+ *
+ * Creates a new certificate using the CERTCertificate pointed to by "nssCert"
+ * and stores it at "pCert". Once created, a Cert is immutable.
+ *
+ * This function is primarily used as a convenience function for the
+ * performance tests that have easy access to a CERTCertificate.
+ *
+ * PARAMETERS:
+ * "nssCert"
+ * Address of CERTCertificate representing the NSS certificate.
+ * Must be non-NULL.
+ * "pCert"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_CreateWithNSSCert(
+ CERTCertificate *nssCert,
+ PKIX_PL_Cert **pCert,
+ void *plContext)
+{
+ PKIX_PL_Cert *cert = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_CreateWithNSSCert");
+ PKIX_NULLCHECK_TWO(pCert, nssCert);
+
+ /* create a PKIX_PL_Cert object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_CERT_TYPE,
+ sizeof (PKIX_PL_Cert),
+ (PKIX_PL_Object **)&cert,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ /* populate the nssCert field */
+ cert->nssCert = nssCert;
+
+ /* initialize remaining fields */
+ /*
+ * Fields ending with Absent are initialized to PKIX_FALSE so that the
+ * first time we need the value we will look for it. If we find it is
+ * actually absent, the flag will at that time be set to PKIX_TRUE to
+ * prevent searching for it later.
+ * Fields ending with Processed are those where a value is defined
+ * for the Absent case, and a value of zero is possible. When the
+ * flag is still true we have to look for the field, set the default
+ * value if necessary, and set the Processed flag to PKIX_TRUE.
+ */
+ cert->subject = NULL;
+ cert->issuer = NULL;
+ cert->subjAltNames = NULL;
+ cert->subjAltNamesAbsent = PKIX_FALSE;
+ cert->publicKeyAlgId = NULL;
+ cert->publicKey = NULL;
+ cert->serialNumber = NULL;
+ cert->critExtOids = NULL;
+ cert->subjKeyId = NULL;
+ cert->subjKeyIdAbsent = PKIX_FALSE;
+ cert->authKeyId = NULL;
+ cert->authKeyIdAbsent = PKIX_FALSE;
+ cert->extKeyUsages = NULL;
+ cert->extKeyUsagesAbsent = PKIX_FALSE;
+ cert->certBasicConstraints = NULL;
+ cert->basicConstraintsAbsent = PKIX_FALSE;
+ cert->certPolicyInfos = NULL;
+ cert->policyInfoAbsent = PKIX_FALSE;
+ cert->policyMappingsAbsent = PKIX_FALSE;
+ cert->certPolicyMappings = NULL;
+ cert->policyConstraintsProcessed = PKIX_FALSE;
+ cert->policyConstraintsExplicitPolicySkipCerts = 0;
+ cert->policyConstraintsInhibitMappingSkipCerts = 0;
+ cert->inhibitAnyPolicyProcessed = PKIX_FALSE;
+ cert->inhibitAnySkipCerts = 0;
+ cert->nameConstraints = NULL;
+ cert->nameConstraintsAbsent = PKIX_FALSE;
+ cert->arenaNameConstraints = NULL;
+ cert->nssSubjAltNames = NULL;
+ cert->cacheFlag = PKIX_FALSE;
+ cert->store = NULL;
+ cert->authorityInfoAccess = NULL;
+ cert->subjectInfoAccess = NULL;
+ cert->isUserTrustAnchor = PKIX_FALSE;
+ cert->crldpList = NULL;
+
+ *pCert = cert;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_CreateToList
+ * DESCRIPTION:
+ *
+ * Creates a new certificate using the DER-encoding pointed to by "derCertItem"
+ * and appends it to the list pointed to by "certList". If Cert creation fails,
+ * the function returns with certList unchanged, but any decoding Error is
+ * discarded.
+ *
+ * PARAMETERS:
+ * "derCertItem"
+ * Address of SECItem containing the DER representation of a certificate.
+ * Must be non-NULL.
+ * "certList"
+ * Address of List to which the Cert will be appended, if successfully
+ * created. May be empty, but must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_CreateToList(
+ SECItem *derCertItem,
+ PKIX_List *certList,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ PKIX_PL_Cert *cert = NULL;
+ CERTCertDBHandle *handle;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_CreateToList");
+ PKIX_NULLCHECK_TWO(derCertItem, certList);
+
+ handle = CERT_GetDefaultCertDB();
+ nssCert = CERT_NewTempCertificate(handle, derCertItem,
+ /* nickname */ NULL,
+ /* isPerm */ PR_FALSE,
+ /* copyDer */ PR_TRUE);
+ if (!nssCert) {
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert
+ (nssCert, &cert, plContext),
+ PKIX_CERTCREATEWITHNSSCERTFAILED);
+
+ nssCert = NULL;
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (certList, (PKIX_PL_Object *) cert, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+cleanup:
+ if (nssCert) {
+ CERT_DestroyCertificate(nssCert);
+ }
+
+ PKIX_DECREF(cert);
+ PKIX_RETURN(CERT);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_Cert_Create (see comments in pkix_pl_pki.h)
+ * XXX We may want to cache the cert after parsing it, so it can be reused
+ * XXX Are the NSS/NSPR functions thread safe
+ */
+PKIX_Error *
+PKIX_PL_Cert_Create(
+ PKIX_PL_ByteArray *byteArray,
+ PKIX_PL_Cert **pCert,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ SECItem *derCertItem = NULL;
+ void *derBytes = NULL;
+ PKIX_UInt32 derLength;
+ PKIX_Boolean copyDER;
+ 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
+ */
+ copyDER = PKIX_TRUE;
+ 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 = 1;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetVersion");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pVersion);
+
+ nssCert = cert->nssCert;
+ if (nssCert->version.data) {
+ 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);
+ }
+
+ /* save a cached copy in case it is asked for again */
+ cert->extKeyUsages = oidsList;
+ oidsList = NULL;
+ }
+
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (cert->extKeyUsages, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ 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) {
+ 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) ||
+ (requiredUsages & certificateUsageSSLServerWithStepUp));
+ 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,
+ 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 both Subject and Subject Alt Names */
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_GetConstrainedCertificateNames\n");
+ nssSubjectNames = CERT_GetConstrainedCertificateNames
+ (cert->nssCert, arena, PR_TRUE);
+
+ 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);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_IsCertTrusted
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_IsCertTrusted(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean trustOnlyUserAnchors,
+ PKIX_Boolean *pTrusted,
+ void *plContext)
+{
+ PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
+ SECCertUsage certUsage = 0;
+ PKIX_Boolean trusted = PKIX_FALSE;
+ SECStatus rv = SECFailure;
+ unsigned int requiredFlags;
+ SECTrustType trustType;
+ CERTCertTrust trust;
+ CERTCertificate *nssCert = NULL;
+ SECCertificateUsage certificateUsage;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_IsCertTrusted");
+ PKIX_NULLCHECK_TWO(cert, pTrusted);
+
+ if (trustOnlyUserAnchors) {
+ *pTrusted = cert->isUserTrustAnchor;
+ goto cleanup;
+ }
+
+ /* no key usage information and store is not trusted */
+ if (plContext == NULL || cert->store == NULL) {
+ *pTrusted = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ if (cert->store) {
+ PKIX_CHECK(PKIX_CertStore_GetTrustCallback
+ (cert->store, &trustCallback, plContext),
+ PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
+
+ PKIX_CHECK_ONLY_FATAL(trustCallback
+ (cert->store, cert, &trusted, plContext),
+ PKIX_CHECKTRUSTCALLBACKFAILED);
+
+ if (PKIX_ERROR_RECEIVED || (trusted == PKIX_FALSE)) {
+
+ *pTrusted = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ }
+
+ 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++; }
+
+ rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, &trustType);
+ if (rv != SECSuccess) {
+ *pTrusted = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ nssCert = cert->nssCert;
+
+ rv = CERT_GetCertTrust(nssCert, &trust);
+ if (rv == SECSuccess) {
+ unsigned int certFlags;
+ certFlags = SEC_GET_TRUST_FLAGS((&trust), trustType);
+ if ((certFlags & requiredFlags) == requiredFlags) {
+ trusted = PKIX_TRUE;
+ }
+ }
+
+ *pTrusted = trusted;
+
+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);
+}