diff options
Diffstat (limited to 'security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c')
-rw-r--r-- | security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c | 667 |
1 files changed, 667 insertions, 0 deletions
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 000000000..e37439cf0 --- /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); +} |