andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * pkix_pl_publickey.c andre@0: * andre@0: * Certificate Object Functions andre@0: * andre@0: */ andre@0: andre@0: #include "pkix_pl_publickey.h" andre@0: andre@0: /* --Private-Cert-Functions------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_PublicKey_ToString_Helper andre@0: * DESCRIPTION: andre@0: * andre@0: * Helper function that creates a string representation of the PublicKey andre@0: * pointed to by "pkixPubKey" and stores it at "pString". andre@0: * andre@0: * PARAMETERS andre@0: * "pkixPubKey" andre@0: * Address of PublicKey whose string representation is desired. andre@0: * Must be non-NULL. andre@0: * "pString" andre@0: * Address where object pointer will be stored. Must be non-NULL. andre@0: * "plContext" - Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a PublicKey Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_PublicKey_ToString_Helper( andre@0: PKIX_PL_PublicKey *pkixPubKey, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: SECAlgorithmID algorithm; andre@0: SECOidTag pubKeyTag; andre@0: char *asciiOID = NULL; andre@0: PKIX_Boolean freeAsciiOID = PKIX_FALSE; andre@0: SECItem oidBytes; andre@0: andre@0: PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_ToString_Helper"); andre@0: PKIX_NULLCHECK_THREE(pkixPubKey, pkixPubKey->nssSPKI, pString); andre@0: andre@0: /* andre@0: * XXX for now, we print out public key algorithm's andre@0: * description - add params and bytes later andre@0: */ andre@0: andre@0: /* andre@0: * If the algorithm OID is known to NSS, andre@0: * we print out the ASCII description that is andre@0: * registered with NSS. Otherwise, if unknown, andre@0: * we print out the OID numbers (eg. "1.2.840.3") andre@0: */ andre@0: andre@0: algorithm = pkixPubKey->nssSPKI->algorithm; andre@0: andre@0: PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_GetAlgorithmTag).\n"); andre@0: pubKeyTag = SECOID_GetAlgorithmTag(&algorithm); andre@0: if (pubKeyTag != SEC_OID_UNKNOWN){ andre@0: PKIX_PUBLICKEY_DEBUG andre@0: ("\t\tCalling SECOID_FindOIDTagDescription).\n"); andre@0: asciiOID = (char *)SECOID_FindOIDTagDescription(pubKeyTag); andre@0: if (!asciiOID){ andre@0: PKIX_ERROR(PKIX_SECOIDFINDOIDTAGDESCRIPTIONFAILED); andre@0: } andre@0: } else { /* pubKeyTag == SEC_OID_UNKNOWN */ andre@0: oidBytes = algorithm.algorithm; andre@0: PKIX_CHECK(pkix_pl_oidBytes2Ascii andre@0: (&oidBytes, &asciiOID, plContext), andre@0: PKIX_OIDBYTES2ASCIIFAILED); andre@0: freeAsciiOID = PKIX_TRUE; andre@0: } andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, (void *)asciiOID, 0, pString, plContext), andre@0: PKIX_UNABLETOCREATEPSTRING); andre@0: andre@0: cleanup: andre@0: andre@0: /* andre@0: * we only free asciiOID if it was malloc'ed by pkix_pl_oidBytes2Ascii andre@0: */ andre@0: if (freeAsciiOID){ andre@0: PKIX_FREE(asciiOID); andre@0: } andre@0: andre@0: PKIX_RETURN(PUBLICKEY); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_DestroySPKI andre@0: * DESCRIPTION: andre@0: * Frees all memory associated with the CERTSubjectPublicKeyInfo pointed to andre@0: * by "nssSPKI". andre@0: * PARAMETERS andre@0: * "nssSPKI" andre@0: * Address of CERTSubjectPublicKeyInfo. Must be non-NULL. andre@0: * "plContext" - Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an Object Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_DestroySPKI( andre@0: CERTSubjectPublicKeyInfo *nssSPKI, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(PUBLICKEY, "pkix_pl_DestroySPKI"); andre@0: andre@0: PKIX_NULLCHECK_ONE(nssSPKI); andre@0: andre@0: PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_DestroyAlgorithmID).\n"); andre@0: SECOID_DestroyAlgorithmID(&nssSPKI->algorithm, PKIX_FALSE); andre@0: andre@0: PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_FreeItem).\n"); andre@0: SECITEM_FreeItem(&nssSPKI->subjectPublicKey, PKIX_FALSE); andre@0: andre@0: PKIX_RETURN(PUBLICKEY); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_PublicKey_Destroy andre@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_PublicKey_Destroy( andre@0: PKIX_PL_Object *object, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_PublicKey *pubKey = NULL; andre@0: andre@0: PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Destroy"); andre@0: andre@0: PKIX_NULLCHECK_ONE(object); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext), andre@0: PKIX_OBJECTNOTPUBLICKEY); andre@0: andre@0: pubKey = (PKIX_PL_PublicKey *)object; andre@0: andre@0: if (pubKey->nssSPKI) { andre@0: andre@0: PKIX_CHECK(pkix_pl_DestroySPKI(pubKey->nssSPKI, plContext), andre@0: PKIX_DESTROYSPKIFAILED); andre@0: andre@0: PKIX_FREE(pubKey->nssSPKI); andre@0: } andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(PUBLICKEY); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_PublicKey_ToString andre@0: * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_PublicKey_ToString( andre@0: PKIX_PL_Object *object, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_PublicKey *pkixPubKey = NULL; andre@0: PKIX_PL_String *pubKeyString = NULL; andre@0: andre@0: PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_toString"); andre@0: PKIX_NULLCHECK_TWO(object, pString); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext), andre@0: PKIX_OBJECTNOTPUBLICKEY); andre@0: andre@0: pkixPubKey = (PKIX_PL_PublicKey *)object; andre@0: andre@0: PKIX_CHECK(pkix_pl_PublicKey_ToString_Helper andre@0: (pkixPubKey, &pubKeyString, plContext), andre@0: PKIX_PUBLICKEYTOSTRINGHELPERFAILED); andre@0: andre@0: *pString = pubKeyString; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(PUBLICKEY); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_PublicKey_Hashcode andre@0: * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_PublicKey_Hashcode( andre@0: PKIX_PL_Object *object, andre@0: PKIX_UInt32 *pHashcode, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_PublicKey *pkixPubKey = NULL; andre@0: SECItem algOID; andre@0: SECItem algParams; andre@0: SECItem nssPubKey; andre@0: PKIX_UInt32 algOIDHash; andre@0: PKIX_UInt32 algParamsHash; andre@0: PKIX_UInt32 pubKeyHash; andre@0: PKIX_UInt32 fullHash; andre@0: andre@0: PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Hashcode"); andre@0: PKIX_NULLCHECK_TWO(object, pHashcode); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext), andre@0: PKIX_OBJECTNOTPUBLICKEY); andre@0: andre@0: pkixPubKey = (PKIX_PL_PublicKey *)object; andre@0: andre@0: PKIX_NULLCHECK_ONE(pkixPubKey->nssSPKI); andre@0: andre@0: algOID = pkixPubKey->nssSPKI->algorithm.algorithm; andre@0: algParams = pkixPubKey->nssSPKI->algorithm.parameters; andre@0: nssPubKey = pkixPubKey->nssSPKI->subjectPublicKey; andre@0: andre@0: PKIX_CHECK(pkix_hash andre@0: (algOID.data, algOID.len, &algOIDHash, plContext), andre@0: PKIX_HASHFAILED); andre@0: andre@0: PKIX_CHECK(pkix_hash andre@0: (algParams.data, algParams.len, &algParamsHash, plContext), andre@0: PKIX_HASHFAILED); andre@0: andre@0: PKIX_CHECK(pkix_hash andre@0: (nssPubKey.data, nssPubKey.len, &pubKeyHash, plContext), andre@0: PKIX_HASHFAILED); andre@0: andre@0: fullHash = algOIDHash + algParamsHash + pubKeyHash; andre@0: andre@0: *pHashcode = pubKeyHash; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(PUBLICKEY); andre@0: } andre@0: andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_PublicKey_Equals andre@0: * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_PublicKey_Equals( andre@0: PKIX_PL_Object *firstObject, andre@0: PKIX_PL_Object *secondObject, andre@0: PKIX_Boolean *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_PublicKey *firstPKIXPubKey = NULL; andre@0: PKIX_PL_PublicKey *secondPKIXPubKey = NULL; andre@0: CERTSubjectPublicKeyInfo *firstSPKI = NULL; andre@0: CERTSubjectPublicKeyInfo *secondSPKI = NULL; andre@0: SECComparison cmpResult; andre@0: PKIX_UInt32 secondType; andre@0: andre@0: PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Equals"); andre@0: PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); andre@0: andre@0: /* test that firstObject is a PublicKey */ andre@0: PKIX_CHECK(pkix_CheckType(firstObject, PKIX_PUBLICKEY_TYPE, plContext), andre@0: PKIX_FIRSTOBJECTNOTPUBLICKEY); andre@0: andre@0: /* andre@0: * Since we know firstObject is a PublicKey, if both references are andre@0: * identical, they must be equal andre@0: */ andre@0: if (firstObject == secondObject){ andre@0: *pResult = PKIX_TRUE; andre@0: goto cleanup; andre@0: } andre@0: andre@0: /* andre@0: * If secondObject isn't a PublicKey, we don't throw an error. andre@0: * We simply return a Boolean result of FALSE andre@0: */ andre@0: *pResult = PKIX_FALSE; andre@0: PKIX_CHECK(PKIX_PL_Object_GetType andre@0: (secondObject, &secondType, plContext), andre@0: PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); andre@0: if (secondType != PKIX_PUBLICKEY_TYPE) goto cleanup; andre@0: andre@0: firstPKIXPubKey = ((PKIX_PL_PublicKey *)firstObject); andre@0: secondPKIXPubKey = (PKIX_PL_PublicKey *)secondObject; andre@0: andre@0: firstSPKI = firstPKIXPubKey->nssSPKI; andre@0: secondSPKI = secondPKIXPubKey->nssSPKI; andre@0: andre@0: PKIX_NULLCHECK_TWO(firstSPKI, secondSPKI); andre@0: andre@0: PKIX_PL_NSSCALLRV(PUBLICKEY, cmpResult, SECOID_CompareAlgorithmID, andre@0: (&firstSPKI->algorithm, &secondSPKI->algorithm)); andre@0: andre@0: if (cmpResult == SECEqual){ andre@0: PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_CompareItem).\n"); andre@0: cmpResult = SECITEM_CompareItem andre@0: (&firstSPKI->subjectPublicKey, andre@0: &secondSPKI->subjectPublicKey); andre@0: } andre@0: andre@0: *pResult = (cmpResult == SECEqual)?PKIX_TRUE:PKIX_FALSE; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(PUBLICKEY); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_PublicKey_RegisterSelf andre@0: * DESCRIPTION: andre@0: * Registers PKIX_PUBLICKEY_TYPE and its related functions with systemClasses[] andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe - for performance and complexity reasons andre@0: * andre@0: * Since this function is only called by PKIX_PL_Initialize, which should andre@0: * only be called once, it is acceptable that this function is not andre@0: * thread-safe. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_PublicKey_RegisterSelf(void *plContext) andre@0: { andre@0: andre@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; andre@0: pkix_ClassTable_Entry entry; andre@0: andre@0: PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_RegisterSelf"); andre@0: andre@0: entry.description = "PublicKey"; andre@0: entry.objCounter = 0; andre@0: entry.typeObjectSize = sizeof(PKIX_PL_PublicKey); andre@0: entry.destructor = pkix_pl_PublicKey_Destroy; andre@0: entry.equalsFunction = pkix_pl_PublicKey_Equals; andre@0: entry.hashcodeFunction = pkix_pl_PublicKey_Hashcode; andre@0: entry.toStringFunction = pkix_pl_PublicKey_ToString; andre@0: entry.comparator = NULL; andre@0: entry.duplicateFunction = pkix_duplicateImmutable; andre@0: systemClasses[PKIX_PUBLICKEY_TYPE] = entry; andre@0: andre@0: PKIX_RETURN(PUBLICKEY); andre@0: } andre@0: andre@0: /* --Public-Functions------------------------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_PublicKey_NeedsDSAParameters andre@0: * (see comments in pkix_pl_pki.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_PublicKey_NeedsDSAParameters( andre@0: PKIX_PL_PublicKey *pubKey, andre@0: PKIX_Boolean *pNeedsParams, andre@0: void *plContext) andre@0: { andre@0: CERTSubjectPublicKeyInfo *nssSPKI = NULL; andre@0: KeyType pubKeyType; andre@0: PKIX_Boolean needsParams = PKIX_FALSE; andre@0: andre@0: PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_NeedsDSAParameters"); andre@0: PKIX_NULLCHECK_TWO(pubKey, pNeedsParams); andre@0: andre@0: nssSPKI = pubKey->nssSPKI; andre@0: andre@0: PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n"); andre@0: pubKeyType = CERT_GetCertKeyType(nssSPKI); andre@0: if (!pubKeyType){ andre@0: PKIX_ERROR(PKIX_PUBKEYTYPENULLKEY); andre@0: } andre@0: andre@0: if ((pubKeyType == dsaKey) && andre@0: (nssSPKI->algorithm.parameters.len == 0)){ andre@0: needsParams = PKIX_TRUE; andre@0: } andre@0: andre@0: *pNeedsParams = needsParams; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(PUBLICKEY); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_PublicKey_MakeInheritedDSAPublicKey andre@0: * (see comments in pkix_pl_pki.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_PublicKey_MakeInheritedDSAPublicKey( andre@0: PKIX_PL_PublicKey *firstKey, andre@0: PKIX_PL_PublicKey *secondKey, andre@0: PKIX_PL_PublicKey **pResultKey, andre@0: void *plContext) andre@0: { andre@0: CERTSubjectPublicKeyInfo *firstSPKI = NULL; andre@0: CERTSubjectPublicKeyInfo *secondSPKI = NULL; andre@0: CERTSubjectPublicKeyInfo *thirdSPKI = NULL; andre@0: PKIX_PL_PublicKey *resultKey = NULL; andre@0: KeyType firstPubKeyType; andre@0: KeyType secondPubKeyType; andre@0: SECStatus rv; andre@0: andre@0: PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_MakeInheritedDSAPublicKey"); andre@0: PKIX_NULLCHECK_THREE(firstKey, secondKey, pResultKey); andre@0: PKIX_NULLCHECK_TWO(firstKey->nssSPKI, secondKey->nssSPKI); andre@0: andre@0: firstSPKI = firstKey->nssSPKI; andre@0: secondSPKI = secondKey->nssSPKI; andre@0: andre@0: PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n"); andre@0: firstPubKeyType = CERT_GetCertKeyType(firstSPKI); andre@0: if (!firstPubKeyType){ andre@0: PKIX_ERROR(PKIX_FIRSTPUBKEYTYPENULLKEY); andre@0: } andre@0: andre@0: PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n"); andre@0: secondPubKeyType = CERT_GetCertKeyType(secondSPKI); andre@0: if (!secondPubKeyType){ andre@0: PKIX_ERROR(PKIX_SECONDPUBKEYTYPENULLKEY); andre@0: } andre@0: andre@0: if ((firstPubKeyType == dsaKey) && andre@0: (firstSPKI->algorithm.parameters.len == 0)){ andre@0: if (secondPubKeyType != dsaKey) { andre@0: PKIX_ERROR(PKIX_SECONDKEYNOTDSAPUBLICKEY); andre@0: } else if (secondSPKI->algorithm.parameters.len == 0) { andre@0: PKIX_ERROR andre@0: (PKIX_SECONDKEYDSAPUBLICKEY); andre@0: } else { andre@0: PKIX_CHECK(PKIX_PL_Calloc andre@0: (1, andre@0: sizeof (CERTSubjectPublicKeyInfo), andre@0: (void **)&thirdSPKI, andre@0: plContext), andre@0: PKIX_CALLOCFAILED); andre@0: andre@0: PKIX_PUBLICKEY_DEBUG andre@0: ("\t\tCalling" andre@0: "SECKEY_CopySubjectPublicKeyInfo).\n"); andre@0: rv = SECKEY_CopySubjectPublicKeyInfo andre@0: (NULL, thirdSPKI, firstSPKI); andre@0: if (rv != SECSuccess) { andre@0: PKIX_ERROR andre@0: (PKIX_SECKEYCOPYSUBJECTPUBLICKEYINFOFAILED); andre@0: } andre@0: andre@0: PKIX_PUBLICKEY_DEBUG andre@0: ("\t\tCalling SECITEM_CopyItem).\n"); andre@0: rv = SECITEM_CopyItem(NULL, andre@0: &thirdSPKI->algorithm.parameters, andre@0: &secondSPKI->algorithm.parameters); andre@0: andre@0: if (rv != SECSuccess) { andre@0: PKIX_ERROR(PKIX_OUTOFMEMORY); andre@0: } andre@0: andre@0: /* create a PKIX_PL_PublicKey object */ andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_PUBLICKEY_TYPE, andre@0: sizeof (PKIX_PL_PublicKey), andre@0: (PKIX_PL_Object **)&resultKey, andre@0: plContext), andre@0: PKIX_COULDNOTCREATEOBJECT); andre@0: andre@0: /* populate the SPKI field */ andre@0: resultKey->nssSPKI = thirdSPKI; andre@0: *pResultKey = resultKey; andre@0: } andre@0: } else { andre@0: *pResultKey = NULL; andre@0: } andre@0: andre@0: cleanup: andre@0: andre@0: if (thirdSPKI && PKIX_ERROR_RECEIVED){ andre@0: PKIX_CHECK(pkix_pl_DestroySPKI(thirdSPKI, plContext), andre@0: PKIX_DESTROYSPKIFAILED); andre@0: PKIX_FREE(thirdSPKI); andre@0: } andre@0: andre@0: PKIX_RETURN(PUBLICKEY); andre@0: }