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