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