| /* 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); |
| } |