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