diff options
Diffstat (limited to 'security/nss/lib/libpkix/pkix_pl_nss/pki')
38 files changed, 14953 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/pki/Makefile new file mode 100644 index 0000000000..2b4b1574ab --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/Makefile @@ -0,0 +1,47 @@ +#! gmake +# +# 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/. + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp b/security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp new file mode 100644 index 0000000000..616f94fd46 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp @@ -0,0 +1,41 @@ +# 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/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'lib_libpkix_pkix_pl_nss_pki_exports', + 'type': 'none', + 'copies': [ + { + 'files': [ + 'pkix_pl_basicconstraints.h', + 'pkix_pl_cert.h', + 'pkix_pl_certpolicyinfo.h', + 'pkix_pl_certpolicymap.h', + 'pkix_pl_certpolicyqualifier.h', + 'pkix_pl_crl.h', + 'pkix_pl_crldp.h', + 'pkix_pl_crlentry.h', + 'pkix_pl_date.h', + 'pkix_pl_generalname.h', + 'pkix_pl_infoaccess.h', + 'pkix_pl_nameconstraints.h', + 'pkix_pl_ocspcertid.h', + 'pkix_pl_ocsprequest.h', + 'pkix_pl_ocspresponse.h', + 'pkix_pl_publickey.h', + 'pkix_pl_x500name.h' + ], + 'destination': '<(nss_private_dist_dir)/<(module)' + } + ] + } + ], + 'variables': { + 'module': 'nss' + } +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn new file mode 100644 index 0000000000..aba1367e56 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn @@ -0,0 +1,50 @@ +# +# 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/. +CORE_DEPTH = ../../../.. + +PRIVATE_EXPORTS = \ + pkix_pl_basicconstraints.h \ + pkix_pl_cert.h \ + pkix_pl_certpolicyinfo.h \ + pkix_pl_certpolicymap.h \ + pkix_pl_certpolicyqualifier.h \ + pkix_pl_crl.h \ + pkix_pl_crldp.h \ + pkix_pl_crlentry.h \ + pkix_pl_date.h \ + pkix_pl_generalname.h \ + pkix_pl_infoaccess.h \ + pkix_pl_nameconstraints.h \ + pkix_pl_ocsprequest.h \ + pkix_pl_ocspresponse.h \ + pkix_pl_publickey.h \ + pkix_pl_x500name.h \ + pkix_pl_ocspcertid.h \ + $(NULL) + +MODULE = nss + +CSRCS = \ + pkix_pl_basicconstraints.c \ + pkix_pl_cert.c \ + pkix_pl_certpolicyinfo.c \ + pkix_pl_certpolicymap.c \ + pkix_pl_certpolicyqualifier.c \ + pkix_pl_crl.c \ + pkix_pl_crldp.c \ + pkix_pl_crlentry.c \ + pkix_pl_date.c \ + pkix_pl_generalname.c \ + pkix_pl_infoaccess.c \ + pkix_pl_nameconstraints.c \ + pkix_pl_ocsprequest.c \ + pkix_pl_ocspresponse.c \ + pkix_pl_publickey.c \ + pkix_pl_x500name.c \ + pkix_pl_ocspcertid.c \ + $(NULL) + +LIBRARY_NAME = pkixpki +SHARED_LIBRARY = $(NULL) diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp b/security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp new file mode 100644 index 0000000000..af7730c0bf --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp @@ -0,0 +1,39 @@ +# 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/. +{ + 'includes': [ + '../../../../coreconf/config.gypi' + ], + 'targets': [ + { + 'target_name': 'pkixpki', + 'type': 'static_library', + 'sources': [ + 'pkix_pl_basicconstraints.c', + 'pkix_pl_cert.c', + 'pkix_pl_certpolicyinfo.c', + 'pkix_pl_certpolicymap.c', + 'pkix_pl_certpolicyqualifier.c', + 'pkix_pl_crl.c', + 'pkix_pl_crldp.c', + 'pkix_pl_crlentry.c', + 'pkix_pl_date.c', + 'pkix_pl_generalname.c', + 'pkix_pl_infoaccess.c', + 'pkix_pl_nameconstraints.c', + 'pkix_pl_ocspcertid.c', + 'pkix_pl_ocsprequest.c', + 'pkix_pl_ocspresponse.c', + 'pkix_pl_publickey.c', + 'pkix_pl_x500name.c' + ], + 'dependencies': [ + '<(DEPTH)/exports.gyp:nss_exports' + ] + } + ], + 'variables': { + 'module': 'nss' + } +}
\ No newline at end of file diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c new file mode 100644 index 0000000000..81615da37a --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c @@ -0,0 +1,407 @@ +/* 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_basicconstraints.c + * + * BasicConstraints Object Functions + * + */ + +#include "pkix_pl_basicconstraints.h" + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_Create + * DESCRIPTION: + * + * Creates a new CertBasicConstraints object whose CA Flag has the value + * given by the Boolean value of "isCA" and whose path length field has the + * value given by the "pathLen" argument and stores it at "pObject". + * + * PARAMETERS + * "isCA" + * Boolean value with the desired value of CA Flag. + * "pathLen" + * a PKIX_Int32 with the desired value of path length + * "pObject" + * Address of object pointer's destination. 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 CertBasicConstraints 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_CertBasicConstraints_Create( + PKIX_Boolean isCA, + PKIX_Int32 pathLen, + PKIX_PL_CertBasicConstraints **pObject, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *basic = NULL; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_Create"); + PKIX_NULLCHECK_ONE(pObject); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTBASICCONSTRAINTS_TYPE, + sizeof (PKIX_PL_CertBasicConstraints), + (PKIX_PL_Object **)&basic, + plContext), + PKIX_COULDNOTCREATECERTBASICCONSTRAINTSOBJECT); + + basic->isCA = isCA; + + /* pathLen has meaning only for CAs, but it's not worth checking */ + basic->pathLen = pathLen; + + *pObject = basic; + +cleanup: + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertBasicConstraints_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *certB = NULL; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTBASICCONSTRAINTS); + + certB = (PKIX_PL_CertBasicConstraints*)object; + + certB->isCA = PKIX_FALSE; + certB->pathLen = 0; + +cleanup: + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertBasicConstraints_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *certBasicConstraintsString = NULL; + PKIX_PL_CertBasicConstraints *certB = NULL; + PKIX_Boolean isCA = PKIX_FALSE; + PKIX_Int32 pathLen = 0; + PKIX_PL_String *outString = NULL; + char *fmtString = NULL; + PKIX_Boolean pathlenArg = PKIX_FALSE; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext), + PKIX_FIRSTARGUMENTNOTCERTBASICCONSTRAINTSOBJECT); + + certB = (PKIX_PL_CertBasicConstraints *)object; + + /* + * if CA == TRUE + * if pathLen == CERT_UNLIMITED_PATH_CONSTRAINT + * print "CA(-1)" + * else print "CA(nnn)" + * if CA == FALSE, print "~CA" + */ + + isCA = certB->isCA; + + if (isCA) { + pathLen = certB->pathLen; + + if (pathLen == CERT_UNLIMITED_PATH_CONSTRAINT) { + /* print "CA(-1)" */ + fmtString = "CA(-1)"; + pathlenArg = PKIX_FALSE; + } else { + /* print "CA(pathLen)" */ + fmtString = "CA(%d)"; + pathlenArg = PKIX_TRUE; + } + } else { + /* print "~CA" */ + fmtString = "~CA"; + pathlenArg = PKIX_FALSE; + } + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + fmtString, + 0, + &certBasicConstraintsString, + plContext), + PKIX_STRINGCREATEFAILED); + + if (pathlenArg) { + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, + plContext, + certBasicConstraintsString, + pathLen), + PKIX_SPRINTFFAILED); + } else { + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, + plContext, + certBasicConstraintsString), + PKIX_SPRINTFFAILED); + } + + *pString = outString; + +cleanup: + + PKIX_DECREF(certBasicConstraintsString); + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertBasicConstraints_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *certB = NULL; + PKIX_Boolean isCA = PKIX_FALSE; + PKIX_Int32 pathLen = 0; + PKIX_Int32 hashInput = 0; + PKIX_UInt32 cbcHash = 0; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTBASICCONSTRAINTS); + + certB = (PKIX_PL_CertBasicConstraints *)object; + + /* + * if CA == TRUE + * hash(pathLen + 1 - PKIX_UNLIMITED_PATH_CONSTRAINT) + * if CA == FALSE, hash(0) + */ + + isCA = certB->isCA; + + if (isCA) { + pathLen = certB->pathLen; + + hashInput = pathLen + 1 - PKIX_UNLIMITED_PATH_CONSTRAINT; + } + + PKIX_CHECK(pkix_hash + ((const unsigned char *)&hashInput, + sizeof (hashInput), + &cbcHash, + plContext), + PKIX_HASHFAILED); + + *pHashcode = cbcHash; + +cleanup: + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertBasicConstraints_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertBasicConstraints *firstCBC = NULL; + PKIX_PL_CertBasicConstraints *secondCBC = NULL; + PKIX_UInt32 secondType; + PKIX_Boolean firstIsCA = PKIX_FALSE; + PKIX_Boolean secondIsCA = PKIX_FALSE; + PKIX_Int32 firstPathLen = 0; + PKIX_Int32 secondPathLen = 0; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertBasicConstraints */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTBASICCONSTRAINTS); + + /* + * Since we know firstObject is a CertBasicConstraints, + * if both references are identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a CertBasicConstraints, we + * don't throw an error. We simply return FALSE. + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CERTBASICCONSTRAINTS_TYPE) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + firstCBC = (PKIX_PL_CertBasicConstraints *)firstObject; + secondCBC = (PKIX_PL_CertBasicConstraints *)secondObject; + + /* + * Compare the value of the CAFlag components + */ + + firstIsCA = firstCBC->isCA; + + /* + * Failure here would be an error, not merely a miscompare, + * since we know second is a CertBasicConstraints. + */ + secondIsCA = secondCBC->isCA; + + /* + * If isCA flags differ, the objects are not equal. + */ + if (secondIsCA != firstIsCA) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + /* + * If isCA was FALSE, the objects are equal, because + * pathLen is meaningless in that case. + */ + if (!firstIsCA) { + *pResult = PKIX_TRUE; + goto cleanup; + } + + firstPathLen = firstCBC->pathLen; + secondPathLen = secondCBC->pathLen; + + *pResult = (secondPathLen == firstPathLen); + +cleanup: + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertBasicConstraints_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTBASICCONSTRAINTS_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_CertBasicConstraints_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTBASICCONSTRAINTS, + "pkix_pl_CertBasicConstraints_RegisterSelf"); + + entry.description = "CertBasicConstraints"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertBasicConstraints); + entry.destructor = pkix_pl_CertBasicConstraints_Destroy; + entry.equalsFunction = pkix_pl_CertBasicConstraints_Equals; + entry.hashcodeFunction = pkix_pl_CertBasicConstraints_Hashcode; + entry.toStringFunction = pkix_pl_CertBasicConstraints_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CERTBASICCONSTRAINTS_TYPE] = entry; + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_BasicConstraints_GetCAFlag + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_BasicConstraints_GetCAFlag( + PKIX_PL_CertBasicConstraints *basicConstraints, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_ENTER(CERTBASICCONSTRAINTS, + "PKIX_PL_BasicConstraintsGetCAFlag"); + PKIX_NULLCHECK_TWO(basicConstraints, pResult); + + *pResult = basicConstraints->isCA; + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} + +/* + * FUNCTION: PKIX_PL_BasicConstraints_GetPathLenConstraint + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_BasicConstraints_GetPathLenConstraint( + PKIX_PL_CertBasicConstraints *basicConstraints, + PKIX_Int32 *pPathLenConstraint, + void *plContext) +{ + PKIX_ENTER(CERTBASICCONSTRAINTS, + "PKIX_PL_BasicConstraintsGetPathLenConstraint"); + PKIX_NULLCHECK_TWO(basicConstraints, pPathLenConstraint); + + *pPathLenConstraint = basicConstraints->pathLen; + + PKIX_RETURN(CERTBASICCONSTRAINTS); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h new file mode 100644 index 0000000000..857529c95c --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h @@ -0,0 +1,47 @@ +/* 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_basicconstraints.h + * + * BasicConstraints Object Definitions + * + */ + +#ifndef _PKIX_PL_BASICCONSTRAINTS_H +#define _PKIX_PL_BASICCONSTRAINTS_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This structure reflects the contents of the basic constraints + * extension as described in Section 4.2.1.10 of RFC 3280. + * The cA flag indicates whether the public key in this certificate + * belongs to a certification authority. The pathLen constraint + * gives the maximum number of non-self-issued intermediate certificates + * that may follow this certificate in a valid certification path. + */ +struct PKIX_PL_CertBasicConstraintsStruct { + PKIX_Boolean isCA; + PKIX_Int32 pathLen; +}; + +PKIX_Error * +pkix_pl_CertBasicConstraints_Create( + PKIX_Boolean isCA, + PKIX_Int32 pathLen, + PKIX_PL_CertBasicConstraints **object, + void *plContext); + +PKIX_Error * +pkix_pl_CertBasicConstraints_RegisterSelf( + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_BASICCONSTRAINTS_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c new file mode 100644 index 0000000000..9dddd2e40f --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c @@ -0,0 +1,3734 @@ +/* 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; + PKIX_Error *checkSig = NULL; + SECStatus status; + PKIX_Boolean certEqual = PKIX_FALSE; + PKIX_Boolean certInHash = PKIX_FALSE; + PKIX_Boolean checkCertSig = PKIX_TRUE; + void* wincx = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifySignature"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pubKey); + + /* if the cert check flag is off, skip the check */ + checkSig = pkix_pl_NssContext_GetCertSignatureCheck( + (PKIX_PL_NssContext *)plContext, &checkCertSig); + if ((checkCertSig == PKIX_FALSE) && (checkSig == NULL)) { + goto cleanup; + } + + 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(checkSig); + 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 (!(certType & requiredCertType)) { + PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED); + } +cleanup: + PKIX_DECREF(basicConstraints); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_VerifyKeyUsage (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_VerifyKeyUsage( + PKIX_PL_Cert *cert, + PKIX_UInt32 keyUsage, + void *plContext) +{ + CERTCertificate *nssCert = NULL; + PKIX_UInt32 nssKeyUsage = 0; + SECStatus status; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifyKeyUsage"); + PKIX_NULLCHECK_TWO(cert, cert->nssCert); + + nssCert = cert->nssCert; + + /* if cert doesn't have keyUsage extension, all keyUsages are valid */ + if (!nssCert->keyUsagePresent){ + goto cleanup; + } + + if (keyUsage & PKIX_DIGITAL_SIGNATURE){ + nssKeyUsage = nssKeyUsage | KU_DIGITAL_SIGNATURE; + } + + if (keyUsage & PKIX_NON_REPUDIATION){ + nssKeyUsage = nssKeyUsage | KU_NON_REPUDIATION; + } + + if (keyUsage & PKIX_KEY_ENCIPHERMENT){ + nssKeyUsage = nssKeyUsage | KU_KEY_ENCIPHERMENT; + } + + if (keyUsage & PKIX_DATA_ENCIPHERMENT){ + nssKeyUsage = nssKeyUsage | KU_DATA_ENCIPHERMENT; + } + + if (keyUsage & PKIX_KEY_AGREEMENT){ + nssKeyUsage = nssKeyUsage | KU_KEY_AGREEMENT; + } + + if (keyUsage & PKIX_KEY_CERT_SIGN){ + nssKeyUsage = nssKeyUsage | KU_KEY_CERT_SIGN; + } + + if (keyUsage & PKIX_CRL_SIGN){ + nssKeyUsage = nssKeyUsage | KU_CRL_SIGN; + } + + if (keyUsage & PKIX_ENCIPHER_ONLY){ + nssKeyUsage = nssKeyUsage | 0x01; + } + + if (keyUsage & PKIX_DECIPHER_ONLY){ + /* XXX we should support this once it is fixed in NSS */ + PKIX_ERROR(PKIX_DECIPHERONLYKEYUSAGENOTSUPPORTED); + } + + status = CERT_CheckKeyUsage(nssCert, nssKeyUsage); + if (status != SECSuccess) { + PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED); + } + +cleanup: + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_GetNameConstraints + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_GetNameConstraints( + PKIX_PL_Cert *cert, + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_GetNameConstraints"); + PKIX_NULLCHECK_THREE(cert, cert->nssCert, pNameConstraints); + + /* if we don't have a cached copy from before, we create one */ + if (cert->nameConstraints == NULL && !cert->nameConstraintsAbsent) { + + PKIX_OBJECT_LOCK(cert); + + if (cert->nameConstraints == NULL && + !cert->nameConstraintsAbsent) { + + PKIX_CHECK(pkix_pl_CertNameConstraints_Create + (cert->nssCert, &nameConstraints, plContext), + PKIX_CERTNAMECONSTRAINTSCREATEFAILED); + + if (nameConstraints == NULL) { + cert->nameConstraintsAbsent = PKIX_TRUE; + } + + cert->nameConstraints = nameConstraints; + } + + PKIX_OBJECT_UNLOCK(cert); + + } + + PKIX_INCREF(cert->nameConstraints); + + *pNameConstraints = cert->nameConstraints; + +cleanup: + PKIX_OBJECT_UNLOCK(lockedObject); + PKIX_RETURN(CERT); +} + +/* + * FUNCTION: PKIX_PL_Cert_CheckNameConstraints + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Cert_CheckNameConstraints( + PKIX_PL_Cert *cert, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean treatCommonNameAsDNSName, + void *plContext) +{ + PKIX_Boolean checkPass = PKIX_TRUE; + CERTGeneralName *nssSubjectNames = NULL; + PLArenaPool *arena = NULL; + + PKIX_ENTER(CERT, "PKIX_PL_Cert_CheckNameConstraints"); + PKIX_NULLCHECK_ONE(cert); + + if (nameConstraints != NULL) { + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + /* only check common Name if the usage requires it */ + if (treatCommonNameAsDNSName) { + SECCertificateUsage certificateUsage; + certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage; + if ((certificateUsage != certificateUsageSSLServer) && + (certificateUsage != certificateUsageIPsec)) { + treatCommonNameAsDNSName = PKIX_FALSE; + } + } + + /* 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); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h new file mode 100644 index 0000000000..56fe64228d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h @@ -0,0 +1,107 @@ +/* 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.h + * + * Certificate Object Definitions + * + */ + +#ifndef _PKIX_PL_CERT_H +#define _PKIX_PL_CERT_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_CertStruct { + CERTCertificate *nssCert; /* Must be the first field. The + * cert_NSSCertFromPKIXCert function in + * lib/certhigh/certvfypkix.c depends on + * this. */ + CERTGeneralName *nssSubjAltNames; + PLArenaPool *arenaNameConstraints; + PKIX_PL_X500Name *issuer; + PKIX_PL_X500Name *subject; + PKIX_List *subjAltNames; + PKIX_Boolean subjAltNamesAbsent; + PKIX_PL_OID *publicKeyAlgId; + PKIX_PL_PublicKey *publicKey; + PKIX_PL_BigInt *serialNumber; + PKIX_List *critExtOids; + PKIX_PL_ByteArray *subjKeyId; + PKIX_Boolean subjKeyIdAbsent; + PKIX_PL_ByteArray *authKeyId; + PKIX_Boolean authKeyIdAbsent; + PKIX_List *extKeyUsages; + PKIX_Boolean extKeyUsagesAbsent; + PKIX_PL_CertBasicConstraints *certBasicConstraints; + PKIX_Boolean basicConstraintsAbsent; + PKIX_List *certPolicyInfos; + PKIX_Boolean policyInfoAbsent; + PKIX_Boolean policyMappingsAbsent; + PKIX_List *certPolicyMappings; /* List of PKIX_PL_CertPolicyMap */ + PKIX_Boolean policyConstraintsProcessed; + PKIX_Int32 policyConstraintsExplicitPolicySkipCerts; + PKIX_Int32 policyConstraintsInhibitMappingSkipCerts; + PKIX_Boolean inhibitAnyPolicyProcessed; + PKIX_Int32 inhibitAnySkipCerts; + PKIX_PL_CertNameConstraints *nameConstraints; + PKIX_Boolean nameConstraintsAbsent; + PKIX_Boolean cacheFlag; + PKIX_CertStore *store; + PKIX_List *authorityInfoAccess; /* list of PKIX_PL_InfoAccess */ + PKIX_List *subjectInfoAccess; /* list of PKIX_PL_InfoAccess */ + PKIX_Boolean isUserTrustAnchor; + PKIX_List *crldpList; /* list of CRL DPs based on der in nssCert arena. + * Destruction is needed for pkix object and + * not for undelying der as it is a part + * nssCert arena. */ +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_Cert_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_Cert_CreateWithNSSCert( + CERTCertificate *nssCert, + PKIX_PL_Cert **pCert, + void *plContext); + +PKIX_Error * +pkix_pl_Cert_CreateToList( + SECItem *derCertItem, + PKIX_List *certList, + void *plContext); + +PKIX_Error * +pkix_pl_Cert_CheckSubjectAltNameConstraints( + PKIX_PL_Cert *cert, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean matchAll, + void *plContext); + +PKIX_Error * +pkix_pl_Cert_ToString_Helper( + PKIX_PL_Cert *cert, + PKIX_Boolean partialString, + PKIX_PL_String **pString, + void *plContext); + +PKIX_Error * +pkix_pl_Cert_CheckExtendedKeyUsage( + PKIX_PL_Cert *cert, + PKIX_UInt32 requiredExtendedKeyUsages, + PKIX_Boolean *pPass, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CERT_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c new file mode 100644 index 0000000000..a44ac65900 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c @@ -0,0 +1,371 @@ +/* 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_certpolicyinfo.c + * + * CertPolicyInfo Type Functions + * + */ + +#include "pkix_pl_certpolicyinfo.h" + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_Create + * DESCRIPTION: + * + * Creates a new CertPolicyInfo Object using the OID pointed to by "oid" and + * the List of CertPolicyQualifiers pointed to by "qualifiers", and stores it + * at "pObject". If a non-NULL list is provided, the caller is expected to + * have already set it to be immutable. The caller may provide an empty List, + * but a NULL List is preferable so a user does not need to call + * List_GetLength to get the number of qualifiers. + * + * PARAMETERS + * "oid" + * OID of the desired PolicyInfo ID; must be non-NULL + * "qualifiers" + * List of CertPolicyQualifiers; may be NULL or empty + * "pObject" + * 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 Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_CertPolicyInfo_Create( + PKIX_PL_OID *oid, + PKIX_List *qualifiers, + PKIX_PL_CertPolicyInfo **pObject, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *policyInfo = NULL; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Create"); + + PKIX_NULLCHECK_TWO(oid, pObject); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTPOLICYINFO_TYPE, + sizeof (PKIX_PL_CertPolicyInfo), + (PKIX_PL_Object **)&policyInfo, + plContext), + PKIX_COULDNOTCREATECERTPOLICYINFOOBJECT); + + PKIX_INCREF(oid); + policyInfo->cpID = oid; + + PKIX_INCREF(qualifiers); + policyInfo->policyQualifiers = qualifiers; + + *pObject = policyInfo; + policyInfo = NULL; + +cleanup: + PKIX_DECREF(policyInfo); + + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyInfo_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *certPI = NULL; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYINFO_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYINFO); + + certPI = (PKIX_PL_CertPolicyInfo*)object; + + PKIX_DECREF(certPI->cpID); + PKIX_DECREF(certPI->policyQualifiers); + +cleanup: + + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyInfo_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *certPI = NULL; + PKIX_PL_String *oidString = NULL; + PKIX_PL_String *listString = NULL; + PKIX_PL_String *format = NULL; + PKIX_PL_String *outString = NULL; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_ToString"); + + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYINFO_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYINFO); + + certPI = (PKIX_PL_CertPolicyInfo *)object; + + PKIX_NULLCHECK_ONE(certPI->cpID); + + PKIX_TOSTRING + (certPI->cpID, + &oidString, + plContext, + PKIX_OIDTOSTRINGFAILED); + + PKIX_TOSTRING + (certPI->policyQualifiers, + &listString, + plContext, + PKIX_LISTTOSTRINGFAILED); + + /* Put them together in the form OID[Qualifiers] */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "%s[%s]", 0, &format, plContext), + PKIX_ERRORINSTRINGCREATE); + + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, plContext, format, oidString, listString), + PKIX_ERRORINSPRINTF); + + *pString = outString; + +cleanup: + + PKIX_DECREF(oidString); + PKIX_DECREF(listString); + PKIX_DECREF(format); + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyInfo_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *certPI = NULL; + PKIX_UInt32 oidHash = 0; + PKIX_UInt32 listHash = 0; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Hashcode"); + + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYINFO_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYINFO); + + certPI = (PKIX_PL_CertPolicyInfo *)object; + + PKIX_NULLCHECK_ONE(certPI->cpID); + + PKIX_HASHCODE + (certPI->cpID, + &oidHash, + plContext, + PKIX_ERRORINOIDHASHCODE); + + PKIX_HASHCODE + (certPI->policyQualifiers, + &listHash, + plContext, + PKIX_ERRORINLISTHASHCODE); + + *pHashcode = (31 * oidHash) + listHash; + +cleanup: + + PKIX_RETURN(CERTPOLICYINFO); +} + + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyInfo_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertPolicyInfo *firstCPI = NULL; + PKIX_PL_CertPolicyInfo *secondCPI = NULL; + PKIX_UInt32 secondType = 0; + PKIX_Boolean compare = PKIX_FALSE; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertPolicyInfo */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTPOLICYINFO_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTPOLICYINFO); + + /* + * Since we know firstObject is a CertPolicyInfo, + * if both references are identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a CertPolicyInfo, we + * don't throw an error. We simply return FALSE. + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CERTPOLICYINFO_TYPE) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + firstCPI = (PKIX_PL_CertPolicyInfo *)firstObject; + secondCPI = (PKIX_PL_CertPolicyInfo *)secondObject; + + /* + * Compare the value of the OID components + */ + + PKIX_NULLCHECK_TWO(firstCPI->cpID, secondCPI->cpID); + + PKIX_EQUALS + (firstCPI->cpID, + secondCPI->cpID, + &compare, + plContext, + PKIX_OIDEQUALSFAILED); + + /* + * If the OIDs did not match, we don't need to + * compare the Lists. If the OIDs did match, + * the return value is the value of the + * List comparison. + */ + if (compare) { + PKIX_EQUALS + (firstCPI->policyQualifiers, + secondCPI->policyQualifiers, + &compare, + plContext, + PKIX_LISTEQUALSFAILED); + } + + *pResult = compare; + +cleanup: + + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: pkix_pl_CertPolicyInfo_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTPOLICYINFO_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_CertPolicyInfo_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_RegisterSelf"); + + entry.description = "CertPolicyInfo"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertPolicyInfo); + entry.destructor = pkix_pl_CertPolicyInfo_Destroy; + entry.equalsFunction = pkix_pl_CertPolicyInfo_Equals; + entry.hashcodeFunction = pkix_pl_CertPolicyInfo_Hashcode; + entry.toStringFunction = pkix_pl_CertPolicyInfo_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CERTPOLICYINFO_TYPE] = entry; + + PKIX_RETURN(CERTPOLICYINFO); +} + +/* --Public-CertPolicyInfo-Functions------------------------- */ + +/* + * FUNCTION: PKIX_PL_CertPolicyInfo_GetPolicyId + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CertPolicyInfo_GetPolicyId( + PKIX_PL_CertPolicyInfo *policyInfo, + PKIX_PL_OID **pPolicyId, + void *plContext) +{ + PKIX_ENTER(CERTPOLICYINFO, "PKIX_PL_CertPolicyInfo_GetPolicyId"); + + PKIX_NULLCHECK_TWO(policyInfo, pPolicyId); + + PKIX_INCREF(policyInfo->cpID); + + *pPolicyId = policyInfo->cpID; + +cleanup: + PKIX_RETURN(CERTPOLICYINFO); +} + +/* + * FUNCTION: PKIX_PL_CertPolicyInfo_GetPolQualifiers + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CertPolicyInfo_GetPolQualifiers( + PKIX_PL_CertPolicyInfo *policyInfo, + PKIX_List **pQuals, + void *plContext) +{ + PKIX_ENTER(CERTPOLICYINFO, "PKIX_PL_CertPolicyInfo_GetPolQualifiers"); + + PKIX_NULLCHECK_TWO(policyInfo, pQuals); + + PKIX_INCREF(policyInfo->policyQualifiers); + + /* + * This List is created in PKIX_PL_Cert_DecodePolicyInfo + * and is set immutable immediately after being created. + */ + *pQuals = policyInfo->policyQualifiers; + +cleanup: + PKIX_RETURN(CERTPOLICYINFO); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h new file mode 100644 index 0000000000..5c324e6cd2 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h @@ -0,0 +1,50 @@ +/* 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_certpolicyinfo.h + * + * PolicyInfo Type Definitions + * + */ + +#ifndef _PKIX_PL_POLICYINFO_H +#define _PKIX_PL_POLICYINFO_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure reflects the contents of the policy info extension as + * described in Section 4.2.1.5 of RFC3280. + * + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * PolicyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + * + */ +struct PKIX_PL_CertPolicyInfoStruct { + PKIX_PL_OID *cpID; + PKIX_List *policyQualifiers; /* LIST of PKIX_PL_CertPolicyQualifier */ +}; + +PKIX_Error * +pkix_pl_CertPolicyInfo_Create( + PKIX_PL_OID *oid, + PKIX_List *qualifiers, + PKIX_PL_CertPolicyInfo **pObject, + void *plContext); + +PKIX_Error * +pkix_pl_CertPolicyInfo_RegisterSelf( + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_POLICYINFO_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c new file mode 100644 index 0000000000..08b1ca9df1 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c @@ -0,0 +1,386 @@ +/* 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_certpolicymap.c + * + * CertPolicyMap Type Functions + * + */ + +#include "pkix_pl_certpolicymap.h" + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Create + * DESCRIPTION: + * + * Creates a new CertPolicyMap Object pairing the OID given by + * "issuerDomainPolicy" with the OID given by "subjectDomainPolicy", and + * stores the result at "pCertPolicyMap". + * + * PARAMETERS + * "issuerDomainPolicy" + * Address of the OID of the IssuerDomainPolicy. Must be non-NULL. + * "subjectDomainPolicy" + * Address of the OID of the SubjectDomainPolicy. Must be non-NULL. + * "pCertPolicyMap" + * Address where CertPolicyMap 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 CertPolicyMap 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_CertPolicyMap_Create( + PKIX_PL_OID *issuerDomainPolicy, + PKIX_PL_OID *subjectDomainPolicy, + PKIX_PL_CertPolicyMap **pCertPolicyMap, + void *plContext) +{ + PKIX_PL_CertPolicyMap *policyMap = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Create"); + + PKIX_NULLCHECK_THREE + (issuerDomainPolicy, subjectDomainPolicy, pCertPolicyMap); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTPOLICYMAP_TYPE, + sizeof (PKIX_PL_CertPolicyMap), + (PKIX_PL_Object **)&policyMap, + plContext), + PKIX_COULDNOTCREATECERTPOLICYMAPOBJECT); + + PKIX_INCREF(issuerDomainPolicy); + policyMap->issuerDomainPolicy = issuerDomainPolicy; + + PKIX_INCREF(subjectDomainPolicy); + policyMap->subjectDomainPolicy = subjectDomainPolicy; + + *pCertPolicyMap = policyMap; + policyMap = NULL; + +cleanup: + PKIX_DECREF(policyMap); + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertPolicyMap *certMap = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYMAP); + + certMap = (PKIX_PL_CertPolicyMap*)object; + + PKIX_DECREF(certMap->issuerDomainPolicy); + PKIX_DECREF(certMap->subjectDomainPolicy); + +cleanup: + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_CertPolicyMap *certMap = NULL; + PKIX_PL_String *format = NULL; + PKIX_PL_String *outString = NULL; + PKIX_PL_String *issuerString = NULL; + PKIX_PL_String *subjectString = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_ToString"); + + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYMAP); + + certMap = (PKIX_PL_CertPolicyMap *)object; + + PKIX_TOSTRING + (certMap->issuerDomainPolicy, + &issuerString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + PKIX_TOSTRING + (certMap->subjectDomainPolicy, + &subjectString, + plContext, + PKIX_OBJECTTOSTRINGFAILED); + + /* Put them together in the form issuerPolicy=>subjectPolicy */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "%s=>%s", 0, &format, plContext), + PKIX_ERRORINSTRINGCREATE); + + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, plContext, format, issuerString, subjectString), + PKIX_ERRORINSPRINTF); + + *pString = outString; + +cleanup: + PKIX_DECREF(format); + PKIX_DECREF(issuerString); + PKIX_DECREF(subjectString); + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_UInt32 issuerHash = 0; + PKIX_UInt32 subjectHash = 0; + PKIX_PL_CertPolicyMap *certMap = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Hashcode"); + + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYMAP); + + certMap = (PKIX_PL_CertPolicyMap *)object; + + PKIX_HASHCODE + (certMap->issuerDomainPolicy, + &issuerHash, + plContext, + PKIX_OBJECTHASHCODEFAILED); + + PKIX_HASHCODE + (certMap->subjectDomainPolicy, + &subjectHash, + plContext, + PKIX_OBJECTHASHCODEFAILED); + + *pHashcode = issuerHash*31 + subjectHash; + +cleanup: + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertPolicyMap *firstCertMap = NULL; + PKIX_PL_CertPolicyMap *secondCertMap = NULL; + PKIX_UInt32 secondType = 0; + PKIX_Boolean compare = PKIX_FALSE; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertPolicyMap */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTPOLICYMAP); + + /* + * Since we know firstObject is a CertPolicyMap, + * if both references are identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a CertPolicyMap, we + * don't throw an error. We simply return FALSE. + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CERTPOLICYMAP_TYPE) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + firstCertMap = (PKIX_PL_CertPolicyMap *)firstObject; + secondCertMap = (PKIX_PL_CertPolicyMap *)secondObject; + + PKIX_EQUALS + (firstCertMap->issuerDomainPolicy, + secondCertMap->issuerDomainPolicy, + &compare, + plContext, + PKIX_OBJECTEQUALSFAILED); + + if (compare) { + PKIX_EQUALS + (firstCertMap->subjectDomainPolicy, + secondCertMap->subjectDomainPolicy, + &compare, + plContext, + PKIX_OBJECTEQUALSFAILED); + } + + *pResult = compare; + +cleanup: + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_Duplicate + * (see comments for PKIX_PL_Duplicate_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyMap_Duplicate( + PKIX_PL_Object *object, + PKIX_PL_Object **pNewObject, + void *plContext) +{ + PKIX_PL_CertPolicyMap *original = NULL; + PKIX_PL_CertPolicyMap *copy = NULL; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Duplicate"); + + PKIX_NULLCHECK_TWO(object, pNewObject); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYMAP_TYPE, plContext), + PKIX_OBJECTARGUMENTNOTPOLICYMAP); + + original = (PKIX_PL_CertPolicyMap *)object; + + PKIX_CHECK(pkix_pl_CertPolicyMap_Create + (original->issuerDomainPolicy, + original->subjectDomainPolicy, + ©, + plContext), + PKIX_CERTPOLICYMAPCREATEFAILED); + + *pNewObject = (PKIX_PL_Object *)copy; + +cleanup: + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: pkix_pl_CertPolicyMap_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTPOLICYMAP_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_CertPolicyMap_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_RegisterSelf"); + + entry.description = "CertPolicyMap"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertPolicyMap); + entry.destructor = pkix_pl_CertPolicyMap_Destroy; + entry.equalsFunction = pkix_pl_CertPolicyMap_Equals; + entry.hashcodeFunction = pkix_pl_CertPolicyMap_Hashcode; + entry.toStringFunction = pkix_pl_CertPolicyMap_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_pl_CertPolicyMap_Duplicate; + + systemClasses[PKIX_CERTPOLICYMAP_TYPE] = entry; + + PKIX_RETURN(CERTPOLICYMAP); +} + +/* --Public-CertPolicyMap-Functions------------------------- */ + +/* + * FUNCTION: PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy( + PKIX_PL_CertPolicyMap *policyMapping, + PKIX_PL_OID **pIssuerDomainPolicy, + void *plContext) +{ + PKIX_ENTER + (CERTPOLICYMAP, "PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy"); + + PKIX_NULLCHECK_TWO(policyMapping, pIssuerDomainPolicy); + + PKIX_INCREF(policyMapping->issuerDomainPolicy); + *pIssuerDomainPolicy = policyMapping->issuerDomainPolicy; + +cleanup: + PKIX_RETURN(CERTPOLICYMAP); +} + +/* + * FUNCTION: PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy( + PKIX_PL_CertPolicyMap *policyMapping, + PKIX_PL_OID **pSubjectDomainPolicy, + void *plContext) +{ + PKIX_ENTER + (CERTPOLICYMAP, "PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy"); + + PKIX_NULLCHECK_TWO(policyMapping, pSubjectDomainPolicy); + + PKIX_INCREF(policyMapping->subjectDomainPolicy); + *pSubjectDomainPolicy = policyMapping->subjectDomainPolicy; + +cleanup: + PKIX_RETURN(CERTPOLICYMAP); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h new file mode 100644 index 0000000000..a03bce2c8c --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h @@ -0,0 +1,49 @@ +/* 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_certpolicymap.h + * + * CertPolicyMap Object Definitions + * + */ + +#ifndef _PKIX_PL_CERTPOLICYMAP_H +#define _PKIX_PL_CERTPOLICYMAP_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure reflects the contents of the policy mapping extension as + * described in Section 4.2.1.6 of RFC3280. + * + * PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { + * issuerDomainPolicy CertPolicyId, + * subjectDomainPolicy CertPolicyId } + * + */ +struct PKIX_PL_CertPolicyMapStruct { + PKIX_PL_OID *issuerDomainPolicy; + PKIX_PL_OID *subjectDomainPolicy; +}; + +PKIX_Error * +pkix_pl_CertPolicyMap_Create( + PKIX_PL_OID *issuerDomainPolicy, + PKIX_PL_OID *subjectDomainPolicy, + PKIX_PL_CertPolicyMap **pObject, + void *plContext); + +PKIX_Error * +pkix_pl_CertPolicyMap_RegisterSelf( + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CERTPOLICYMAP_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c new file mode 100644 index 0000000000..b57623d269 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c @@ -0,0 +1,365 @@ +/* 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_certpolicyqualifier.c + * + * CertPolicyQualifier Type Functions + * + */ + +#include "pkix_pl_certpolicyqualifier.h" + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_Create + * DESCRIPTION: + * + * Creates a CertPolicyQualifier object with the OID given by "oid" + * and the ByteArray given by "qualifier", and stores it at "pObject". + * + * PARAMETERS + * "oid" + * Address of OID of the desired policyQualifierId; must be non-NULL + * "qualifier" + * Address of ByteArray with the desired value of the qualifier; + * must be non-NULL + * "pObject" + * 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 Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_CertPolicyQualifier_Create( + PKIX_PL_OID *oid, + PKIX_PL_ByteArray *qualifier, + PKIX_PL_CertPolicyQualifier **pObject, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *qual = NULL; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Create"); + + PKIX_NULLCHECK_THREE(oid, qualifier, pObject); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTPOLICYQUALIFIER_TYPE, + sizeof (PKIX_PL_CertPolicyQualifier), + (PKIX_PL_Object **)&qual, + plContext), + PKIX_COULDNOTCREATECERTPOLICYQUALIFIEROBJECT); + + PKIX_INCREF(oid); + qual->policyQualifierId = oid; + + PKIX_INCREF(qualifier); + qual->qualifier = qualifier; + + *pObject = qual; + qual = NULL; + +cleanup: + PKIX_DECREF(qual); + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyQualifier_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *certPQ = NULL; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYQUALIFIER); + + certPQ = (PKIX_PL_CertPolicyQualifier*)object; + + PKIX_DECREF(certPQ->policyQualifierId); + PKIX_DECREF(certPQ->qualifier); + +cleanup: + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyQualifier_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *certPQ = NULL; + char *asciiFormat = "%s:%s"; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *pqIDString = NULL; + PKIX_PL_String *pqValString = NULL; + PKIX_PL_String *outString = NULL; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_ToString"); + + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYQUALIFIER); + + certPQ = (PKIX_PL_CertPolicyQualifier *)object; + + /* + * The policyQualifierId is required. If there is no qualifier, + * we should have a ByteArray of zero length. + */ + PKIX_NULLCHECK_TWO(certPQ->policyQualifierId, certPQ->qualifier); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_TOSTRING(certPQ->policyQualifierId, &pqIDString, plContext, + PKIX_OIDTOSTRINGFAILED); + + PKIX_CHECK(pkix_pl_ByteArray_ToHexString + (certPQ->qualifier, &pqValString, plContext), + PKIX_BYTEARRAYTOHEXSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&outString, plContext, formatString, pqIDString, pqValString), + PKIX_SPRINTFFAILED); + + *pString = outString; + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(pqIDString); + PKIX_DECREF(pqValString); + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyQualifier_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *certPQ = NULL; + PKIX_UInt32 cpidHash = 0; + PKIX_UInt32 cpqHash = 0; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext), + PKIX_OBJECTNOTCERTPOLICYQUALIFIER); + + certPQ = (PKIX_PL_CertPolicyQualifier *)object; + + PKIX_NULLCHECK_TWO(certPQ->policyQualifierId, certPQ->qualifier); + + PKIX_HASHCODE(certPQ->policyQualifierId, &cpidHash, plContext, + PKIX_ERRORINOIDHASHCODE); + + PKIX_HASHCODE(certPQ->qualifier, &cpqHash, plContext, + PKIX_ERRORINBYTEARRAYHASHCODE); + + *pHashcode = cpidHash*31 + cpqHash; + +cleanup: + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertPolicyQualifier_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertPolicyQualifier *firstCPQ = NULL; + PKIX_PL_CertPolicyQualifier *secondCPQ = NULL; + PKIX_UInt32 secondType = 0; + PKIX_Boolean compare = PKIX_FALSE; + + PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertPolicyQualifier */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTPOLICYQUALIFIER); + + /* + * Since we know firstObject is a CertPolicyQualifier, + * if both references are identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a CertPolicyQualifier, we + * don't throw an error. We simply return FALSE. + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObject, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CERTPOLICYQUALIFIER_TYPE) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + firstCPQ = (PKIX_PL_CertPolicyQualifier *)firstObject; + secondCPQ = (PKIX_PL_CertPolicyQualifier *)secondObject; + + /* + * Compare the value of the OID components + */ + + PKIX_NULLCHECK_TWO + (firstCPQ->policyQualifierId, secondCPQ->policyQualifierId); + + PKIX_EQUALS + (firstCPQ->policyQualifierId, + secondCPQ->policyQualifierId, + &compare, + plContext, + PKIX_OIDEQUALSFAILED); + + /* + * If the OIDs did not match, we don't need to + * compare the ByteArrays. If the OIDs did match, + * the return value is the value of the + * ByteArray comparison. + */ + if (compare) { + PKIX_NULLCHECK_TWO(firstCPQ->qualifier, secondCPQ->qualifier); + + PKIX_EQUALS + (firstCPQ->qualifier, + secondCPQ->qualifier, + &compare, + plContext, + PKIX_BYTEARRAYEQUALSFAILED); + } + + *pResult = compare; + +cleanup: + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: pkix_pl_CertPolicyQualifier_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTPOLICYQUALIFIER_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_CertPolicyQualifier_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTPOLICYQUALIFIER, + "pkix_pl_CertPolicyQualifier_RegisterSelf"); + + entry.description = "CertPolicyQualifier"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertPolicyQualifier); + entry.destructor = pkix_pl_CertPolicyQualifier_Destroy; + entry.equalsFunction = pkix_pl_CertPolicyQualifier_Equals; + entry.hashcodeFunction = pkix_pl_CertPolicyQualifier_Hashcode; + entry.toStringFunction = pkix_pl_CertPolicyQualifier_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CERTPOLICYQUALIFIER_TYPE] = entry; + + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* --Public-CertPolicyQualifier-Functions------------------------- */ + +/* + * FUNCTION: PKIX_PL_PolicyQualifier_GetPolicyQualifierId + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_PolicyQualifier_GetPolicyQualifierId( + PKIX_PL_CertPolicyQualifier *policyQualifierInfo, + PKIX_PL_OID **pPolicyQualifierId, + void *plContext) +{ + PKIX_ENTER(CERTPOLICYQUALIFIER, + "PKIX_PL_PolicyQualifier_GetPolicyQualifierId"); + + PKIX_NULLCHECK_TWO(policyQualifierInfo, pPolicyQualifierId); + + PKIX_INCREF(policyQualifierInfo->policyQualifierId); + + *pPolicyQualifierId = policyQualifierInfo->policyQualifierId; + +cleanup: + PKIX_RETURN(CERTPOLICYQUALIFIER); +} + +/* + * FUNCTION: PKIX_PL_PolicyQualifier_GetQualifier + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_PolicyQualifier_GetQualifier( + PKIX_PL_CertPolicyQualifier *policyQualifierInfo, + PKIX_PL_ByteArray **pQualifier, + void *plContext) +{ + PKIX_ENTER(CERTPOLICYQUALIFIER, "PKIX_PL_PolicyQualifier_GetQualifier"); + + PKIX_NULLCHECK_TWO(policyQualifierInfo, pQualifier); + + PKIX_INCREF(policyQualifierInfo->qualifier); + + *pQualifier = policyQualifierInfo->qualifier; + +cleanup: + PKIX_RETURN(CERTPOLICYQUALIFIER); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h new file mode 100644 index 0000000000..4c6c8a21ba --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h @@ -0,0 +1,52 @@ +/* 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_certpolicyqualifier.h + * + * PolicyQualifier Type Definitions + * + */ + +#ifndef _PKIX_PL_POLICYQUALIFIER_H +#define _PKIX_PL_POLICYQUALIFIER_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure reflects the contents of the policy qualifier extension as + * described in Section 4.2.1.5 of RFC3280. + * + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + * + * PolicyQualifierId ::= + * OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice) + * + */ +struct PKIX_PL_CertPolicyQualifierStruct { + PKIX_PL_OID *policyQualifierId; + PKIX_PL_ByteArray *qualifier; +}; + +PKIX_Error * +pkix_pl_CertPolicyQualifier_Create( + PKIX_PL_OID *oid, + PKIX_PL_ByteArray *qualifierArray, + PKIX_PL_CertPolicyQualifier **pObject, + void *plContext); + +PKIX_Error * +pkix_pl_CertPolicyQualifier_RegisterSelf( + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_POLICYQUALIFIER_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c new file mode 100644 index 0000000000..b83db357ac --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c @@ -0,0 +1,1068 @@ +/* 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_crl.c + * + * CRL Function Definitions + * + */ + +#include "pkix_pl_crl.h" +#include "certxutl.h" + +extern PKIX_PL_HashTable *cachedCrlSigTable; + +/* --Private-CRL-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_CRL_GetVersion + * DESCRIPTION: + * + * Retrieves the version of the CRL pointed to by "crl" and stores it at + * "pVersion". The version number will either be 0 or 1 (corresponding to + * v1 or v2, respectively). + * + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * PARAMETERS: + * "crl" + * Address of CRL whose version is to be stored. Must be non-NULL. + * "pVersion" + * Address where a version 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 CRL 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_CRL_GetVersion( + PKIX_PL_CRL *crl, + PKIX_UInt32 *pVersion, + void *plContext) +{ + PKIX_UInt32 myVersion; + + PKIX_ENTER(CRL, "pkix_pl_CRL_GetVersion"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pVersion); + + PKIX_NULLCHECK_ONE(crl->nssSignedCrl->crl.version.data); + + myVersion = *(crl->nssSignedCrl->crl.version.data); + + if (myVersion > 1) { + PKIX_ERROR(PKIX_VERSIONVALUEMUSTBEV1ORV2); + } + + *pVersion = myVersion; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_GetCRLNumber (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_GetCRLNumber( + PKIX_PL_CRL *crl, + PKIX_PL_BigInt **pCrlNumber, + void *plContext) +{ + PKIX_PL_BigInt *crlNumber = NULL; + SECItem nssCrlNumber; + PLArenaPool *arena = NULL; + SECStatus status; + PKIX_UInt32 length = 0; + char *bytes = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_GetCRLNumber"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCrlNumber); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + if (!crl->crlNumberAbsent && crl->crlNumber == NULL) { + + PKIX_OBJECT_LOCK(crl); + + if (!crl->crlNumberAbsent && crl->crlNumber == NULL) { + + nssCrlNumber.type = 0; + nssCrlNumber.len = 0; + nssCrlNumber.data = NULL; + + PKIX_CRL_DEBUG("\t\tCalling PORT_NewArena).\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CRL_DEBUG("\t\tCalling CERT_FindCRLNumberExten\n"); + status = CERT_FindCRLNumberExten + (arena, &crl->nssSignedCrl->crl, &nssCrlNumber); + + if (status == SECSuccess) { + /* Get data in bytes then convert to bigint */ + length = nssCrlNumber.len; + bytes = (char *)nssCrlNumber.data; + + PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes + (bytes, length, &crlNumber, plContext), + PKIX_BIGINTCREATEWITHBYTESFAILED); + + /* arena release does the job + PKIX_CRL_DEBUG("\t\tCalling SECITEM_FreeItem\n"); + SECITEM_FreeItem(&nssCrlNumber, PKIX_FALSE); + */ + crl->crlNumber = crlNumber; + + } else { + + crl->crlNumberAbsent = PKIX_TRUE; + } + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + PKIX_INCREF(crl->crlNumber); + + *pCrlNumber = crl->crlNumber; + +cleanup: + + if (arena){ + PKIX_CRL_DEBUG("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_GetSignatureAlgId + * + * DESCRIPTION: + * Retrieves a pointer to the OID that represents the signature algorithm of + * the CRL pointed to by "crl" and stores it at "pSignatureAlgId". + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * + * PARAMETERS: + * "crl" + * Address of CRL whose signature algorithm OID is to be stored. + * Must be non-NULL. + * "pSignatureAlgId" + * 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 CRL 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_CRL_GetSignatureAlgId( + PKIX_PL_CRL *crl, + PKIX_PL_OID **pSignatureAlgId, + void *plContext) +{ + PKIX_PL_OID *signatureAlgId = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_GetSignatureAlgId"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pSignatureAlgId); + + /* if we don't have a cached copy from before, we create one */ + if (crl->signatureAlgId == NULL){ + PKIX_OBJECT_LOCK(crl); + if (crl->signatureAlgId == NULL){ + CERTCrl *nssCrl = &(crl->nssSignedCrl->crl); + SECAlgorithmID *algorithm = &nssCrl->signatureAlg; + SECItem *algBytes = &algorithm->algorithm; + + if (!algBytes->data || !algBytes->len) { + PKIX_ERROR(PKIX_OIDBYTESLENGTH0); + } + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem + (algBytes, &signatureAlgId, plContext), + PKIX_OIDCREATEFAILED); + + /* save a cached copy in case it is asked for again */ + crl->signatureAlgId = signatureAlgId; + signatureAlgId = NULL; + } + PKIX_OBJECT_UNLOCK(crl); + } + PKIX_INCREF(crl->signatureAlgId); + *pSignatureAlgId = crl->signatureAlgId; +cleanup: + PKIX_DECREF(signatureAlgId); + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_GetCRLEntries + * DESCRIPTION: + * + * Retrieves a pointer to the List of CRLEntries found in the CRL pointed to + * by "crl" and stores it at "pCRLEntries". If there are no CRLEntries, + * this functions stores NULL at "pCRLEntries". + * + * PARAMETERS: + * "crl" + * Address of CRL whose CRL Entries are to be retrieved. Must be non-NULL. + * "pCRLEntries" + * 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 CRL 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_CRL_GetCRLEntries( + PKIX_PL_CRL *crl, + PKIX_List **pCrlEntries, + void *plContext) +{ + PKIX_List *entryList = NULL; + CERTCrl *nssCrl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_GetCRLEntries"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCrlEntries); + + /* if we don't have a cached copy from before, we create one */ + if (crl->crlEntryList == NULL) { + + PKIX_OBJECT_LOCK(crl); + + if (crl->crlEntryList == NULL){ + + nssCrl = &(crl->nssSignedCrl->crl); + + PKIX_CHECK(pkix_pl_CRLEntry_Create + (nssCrl->entries, &entryList, plContext), + PKIX_CRLENTRYCREATEFAILED); + + PKIX_CHECK(PKIX_List_SetImmutable + (entryList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + crl->crlEntryList = entryList; + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + PKIX_INCREF(crl->crlEntryList); + + *pCrlEntries = crl->crlEntryList; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext), + PKIX_OBJECTNOTCRL); + + crl = (PKIX_PL_CRL*)object; + + PKIX_CRL_DEBUG("\t\tCalling CERT_DestroyCrl\n"); + if (crl->nssSignedCrl) { + CERT_DestroyCrl(crl->nssSignedCrl); + } + if (crl->adoptedDerCrl) { + SECITEM_FreeItem(crl->adoptedDerCrl, PR_TRUE); + } + crl->nssSignedCrl = NULL; + crl->adoptedDerCrl = NULL; + crl->crlNumberAbsent = PKIX_FALSE; + + PKIX_DECREF(crl->issuer); + PKIX_DECREF(crl->signatureAlgId); + PKIX_DECREF(crl->crlNumber); + PKIX_DECREF(crl->crlEntryList); + PKIX_DECREF(crl->critExtOids); + if (crl->derGenName) { + SECITEM_FreeItem(crl->derGenName, PR_TRUE); + } + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the CRL pointed + * to by "crl" and stores it at "pString". + * + * PARAMETERS + * "crl" + * Address of CRL whose string representation is desired. + * Must be non-NULL. + * "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 CRL 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_CRL_ToString_Helper( + PKIX_PL_CRL *crl, + PKIX_PL_String **pString, + void *plContext) +{ + char *asciiFormat = NULL; + PKIX_UInt32 crlVersion = 0; + PKIX_PL_X500Name *crlIssuer = NULL; + PKIX_PL_OID *nssSignatureAlgId = NULL; + PKIX_PL_BigInt *crlNumber = NULL; + PKIX_List *crlEntryList = NULL; + PKIX_List *critExtOIDs = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *crlIssuerString = NULL; + PKIX_PL_String *lastUpdateString = NULL; + PKIX_PL_String *nextUpdateString = NULL; + PKIX_PL_String *nssSignatureAlgIdString = NULL; + PKIX_PL_String *crlNumberString = NULL; + PKIX_PL_String *crlEntryListString = NULL; + PKIX_PL_String *critExtOIDsString = NULL; + PKIX_PL_String *crlString = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_ToString_Helper"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pString); + + asciiFormat = + "[\n" + "\tVersion: v%d\n" + "\tIssuer: %s\n" + "\tUpdate: [Last: %s\n" + "\t Next: %s]\n" + "\tSignatureAlgId: %s\n" + "\tCRL Number : %s\n" + "\n" + "\tEntry List: %s\n" + "\n" + "\tCritExtOIDs: %s\n" + "]\n"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + /* Version */ + PKIX_CHECK(pkix_pl_CRL_GetVersion(crl, &crlVersion, plContext), + PKIX_CRLGETVERSIONFAILED); + + /* Issuer */ + PKIX_CHECK(PKIX_PL_CRL_GetIssuer(crl, &crlIssuer, plContext), + PKIX_CRLGETISSUERFAILED); + + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)crlIssuer, &crlIssuerString, plContext), + PKIX_X500NAMETOSTRINGFAILED); + + /* This update - No Date object created, use nss data directly */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(crl->nssSignedCrl->crl.lastUpdate), + &lastUpdateString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* Next update - No Date object created, use nss data directly */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(crl->nssSignedCrl->crl.nextUpdate), + &nextUpdateString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* Signature Algorithm Id */ + PKIX_CHECK(pkix_pl_CRL_GetSignatureAlgId + (crl, &nssSignatureAlgId, plContext), + PKIX_CRLGETSIGNATUREALGIDFAILED); + + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)nssSignatureAlgId, + &nssSignatureAlgIdString, + plContext), + PKIX_OIDTOSTRINGFAILED); + + /* CRL Number */ + PKIX_CHECK(PKIX_PL_CRL_GetCRLNumber + (crl, &crlNumber, plContext), + PKIX_CRLGETCRLNUMBERFAILED); + + PKIX_TOSTRING(crlNumber, &crlNumberString, plContext, + PKIX_BIGINTTOSTRINGFAILED); + + /* CRL Entries */ + PKIX_CHECK(pkix_pl_CRL_GetCRLEntries(crl, &crlEntryList, plContext), + PKIX_CRLGETCRLENTRIESFAILED); + + PKIX_TOSTRING(crlEntryList, &crlEntryListString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* CriticalExtensionOIDs */ + PKIX_CHECK(PKIX_PL_CRL_GetCriticalExtensionOIDs + (crl, &critExtOIDs, plContext), + PKIX_CRLGETCRITICALEXTENSIONOIDSFAILED); + + PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext, + PKIX_LISTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&crlString, + plContext, + formatString, + crlVersion + 1, + crlIssuerString, + lastUpdateString, + nextUpdateString, + nssSignatureAlgIdString, + crlNumberString, + crlEntryListString, + critExtOIDsString), + PKIX_SPRINTFFAILED); + + *pString = crlString; + +cleanup: + + PKIX_DECREF(crlIssuer); + PKIX_DECREF(nssSignatureAlgId); + PKIX_DECREF(crlNumber); + PKIX_DECREF(crlEntryList); + PKIX_DECREF(critExtOIDs); + PKIX_DECREF(crlIssuerString); + PKIX_DECREF(lastUpdateString); + PKIX_DECREF(nextUpdateString); + PKIX_DECREF(nssSignatureAlgIdString); + PKIX_DECREF(crlNumberString); + PKIX_DECREF(crlEntryListString); + PKIX_DECREF(critExtOIDsString); + PKIX_DECREF(formatString); + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *crlString = NULL; + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext), + PKIX_OBJECTNOTCRL); + + crl = (PKIX_PL_CRL *) object; + + PKIX_CHECK(pkix_pl_CRL_ToString_Helper(crl, &crlString, plContext), + PKIX_CRLTOSTRINGHELPERFAILED); + + *pString = crlString; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CRL *crl = NULL; + PKIX_UInt32 certHash; + SECItem *crlDer = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext), + PKIX_OBJECTNOTCRL); + + crl = (PKIX_PL_CRL *)object; + if (crl->adoptedDerCrl) { + crlDer = crl->adoptedDerCrl; + } else if (crl->nssSignedCrl && crl->nssSignedCrl->derCrl) { + crlDer = crl->nssSignedCrl->derCrl; + } + if (!crlDer || !crlDer->data) { + PKIX_ERROR(PKIX_CANNOTAQUIRECRLDER); + } + + PKIX_CHECK(pkix_hash(crlDer->data, crlDer->len, + &certHash, plContext), + PKIX_ERRORINHASH); + + *pHashcode = certHash; + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRL_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CRL *firstCrl = NULL; + PKIX_PL_CRL *secondCrl = NULL; + SECItem *crlDerOne = NULL, *crlDerTwo = NULL; + PKIX_UInt32 secondType; + + PKIX_ENTER(CRL, "pkix_pl_CRL_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CRL */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CRL_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCRL); + + firstCrl = (PKIX_PL_CRL *)firstObject; + secondCrl = (PKIX_PL_CRL *)secondObject; + + /* + * Since we know firstObject is a CRL, if both references are + * identical, they must be equal + */ + if (firstCrl == secondCrl){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondCrl isn't a CRL, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + ((PKIX_PL_Object *)secondCrl, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CRL_TYPE) goto cleanup; + + if (firstCrl->adoptedDerCrl) { + crlDerOne = firstCrl->adoptedDerCrl; + } else if (firstCrl->nssSignedCrl && firstCrl->nssSignedCrl->derCrl) { + crlDerOne = firstCrl->nssSignedCrl->derCrl; + } + + if (secondCrl->adoptedDerCrl) { + crlDerTwo = secondCrl->adoptedDerCrl; + } else if (secondCrl->nssSignedCrl && secondCrl->nssSignedCrl->derCrl) { + crlDerTwo = secondCrl->nssSignedCrl->derCrl; + } + + if (SECITEM_CompareItem(crlDerOne, crlDerTwo) == SECEqual) { + *pResult = PKIX_TRUE; + } + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_CRL_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_CRL_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = &systemClasses[PKIX_CRL_TYPE]; + + PKIX_ENTER(CRL, "pkix_pl_CRL_RegisterSelf"); + + entry->description = "CRL"; + entry->typeObjectSize = sizeof(PKIX_PL_CRL); + entry->destructor = pkix_pl_CRL_Destroy; + entry->equalsFunction = pkix_pl_CRL_Equals; + entry->hashcodeFunction = pkix_pl_CRL_Hashcode; + entry->toStringFunction = pkix_pl_CRL_ToString; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_VerifyUpdateTime (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_VerifyUpdateTime( + PKIX_PL_CRL *crl, + PKIX_PL_Date *date, + PKIX_Boolean *pResult, + void *plContext) +{ + PRTime timeToCheck; + PRTime nextUpdate; + PRTime lastUpdate; + SECStatus status; + CERTCrl *nssCrl = NULL; + SECItem *nextUpdateDer = NULL; + PKIX_Boolean haveNextUpdate = PR_FALSE; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifyUpdateTime"); + PKIX_NULLCHECK_FOUR(crl, crl->nssSignedCrl, date, pResult); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + nssCrl = &(crl->nssSignedCrl->crl); + timeToCheck = date->nssTime; + + /* nextUpdate can be NULL. Checking before using it */ + nextUpdateDer = &nssCrl->nextUpdate; + if (nextUpdateDer->data && nextUpdateDer->len) { + haveNextUpdate = PR_TRUE; + status = DER_DecodeTimeChoice(&nextUpdate, nextUpdateDer); + if (status != SECSuccess) { + PKIX_ERROR(PKIX_DERDECODETIMECHOICEFORNEXTUPDATEFAILED); + } + } + + status = DER_DecodeTimeChoice(&lastUpdate, &(nssCrl->lastUpdate)); + if (status != SECSuccess) { + PKIX_ERROR(PKIX_DERDECODETIMECHOICEFORLASTUPDATEFAILED); + } + + if (!haveNextUpdate || nextUpdate < timeToCheck) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + if (lastUpdate <= timeToCheck) { + *pResult = PKIX_TRUE; + } else { + *pResult = PKIX_FALSE; + } + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: pkix_pl_CRL_CreateWithSignedCRL + * DESCRIPTION: + * + * Creates a new CRL using the CERTSignedCrl pointed to by "nssSignedCrl" + * and stores it at "pCRL". If the decoding of the CERTSignedCrl fails, + * a PKIX_Error is returned. + * + * PARAMETERS: + * "nssSignedCrl" + * Address of CERTSignedCrl. Must be non-NULL. + * "adoptedDerCrl" + * SECItem ponter that if not NULL is indicating that memory used + * for der should be adopted by crl that is about to be created. + * "pCRL" + * 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 CRL 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_CRL_CreateWithSignedCRL( + CERTSignedCrl *nssSignedCrl, + SECItem *adoptedDerCrl, + SECItem *derGenName, + PKIX_PL_CRL **pCrl, + void *plContext) +{ + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "pkix_pl_CRL_CreateWithSignedCRL"); + PKIX_NULLCHECK_ONE(pCrl); + + /* create a PKIX_PL_CRL object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CRL_TYPE, + sizeof (PKIX_PL_CRL), + (PKIX_PL_Object **)&crl, + plContext), + PKIX_COULDNOTCREATECRLOBJECT); + + /* populate the nssSignedCrl field */ + crl->nssSignedCrl = nssSignedCrl; + crl->adoptedDerCrl = adoptedDerCrl; + crl->issuer = NULL; + crl->signatureAlgId = NULL; + crl->crlNumber = NULL; + crl->crlNumberAbsent = PKIX_FALSE; + crl->crlEntryList = NULL; + crl->critExtOids = NULL; + if (derGenName) { + crl->derGenName = + SECITEM_DupItem(derGenName); + if (!crl->derGenName) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + } + + *pCrl = crl; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(crl); + } + + PKIX_RETURN(CRL); +} + +/* --Public-CRL-Functions------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_CRL_Create (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_Create( + PKIX_PL_ByteArray *byteArray, + PKIX_PL_CRL **pCrl, + void *plContext) +{ + CERTSignedCrl *nssSignedCrl = NULL; + SECItem derItem, *derCrl = NULL; + PKIX_PL_CRL *crl = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_Create"); + PKIX_NULLCHECK_TWO(byteArray, pCrl); + + if (byteArray->length == 0){ + PKIX_ERROR(PKIX_ZEROLENGTHBYTEARRAYFORCRLENCODING); + } + derItem.type = siBuffer; + derItem.data = byteArray->array; + derItem.len = byteArray->length; + derCrl = SECITEM_DupItem(&derItem); + if (!derCrl) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + nssSignedCrl = + CERT_DecodeDERCrlWithFlags(NULL, derCrl, SEC_CRL_TYPE, + CRL_DECODE_DONT_COPY_DER | + CRL_DECODE_SKIP_ENTRIES); + if (!nssSignedCrl) { + PKIX_ERROR(PKIX_CERTDECODEDERCRLFAILED); + } + PKIX_CHECK( + pkix_pl_CRL_CreateWithSignedCRL(nssSignedCrl, derCrl, NULL, + &crl, plContext), + PKIX_CRLCREATEWITHSIGNEDCRLFAILED); + nssSignedCrl = NULL; + derCrl = NULL; + *pCrl = crl; + +cleanup: + if (derCrl) { + SECITEM_FreeItem(derCrl, PR_TRUE); + } + if (nssSignedCrl) { + SEC_DestroyCrl(nssSignedCrl); + } + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_GetIssuer (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_GetIssuer( + PKIX_PL_CRL *crl, + PKIX_PL_X500Name **pCRLIssuer, + void *plContext) +{ + PKIX_PL_String *crlString = NULL; + PKIX_PL_X500Name *issuer = NULL; + SECItem *derIssuerName = NULL; + CERTName *issuerName = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_GetIssuer"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCRLIssuer); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + /* if we don't have a cached copy from before, we create one */ + if (crl->issuer == NULL){ + + PKIX_OBJECT_LOCK(crl); + + if (crl->issuer == NULL) { + + issuerName = &crl->nssSignedCrl->crl.name; + derIssuerName = &crl->nssSignedCrl->crl.derName; + + PKIX_CHECK( + PKIX_PL_X500Name_CreateFromCERTName(derIssuerName, + issuerName, + &issuer, + plContext), + PKIX_X500NAMECREATEFROMCERTNAMEFAILED); + + /* save a cached copy in case it is asked for again */ + crl->issuer = issuer; + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + PKIX_INCREF(crl->issuer); + + *pCRLIssuer = crl->issuer; + +cleanup: + + PKIX_DECREF(crlString); + + PKIX_RETURN(CRL); +} + + +/* + * FUNCTION: PKIX_PL_CRL_GetCriticalExtensionOIDs + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_GetCriticalExtensionOIDs( + PKIX_PL_CRL *crl, + PKIX_List **pExtensions, /* list of PKIX_PL_OID */ + void *plContext) +{ + PKIX_List *oidsList = NULL; + CERTCertExtension **extensions = NULL; + CERTCrl *nssSignedCrl = NULL; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_GetCriticalExtensionOIDs"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pExtensions); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + /* if we don't have a cached copy from before, we create one */ + if (crl->critExtOids == NULL) { + + PKIX_OBJECT_LOCK(crl); + + nssSignedCrl = &(crl->nssSignedCrl->crl); + extensions = nssSignedCrl->extensions; + + if (crl->critExtOids == NULL) { + + PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs + (extensions, &oidsList, plContext), + PKIX_GETCRITICALEXTENSIONOIDSFAILED); + + crl->critExtOids = oidsList; + } + + PKIX_OBJECT_UNLOCK(crl); + + } + + /* We should return a copy of the List since this list changes */ + PKIX_DUPLICATE(crl->critExtOids, pExtensions, plContext, + PKIX_OBJECTDUPLICATELISTFAILED); + +cleanup: + + PKIX_RETURN(CRL); +} + +/* + * FUNCTION: PKIX_PL_CRL_VerifySignature (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRL_VerifySignature( + PKIX_PL_CRL *crl, + PKIX_PL_PublicKey *pubKey, + void *plContext) +{ + PKIX_PL_CRL *cachedCrl = NULL; + PKIX_Error *verifySig = NULL; + PKIX_Error *cachedSig = NULL; + PKIX_Boolean crlEqual = PKIX_FALSE; + PKIX_Boolean crlInHash= PKIX_FALSE; + CERTSignedCrl *nssSignedCrl = NULL; + SECKEYPublicKey *nssPubKey = NULL; + CERTSignedData *tbsCrl = NULL; + void* wincx = NULL; + SECStatus status; + + PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifySignature"); + PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pubKey); + + /* Can call this function only with der been adopted. */ + PORT_Assert(crl->adoptedDerCrl); + + verifySig = PKIX_PL_HashTable_Lookup + (cachedCrlSigTable, + (PKIX_PL_Object *) pubKey, + (PKIX_PL_Object **) &cachedCrl, + plContext); + + if (cachedCrl != NULL && verifySig == NULL) { + /* Cached Signature Table lookup succeed */ + PKIX_EQUALS(crl, cachedCrl, &crlEqual, plContext, + PKIX_OBJECTEQUALSFAILED); + if (crlEqual == PKIX_TRUE) { + goto cleanup; + } + /* Different PubKey may hash to same value, skip add */ + crlInHash = PKIX_TRUE; + } + + nssSignedCrl = crl->nssSignedCrl; + tbsCrl = &nssSignedCrl->signatureWrap; + + PKIX_CRL_DEBUG("\t\tCalling SECKEY_ExtractPublicKey\n"); + nssPubKey = SECKEY_ExtractPublicKey(pubKey->nssSPKI); + if (!nssPubKey){ + PKIX_ERROR(PKIX_SECKEYEXTRACTPUBLICKEYFAILED); + } + + PKIX_CHECK(pkix_pl_NssContext_GetWincx + ((PKIX_PL_NssContext *)plContext, &wincx), + PKIX_NSSCONTEXTGETWINCXFAILED); + + PKIX_CRL_DEBUG("\t\tCalling CERT_VerifySignedDataWithPublicKey\n"); + status = CERT_VerifySignedDataWithPublicKey(tbsCrl, nssPubKey, wincx); + + if (status != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + PKIX_ERROR(PKIX_SIGNATUREDIDNOTVERIFYWITHTHEPUBLICKEY); + } + + if (crlInHash == PKIX_FALSE) { + cachedSig = PKIX_PL_HashTable_Add + (cachedCrlSigTable, + (PKIX_PL_Object *) pubKey, + (PKIX_PL_Object *) crl, + plContext); + + if (cachedSig != NULL) { + PKIX_DEBUG("PKIX_PL_HashTable_Add skipped: entry existed\n"); + } + } + +cleanup: + + if (nssPubKey){ + PKIX_CRL_DEBUG("\t\tCalling SECKEY_DestroyPublicKey\n"); + SECKEY_DestroyPublicKey(nssPubKey); + nssPubKey = NULL; + } + + PKIX_DECREF(cachedCrl); + PKIX_DECREF(verifySig); + PKIX_DECREF(cachedSig); + + PKIX_RETURN(CRL); +} + +PKIX_Error* +PKIX_PL_CRL_ReleaseDerCrl(PKIX_PL_CRL *crl, + SECItem **derCrl, + void *plContext) +{ + PKIX_ENTER(CRL, "PKIX_PL_CRL_ReleaseDerCrl"); + *derCrl = crl->adoptedDerCrl; + crl->adoptedDerCrl = NULL; + + PKIX_RETURN(CRL); +} + +PKIX_Error* +PKIX_PL_CRL_AdoptDerCrl(PKIX_PL_CRL *crl, + SECItem *derCrl, + void *plContext) +{ + PKIX_ENTER(CRL, "PKIX_PL_CRL_AquireDerCrl"); + if (crl->adoptedDerCrl) { + PKIX_ERROR(PKIX_CANNOTAQUIRECRLDER); + } + crl->adoptedDerCrl = derCrl; +cleanup: + PKIX_RETURN(CRL); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h new file mode 100644 index 0000000000..a45059ea0d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h @@ -0,0 +1,48 @@ +/* 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_crl.h + * + * CRL Object Type Definitions + * + */ + +#ifndef _PKIX_PL_CRL_H +#define _PKIX_PL_CRL_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_CRLStruct { + CERTSignedCrl *nssSignedCrl; + PKIX_PL_X500Name *issuer; + PKIX_PL_OID *signatureAlgId; + PKIX_PL_BigInt *crlNumber; + PKIX_Boolean crlNumberAbsent; + PKIX_List *crlEntryList; /* list of PKIX_PL_CRLEntry */ + PKIX_List *critExtOids; + SECItem *adoptedDerCrl; + SECItem *derGenName; /* der of general name which was used + * to download the crl. */ +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_CRL_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_CRL_CreateWithSignedCRL(CERTSignedCrl *nssSignedCrl, + SECItem *derCrl, + SECItem *derGenName, + PKIX_PL_CRL **pCrl, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CRL_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c new file mode 100644 index 0000000000..4f29de2849 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c @@ -0,0 +1,151 @@ +/* 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_crldp.c + * + * Crl DP Object Functions + * + */ + +#include "pkix_pl_crldp.h" + +static PKIX_Error * +pkix_pl_CrlDp_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + pkix_pl_CrlDp *crldp = NULL; + + PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a default CRL checker state */ + PKIX_CHECK( + pkix_CheckType(object, PKIX_CRLDP_TYPE, plContext), + PKIX_OBJECTNOTCRLCHECKER); + + crldp = (pkix_pl_CrlDp *)object; + if (crldp->distPointType == relativeDistinguishedName) { + CERT_DestroyName(crldp->name.issuerName); + crldp->name.issuerName = NULL; + } + crldp->nssdp = NULL; +cleanup: + PKIX_RETURN(CRLCHECKER); +} + +/* + * FUNCTION: pkix_pl_CrlDp_RegisterSelf + * + * DESCRIPTION: + * Registers PKIX_CRLDP_TYPE and its related functions + * with systemClasses[] + * + * THREAD SAFETY: + * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * + * 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_CrlDp_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry* entry = &systemClasses[PKIX_CRLDP_TYPE]; + + PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_RegisterSelf"); + + entry->description = "CrlDistPoint"; + entry->typeObjectSize = sizeof(pkix_pl_CrlDp); + entry->destructor = pkix_pl_CrlDp_Destroy; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(CRLCHECKER); +} + + + +PKIX_Error * +pkix_pl_CrlDp_Create( + const CRLDistributionPoint *dp, + const CERTName *certIssuerName, + pkix_pl_CrlDp **pPkixDP, + void *plContext) +{ + PLArenaPool *rdnArena = NULL; + CERTName *issuerNameCopy = NULL; + pkix_pl_CrlDp *dpl = NULL; + + /* Need to save the following info to update crl cache: + * - reasons if partitioned(but can not return revocation check + * success if not all crl are downloaded) + * - issuer name if different from issuer of the cert + * - url to upload a crl if needed. + * */ + PKIX_ENTER(CRLDP, "pkix_pl_CrlDp_Create"); + PKIX_NULLCHECK_ONE(dp); + + PKIX_CHECK( + PKIX_PL_Object_Alloc(PKIX_CRLDP_TYPE, + sizeof (pkix_pl_CrlDp), + (PKIX_PL_Object **)&dpl, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + dpl->nssdp = dp; + dpl->isPartitionedByReasonCode = PKIX_FALSE; + if (dp->reasons.data) { + dpl->isPartitionedByReasonCode = PKIX_TRUE; + } + if (dp->distPointType == generalName) { + dpl->distPointType = generalName; + dpl->name.fullName = dp->distPoint.fullName; + } else { + SECStatus rv; + const CERTName *issuerName = NULL; + const CERTRDN *relName = &dp->distPoint.relativeName; + + if (dp->crlIssuer) { + if (dp->crlIssuer->l.next) { + /* Violate RFC 5280: in this case crlIssuer + * should have only one name and should be + * a distinguish name. */ + PKIX_ERROR(PKIX_NOTCONFORMINGCRLDP); + } + issuerName = &dp->crlIssuer->name.directoryName; + } else { + issuerName = certIssuerName; + } + rdnArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!rdnArena) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + issuerNameCopy = (CERTName *)PORT_ArenaZNew(rdnArena, CERTName); + if (!issuerNameCopy) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + rv = CERT_CopyName(rdnArena, issuerNameCopy, (CERTName*)issuerName); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + rv = CERT_AddRDN(issuerNameCopy, (CERTRDN*)relName); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_ALLOCERROR); + } + dpl->distPointType = relativeDistinguishedName; + dpl->name.issuerName = issuerNameCopy; + rdnArena = NULL; + } + *pPkixDP = dpl; + dpl = NULL; + +cleanup: + if (rdnArena) { + PORT_FreeArena(rdnArena, PR_FALSE); + } + PKIX_DECREF(dpl); + + PKIX_RETURN(CRLDP); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h new file mode 100644 index 0000000000..49cd9d2cdf --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h @@ -0,0 +1,53 @@ +/* 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_crldp.h + * + * Crp DP Object Definitions + * + */ +#include "pkix_pl_common.h" + +#ifndef _PKIX_PL_CRLDP_H +#define _PKIX_PL_CRLDP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* CRLDP object can not be used without holding a reference + * to the pkix certificate they belong to. The memory for dp der + * object is allocated on nssCert certificate - a member of + * PKIX_PL_Cert struct. */ +typedef struct pkix_pl_CrlDpStruct { + /* reference to decoded crldp that allocated on nssCert arena. */ + const CRLDistributionPoint *nssdp; + DistributionPointTypes distPointType; + union { + CERTGeneralName *fullName; + /* if dp is a relative name, the issuerName is a merged value + * of crlIssuer and a relative name. Must be destroyed by CrlDp + * destructor. */ + CERTName *issuerName; + } name; + PKIX_Boolean isPartitionedByReasonCode; +} pkix_pl_CrlDp; + + +PKIX_Error * +pkix_pl_CrlDp_RegisterSelf(void *plContext); + +/* Parses CRLDistributionPoint structure and creaetes + * pkix_pl_CrlDp object. */ +PKIX_Error * +pkix_pl_CrlDp_Create(const CRLDistributionPoint *dp, + const CERTName *certIssuerName, + pkix_pl_CrlDp **pPkixDP, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CRLDP_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c new file mode 100644 index 0000000000..e2b3e02688 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c @@ -0,0 +1,880 @@ +/* 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_crlentry.c + * + * CRLENTRY Function Definitions + * + */ + +#include "pkix_pl_crlentry.h" + +/* --Private-CRLEntry-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_CRLEntry_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRLEntry_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CRLEntry *crlEntry = NULL; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRLENTRY_TYPE, plContext), + PKIX_OBJECTNOTCRLENTRY); + + crlEntry = (PKIX_PL_CRLEntry*)object; + + /* crlEntry->nssCrlEntry is freed by NSS when freeing CRL */ + crlEntry->userReasonCode = 0; + crlEntry->userReasonCodeAbsent = PKIX_FALSE; + crlEntry->nssCrlEntry = NULL; + PKIX_DECREF(crlEntry->serialNumber); + PKIX_DECREF(crlEntry->critExtOids); + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_ToString_Helper + * + * DESCRIPTION: + * Helper function that creates a string representation of the CRLEntry + * pointed to by "crlEntry" and stores it at "pString". + * + * PARAMETERS + * "crlEntry" + * Address of CRLEntry whose string representation is desired. + * Must be non-NULL. + * "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 CRLEntry 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_CRLEntry_ToString_Helper( + PKIX_PL_CRLEntry *crlEntry, + PKIX_PL_String **pString, + void *plContext) +{ + char *asciiFormat = NULL; + PKIX_List *critExtOIDs = NULL; + PKIX_PL_String *crlEntryString = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *crlSerialNumberString = NULL; + PKIX_PL_String *crlRevocationDateString = NULL; + PKIX_PL_String *critExtOIDsString = NULL; + PKIX_Int32 reasonCode = 0; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_ToString_Helper"); + PKIX_NULLCHECK_FOUR + (crlEntry, + crlEntry->serialNumber, + crlEntry->nssCrlEntry, + pString); + + asciiFormat = + "\n\t[\n" + "\tSerialNumber: %s\n" + "\tReasonCode: %d\n" + "\tRevocationDate: %s\n" + "\tCritExtOIDs: %s\n" + "\t]\n\t"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + /* SerialNumber */ + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)crlEntry->serialNumber, + &crlSerialNumberString, + plContext), + PKIX_BIGINTTOSTRINGHELPERFAILED); + + /* RevocationDate - No Date object created, use nss data directly */ + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&(crlEntry->nssCrlEntry->revocationDate), + &crlRevocationDateString, + plContext), + PKIX_DATETOSTRINGHELPERFAILED); + + /* CriticalExtensionOIDs */ + PKIX_CHECK(PKIX_PL_CRLEntry_GetCriticalExtensionOIDs + (crlEntry, &critExtOIDs, plContext), + PKIX_CRLENTRYGETCRITICALEXTENSIONOIDSFAILED); + + PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext, + PKIX_LISTTOSTRINGFAILED); + + /* Revocation Reason Code */ + PKIX_CHECK(PKIX_PL_CRLEntry_GetCRLEntryReasonCode + (crlEntry, &reasonCode, plContext), + PKIX_CRLENTRYGETCRLENTRYREASONCODEFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&crlEntryString, + plContext, + formatString, + crlSerialNumberString, + reasonCode, + crlRevocationDateString, + critExtOIDsString), + PKIX_SPRINTFFAILED); + + *pString = crlEntryString; + +cleanup: + + PKIX_DECREF(critExtOIDs); + PKIX_DECREF(crlSerialNumberString); + PKIX_DECREF(crlRevocationDateString); + PKIX_DECREF(critExtOIDsString); + PKIX_DECREF(formatString); + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRLEntry_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *crlEntryString = NULL; + PKIX_PL_CRLEntry *crlEntry = NULL; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRLENTRY_TYPE, plContext), + PKIX_OBJECTNOTCRLENTRY); + + crlEntry = (PKIX_PL_CRLEntry *) object; + + PKIX_CHECK(pkix_pl_CRLEntry_ToString_Helper + (crlEntry, &crlEntryString, plContext), + PKIX_CRLENTRYTOSTRINGHELPERFAILED); + + *pString = crlEntryString; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_Extensions_Hashcode + * DESCRIPTION: + * + * For each CRL Entry extension stored at NSS structure CERTCertExtension, + * get its derbyte data and do the hash. + * + * PARAMETERS + * "extensions" + * Address of arrray of CERTCertExtension whose hash value is desired. + * Must be non-NULL. + * "pHashValue" + * Address where the final hash value is returned. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Conditional Thread Safe + * Though the value of extensions once created is not supposed to change, + * it may be de-allocated while we are accessing it. But since we are + * validating the object, it is unlikely we or someone is de-allocating + * at the moment. + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an OID 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_CRLEntry_Extensions_Hashcode( + CERTCertExtension **extensions, + PKIX_UInt32 *pHashValue, + void *plContext) +{ + CERTCertExtension *extension = NULL; + PLArenaPool *arena = NULL; + PKIX_UInt32 extHash = 0; + PKIX_UInt32 hashValue = 0; + SECItem *derBytes = NULL; + SECItem *resultSecItem = NULL; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Extensions_Hashcode"); + PKIX_NULLCHECK_TWO(extensions, pHashValue); + + if (extensions) { + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_NewArena\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + while (*extensions) { + + extension = *extensions++; + + PKIX_NULLCHECK_ONE(extension); + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_ArenaZNew\n"); + derBytes = PORT_ArenaZNew(arena, SECItem); + if (derBytes == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PKIX_CRLENTRY_DEBUG + ("\t\tCalling SEC_ASN1EncodeItem\n"); + resultSecItem = SEC_ASN1EncodeItem + (arena, + derBytes, + extension, + CERT_CertExtensionTemplate); + + if (resultSecItem == NULL){ + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + PKIX_CHECK(pkix_hash + (derBytes->data, + derBytes->len, + &extHash, + plContext), + PKIX_HASHFAILED); + + hashValue += (extHash << 7); + + } + } + + *pHashValue = hashValue; + +cleanup: + + if (arena){ + /* Note that freeing the arena also frees derBytes */ + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_FreeArena\n"); + PORT_FreeArena(arena, PR_FALSE); + arena = NULL; + } + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRLEntry_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + SECItem *nssDate = NULL; + PKIX_PL_CRLEntry *crlEntry = NULL; + PKIX_UInt32 crlEntryHash; + PKIX_UInt32 hashValue; + PKIX_Int32 reasonCode = 0; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_CRLENTRY_TYPE, plContext), + PKIX_OBJECTNOTCRLENTRY); + + crlEntry = (PKIX_PL_CRLEntry *)object; + + PKIX_NULLCHECK_ONE(crlEntry->nssCrlEntry); + nssDate = &(crlEntry->nssCrlEntry->revocationDate); + + PKIX_NULLCHECK_ONE(nssDate->data); + + PKIX_CHECK(pkix_hash + ((const unsigned char *)nssDate->data, + nssDate->len, + &crlEntryHash, + plContext), + PKIX_ERRORGETTINGHASHCODE); + + PKIX_CHECK(PKIX_PL_Object_Hashcode + ((PKIX_PL_Object *)crlEntry->serialNumber, + &hashValue, + plContext), + PKIX_OBJECTHASHCODEFAILED); + + crlEntryHash += (hashValue << 7); + + hashValue = 0; + + if (crlEntry->nssCrlEntry->extensions) { + + PKIX_CHECK(pkix_pl_CRLEntry_Extensions_Hashcode + (crlEntry->nssCrlEntry->extensions, &hashValue, plContext), + PKIX_CRLENTRYEXTENSIONSHASHCODEFAILED); + } + + crlEntryHash += (hashValue << 7); + + PKIX_CHECK(PKIX_PL_CRLEntry_GetCRLEntryReasonCode + (crlEntry, &reasonCode, plContext), + PKIX_CRLENTRYGETCRLENTRYREASONCODEFAILED); + + crlEntryHash += (reasonCode + 777) << 3; + + *pHashcode = crlEntryHash; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLENTRY_Extensions_Equals + * DESCRIPTION: + * + * Compare each extension's DERbyte data in "firstExtensions" with extension + * in "secondExtensions" in sequential order and store the result in + * "pResult". + * + * PARAMETERS + * "firstExtensions" + * Address of first NSS structure CERTCertExtension to be compared. + * Must be non-NULL. + * "secondExtensions" + * Address of second NSS structure CERTCertExtension to be compared. + * Must be non-NULL. + * "pResult" + * Address where the comparison result is returned. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * Though the value of extensions once created is not supposed to change, + * it may be de-allocated while we are accessing it. But since we are + * validating the object, it is unlikely we or someone is de-allocating + * at the moment. + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an OID 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_CRLEntry_Extensions_Equals( + CERTCertExtension **extensions1, + CERTCertExtension **extensions2, + PKIX_Boolean *pResult, + void *plContext) +{ + CERTCertExtension **firstExtensions; + CERTCertExtension **secondExtensions; + CERTCertExtension *firstExtension = NULL; + CERTCertExtension *secondExtension = NULL; + PLArenaPool *arena = NULL; + PKIX_Boolean cmpResult = PKIX_FALSE; + SECItem *firstDerBytes = NULL; + SECItem *secondDerBytes = NULL; + SECItem *firstResultSecItem = NULL; + SECItem *secondResultSecItem = NULL; + PKIX_UInt32 firstNumExt = 0; + PKIX_UInt32 secondNumExt = 0; + SECComparison secResult; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Extensions_Equals"); + PKIX_NULLCHECK_THREE(extensions1, extensions2, pResult); + + firstExtensions = extensions1; + secondExtensions = extensions2; + + if (firstExtensions) { + while (*firstExtensions) { + firstExtension = *firstExtensions++; + firstNumExt++; + } + } + + if (secondExtensions) { + while (*secondExtensions) { + secondExtension = *secondExtensions++; + secondNumExt++; + } + } + + if (firstNumExt != secondNumExt) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + if (firstNumExt == 0 && secondNumExt == 0) { + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* now have equal number, but non-zero extension items to compare */ + + firstExtensions = extensions1; + secondExtensions = extensions2; + + cmpResult = PKIX_TRUE; + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_NewArena\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE*2); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + while (firstNumExt--) { + + firstExtension = *firstExtensions++; + secondExtension = *secondExtensions++; + + PKIX_NULLCHECK_TWO(firstExtension, secondExtension); + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_ArenaZNew\n"); + firstDerBytes = PORT_ArenaZNew(arena, SECItem); + if (firstDerBytes == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_ArenaZNew\n"); + secondDerBytes = PORT_ArenaZNew(arena, SECItem); + if (secondDerBytes == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PKIX_CRLENTRY_DEBUG + ("\t\tCalling SEC_ASN1EncodeItem\n"); + firstResultSecItem = SEC_ASN1EncodeItem + (arena, + firstDerBytes, + firstExtension, + CERT_CertExtensionTemplate); + + if (firstResultSecItem == NULL){ + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + PKIX_CRLENTRY_DEBUG + ("\t\tCalling SEC_ASN1EncodeItem\n"); + secondResultSecItem = SEC_ASN1EncodeItem + (arena, + secondDerBytes, + secondExtension, + CERT_CertExtensionTemplate); + + if (secondResultSecItem == NULL){ + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + PKIX_CRLENTRY_DEBUG("\t\tCalling SECITEM_CompareItem\n"); + secResult = SECITEM_CompareItem + (firstResultSecItem, secondResultSecItem); + + if (secResult != SECEqual) { + cmpResult = PKIX_FALSE; + break; + } + + } + + *pResult = cmpResult; + +cleanup: + + if (arena){ + /* Note that freeing the arena also frees derBytes */ + PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_FreeArena\n"); + PORT_FreeArena(arena, PR_FALSE); + arena = NULL; + } + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CRLEntry_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CRLEntry *firstCrlEntry = NULL; + PKIX_PL_CRLEntry *secondCrlEntry = NULL; + PKIX_UInt32 secondType; + PKIX_Boolean cmpResult = PKIX_FALSE; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CRLEntry */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CRLENTRY_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCRLENTRY); + + firstCrlEntry = (PKIX_PL_CRLEntry *)firstObject; + secondCrlEntry = (PKIX_PL_CRLEntry *)secondObject; + + PKIX_NULLCHECK_TWO + (firstCrlEntry->nssCrlEntry, secondCrlEntry->nssCrlEntry); + + /* + * Since we know firstObject is a CRLEntry, if both references are + * identical, they must be equal + */ + if (firstCrlEntry == secondCrlEntry){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondCrlEntry isn't a CRL Entry, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType + ((PKIX_PL_Object *)secondCrlEntry, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_CRLENTRY_TYPE) goto cleanup; + + /* Compare userSerialNumber */ + PKIX_CRLENTRY_DEBUG("\t\tCalling SECITEM_CompareItem\n"); + if (SECITEM_CompareItem( + &(((PKIX_PL_CRLEntry *)firstCrlEntry)->nssCrlEntry->serialNumber), + &(((PKIX_PL_CRLEntry *)secondCrlEntry)->nssCrlEntry->serialNumber)) + != SECEqual) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + /* Compare revocationDate */ + PKIX_CRLENTRY_DEBUG("\t\tCalling SECITEM_CompareItem\n"); + if (SECITEM_CompareItem + (&(((PKIX_PL_CRLEntry *)firstCrlEntry)->nssCrlEntry-> + revocationDate), + &(((PKIX_PL_CRLEntry *)secondCrlEntry)->nssCrlEntry-> + revocationDate)) + != SECEqual) { + *pResult = PKIX_FALSE; + goto cleanup; + } + + /* Compare Critical Extension List */ + PKIX_CHECK(pkix_pl_CRLEntry_Extensions_Equals + (firstCrlEntry->nssCrlEntry->extensions, + secondCrlEntry->nssCrlEntry->extensions, + &cmpResult, + plContext), + PKIX_CRLENTRYEXTENSIONSEQUALSFAILED); + + if (cmpResult != PKIX_TRUE){ + *pResult = PKIX_FALSE; + goto cleanup; + } + + cmpResult = (firstCrlEntry->userReasonCode == + secondCrlEntry->userReasonCode); + + *pResult = cmpResult; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CRLEntry_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_CRLEntry_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_RegisterSelf"); + + entry.description = "CRLEntry"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CRLEntry); + entry.destructor = pkix_pl_CRLEntry_Destroy; + entry.equalsFunction = pkix_pl_CRLEntry_Equals; + entry.hashcodeFunction = pkix_pl_CRLEntry_Hashcode; + entry.toStringFunction = pkix_pl_CRLEntry_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CRLENTRY_TYPE] = entry; + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_CreateEntry + * DESCRIPTION: + * + * Creates a new CRLEntry using the CertCrlEntry pointed to by "nssCrlEntry" + * and stores it at "pCrlEntry". Once created, a CRLEntry is immutable. + * + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, MUST be v2 + * + * PARAMETERS: + * "nssCrlEntry" + * Address of CERTCrlEntry representing an NSS CRL entry. + * Must be non-NULL. + * "pCrlEntry" + * 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 CRLEntry 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_CRLEntry_CreateEntry( + CERTCrlEntry *nssCrlEntry, /* entry data to be created from */ + PKIX_PL_CRLEntry **pCrlEntry, + void *plContext) +{ + PKIX_PL_CRLEntry *crlEntry = NULL; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_CreateEntry"); + PKIX_NULLCHECK_TWO(nssCrlEntry, pCrlEntry); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CRLENTRY_TYPE, + sizeof (PKIX_PL_CRLEntry), + (PKIX_PL_Object **)&crlEntry, + plContext), + PKIX_COULDNOTCREATECRLENTRYOBJECT); + + crlEntry->nssCrlEntry = nssCrlEntry; + crlEntry->serialNumber = NULL; + crlEntry->critExtOids = NULL; + crlEntry->userReasonCode = 0; + crlEntry->userReasonCodeAbsent = PKIX_FALSE; + + *pCrlEntry = crlEntry; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: pkix_pl_CRLEntry_Create + * DESCRIPTION: + * + * Creates a List of CRLEntries using the array of CERTCrlEntries pointed to + * by "nssCrlEntries" and stores it at "pCrlEntryList". If "nssCrlEntries" is + * NULL, this function stores an empty List at "pCrlEntryList". + * } + * PARAMETERS: + * "nssCrlEntries" + * Address of array of CERTCrlEntries representing NSS CRL entries. + * Can be NULL if CRL has no NSS CRL entries. + * "pCrlEntryList" + * 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 CRLEntry 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_CRLEntry_Create( + CERTCrlEntry **nssCrlEntries, /* head of entry list */ + PKIX_List **pCrlEntryList, + void *plContext) +{ + PKIX_List *entryList = NULL; + PKIX_PL_CRLEntry *crlEntry = NULL; + CERTCrlEntry **entries = NULL; + SECItem serialNumberItem; + PKIX_PL_BigInt *serialNumber; + char *bytes = NULL; + PKIX_UInt32 length; + + PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Create"); + PKIX_NULLCHECK_ONE(pCrlEntryList); + + entries = nssCrlEntries; + + PKIX_CHECK(PKIX_List_Create(&entryList, plContext), + PKIX_LISTCREATEFAILED); + + if (entries) { + while (*entries){ + PKIX_CHECK(pkix_pl_CRLEntry_CreateEntry + (*entries, &crlEntry, plContext), + PKIX_COULDNOTCREATECRLENTRYOBJECT); + + /* Get Serial Number */ + serialNumberItem = (*entries)->serialNumber; + length = serialNumberItem.len; + bytes = (char *)serialNumberItem.data; + + PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes + (bytes, length, &serialNumber, plContext), + PKIX_BIGINTCREATEWITHBYTESFAILED); + + crlEntry->serialNumber = serialNumber; + crlEntry->nssCrlEntry = *entries; + + PKIX_CHECK(PKIX_List_AppendItem + (entryList, (PKIX_PL_Object *)crlEntry, plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(crlEntry); + + entries++; + } + } + + *pCrlEntryList = entryList; + +cleanup: + PKIX_DECREF(crlEntry); + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(entryList); + } + + PKIX_RETURN(CRLENTRY); +} + +/* --Public-CRLENTRY-Functions------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_CRLEntry_GetCRLEntryReasonCode + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRLEntry_GetCRLEntryReasonCode ( + PKIX_PL_CRLEntry *crlEntry, + PKIX_Int32 *pReason, + void *plContext) +{ + SECStatus status; + CERTCRLEntryReasonCode nssReasonCode; + + PKIX_ENTER(CRLENTRY, "PKIX_PL_CRLEntry_GetCRLEntryReasonCode"); + PKIX_NULLCHECK_TWO(crlEntry, pReason); + + if (!crlEntry->userReasonCodeAbsent && crlEntry->userReasonCode == 0) { + + PKIX_OBJECT_LOCK(crlEntry); + + if (!crlEntry->userReasonCodeAbsent && + crlEntry->userReasonCode == 0) { + + /* reason code has not been cached in */ + PKIX_CRLENTRY_DEBUG("\t\tCERT_FindCRLEntryReasonExten.\n"); + status = CERT_FindCRLEntryReasonExten + (crlEntry->nssCrlEntry, &nssReasonCode); + + if (status == SECSuccess) { + crlEntry->userReasonCode = (PKIX_Int32) nssReasonCode; + } else { + crlEntry->userReasonCodeAbsent = PKIX_TRUE; + } + } + + PKIX_OBJECT_UNLOCK(crlEntry); + + } + + *pReason = crlEntry->userReasonCode; + +cleanup: + + PKIX_RETURN(CRLENTRY); +} + +/* + * FUNCTION: PKIX_PL_CRLEntry_GetCriticalExtensionOIDs + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_CRLEntry_GetCriticalExtensionOIDs ( + PKIX_PL_CRLEntry *crlEntry, + PKIX_List **pList, /* list of PKIX_PL_OID */ + void *plContext) +{ + PKIX_List *oidsList = NULL; + CERTCertExtension **extensions; + + PKIX_ENTER(CRLENTRY, "PKIX_PL_CRLEntry_GetCriticalExtensionOIDs"); + PKIX_NULLCHECK_THREE(crlEntry, crlEntry->nssCrlEntry, pList); + + /* if we don't have a cached copy from before, we create one */ + if (crlEntry->critExtOids == NULL) { + + PKIX_OBJECT_LOCK(crlEntry); + + if (crlEntry->critExtOids == NULL) { + + extensions = crlEntry->nssCrlEntry->extensions; + + PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs + (extensions, &oidsList, plContext), + PKIX_GETCRITICALEXTENSIONOIDSFAILED); + + crlEntry->critExtOids = oidsList; + } + + PKIX_OBJECT_UNLOCK(crlEntry); + + } + + /* We should return a copy of the List since this list changes */ + PKIX_DUPLICATE(crlEntry->critExtOids, pList, plContext, + PKIX_OBJECTDUPLICATELISTFAILED); + +cleanup: + + PKIX_RETURN(CRLENTRY); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h new file mode 100644 index 0000000000..9cdb6bc927 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h @@ -0,0 +1,46 @@ +/* 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_crlentry.h + * + * CRL Entry Type Object Definitions + * + */ + +#ifndef _PKIX_PL_CRLENTRY_H +#define _PKIX_PL_CRLENTRY_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PKIX_PL_CRL_REASONCODE_NOTSET (-1) + +struct PKIX_PL_CRLEntryStruct { + CERTCrlEntry *nssCrlEntry; + PKIX_PL_BigInt *serialNumber; + PKIX_List *critExtOids; + PKIX_Int32 userReasonCode; + PKIX_Boolean userReasonCodeAbsent; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_CRLEntry_RegisterSelf(void *plContext); + +/* following functions are called by CRL only hence not public */ + +PKIX_Error * +pkix_pl_CRLEntry_Create( + CERTCrlEntry **nssCrlEntry, /* head of entry list */ + PKIX_List **pCrlEntryList, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_CRLENTRY_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c new file mode 100644 index 0000000000..4b5016bd01 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c @@ -0,0 +1,466 @@ +/* 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_date.c + * + * Date Object Definitions + * + */ + +#include "pkix_pl_date.h" + +/* --Private-Date-Functions------------------------------------- */ +/* + * FUNCTION: pkix_pl_Date_GetPRTime + * DESCRIPTION: + * + * Translates into a PRTime the Date embodied by the Date object pointed to + * by "date", and stores it at "pPRTime". + * + * PARAMETERS + * "date" + * Address of Date whose PRTime representation is desired. Must be + * non-NULL. + * "pPRTime" + * Address where PRTime 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 Date 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_Date_GetPRTime( + PKIX_PL_Date *date, + PRTime *pPRTime, + void *plContext) +{ + PKIX_ENTER(DATE, "PKIX_PL_Date_GetPRTime"); + PKIX_NULLCHECK_TWO(date, pPRTime); + + *pPRTime = date->nssTime; + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_CreateFromPRTime + * DESCRIPTION: + * + * Creates a new Date from the PRTime whose value is "prtime", and stores the + * result at "pDate". + * + * PARAMETERS + * "prtime" + * The PRTime value to be embodied in the new Date object. + * "pDate" + * 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 Date 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_Date_CreateFromPRTime( + PRTime prtime, + PKIX_PL_Date **pDate, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + + PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime"); + PKIX_NULLCHECK_ONE(pDate); + + /* create a PKIX_PL_Date object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_DATE_TYPE, + sizeof (PKIX_PL_Date), + (PKIX_PL_Object **)&date, + plContext), + PKIX_COULDNOTCREATEOBJECT); + /* populate the nssTime field */ + date->nssTime = prtime; + *pDate = date; +cleanup: + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the SECItem pointed + * to by "nssTime" (which represents a date) and stores it at "pString". + * + * PARAMETERS + * "nssTime" + * Address of SECItem whose string representation is desired. + * Must be non-NULL. + * "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 Date 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_Date_ToString_Helper( + SECItem *nssTime, + PKIX_PL_String **pString, + void *plContext) +{ + char *asciiDate = NULL; + + PKIX_ENTER(DATE, "pkix_pl_Date_ToString_Helper"); + PKIX_NULLCHECK_TWO(nssTime, pString); + + switch (nssTime->type) { + case siUTCTime: + PKIX_PL_NSSCALLRV + (DATE, asciiDate, DER_UTCDayToAscii, (nssTime)); + if (!asciiDate){ + PKIX_ERROR(PKIX_DERUTCTIMETOASCIIFAILED); + } + break; + case siGeneralizedTime: + /* + * we don't currently have any way to create GeneralizedTime. + * this code is only here so that it will be in place when + * we do have the capability to create GeneralizedTime. + */ + PKIX_PL_NSSCALLRV + (DATE, asciiDate, DER_GeneralizedDayToAscii, (nssTime)); + if (!asciiDate){ + PKIX_ERROR(PKIX_DERGENERALIZEDDAYTOASCIIFAILED); + } + break; + default: + PKIX_ERROR(PKIX_UNRECOGNIZEDTIMETYPE); + } + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, asciiDate, 0, pString, plContext), + PKIX_STRINGCREATEFAILED); + +cleanup: + PR_Free(asciiDate); + + PKIX_RETURN(DATE); +} + + +/* + * FUNCTION: pkix_pl_Date_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_ENTER(DATE, "pkix_pl_Date_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), + PKIX_OBJECTNOTDATE); +cleanup: + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + SECItem nssTime = {siBuffer, NULL, 0}; + SECStatus rv; + + PKIX_ENTER(DATE, "pkix_pl_Date_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), + PKIX_OBJECTNOTDATE); + + date = (PKIX_PL_Date *)object; + rv = DER_EncodeTimeChoice(NULL, &nssTime, date->nssTime); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_DERENCODETIMECHOICEFAILED); + } + PKIX_CHECK(pkix_pl_Date_ToString_Helper + (&nssTime, pString, plContext), + PKIX_DATETOSTRINGHELPERFAILED); +cleanup: + if (nssTime.data) { + SECITEM_FreeItem(&nssTime, PR_FALSE); + } + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + PKIX_UInt32 dateHash; + + PKIX_ENTER(DATE, "pkix_pl_Date_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext), + PKIX_OBJECTNOTDATE); + + date = (PKIX_PL_Date *)object; + + PKIX_CHECK(pkix_hash + ((const unsigned char *)&date->nssTime, + sizeof(date->nssTime), + &dateHash, + plContext), + PKIX_HASHFAILED); + + *pHashcode = dateHash; + +cleanup: + + PKIX_RETURN(DATE); + +} + +/* + * FUNCTION: pkix_pl_Date_Comparator + * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_Comparator( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pResult, + void *plContext) +{ + PRTime firstTime; + PRTime secondTime; + SECComparison cmpResult; + + PKIX_ENTER(DATE, "pkix_pl_Date_Comparator"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + PKIX_CHECK(pkix_CheckTypes + (firstObject, secondObject, PKIX_DATE_TYPE, plContext), + PKIX_ARGUMENTSNOTDATES); + + firstTime = ((PKIX_PL_Date *)firstObject)->nssTime; + secondTime = ((PKIX_PL_Date *)secondObject)->nssTime; + + if (firstTime == secondTime) + cmpResult = SECEqual; + else if (firstTime < secondTime) + cmpResult = SECLessThan; + else + cmpResult = SECGreaterThan; + + *pResult = cmpResult; + +cleanup: + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_Date_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_ENTER(DATE, "pkix_pl_Date_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a Date */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_DATE_TYPE, plContext), + PKIX_FIRSTOBJECTNOTDATE); + + /* + * Since we know firstObject is a Date, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + *pResult = PKIX_FALSE; + pkixErrorResult = + pkix_pl_Date_Comparator(firstObject, secondObject, + pResult, plContext); + if (pkixErrorResult) { + PKIX_DECREF(pkixErrorResult); + } + +cleanup: + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: pkix_pl_Date_RegisterSelf + * DESCRIPTION: + * Registers PKIX_DATE_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_Date_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry* entry = &systemClasses[PKIX_DATE_TYPE]; + + PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_RegisterSelf"); + + entry->description = "Date"; + entry->typeObjectSize = sizeof(PKIX_PL_Date); + entry->destructor = pkix_pl_Date_Destroy; + entry->equalsFunction = pkix_pl_Date_Equals; + entry->hashcodeFunction = pkix_pl_Date_Hashcode; + entry->toStringFunction = pkix_pl_Date_ToString; + entry->comparator = pkix_pl_Date_Comparator; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(DATE); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_Date_Create_UTCTime (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Date_Create_UTCTime( + PKIX_PL_String *stringRep, + PKIX_PL_Date **pDate, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + char *asciiString = NULL; + PKIX_UInt32 escAsciiLength; + SECStatus rv; + PRTime time; + + PKIX_ENTER(DATE, "PKIX_PL_Date_Create_UTCTime"); + PKIX_NULLCHECK_ONE(pDate); + + if (stringRep == NULL){ + PKIX_DATE_DEBUG("\t\tCalling PR_Now).\n"); + time = PR_Now(); + } else { + /* convert the input PKIX_PL_String to PKIX_ESCASCII */ + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stringRep, + PKIX_ESCASCII, + (void **)&asciiString, + &escAsciiLength, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_DATE_DEBUG("\t\tCalling DER_AsciiToTime).\n"); + /* DER_AsciiToTime only supports UTCTime (2-digit years) */ + rv = DER_AsciiToTime(&time, asciiString); + if (rv != SECSuccess){ + PKIX_ERROR(PKIX_DERASCIITOTIMEFAILED); + } + } + + /* create a PKIX_PL_Date object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_DATE_TYPE, + sizeof (PKIX_PL_Date), + (PKIX_PL_Object **)&date, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* populate the nssTime field */ + date->nssTime = time; + *pDate = date; + +cleanup: + PKIX_FREE(asciiString); + + PKIX_RETURN(DATE); +} + +/* + * FUNCTION: PKIX_PL_Date_Create_CurrentOffBySeconds + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_Date_Create_CurrentOffBySeconds( + PKIX_Int32 secondsOffset, + PKIX_PL_Date **pDate, + void *plContext) +{ + PKIX_PL_Date *date = NULL; + PRTime time; + + PKIX_ENTER(DATE, "PKIX_PL_Date_Create_CurrentOffBySeconds"); + PKIX_NULLCHECK_ONE(pDate); + + time = PR_Now() + PR_SecondsToInterval(secondsOffset); + /* create a PKIX_PL_Date object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_DATE_TYPE, + sizeof (PKIX_PL_Date), + (PKIX_PL_Object **)&date, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* populate the nssTime field */ + date->nssTime = time; + *pDate = date; + +cleanup: + PKIX_RETURN(DATE); +} + +PKIX_Error * +PKIX_PL_Date_CreateFromPRTime( + PRTime prtime, + PKIX_PL_Date **pDate, + void *plContext) +{ + PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime"); + PKIX_CHECK( + pkix_pl_Date_CreateFromPRTime(prtime, pDate, plContext), + PKIX_DATECREATEFROMPRTIMEFAILED); + +cleanup: + PKIX_RETURN(DATE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h new file mode 100644 index 0000000000..415597580a --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h @@ -0,0 +1,55 @@ +/* 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_date.h + * + * Date Object Definitions + * + */ + +#ifndef _PKIX_PL_DATE_H +#define _PKIX_PL_DATE_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_DateStruct{ + PRTime nssTime; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_Date_ToString_Helper( + SECItem *nssTime, + PKIX_PL_String **pString, + void *plContext); + +PKIX_Error *pkix_pl_Date_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_Date_GetPRTime( + PKIX_PL_Date *date, + PRTime *pPRTime, + void *plContext); + +PKIX_Error * +pkix_pl_Date_CreateFromPRTime( + PRTime prtime, + PKIX_PL_Date **pDate, + void *plContext); + +PKIX_Error * +PKIX_PL_Date_CreateFromPRTime( + PRTime prtime, + PKIX_PL_Date **pDate, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_DATE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c new file mode 100644 index 0000000000..9e9a74c783 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c @@ -0,0 +1,873 @@ +/* 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_generalname.c + * + * GeneralName Object Definitions + * + */ + +#include "pkix_pl_generalname.h" + +/* --Private-GeneralName-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_GeneralName_GetNssGeneralName + * DESCRIPTION: + * + * Retrieves the NSS representation of the PKIX_PL_GeneralName pointed by + * "genName" and stores it at "pNssGenName". The NSS data type CERTGeneralName + * is stored in this object when the object was created. + * + * PARAMETERS: + * "genName" + * Address of PKIX_PL_GeneralName. Must be non-NULL. + * "pNssGenName" + * Address where CERTGeneralName 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 GeneralName 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_GeneralName_GetNssGeneralName( + PKIX_PL_GeneralName *genName, + CERTGeneralName **pNssGenName, + void *plContext) +{ + CERTGeneralName *nssGenName = NULL; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_GetNssGeneralName"); + PKIX_NULLCHECK_THREE(genName, pNssGenName, genName->nssGeneralNameList); + + nssGenName = genName->nssGeneralNameList->name; + + *pNssGenName = nssGenName; + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_OtherName_Create + * DESCRIPTION: + * + * Creates new OtherName which represents the CERTGeneralName pointed to by + * "nssAltName" and stores it at "pOtherName". + * + * PARAMETERS: + * "nssAltName" + * Address of CERTGeneralName. Must be non-NULL. + * "pOtherName" + * 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 GeneralName 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_OtherName_Create( + CERTGeneralName *nssAltName, + OtherName **pOtherName, + void *plContext) +{ + OtherName *otherName = NULL; + SECItem secItemName; + SECItem secItemOID; + SECStatus rv; + + PKIX_ENTER(GENERALNAME, "pkix_pl_OtherName_Create"); + PKIX_NULLCHECK_TWO(nssAltName, pOtherName); + + PKIX_CHECK(PKIX_PL_Malloc + (sizeof (OtherName), (void **)&otherName, plContext), + PKIX_MALLOCFAILED); + + /* make a copy of the name field */ + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CopyItem).\n"); + rv = SECITEM_CopyItem + (NULL, &otherName->name, &nssAltName->name.OthName.name); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + /* make a copy of the oid field */ + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CopyItem).\n"); + rv = SECITEM_CopyItem + (NULL, &otherName->oid, &nssAltName->name.OthName.oid); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + *pOtherName = otherName; + +cleanup: + + if (otherName && PKIX_ERROR_RECEIVED){ + secItemName = otherName->name; + secItemOID = otherName->oid; + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&secItemName, PR_FALSE); + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&secItemOID, PR_FALSE); + + PKIX_FREE(otherName); + otherName = NULL; + } + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_DirectoryName_Create + * DESCRIPTION: + * + * Creates a new X500Name which represents the directoryName component of the + * CERTGeneralName pointed to by "nssAltName" and stores it at "pX500Name". + * + * PARAMETERS: + * "nssAltName" + * Address of CERTGeneralName. Must be non-NULL. + * "pX500Name" + * 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 GeneralName 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_DirectoryName_Create( + CERTGeneralName *nssAltName, + PKIX_PL_X500Name **pX500Name, + void *plContext) +{ + PKIX_PL_X500Name *pkixDN = NULL; + CERTName *dirName = NULL; + PKIX_PL_String *pkixDNString = NULL; + char *utf8String = NULL; + + PKIX_ENTER(GENERALNAME, "pkix_pl_DirectoryName_Create"); + PKIX_NULLCHECK_TWO(nssAltName, pX500Name); + + dirName = &nssAltName->name.directoryName; + + PKIX_CHECK(PKIX_PL_X500Name_CreateFromCERTName(NULL, dirName, + &pkixDN, plContext), + PKIX_X500NAMECREATEFROMCERTNAMEFAILED); + + *pX500Name = pkixDN; + +cleanup: + + PR_Free(utf8String); + PKIX_DECREF(pkixDNString); + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_Create + * DESCRIPTION: + * + * Creates new GeneralName which represents the CERTGeneralName pointed to by + * "nssAltName" and stores it at "pGenName". + * + * PARAMETERS: + * "nssAltName" + * Address of CERTGeneralName. Must be non-NULL. + * "pGenName" + * 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 GeneralName 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_GeneralName_Create( + CERTGeneralName *nssAltName, + PKIX_PL_GeneralName **pGenName, + void *plContext) +{ + PKIX_PL_GeneralName *genName = NULL; + PKIX_PL_X500Name *pkixDN = NULL; + PKIX_PL_OID *pkixOID = NULL; + OtherName *otherName = NULL; + CERTGeneralNameList *nssGenNameList = NULL; + CERTGeneralNameType nameType; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Create"); + PKIX_NULLCHECK_TWO(nssAltName, pGenName); + + /* create a PKIX_PL_GeneralName object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_GENERALNAME_TYPE, + sizeof (PKIX_PL_GeneralName), + (PKIX_PL_Object **)&genName, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + nameType = nssAltName->type; + + /* + * We use CERT_CreateGeneralNameList to create just one CERTGeneralName + * item for memory allocation reason. If we want to just create one + * item, we have to use the calling path CERT_NewGeneralName, then + * CERT_CopyOneGeneralName. With this calling path, if we pass + * the arena argument as NULL, in CERT_CopyOneGeneralName's subsequent + * call to CERT_CopyName, it assumes arena should be valid, hence + * segmentation error (not sure this is a NSS bug, certainly it is + * not consistent). But on the other hand, we don't want to keep an + * arena record here explicitely for every PKIX_PL_GeneralName. + * So I concluded it is better to use CERT_CreateGeneralNameList, + * which keeps an arena pointer in its data structure and also masks + * out details calls from this libpkix level. + */ + + PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_CreateGeneralNameList).\n"); + nssGenNameList = CERT_CreateGeneralNameList(nssAltName); + + if (nssGenNameList == NULL) { + PKIX_ERROR(PKIX_CERTCREATEGENERALNAMELISTFAILED); + } + + genName->nssGeneralNameList = nssGenNameList; + + /* initialize fields */ + genName->type = nameType; + genName->directoryName = NULL; + genName->OthName = NULL; + genName->other = NULL; + genName->oid = NULL; + + switch (nameType){ + case certOtherName: + + PKIX_CHECK(pkix_pl_OtherName_Create + (nssAltName, &otherName, plContext), + PKIX_OTHERNAMECREATEFAILED); + + genName->OthName = otherName; + break; + + case certDirectoryName: + + PKIX_CHECK(pkix_pl_DirectoryName_Create + (nssAltName, &pkixDN, plContext), + PKIX_DIRECTORYNAMECREATEFAILED); + + genName->directoryName = pkixDN; + break; + case certRegisterID: + PKIX_CHECK(PKIX_PL_OID_CreateBySECItem(&nssAltName->name.other, + &pkixOID, plContext), + PKIX_OIDCREATEFAILED); + + genName->oid = pkixOID; + break; + case certDNSName: + case certEDIPartyName: + case certIPAddress: + case certRFC822Name: + case certX400Address: + case certURI: + genName->other = SECITEM_DupItem(&nssAltName->name.other); + if (!genName->other) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + break; + default: + PKIX_ERROR(PKIX_NAMETYPENOTSUPPORTED); + } + + *pGenName = genName; + genName = NULL; + +cleanup: + PKIX_DECREF(genName); + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the GeneralName + * pointed to by "name" and stores it at "pString" Different mechanisms are + * used to create the string, depending on the type of the GeneralName. + * + * PARAMETERS + * "name" + * Address of GeneralName whose string representation is desired. + * Must be non-NULL. + * "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 GeneralName 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_GeneralName_ToString_Helper( + PKIX_PL_GeneralName *name, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_X500Name *pkixDN = NULL; + PKIX_PL_OID *pkixOID = NULL; + char *x400AsciiName = NULL; + char *ediPartyName = NULL; + char *asciiName = NULL; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_ToString_Helper"); + PKIX_NULLCHECK_TWO(name, pString); + + switch (name->type) { + case certRFC822Name: + case certDNSName: + case certURI: + /* + * Note that we can't use PKIX_ESCASCII here because + * name->other->data is not guaranteed to be null-terminated. + */ + + PKIX_NULLCHECK_ONE(name->other); + + PKIX_CHECK(PKIX_PL_String_Create(PKIX_UTF8, + (name->other)->data, + (name->other)->len, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certEDIPartyName: + /* XXX print out the actual bytes */ + ediPartyName = "EDIPartyName: <DER-encoded value>"; + PKIX_CHECK(PKIX_PL_String_Create(PKIX_ESCASCII, + ediPartyName, + 0, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certX400Address: + /* XXX print out the actual bytes */ + x400AsciiName = "X400Address: <DER-encoded value>"; + PKIX_CHECK(PKIX_PL_String_Create(PKIX_ESCASCII, + x400AsciiName, + 0, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certIPAddress: + PKIX_CHECK(pkix_pl_ipAddrBytes2Ascii + (name->other, &asciiName, plContext), + PKIX_IPADDRBYTES2ASCIIFAILED); + + PKIX_CHECK(PKIX_PL_String_Create(PKIX_ESCASCII, + asciiName, + 0, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certOtherName: + PKIX_NULLCHECK_ONE(name->OthName); + + /* we only print type-id - don't know how to print value */ + /* XXX print out the bytes of the value */ + PKIX_CHECK(pkix_pl_oidBytes2Ascii + (&name->OthName->oid, &asciiName, plContext), + PKIX_OIDBYTES2ASCIIFAILED); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiName, + 0, + pString, + plContext), + PKIX_STRINGCREATEFAILED); + break; + case certRegisterID: + pkixOID = name->oid; + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)pkixOID, pString, plContext), + PKIX_OIDTOSTRINGFAILED); + break; + case certDirectoryName: + pkixDN = name->directoryName; + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object *)pkixDN, pString, plContext), + PKIX_X500NAMETOSTRINGFAILED); + break; + default: + PKIX_ERROR + (PKIX_TOSTRINGFORTHISGENERALNAMETYPENOTSUPPORTED); + } + +cleanup: + + PKIX_FREE(asciiName); + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_GeneralName_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_GeneralName *name = NULL; + SECItem secItemName; + SECItem secItemOID; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_GENERALNAME_TYPE, plContext), + PKIX_OBJECTNOTGENERALNAME); + + name = (PKIX_PL_GeneralName *)object; + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(name->other, PR_TRUE); + name->other = NULL; + + if (name->OthName){ + secItemName = name->OthName->name; + secItemOID = name->OthName->oid; + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&secItemName, PR_FALSE); + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&secItemOID, PR_FALSE); + + PKIX_FREE(name->OthName); + name->OthName = NULL; + } + + if (name->nssGeneralNameList != NULL) { + PKIX_GENERALNAME_DEBUG + ("\t\tCalling CERT_DestroyGeneralNameList).\n"); + CERT_DestroyGeneralNameList(name->nssGeneralNameList); + } + + PKIX_DECREF(name->directoryName); + PKIX_DECREF(name->oid); + +cleanup: + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_GeneralName_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *nameString = NULL; + PKIX_PL_GeneralName *name = NULL; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_GENERALNAME_TYPE, plContext), + PKIX_OBJECTNOTGENERALNAME); + + name = (PKIX_PL_GeneralName *)object; + + PKIX_CHECK(pkix_pl_GeneralName_ToString_Helper + (name, &nameString, plContext), + PKIX_GENERALNAMETOSTRINGHELPERFAILED); + + *pString = nameString; + +cleanup: + + + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_GeneralName_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_GeneralName *name = NULL; + PKIX_UInt32 firstHash, secondHash, nameHash; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_GENERALNAME_TYPE, plContext), + PKIX_OBJECTNOTGENERALNAME); + + name = (PKIX_PL_GeneralName *)object; + + switch (name->type) { + case certRFC822Name: + case certDNSName: + case certX400Address: + case certEDIPartyName: + case certURI: + case certIPAddress: + PKIX_NULLCHECK_ONE(name->other); + PKIX_CHECK(pkix_hash + ((const unsigned char *) + name->other->data, + name->other->len, + &nameHash, + plContext), + PKIX_HASHFAILED); + break; + case certRegisterID: + PKIX_CHECK(PKIX_PL_Object_Hashcode + ((PKIX_PL_Object *)name->oid, + &nameHash, + plContext), + PKIX_OIDHASHCODEFAILED); + break; + case certOtherName: + PKIX_NULLCHECK_ONE(name->OthName); + PKIX_CHECK(pkix_hash + ((const unsigned char *) + name->OthName->oid.data, + name->OthName->oid.len, + &firstHash, + plContext), + PKIX_HASHFAILED); + + PKIX_CHECK(pkix_hash + ((const unsigned char *) + name->OthName->name.data, + name->OthName->name.len, + &secondHash, + plContext), + PKIX_HASHFAILED); + + nameHash = firstHash + secondHash; + break; + case certDirectoryName: + PKIX_CHECK(PKIX_PL_Object_Hashcode + ((PKIX_PL_Object *) + name->directoryName, + &nameHash, + plContext), + PKIX_X500NAMEHASHCODEFAILED); + break; + } + + *pHashcode = nameHash; + +cleanup: + + PKIX_RETURN(GENERALNAME); + +} + +/* + * FUNCTION: pkix_pl_GeneralName_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_GeneralName_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_GeneralName *firstName = NULL; + PKIX_PL_GeneralName *secondName = NULL; + PKIX_UInt32 secondType; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a GeneralName */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_GENERALNAME_TYPE, plContext), + PKIX_FIRSTOBJECTNOTGENERALNAME); + + /* + * Since we know firstObject is a GeneralName, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a GeneralName, 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_GENERALNAME_TYPE){ + goto cleanup; + } + + firstName = (PKIX_PL_GeneralName *)firstObject; + secondName = (PKIX_PL_GeneralName *)secondObject; + + if (firstName->type != secondName->type){ + goto cleanup; + } + + switch (firstName->type) { + case certRFC822Name: + case certDNSName: + case certX400Address: + case certEDIPartyName: + case certURI: + case certIPAddress: + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); + if (SECITEM_CompareItem(firstName->other, + secondName->other) != SECEqual) { + goto cleanup; + } + break; + case certRegisterID: + PKIX_CHECK(PKIX_PL_Object_Equals + ((PKIX_PL_Object *)firstName->oid, + (PKIX_PL_Object *)secondName->oid, + pResult, + plContext), + PKIX_OIDEQUALSFAILED); + goto cleanup; + case certOtherName: + PKIX_NULLCHECK_TWO(firstName->OthName, secondName->OthName); + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); + if (SECITEM_CompareItem(&firstName->OthName->oid, + &secondName->OthName->oid) + != SECEqual || + SECITEM_CompareItem(&firstName->OthName->name, + &secondName->OthName->name) + != SECEqual) { + goto cleanup; + } + break; + case certDirectoryName: + PKIX_CHECK(PKIX_PL_Object_Equals + ((PKIX_PL_Object *)firstName->directoryName, + (PKIX_PL_Object *)secondName->directoryName, + pResult, + plContext), + PKIX_X500NAMEEQUALSFAILED); + goto cleanup; + } + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(GENERALNAME); +} + +/* + * FUNCTION: pkix_pl_GeneralName_RegisterSelf + * DESCRIPTION: + * Registers PKIX_GENERALNAME_TYPE and 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_GeneralName_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_RegisterSelf"); + + entry.description = "GeneralName"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_GeneralName); + entry.destructor = pkix_pl_GeneralName_Destroy; + entry.equalsFunction = pkix_pl_GeneralName_Equals; + entry.hashcodeFunction = pkix_pl_GeneralName_Hashcode; + entry.toStringFunction = pkix_pl_GeneralName_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_GENERALNAME_TYPE] = entry; + + PKIX_RETURN(GENERALNAME); +} + +/* --Public-Functions------------------------------------------------------- */ + +#ifdef BUILD_LIBPKIX_TESTS +/* + * FUNCTION: PKIX_PL_GeneralName_Create (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_GeneralName_Create( + PKIX_UInt32 nameType, + PKIX_PL_String *stringRep, + PKIX_PL_GeneralName **pGName, + void *plContext) +{ + PKIX_PL_X500Name *pkixDN = NULL; + PKIX_PL_OID *pkixOID = NULL; + SECItem *secItem = NULL; + char *asciiString = NULL; + PKIX_UInt32 length = 0; + PKIX_PL_GeneralName *genName = NULL; + CERTGeneralName *nssGenName = NULL; + CERTGeneralNameList *nssGenNameList = NULL; + CERTName *nssCertName = NULL; + PLArenaPool *arena = NULL; + + PKIX_ENTER(GENERALNAME, "PKIX_PL_GeneralName_Create"); + PKIX_NULLCHECK_TWO(pGName, stringRep); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stringRep, + PKIX_ESCASCII, + (void **)&asciiString, + &length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + /* Create a temporary CERTGeneralName */ + PKIX_GENERALNAME_DEBUG("\t\tCalling PL_strlen).\n"); + length = PL_strlen(asciiString); + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_AllocItem).\n"); + secItem = SECITEM_AllocItem(NULL, NULL, length); + PKIX_GENERALNAME_DEBUG("\t\tCalling PORT_Memcpy).\n"); + (void) PORT_Memcpy(secItem->data, asciiString, length); + PKIX_CERT_DEBUG("\t\tCalling PORT_NewArena).\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_NewGeneralName).\n"); + nssGenName = CERT_NewGeneralName(arena, nameType); + if (nssGenName == NULL) { + PKIX_ERROR(PKIX_ALLOCATENEWCERTGENERALNAMEFAILED); + } + + switch (nameType) { + case certRFC822Name: + case certDNSName: + case certURI: + nssGenName->name.other = *secItem; + break; + + case certDirectoryName: + + PKIX_CHECK(PKIX_PL_X500Name_Create + (stringRep, &pkixDN, plContext), + PKIX_X500NAMECREATEFAILED); + + PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_AsciiToName).\n"); + nssCertName = CERT_AsciiToName(asciiString); + nssGenName->name.directoryName = *nssCertName; + break; + + case certRegisterID: + PKIX_CHECK(PKIX_PL_OID_Create + (asciiString, &pkixOID, plContext), + PKIX_OIDCREATEFAILED); + nssGenName->name.other = *secItem; + break; + default: + /* including IPAddress, EDIPartyName, OtherName, X400Address */ + PKIX_ERROR(PKIX_UNABLETOCREATEGENERALNAMEOFTHISTYPE); + } + + /* create a PKIX_PL_GeneralName object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_GENERALNAME_TYPE, + sizeof (PKIX_PL_GeneralName), + (PKIX_PL_Object **)&genName, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* create a CERTGeneralNameList */ + nssGenName->type = nameType; + PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_CreateGeneralNameList).\n"); + nssGenNameList = CERT_CreateGeneralNameList(nssGenName); + if (nssGenNameList == NULL) { + PKIX_ERROR(PKIX_CERTCREATEGENERALNAMELISTFAILED); + } + genName->nssGeneralNameList = nssGenNameList; + + /* initialize fields */ + genName->type = nameType; + genName->directoryName = pkixDN; + genName->OthName = NULL; + genName->other = secItem; + genName->oid = pkixOID; + + *pGName = genName; +cleanup: + + PKIX_FREE(asciiString); + + if (nssCertName != NULL) { + PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyName).\n"); + CERT_DestroyName(nssCertName); + } + + if (arena){ /* will free nssGenName */ + PKIX_CERT_DEBUG("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(pkixDN); + PKIX_DECREF(pkixOID); + + PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + if (secItem){ + SECITEM_FreeItem(secItem, PR_TRUE); + secItem = NULL; + } + } + + PKIX_RETURN(GENERALNAME); +} + +#endif /* BUILD_LIBPKIX_TESTS */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h new file mode 100644 index 0000000000..3cb5264d51 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h @@ -0,0 +1,49 @@ +/* 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_generalname.h + * + * GeneralName Object Definitions + * + */ + +#ifndef _PKIX_PL_GENERALNAME_H +#define _PKIX_PL_GENERALNAME_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_GeneralNameStruct{ + CERTGeneralNameList *nssGeneralNameList; + CERTGeneralNameType type; + PKIX_PL_X500Name *directoryName; + PKIX_PL_OID *oid; + OtherName *OthName; + SECItem *other; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_GeneralName_Create( + CERTGeneralName *nssAltName, + PKIX_PL_GeneralName **pGenName, + void *plContext); + +PKIX_Error * +pkix_pl_GeneralName_GetNssGeneralName( + PKIX_PL_GeneralName *genName, + CERTGeneralName **pNssGenName, + void *plContext); + +PKIX_Error *pkix_pl_GeneralName_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_GENERALNAME_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c new file mode 100644 index 0000000000..09b54a2be3 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c @@ -0,0 +1,874 @@ +/* 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_infoaccess.c + * + * InfoAccess Object Definitions + * + */ + +#include "pkix_pl_infoaccess.h" + +/* --Private-InfoAccess-Functions----------------------------------*/ + +/* + * FUNCTION: pkix_pl_InfoAccess_Create + * DESCRIPTION: + * + * This function creates an InfoAccess from the method provided in "method" and + * the GeneralName provided in "generalName" and stores the result at + * "pInfoAccess". + * + * PARAMETERS + * "method" + * The UInt32 value to be stored as the method field of the InfoAccess. + * "gName" + * The GeneralName to be stored as the gName field of the InfoAccess. + * Must be non-NULL. + * "pInfoAccess" + * Address where the result 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 Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_InfoAccess_Create( + PKIX_UInt32 method, + PKIX_PL_GeneralName *gName, + PKIX_PL_InfoAccess **pInfoAccess, + void *plContext) +{ + + PKIX_PL_InfoAccess *infoAccess = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Create"); + PKIX_NULLCHECK_TWO(gName, pInfoAccess); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_INFOACCESS_TYPE, + sizeof (PKIX_PL_InfoAccess), + (PKIX_PL_Object **)&infoAccess, + plContext), + PKIX_COULDNOTCREATEINFOACCESSOBJECT); + + infoAccess->method = method; + + PKIX_INCREF(gName); + infoAccess->location = gName; + + *pInfoAccess = infoAccess; + infoAccess = NULL; + +cleanup: + PKIX_DECREF(infoAccess); + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h) + */ +static PKIX_Error * +pkix_pl_InfoAccess_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_InfoAccess *infoAccess = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_INFOACCESS_TYPE, plContext), + PKIX_OBJECTNOTANINFOACCESS); + + infoAccess = (PKIX_PL_InfoAccess *)object; + + PKIX_DECREF(infoAccess->location); + +cleanup: + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_pki.h) + */ +static PKIX_Error * +pkix_pl_InfoAccess_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_InfoAccess *infoAccess; + PKIX_PL_String *infoAccessString = NULL; + char *asciiFormat = NULL; + char *asciiMethod = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *methodString = NULL; + PKIX_PL_String *locationString = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_INFOACCESS_TYPE, plContext), + PKIX_OBJECTNOTINFOACCESS); + + infoAccess = (PKIX_PL_InfoAccess *)object; + + asciiFormat = + "[" + "method:%s, " + "location:%s" + "]"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + switch(infoAccess->method) { + case PKIX_INFOACCESS_CA_ISSUERS: + asciiMethod = "caIssuers"; + break; + case PKIX_INFOACCESS_OCSP: + asciiMethod = "ocsp"; + break; + case PKIX_INFOACCESS_TIMESTAMPING: + asciiMethod = "timestamping"; + break; + case PKIX_INFOACCESS_CA_REPOSITORY: + asciiMethod = "caRepository"; + break; + default: + asciiMethod = "unknown"; + } + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiMethod, + 0, + &methodString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_TOSTRING(infoAccess->location, &locationString, plContext, + PKIX_GENERALNAMETOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&infoAccessString, + plContext, + formatString, + methodString, + locationString), + PKIX_SPRINTFFAILED); + + *pString = infoAccessString; + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(methodString); + PKIX_DECREF(locationString); + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_pki.h) + */ +static PKIX_Error * +pkix_pl_InfoAccess_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_InfoAccess *infoAccess = NULL; + PKIX_UInt32 infoAccessHash; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_INFOACCESS_TYPE, plContext), + PKIX_OBJECTNOTINFOACCESS); + + infoAccess = (PKIX_PL_InfoAccess *)object; + + PKIX_HASHCODE(infoAccess->location, &infoAccessHash, plContext, + PKIX_OBJECTHASHCODEFAILED); + + infoAccessHash += (infoAccess->method << 7); + + *pHashcode = infoAccessHash; + +cleanup: + + PKIX_RETURN(INFOACCESS); + +} + +/* + * FUNCTION: pkix_pl_InfoAccess_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_pki.h) + */ +static PKIX_Error * +pkix_pl_InfoAccess_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_InfoAccess *firstInfoAccess = NULL; + PKIX_PL_InfoAccess *secondInfoAccess = NULL; + PKIX_UInt32 secondType; + PKIX_Boolean cmpResult; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a InfoAccess */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_INFOACCESS_TYPE, plContext), + PKIX_FIRSTOBJECTNOTINFOACCESS); + + /* + * Since we know firstObject is a InfoAccess, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a InfoAccess, 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_INFOACCESS_TYPE) goto cleanup; + + firstInfoAccess = (PKIX_PL_InfoAccess *)firstObject; + secondInfoAccess = (PKIX_PL_InfoAccess *)secondObject; + + *pResult = PKIX_FALSE; + + if (firstInfoAccess->method != secondInfoAccess->method) { + goto cleanup; + } + + PKIX_EQUALS(firstInfoAccess, secondInfoAccess, &cmpResult, plContext, + PKIX_OBJECTEQUALSFAILED); + + *pResult = cmpResult; + +cleanup: + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_RegisterSelf + * DESCRIPTION: + * Registers PKIX_INFOACCESS_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_InfoAccess_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(INFOACCESS, + "pkix_pl_InfoAccess_RegisterSelf"); + + entry.description = "InfoAccess"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_InfoAccess); + entry.destructor = pkix_pl_InfoAccess_Destroy; + entry.equalsFunction = pkix_pl_InfoAccess_Equals; + entry.hashcodeFunction = pkix_pl_InfoAccess_Hashcode; + entry.toStringFunction = pkix_pl_InfoAccess_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_INFOACCESS_TYPE] = entry; + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: pkix_pl_InfoAccess_CreateList + * DESCRIPTION: + * + * Based on data in CERTAuthInfoAccess array "nssInfoAccess", this function + * creates and returns a PKIX_List of PKIX_PL_InfoAccess at "pInfoAccessList". + * + * PARAMETERS + * "nssInfoAccess" + * The pointer array of CERTAuthInfoAccess that contains access data. + * May be NULL. + * "pInfoAccessList" + * Address where a list of PKIX_PL_InfoAccess is returned. + * 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. + */ +PKIX_Error * +pkix_pl_InfoAccess_CreateList( + CERTAuthInfoAccess **nssInfoAccess, + PKIX_List **pInfoAccessList, /* of PKIX_PL_InfoAccess */ + void *plContext) +{ + PKIX_List *infoAccessList = NULL; + PKIX_PL_InfoAccess *infoAccess = NULL; + PKIX_PL_GeneralName *location = NULL; + PKIX_UInt32 method; + int i; + + PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_CreateList"); + PKIX_NULLCHECK_ONE(pInfoAccessList); + + PKIX_CHECK(PKIX_List_Create(&infoAccessList, plContext), + PKIX_LISTCREATEFAILED); + + if (nssInfoAccess == NULL) { + goto cleanup; + } + + for (i = 0; nssInfoAccess[i] != NULL; i++) { + + if (nssInfoAccess[i]->location == NULL) { + continue; + } + + PKIX_CHECK(pkix_pl_GeneralName_Create + (nssInfoAccess[i]->location, &location, plContext), + PKIX_GENERALNAMECREATEFAILED); + + PKIX_CERT_DEBUG("\t\tCalling SECOID_FindOIDTag).\n"); + method = SECOID_FindOIDTag(&nssInfoAccess[i]->method); + /* Map NSS access method value into PKIX constant */ + switch(method) { + case SEC_OID_PKIX_CA_ISSUERS: + method = PKIX_INFOACCESS_CA_ISSUERS; + break; + case SEC_OID_PKIX_OCSP: + method = PKIX_INFOACCESS_OCSP; + break; + case SEC_OID_PKIX_TIMESTAMPING: + method = PKIX_INFOACCESS_TIMESTAMPING; + break; + case SEC_OID_PKIX_CA_REPOSITORY: + method = PKIX_INFOACCESS_CA_REPOSITORY; + break; + default: + PKIX_ERROR(PKIX_UNKNOWNINFOACCESSMETHOD); + } + + PKIX_CHECK(pkix_pl_InfoAccess_Create + (method, location, &infoAccess, plContext), + PKIX_INFOACCESSCREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (infoAccessList, + (PKIX_PL_Object *)infoAccess, + plContext), + PKIX_LISTAPPENDITEMFAILED); + PKIX_DECREF(infoAccess); + PKIX_DECREF(location); + } + + *pInfoAccessList = infoAccessList; + infoAccessList = NULL; + +cleanup: + + PKIX_DECREF(infoAccessList); + PKIX_DECREF(infoAccess); + PKIX_DECREF(location); + + PKIX_RETURN(INFOACCESS); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_InfoAccess_GetMethod (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_InfoAccess_GetMethod( + PKIX_PL_InfoAccess *infoAccess, + PKIX_UInt32 *pMethod, + void *plContext) +{ + PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetMethod"); + PKIX_NULLCHECK_TWO(infoAccess, pMethod); + + *pMethod = infoAccess->method; + + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: PKIX_PL_InfoAccess_GetLocation (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_InfoAccess_GetLocation( + PKIX_PL_InfoAccess *infoAccess, + PKIX_PL_GeneralName **pLocation, + void *plContext) +{ + PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocation"); + PKIX_NULLCHECK_TWO(infoAccess, pLocation); + + PKIX_INCREF(infoAccess->location); + + *pLocation = infoAccess->location; + +cleanup: + PKIX_RETURN(INFOACCESS); +} + +/* + * FUNCTION: PKIX_PL_InfoAccess_GetLocationType (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_InfoAccess_GetLocationType( + PKIX_PL_InfoAccess *infoAccess, + PKIX_UInt32 *pType, + void *plContext) +{ + PKIX_PL_String *locationString = NULL; + PKIX_UInt32 type = PKIX_INFOACCESS_LOCATION_UNKNOWN; + PKIX_UInt32 len = 0; + void *location = NULL; + + PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocationType"); + PKIX_NULLCHECK_TWO(infoAccess, pType); + + if (infoAccess->location != NULL) { + + PKIX_TOSTRING(infoAccess->location, &locationString, plContext, + PKIX_GENERALNAMETOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (locationString, PKIX_ESCASCII, &location, &len, plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n"); +#ifndef NSS_PKIX_NO_LDAP + if (PORT_Strncmp(location, "ldap:", 5) == 0){ + type = PKIX_INFOACCESS_LOCATION_LDAP; + } else +#endif + if (PORT_Strncmp(location, "http:", 5) == 0){ + type = PKIX_INFOACCESS_LOCATION_HTTP; + } + } + + *pType = type; + +cleanup: + + PKIX_PL_Free(location, plContext); + PKIX_DECREF(locationString); + + PKIX_RETURN(INFOACCESS); +} + +#ifndef NSS_PKIX_NO_LDAP +/* + * FUNCTION: pkix_pl_InfoAccess_ParseTokens + * DESCRIPTION: + * + * This function parses the string beginning at "startPos" into tokens using + * the separator contained in "separator" and the terminator contained in + * "terminator", copying the tokens into space allocated from the arena + * pointed to by "arena". It stores in "tokens" a null-terminated array of + * pointers to those tokens. + * + * PARAMETERS + * "arena" + * Address of a PLArenaPool to be used in populating the LDAPLocation. + * Must be non-NULL. + * "startPos" + * The address of char string that contains a subset of ldap location. + * "tokens" + * The address of an array of char string for storing returned tokens. + * Must be non-NULL. + * "separator" + * The character that is taken as token separator. Must be non-NULL. + * "terminator" + * The character that is taken as parsing terminator. 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 an InfoAccess 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_InfoAccess_ParseTokens( + PLArenaPool *arena, + char **startPos, /* return update */ + char ***tokens, + char separator, + char terminator, + void *plContext) +{ + PKIX_UInt32 numFilters = 0; + char *endPos = NULL; + char **filterP = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseTokens"); + PKIX_NULLCHECK_THREE(arena, startPos, tokens); + + endPos = *startPos; + + /* First pass: parse to <terminator> to count number of components */ + numFilters = 0; + while (*endPos != terminator && *endPos != '\0') { + endPos++; + if (*endPos == separator) { + numFilters++; + } + } + + if (*endPos != terminator) { + PKIX_ERROR(PKIX_LOCATIONSTRINGNOTPROPERLYTERMINATED); + } + + /* Last component doesn't need a separator, although we allow it */ + if (endPos > *startPos && *(endPos-1) != separator) { + numFilters++; + } + + /* + * If string is a=xx, b=yy, c=zz, etc., use a=xx for filter, + * and everything else for the base + */ + if (numFilters > 2) numFilters = 2; + + filterP = PORT_ArenaZNewArray(arena, char*, numFilters+1); + if (filterP == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + /* Second pass: parse to fill in components in token array */ + *tokens = filterP; + endPos = *startPos; + + while (numFilters) { + if (*endPos == separator || *endPos == terminator) { + PKIX_UInt32 len = endPos - *startPos; + char *p = PORT_ArenaZAlloc(arena, len+1); + if (p == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PORT_Memcpy(p, *startPos, len); + p[len] = '\0'; + + *filterP = p; + filterP++; + numFilters--; + + separator = terminator; + + if (*endPos == '\0') { + *startPos = endPos; + break; + } else { + endPos++; + *startPos = endPos; + continue; + } + } + endPos++; + } + + *filterP = NULL; + +cleanup: + + PKIX_RETURN(INFOACCESS); +} + +static int +pkix_pl_HexDigitToInt( + int ch) +{ + if (isdigit(ch)) { + ch = ch - '0'; + } else if (isupper(ch)) { + ch = ch - 'A' + 10; + } else { + ch = ch - 'a' + 10; + } + return ch; +} + +/* + * Convert the "%" hex hex escape sequences in the URL 'location' in place. + */ +static void +pkix_pl_UnescapeURL( + char *location) +{ + const char *src; + char *dst; + + for (src = dst = location; *src != '\0'; src++, dst++) { + if (*src == '%' && isxdigit((unsigned char)*(src+1)) && + isxdigit((unsigned char)*(src+2))) { + *dst = pkix_pl_HexDigitToInt((unsigned char)*(src+1)); + *dst *= 16; + *dst += pkix_pl_HexDigitToInt((unsigned char)*(src+2)); + src += 2; + } else { + *dst = *src; + } + } + *dst = *src; /* the terminating null */ +} + +/* + * FUNCTION: pkix_pl_InfoAccess_ParseLocation + * DESCRIPTION: + * + * This function parses the GeneralName pointed to by "generalName" into the + * fields of the LDAPRequestParams pointed to by "request" and a domainName + * pointed to by "pDomainName", using the PLArenaPool pointed to by "arena" to + * allocate storage for the request components and for the domainName string. + * + * The expected GeneralName string should be in the format described by the + * following BNF: + * + * ldap://<ldap-server-site>/[cn=<cname>][,o=<org>][,c=<country>]? + * [caCertificate|crossCertificatPair|certificateRevocationList]; + * [binary|<other-type>] + * [[,caCertificate|crossCertificatPair|certificateRevocationList] + * [binary|<other-type>]]* + * + * PARAMETERS + * "gName" + * Address of the GeneralName whose LDAPLocation is to be parsed. Must be + * non-NULL. + * "arena" + * Address of PLArenaPool to be used for the domainName and for components + * of the LDAPRequest. Must be non-NULL. + * "request" + * Address of the LDAPRequestParams into which request components are + * stored. Must be non-NULL. + * *pDomainName" + * Address at which the domainName 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 an InfoAccess 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_InfoAccess_ParseLocation( + PKIX_PL_GeneralName *gName, + PLArenaPool *arena, + LDAPRequestParams *request, + char **pDomainName, + void *plContext) +{ + PKIX_PL_String *locationString = NULL; + PKIX_UInt32 len = 0; + PKIX_UInt32 ncIndex = 0; + char *domainName = NULL; + char **avaArray = NULL; + char **attrArray = NULL; + char *attr = NULL; + char *locationAscii = NULL; + char *startPos = NULL; + char *endPos = NULL; + char *avaPtr = NULL; + LdapAttrMask attrBit = 0; + LDAPNameComponent **setOfNameComponent = NULL; + LDAPNameComponent *nameComponent = NULL; + + PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseLocation"); + PKIX_NULLCHECK_FOUR(gName, arena, request, pDomainName); + + PKIX_TOSTRING(gName, &locationString, plContext, + PKIX_GENERALNAMETOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (locationString, + PKIX_ESCASCII, + (void **)&locationAscii, + &len, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + pkix_pl_UnescapeURL(locationAscii); + + /* Skip "ldap:" */ + endPos = locationAscii; + while (*endPos != ':' && *endPos != '\0') { + endPos++; + } + if (*endPos == '\0') { + PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGLOCATIONTYPE); + } + + /* Skip "//" */ + endPos++; + if (*endPos != '\0' && *(endPos+1) != '0' && + *endPos == '/' && *(endPos+1) == '/') { + endPos += 2; + } else { + PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGDOUBLESLASH); + } + + /* Get the server-site */ + startPos = endPos; + while(*endPos != '/' && *(endPos) != '\0') { + endPos++; + } + if (*endPos == '\0') { + PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGSERVERSITE); + } + + len = endPos - startPos; + endPos++; + + domainName = PORT_ArenaZAlloc(arena, len + 1); + if (!domainName) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + PORT_Memcpy(domainName, startPos, len); + + domainName[len] = '\0'; + + *pDomainName = domainName; + + /* + * Get a list of AttrValueAssertions (such as + * "cn=CommonName, o=Organization, c=US" into a null-terminated array + */ + startPos = endPos; + PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens + (arena, + &startPos, + (char ***) &avaArray, + ',', + '?', + plContext), + PKIX_INFOACCESSPARSETOKENSFAILED); + + /* Count how many AVAs we have */ + for (len = 0; avaArray[len] != NULL; len++) {} + + if (len < 2) { + PKIX_ERROR(PKIX_NOTENOUGHNAMECOMPONENTSINGENERALNAME); + } + + /* Use last name component for baseObject */ + request->baseObject = avaArray[len - 1]; + + /* Use only one component for filter. LDAP servers aren't too smart. */ + len = 2; /* Eliminate this when servers get smarter. */ + + avaArray[len - 1] = NULL; + + /* Get room for null-terminated array of (LdapNameComponent *) */ + setOfNameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent *, len); + if (setOfNameComponent == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + /* Get room for the remaining LdapNameComponents */ + nameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent, --len); + if (nameComponent == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + /* Convert remaining AVAs to LDAPNameComponents */ + for (ncIndex = 0; ncIndex < len; ncIndex ++) { + setOfNameComponent[ncIndex] = nameComponent; + avaPtr = avaArray[ncIndex]; + nameComponent->attrType = (unsigned char *)avaPtr; + while ((*avaPtr != '=') && (*avaPtr != '\0')) { + avaPtr++; + if (*avaPtr == '\0') { + PKIX_ERROR(PKIX_NAMECOMPONENTWITHNOEQ); + } + } + *(avaPtr++) = '\0'; + nameComponent->attrValue = (unsigned char *)avaPtr; + nameComponent++; + } + + setOfNameComponent[len] = NULL; + request->nc = setOfNameComponent; + + /* + * Get a list of AttrTypes (such as + * "caCertificate;binary, crossCertificatePair;binary") into + * a null-terminated array + */ + + PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens + (arena, + (char **) &startPos, + (char ***) &attrArray, + ',', + '\0', + plContext), + PKIX_INFOACCESSPARSETOKENSFAILED); + + /* Convert array of Attr Types into a bit mask */ + request->attributes = 0; + attr = attrArray[0]; + while (attr != NULL) { + PKIX_CHECK(pkix_pl_LdapRequest_AttrStringToBit + (attr, &attrBit, plContext), + PKIX_LDAPREQUESTATTRSTRINGTOBITFAILED); + request->attributes |= attrBit; + attr = *(++attrArray); + } + +cleanup: + + PKIX_PL_Free(locationAscii, plContext); + PKIX_DECREF(locationString); + + PKIX_RETURN(INFOACCESS); +} +#endif /* !NSS_PKIX_NO_LDAP */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h new file mode 100644 index 0000000000..e69d7b4139 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h @@ -0,0 +1,49 @@ +/* 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_infoaccess.h + * + * InfoAccess Object Definitions + * + */ + +#ifndef _PKIX_PL_INFOACCESS_H +#define _PKIX_PL_INFOACCESS_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_InfoAccessStruct{ + PKIX_UInt32 method; + PKIX_PL_GeneralName *location; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_InfoAccess_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_InfoAccess_CreateList( + CERTAuthInfoAccess **authInfoAccess, + PKIX_List **pAiaList, /* of PKIX_PL_InfoAccess */ + void *plContext); + +#ifndef NSS_PKIX_NO_LDAP +PKIX_Error * +pkix_pl_InfoAccess_ParseLocation( + PKIX_PL_GeneralName *generalName, + PLArenaPool *arena, + LDAPRequestParams *request, + char **pDomainName, + void *plContext); +#endif /* !NSS_PKIX_NO_LDAP */ + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_INFOACCESS_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c new file mode 100644 index 0000000000..1d0b61bb44 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c @@ -0,0 +1,1279 @@ +/* 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_nameconstraints.c + * + * Name Constraints Object Functions Definitions + * + */ + +#include "pkix_pl_nameconstraints.h" + + +/* --Private-NameConstraints-Functions----------------------------- */ + +/* + * FUNCTION: pkix_pl_CertNameConstraints_GetPermitted + * DESCRIPTION: + * + * This function retrieve name constraints permitted list from NSS + * data in "nameConstraints" and returns a PKIX_PL_GeneralName list + * in "pPermittedList". + * + * PARAMETERS + * "nameConstraints" + * Address of CertNameConstraints which has a pointer to + * CERTNameConstraints data. Must be non-NULL. + * "pPermittedList" + * Address where returned permitted name list is stored. Must be non-NULL. + * "plContext" - Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a NameConstraints 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_CertNameConstraints_GetPermitted( + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_List **pPermittedList, + void *plContext) +{ + CERTNameConstraints *nssNameConstraints = NULL; + CERTNameConstraints **nssNameConstraintsList = NULL; + CERTNameConstraint *nssPermitted = NULL; + CERTNameConstraint *firstPermitted = NULL; + PKIX_List *permittedList = NULL; + PKIX_PL_GeneralName *name = NULL; + PKIX_UInt32 numItems = 0; + PKIX_UInt32 i; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_GetPermitted"); + PKIX_NULLCHECK_TWO(nameConstraints, pPermittedList); + + /* + * nssNameConstraints is an array of CERTNameConstraints + * pointers where CERTNameConstraints keep its permitted and excluded + * lists as pointer array of CERTNameConstraint. + */ + + if (nameConstraints->permittedList == NULL) { + + PKIX_OBJECT_LOCK(nameConstraints); + + if (nameConstraints->permittedList == NULL) { + + PKIX_CHECK(PKIX_List_Create(&permittedList, plContext), + PKIX_LISTCREATEFAILED); + + numItems = nameConstraints->numNssNameConstraints; + nssNameConstraintsList = + nameConstraints->nssNameConstraintsList; + + for (i = 0; i < numItems; i++) { + + PKIX_NULLCHECK_ONE(nssNameConstraintsList); + nssNameConstraints = *(nssNameConstraintsList + i); + PKIX_NULLCHECK_ONE(nssNameConstraints); + + if (nssNameConstraints->permited != NULL) { + + nssPermitted = nssNameConstraints->permited; + firstPermitted = nssPermitted; + + do { + + PKIX_CHECK(pkix_pl_GeneralName_Create + (&nssPermitted->name, &name, plContext), + PKIX_GENERALNAMECREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (permittedList, + (PKIX_PL_Object *)name, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(name); + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextNameConstraint\n"); + nssPermitted = CERT_GetNextNameConstraint + (nssPermitted); + + } while (nssPermitted != firstPermitted); + + } + } + + PKIX_CHECK(PKIX_List_SetImmutable(permittedList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + nameConstraints->permittedList = permittedList; + + } + + PKIX_OBJECT_UNLOCK(nameConstraints); + + } + + PKIX_INCREF(nameConstraints->permittedList); + + *pPermittedList = nameConstraints->permittedList; + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_GetExcluded + * DESCRIPTION: + * + * This function retrieve name constraints excluded list from NSS + * data in "nameConstraints" and returns a PKIX_PL_GeneralName list + * in "pExcludedList". + * + * PARAMETERS + * "nameConstraints" + * Address of CertNameConstraints which has a pointer to NSS data. + * Must be non-NULL. + * "pPermittedList" + * Address where returned excluded name list is stored. Must be non-NULL. + * "plContext" - Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a NameConstraints 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_CertNameConstraints_GetExcluded( + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_List **pExcludedList, + void *plContext) +{ + CERTNameConstraints *nssNameConstraints = NULL; + CERTNameConstraints **nssNameConstraintsList = NULL; + CERTNameConstraint *nssExcluded = NULL; + CERTNameConstraint *firstExcluded = NULL; + PKIX_List *excludedList = NULL; + PKIX_PL_GeneralName *name = NULL; + PKIX_UInt32 numItems = 0; + PKIX_UInt32 i; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_GetExcluded"); + PKIX_NULLCHECK_TWO(nameConstraints, pExcludedList); + + if (nameConstraints->excludedList == NULL) { + + PKIX_OBJECT_LOCK(nameConstraints); + + if (nameConstraints->excludedList == NULL) { + + PKIX_CHECK(PKIX_List_Create(&excludedList, plContext), + PKIX_LISTCREATEFAILED); + + numItems = nameConstraints->numNssNameConstraints; + nssNameConstraintsList = + nameConstraints->nssNameConstraintsList; + + for (i = 0; i < numItems; i++) { + + PKIX_NULLCHECK_ONE(nssNameConstraintsList); + nssNameConstraints = *(nssNameConstraintsList + i); + PKIX_NULLCHECK_ONE(nssNameConstraints); + + if (nssNameConstraints->excluded != NULL) { + + nssExcluded = nssNameConstraints->excluded; + firstExcluded = nssExcluded; + + do { + + PKIX_CHECK(pkix_pl_GeneralName_Create + (&nssExcluded->name, &name, plContext), + PKIX_GENERALNAMECREATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (excludedList, + (PKIX_PL_Object *)name, + plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(name); + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextNameConstraint\n"); + nssExcluded = CERT_GetNextNameConstraint + (nssExcluded); + + } while (nssExcluded != firstExcluded); + + } + + } + PKIX_CHECK(PKIX_List_SetImmutable(excludedList, plContext), + PKIX_LISTSETIMMUTABLEFAILED); + + nameConstraints->excludedList = excludedList; + + } + + PKIX_OBJECT_UNLOCK(nameConstraints); + } + + PKIX_INCREF(nameConstraints->excludedList); + + *pExcludedList = nameConstraints->excludedList; + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_CheckNameSpaceNssNames + * DESCRIPTION: + * + * This function checks if CERTGeneralNames in "nssSubjectNames" comply + * with the permitted and excluded names in "nameConstraints". It returns + * PKIX_TRUE in "pCheckPass", if the Names satify the name space of the + * permitted list and if the Names are not in the excluded list. Otherwise, + * it returns PKIX_FALSE. + * + * PARAMETERS + * "nssSubjectNames" + * List of CERTGeneralName that nameConstraints verification is based on. + * "nameConstraints" + * Address of CertNameConstraints that provides lists of permitted + * and excluded names. Must be non-NULL. + * "pCheckPass" + * Address where PKIX_TRUE is returned if the all names in "nameList" are + * valid. + * "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 NameConstraints 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_CertNameConstraints_CheckNameSpaceNssNames( + CERTGeneralName *nssSubjectNames, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean *pCheckPass, + void *plContext) +{ + CERTNameConstraints **nssNameConstraintsList = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + CERTGeneralName *nssMatchName = NULL; + PLArenaPool *arena = NULL; + PKIX_UInt32 numItems = 0; + PKIX_UInt32 i; + SECStatus status = SECSuccess; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_CheckNameSpaceNssNames"); + PKIX_NULLCHECK_THREE(nssSubjectNames, nameConstraints, pCheckPass); + + *pCheckPass = PKIX_TRUE; + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + nssMatchName = nssSubjectNames; + nssNameConstraintsList = nameConstraints->nssNameConstraintsList; + + /* + * CERTNameConstraint items in each permitted or excluded list + * is verified as OR condition. That means, if one item matched, + * then the checking on the remaining items on the list is skipped. + * (see NSS cert_CompareNameWithConstraints(...)). + * Items on PKIX_PL_NameConstraint's nssNameConstraints are verified + * as AND condition. PKIX_PL_NameConstraint keeps an array of pointers + * of CERTNameConstraints resulting from merging multiple + * PKIX_PL_NameConstraints. Since each CERTNameConstraint are created + * for different entity, a union condition of these entities then is + * performed. + */ + + do { + + numItems = nameConstraints->numNssNameConstraints; + + for (i = 0; i < numItems; i++) { + + PKIX_NULLCHECK_ONE(nssNameConstraintsList); + nssNameConstraints = *(nssNameConstraintsList + i); + PKIX_NULLCHECK_ONE(nssNameConstraints); + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_CheckNameSpace\n"); + status = CERT_CheckNameSpace + (arena, nssNameConstraints, nssMatchName); + if (status != SECSuccess) { + break; + } + + } + + if (status != SECSuccess) { + break; + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextGeneralName\n"); + nssMatchName = CERT_GetNextGeneralName(nssMatchName); + + } while (nssMatchName != nssSubjectNames); + + if (status == SECFailure) { + + *pCheckPass = PKIX_FALSE; + } + +cleanup: + + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_NameConstraints_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertNameConstraints_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTNAMECONSTRAINTS); + + nameConstraints = (PKIX_PL_CertNameConstraints *)object; + + PKIX_CHECK(PKIX_PL_Free + (nameConstraints->nssNameConstraintsList, plContext), + PKIX_FREEFAILED); + + if (nameConstraints->arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(nameConstraints->arena, PR_FALSE); + nameConstraints->arena = NULL; + } + + PKIX_DECREF(nameConstraints->permittedList); + PKIX_DECREF(nameConstraints->excludedList); + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the object + * NameConstraints and stores it at "pString". + * + * PARAMETERS + * "nameConstraints" + * Address of CertNameConstraints whose string representation is + * desired. Must be non-NULL. + * "pString" + * Address where string 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 NameConstraints 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_CertNameConstraints_ToString_Helper( + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_PL_String **pString, + void *plContext) +{ + char *asciiFormat = NULL; + PKIX_PL_String *formatString = NULL; + PKIX_List *permittedList = NULL; + PKIX_List *excludedList = NULL; + PKIX_PL_String *permittedListString = NULL; + PKIX_PL_String *excludedListString = NULL; + PKIX_PL_String *nameConstraintsString = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_ToString_Helper"); + PKIX_NULLCHECK_TWO(nameConstraints, pString); + + asciiFormat = + "[\n" + "\t\tPermitted Name: %s\n" + "\t\tExcluded Name: %s\n" + "\t]\n"; + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + asciiFormat, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted + (nameConstraints, &permittedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED); + + PKIX_TOSTRING(permittedList, &permittedListString, plContext, + PKIX_LISTTOSTRINGFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded + (nameConstraints, &excludedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED); + + PKIX_TOSTRING(excludedList, &excludedListString, plContext, + PKIX_LISTTOSTRINGFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (&nameConstraintsString, + plContext, + formatString, + permittedListString, + excludedListString), + PKIX_SPRINTFFAILED); + + *pString = nameConstraintsString; + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(permittedList); + PKIX_DECREF(excludedList); + PKIX_DECREF(permittedListString); + PKIX_DECREF(excludedListString); + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertNameConstraints_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *nameConstraintsString = NULL; + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType( + object, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTNAMECONSTRAINTS); + + nameConstraints = (PKIX_PL_CertNameConstraints *)object; + + PKIX_CHECK(pkix_pl_CertNameConstraints_ToString_Helper + (nameConstraints, &nameConstraintsString, plContext), + PKIX_CERTNAMECONSTRAINTSTOSTRINGHELPERFAILED); + + *pString = nameConstraintsString; + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertNameConstraints_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + PKIX_List *permittedList = NULL; + PKIX_List *excludedList = NULL; + PKIX_UInt32 permitHash = 0; + PKIX_UInt32 excludeHash = 0; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType + (object, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext), + PKIX_OBJECTNOTCERTNAMECONSTRAINTS); + + nameConstraints = (PKIX_PL_CertNameConstraints *)object; + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted + (nameConstraints, &permittedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED); + + PKIX_HASHCODE(permittedList, &permitHash, plContext, + PKIX_OBJECTHASHCODEFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded + (nameConstraints, &excludedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED); + + PKIX_HASHCODE(excludedList, &excludeHash, plContext, + PKIX_OBJECTHASHCODEFAILED); + + *pHashcode = (((permitHash << 7) + excludeHash) << 7) + + nameConstraints->numNssNameConstraints; + +cleanup: + + PKIX_DECREF(permittedList); + PKIX_DECREF(excludedList); + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_CertNameConstraints_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_CertNameConstraints *firstNC = NULL; + PKIX_PL_CertNameConstraints *secondNC = NULL; + PKIX_List *firstPermittedList = NULL; + PKIX_List *secondPermittedList = NULL; + PKIX_List *firstExcludedList = NULL; + PKIX_List *secondExcludedList = NULL; + PKIX_UInt32 secondType; + PKIX_Boolean cmpResult = PKIX_FALSE; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a CertNameConstraints */ + PKIX_CHECK(pkix_CheckType + (firstObject, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext), + PKIX_FIRSTOBJECTNOTCERTNAMECONSTRAINTS); + + firstNC = (PKIX_PL_CertNameConstraints *)firstObject; + secondNC = (PKIX_PL_CertNameConstraints *)secondObject; + + /* + * Since we know firstObject is a CertNameConstraints, if both + * references are identical, they must be equal + */ + if (firstNC == secondNC){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondNC isn't a CertNameConstraints, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + + PKIX_CHECK(PKIX_PL_Object_GetType + ((PKIX_PL_Object *)secondNC, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + + if (secondType != PKIX_CERTNAMECONSTRAINTS_TYPE) { + goto cleanup; + } + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted + (firstNC, &firstPermittedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted + (secondNC, &secondPermittedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED); + + PKIX_EQUALS + (firstPermittedList, secondPermittedList, &cmpResult, plContext, + PKIX_OBJECTEQUALSFAILED); + + if (cmpResult != PKIX_TRUE) { + goto cleanup; + } + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded + (firstNC, &firstExcludedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED); + + PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded + (secondNC, &secondExcludedList, plContext), + PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED); + + PKIX_EQUALS + (firstExcludedList, secondExcludedList, &cmpResult, plContext, + PKIX_OBJECTEQUALSFAILED); + + if (cmpResult != PKIX_TRUE) { + goto cleanup; + } + + /* + * numNssNameConstraints is not checked because it is basically a + * merge count, it cannot determine the data equality. + */ + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_DECREF(firstPermittedList); + PKIX_DECREF(secondPermittedList); + PKIX_DECREF(firstExcludedList); + PKIX_DECREF(secondExcludedList); + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_RegisterSelf + * DESCRIPTION: + * Registers PKIX_CERTNAMECONSTRAINTS_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_CertNameConstraints_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_RegisterSelf"); + + entry.description = "CertNameConstraints"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_CertNameConstraints); + entry.destructor = pkix_pl_CertNameConstraints_Destroy; + entry.equalsFunction = pkix_pl_CertNameConstraints_Equals; + entry.hashcodeFunction = pkix_pl_CertNameConstraints_Hashcode; + entry.toStringFunction = pkix_pl_CertNameConstraints_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_CERTNAMECONSTRAINTS_TYPE] = entry; + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Create_Helper + * + * DESCRIPTION: + * This function retrieves name constraints in "nssNameConstraints", + * converts and stores the result in a PKIX_PL_CertNameConstraints object. + * + * PARAMETERS + * "nssNameConstraints" + * Address of CERTNameConstraints that contains this object's data. + * Must be non-NULL. + * "pNameConstraints" + * Address where object pointer will be stored. Must be non-NULL. + * A NULL value will be returned if there is no Name Constraints extension. + * "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 NameConstraints 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_CertNameConstraints_Create_Helper( + CERTNameConstraints *nssNameConstraints, + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + CERTNameConstraints **nssNameConstraintPtr = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_Create_Helper"); + PKIX_NULLCHECK_TWO(nssNameConstraints, pNameConstraints); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_CERTNAMECONSTRAINTS_TYPE, + sizeof (PKIX_PL_CertNameConstraints), + (PKIX_PL_Object **)&nameConstraints, + plContext), + PKIX_COULDNOTCREATECERTNAMECONSTRAINTSOBJECT); + + PKIX_CHECK(PKIX_PL_Malloc + (sizeof (CERTNameConstraint *), + (void *)&nssNameConstraintPtr, + plContext), + PKIX_MALLOCFAILED); + + nameConstraints->numNssNameConstraints = 1; + nameConstraints->nssNameConstraintsList = nssNameConstraintPtr; + *nssNameConstraintPtr = nssNameConstraints; + + nameConstraints->permittedList = NULL; + nameConstraints->excludedList = NULL; + nameConstraints->arena = NULL; + + *pNameConstraints = nameConstraints; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(nameConstraints); + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Create + * + * DESCRIPTION: + * function that allocates and initialize the object CertNameConstraints. + * + * PARAMETERS + * "nssCert" + * Address of CERT that contains this object's data. + * Must be non-NULL. + * "pNameConstraints" + * Address where object pointer will be stored. Must be non-NULL. + * A NULL value will be returned if there is no Name Constraints extension. + * "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 NameConstraints 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_CertNameConstraints_Create( + CERTCertificate *nssCert, + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + PLArenaPool *arena = NULL; + SECStatus status; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Create"); + PKIX_NULLCHECK_THREE(nssCert, pNameConstraints, nssCert->arena); + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena).\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_FindNameConstraintsExten\n"); + status = CERT_FindNameConstraintsExten + (arena, nssCert, &nssNameConstraints); + + if (status != SECSuccess) { + PKIX_ERROR(PKIX_DECODINGCERTNAMECONSTRAINTSFAILED); + } + + if (nssNameConstraints == NULL) { + *pNameConstraints = NULL; + /* we free the arnea here because PKIX_ERROR_RECEIVED + * may not be set. Setting arena to NULL makes sure + * we don't try to free it again (and makes scanners + * happy). */ + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + arena = NULL; + } + goto cleanup; + } + + PKIX_CHECK(pkix_pl_CertNameConstraints_Create_Helper + (nssNameConstraints, &nameConstraints, plContext), + PKIX_CERTNAMECONSTRAINTSCREATEHELPERFAILED); + + nameConstraints->arena = arena; + + *pNameConstraints = nameConstraints; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_CreateByMerge + * + * DESCRIPTION: + * + * This function allocates and creates a PKIX_PL_NameConstraint object + * for merging. It also allocates CERTNameConstraints data space for the + * merged NSS NameConstraints data. + * + * PARAMETERS + * "pNameConstraints" + * Address where object pointer will be stored and returned. + * 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 NameConstraints 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_CertNameConstraints_CreateByMerge( + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + PLArenaPool *arena = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_CreateByMerge"); + PKIX_NULLCHECK_ONE(pNameConstraints); + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena).\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_ArenaZNew).\n"); + nssNameConstraints = PORT_ArenaZNew(arena, CERTNameConstraints); + if (nssNameConstraints == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + nssNameConstraints->permited = NULL; + nssNameConstraints->excluded = NULL; + nssNameConstraints->DERPermited = NULL; + nssNameConstraints->DERExcluded = NULL; + + PKIX_CHECK(pkix_pl_CertNameConstraints_Create_Helper + (nssNameConstraints, &nameConstraints, plContext), + PKIX_CERTNAMECONSTRAINTSCREATEHELPERFAILED); + + nameConstraints->arena = arena; + + *pNameConstraints = nameConstraints; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_CopyNssNameConstraints + * + * DESCRIPTION: + * + * This function allocates and copies data to a NSS CERTNameConstraints from + * the NameConstraints given by "srcNC" and stores the result at "pDestNC". It + * copies items on both the permitted and excluded lists, but not the + * DERPermited and DERExcluded. + * + * PARAMETERS + * "arena" + * Memory pool where object data is allocated from. Must be non-NULL. + * "srcNC" + * Address of the NameConstraints to copy from. Must be non-NULL. + * "pDestNC" + * Address where new copied object is stored and returned. + * 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 NameConstraints 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_CertNameConstraints_CopyNssNameConstraints( + PLArenaPool *arena, + CERTNameConstraints *srcNC, + CERTNameConstraints **pDestNC, + void *plContext) +{ + CERTNameConstraints *nssNameConstraints = NULL; + CERTNameConstraint *nssNameConstraintHead = NULL; + CERTNameConstraint *nssCurrent = NULL; + CERTNameConstraint *nssCopyTo = NULL; + CERTNameConstraint *nssCopyFrom = NULL; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "pkix_pl_CertNameConstraints_CopyNssNameConstraints"); + PKIX_NULLCHECK_THREE(arena, srcNC, pDestNC); + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_ArenaZNew).\n"); + nssNameConstraints = PORT_ArenaZNew(arena, CERTNameConstraints); + if (nssNameConstraints == NULL) { + PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); + } + + if (srcNC->permited) { + + nssCopyFrom = srcNC->permited; + + do { + + nssCopyTo = NULL; + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_CopyNameConstraint).\n"); + nssCopyTo = CERT_CopyNameConstraint + (arena, nssCopyTo, nssCopyFrom); + if (nssCopyTo == NULL) { + PKIX_ERROR(PKIX_CERTCOPYNAMECONSTRAINTFAILED); + } + if (nssCurrent == NULL) { + nssCurrent = nssNameConstraintHead = nssCopyTo; + } else { + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_AddNameConstraint).\n"); + nssCurrent = CERT_AddNameConstraint + (nssCurrent, nssCopyTo); + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextNameConstrain).\n"); + nssCopyFrom = CERT_GetNextNameConstraint(nssCopyFrom); + + } while (nssCopyFrom != srcNC->permited); + + nssNameConstraints->permited = nssNameConstraintHead; + } + + if (srcNC->excluded) { + + nssCurrent = NULL; + nssCopyFrom = srcNC->excluded; + + do { + + /* + * Cannot use CERT_DupGeneralNameList, which just increments + * refcount. We need our own copy since arena is for each + * PKIX_PL_NameConstraints. Perhaps contribute this code + * as CERT_CopyGeneralNameList (in the future). + */ + nssCopyTo = NULL; + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_CopyNameConstraint).\n"); + nssCopyTo = CERT_CopyNameConstraint + (arena, nssCopyTo, nssCopyFrom); + if (nssCopyTo == NULL) { + PKIX_ERROR(PKIX_CERTCOPYNAMECONSTRAINTFAILED); + } + if (nssCurrent == NULL) { + nssCurrent = nssNameConstraintHead = nssCopyTo; + } else { + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_AddNameConstraint).\n"); + nssCurrent = CERT_AddNameConstraint + (nssCurrent, nssCopyTo); + } + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_GetNextNameConstrain).\n"); + nssCopyFrom = CERT_GetNextNameConstraint(nssCopyFrom); + + } while (nssCopyFrom != srcNC->excluded); + + nssNameConstraints->excluded = nssNameConstraintHead; + } + + *pDestNC = nssNameConstraints; + +cleanup: + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* + * FUNCTION: pkix_pl_CertNameConstraints_Merge + * + * DESCRIPTION: + * + * This function merges two NameConstraints pointed to by "firstNC" and + * "secondNC" and stores the result in "pMergedNC". + * + * PARAMETERS + * "firstNC" + * Address of the first NameConstraints to be merged. Must be non-NULL. + * "secondNC" + * Address of the second NameConstraints to be merged. Must be non-NULL. + * "pMergedNC" + * Address where the merge result is stored and returned. 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 NameConstraints 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_CertNameConstraints_Merge( + PKIX_PL_CertNameConstraints *firstNC, + PKIX_PL_CertNameConstraints *secondNC, + PKIX_PL_CertNameConstraints **pMergedNC, + void *plContext) +{ + PKIX_PL_CertNameConstraints *nameConstraints = NULL; + CERTNameConstraints **nssNCto = NULL; + CERTNameConstraints **nssNCfrom = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + PKIX_UInt32 numNssItems = 0; + PKIX_UInt32 i; + + PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Merge"); + PKIX_NULLCHECK_THREE(firstNC, secondNC, pMergedNC); + + PKIX_CHECK(pkix_pl_CertNameConstraints_CreateByMerge + (&nameConstraints, plContext), + PKIX_CERTNAMECONSTRAINTSCREATEBYMERGEFAILED); + + /* Merge NSSCertConstraint lists */ + + numNssItems = firstNC->numNssNameConstraints + + secondNC->numNssNameConstraints; + + /* Free the default space (only one entry) allocated by create */ + PKIX_CHECK(PKIX_PL_Free + (nameConstraints->nssNameConstraintsList, plContext), + PKIX_FREEFAILED); + + /* Reallocate the size we need */ + PKIX_CHECK(PKIX_PL_Malloc + (numNssItems * sizeof (CERTNameConstraint *), + (void *)&nssNCto, + plContext), + PKIX_MALLOCFAILED); + + nameConstraints->nssNameConstraintsList = nssNCto; + + nssNCfrom = firstNC->nssNameConstraintsList; + + for (i = 0; i < firstNC->numNssNameConstraints; i++) { + + PKIX_CHECK(pkix_pl_CertNameConstraints_CopyNssNameConstraints + (nameConstraints->arena, + *nssNCfrom, + &nssNameConstraints, + plContext), + PKIX_CERTNAMECONSTRAINTSCOPYNSSNAMECONSTRAINTSFAILED); + + *nssNCto = nssNameConstraints; + + nssNCto++; + nssNCfrom++; + } + + nssNCfrom = secondNC->nssNameConstraintsList; + + for (i = 0; i < secondNC->numNssNameConstraints; i++) { + + PKIX_CHECK(pkix_pl_CertNameConstraints_CopyNssNameConstraints + (nameConstraints->arena, + *nssNCfrom, + &nssNameConstraints, + plContext), + PKIX_CERTNAMECONSTRAINTSCOPYNSSNAMECONSTRAINTSFAILED); + + *nssNCto = nssNameConstraints; + + nssNCto++; + nssNCfrom++; + } + + nameConstraints->numNssNameConstraints = numNssItems; + nameConstraints->permittedList = NULL; + nameConstraints->excludedList = NULL; + + *pMergedNC = nameConstraints; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(nameConstraints); + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} + +/* --Public-NameConstraints-Functions-------------------------------- */ + +/* + * FUNCTION: PKIX_PL_CertNameConstraints_CheckNamesInNameSpace + * (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_CertNameConstraints_CheckNamesInNameSpace( + PKIX_List *nameList, /* List of PKIX_PL_GeneralName */ + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean *pCheckPass, + void *plContext) +{ + CERTNameConstraints **nssNameConstraintsList = NULL; + CERTNameConstraints *nssNameConstraints = NULL; + CERTGeneralName *nssMatchName = NULL; + PLArenaPool *arena = NULL; + PKIX_PL_GeneralName *name = NULL; + PKIX_UInt32 numNameItems = 0; + PKIX_UInt32 numNCItems = 0; + PKIX_UInt32 i, j; + SECStatus status = SECSuccess; + + PKIX_ENTER(CERTNAMECONSTRAINTS, + "PKIX_PL_CertNameConstraints_CheckNamesInNameSpace"); + PKIX_NULLCHECK_TWO(nameConstraints, pCheckPass); + + *pCheckPass = PKIX_TRUE; + + if (nameList != NULL) { + + PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena\n"); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + nssNameConstraintsList = + nameConstraints->nssNameConstraintsList; + PKIX_NULLCHECK_ONE(nssNameConstraintsList); + numNCItems = nameConstraints->numNssNameConstraints; + + PKIX_CHECK(PKIX_List_GetLength + (nameList, &numNameItems, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (i = 0; i < numNameItems; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (nameList, + i, + (PKIX_PL_Object **) &name, + plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_pl_GeneralName_GetNssGeneralName + (name, &nssMatchName, plContext), + PKIX_GENERALNAMEGETNSSGENERALNAMEFAILED); + + PKIX_DECREF(name); + + for (j = 0; j < numNCItems; j++) { + + nssNameConstraints = *(nssNameConstraintsList + j); + PKIX_NULLCHECK_ONE(nssNameConstraints); + + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling CERT_CheckNameSpace\n"); + status = CERT_CheckNameSpace + (arena, nssNameConstraints, nssMatchName); + if (status != SECSuccess) { + break; + } + + } + + if (status != SECSuccess) { + break; + } + + } + } + + if (status == SECFailure) { + *pCheckPass = PKIX_FALSE; + } + +cleanup: + + if (arena){ + PKIX_CERTNAMECONSTRAINTS_DEBUG + ("\t\tCalling PORT_FreeArena).\n"); + PORT_FreeArena(arena, PR_FALSE); + } + + PKIX_RETURN(CERTNAMECONSTRAINTS); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h new file mode 100644 index 0000000000..2f305ac10a --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h @@ -0,0 +1,68 @@ +/* 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_nameconstraints.h + * + * Name Constraints Object Definitions + * + */ + +#ifndef _PKIX_PL_NAMECONSTRAINTS_H +#define _PKIX_PL_NAMECONSTRAINTS_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_CertNameConstraintsStruct { + PLArenaPool *arena; + CERTNameConstraints **nssNameConstraintsList; + PKIX_UInt32 numNssNameConstraints; + PKIX_List *permittedList; /* list of PKIX_PL_GeneralName */ + PKIX_List *excludedList; /* list of PKIX_PL_GeneralName */ +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_CertNameConstraints_RegisterSelf(void *plContext); + +PKIX_Error *pkix_pl_CertNameConstraints_Create( + CERTCertificate *nssCert, + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext); + +PKIX_Error * +pkix_pl_CertNameConstraints_CreateWithNames( + PKIX_List *names, /* List of PKIX_PL_GeneralName */ + PKIX_PL_CertNameConstraints **pNameConstraints, + void *plContext); + +PKIX_Error * +pkix_pl_CertNameConstraints_CheckNameSpaceNssNames( + CERTGeneralName *nssSubjectNames, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean *pCheckPass, + void *plContext); + +PKIX_Error * +pkix_pl_CertNameConstraints_CheckNameSpacePkixNames( + PKIX_List *nameList, + PKIX_PL_CertNameConstraints *nameConstraints, + PKIX_Boolean *pCheckPass, + void *plContext); + + +PKIX_Error *pkix_pl_CertNameConstraints_Merge( + PKIX_PL_CertNameConstraints *firstNC, + PKIX_PL_CertNameConstraints *secondNC, + PKIX_PL_CertNameConstraints **pMergedNC, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_NAMECONSTRAINTS_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c new file mode 100644 index 0000000000..679811dec1 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c @@ -0,0 +1,251 @@ +/* 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_ocspcertid.c + * + * Certificate ID Object for OCSP + * + */ + +#include "pkix_pl_ocspcertid.h" + +/* --Private-Cert-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspCertID_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspCertID_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_OcspCertID *certID = NULL; + + PKIX_ENTER(OCSPCERTID, "pkix_pl_OcspCertID_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPCERTID_TYPE, plContext), + PKIX_OBJECTNOTOCSPCERTID); + + certID = (PKIX_PL_OcspCertID *)object; + + if (certID->certID) { + CERT_DestroyOCSPCertID(certID->certID); + } + +cleanup: + + PKIX_RETURN(OCSPCERTID); +} + +/* + * FUNCTION: pkix_pl_OcspCertID_RegisterSelf + * DESCRIPTION: + * Registers PKIX_PUBLICKEY_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_OcspCertID_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(OCSPCERTID, "pkix_pl_OcspCertID_RegisterSelf"); + + entry.description = "OcspCertID"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_OcspCertID); + entry.destructor = pkix_pl_OcspCertID_Destroy; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + systemClasses[PKIX_OCSPCERTID_TYPE] = entry; + + PKIX_RETURN(OCSPCERTID); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_OcspCertID_Create + * DESCRIPTION: + * + * This function creates an OcspCertID for a given certificate, + * to be used with OCSP transactions. + * + * If a Date is provided in "validity" it may be used in the search for the + * issuer of "cert" but has no effect on the request itself. + * + * PARAMETERS: + * "cert" + * Address of the Cert for which an OcspCertID is to be created. Must be + * non-NULL. + * "validity" + * Address of the Date for which the Cert's validity is to be determined. + * May be NULL. + * "object" + * Address at which the result 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 an OcspCertID 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_OcspCertID_Create( + PKIX_PL_Cert *cert, + PKIX_PL_Date *validity, + PKIX_PL_OcspCertID **object, + void *plContext) +{ + PKIX_PL_OcspCertID *cid = NULL; + PRTime time = 0; + + PKIX_ENTER(DATE, "PKIX_PL_OcspCertID_Create"); + PKIX_NULLCHECK_TWO(cert, object); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_OCSPCERTID_TYPE, + sizeof (PKIX_PL_OcspCertID), + (PKIX_PL_Object **)&cid, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + if (validity != NULL) { + PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext), + PKIX_DATEGETPRTIMEFAILED); + } else { + time = PR_Now(); + } + + cid->certID = CERT_CreateOCSPCertID(cert->nssCert, time); + if (!cid->certID) { + PKIX_ERROR(PKIX_COULDNOTCREATEOBJECT); + } + + *object = cid; + cid = NULL; +cleanup: + PKIX_DECREF(cid); + PKIX_RETURN(OCSPCERTID); +} + +/* + * FUNCTION: PKIX_PL_OcspCertID_GetFreshCacheStatus + * DESCRIPTION: + * + * This function may return cached OCSP results for the provided + * certificate, but only if stored information is still considered to be + * fresh. + * + * PARAMETERS + * "cid" + * A certificate ID as used by OCSP + * "validity" + * Optional date parameter to request validity for a specifc time. + * "hasFreshStatus" + * Output parameter, if the function successed to find fresh cached + * information, this will be set to true. Must be non-NULL. + * "statusIsGood" + * The good/bad result stored in the cache. Must be non-NULL. + * "missingResponseError" + * If OCSP status is "bad", this variable may indicate the exact + * reason why the previous OCSP request had failed. + * "plContext" + * Platform-specific context pointer. + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an OcspCertID 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_OcspCertID_GetFreshCacheStatus( + PKIX_PL_OcspCertID *cid, + PKIX_PL_Date *validity, + PKIX_Boolean *hasFreshStatus, + PKIX_Boolean *statusIsGood, + SECErrorCodes *missingResponseError, + void *plContext) +{ + PRTime time = 0; + SECStatus rv; + SECStatus rvOcsp; + OCSPFreshness freshness; + + PKIX_ENTER(DATE, "PKIX_PL_OcspCertID_GetFreshCacheStatus"); + PKIX_NULLCHECK_THREE(cid, hasFreshStatus, statusIsGood); + + if (validity != NULL) { + PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext), + PKIX_DATEGETPRTIMEFAILED); + } else { + time = PR_Now(); + } + + rv = ocsp_GetCachedOCSPResponseStatus( + cid->certID, time, PR_TRUE, /*ignoreGlobalOcspFailureSetting*/ + &rvOcsp, missingResponseError, &freshness); + + *hasFreshStatus = (rv == SECSuccess && freshness == ocspFresh); + if (*hasFreshStatus) { + *statusIsGood = (rvOcsp == SECSuccess); + } +cleanup: + PKIX_RETURN(OCSPCERTID); +} + +/* + * FUNCTION: PKIX_PL_OcspCertID_RememberOCSPProcessingFailure + * DESCRIPTION: + * + * Information about the current failure associated to the given certID + * will be remembered in the cache, potentially allowing future calls + * to prevent repetitive OCSP requests. + * After this function got called, it may no longer be safe to + * use the provided cid parameter, because ownership might have been + * transfered to the cache. This status will be recorded inside the + * cid object. + * + * PARAMETERS + * "cid" + * The certificate ID associated to a failed OCSP processing. + * "plContext" + * Platform-specific context pointer. + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an OcspCertID 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_OcspCertID_RememberOCSPProcessingFailure( + PKIX_PL_OcspCertID *cid, + void *plContext) +{ + PRBool certIDWasConsumed = PR_FALSE; + + PKIX_ENTER(DATE, "PKIX_PL_OcspCertID_RememberOCSPProcessingFailure"); + PKIX_NULLCHECK_TWO(cid, cid->certID); + + cert_RememberOCSPProcessingFailure(cid->certID, &certIDWasConsumed); + + if (certIDWasConsumed) { + cid->certID = NULL; + } + + PKIX_RETURN(OCSPCERTID); +} + diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h new file mode 100644 index 0000000000..772a12b25f --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h @@ -0,0 +1,53 @@ +/* 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_ocspcertid.h + * + * Public Key Object Definitions + * + */ + +#ifndef _PKIX_PL_OCSPCERTID_H +#define _PKIX_PL_OCSPCERTID_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_OcspCertIDStruct { + CERTOCSPCertID *certID; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_OcspCertID_RegisterSelf(void *plContext); + +PKIX_Error * +PKIX_PL_OcspCertID_Create( + PKIX_PL_Cert *cert, + PKIX_PL_Date *validity, + PKIX_PL_OcspCertID **object, + void *plContext); + +PKIX_Error * +PKIX_PL_OcspCertID_GetFreshCacheStatus( + PKIX_PL_OcspCertID *cid, + PKIX_PL_Date *validity, + PKIX_Boolean *hasFreshStatus, + PKIX_Boolean *statusIsGood, + SECErrorCodes *missingResponseError, + void *plContext); + +PKIX_Error * +PKIX_PL_OcspCertID_RememberOCSPProcessingFailure( + PKIX_PL_OcspCertID *cid, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_OCSPCERTID_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c new file mode 100644 index 0000000000..28b6953a76 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c @@ -0,0 +1,441 @@ +/* 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_ocsprequest.c + * + */ + +#include "pkix_pl_ocsprequest.h" + +/* --Private-OcspRequest-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspRequest_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspRequest_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_OcspRequest *ocspReq = NULL; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext), + PKIX_OBJECTNOTOCSPREQUEST); + + ocspReq = (PKIX_PL_OcspRequest *)object; + + if (ocspReq->decoded != NULL) { + CERT_DestroyOCSPRequest(ocspReq->decoded); + } + + if (ocspReq->encoded != NULL) { + SECITEM_FreeItem(ocspReq->encoded, PR_TRUE); + } + + if (ocspReq->location != NULL) { + PORT_Free(ocspReq->location); + } + + PKIX_DECREF(ocspReq->cert); + PKIX_DECREF(ocspReq->validity); + PKIX_DECREF(ocspReq->signerCert); + +cleanup: + + PKIX_RETURN(OCSPREQUEST); +} + +/* + * FUNCTION: pkix_pl_OcspRequest_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspRequest_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_UInt32 certHash = 0; + PKIX_UInt32 dateHash = 0; + PKIX_UInt32 extensionHash = 0; + PKIX_UInt32 signerHash = 0; + PKIX_PL_OcspRequest *ocspRq = NULL; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext), + PKIX_OBJECTNOTOCSPREQUEST); + + ocspRq = (PKIX_PL_OcspRequest *)object; + + *pHashcode = 0; + + PKIX_HASHCODE(ocspRq->cert, &certHash, plContext, + PKIX_CERTHASHCODEFAILED); + + PKIX_HASHCODE(ocspRq->validity, &dateHash, plContext, + PKIX_DATEHASHCODEFAILED); + + if (ocspRq->addServiceLocator == PKIX_TRUE) { + extensionHash = 0xff; + } + + PKIX_HASHCODE(ocspRq->signerCert, &signerHash, plContext, + PKIX_CERTHASHCODEFAILED); + + *pHashcode = (((((extensionHash << 8) | certHash) << 8) | + dateHash) << 8) | signerHash; + +cleanup: + + PKIX_RETURN(OCSPREQUEST); + +} + +/* + * FUNCTION: pkix_pl_OcspRequest_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspRequest_Equals( + PKIX_PL_Object *firstObj, + PKIX_PL_Object *secondObj, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_Boolean match = PKIX_FALSE; + PKIX_UInt32 secondType = 0; + PKIX_PL_OcspRequest *firstReq = NULL; + PKIX_PL_OcspRequest *secondReq = NULL; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Equals"); + PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult); + + /* test that firstObj is a OcspRequest */ + PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPREQUEST_TYPE, plContext), + PKIX_FIRSTOBJARGUMENTNOTOCSPREQUEST); + + /* + * Since we know firstObj is a OcspRequest, if both references are + * identical, they must be equal + */ + if (firstObj == secondObj){ + match = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObj isn't a OcspRequest, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + PKIX_CHECK(PKIX_PL_Object_GetType + (secondObj, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_OCSPREQUEST_TYPE) { + goto cleanup; + } + + firstReq = (PKIX_PL_OcspRequest *)firstObj; + secondReq = (PKIX_PL_OcspRequest *)secondObj; + + if (firstReq->addServiceLocator != secondReq->addServiceLocator) { + goto cleanup; + } + + PKIX_EQUALS(firstReq->cert, secondReq->cert, &match, plContext, + PKIX_CERTEQUALSFAILED); + + if (match == PKIX_FALSE) { + goto cleanup; + } + + PKIX_EQUALS(firstReq->validity, secondReq->validity, &match, plContext, + PKIX_DATEEQUALSFAILED); + + if (match == PKIX_FALSE) { + goto cleanup; + } + + PKIX_EQUALS + (firstReq->signerCert, secondReq->signerCert, &match, plContext, + PKIX_CERTEQUALSFAILED); + +cleanup: + + *pResult = match; + + PKIX_RETURN(OCSPREQUEST); +} + +/* + * FUNCTION: pkix_pl_OcspRequest_RegisterSelf + * DESCRIPTION: + * Registers PKIX_OCSPREQUEST_TYPE and its related functions with + * systemClasses[] + * PARAMETERS: + * "plContext" + * Platform-specific context pointer. + * 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_OcspRequest_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_RegisterSelf"); + + entry.description = "OcspRequest"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_OcspRequest); + entry.destructor = pkix_pl_OcspRequest_Destroy; + entry.equalsFunction = pkix_pl_OcspRequest_Equals; + entry.hashcodeFunction = pkix_pl_OcspRequest_Hashcode; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_OCSPREQUEST_TYPE] = entry; + + PKIX_RETURN(OCSPREQUEST); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspRequest_Create + * DESCRIPTION: + * + * This function creates an OcspRequest to be used in validating the Cert + * pointed to by "cert" and storing the result at "pRequest". If a URI + * is found for an OCSP responder, PKIX_TRUE is stored at "pURIFound". If no + * URI is found, PKIX_FALSE is stored. + * + * If a Date is provided in "validity" it may be used in the search for the + * issuer of "cert" but has no effect on the request itself. If + * "addServiceLocator" is TRUE, the AddServiceLocator extension will be + * included in the Request. If "signerCert" is provided it will be used to sign + * the Request. (Note: this signed request feature is not currently supported.) + * + * PARAMETERS: + * "cert" + * Address of the Cert for which an OcspRequest is to be created. Must be + * non-NULL. + * "validity" + * Address of the Date for which the Cert's validity is to be determined. + * May be NULL. + * "signerCert" + * Address of the Cert to be used, if present, in signing the request. + * May be NULL. + * "pRequest" + * Address at which the result 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 an OcspRequest 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_OcspRequest_Create( + PKIX_PL_Cert *cert, + PKIX_PL_OcspCertID *cid, + PKIX_PL_Date *validity, + PKIX_PL_Cert *signerCert, + PKIX_UInt32 methodFlags, + PKIX_Boolean *pURIFound, + PKIX_PL_OcspRequest **pRequest, + void *plContext) +{ + PKIX_PL_OcspRequest *ocspRequest = NULL; + + CERTCertDBHandle *handle = NULL; + SECStatus rv = SECFailure; + SECItem *encoding = NULL; + CERTOCSPRequest *certRequest = NULL; + PRTime time = 0; + PRBool addServiceLocatorExtension = PR_FALSE; + CERTCertificate *nssCert = NULL; + CERTCertificate *nssSignerCert = NULL; + char *location = NULL; + PRErrorCode locError = 0; + PKIX_Boolean canUseDefaultSource = PKIX_FALSE; + + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Create"); + PKIX_NULLCHECK_TWO(cert, pRequest); + + /* create a PKIX_PL_OcspRequest object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_OCSPREQUEST_TYPE, + sizeof (PKIX_PL_OcspRequest), + (PKIX_PL_Object **)&ocspRequest, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + PKIX_INCREF(cert); + ocspRequest->cert = cert; + + PKIX_INCREF(validity); + ocspRequest->validity = validity; + + PKIX_INCREF(signerCert); + ocspRequest->signerCert = signerCert; + + ocspRequest->decoded = NULL; + ocspRequest->encoded = NULL; + + ocspRequest->location = NULL; + + nssCert = cert->nssCert; + + /* + * Does this Cert have an Authority Information Access extension with + * the URI of an OCSP responder? + */ + handle = CERT_GetDefaultCertDB(); + + if (!(methodFlags & PKIX_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE)) { + canUseDefaultSource = PKIX_TRUE; + } + location = ocsp_GetResponderLocation(handle, nssCert, + canUseDefaultSource, + &addServiceLocatorExtension); + if (location == NULL) { + locError = PORT_GetError(); + if (locError == SEC_ERROR_EXTENSION_NOT_FOUND || + locError == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) { + PORT_SetError(0); + *pURIFound = PKIX_FALSE; + goto cleanup; + } + PKIX_ERROR(PKIX_ERRORFINDINGORPROCESSINGURI); + } + + ocspRequest->location = location; + *pURIFound = PKIX_TRUE; + + if (signerCert != NULL) { + nssSignerCert = signerCert->nssCert; + } + + if (validity != NULL) { + PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext), + PKIX_DATEGETPRTIMEFAILED); + } else { + time = PR_Now(); + } + + certRequest = cert_CreateSingleCertOCSPRequest( + cid->certID, cert->nssCert, time, + addServiceLocatorExtension, nssSignerCert); + + ocspRequest->decoded = certRequest; + + if (certRequest == NULL) { + PKIX_ERROR(PKIX_UNABLETOCREATECERTOCSPREQUEST); + } + + rv = CERT_AddOCSPAcceptableResponses( + certRequest, SEC_OID_PKIX_OCSP_BASIC_RESPONSE); + + if (rv == SECFailure) { + PKIX_ERROR(PKIX_UNABLETOADDACCEPTABLERESPONSESTOREQUEST); + } + + encoding = CERT_EncodeOCSPRequest(NULL, certRequest, NULL); + + ocspRequest->encoded = encoding; + + *pRequest = ocspRequest; + ocspRequest = NULL; + +cleanup: + PKIX_DECREF(ocspRequest); + + PKIX_RETURN(OCSPREQUEST); +} + +/* + * FUNCTION: pkix_pl_OcspRequest_GetEncoded + * DESCRIPTION: + * + * This function obtains the encoded message from the OcspRequest pointed to + * by "request", storing the result at "pRequest". + * + * PARAMETERS + * "request" + * The address of the OcspRequest whose encoded message is to be + * retrieved. Must be non-NULL. + * "pRequest" + * The address at which is stored the address of the encoded message. 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. + */ +PKIX_Error * +pkix_pl_OcspRequest_GetEncoded( + PKIX_PL_OcspRequest *request, + SECItem **pRequest, + void *plContext) +{ + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetEncoded"); + PKIX_NULLCHECK_TWO(request, pRequest); + + *pRequest = request->encoded; + + PKIX_RETURN(OCSPREQUEST); +} + +/* + * FUNCTION: pkix_pl_OcspRequest_GetLocation + * DESCRIPTION: + * + * This function obtains the location from the OcspRequest pointed to + * by "request", storing the result at "pLocation". + * + * PARAMETERS + * "request" + * The address of the OcspRequest whose encoded message is to be + * retrieved. Must be non-NULL. + * "pLocation" + * The address at which is stored the address of the location. 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. + */ +PKIX_Error * +pkix_pl_OcspRequest_GetLocation( + PKIX_PL_OcspRequest *request, + char **pLocation, + void *plContext) +{ + PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetLocation"); + PKIX_NULLCHECK_TWO(request, pLocation); + + *pLocation = request->location; + + PKIX_RETURN(OCSPREQUEST); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h new file mode 100644 index 0000000000..fa79266eec --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h @@ -0,0 +1,61 @@ +/* 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_ocsprequest.h + * + * OcspRequest Object Definitions + * + */ + +#ifndef _PKIX_PL_OCSPREQUEST_H +#define _PKIX_PL_OCSPREQUEST_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_OcspRequestStruct{ + PKIX_PL_Cert *cert; + PKIX_PL_Date *validity; + PKIX_Boolean addServiceLocator; + PKIX_PL_Cert *signerCert; + CERTOCSPRequest *decoded; + SECItem *encoded; + char *location; +}; + +/* see source file for function documentation */ + +PKIX_Error * +pkix_pl_OcspRequest_Create( + PKIX_PL_Cert *cert, + PKIX_PL_OcspCertID *cid, + PKIX_PL_Date *validity, + PKIX_PL_Cert *signerCert, + PKIX_UInt32 methodFlags, + PKIX_Boolean *pURIFound, + PKIX_PL_OcspRequest **pRequest, + void *plContext); + +PKIX_Error * +pkix_pl_OcspRequest_GetEncoded( + PKIX_PL_OcspRequest *request, + SECItem **pRequest, + void *plContext); + +PKIX_Error * +pkix_pl_OcspRequest_GetLocation( + PKIX_PL_OcspRequest *request, + char **pLocation, + void *plContext); + +PKIX_Error *pkix_pl_OcspRequest_RegisterSelf(void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_OCSPREQUEST_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c new file mode 100644 index 0000000000..fa41f8102e --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c @@ -0,0 +1,1069 @@ +/* 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_ocspresponse.c + * + */ + +#include "pkix_pl_ocspresponse.h" + +/* ----Public functions------------------------------------- */ +/* + * This is the libpkix replacement for CERT_VerifyOCSPResponseSignature. + * It is used if it has been set as the verifyFcn member of ocspChecker. + */ +PKIX_Error * +PKIX_PL_OcspResponse_UseBuildChain( + PKIX_PL_Cert *signerCert, + PKIX_PL_Date *producedAt, + PKIX_ProcessingParams *procParams, + void **pNBIOContext, + void **pState, + PKIX_BuildResult **pBuildResult, + PKIX_VerifyNode **pVerifyTree, + void *plContext) +{ + PKIX_ProcessingParams *caProcParams = NULL; + PKIX_PL_Date *date = NULL; + PKIX_ComCertSelParams *certSelParams = NULL; + PKIX_CertSelector *certSelector = NULL; + void *nbioContext = NULL; + PKIX_Error *buildError = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_OcspResponse_UseBuildChain"); + PKIX_NULLCHECK_THREE(signerCert, producedAt, procParams); + PKIX_NULLCHECK_THREE(pNBIOContext, pState, pBuildResult); + + nbioContext = *pNBIOContext; + *pNBIOContext = NULL; + + /* Are we resuming after a WOULDBLOCK return, or starting anew ? */ + if (nbioContext == NULL) { + /* Starting anew */ + PKIX_CHECK(PKIX_PL_Object_Duplicate + ((PKIX_PL_Object *)procParams, + (PKIX_PL_Object **)&caProcParams, + plContext), + PKIX_OBJECTDUPLICATEFAILED); + + PKIX_CHECK(PKIX_ProcessingParams_SetDate(procParams, date, plContext), + PKIX_PROCESSINGPARAMSSETDATEFAILED); + + /* create CertSelector with target certificate in params */ + + PKIX_CHECK(PKIX_CertSelector_Create + (NULL, NULL, &certSelector, plContext), + PKIX_CERTSELECTORCREATEFAILED); + + PKIX_CHECK(PKIX_ComCertSelParams_Create + (&certSelParams, plContext), + PKIX_COMCERTSELPARAMSCREATEFAILED); + + PKIX_CHECK(PKIX_ComCertSelParams_SetCertificate + (certSelParams, signerCert, plContext), + PKIX_COMCERTSELPARAMSSETCERTIFICATEFAILED); + + PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams + (certSelector, certSelParams, plContext), + PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED); + + PKIX_CHECK(PKIX_ProcessingParams_SetTargetCertConstraints + (caProcParams, certSelector, plContext), + PKIX_PROCESSINGPARAMSSETTARGETCERTCONSTRAINTSFAILED); + } + + buildError = PKIX_BuildChain + (caProcParams, + &nbioContext, + pState, + pBuildResult, + pVerifyTree, + plContext); + + /* non-null nbioContext means the build would block */ + if (nbioContext != NULL) { + + *pNBIOContext = nbioContext; + + /* no buildResult means the build has failed */ + } else if (buildError) { + pkixErrorResult = buildError; + buildError = NULL; + } else { + PKIX_DECREF(*pState); + } + +cleanup: + + PKIX_DECREF(caProcParams); + PKIX_DECREF(date); + PKIX_DECREF(certSelParams); + PKIX_DECREF(certSelector); + + PKIX_RETURN(OCSPRESPONSE); +} + +/* --Private-OcspResponse-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspResponse_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspResponse_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_OcspResponse *ocspRsp = NULL; + const SEC_HttpClientFcn *httpClient = NULL; + const SEC_HttpClientFcnV1 *hcv1 = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext), + PKIX_OBJECTNOTANOCSPRESPONSE); + + ocspRsp = (PKIX_PL_OcspResponse *)object; + + if (ocspRsp->nssOCSPResponse != NULL) { + CERT_DestroyOCSPResponse(ocspRsp->nssOCSPResponse); + ocspRsp->nssOCSPResponse = NULL; + } + + if (ocspRsp->signerCert != NULL) { + CERT_DestroyCertificate(ocspRsp->signerCert); + ocspRsp->signerCert = NULL; + } + + httpClient = (const SEC_HttpClientFcn *)(ocspRsp->httpClient); + + if (httpClient && (httpClient->version == 1)) { + + hcv1 = &(httpClient->fcnTable.ftable1); + + if (ocspRsp->sessionRequest != NULL) { + (*hcv1->freeFcn)(ocspRsp->sessionRequest); + ocspRsp->sessionRequest = NULL; + } + + if (ocspRsp->serverSession != NULL) { + (*hcv1->freeSessionFcn)(ocspRsp->serverSession); + ocspRsp->serverSession = NULL; + } + } + + if (ocspRsp->arena != NULL) { + PORT_FreeArena(ocspRsp->arena, PR_FALSE); + ocspRsp->arena = NULL; + } + + PKIX_DECREF(ocspRsp->producedAtDate); + PKIX_DECREF(ocspRsp->pkixSignerCert); + PKIX_DECREF(ocspRsp->request); + +cleanup: + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspResponse_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_OcspResponse *ocspRsp = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext), + PKIX_OBJECTNOTANOCSPRESPONSE); + + ocspRsp = (PKIX_PL_OcspResponse *)object; + + if (ocspRsp->encodedResponse->data == NULL) { + *pHashcode = 0; + } else { + PKIX_CHECK(pkix_hash + (ocspRsp->encodedResponse->data, + ocspRsp->encodedResponse->len, + pHashcode, + plContext), + PKIX_HASHFAILED); + } + +cleanup: + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_OcspResponse_Equals( + PKIX_PL_Object *firstObj, + PKIX_PL_Object *secondObj, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_UInt32 secondType = 0; + PKIX_UInt32 firstLen = 0; + PKIX_UInt32 i = 0; + PKIX_PL_OcspResponse *rsp1 = NULL; + PKIX_PL_OcspResponse *rsp2 = NULL; + const unsigned char *firstData = NULL; + const unsigned char *secondData = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Equals"); + PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult); + + /* test that firstObj is a OcspResponse */ + PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPRESPONSE_TYPE, plContext), + PKIX_FIRSTOBJARGUMENTNOTANOCSPRESPONSE); + + /* + * Since we know firstObj is a OcspResponse, if both references are + * identical, they must be equal + */ + if (firstObj == secondObj){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObj isn't a OcspResponse, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType(secondObj, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_OCSPRESPONSE_TYPE) { + goto cleanup; + } + + rsp1 = (PKIX_PL_OcspResponse *)firstObj; + rsp2 = (PKIX_PL_OcspResponse *)secondObj; + + /* If either lacks an encoded string, they cannot be compared */ + firstData = (const unsigned char *)rsp1->encodedResponse->data; + secondData = (const unsigned char *)rsp2->encodedResponse->data; + if ((firstData == NULL) || (secondData == NULL)) { + goto cleanup; + } + + firstLen = rsp1->encodedResponse->len; + + if (firstLen != rsp2->encodedResponse->len) { + goto cleanup; + } + + for (i = 0; i < firstLen; i++) { + if (*firstData++ != *secondData++) { + goto cleanup; + } + } + + *pResult = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_RegisterSelf + * DESCRIPTION: + * Registers PKIX_OCSPRESPONSE_TYPE and its related functions with + * systemClasses[] + * PARAMETERS: + * "plContext" + * Platform-specific context pointer. + * 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_OcspResponse_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry *entry = &systemClasses[PKIX_OCSPRESPONSE_TYPE]; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_RegisterSelf"); + + entry->description = "OcspResponse"; + entry->typeObjectSize = sizeof(PKIX_PL_OcspResponse); + entry->destructor = pkix_pl_OcspResponse_Destroy; + entry->equalsFunction = pkix_pl_OcspResponse_Equals; + entry->hashcodeFunction = pkix_pl_OcspResponse_Hashcode; + entry->duplicateFunction = pkix_duplicateImmutable; + + PKIX_RETURN(OCSPRESPONSE); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_OcspResponse_Create + * DESCRIPTION: + * + * This function transmits the OcspRequest pointed to by "request" and obtains + * an OcspResponse, which it stores at "pOcspResponse". If the HTTPClient + * supports non-blocking I/O this function may store a non-NULL value at + * "pNBIOContext" (the WOULDBLOCK condition). In that case the caller should + * make a subsequent call with the same value in "pNBIOContext" and + * "pOcspResponse" to resume the operation. Additional WOULDBLOCK returns may + * occur; the caller should persist until a return occurs with NULL stored at + * "pNBIOContext". + * + * If a SEC_HttpClientFcn "responder" is supplied, it is used as the client + * to which the OCSP query is sent. If none is supplied, the default responder + * is used. + * + * If an OcspResponse_VerifyCallback "verifyFcn" is supplied, it is used to + * verify the Cert received from the responder as the signer. If none is + * supplied, the default verification function is used. + * + * The contents of "request" are ignored on calls subsequent to a WOULDBLOCK + * return, and the caller is permitted to supply NULL. + * + * PARAMETERS + * "request" + * Address of the OcspRequest for which a response is desired. + * "httpMethod" + * GET or POST + * "responder" + * Address, if non-NULL, of the SEC_HttpClientFcn to be sent the OCSP + * query. + * "verifyFcn" + * Address, if non-NULL, of the OcspResponse_VerifyCallback function to be + * used to verify the Cert of the OCSP responder. + * "pNBIOContext" + * Address at which platform-dependent information is stored for handling + * of non-blocking I/O. Must be non-NULL. + * "pOcspResponse" + * The address where the created OcspResponse 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 an OcspResponse 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_OcspResponse_Create( + PKIX_PL_OcspRequest *request, + const char *httpMethod, + void *responder, + PKIX_PL_VerifyCallback verifyFcn, + void **pNBIOContext, + PKIX_PL_OcspResponse **pResponse, + void *plContext) +{ + void *nbioContext = NULL; + PKIX_PL_OcspResponse *ocspResponse = NULL; + const SEC_HttpClientFcn *httpClient = NULL; + const SEC_HttpClientFcnV1 *hcv1 = NULL; + SECStatus rv = SECFailure; + char *location = NULL; + char *hostname = NULL; + char *path = NULL; + char *responseContentType = NULL; + PRUint16 port = 0; + SEC_HTTP_SERVER_SESSION serverSession = NULL; + SEC_HTTP_REQUEST_SESSION sessionRequest = NULL; + SECItem *encodedRequest = NULL; + PRUint16 responseCode = 0; + char *responseData = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Create"); + PKIX_NULLCHECK_TWO(pNBIOContext, pResponse); + + if (!strcmp(httpMethod, "GET") && !strcmp(httpMethod, "POST")) { + PKIX_ERROR(PKIX_INVALIDOCSPHTTPMETHOD); + } + + nbioContext = *pNBIOContext; + *pNBIOContext = NULL; + + if (nbioContext != NULL) { + + ocspResponse = *pResponse; + PKIX_NULLCHECK_ONE(ocspResponse); + + httpClient = ocspResponse->httpClient; + serverSession = ocspResponse->serverSession; + sessionRequest = ocspResponse->sessionRequest; + PKIX_NULLCHECK_THREE(httpClient, serverSession, sessionRequest); + + } else { + PKIX_UInt32 timeout = + ((PKIX_PL_NssContext*)plContext)->timeoutSeconds; + + PKIX_NULLCHECK_ONE(request); + + PKIX_CHECK(pkix_pl_OcspRequest_GetEncoded + (request, &encodedRequest, plContext), + PKIX_OCSPREQUESTGETENCODEDFAILED); + + /* prepare initial message to HTTPClient */ + + /* Is there a default responder and is it enabled? */ + if (responder) { + httpClient = (const SEC_HttpClientFcn *)responder; + } else { + httpClient = SEC_GetRegisteredHttpClient(); + } + + if (httpClient && (httpClient->version == 1)) { + char *fullGetPath = NULL; + const char *sessionPath = NULL; + PRBool usePOST = !strcmp(httpMethod, "POST"); + + hcv1 = &(httpClient->fcnTable.ftable1); + + PKIX_CHECK(pkix_pl_OcspRequest_GetLocation + (request, &location, plContext), + PKIX_OCSPREQUESTGETLOCATIONFAILED); + + /* parse location -> hostname, port, path */ + rv = CERT_ParseURL(location, &hostname, &port, &path); + if (rv == SECFailure || hostname == NULL || path == NULL) { + PKIX_ERROR(PKIX_URLPARSINGFAILED); + } + + rv = (*hcv1->createSessionFcn)(hostname, port, + &serverSession); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + + if (usePOST) { + sessionPath = path; + } else { + /* calculate, are we allowed to use GET? */ + enum { max_get_request_size = 255 }; /* defined by RFC2560 */ + char b64ReqBuf[max_get_request_size+1]; + size_t base64size; + size_t slashLengthIfNeeded = 0; + size_t pathLength; + PRInt32 urlEncodedBufLength; + size_t getURLLength; + char *walkOutput = NULL; + + pathLength = strlen(path); + if (path[pathLength-1] != '/') { + slashLengthIfNeeded = 1; + } + base64size = (((encodedRequest->len +2)/3) * 4); + if (base64size > max_get_request_size) { + PKIX_ERROR(PKIX_OCSPGETREQUESTTOOBIG); + } + memset(b64ReqBuf, 0, sizeof(b64ReqBuf)); + PL_Base64Encode((const char *)encodedRequest->data, encodedRequest->len, b64ReqBuf); + urlEncodedBufLength = ocsp_UrlEncodeBase64Buf(b64ReqBuf, NULL); + getURLLength = pathLength + urlEncodedBufLength + slashLengthIfNeeded; + fullGetPath = (char*)PORT_Alloc(getURLLength); + if (!fullGetPath) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + strcpy(fullGetPath, path); + walkOutput = fullGetPath + pathLength; + if (walkOutput > fullGetPath && slashLengthIfNeeded) { + strcpy(walkOutput, "/"); + ++walkOutput; + } + ocsp_UrlEncodeBase64Buf(b64ReqBuf, walkOutput); + sessionPath = fullGetPath; + } + + rv = (*hcv1->createFcn)(serverSession, "http", + sessionPath, httpMethod, + PR_SecondsToInterval(timeout), + &sessionRequest); + sessionPath = NULL; + if (fullGetPath) { + PORT_Free(fullGetPath); + fullGetPath = NULL; + } + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + + if (usePOST) { + rv = (*hcv1->setPostDataFcn)(sessionRequest, + (char *)encodedRequest->data, + encodedRequest->len, + "application/ocsp-request"); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + } + + /* create a PKIX_PL_OcspResponse object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_OCSPRESPONSE_TYPE, + sizeof (PKIX_PL_OcspResponse), + (PKIX_PL_Object **)&ocspResponse, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + PKIX_INCREF(request); + ocspResponse->request = request; + ocspResponse->httpClient = httpClient; + ocspResponse->serverSession = serverSession; + serverSession = NULL; + ocspResponse->sessionRequest = sessionRequest; + sessionRequest = NULL; + ocspResponse->verifyFcn = verifyFcn; + ocspResponse->handle = CERT_GetDefaultCertDB(); + ocspResponse->encodedResponse = NULL; + ocspResponse->arena = NULL; + ocspResponse->producedAt = 0; + ocspResponse->producedAtDate = NULL; + ocspResponse->pkixSignerCert = NULL; + ocspResponse->nssOCSPResponse = NULL; + ocspResponse->signerCert = NULL; + } + } + + /* begin or resume IO to HTTPClient */ + if (httpClient && (httpClient->version == 1)) { + PRUint32 responseDataLen = + ((PKIX_PL_NssContext*)plContext)->maxResponseLength; + + hcv1 = &(httpClient->fcnTable.ftable1); + + rv = (*hcv1->trySendAndReceiveFcn)(ocspResponse->sessionRequest, + (PRPollDesc **)&nbioContext, + &responseCode, + (const char **)&responseContentType, + NULL, /* responseHeaders */ + (const char **)&responseData, + &responseDataLen); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + /* responseContentType is a pointer to the null-terminated + * string returned by httpclient. Memory allocated for context + * type will be freed with freeing of the HttpClient struct. */ + if (PORT_Strcasecmp(responseContentType, + "application/ocsp-response")) { + PKIX_ERROR(PKIX_OCSPSERVERERROR); + } + if (nbioContext != NULL) { + *pNBIOContext = nbioContext; + goto cleanup; + } + if (responseCode != 200) { + PKIX_ERROR(PKIX_OCSPBADHTTPRESPONSE); + } + ocspResponse->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (ocspResponse->arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + ocspResponse->encodedResponse = SECITEM_AllocItem + (ocspResponse->arena, NULL, responseDataLen); + if (ocspResponse->encodedResponse == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + PORT_Memcpy(ocspResponse->encodedResponse->data, + responseData, responseDataLen); + } + *pResponse = ocspResponse; + ocspResponse = NULL; + +cleanup: + + if (path != NULL) { + PORT_Free(path); + } + if (hostname != NULL) { + PORT_Free(hostname); + } + if (ocspResponse) { + PKIX_DECREF(ocspResponse); + } + if (serverSession) { + hcv1->freeSessionFcn(serverSession); + } + if (sessionRequest) { + hcv1->freeFcn(sessionRequest); + } + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_Decode + * DESCRIPTION: + * + * This function decodes the DER data contained in the OcspResponse pointed to + * by "response", storing PKIX_TRUE at "pPassed" if the decoding was + * successful, and PKIX_FALSE otherwise. + * + * PARAMETERS + * "response" + * The address of the OcspResponse whose DER data is to be decoded. Must + * be non-NULL. + * "pPassed" + * Address at which the Boolean result is stored. Must be non-NULL. + * "pReturnCode" + * Address at which the SECErrorCodes result 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 an OcspResponse 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_OcspResponse_Decode( + PKIX_PL_OcspResponse *response, + PKIX_Boolean *pPassed, + SECErrorCodes *pReturnCode, + void *plContext) +{ + + PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_Decode"); + PKIX_NULLCHECK_TWO(response, response->encodedResponse); + + response->nssOCSPResponse = + CERT_DecodeOCSPResponse(response->encodedResponse); + + if (response->nssOCSPResponse != NULL) { + *pPassed = PKIX_TRUE; + *pReturnCode = 0; + } else { + *pPassed = PKIX_FALSE; + *pReturnCode = PORT_GetError(); + } + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_GetStatus + * DESCRIPTION: + * + * This function checks the response status of the OcspResponse pointed to + * by "response", storing PKIX_TRUE at "pPassed" if the responder understood + * the request and considered it valid, and PKIX_FALSE otherwise. + * + * PARAMETERS + * "response" + * The address of the OcspResponse whose status is to be retrieved. Must + * be non-NULL. + * "pPassed" + * Address at which the Boolean result 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 an OcspResponse 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_OcspResponse_GetStatus( + PKIX_PL_OcspResponse *response, + PKIX_Boolean *pPassed, + SECErrorCodes *pReturnCode, + void *plContext) +{ + SECStatus rv = SECFailure; + + PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_GetStatus"); + PKIX_NULLCHECK_FOUR(response, response->nssOCSPResponse, pPassed, pReturnCode); + + rv = CERT_GetOCSPResponseStatus(response->nssOCSPResponse); + + if (rv == SECSuccess) { + *pPassed = PKIX_TRUE; + *pReturnCode = 0; + } else { + *pPassed = PKIX_FALSE; + *pReturnCode = PORT_GetError(); + } + + PKIX_RETURN(OCSPRESPONSE); +} + + +static PKIX_Error* +pkix_pl_OcspResponse_VerifyResponse( + PKIX_PL_OcspResponse *response, + PKIX_ProcessingParams *procParams, + SECCertUsage certUsage, + void **state, + PKIX_BuildResult **buildResult, + void **pNBIOContext, + void *plContext) +{ + SECStatus rv = SECFailure; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifyResponse"); + + if (response->verifyFcn != NULL) { + void *lplContext = NULL; + + PKIX_CHECK( + PKIX_PL_NssContext_Create(((SECCertificateUsage)1) << certUsage, + PKIX_FALSE, NULL, &lplContext), + PKIX_NSSCONTEXTCREATEFAILED); + + PKIX_CHECK( + (response->verifyFcn)((PKIX_PL_Object*)response->pkixSignerCert, + NULL, response->producedAtDate, + procParams, pNBIOContext, + state, buildResult, + NULL, lplContext), + PKIX_CERTVERIFYKEYUSAGEFAILED); + rv = SECSuccess; + } else { + /* checkSig is !isRoot */ + PRBool checkSig = response->signerCert->isRoot ? PR_FALSE : PR_TRUE; + rv = CERT_VerifyCert(response->handle, response->signerCert, checkSig, + certUsage, response->producedAt, NULL, NULL); + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_CERTVERIFYKEYUSAGEFAILED); + } + } + +cleanup: + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); + } + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_VerifySignature + * DESCRIPTION: + * + * This function verifies the ocspResponse signature field in the OcspResponse + * pointed to by "response", storing PKIX_TRUE at "pPassed" if verification + * is successful and PKIX_FALSE otherwise. If verification is unsuccessful an + * error code (an enumeration of type SECErrorCodes) is stored at *pReturnCode. + * + * PARAMETERS + * "response" + * The address of the OcspResponse whose signature field is to be + * retrieved. Must be non-NULL. + * "cert" + * The address of the Cert for which the OCSP query was made. Must be + * non-NULL. + * "procParams" + * Address of ProcessingParams used to initialize the ExpirationChecker + * and TargetCertChecker. Must be non-NULL. + * "pPassed" + * Address at which the Boolean result is stored. Must be non-NULL. + * "pNBIOContext" + * Address at which the NBIOContext is stored indicating whether the + * checking is complete. 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 an OcspResponse 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_OcspResponse_VerifySignature( + PKIX_PL_OcspResponse *response, + PKIX_PL_Cert *cert, + PKIX_ProcessingParams *procParams, + PKIX_Boolean *pPassed, + void **pNBIOContext, + void *plContext) +{ + SECStatus rv = SECFailure; + CERTOCSPResponse *nssOCSPResponse = NULL; + CERTCertificate *issuerCert = NULL; + PKIX_BuildResult *buildResult = NULL; + void *nbio = NULL; + void *state = NULL; + + ocspSignature *signature = NULL; + ocspResponseData *tbsData = NULL; + SECItem *tbsResponseDataDER = NULL; + + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifySignature"); + PKIX_NULLCHECK_FOUR(response, cert, pPassed, pNBIOContext); + + nbio = *pNBIOContext; + *pNBIOContext = NULL; + + nssOCSPResponse = response->nssOCSPResponse; + if (nssOCSPResponse == NULL) { + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); + goto cleanup; + } + + tbsData = + ocsp_GetResponseData(nssOCSPResponse, &tbsResponseDataDER); + + signature = ocsp_GetResponseSignature(nssOCSPResponse); + + + /* Are we resuming after a WOULDBLOCK response? */ + if (nbio == NULL) { + /* No, this is a new query */ + + issuerCert = CERT_FindCertIssuer(cert->nssCert, PR_Now(), + certUsageAnyCA); + + /* + * If this signature has already gone through verification, + * just return the cached result. + */ + if (signature->wasChecked) { + if (signature->status == SECSuccess) { + response->signerCert = + CERT_DupCertificate(signature->cert); + } else { + PORT_SetError(signature->failureReason); + goto cleanup; + } + } + + response->signerCert = + ocsp_GetSignerCertificate(response->handle, tbsData, + signature, issuerCert); + + if (response->signerCert == NULL) { + if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) { + /* Make the error a little more specific. */ + PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT); + } + goto cleanup; + } + PKIX_CHECK( + PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert, + &(response->pkixSignerCert), + plContext), + PKIX_CERTCREATEWITHNSSCERTFAILED); + + /* + * We could mark this true at the top of this function, or + * always below at "finish", but if the problem was just that + * we could not find the signer's cert, leave that as if the + * signature hasn't been checked. Maybe a subsequent call will + * have better luck. + */ + signature->wasChecked = PR_TRUE; + + /* + * We are about to verify the signer certificate; we need to + * specify *when* that certificate must be valid -- for our + * purposes we expect it to be valid when the response was + * signed. The value of "producedAt" is the signing time. + */ + rv = DER_GeneralizedTimeToTime(&response->producedAt, + &tbsData->producedAt); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE); + goto cleanup; + } + + /* + * We need producedAtDate and pkixSignerCert if we are calling a + * user-supplied verification function. Let's put their + * creation before the code that gets repeated when + * non-blocking I/O is used. + */ + + PKIX_CHECK( + pkix_pl_Date_CreateFromPRTime((PRTime)response->producedAt, + &(response->producedAtDate), + plContext), + PKIX_DATECREATEFROMPRTIMEFAILED); + + } + + /* + * Just because we have a cert does not mean it is any good; check + * it for validity, trust and usage. Use the caller-supplied + * verification function, if one was supplied. + */ + if (ocsp_CertIsOCSPDefaultResponder(response->handle, + response->signerCert)) { + rv = SECSuccess; + } else { + SECCertUsage certUsage; + if (CERT_IsCACert(response->signerCert, NULL)) { + certUsage = certUsageAnyCA; + } else { + certUsage = certUsageStatusResponder; + } + PKIX_CHECK_ONLY_FATAL( + pkix_pl_OcspResponse_VerifyResponse(response, procParams, + certUsage, &state, + &buildResult, &nbio, + plContext), + PKIX_CERTVERIFYKEYUSAGEFAILED); + if (pkixTempErrorReceived) { + rv = SECFailure; + goto cleanup; + } + if (nbio != NULL) { + *pNBIOContext = nbio; + goto cleanup; + } + } + + rv = ocsp_VerifyResponseSignature(response->signerCert, signature, + tbsResponseDataDER, NULL); + +cleanup: + if (rv == SECSuccess) { + *pPassed = PKIX_TRUE; + } else { + *pPassed = PKIX_FALSE; + } + + if (signature) { + if (signature->wasChecked) { + signature->status = rv; + } + + if (rv != SECSuccess) { + signature->failureReason = PORT_GetError(); + if (response->signerCert != NULL) { + CERT_DestroyCertificate(response->signerCert); + response->signerCert = NULL; + } + } else { + /* Save signer's certificate in signature. */ + signature->cert = CERT_DupCertificate(response->signerCert); + } + } + + if (issuerCert) + CERT_DestroyCertificate(issuerCert); + + PKIX_RETURN(OCSPRESPONSE); +} + +/* + * FUNCTION: pkix_pl_OcspResponse_GetStatusForCert + * DESCRIPTION: + * + * This function checks the revocation status of the Cert for which the + * OcspResponse was obtained, storing PKIX_TRUE at "pPassed" if the Cert has + * not been revoked and PKIX_FALSE otherwise. + * + * PARAMETERS + * "response" + * The address of the OcspResponse whose certificate status is to be + * retrieved. Must be non-NULL. + * "pPassed" + * Address at which the Boolean result is stored. Must be non-NULL. + * "pReturnCode" + * Address at which the SECErrorCodes result 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 an OcspResponse 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_OcspResponse_GetStatusForCert( + PKIX_PL_OcspCertID *cid, + PKIX_PL_OcspResponse *response, + PKIX_Boolean allowCachingOfFailures, + PKIX_PL_Date *validity, + PKIX_Boolean *pPassed, + SECErrorCodes *pReturnCode, + void *plContext) +{ + PRTime time = 0; + SECStatus rv = SECFailure; + CERTOCSPSingleResponse *single = NULL; + + PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_GetStatusForCert"); + PKIX_NULLCHECK_THREE(response, pPassed, pReturnCode); + + /* + * It is an error to call this function except following a successful + * return from pkix_pl_OcspResponse_VerifySignature, which would have + * set response->signerCert. + */ + PKIX_NULLCHECK_TWO(response->signerCert, response->request); + PKIX_NULLCHECK_TWO(cid, cid->certID); + + if (validity != NULL) { + PKIX_Error *er = pkix_pl_Date_GetPRTime(validity, &time, plContext); + PKIX_DECREF(er); + } + if (!time) { + time = PR_Now(); + } + + rv = ocsp_GetVerifiedSingleResponseForCertID(response->handle, + response->nssOCSPResponse, + cid->certID, + response->signerCert, + time, &single); + if (rv == SECSuccess) { + /* + * Check whether the status says revoked, and if so + * how that compares to the time value passed into this routine. + */ + rv = ocsp_CertHasGoodStatus(single->certStatus, time); + } + + if (rv == SECSuccess || allowCachingOfFailures) { + /* allowed to update the cache */ + PRBool certIDWasConsumed = PR_FALSE; + + if (single) { + ocsp_CacheSingleResponse(cid->certID,single, + &certIDWasConsumed); + } else { + cert_RememberOCSPProcessingFailure(cid->certID, + &certIDWasConsumed); + } + + if (certIDWasConsumed) { + cid->certID = NULL; + } + } + + if (rv == SECSuccess) { + *pPassed = PKIX_TRUE; + *pReturnCode = 0; + } else { + *pPassed = PKIX_FALSE; + *pReturnCode = PORT_GetError(); + } + + PKIX_RETURN(OCSPRESPONSE); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h new file mode 100644 index 0000000000..dcf88c9603 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h @@ -0,0 +1,106 @@ +/* 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_ocspresponse.h + * + * OcspResponse Object Definitions + * + */ + +#ifndef _PKIX_PL_OCSPRESPONSE_H +#define _PKIX_PL_OCSPRESPONSE_H + +#include "pkix_pl_common.h" +#include "pkix_pl_ocspcertid.h" +#include "hasht.h" +#include "cryptohi.h" +#include "ocspti.h" +#include "ocspi.h" +#include "plbase64.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_OCSP_RESPONSE_LEN (64*1024) + +struct PKIX_PL_OcspResponseStruct{ + PLArenaPool *arena; + const PKIX_PL_OcspRequest *request; + const SEC_HttpClientFcn *httpClient; + SEC_HTTP_SERVER_SESSION serverSession; + SEC_HTTP_REQUEST_SESSION sessionRequest; + PKIX_PL_VerifyCallback verifyFcn; + SECItem *encodedResponse; + CERTCertDBHandle *handle; + PRTime producedAt; + PKIX_PL_Date *producedAtDate; + PKIX_PL_Cert *pkixSignerCert; + CERTOCSPResponse *nssOCSPResponse; + CERTCertificate *signerCert; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_OcspResponse_RegisterSelf(void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_Create( + PKIX_PL_OcspRequest *request, + const char *httpMechanism, + void *responder, + PKIX_PL_VerifyCallback verifyFcn, + void **pNBIOContext, + PKIX_PL_OcspResponse **pResponse, + void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_Decode( + PKIX_PL_OcspResponse *response, + PKIX_Boolean *passed, + SECErrorCodes *pReturnCode, + void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_GetStatus( + PKIX_PL_OcspResponse *response, + PKIX_Boolean *passed, + SECErrorCodes *pReturnCode, + void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_VerifySignature( + PKIX_PL_OcspResponse *response, + PKIX_PL_Cert *cert, + PKIX_ProcessingParams *procParams, + PKIX_Boolean *pPassed, + void **pNBIOContext, + void *plContext); + +PKIX_Error * +pkix_pl_OcspResponse_GetStatusForCert( + PKIX_PL_OcspCertID *cid, + PKIX_PL_OcspResponse *response, + PKIX_Boolean allowCachingOfFailures, + PKIX_PL_Date *validity, + PKIX_Boolean *pPassed, + SECErrorCodes *pReturnCode, + void *plContext); + +PKIX_Error * +PKIX_PL_OcspResponse_UseBuildChain( + PKIX_PL_Cert *signerCert, + PKIX_PL_Date *producedAt, + PKIX_ProcessingParams *procParams, + void **pNBIOContext, + void **pState, + PKIX_BuildResult **pBuildResult, + PKIX_VerifyNode **pVerifyTree, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_OCSPRESPONSE_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c new file mode 100644 index 0000000000..2dfe9a9c2c --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c @@ -0,0 +1,489 @@ +/* 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_publickey.c + * + * Certificate Object Functions + * + */ + +#include "pkix_pl_publickey.h" + +/* --Private-Cert-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_PublicKey_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the PublicKey + * pointed to by "pkixPubKey" and stores it at "pString". + * + * PARAMETERS + * "pkixPubKey" + * Address of PublicKey whose string representation is desired. + * Must be non-NULL. + * "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 PublicKey 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_PublicKey_ToString_Helper( + PKIX_PL_PublicKey *pkixPubKey, + PKIX_PL_String **pString, + void *plContext) +{ + SECAlgorithmID algorithm; + SECOidTag pubKeyTag; + char *asciiOID = NULL; + PKIX_Boolean freeAsciiOID = PKIX_FALSE; + SECItem oidBytes; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_ToString_Helper"); + PKIX_NULLCHECK_THREE(pkixPubKey, pkixPubKey->nssSPKI, pString); + + /* + * XXX for now, we print out public key algorithm's + * description - add params and bytes later + */ + + /* + * If the algorithm OID is known to NSS, + * we print out the ASCII description that is + * registered with NSS. Otherwise, if unknown, + * we print out the OID numbers (eg. "1.2.840.3") + */ + + algorithm = pkixPubKey->nssSPKI->algorithm; + + PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_GetAlgorithmTag).\n"); + pubKeyTag = SECOID_GetAlgorithmTag(&algorithm); + if (pubKeyTag != SEC_OID_UNKNOWN){ + PKIX_PUBLICKEY_DEBUG + ("\t\tCalling SECOID_FindOIDTagDescription).\n"); + asciiOID = (char *)SECOID_FindOIDTagDescription(pubKeyTag); + if (!asciiOID){ + PKIX_ERROR(PKIX_SECOIDFINDOIDTAGDESCRIPTIONFAILED); + } + } else { /* pubKeyTag == SEC_OID_UNKNOWN */ + oidBytes = algorithm.algorithm; + PKIX_CHECK(pkix_pl_oidBytes2Ascii + (&oidBytes, &asciiOID, plContext), + PKIX_OIDBYTES2ASCIIFAILED); + freeAsciiOID = PKIX_TRUE; + } + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, (void *)asciiOID, 0, pString, plContext), + PKIX_UNABLETOCREATEPSTRING); + +cleanup: + + /* + * we only free asciiOID if it was malloc'ed by pkix_pl_oidBytes2Ascii + */ + if (freeAsciiOID){ + PKIX_FREE(asciiOID); + } + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_DestroySPKI + * DESCRIPTION: + * Frees all memory associated with the CERTSubjectPublicKeyInfo pointed to + * by "nssSPKI". + * PARAMETERS + * "nssSPKI" + * Address of CERTSubjectPublicKeyInfo. 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 an Object 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_DestroySPKI( + CERTSubjectPublicKeyInfo *nssSPKI, + void *plContext) +{ + PKIX_ENTER(PUBLICKEY, "pkix_pl_DestroySPKI"); + + PKIX_NULLCHECK_ONE(nssSPKI); + + PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_DestroyAlgorithmID).\n"); + SECOID_DestroyAlgorithmID(&nssSPKI->algorithm, PKIX_FALSE); + + PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); + SECITEM_FreeItem(&nssSPKI->subjectPublicKey, PKIX_FALSE); + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_PublicKey_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_PublicKey_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_PublicKey *pubKey = NULL; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Destroy"); + + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext), + PKIX_OBJECTNOTPUBLICKEY); + + pubKey = (PKIX_PL_PublicKey *)object; + + if (pubKey->nssSPKI) { + + PKIX_CHECK(pkix_pl_DestroySPKI(pubKey->nssSPKI, plContext), + PKIX_DESTROYSPKIFAILED); + + PKIX_FREE(pubKey->nssSPKI); + } + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_PublicKey_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_PublicKey_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_PublicKey *pkixPubKey = NULL; + PKIX_PL_String *pubKeyString = NULL; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext), + PKIX_OBJECTNOTPUBLICKEY); + + pkixPubKey = (PKIX_PL_PublicKey *)object; + + PKIX_CHECK(pkix_pl_PublicKey_ToString_Helper + (pkixPubKey, &pubKeyString, plContext), + PKIX_PUBLICKEYTOSTRINGHELPERFAILED); + + *pString = pubKeyString; + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_PublicKey_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_PublicKey_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_PublicKey *pkixPubKey = NULL; + SECItem algOID; + SECItem algParams; + SECItem nssPubKey; + PKIX_UInt32 algOIDHash; + PKIX_UInt32 algParamsHash; + PKIX_UInt32 pubKeyHash; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext), + PKIX_OBJECTNOTPUBLICKEY); + + pkixPubKey = (PKIX_PL_PublicKey *)object; + + PKIX_NULLCHECK_ONE(pkixPubKey->nssSPKI); + + algOID = pkixPubKey->nssSPKI->algorithm.algorithm; + algParams = pkixPubKey->nssSPKI->algorithm.parameters; + nssPubKey = pkixPubKey->nssSPKI->subjectPublicKey; + + PKIX_CHECK(pkix_hash + (algOID.data, algOID.len, &algOIDHash, plContext), + PKIX_HASHFAILED); + + PKIX_CHECK(pkix_hash + (algParams.data, algParams.len, &algParamsHash, plContext), + PKIX_HASHFAILED); + + PKIX_CHECK(pkix_hash + (nssPubKey.data, nssPubKey.len, &pubKeyHash, plContext), + PKIX_HASHFAILED); + + *pHashcode = pubKeyHash; + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + + +/* + * FUNCTION: pkix_pl_PublicKey_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_PublicKey_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_PublicKey *firstPKIXPubKey = NULL; + PKIX_PL_PublicKey *secondPKIXPubKey = NULL; + CERTSubjectPublicKeyInfo *firstSPKI = NULL; + CERTSubjectPublicKeyInfo *secondSPKI = NULL; + SECComparison cmpResult; + PKIX_UInt32 secondType; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is a PublicKey */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_PUBLICKEY_TYPE, plContext), + PKIX_FIRSTOBJECTNOTPUBLICKEY); + + /* + * Since we know firstObject is a PublicKey, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't a PublicKey, 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_PUBLICKEY_TYPE) goto cleanup; + + firstPKIXPubKey = ((PKIX_PL_PublicKey *)firstObject); + secondPKIXPubKey = (PKIX_PL_PublicKey *)secondObject; + + firstSPKI = firstPKIXPubKey->nssSPKI; + secondSPKI = secondPKIXPubKey->nssSPKI; + + PKIX_NULLCHECK_TWO(firstSPKI, secondSPKI); + + PKIX_PL_NSSCALLRV(PUBLICKEY, cmpResult, SECOID_CompareAlgorithmID, + (&firstSPKI->algorithm, &secondSPKI->algorithm)); + + if (cmpResult == SECEqual){ + PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); + cmpResult = SECITEM_CompareItem + (&firstSPKI->subjectPublicKey, + &secondSPKI->subjectPublicKey); + } + + *pResult = (cmpResult == SECEqual)?PKIX_TRUE:PKIX_FALSE; + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: pkix_pl_PublicKey_RegisterSelf + * DESCRIPTION: + * Registers PKIX_PUBLICKEY_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_PublicKey_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_RegisterSelf"); + + entry.description = "PublicKey"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_PublicKey); + entry.destructor = pkix_pl_PublicKey_Destroy; + entry.equalsFunction = pkix_pl_PublicKey_Equals; + entry.hashcodeFunction = pkix_pl_PublicKey_Hashcode; + entry.toStringFunction = pkix_pl_PublicKey_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + systemClasses[PKIX_PUBLICKEY_TYPE] = entry; + + PKIX_RETURN(PUBLICKEY); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_PublicKey_NeedsDSAParameters + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_PublicKey_NeedsDSAParameters( + PKIX_PL_PublicKey *pubKey, + PKIX_Boolean *pNeedsParams, + void *plContext) +{ + CERTSubjectPublicKeyInfo *nssSPKI = NULL; + KeyType pubKeyType; + PKIX_Boolean needsParams = PKIX_FALSE; + + PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_NeedsDSAParameters"); + PKIX_NULLCHECK_TWO(pubKey, pNeedsParams); + + nssSPKI = pubKey->nssSPKI; + + PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n"); + pubKeyType = CERT_GetCertKeyType(nssSPKI); + if (!pubKeyType){ + PKIX_ERROR(PKIX_PUBKEYTYPENULLKEY); + } + + if ((pubKeyType == dsaKey) && + (nssSPKI->algorithm.parameters.len == 0)){ + needsParams = PKIX_TRUE; + } + + *pNeedsParams = needsParams; + +cleanup: + + PKIX_RETURN(PUBLICKEY); +} + +/* + * FUNCTION: PKIX_PL_PublicKey_MakeInheritedDSAPublicKey + * (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_PublicKey_MakeInheritedDSAPublicKey( + PKIX_PL_PublicKey *firstKey, + PKIX_PL_PublicKey *secondKey, + PKIX_PL_PublicKey **pResultKey, + void *plContext) +{ + CERTSubjectPublicKeyInfo *firstSPKI = NULL; + CERTSubjectPublicKeyInfo *secondSPKI = NULL; + CERTSubjectPublicKeyInfo *thirdSPKI = NULL; + PKIX_PL_PublicKey *resultKey = NULL; + KeyType firstPubKeyType; + KeyType secondPubKeyType; + SECStatus rv; + + PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_MakeInheritedDSAPublicKey"); + PKIX_NULLCHECK_THREE(firstKey, secondKey, pResultKey); + PKIX_NULLCHECK_TWO(firstKey->nssSPKI, secondKey->nssSPKI); + + firstSPKI = firstKey->nssSPKI; + secondSPKI = secondKey->nssSPKI; + + PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n"); + firstPubKeyType = CERT_GetCertKeyType(firstSPKI); + if (!firstPubKeyType){ + PKIX_ERROR(PKIX_FIRSTPUBKEYTYPENULLKEY); + } + + PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n"); + secondPubKeyType = CERT_GetCertKeyType(secondSPKI); + if (!secondPubKeyType){ + PKIX_ERROR(PKIX_SECONDPUBKEYTYPENULLKEY); + } + + if ((firstPubKeyType == dsaKey) && + (firstSPKI->algorithm.parameters.len == 0)){ + if (secondPubKeyType != dsaKey) { + PKIX_ERROR(PKIX_SECONDKEYNOTDSAPUBLICKEY); + } else if (secondSPKI->algorithm.parameters.len == 0) { + PKIX_ERROR + (PKIX_SECONDKEYDSAPUBLICKEY); + } else { + PKIX_CHECK(PKIX_PL_Calloc + (1, + sizeof (CERTSubjectPublicKeyInfo), + (void **)&thirdSPKI, + plContext), + PKIX_CALLOCFAILED); + + PKIX_PUBLICKEY_DEBUG + ("\t\tCalling" + "SECKEY_CopySubjectPublicKeyInfo).\n"); + rv = SECKEY_CopySubjectPublicKeyInfo + (NULL, thirdSPKI, firstSPKI); + if (rv != SECSuccess) { + PKIX_ERROR + (PKIX_SECKEYCOPYSUBJECTPUBLICKEYINFOFAILED); + } + + PKIX_PUBLICKEY_DEBUG + ("\t\tCalling SECITEM_CopyItem).\n"); + rv = SECITEM_CopyItem(NULL, + &thirdSPKI->algorithm.parameters, + &secondSPKI->algorithm.parameters); + + if (rv != SECSuccess) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + /* create a PKIX_PL_PublicKey object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_PUBLICKEY_TYPE, + sizeof (PKIX_PL_PublicKey), + (PKIX_PL_Object **)&resultKey, + plContext), + PKIX_COULDNOTCREATEOBJECT); + + /* populate the SPKI field */ + resultKey->nssSPKI = thirdSPKI; + *pResultKey = resultKey; + } + } else { + *pResultKey = NULL; + } + +cleanup: + + if (thirdSPKI && PKIX_ERROR_RECEIVED){ + PKIX_CHECK(pkix_pl_DestroySPKI(thirdSPKI, plContext), + PKIX_DESTROYSPKIFAILED); + PKIX_FREE(thirdSPKI); + } + + PKIX_RETURN(PUBLICKEY); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h new file mode 100644 index 0000000000..8918859d2d --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h @@ -0,0 +1,38 @@ +/* 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_publickey.h + * + * Public Key Object Definitions + * + */ + +#ifndef _PKIX_PL_PUBLICKEY_H +#define _PKIX_PL_PUBLICKEY_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PKIX_PL_PublicKeyStruct { + CERTSubjectPublicKeyInfo *nssSPKI; +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_PublicKey_RegisterSelf(void *plContext); + +PKIX_Error * +PKIX_PL_PublicKey_NeedsDSAParameters( + PKIX_PL_PublicKey *pubKey, + PKIX_Boolean *pNeedsParams, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_PUBLICKEY_H */ diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c new file mode 100644 index 0000000000..e37439cf01 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c @@ -0,0 +1,667 @@ +/* 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_x500name.c + * + * X500Name Object Functions + * + */ + +#include "pkix_pl_x500name.h" + +/* --Private-X500Name-Functions------------------------------------- */ + +/* + * FUNCTION: pkix_pl_X500Name_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_X500Name_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_X500Name *name = NULL; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_Destroy"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_CheckType(object, PKIX_X500NAME_TYPE, plContext), + PKIX_OBJECTNOTANX500NAME); + + name = (PKIX_PL_X500Name *)object; + + /* PORT_FreeArena will destroy arena, and, allocated on it, CERTName + * and SECItem */ + if (name->arena) { + PORT_FreeArena(name->arena, PR_FALSE); + name->arena = NULL; + } + +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_X500Name_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_X500Name *name = NULL; + char *string = NULL; + PKIX_UInt32 strLength = 0; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_toString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_X500NAME_TYPE, plContext), + PKIX_OBJECTNOTANX500NAME); + + name = (PKIX_PL_X500Name *)object; + string = CERT_NameToAscii(&name->nssDN); + if (!string){ + PKIX_ERROR(PKIX_CERTNAMETOASCIIFAILED); + } + strLength = PL_strlen(string); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, string, strLength, pString, plContext), + PKIX_STRINGCREATEFAILED); + +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_X500Name_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_PL_X500Name *name = NULL; + SECItem *derBytes = NULL; + PKIX_UInt32 nameHash; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_X500NAME_TYPE, plContext), + PKIX_OBJECTNOTANX500NAME); + + name = (PKIX_PL_X500Name *)object; + + /* we hash over the bytes in the DER encoding */ + + derBytes = &name->derName; + + PKIX_CHECK(pkix_hash + (derBytes->data, derBytes->len, &nameHash, plContext), + PKIX_HASHFAILED); + + *pHashcode = nameHash; + +cleanup: + + PKIX_RETURN(X500NAME); +} + + +/* + * FUNCTION: pkix_pl_X500Name_Equals + * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_pl_X500Name_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_UInt32 secondType; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* test that firstObject is an X500Name */ + PKIX_CHECK(pkix_CheckType(firstObject, PKIX_X500NAME_TYPE, plContext), + PKIX_FIRSTOBJECTARGUMENTNOTANX500NAME); + + /* + * Since we know firstObject is an X500Name, if both references are + * identical, they must be equal + */ + if (firstObject == secondObject){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If secondObject isn't an X500Name, 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_X500NAME_TYPE) goto cleanup; + + PKIX_CHECK( + PKIX_PL_X500Name_Match((PKIX_PL_X500Name *)firstObject, + (PKIX_PL_X500Name *)secondObject, + pResult, plContext), + PKIX_X500NAMEMATCHFAILED); + +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_RegisterSelf + * DESCRIPTION: + * Registers PKIX_X500NAME_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_X500Name_RegisterSelf(void *plContext) +{ + + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_RegisterSelf"); + + entry.description = "X500Name"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_X500Name); + entry.destructor = pkix_pl_X500Name_Destroy; + entry.equalsFunction = pkix_pl_X500Name_Equals; + entry.hashcodeFunction = pkix_pl_X500Name_Hashcode; + entry.toStringFunction = pkix_pl_X500Name_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_duplicateImmutable; + + systemClasses[PKIX_X500NAME_TYPE] = entry; + + PKIX_RETURN(X500NAME); +} + +#ifdef BUILD_LIBPKIX_TESTS +/* + * FUNCTION: pkix_pl_X500Name_CreateFromUtf8 + * + * DESCRIPTION: + * Creates an X500Name object from the RFC1485 string representation pointed + * to by "stringRep", and stores the result at "pName". If the string cannot + * be successfully converted, a non-fatal error is returned. + * + * NOTE: ifdefed BUILD_LIBPKIX_TESTS function: this function is allowed to be + * called only by pkix tests programs. + * + * PARAMETERS: + * "stringRep" + * Address of the RFC1485 string to be converted. Must be non-NULL. + * "pName" + * Address where the X500Name result 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 an X500NAME 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_X500Name_CreateFromUtf8( + char *stringRep, + PKIX_PL_X500Name **pName, + void *plContext) +{ + PKIX_PL_X500Name *x500Name = NULL; + PLArenaPool *arena = NULL; + CERTName *nssDN = NULL; + SECItem *resultSecItem = NULL; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_CreateFromUtf8"); + PKIX_NULLCHECK_TWO(pName, stringRep); + + nssDN = CERT_AsciiToName(stringRep); + if (nssDN == NULL) { + PKIX_ERROR(PKIX_COULDNOTCREATENSSDN); + } + + arena = nssDN->arena; + + /* create a PKIX_PL_X500Name object */ + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_X500NAME_TYPE, + sizeof (PKIX_PL_X500Name), + (PKIX_PL_Object **)&x500Name, + plContext), + PKIX_COULDNOTCREATEX500NAMEOBJECT); + + /* populate the nssDN field */ + x500Name->arena = arena; + x500Name->nssDN.arena = arena; + x500Name->nssDN.rdns = nssDN->rdns; + + resultSecItem = + SEC_ASN1EncodeItem(arena, &x500Name->derName, nssDN, + CERT_NameTemplate); + + if (resultSecItem == NULL){ + PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED); + } + + *pName = x500Name; + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + if (x500Name) { + PKIX_PL_Object_DecRef((PKIX_PL_Object*)x500Name, + plContext); + } else if (nssDN) { + CERT_DestroyName(nssDN); + } + } + + PKIX_RETURN(X500NAME); +} +#endif /* BUILD_LIBPKIX_TESTS */ + +/* + * FUNCTION: pkix_pl_X500Name_GetCERTName + * + * DESCRIPTION: + * + * Returns the pointer to CERTName member of X500Name structure. + * + * Returned pointed should not be freed.2 + * + * PARAMETERS: + * "xname" + * Address of X500Name whose OrganizationName is to be extracted. Must be + * non-NULL. + * "pCERTName" + * Address where result 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. + */ +PKIX_Error * +pkix_pl_X500Name_GetCERTName( + PKIX_PL_X500Name *xname, + CERTName **pCERTName, + void *plContext) +{ + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetCERTName"); + PKIX_NULLCHECK_TWO(xname, pCERTName); + + *pCERTName = &xname->nssDN; + + PKIX_RETURN(X500NAME); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_X500Name_CreateFromCERTName (see comments in pkix_pl_pki.h) + */ + +PKIX_Error * +PKIX_PL_X500Name_CreateFromCERTName( + SECItem *derName, + CERTName *name, + PKIX_PL_X500Name **pName, + void *plContext) +{ + PLArenaPool *arena = NULL; + SECStatus rv = SECFailure; + PKIX_PL_X500Name *x500Name = NULL; + + PKIX_ENTER(X500NAME, "PKIX_PL_X500Name_CreateFromCERTName"); + PKIX_NULLCHECK_ONE(pName); + if (derName == NULL && name == NULL) { + PKIX_ERROR(PKIX_NULLARGUMENT); + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_X500NAME_TYPE, + sizeof (PKIX_PL_X500Name), + (PKIX_PL_Object **)&x500Name, + plContext), + PKIX_COULDNOTCREATEX500NAMEOBJECT); + + x500Name->arena = arena; + x500Name->nssDN.arena = NULL; + + if (derName != NULL) { + rv = SECITEM_CopyItem(arena, &x500Name->derName, derName); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + } + + if (name != NULL) { + rv = CERT_CopyName(arena, &x500Name->nssDN, name); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_CERTCOPYNAMEFAILED); + } + } else { + rv = SEC_QuickDERDecodeItem(arena, &x500Name->nssDN, + CERT_NameTemplate, + &x500Name->derName); + if (rv == SECFailure) { + PKIX_ERROR(PKIX_SECQUICKDERDECODERFAILED); + } + } + + *pName = x500Name; + +cleanup: + if (PKIX_ERROR_RECEIVED) { + if (x500Name) { + PKIX_PL_Object_DecRef((PKIX_PL_Object*)x500Name, + plContext); + } else if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } + } + + PKIX_RETURN(X500NAME); +} + +#ifdef BUILD_LIBPKIX_TESTS +/* + * FUNCTION: PKIX_PL_X500Name_Create (see comments in pkix_pl_pki.h) + * + * NOTE: ifdefed BUILD_LIBPKIX_TESTS function: this function is allowed + * to be called only by pkix tests programs. + */ +PKIX_Error * +PKIX_PL_X500Name_Create( + PKIX_PL_String *stringRep, + PKIX_PL_X500Name **pName, + void *plContext) +{ + char *utf8String = NULL; + PKIX_UInt32 utf8Length = 0; + + PKIX_ENTER(X500NAME, "PKIX_PL_X500Name_Create"); + PKIX_NULLCHECK_TWO(pName, stringRep); + + /* + * convert the input PKIX_PL_String to PKIX_UTF8_NULL_TERM. + * we need to use this format specifier because + * CERT_AsciiToName expects a NULL-terminated UTF8 string. + * Since UTF8 allow NUL characters in the middle of the + * string, this is buggy. However, as a workaround, using + * PKIX_UTF8_NULL_TERM gives us a NULL-terminated UTF8 string. + */ + + PKIX_CHECK(PKIX_PL_String_GetEncoded + (stringRep, + PKIX_UTF8_NULL_TERM, + (void **)&utf8String, + &utf8Length, + plContext), + PKIX_STRINGGETENCODEDFAILED); + + PKIX_CHECK( + pkix_pl_X500Name_CreateFromUtf8(utf8String, + pName, plContext), + PKIX_X500NAMECREATEFROMUTF8FAILED); + +cleanup: + PKIX_FREE(utf8String); + + PKIX_RETURN(X500NAME); +} +#endif /* BUILD_LIBPKIX_TESTS */ + +/* + * FUNCTION: PKIX_PL_X500Name_Match (see comments in pkix_pl_pki.h) + */ +PKIX_Error * +PKIX_PL_X500Name_Match( + PKIX_PL_X500Name *firstX500Name, + PKIX_PL_X500Name *secondX500Name, + PKIX_Boolean *pResult, + void *plContext) +{ + SECItem *firstDerName = NULL; + SECItem *secondDerName = NULL; + SECComparison cmpResult; + + PKIX_ENTER(X500NAME, "PKIX_PL_X500Name_Match"); + PKIX_NULLCHECK_THREE(firstX500Name, secondX500Name, pResult); + + if (firstX500Name == secondX500Name){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + firstDerName = &firstX500Name->derName; + secondDerName = &secondX500Name->derName; + + PKIX_NULLCHECK_TWO(firstDerName->data, secondDerName->data); + + cmpResult = SECITEM_CompareItem(firstDerName, secondDerName); + if (cmpResult != SECEqual) { + cmpResult = CERT_CompareName(&firstX500Name->nssDN, + &secondX500Name->nssDN); + } + + *pResult = (cmpResult == SECEqual); + +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_GetSECName + * + * DESCRIPTION: + * Returns a copy of CERTName DER representation allocated on passed in arena. + * If allocation on arena can not be done, NULL is stored at "pSECName". + * + * PARAMETERS: + * "xname" + * Address of X500Name whose CERTName flag is to be encoded. Must be + * non-NULL. + * "arena" + * Address of the PLArenaPool to be used in the encoding, and in which + * "pSECName" will be allocated. Must be non-NULL. + * "pSECName" + * Address where result 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. + */ +PKIX_Error * +pkix_pl_X500Name_GetDERName( + PKIX_PL_X500Name *xname, + PLArenaPool *arena, + SECItem **pDERName, + void *plContext) +{ + SECItem *derName = NULL; + + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetDERName"); + + PKIX_NULLCHECK_THREE(xname, arena, pDERName); + + /* Return NULL is X500Name was not created from DER */ + if (xname->derName.data == NULL) { + *pDERName = NULL; + goto cleanup; + } + + derName = SECITEM_ArenaDupItem(arena, &xname->derName); + if (derName == NULL) { + PKIX_ERROR(PKIX_OUTOFMEMORY); + } + + *pDERName = derName; +cleanup: + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_GetCommonName + * + * DESCRIPTION: + * Extracts the CommonName component of the X500Name object pointed to by + * "xname", and stores the result at "pCommonName". If the CommonName cannot + * be successfully extracted, NULL is stored at "pCommonName". + * + * The returned string must be freed with PORT_Free. + * + * PARAMETERS: + * "xname" + * Address of X500Name whose CommonName is to be extracted. Must be + * non-NULL. + * "pCommonName" + * Address where result 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. + */ +PKIX_Error * +pkix_pl_X500Name_GetCommonName( + PKIX_PL_X500Name *xname, + unsigned char **pCommonName, + void *plContext) +{ + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetCommonName"); + PKIX_NULLCHECK_TWO(xname, pCommonName); + + *pCommonName = (unsigned char *)CERT_GetCommonName(&xname->nssDN); + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_GetCountryName + * + * DESCRIPTION: + * Extracts the CountryName component of the X500Name object pointed to by + * "xname", and stores the result at "pCountryName". If the CountryName cannot + * be successfully extracted, NULL is stored at "pCountryName". + * + * The returned string must be freed with PORT_Free. + * + * PARAMETERS: + * "xname" + * Address of X500Name whose CountryName is to be extracted. Must be + * non-NULL. + * "pCountryName" + * Address where result 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. + */ +PKIX_Error * +pkix_pl_X500Name_GetCountryName( + PKIX_PL_X500Name *xname, + unsigned char **pCountryName, + void *plContext) +{ + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetCountryName"); + PKIX_NULLCHECK_TWO(xname, pCountryName); + + *pCountryName = (unsigned char*)CERT_GetCountryName(&xname->nssDN); + + PKIX_RETURN(X500NAME); +} + +/* + * FUNCTION: pkix_pl_X500Name_GetOrgName + * + * DESCRIPTION: + * Extracts the OrganizationName component of the X500Name object pointed to by + * "xname", and stores the result at "pOrgName". If the OrganizationName cannot + * be successfully extracted, NULL is stored at "pOrgName". + * + * The returned string must be freed with PORT_Free. + * + * PARAMETERS: + * "xname" + * Address of X500Name whose OrganizationName is to be extracted. Must be + * non-NULL. + * "pOrgName" + * Address where result 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. + */ +PKIX_Error * +pkix_pl_X500Name_GetOrgName( + PKIX_PL_X500Name *xname, + unsigned char **pOrgName, + void *plContext) +{ + PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetOrgName"); + PKIX_NULLCHECK_TWO(xname, pOrgName); + + *pOrgName = (unsigned char*)CERT_GetOrgName(&xname->nssDN); + + PKIX_RETURN(X500NAME); +} diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h new file mode 100644 index 0000000000..a62bdb82d5 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h @@ -0,0 +1,74 @@ +/* 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_x500name.h + * + * X500Name Object Type Definitions + * + */ + +#ifndef _PKIX_PL_X500NAME_H +#define _PKIX_PL_X500NAME_H + +#include "pkix_pl_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +struct PKIX_PL_X500NameStruct{ + PLArenaPool *arena; /* X500Name arena. Shared arena with nssDN + * and derName */ + CERTName nssDN; + SECItem derName; /* adding DER encoded CERTName to the structure + * to avoid unnecessary name encoding when pass + * der name to cert finder */ +}; + +/* see source file for function documentation */ + +PKIX_Error *pkix_pl_X500Name_RegisterSelf(void *plContext); + +PKIX_Error *pkix_pl_X500Name_GetDERName( + PKIX_PL_X500Name *xname, + PLArenaPool *arena, + SECItem **pSECName, + void *plContext); + +#ifdef BUILD_LIBPKIX_TESTS +PKIX_Error * pkix_pl_X500Name_CreateFromUtf8( + char *stringRep, + PKIX_PL_X500Name **pName, + void *plContext); +#endif /* BUILD_LIBPKIX_TESTS */ + +PKIX_Error *pkix_pl_X500Name_GetCommonName( + PKIX_PL_X500Name *xname, + unsigned char **pCommonName, + void *plContext); + +PKIX_Error * +pkix_pl_X500Name_GetCountryName( + PKIX_PL_X500Name *xname, + unsigned char **pCountryName, + void *plContext); + +PKIX_Error * +pkix_pl_X500Name_GetOrgName( + PKIX_PL_X500Name *xname, + unsigned char **pOrgName, + void *plContext); + +PKIX_Error * +pkix_pl_X500Name_GetCERTName( + PKIX_PL_X500Name *xname, + CERTName **pCERTName, + void *plContext); + +#ifdef __cplusplus +} +#endif + +#endif /* _PKIX_PL_X500NAME_H */ |