/* ***** 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; CERTPolicyInfo *policyInfo = NULL; CERTPolicyQualifier **policyQualifiers = NULL; CERTPolicyQualifier *policyQualifier = NULL; /* Holder for the return value */ PKIX_List *infos = NULL; char *oidAscii = 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) { policyInfo = *policyInfos; 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) { policyQualifier = *policyQualifiers; /* create the qualifier's OID object */ PKIX_CHECK(pkix_pl_oidBytes2Ascii (&(policyQualifier->qualifierID), &oidAscii, plContext), PKIX_OIDBYTES2ASCIIFAILED); PKIX_CHECK(PKIX_PL_OID_Create (oidAscii, &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_FREE(oidAscii); 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_oidBytes2Ascii (&(policyInfo->policyID), &oidAscii, plContext), PKIX_OIDBYTES2ASCIIFAILED); PKIX_CHECK(PKIX_PL_OID_Create (oidAscii, &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_FREE(oidAscii); 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; cleanup: if (certPol) { PKIX_CERT_DEBUG ("\t\tCalling CERT_DestroyCertificatePoliciesExtension).\n"); CERT_DestroyCertificatePoliciesExtension(certPol); } if (PKIX_ERROR_RECEIVED){ PKIX_DECREF(infos); } PKIX_FREE(oidAscii); 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; CERTPolicyMap *policyMap = NULL; /* Holder for the return value */ PKIX_List *maps = NULL; char *issuerPolicyOIDAscii = NULL; char *subjectPolicyOIDAscii = 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 { policyMap = *policyMaps; /* create the OID for the issuer Domain Policy */ PKIX_CHECK(pkix_pl_oidBytes2Ascii (&(policyMap->issuerDomainPolicy), &issuerPolicyOIDAscii, plContext), PKIX_OIDBYTES2ASCIIFAILED); PKIX_CHECK(PKIX_PL_OID_Create (issuerPolicyOIDAscii, &issuerDomainOID, plContext), PKIX_OIDCREATEFAILED); /* create the OID for the subject Domain Policy */ PKIX_CHECK(pkix_pl_oidBytes2Ascii (&(policyMap->subjectDomainPolicy), &subjectPolicyOIDAscii, plContext), PKIX_OIDBYTES2ASCIIFAILED); PKIX_CHECK(PKIX_PL_OID_Create (subjectPolicyOIDAscii, &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_FREE(issuerPolicyOIDAscii); PKIX_FREE(subjectPolicyOIDAscii); PKIX_DECREF(issuerDomainOID); PKIX_DECREF(subjectDomainOID); PKIX_DECREF(certPolicyMap); policyMaps++; } while (*policyMaps != NULL); PKIX_CHECK(PKIX_List_SetImmutable(maps, plContext), PKIX_LISTSETIMMUTABLEFAILED); *pCertPolicyMaps = maps; cleanup: if (certPolMaps) { PKIX_CERT_DEBUG ("\t\tCalling CERT_DestroyPolicyMappingsExtension).\n"); CERT_DestroyPolicyMappingsExtension(certPolMaps); } PKIX_FREE(issuerPolicyOIDAscii); PKIX_FREE(subjectPolicyOIDAscii); PKIX_DECREF(issuerDomainOID); PKIX_DECREF(subjectDomainOID); PKIX_DECREF(certPolicyMap); PKIX_RETURN(CERT); } /* * FUNCTION: pkix_pl_Cert_DecodePolicyConstraints * DESCRIPTION: * * Decodes the contents of the PolicyConstraints extension in the * CERTCertificate pointed to by "nssCert", to obtain SkipCerts values * which are stored at the addresses "pExplicitPolicySkipCerts" and * "pInhibitMappingSkipCerts", respectively. If this certificate does * not have an PolicyConstraints extension, or if either of the optional * components is not supplied, this function stores a value of -1 for any * missing component. * * PARAMETERS * "nssCert" * Address of the Cert data whose extension is to be examined. Must be * non-NULL. * "pExplicitPolicySkipCerts" * Address where the SkipCert value for the requireExplicitPolicy * component will be stored. Must be non-NULL. * "pInhibitMappingSkipCerts" * Address where the SkipCert value for the inhibitPolicyMapping * component will be stored. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns a Cert Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_Cert_DecodePolicyConstraints( CERTCertificate *nssCert, PKIX_Int32 *pExplicitPolicySkipCerts, PKIX_Int32 *pInhibitMappingSkipCerts, void *plContext) { CERTCertificatePolicyConstraints policyConstraints; SECStatus rv; SECItem encodedCertPolicyConstraints; PKIX_Int32 explicitPolicySkipCerts = -1; PKIX_Int32 inhibitMappingSkipCerts = -1; PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyConstraints"); PKIX_NULLCHECK_THREE (nssCert, pExplicitPolicySkipCerts, pInhibitMappingSkipCerts); /* get the two skipCert values as SECItems */ PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n"); rv = CERT_FindCertExtension (nssCert, SEC_OID_X509_POLICY_CONSTRAINTS, &encodedCertPolicyConstraints); if (rv == SECSuccess) { policyConstraints.explicitPolicySkipCerts.data = (unsigned char *)&explicitPolicySkipCerts; policyConstraints.inhibitMappingSkipCerts.data = (unsigned char *)&inhibitMappingSkipCerts; /* translate DER to CERTCertificatePolicyConstraints */ rv = CERT_DecodePolicyConstraintsExtension (&policyConstraints, &encodedCertPolicyConstraints); PORT_Free(encodedCertPolicyConstraints.data); if (rv != SECSuccess) { PKIX_ERROR (PKIX_CERTDECODEPOLICYCONSTRAINTSEXTENSIONFAILED); } } *pExplicitPolicySkipCerts = explicitPolicySkipCerts; *pInhibitMappingSkipCerts = inhibitMappingSkipCerts; cleanup: PKIX_RETURN(CERT); } /* * FUNCTION: pkix_pl_Cert_DecodeInhibitAnyPolicy * DESCRIPTION: * * Decodes the contents of the InhibitAnyPolicy extension in the * CERTCertificate pointed to by "nssCert", to obtain a SkipCerts value, * which is stored at the address "pSkipCerts". If this certificate does * not have an InhibitAnyPolicy extension, -1 will be stored. * * PARAMETERS * "nssCert" * Address of the Cert data whose InhibitAnyPolicy extension is to be * processed. Must be non-NULL. * "pSkipCerts" * Address where the SkipCert value from the InhibitAnyPolicy extension * will be stored. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns a Cert Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_pl_Cert_DecodeInhibitAnyPolicy( CERTCertificate *nssCert, PKIX_Int32 *pSkipCerts, void *plContext) { CERTCertificateInhibitAny inhibitAny; SECStatus rv; SECItem encodedCertInhibitAny; PKIX_Int32 skipCerts = -1; PKIX_ENTER(CERT, "pkix_pl_Cert_DecodeInhibitAnyPolicy"); PKIX_NULLCHECK_TWO(nssCert, pSkipCerts); /* get InhibitAny as a SECItem */ PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n"); rv = CERT_FindCertExtension (nssCert, SEC_OID_X509_INHIBIT_ANY_POLICY, &encodedCertInhibitAny); if (rv == SECSuccess) { inhibitAny.inhibitAnySkipCerts.data = (unsigned char *)&skipCerts; /* translate DER to CERTCertificateInhibitAny */ rv = CERT_DecodeInhibitAnyExtension (&inhibitAny, &encodedCertInhibitAny); PORT_Free(encodedCertInhibitAny.data); if (rv != SECSuccess) { PKIX_ERROR(PKIX_CERTDECODEINHIBITANYEXTENSIONFAILED); } } *pSkipCerts = skipCerts; cleanup: PKIX_RETURN(CERT); } /* * FUNCTION: pkix_pl_Cert_GetNssSubjectAltNames * DESCRIPTION: * * Retrieves the Subject Alternative Names of the certificate specified by * "cert" and stores it at "pNssSubjAltNames". If the Subject Alternative * Name extension is not present, NULL is returned at "pNssSubjAltNames". * If the Subject Alternative Names has not been previously decoded, it is * decoded here with lock on the "cert" unless the flag "hasLock" indicates * the lock had been obtained at a higher call level. * * PARAMETERS * "cert" * Address of the certificate whose Subject Alternative Names extensions * is retrieved. Must be non-NULL. * "hasLock" * Boolean indicates caller has acquired a lock. * Must be non-NULL. * "pNssSubjAltNames" * Address where the returned Subject Alternative Names will be stored. * Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns a Cert Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_pl_Cert_GetNssSubjectAltNames( PKIX_PL_Cert *cert, PKIX_Boolean hasLock, CERTGeneralName **pNssSubjAltNames, void *plContext) { CERTCertificate *nssCert = NULL; CERTGeneralName *nssOriginalAltName = NULL; PLArenaPool *arena = NULL; SECItem altNameExtension = {siBuffer, NULL, 0}; SECStatus rv = SECFailure; PKIX_ENTER(CERT, "pkix_pl_Cert_GetNssSubjectAltNames"); PKIX_NULLCHECK_THREE(cert, pNssSubjAltNames, cert->nssCert); nssCert = cert->nssCert; if ((cert->nssSubjAltNames == NULL) && (!cert->subjAltNamesAbsent)){ if (!hasLock) { PKIX_OBJECT_LOCK(cert); } if ((cert->nssSubjAltNames == NULL) && (!cert->subjAltNamesAbsent)){ PKIX_PL_NSSCALLRV(CERT, rv, CERT_FindCertExtension, (nssCert, SEC_OID_X509_SUBJECT_ALT_NAME, &altNameExtension)); if (rv != SECSuccess) { *pNssSubjAltNames = NULL; cert->subjAltNamesAbsent = PKIX_TRUE; goto cleanup; } if (cert->arenaNameConstraints == NULL) { PKIX_PL_NSSCALLRV(CERT, arena, PORT_NewArena, (DER_DEFAULT_CHUNKSIZE)); if (arena == NULL) { PKIX_ERROR(PKIX_OUTOFMEMORY); } cert->arenaNameConstraints = arena; } PKIX_PL_NSSCALLRV (CERT, nssOriginalAltName, (CERTGeneralName *) CERT_DecodeAltNameExtension, (cert->arenaNameConstraints, &altNameExtension)); PKIX_PL_NSSCALL(CERT, PORT_Free, (altNameExtension.data)); if (nssOriginalAltName == NULL) { PKIX_ERROR(PKIX_CERTDECODEALTNAMEEXTENSIONFAILED); } cert->nssSubjAltNames = nssOriginalAltName; } if (!hasLock) { PKIX_OBJECT_UNLOCK(cert); } } *pNssSubjAltNames = cert->nssSubjAltNames; cleanup: PKIX_OBJECT_UNLOCK(lockedObject); PKIX_RETURN(CERT); } /* * FUNCTION: pkix_pl_Cert_CheckExtendKeyUsage * DESCRIPTION: * * For each of the ON bit in "requiredExtendedKeyUsages" that represents its * SECCertUsageEnum type, this function checks "cert"'s certType (extended * key usage) and key usage with what is required for SECCertUsageEnum type. * * PARAMETERS * "cert" * Address of the certificate whose Extended Key Usage extensions * is retrieved. Must be non-NULL. * "requiredExtendedKeyUsages" * An unsigned integer, its bit location is ON based on the required key * usage value representing in SECCertUsageEnum. * "pPass" * Address where the return value, indicating key usage check passed, is * stored. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns a Cert Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_pl_Cert_CheckExtendedKeyUsage( PKIX_PL_Cert *cert, PKIX_UInt32 requiredExtendedKeyUsages, PKIX_Boolean *pPass, void *plContext) { PKIX_PL_CertBasicConstraints *basicConstraints = NULL; PKIX_UInt32 certType = 0; PKIX_UInt32 requiredKeyUsage = 0; PKIX_UInt32 requiredCertType = 0; PKIX_UInt32 requiredExtendedKeyUsage = 0; PKIX_UInt32 i; PKIX_Boolean isCA = PKIX_FALSE; SECStatus rv = SECFailure; PKIX_ENTER(CERT, "pkix_pl_Cert_CheckExtendKeyUsage"); PKIX_NULLCHECK_THREE(cert, pPass, cert->nssCert); *pPass = PKIX_FALSE; PKIX_CERT_DEBUG("\t\tCalling cert_GetCertType).\n"); cert_GetCertType(cert->nssCert); certType = cert->nssCert->nsCertType; PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints (cert, &basicConstraints, plContext), PKIX_CERTGETBASICCONSTRAINTFAILED); if (basicConstraints != NULL) { PKIX_CHECK(PKIX_PL_BasicConstraints_GetCAFlag (basicConstraints, &isCA, plContext), PKIX_BASICCONSTRAINTSGETCAFLAGFAILED); } i = 0; while (requiredExtendedKeyUsages != 0) { /* Find the bit location of the right-most non-zero bit */ while (requiredExtendedKeyUsages != 0) { if (((1 << i) & requiredExtendedKeyUsages) != 0) { requiredExtendedKeyUsage = 1 << i; break; } i++; } requiredExtendedKeyUsages ^= requiredExtendedKeyUsage; requiredExtendedKeyUsage = i; PKIX_PL_NSSCALLRV(CERT, rv, CERT_KeyUsageAndTypeForCertUsage, (requiredExtendedKeyUsage, isCA, &requiredKeyUsage, &requiredCertType)); if (!(certType & requiredCertType)) { goto cleanup; } PKIX_PL_NSSCALLRV(CERT, rv, CERT_CheckKeyUsage, (cert->nssCert, requiredKeyUsage)); if (rv != SECSuccess) { goto cleanup; } i++; } *pPass = PKIX_TRUE; cleanup: PKIX_DECREF(basicConstraints); PKIX_RETURN(CERT); } /* * FUNCTION: pkix_pl_Cert_ToString_Helper * DESCRIPTION: * * Helper function that creates a string representation of the Cert pointed * to by "cert" and stores it at "pString", where the value of * "partialString" determines whether a full or partial representation of * the Cert is stored. * * PARAMETERS * "cert" * Address of Cert whose string representation is desired. * Must be non-NULL. * "partialString" * Boolean indicating whether a partial Cert representation is desired. * "pString" * Address where object pointer will be stored. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns a Cert Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_pl_Cert_ToString_Helper( PKIX_PL_Cert *cert, PKIX_Boolean partialString, PKIX_PL_String **pString, void *plContext) { PKIX_PL_String *certString = NULL; char *asciiFormat = NULL; PKIX_PL_String *formatString = NULL; PKIX_UInt32 certVersion; PKIX_PL_BigInt *certSN = NULL; PKIX_PL_String *certSNString = NULL; PKIX_PL_X500Name *certIssuer = NULL; PKIX_PL_String *certIssuerString = NULL; PKIX_PL_X500Name *certSubject = NULL; PKIX_PL_String *certSubjectString = NULL; PKIX_PL_String *notBeforeString = NULL; PKIX_PL_String *notAfterString = NULL; PKIX_List *subjAltNames = NULL; PKIX_PL_String *subjAltNamesString = NULL; PKIX_PL_ByteArray *authKeyId = NULL; PKIX_PL_String *authKeyIdString = NULL; PKIX_PL_ByteArray *subjKeyId = NULL; PKIX_PL_String *subjKeyIdString = NULL; PKIX_PL_PublicKey *nssPubKey = NULL; PKIX_PL_String *nssPubKeyString = NULL; PKIX_List *critExtOIDs = NULL; PKIX_PL_String *critExtOIDsString = NULL; PKIX_List *extKeyUsages = NULL; PKIX_PL_String *extKeyUsagesString = NULL; PKIX_PL_CertBasicConstraints *basicConstraint = NULL; PKIX_PL_String *certBasicConstraintsString = NULL; PKIX_List *policyInfo = NULL; PKIX_PL_String *certPolicyInfoString = NULL; PKIX_List *certPolicyMappings = NULL; PKIX_PL_String *certPolicyMappingsString = NULL; PKIX_Int32 certExplicitPolicy = 0; PKIX_Int32 certInhibitMapping = 0; PKIX_Int32 certInhibitAnyPolicy = 0; PKIX_PL_CertNameConstraints *nameConstraints = NULL; PKIX_PL_String *nameConstraintsString = NULL; PKIX_List *authorityInfoAccess = NULL; PKIX_PL_String *authorityInfoAccessString = NULL; PKIX_List *subjectInfoAccess = NULL; PKIX_PL_String *subjectInfoAccessString = NULL; PKIX_ENTER(CERT, "pkix_pl_Cert_ToString_Helper"); PKIX_NULLCHECK_THREE(cert, cert->nssCert, pString); /* * XXX Add to this format as certificate components are developed. */ if (partialString){ asciiFormat = "\t[Issuer: %s\n" "\t Subject: %s]"; } else { asciiFormat = "[\n" "\tVersion: v%d\n" "\tSerialNumber: %s\n" "\tIssuer: %s\n" "\tSubject: %s\n" "\tValidity: [From: %s\n" "\t To: %s]\n" "\tSubjectAltNames: %s\n" "\tAuthorityKeyId: %s\n" "\tSubjectKeyId: %s\n" "\tSubjPubKeyAlgId: %s\n" "\tCritExtOIDs: %s\n" "\tExtKeyUsages: %s\n" "\tBasicConstraint: %s\n" "\tCertPolicyInfo: %s\n" "\tPolicyMappings: %s\n" "\tExplicitPolicy: %d\n" "\tInhibitMapping: %d\n" "\tInhibitAnyPolicy:%d\n" "\tNameConstraints: %s\n" "\tAuthorityInfoAccess: %s\n" "\tSubjectInfoAccess: %s\n" "\tCacheFlag: %d\n" "]\n"; } PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext), PKIX_STRINGCREATEFAILED); /* Issuer */ PKIX_CHECK(PKIX_PL_Cert_GetIssuer (cert, &certIssuer, plContext), PKIX_CERTGETISSUERFAILED); PKIX_CHECK(PKIX_PL_Object_ToString ((PKIX_PL_Object *)certIssuer, &certIssuerString, plContext), PKIX_X500NAMETOSTRINGFAILED); /* Subject */ PKIX_CHECK(PKIX_PL_Cert_GetSubject(cert, &certSubject, plContext), PKIX_CERTGETSUBJECTFAILED); PKIX_TOSTRING(certSubject, &certSubjectString, plContext, PKIX_X500NAMETOSTRINGFAILED); if (partialString){ PKIX_CHECK(PKIX_PL_Sprintf (&certString, plContext, formatString, certIssuerString, certSubjectString), PKIX_SPRINTFFAILED); *pString = certString; goto cleanup; } /* Version */ PKIX_CHECK(PKIX_PL_Cert_GetVersion(cert, &certVersion, plContext), PKIX_CERTGETVERSIONFAILED); /* SerialNumber */ PKIX_CHECK(PKIX_PL_Cert_GetSerialNumber(cert, &certSN, plContext), PKIX_CERTGETSERIALNUMBERFAILED); PKIX_CHECK(PKIX_PL_Object_ToString ((PKIX_PL_Object *)certSN, &certSNString, plContext), PKIX_BIGINTTOSTRINGFAILED); /* Validity: NotBefore */ PKIX_CHECK(pkix_pl_Date_ToString_Helper (&(cert->nssCert->validity.notBefore), ¬BeforeString, plContext), PKIX_DATETOSTRINGHELPERFAILED); /* Validity: NotAfter */ PKIX_CHECK(pkix_pl_Date_ToString_Helper (&(cert->nssCert->validity.notAfter), ¬AfterString, plContext), PKIX_DATETOSTRINGHELPERFAILED); /* SubjectAltNames */ PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames (cert, &subjAltNames, plContext), PKIX_CERTGETSUBJECTALTNAMESFAILED); PKIX_TOSTRING(subjAltNames, &subjAltNamesString, plContext, PKIX_LISTTOSTRINGFAILED); /* AuthorityKeyIdentifier */ PKIX_CHECK(PKIX_PL_Cert_GetAuthorityKeyIdentifier (cert, &authKeyId, plContext), PKIX_CERTGETAUTHORITYKEYIDENTIFIERFAILED); PKIX_TOSTRING(authKeyId, &authKeyIdString, plContext, PKIX_BYTEARRAYTOSTRINGFAILED); /* SubjectKeyIdentifier */ PKIX_CHECK(PKIX_PL_Cert_GetSubjectKeyIdentifier (cert, &subjKeyId, plContext), PKIX_CERTGETSUBJECTKEYIDENTIFIERFAILED); PKIX_TOSTRING(subjKeyId, &subjKeyIdString, plContext, PKIX_BYTEARRAYTOSTRINGFAILED); /* SubjectPublicKey */ PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey (cert, &nssPubKey, plContext), PKIX_CERTGETSUBJECTPUBLICKEYFAILED); PKIX_CHECK(PKIX_PL_Object_ToString ((PKIX_PL_Object *)nssPubKey, &nssPubKeyString, plContext), PKIX_PUBLICKEYTOSTRINGFAILED); /* CriticalExtensionOIDs */ PKIX_CHECK(PKIX_PL_Cert_GetCriticalExtensionOIDs (cert, &critExtOIDs, plContext), PKIX_CERTGETCRITICALEXTENSIONOIDSFAILED); PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext, PKIX_LISTTOSTRINGFAILED); /* ExtendedKeyUsages */ PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage (cert, &extKeyUsages, plContext), PKIX_CERTGETEXTENDEDKEYUSAGEFAILED); PKIX_TOSTRING(extKeyUsages, &extKeyUsagesString, plContext, PKIX_LISTTOSTRINGFAILED); /* CertBasicConstraints */ PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints (cert, &basicConstraint, plContext), PKIX_CERTGETBASICCONSTRAINTSFAILED); PKIX_TOSTRING(basicConstraint, &certBasicConstraintsString, plContext, PKIX_CERTBASICCONSTRAINTSTOSTRINGFAILED); /* CertPolicyInfo */ PKIX_CHECK(PKIX_PL_Cert_GetPolicyInformation (cert, &policyInfo, plContext), PKIX_CERTGETPOLICYINFORMATIONFAILED); PKIX_TOSTRING(policyInfo, &certPolicyInfoString, plContext, PKIX_LISTTOSTRINGFAILED); /* Advanced Policies */ PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappings (cert, &certPolicyMappings, plContext), PKIX_CERTGETPOLICYMAPPINGSFAILED); PKIX_TOSTRING(certPolicyMappings, &certPolicyMappingsString, plContext, PKIX_LISTTOSTRINGFAILED); PKIX_CHECK(PKIX_PL_Cert_GetRequireExplicitPolicy (cert, &certExplicitPolicy, plContext), PKIX_CERTGETREQUIREEXPLICITPOLICYFAILED); PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappingInhibited (cert, &certInhibitMapping, plContext), PKIX_CERTGETPOLICYMAPPINGINHIBITEDFAILED); PKIX_CHECK(PKIX_PL_Cert_GetInhibitAnyPolicy (cert, &certInhibitAnyPolicy, plContext), PKIX_CERTGETINHIBITANYPOLICYFAILED); /* Name Constraints */ PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints (cert, &nameConstraints, plContext), PKIX_CERTGETNAMECONSTRAINTSFAILED); PKIX_TOSTRING(nameConstraints, &nameConstraintsString, plContext, PKIX_LISTTOSTRINGFAILED); /* Authority Information Access */ PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess (cert, &authorityInfoAccess, plContext), PKIX_CERTGETAUTHORITYINFOACCESSFAILED); PKIX_TOSTRING(authorityInfoAccess, &authorityInfoAccessString, plContext, PKIX_LISTTOSTRINGFAILED); /* Subject Information Access */ PKIX_CHECK(PKIX_PL_Cert_GetSubjectInfoAccess (cert, &subjectInfoAccess, plContext), PKIX_CERTGETSUBJECTINFOACCESSFAILED); PKIX_TOSTRING(subjectInfoAccess, &subjectInfoAccessString, plContext, PKIX_LISTTOSTRINGFAILED); PKIX_CHECK(PKIX_PL_Sprintf (&certString, plContext, formatString, certVersion + 1, certSNString, certIssuerString, certSubjectString, notBeforeString, notAfterString, subjAltNamesString, authKeyIdString, subjKeyIdString, nssPubKeyString, critExtOIDsString, extKeyUsagesString, certBasicConstraintsString, certPolicyInfoString, certPolicyMappingsString, certExplicitPolicy, /* an Int32, not a String */ certInhibitMapping, /* an Int32, not a String */ certInhibitAnyPolicy, /* an Int32, not a String */ nameConstraintsString, authorityInfoAccessString, subjectInfoAccessString, cert->cacheFlag), /* a boolean */ PKIX_SPRINTFFAILED); *pString = certString; cleanup: PKIX_DECREF(certSN); PKIX_DECREF(certSNString); PKIX_DECREF(certIssuer); PKIX_DECREF(certIssuerString); PKIX_DECREF(certSubject); PKIX_DECREF(certSubjectString); PKIX_DECREF(notBeforeString); PKIX_DECREF(notAfterString); PKIX_DECREF(subjAltNames); PKIX_DECREF(subjAltNamesString); PKIX_DECREF(authKeyId); PKIX_DECREF(authKeyIdString); PKIX_DECREF(subjKeyId); PKIX_DECREF(subjKeyIdString); PKIX_DECREF(nssPubKey); PKIX_DECREF(nssPubKeyString); PKIX_DECREF(critExtOIDs); PKIX_DECREF(critExtOIDsString); PKIX_DECREF(extKeyUsages); PKIX_DECREF(extKeyUsagesString); PKIX_DECREF(basicConstraint); PKIX_DECREF(certBasicConstraintsString); PKIX_DECREF(policyInfo); PKIX_DECREF(certPolicyInfoString); PKIX_DECREF(certPolicyMappings); PKIX_DECREF(certPolicyMappingsString); PKIX_DECREF(nameConstraints); PKIX_DECREF(nameConstraintsString); PKIX_DECREF(authorityInfoAccess); PKIX_DECREF(authorityInfoAccessString); PKIX_DECREF(subjectInfoAccess); PKIX_DECREF(subjectInfoAccessString); PKIX_DECREF(formatString); PKIX_RETURN(CERT); } /* * FUNCTION: pkix_pl_Cert_Destroy * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_Cert_Destroy( PKIX_PL_Object *object, void *plContext) { PKIX_PL_Cert *cert = NULL; PKIX_ENTER(CERT, "pkix_pl_Cert_Destroy"); PKIX_NULLCHECK_ONE(object); PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext), PKIX_OBJECTNOTCERT); cert = (PKIX_PL_Cert*)object; PKIX_DECREF(cert->subject); PKIX_DECREF(cert->issuer); PKIX_DECREF(cert->subjAltNames); PKIX_DECREF(cert->publicKeyAlgId); PKIX_DECREF(cert->publicKey); PKIX_DECREF(cert->serialNumber); PKIX_DECREF(cert->critExtOids); PKIX_DECREF(cert->authKeyId); PKIX_DECREF(cert->subjKeyId); PKIX_DECREF(cert->extKeyUsages); PKIX_DECREF(cert->certBasicConstraints); PKIX_DECREF(cert->certPolicyInfos); PKIX_DECREF(cert->certPolicyMappings); PKIX_DECREF(cert->nameConstraints); PKIX_DECREF(cert->store); PKIX_DECREF(cert->authorityInfoAccess); PKIX_DECREF(cert->subjectInfoAccess); 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; *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) { CERTCertificate *nssCert = NULL; PKIX_PL_OID *pubKeyAlgId = NULL; SECAlgorithmID algorithm; SECItem algBytes; char *asciiOID = 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){ nssCert = cert->nssCert; algorithm = nssCert->subjectPublicKeyInfo.algorithm; algBytes = algorithm.algorithm; PKIX_NULLCHECK_ONE(algBytes.data); if (algBytes.len == 0) { PKIX_ERROR_FATAL(PKIX_ALGORITHMBYTESLENGTH0); } PKIX_CHECK(pkix_pl_oidBytes2Ascii (&algBytes, &asciiOID, plContext), PKIX_OIDBYTES2ASCIIFAILED); PKIX_CHECK(PKIX_PL_OID_Create (asciiOID, &pubKeyAlgId, plContext), PKIX_OIDCREATEFAILED); /* save a cached copy in case it is asked for again */ cert->publicKeyAlgId = pubKeyAlgId; } PKIX_OBJECT_UNLOCK(cert); } PKIX_INCREF(cert->publicKeyAlgId); *pSubjKeyAlgId = cert->publicKeyAlgId; cleanup: PKIX_FREE(asciiOID); 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; char *oidAscii = NULL; SECItem **oids = NULL; SECItem *oid = 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){ oid = *oids++; PKIX_CHECK(pkix_pl_oidBytes2Ascii (oid, &oidAscii, plContext), PKIX_OIDBYTES2ASCIIFAILED); PKIX_CHECK(PKIX_PL_OID_Create (oidAscii, &pkixOID, plContext), PKIX_OIDCREATEFAILED); PKIX_CHECK(PKIX_List_AppendItem (oidsList, (PKIX_PL_Object *)pkixOID, plContext), PKIX_LISTAPPENDITEMFAILED); PKIX_FREE(oidAscii); PKIX_DECREF(pkixOID); } /* save a cached copy in case it is asked for again */ cert->extKeyUsages = oidsList; } PKIX_OBJECT_UNLOCK(cert); } if (cert->extKeyUsages){ PKIX_INCREF(cert->extKeyUsages); PKIX_CHECK(PKIX_List_SetImmutable (cert->extKeyUsages, plContext), PKIX_LISTSETIMMUTABLEFAILED); } *pKeyUsage = cert->extKeyUsages; cleanup: PKIX_OBJECT_UNLOCK(lockedObject); PKIX_FREE(oidAscii); PKIX_DECREF(pkixOID); CERT_DestroyOidSequence(extKeyUsage); if (PKIX_ERROR_RECEIVED){ PKIX_DECREF(oidsList); } 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; } PKIX_INCREF(cert->certPolicyInfos); *pPolicyInfo = cert->certPolicyInfos; cleanup: PKIX_OBJECT_UNLOCK(lockedObject); 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; } PKIX_INCREF(cert->certPolicyMappings); *pPolicyMappings = cert->certPolicyMappings; cleanup: PKIX_OBJECT_UNLOCK(lockedObject); 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_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_GetCertificateNames\n"); nssSubjectNames = CERT_GetCertificateNames (cert->nssCert, arena); 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 *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); /* 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_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_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); }