/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

/*****************************************************************************
 *
 * COMPONENT_NAME: FWK - CSSM framework
 *
 * FILE: keyformats.c
 *
 * This file contains the functions needed to support different key
 * formats in the framework. These functions are used mainly in higher
 * level functions that work with contexts.
 *
 */
/*
 * (C) COPYRIGHT International Business Machines Corp. 1996, 1997
 * All Rights Reserved
 * Licensed Materials - Property of IBM
 *
 * Copyright (c) 1995, 1996, 1997 Intel Corporation. All rights reserved.
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *
 */
/*
 * WARNING: EXPORT RESTRICTED.
 * This software listing contains cryptographic methods and technology.
 * It is export restricted by the Office of Defense Trade Controls, United
 * States Department of State and cannot be downloaded or otherwise
 * exported or re-exported (i) into (or to a national or resident of) Cuba,
 * Iraq, Libya, Yugoslavia, North Korea, Iran, Syria or any other country
 * to which the US has embargoed goods; or (ii) to anyone on the US
 * Treasury Department's list of Specially Designated Nationals or the US
 * Commerce Department's Table of Denial Orders. By downloading or using
 * this product, you are agreeing to the foregoing and you are representing
 * and warranting that you are not located in, under the control of, or a
 * national or resident of any such country or on any such list.
 */

#include "cssm.h"
#include "cssmkeyformats.h"
#include "internal.h"

/* useful macros */
#define AND &&
#define OR  ||

/* static function prototypes */

static CSSM_RETURN ProcessRawKey(	CSSM_KEY_PTR srcKey,
									CSSM_KEY_PTR destKey,
									CSSM_CALLOC local_calloc,
									CSSM_FREE local_free,
									void * local_ref);

static CSSM_RETURN ProcessFlatKey(	CSSM_KEY_PTR srcKey,
									CSSM_KEY_PTR destKey,
									CSSM_CALLOC local_calloc,
									CSSM_FREE local_free,
									void * local_ref);

static CSSM_RETURN ProcessCDSAKey(	CSSM_KEY_PTR srcKey,
									CSSM_KEY_PTR destKey,
									CSSM_CALLOC local_calloc,
									CSSM_FREE local_free,
									void * local_ref);

static CSSM_RETURN CopyCssmData(CSSM_DATA_PTR src,
								CSSM_DATA_PTR	dest,
								CSSM_CALLOC local_calloc,
								void * local_ref);

static void FreeRawKey(CSSM_KEY_PTR srcKey,CSSM_FREE local_free,void * local_ref);
static void FreeCssmData(CSSM_DATA_PTR src, CSSM_FREE local_free, void *local_ref);
static void FreeRSAPublicKey(CSSM_RSA_PUBLIC_PTR src, CSSM_FREE local_free, void *local_ref);
static void FreeRSAPrivateKey(CSSM_RSA_PRIVATE_PTR src, CSSM_FREE local_free, void *local_ref);
static void FreeDSAPrivateKey(CSSM_DSA_PRIVATE_PTR src, CSSM_FREE local_free, void *local_ref);
static void FreeDSAPublicKey(CSSM_DSA_PUBLIC_PTR src, CSSM_FREE local_free, void *local_ref);
static void FreeDHPublicKey(CSSM_DH_PUBLIC_PTR src, CSSM_FREE local_free, void *local_ref);
static void FreeDHPrivateKey(CSSM_DH_PRIVATE_PTR src, CSSM_FREE local_free, void *local_ref);
static void FreeCDSAKey(CSSM_KEY_PTR srcKey, CSSM_FREE local_free,void * local_ref);
static CSSM_RETURN CheckCssmData(CSSM_DATA_PTR src);

/*****************************************************************************
 * Function: cssm_CopyKeyData
 *
 * This function deep-copies the key data from src to destination structure.
 * Depending on the format of the key, the keydata could be a flat array of
 * bytes or a structure as defined in cssmkeyformats.h.
 * Note that this function assumes that destKey structure is allocated
 * by the calling function.
 *
 *
 * Input:
 *   srcKey: The key structure to be copied
 *   destKey: The Key structure that is going to contain the copy
 *
 * Output:
 *
 * Returns:
 *		CSSM_OK
 *		CSSM_FAIL with appropriate error code
 *
 *
 */


CSSM_RETURN	cssm_CopyKeyData(CSSM_KEY_PTR	srcKey,
							 CSSM_KEY_PTR	destKey,
							 CSSM_CALLOC	local_calloc,
							 CSSM_FREE		local_free,
							 void*			local_ref) {

	CSSM_RETURN	status = CSSM_OK;



	if( cssm_IsBadReadPtr(srcKey, sizeof(*srcKey)) ){
		CSSM_SetError(&cssm_GUID, CSSM_BAD_PTR_PASSED);
		return(CSSM_FAIL);
	}

	if( cssm_IsBadWritePtr(destKey, sizeof(*destKey))) {
		CSSM_SetError(&cssm_GUID, CSSM_BAD_PTR_PASSED);
		return(CSSM_FAIL);
	}

	if (srcKey->KeyHeader.BlobType==CSSM_KEYBLOB_RAW) {
		status = ProcessRawKey(srcKey, destKey, local_calloc, local_free, local_ref);
	} else {
		/* we have a BERDER encoded or wrapped key, i.e. a flat
		 * structure
		 */
		status = ProcessFlatKey(srcKey, destKey, local_calloc, local_free, local_ref);
	}

	return(status);
}

/*****************************************************************************
 * Function: cssm_FreeKeyData
 *
 * This function deep-frees the key data structure.
 * Depending on the format of the key, the keydata could be a flat array of
 * bytes or a structure as defined in cssmkeyformats.h.
 *
 *
 * Input:
 *   srcKey: The key structure to be freed
 *
 * Output:
 *
 * Returns:
 *		void
 *
 */
void	cssm_FreeKeyData(CSSM_KEY_PTR	srcKey,
						 CSSM_FREE		local_free,
						 void*			local_ref) {

	if( cssm_IsBadWritePtr(srcKey, sizeof(*srcKey)) ){
		return;
	}

	if (srcKey->KeyHeader.BlobType==CSSM_KEYBLOB_RAW) {
		FreeRawKey(srcKey, local_free, local_ref);
	} else {
		/* we have a BERDER encoded or wrapped key, i.e. a flat
		 * structure
		 */
		FreeCssmData(&srcKey->KeyData, local_free, local_ref);
	}

	return;
}

/*****************************************************************************
 * Function: ProcessFlatKey
 *
 * This function copies the key data that is in a flat form. It will
 * allocate memory for CSSM_DATA.Data.
 *
 * Input:
 *   srcKey: The key structure to be copied
 *   destKey: The Key structure that is going to contain the copy
 *
 * Output:
 *
 * Returns:
 *		CSSM_OK
 *		CSSM_FAIL with appropriate error code
 *
 *
 */

CSSM_RETURN ProcessFlatKey(CSSM_KEY_PTR	srcKey,
						   CSSM_KEY_PTR destKey,
						   CSSM_CALLOC local_calloc,
                           CSSM_FREE local_free,
                           void * local_ref) {

	uint32	length;

	if( cssm_IsBadReadPtr(srcKey->KeyData.Data, srcKey->KeyData.Length) ){
		CSSM_SetError(&cssm_GUID, CSSM_BAD_PTR_PASSED);
		return(CSSM_FAIL);
	}

	length = srcKey->KeyData.Length;
	if ((destKey->KeyData.Data = local_calloc (length,1, local_ref)) == NULL) {
		CSSM_SetError(&cssm_GUID, CSSM_CALLOC_FAILED);
		return(CSSM_FAIL);
	}

	destKey->KeyData.Length = length;
	memcpy(	destKey->KeyData.Data,
			srcKey->KeyData.Data,
			length);

	return(CSSM_OK);
}

/*****************************************************************************
 * Function: ProcessRawKey
 *
 * This function deep-copies the key data that is in raw format
 *
 * Input:
 *   srcKey: The key structure to be copied
 *   destKey: The Key structure that is going to contain the copy
 *
 * Output:
 *
 * Returns:
 *		CSSM_OK
 *		CSSM_FAIL with appropriate error code
 *
 *
 */


CSSM_RETURN ProcessRawKey(CSSM_KEY_PTR srcKey,
						  CSSM_KEY_PTR destKey,
						  CSSM_CALLOC local_calloc,
                          CSSM_FREE local_free,
                          void * local_ref) {

	CSSM_RETURN	status=CSSM_OK;

	switch(srcKey->KeyHeader.Format) {
		case CSSM_KEYBLOB_RAW_FORMAT_CDSA:
			/* based on the key type we need to take action */
			switch(srcKey->KeyHeader.KeyClass) {
				case CSSM_KEYCLASS_PUBLIC_KEY:
				case CSSM_KEYCLASS_PRIVATE_KEY:
					status = ProcessCDSAKey(srcKey, destKey,
											local_calloc,
											local_free,
											local_ref);
				break;
				/* the following Key classes are also flat structures */
				case CSSM_KEYCLASS_SESSION_KEY:
				case CSSM_KEYCLASS_SECRET_PART:
				case CSSM_KEYCLASS_OTHER:
					status = ProcessFlatKey(srcKey, destKey,
											local_calloc,
											local_free,
											local_ref);
				break;
				default:
				break;
			}

		break;

		case CSSM_KEYBLOB_RAW_FORMAT_OTHER:
		case CSSM_KEYBLOB_RAW_FORMAT_NONE:
		case CSSM_KEYBLOB_RAW_FORMAT_CCA:
		/* this format is actually a flat structure, so we just memcpy */
			status = ProcessFlatKey(srcKey, destKey, local_calloc, local_free, local_ref);
		break;

		/* not supported or invalid combo of key blob type and format */
		case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
		case CSSM_KEYBLOB_RAW_FORMAT_PKCS3:
		case CSSM_KEYBLOB_RAW_FORMAT_MSCAPI:
		case CSSM_KEYBLOB_RAW_FORMAT_PGP:
		case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
		case CSSM_KEYBLOB_RAW_FORMAT_BSAFE:
		case CSSM_KEYBLOB_RAW_FORMAT_PKCS11:
		default:
			CSSM_SetError(&cssm_GUID,CSSM_KEY_FORMAT_NOT_SUPPORTED);
			status = CSSM_FAIL;
		break;
	}

	return(status);
}


/*****************************************************************************
 * Function: FreeRawKey
 *
 * This function deep-frees the key data that is in raw format
 *
 * Input:
 *   srcKey: The key structure to be freed
 *
 * Output:
 *
 * Returns:
 *		void
 *
 */


void FreeRawKey(CSSM_KEY_PTR srcKey,
				CSSM_FREE local_free,
                void * local_ref) {

	switch(srcKey->KeyHeader.Format) {
		case CSSM_KEYBLOB_RAW_FORMAT_CDSA:
			/* based on the key type we need to take action */
			switch(srcKey->KeyHeader.KeyClass) {
				case CSSM_KEYCLASS_PUBLIC_KEY:
				case CSSM_KEYCLASS_PRIVATE_KEY:
					FreeCDSAKey(srcKey, local_free, local_ref);
				break;
				/* the following Key classes are also flat structures */
				case CSSM_KEYCLASS_SESSION_KEY:
				case CSSM_KEYCLASS_SECRET_PART:
				case CSSM_KEYCLASS_OTHER:
					FreeCssmData(&srcKey->KeyData, local_free, local_ref);
				break;
				default:
				break;
			}

		break;

		case CSSM_KEYBLOB_RAW_FORMAT_NONE:
		case CSSM_KEYBLOB_RAW_FORMAT_CCA:
		/* this format is actually a flat structure, so we just free */
			FreeCssmData(&srcKey->KeyData, local_free, local_ref);
		break;

		/* not supported or invalid combo of key blob type and format */
		case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
		case CSSM_KEYBLOB_RAW_FORMAT_PKCS3:
		case CSSM_KEYBLOB_RAW_FORMAT_MSCAPI:
		case CSSM_KEYBLOB_RAW_FORMAT_PGP:
		case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
		case CSSM_KEYBLOB_RAW_FORMAT_BSAFE:
		case CSSM_KEYBLOB_RAW_FORMAT_PKCS11:
		case CSSM_KEYBLOB_RAW_FORMAT_OTHER:
		default:
			CSSM_SetError(&cssm_GUID,CSSM_KEY_FORMAT_NOT_SUPPORTED);

		break;
	}

	return;
}


/*****************************************************************************
 * Function: ProcessCDSAKey
 *
 * This function deep-copies the key data that is in raw format
 *
 * Input:
 *   srcKey: The key structure to be copied
 *   destKey: The Key structure that is going to contain the copy
 *
 * Output:
 *
 * Returns:
 *		CSSM_OK
 *		CSSM_FAIL with appropriate error code
 *
 *
 */


CSSM_RETURN ProcessCDSAKey(CSSM_KEY_PTR srcKey,
						  CSSM_KEY_PTR destKey,
						  CSSM_CALLOC local_calloc,
                          CSSM_FREE local_free,
                          void * local_ref) {

	CSSM_RSA_PUBLIC_PTR		rsaPublicPtr=NULL, src1;
	CSSM_RSA_PRIVATE_PTR	rsaPrivPtr=NULL,src2;
	CSSM_DSA_PUBLIC_PTR		dsaPublicPtr=NULL, src3;
	CSSM_DSA_PRIVATE_PTR	dsaPrivPtr=NULL, src4;
	CSSM_DH_PUBLIC_PTR		dhPublicPtr=NULL, src5;
	CSSM_DH_PRIVATE_PTR		dhPrivPtr=NULL, src6;
	CSSM_RETURN				status = CSSM_OK;


	switch(srcKey->KeyHeader.AlgorithmId) {

	case CSSM_ALGID_RSA:
		if (srcKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
			rsaPublicPtr = (CSSM_RSA_PUBLIC_PTR) local_calloc(sizeof(*rsaPublicPtr) ,1,
																	   local_ref);
			if( rsaPublicPtr ==NULL) {
				CSSM_SetError(&cssm_GUID, CSSM_CALLOC_FAILED);
				goto Finally;
			}

			src1 = (CSSM_RSA_PUBLIC_PTR) srcKey->KeyData.Data;
			rsaPublicPtr->modulusBits = src1->modulusBits;


			status=CopyCssmData(&src1->modulus, &rsaPublicPtr->modulus, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src1->publicExponent, &rsaPublicPtr->publicExponent, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			destKey->KeyData.Data = (uint8 *)rsaPublicPtr;
			destKey->KeyData.Length = sizeof(*rsaPublicPtr);
		} else {
			rsaPrivPtr = (CSSM_RSA_PRIVATE_PTR) local_calloc(sizeof(*rsaPrivPtr) ,1,
																	   local_ref);
			if( rsaPrivPtr ==NULL) {
				CSSM_SetError(&cssm_GUID, CSSM_CALLOC_FAILED);
				goto Finally;
			}
			src2 = (CSSM_RSA_PRIVATE_PTR) srcKey->KeyData.Data;
			status=CopyCssmData(&src2->modulus, &rsaPrivPtr->modulus, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src2->publicExponent, &rsaPrivPtr->publicExponent, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src2->privateExponent, &rsaPrivPtr->privateExponent, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src2->primeOne, &rsaPrivPtr->primeOne, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src2->primeTwo, &rsaPrivPtr->primeTwo, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src2->exponentOne, &rsaPrivPtr->exponentOne, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src2->exponentTwo, &rsaPrivPtr->exponentTwo, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src2->coefficient, &rsaPrivPtr->coefficient, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			destKey->KeyData.Data = (uint8 *)rsaPrivPtr;
			destKey->KeyData.Length = sizeof(*rsaPrivPtr);
		}
	break;



	case CSSM_ALGID_DSA:
		if (srcKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
			dsaPublicPtr = (CSSM_DSA_PUBLIC_PTR) local_calloc(sizeof(*dsaPublicPtr),1,
																	   local_ref);

			if( dsaPublicPtr ==NULL) {
				CSSM_SetError(&cssm_GUID, CSSM_CALLOC_FAILED);
				goto Finally;
			}


			src3 = (CSSM_DSA_PUBLIC_PTR) srcKey->KeyData.Data;
			status=CopyCssmData(&src3->prime,
				 &dsaPublicPtr->prime, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src3->subPrime,
				 &dsaPublicPtr->subPrime, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src3->base,
				 &dsaPublicPtr->base, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src3->publicValue,
				 &dsaPublicPtr->publicValue, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			destKey->KeyData.Data = (uint8 *)dsaPublicPtr;
			destKey->KeyData.Length = sizeof(*dsaPublicPtr);
		} else {
			dsaPrivPtr = (CSSM_DSA_PRIVATE_PTR) local_calloc(sizeof(*dsaPrivPtr), 1,
																	   local_ref);

			if( dsaPrivPtr ==NULL) {
				CSSM_SetError(&cssm_GUID, CSSM_CALLOC_FAILED);
				goto Finally;
			}

			src4 = (CSSM_DSA_PRIVATE_PTR) srcKey->KeyData.Data;
			status=CopyCssmData(	&src4->prime,
					  &dsaPrivPtr->prime, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(	&src4->subPrime,
					  &dsaPrivPtr->subPrime, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(	&src4->base,
					  &dsaPrivPtr->base, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(	&src4->privateValue,
					  &dsaPrivPtr->privateValue, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			destKey->KeyData.Data = (uint8 *)dsaPrivPtr;
			destKey->KeyData.Length = sizeof(*dsaPrivPtr);

		}
	break;

	case CSSM_ALGID_DH:
		if (srcKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
			dhPublicPtr = (CSSM_DH_PUBLIC_PTR) local_calloc(sizeof(*dhPublicPtr),1,
																	   local_ref);
			if( dhPublicPtr ==NULL) {
				CSSM_SetError(&cssm_GUID, CSSM_CALLOC_FAILED);
				goto Finally;
			}

			src5 = (CSSM_DH_PUBLIC_PTR) srcKey->KeyData.Data;
			status=CopyCssmData(&src5->prime,
				 &dhPublicPtr->prime, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src5->base,
				 &dhPublicPtr->base, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(&src5->publicValue,
				 &dhPublicPtr->publicValue, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			destKey->KeyData.Data = (uint8 *)dhPublicPtr;
			destKey->KeyData.Length = sizeof(*dhPublicPtr);
		} else {
			dhPrivPtr = (CSSM_DH_PRIVATE_PTR) local_calloc(sizeof(*dhPrivPtr), 1,
																	   local_ref);

			if( dhPrivPtr ==NULL) {
				CSSM_SetError(&cssm_GUID, CSSM_CALLOC_FAILED);
				goto Finally;
			}

			src6 = (CSSM_DH_PRIVATE_PTR) srcKey->KeyData.Data;
			status=CopyCssmData(	&src6->prime,
					  &dhPrivPtr->prime, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(	&src6->base,
					  &dhPrivPtr->base, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			status=CopyCssmData(	&src6->privateValue,
					  &dhPrivPtr->privateValue, local_calloc, local_ref);
			if (status != CSSM_OK) { goto Finally;}

			dhPrivPtr->exponentBits = src6->exponentBits;

			destKey->KeyData.Data = (uint8 *)dhPrivPtr;
			destKey->KeyData.Length = sizeof(*dhPrivPtr);
		}
		break;
	default:
	break;
	}

Finally:
	if (status !=CSSM_OK) {
		/* clean up the memory in case of an error */
		if (rsaPublicPtr != NULL) { FreeRSAPublicKey(rsaPublicPtr, local_free, local_ref);}
		if (rsaPrivPtr != NULL)   { FreeRSAPrivateKey(rsaPrivPtr, local_free, local_ref);}
		if (dsaPublicPtr != NULL) { FreeDSAPublicKey(dsaPublicPtr, local_free, local_ref);}
		if (dsaPrivPtr != NULL)   { FreeDSAPrivateKey(dsaPrivPtr, local_free, local_ref);}
		if (dhPublicPtr != NULL)  { FreeDHPublicKey(dhPublicPtr, local_free, local_ref);}
		if (dhPrivPtr != NULL)    { FreeDHPrivateKey(dhPrivPtr, local_free, local_ref);}
	}

	return(status);
}



/*****************************************************************************
 * Function: FreeCDSAKey
 *
 * This function deep-frees the key data that is in CDSA format
 *
 * Input:
 *   srcKey: The key structure to be freed
 *
 * Output:
 *
 * Returns:
 *
 *
 */


void FreeCDSAKey(	CSSM_KEY_PTR srcKey, CSSM_FREE local_free,void * local_ref) {

	switch(srcKey->KeyHeader.AlgorithmId) {

	case CSSM_ALGID_RSA:
		if (srcKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
			FreeRSAPublicKey((CSSM_RSA_PUBLIC_PTR)srcKey->KeyData.Data, local_free, local_ref);

		} else {
			FreeRSAPrivateKey((CSSM_RSA_PRIVATE_PTR)srcKey->KeyData.Data, local_free, local_ref);

		}
	break;

	case CSSM_ALGID_DSA:
		if (srcKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
			FreeDSAPublicKey((CSSM_DSA_PUBLIC_PTR)srcKey->KeyData.Data, local_free, local_ref);
		} else {
			FreeDSAPrivateKey((CSSM_DSA_PRIVATE_PTR)srcKey->KeyData.Data, local_free, local_ref);
		}
	break;

	case CSSM_ALGID_DH:
		if (srcKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
			FreeDHPublicKey((CSSM_DH_PUBLIC_PTR)srcKey->KeyData.Data, local_free, local_ref);
		} else {
			FreeDHPrivateKey((CSSM_DH_PRIVATE_PTR)srcKey->KeyData.Data, local_free, local_ref);
		}
		break;
	default:
	break;
	}

	return;
}



/*****************************************************************************
 * Function: CopyCssmData
 *
 * This function deep-copies the key data that is in raw format
 *
 * Input:
 *   src: The key structure to be copied
 *   dest: The Key structure that is going to contain the copy
 *
 * Output:
 *
 * Returns:
 *		CSSM_OK
 *		CSSM_FAIL with appropriate error code
 *
 *
 */
CSSM_RETURN CopyCssmData(CSSM_DATA_PTR src, CSSM_DATA_PTR	dest,
						 CSSM_CALLOC local_calloc, void * local_ref) {

	if( CheckCssmData(src)!= CSSM_OK ){
		CSSM_SetError(&cssm_GUID, CSSM_BAD_PTR_PASSED);
		return(CSSM_FAIL);
	}

	if ((dest->Data = local_calloc(src->Length,1, local_ref))==NULL){
		CSSM_SetError(&cssm_GUID, CSSM_CALLOC_FAILED);
		return(CSSM_FAIL);
	}

	memcpy(dest->Data, src->Data, src->Length);
	dest->Length = src->Length;

	return(CSSM_OK);

}

/*****************************************************************************
 * Function: FreeCssmData
 *
 * This function deep-frees the CSSM_DATA structure
 *
 * Input:
 *   src: The  structure to be freed
 *
 * Output:
 *
 * Returns:
 *
 *
 */
void FreeCssmData(CSSM_DATA_PTR src, CSSM_FREE local_free, void *local_ref) {

	if(CheckCssmData(src) != CSSM_OK) {
		return;
	}
	local_free(src->Data, local_ref);
	src->Data=NULL;

	return;
}


/*****************************************************************************
 * Function: FreeRSAPublicKey
 *
 * This function deep-frees the RSA Public key structure
 *
 * Input:
 *   src: The  structure to be freed
 *
 * Output:
 *
 * Returns:
 *
 *
 */
void FreeRSAPublicKey(CSSM_RSA_PUBLIC_PTR src, CSSM_FREE local_free, void *local_ref) {



	if( cssm_IsBadWritePtr(src, sizeof(*src))){ return;}

	FreeCssmData(&src->modulus,local_free, local_ref);
	FreeCssmData(&src->publicExponent, local_free, local_ref);

	local_free(src, local_ref);
	src=NULL;

	return;
}

/*****************************************************************************
 * Function: FreeRSAPrivateKey
 *
 * This function deep-frees the RSA Private key structure
 *
 * Input:
 *   src: The  structure to be freed
 *
 * Output:
 *
 * Returns:
 *
 *
 */

void FreeRSAPrivateKey(CSSM_RSA_PRIVATE_PTR src, CSSM_FREE local_free, void *local_ref) {

	if( cssm_IsBadWritePtr(src, sizeof(*src))) { return; }

	FreeCssmData(&src->modulus,local_free, local_ref);
	FreeCssmData(&src->publicExponent, local_free, local_ref);
	FreeCssmData(&src->privateExponent, local_free, local_ref);
	FreeCssmData(&src->primeOne, local_free, local_ref);
	FreeCssmData(&src->primeTwo, local_free, local_ref);
	FreeCssmData(&src->exponentOne, local_free, local_ref);
	FreeCssmData(&src->exponentTwo, local_free, local_ref);
	FreeCssmData(&src->coefficient, local_free, local_ref);

	local_free(src, local_ref);
	src=NULL;

	return;
}

/*****************************************************************************
 * Function: FreeDSAPublicKey
 *
 * This function deep-frees the DSA Public key structure
 *
 * Input:
 *   src: The  structure to be freed
 *
 * Output:
 *
 * Returns:
 *
 *
 */
void FreeDSAPublicKey(CSSM_DSA_PUBLIC_PTR src, CSSM_FREE local_free, void *local_ref) {


	if( cssm_IsBadWritePtr(src, sizeof(*src))) { return; }

	FreeCssmData(&src->prime,local_free, local_ref);
	FreeCssmData(&src->subPrime,local_free, local_ref);
	FreeCssmData(&src->base,local_free, local_ref);
	FreeCssmData(&src->publicValue,local_free, local_ref);

	local_free(src, local_ref);
	src=NULL;

	return;
}

/*****************************************************************************
 * Function: FreeDSAPrivateKey
 *
 * This function deep-frees the DSA Private key structure
 *
 * Input:
 *   src: The  structure to be freed
 *
 * Output:
 *
 * Returns:
 *
 *
 */
void FreeDSAPrivateKey(CSSM_DSA_PRIVATE_PTR src, CSSM_FREE local_free, void *local_ref) {


	if( cssm_IsBadWritePtr(src, sizeof(*src))) { return; }

	FreeCssmData(&src->prime,local_free, local_ref);
	FreeCssmData(&src->subPrime,local_free, local_ref);
	FreeCssmData(&src->base,local_free, local_ref);
	FreeCssmData(&src->privateValue,local_free, local_ref);

	local_free(src, local_ref);
	src=NULL;

	return;
}

/*****************************************************************************
 * Function: FreeDHPublicKey
 *
 * This function deep-frees the Diffie Hellman public  key structure
 *
 * Input:
 *   src: The  structure to be freed
 *
 * Output:
 *
 * Returns:
 *
 *
 */

void FreeDHPublicKey(CSSM_DH_PUBLIC_PTR src, CSSM_FREE local_free, void *local_ref) {


	if( cssm_IsBadWritePtr(src, sizeof(*src))) { return; }

	FreeCssmData(&src->prime,local_free, local_ref);
	FreeCssmData(&src->base,local_free, local_ref);
	FreeCssmData(&src->publicValue,local_free, local_ref);

	local_free(src, local_ref);
	src=NULL;

	return;
}

/*****************************************************************************
 * Function: FreeDHPrivateKey
 *
 * This function deep-frees the Diffie Hellman private key structure
 *
 * Input:
 *   src: The  structure to be freed
 *
 * Output:
 *
 * Returns:
 *
 *
 */
void FreeDHPrivateKey(CSSM_DH_PRIVATE_PTR src, CSSM_FREE local_free, void *local_ref) {


	if( cssm_IsBadWritePtr(src, sizeof(*src))) { return; }

	FreeCssmData(&src->prime,local_free, local_ref);
	FreeCssmData(&src->base,local_free, local_ref);
	FreeCssmData(&src->privateValue,local_free, local_ref);

	local_free(src, local_ref);
	src=NULL;

	return;
}

/*****************************************************************************
 * Function: CheckCssmData
 *
 * This function checks a CSSM_DATA structure for having read/write
 * access, and for NULL Data or 0 Length
 *
 * Input:
 *   src: The  structure to be checked
 *
 * Output:
 *
 * Returns:
 *	CSSM_OK
 *  CSSM_FAIL
 *
 */
CSSM_RETURN CheckCssmData(CSSM_DATA_PTR src) {


	if ( (cssm_IsBadReadPtr(src->Data, src->Length) ) OR
		 (src->Length==0) OR (src->Data == NULL) ) {
		return(CSSM_FAIL);
	}

	return(CSSM_OK);
}
