/* SCCSID: fwk/cssm/cspapi.c, dss_cdsa_fwk, fwk_rel3, dss_980403 1.39 4/13/98 10:37:26 */
/* 
    * INTEL CONFIDENTIAL 
    * This file, software, or program is supplied under the terms of a 
    * license agreement or nondisclosure agreement with Intel Corporation 
    * and may not be copied or disclosed except in accordance with the 
    * terms of that agreement. This file, software, or program contains 
    * copyrighted material and/or trade secret information of Intel 
    * Corporation, and must be treated as such. Intel reserves all rights 
    * in this material, except as the license agreement or nondisclosure 
    * agreement specifically indicate. 
    */ 
/*-----------------------------------------------------------------------
 *      File:   CSPAPI.C
 *
 * This file contains the functions that are contained in the CPI portion
 * of the CSSM exported functions.
 */
/*
 * (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 "cssmport.h"
#include "internal.h"
#include "cssmcspi.h"
#include "context.h"
#include "addin.h"

/*---------------------------------------------------------------
 *
 *Name: cssm_GetCSPContext
 *
 *Description:
 *   Given a context handle, find the CSP handle and the
 *   actual context information.
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  hCSP (output) - return the CSP handle associated with
 *                  this context handle
 *
 *Returns:
 *   NULL - unable to get context information
 *   non NULL - pointer to context information
 *
 *-------------------------------------------------------------*/
CSSM_CONTEXT_PTR cssm_GetCSPContext (CSSM_CC_HANDLE CCHandle,
                                     CSSM_CSP_HANDLE *hCSP)
{
	CSSM_CONTEXT_PTR	rc;

	/* clear the error */
    CSSM_ClearError ();

    /* lookup the CSP handle */
    if ((*hCSP = cssm_FindCSPHandle (CCHandle)) == 0) {
        return(0);
    }

    /* get a copy of the context */
    rc = CSSM_GetContext (CCHandle);
	return(rc);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_QuerySize
 *
 *Description:
 *   Exported API for querying the input and output sizes for
 *   purpose of allocating output buffers.
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  ReqSizeInBlock (output) - size of input block for context
 *  ReqSizeOutBlock (output) - size of output block for context
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_QuerySize (CSSM_CC_HANDLE CCHandle,
                                    CSSM_BOOL Encrypt,
                                    uint32 QuerySizeCount,
                                    CSSM_QUERY_SIZE_DATA_PTR DataBlock)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

	/* Make sure that function structure is valid */
    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->QuerySize))
		ret = CallBack->QuerySize (hCSP, CCHandle, Context,
		Encrypt, QuerySizeCount, DataBlock);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_SignData
 *
 *Description:
 *   Exported API for signing the data specified in DataBufs
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be sign
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *  Signature (output) - signature of DataBufs
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_SignData (CSSM_CC_HANDLE CCHandle,
                                   const CSSM_DATA_PTR DataBufs,
                                   uint32 DataBufCount,
                                   CSSM_DATA_PTR Signature)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL){
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->SignData))
		ret = CallBack->SignData (hCSP, CCHandle, Context,
		DataBufs, DataBufCount, Signature);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_SignDataInit
 *
 *Description:
 *   Exported API for initializing the stage version of
 *   sign data.
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_SignDataInit (CSSM_CC_HANDLE CCHandle)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->SignDataInit))
		ret = CallBack->SignDataInit (hCSP, CCHandle, Context);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_SignDataUpdate
 *
 *Description:
 *   Exported API for updating the sign data staged operation.
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be sign
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_SignDataUpdate (CSSM_CC_HANDLE CCHandle,
                                         const CSSM_DATA_PTR DataBufs,
                                         uint32 DataBufCount)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL){
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->SignDataUpdate))
		ret = CallBack->SignDataUpdate (hCSP, CCHandle,
		DataBufs, DataBufCount);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_SignDataFinal
 *
 *Description:
 *   Exported API for completing the staged sign operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  Signature (output) - signature of stage function
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
/* Returns a signature item */
CSSM_RETURN CSSMAPI CSSM_SignDataFinal (CSSM_CC_HANDLE CCHandle,
                                        CSSM_DATA_PTR Signature)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL){
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->SignDataFinal))
		ret = CallBack->SignDataFinal (hCSP, CCHandle, Signature);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_VerifyData
 *
 *Description:
 *   Exported API for verifying the signature
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be sign
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *  Signature (input) - signature to verify
 *
 *Returns:
 *   CSSM_FALSE - CSP wasn't able to complete function or
 *                signature did not verify.  Check actual
 *                state by call CSSM_GetLAstError
 *   CSSM_TRUE - the signature matches the data
 *
 *-------------------------------------------------------------*/
CSSM_BOOL CSSMAPI CSSM_VerifyData (CSSM_CC_HANDLE CCHandle,
                                   const CSSM_DATA_PTR DataBufs,
                                   uint32 DataBufCount,
                                   const CSSM_DATA_PTR Signature)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_BOOL ret = CSSM_FALSE;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FALSE);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL){
		cssm_FreeContext (Context);
		return(CSSM_FALSE);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FALSE);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->VerifyData))
		ret = CallBack->VerifyData (hCSP, CCHandle, Context,
		DataBufs, DataBufCount, Signature);
	else {
		ret = CSSM_FALSE;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FALSE;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_VerifyDataInit
 *
 *Description:
 *   Exported API for initializing the staged verify function
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  Signature (input) - signature to verify
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_VerifyDataInit (CSSM_CC_HANDLE CCHandle)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL){
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->VerifyDataInit))
		ret = CallBack->VerifyDataInit (hCSP, CCHandle, Context);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_VerifyDataUpdate
 *
 *Description:
 *   Exported API for updating the stage verify operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be sign
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_VerifyDataUpdate (CSSM_CC_HANDLE CCHandle,
                                           const CSSM_DATA_PTR DataBufs,
                                           uint32 DataBufCount)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL){
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->VerifyDataUpdate))
		ret = CallBack->VerifyDataUpdate (hCSP, CCHandle,
		DataBufs, DataBufCount);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_VerifyDataFinal
 *
 *Description:
 *   Exported API for completing the staged verify operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *
 *Returns:
 *   CSSM_FALSE - CSP wasn't able to complete function or
 *                signature did not verify.  Check actual
 *                state by call CSSM_GetLAstError
 *   CSSM_TRUE - the signature matches the data
 *
 *-------------------------------------------------------------*/
CSSM_BOOL CSSMAPI CSSM_VerifyDataFinal (CSSM_CC_HANDLE CCHandle,
                                        const CSSM_DATA_PTR Signature)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_BOOL ret = CSSM_FALSE;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FALSE);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL){
		cssm_FreeContext (Context);
		return(CSSM_FALSE);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
		    cssm_FreeContext (Context);
            return(CSSM_FALSE);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->VerifyDataFinal))
		ret = CallBack->VerifyDataFinal (hCSP, CCHandle, Signature);
	else {
		ret = CSSM_FALSE;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FALSE;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DigestData
 *
 *Description:
 *   Exported API for performing a digest on data
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be hashed
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *  Digest (output) - pointer to hash result
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_DigestData (CSSM_CC_HANDLE CCHandle,
                                     const CSSM_DATA_PTR DataBufs,
                                     uint32 DataBufCount,
                                     CSSM_DATA_PTR Digest)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }

    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->DigestData))
		ret = CallBack->DigestData (hCSP, CCHandle, Context,
		DataBufs, DataBufCount, Digest);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DigestDataInit
 *
 *Description:
 *   Exported API for initializing the staged digest operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_DigestDataInit (CSSM_CC_HANDLE CCHandle)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
		    cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->DigestDataInit))
		ret = CallBack->DigestDataInit (hCSP, CCHandle, Context);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DigestDataUpdate
 *
 *Description:
 *   Exported API for updating the data to the stage digest operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be hashed
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_DigestDataUpdate (CSSM_CC_HANDLE CCHandle,
                                           const CSSM_DATA_PTR DataBufs,
                                           uint32 DataBufCount)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */
    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->DigestDataUpdate))
		ret = CallBack->DigestDataUpdate (hCSP, CCHandle,
		DataBufs, DataBufCount);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DigestDataClone
 *
 *Description:
 *   Exported API to clone a stage digest operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *
 *Returns:
 *   zero - CSP wasn't able to complete function
 *   none zero - handle to clone cryptographic context
 *
 *-------------------------------------------------------------*/
CSSM_CC_HANDLE CSSMAPI CSSM_DigestDataClone (CSSM_CC_HANDLE CCHandle)
{
	//Note: not supported
	CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	return (0);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DigestFinal
 *
 *Description:
 *   Exported API for completing he stage digest operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  Digest (output) - pointer to hash result
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_DigestDataFinal (CSSM_CC_HANDLE CCHandle,
                                          CSSM_DATA_PTR Digest)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */
    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->DigestDataFinal))
		ret = CallBack->DigestDataFinal (hCSP, CCHandle, Digest);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_GenerateMac
 *
 *Description:
 *   Exported API for generating a MAC
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be hashed
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *  Mac (output) - pointer to mac result
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_GenerateMac (CSSM_CC_HANDLE CCHandle,
                                      const CSSM_DATA_PTR DataBufs,
                                      uint32 DataBufCount,
                                      CSSM_DATA_PTR Mac)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->GenerateMac))
		ret = CallBack->GenerateMac (hCSP, CCHandle, Context, DataBufs,
		DataBufCount, Mac);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_GenerateMacInit
 *
 *Description:
 *   Exported API for stage generation of a mac
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_GenerateMacInit (CSSM_CC_HANDLE CCHandle)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->GenerateMacInit))
		ret = CallBack->GenerateMacInit (hCSP, CCHandle, Context);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_GenerateMacUpdate
 *
 *Description:
 *   Exported API for updating the data to generate the mac
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be hashed
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_GenerateMacUpdate (CSSM_CC_HANDLE CCHandle,
                                            const CSSM_DATA_PTR DataBufs,
                                            uint32 DataBufCount)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->GenerateMacUpdate))
		ret = CallBack->GenerateMacUpdate (hCSP, CCHandle, DataBufs,
		DataBufCount);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_GenerateMacFinal
 *
 *Description:
 *   Exported API complete the stage mac generate operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  Mac (output) - pointer to mac result
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_GenerateMacFinal (CSSM_CC_HANDLE CCHandle,
                                           CSSM_DATA_PTR Mac)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->GenerateMacFinal))
		ret = CallBack->GenerateMacFinal (hCSP, CCHandle, Mac);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_VerifyMac
 *
 *Description:
 *   Exported API for verifying a MAC
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be hashed
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *  Mac (output) - pointer to mac to verify
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_VerifyMac (CSSM_CC_HANDLE CCHandle,
                                      const CSSM_DATA_PTR DataBufs,
                                      uint32 DataBufCount,
                                      CSSM_DATA_PTR Mac)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->VerifyMac))
		ret = CallBack->VerifyMac (hCSP, CCHandle, Context, DataBufs,
		DataBufCount, Mac);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_VerifyMacInit
 *
 *Description:
 *   Exported API for stage verification of a mac
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_VerifyMacInit (CSSM_CC_HANDLE CCHandle)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->VerifyMacInit))
		ret = CallBack->VerifyMacInit (hCSP, CCHandle, Context);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_VerifyMacUpdate
 *
 *Description:
 *   Exported API for updating the data to verify the mac
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  DataBufs (input) - array of data buffers that holds
 *                     information that needs to be hashed
 *  DataBufCount (input) - number of data buffers pointed to
 *                         by parameter DataBufs
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_VerifyMacUpdate (CSSM_CC_HANDLE CCHandle,
                                            const CSSM_DATA_PTR DataBufs,
                                            uint32 DataBufCount)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->VerifyMacUpdate))
		ret = CallBack->VerifyMacUpdate (hCSP, CCHandle, DataBufs,
		DataBufCount);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_VerifyMacFinal
 *
 *Description:
 *   Exported API complete the stage mac verify operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  Mac (output) - pointer to mac result
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_VerifyMacFinal (CSSM_CC_HANDLE CCHandle,
                                         CSSM_DATA_PTR Mac)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->VerifyMacFinal))
		ret = CallBack->VerifyMacFinal (hCSP, CCHandle, Mac);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_EncryptData
 *
 *Description:
 *   Exported API for encrypting the data
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  ClearBufs (input) - array of clear buffers that holds
 *                     information that needs to be encrypted
 *  ClearBufCount (input) - number of clear buffers pointed to
 *                         by parameter DataBufs
 *  CipherBufs (output) - array of cipher buffers that holds
 *                     the encrypted data
 *  CipherBufCount (input) - number of cipher buffers pointed to
 *                         by parameter DataBufs
 *  bytesEncrypted (output) - count of bytes encrypted
 *  RemData (output) - buffers that holds encrypted data that
 *                     did not fit in CipherBufs
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
/* Returns the encrypted data */
CSSM_RETURN CSSMAPI CSSM_EncryptData (CSSM_CC_HANDLE CCHandle,
                                      const CSSM_DATA_PTR ClearBufs,
                                      uint32 ClearBufCount,
                                      CSSM_DATA_PTR CipherBufs,
                                      uint32 CipherBufCount,
                                      uint32 *bytesEncrypted,
                                      CSSM_DATA_PTR RemData)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)  CallBack->EncryptData)) {
		ret = CallBack->EncryptData (hCSP, CCHandle, Context, ClearBufs,
			ClearBufCount, CipherBufs, CipherBufCount,
			bytesEncrypted, RemData);

		if(ret != CSSM_OK) {
			goto exit;
		}
	}else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
		goto exit;
	}

exit:

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_EncryptDataInit
 *
 *Description:
 *   Exported API for initializing the staged encrypt operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_EncryptDataInit (CSSM_CC_HANDLE CCHandle)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
		    cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->EncryptDataInit))
		ret = CallBack->EncryptDataInit (hCSP, CCHandle, Context);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_EncryptDataUpdate
 *
 *Description:
 *   Exported API for updating the encrypt staged operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  ClearBufs (input) - array of clear buffers that holds
 *                     information that needs to be encrypted
 *  ClearBufCount (input) - number of clear buffers pointed to
 *                         by parameter DataBufs
 *  CipherBufs (output) - array of cipher buffers that holds
 *                     the encrypted data
 *  CipherBufCount (input) - number of cipher buffers pointed to
 *                         by parameter DataBufs
 *  bytesEncrypted (output) - count of bytes encrypted
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_EncryptDataUpdate (CSSM_CC_HANDLE CCHandle,
                                            const CSSM_DATA_PTR ClearBufs,
                                            uint32 ClearBufCount,
                                            CSSM_DATA_PTR CipherBufs,
                                            uint32 CipherBufCount,
                                            uint32 *bytesEncrypted)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
    if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->EncryptDataUpdate)) {
        ret = CallBack->EncryptDataUpdate (hCSP, CCHandle, ClearBufs,
                                             ClearBufCount, CipherBufs,
                                             CipherBufCount, bytesEncrypted);
		if(ret != CSSM_OK)
				goto exit;
	} else {
        ret = CSSM_FAIL;
        CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
    }

exit:
    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_EncryptDataFinal
 *
 *Description:
 *   Exported API complete the stage encrypt operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  RemData (output) - buffers that holds encrypted data that
 *                     did not fit in CipherBufs
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
/* Returns the encrypted data */
CSSM_RETURN CSSMAPI CSSM_EncryptDataFinal (CSSM_CC_HANDLE CCHandle,
                                           CSSM_DATA_PTR RemData)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function structure and
       function pointer is valid */
    if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->EncryptDataFinal)) {
        ret = CallBack->EncryptDataFinal (hCSP, CCHandle, RemData);
		if (ret != CSSM_OK)
			goto exit;

	}else {
		ret = CSSM_FAIL;
           CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
		goto exit;
	}

exit:
    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DecryptData
 *
 *Description:
 *   Exported API for decrypting the data
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  CipherBufs (input) - array of cipher buffers that holds
 *                     the encrypted data
 *  CipherBufCount (input) - number of cipher buffers pointed to
 *                         by parameter DataBufs
 *  ClearBufs (output) - array of clear buffers that holds
 *                     information that needs to be decrypted
 *  ClearBufCount (input) - number of clear buffers pointed to
 *                         by parameter DataBufs
 *  bytesEncrypted (output) - count of bytes decrypted
 *  RemData (output) - buffers that holds decrypted data that
 *                     did not fit in ClearBufs
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
/* Returns the decrypted data */
CSSM_RETURN CSSMAPI CSSM_DecryptData (const CSSM_CC_HANDLE CCHandle,
                                      const CSSM_DATA_PTR CipherBufs,
                                      uint32 CipherBufCount,
                                      CSSM_DATA_PTR ClearBufs,
                                      uint32 ClearBufCount,
                                      uint32 *bytesDecrypted,
                                      CSSM_DATA_PTR RemData)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->DecryptData))
		ret = CallBack->DecryptData (hCSP, CCHandle, Context, CipherBufs,
		CipherBufCount, ClearBufs, ClearBufCount,
		bytesDecrypted, RemData);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DecryptDataInit
 *
 *Description:
 *   Exported API for initializing the stage decrypt operation.
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_DecryptDataInit (CSSM_CC_HANDLE CCHandle)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->DecryptDataInit))
		ret = CallBack->DecryptDataInit (hCSP, CCHandle, Context);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DecryptUpdate
 *
 *Description:
 *   Exported API updating the staged decrypt operation with data
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  CipherBufs (input) - array of cipher buffers that holds
 *                     the encrypted data
 *  CipherBufCount (input) - number of cipher buffers pointed to
 *                         by parameter DataBufs
 *  ClearBufs (output) - array of clear buffers that holds
 *                     information that needs to be decrypted
 *  ClearBufCount (input) - number of clear buffers pointed to
 *                         by parameter DataBufs
 *  bytesEncrypted (output) - count of bytes decrypted
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_DecryptDataUpdate (CSSM_CC_HANDLE CCHandle,
                                            const CSSM_DATA_PTR CipherBufs,
                                            uint32 CipherBufCount,
                                            CSSM_DATA_PTR ClearBufs,
                                            uint32 ClearBufCount,
                                            uint32 *bytesDecrypted)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP, CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->DecryptDataUpdate))
		ret = CallBack->DecryptDataUpdate (hCSP, CCHandle, CipherBufs,
		CipherBufCount, ClearBufs, ClearBufCount,
		bytesDecrypted);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DecryptDataFinal
 *
 *Description:
 *   Exported API for completing the stage decrypt operation
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  RemData (output) - buffers that holds decrypted data that
 *                     did not fit in ClearBufs during the stage
 *                     decrypt operation
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_DecryptDataFinal (CSSM_CC_HANDLE CCHandle,
                                           CSSM_DATA_PTR RemData)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->DecryptDataFinal))
		ret = CallBack->DecryptDataFinal (hCSP, CCHandle, RemData);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_QueryKeySizeInBits
 *
 *Description:
 *   Exported API for querying key size
 *
 *Parameters:
 *  CSPHandle (input) - the CSP handle
 *  CCHandle (input) - context handle containing the key
 *  KeySize (output) -  pointer to keysize
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_QueryKeySizeInBits (CSSM_CSP_HANDLE CSPHandle,
											 CSSM_CC_HANDLE CCHandle,
                                             CSSM_KEY_SIZE_PTR KeySize)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(CSPHandle,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL)
		return(CSSM_FAIL);

    if(cssm_CheckThreadSafe (CSPHandle, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (CSPHandle,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->QueryKeySizeInBits))
		ret = CallBack->QueryKeySizeInBits (CSPHandle, CCHandle, KeySize);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (CSPHandle, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (CSPHandle,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_GenerateKey
 *
 *Description:
 *   Exported API for generating a symmetric.
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  StorageMask (input) - how to store the key.
 *  Key (output) - pointer to the generate key
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_GenerateKey (CSSM_CC_HANDLE CCHandle,
                                      uint32 KeyUsage,
                                      uint32 KeyAttr,
                                      const CSSM_DATA_PTR KeyLabel,
                                      CSSM_KEY_PTR Key)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->GenerateKey))
		ret = CallBack->GenerateKey (hCSP, CCHandle, Context, KeyUsage,
		KeyAttr, KeyLabel, Key);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_GenerateKeyPair
 *
 *Description:
 *   Exported API for generating an asymmetric key pair.
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  PublicStorageMask (input) - how to store the public key
 *  PublicKey (output) - pointer to the generated public key
 *  PrivateStorageMask (input) - how to store the private key
 *  PrivateKey (output) - pointer to the generated private key
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_GenerateKeyPair (CSSM_CC_HANDLE CCHandle,
                                          uint32 PublicKeyUsage,
                                          uint32 PublicKeyAttr,
                                          const CSSM_DATA_PTR PublicKeyLabel,
                                          CSSM_KEY_PTR PublicKey,
                                          uint32 PrivateKeyUsage,
                                          uint32 PrivateKeyAttr,
                                          const CSSM_DATA_PTR PrivateKeyLabel,
                                          CSSM_KEY_PTR PrivateKey)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->GenerateKeyPair))
		ret = CallBack->GenerateKeyPair (hCSP, CCHandle, Context,
		PublicKeyUsage, PublicKeyAttr, PublicKeyLabel, PublicKey,
		PrivateKeyUsage, PrivateKeyAttr, PrivateKeyLabel, PrivateKey);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_GenerateRandom
 *
 *Description:
 *   Exported API for generating random data
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  RandomNumber (output) - pointer to the random data
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_GenerateRandom (CSSM_CC_HANDLE CCHandle,
                                         CSSM_DATA_PTR RandomNumber)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_CONTEXT_HANDLE);
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->GenerateRandom))
		ret = CallBack->GenerateRandom (hCSP, CCHandle, Context, RandomNumber);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_GenerateAlgorithmParams
 *
 *Description:
 *   Exported API for generating algorithm parameters
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  ParamBits (input) - number of bits in key exchange parameter
 *  Param (output) - pointer to the generated key exchange
 *                   parameter
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_GenerateAlgorithmParams (CSSM_CC_HANDLE CCHandle,
                                                  uint32 ParamBits,
                                                  CSSM_DATA_PTR Param)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->GenerateAlgorithmParams))
		ret = CallBack->GenerateAlgorithmParams (hCSP, CCHandle, Context, ParamBits,
		Param);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_WrapKey
 *
 *Description:
 *   Exported API
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  PassPhrase (input) - passphrase to unlock the wrapping key
 *  Key (input) - Key used to wrap
 *  WrappedKey (putput) - pointer to the wrapped key
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
/* Returns the key */
CSSM_RETURN CSSMAPI CSSM_WrapKey (CSSM_CC_HANDLE CCHandle,
                                  const CSSM_CRYPTO_DATA_PTR PassPhrase,
                                  const CSSM_KEY_PTR Key,
                                  CSSM_WRAP_KEY_PTR WrappedKey)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->WrapKey))
		ret = CallBack->WrapKey (hCSP, CCHandle, Context, PassPhrase, Key, WrappedKey);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_UnrapKey
 *
 *Description:
 *   Exported API
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  NewPassPhrase (input) - passphrase to unlock the wrapping key
 *  WrappedKey (input) - Key used to wrap
 *  StorageMask (input) - indicate how to store key
 *  KeyLabel (input) - Label for key
 *  UnwrappedKey (output) - pointer to unwrapped key
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
/* Returns the key */
CSSM_RETURN CSSMAPI CSSM_UnwrapKey (CSSM_CC_HANDLE CCHandle,
                                    const CSSM_CRYPTO_DATA_PTR NewPassPhrase,
                                    const CSSM_WRAP_KEY_PTR WrappedKey,
                                    uint32 StorageMask,
                                    const CSSM_DATA_PTR KeyLabel,
                                    CSSM_KEY_PTR UnwrappedKey)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->UnwrapKey))
		ret = CallBack->UnwrapKey (hCSP, CCHandle, Context, NewPassPhrase, WrappedKey,
		StorageMask,KeyLabel,UnwrappedKey);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_DeriveKey
 *
 *Description:
 *   Exported API
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  BaseKey (input) - source key
 *  Param (input) - inputs to derive from
 *  StorageMask (input) - indicate how to store key
 *  KeyLabel (input) - label for key
 *  DerivedKey (output) - pointer to derived key
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
/* Returns the key */
CSSM_RETURN CSSMAPI CSSM_DeriveKey  (CSSM_CC_HANDLE CCHandle,
                                     const CSSM_KEY_PTR BaseKey,
                                     void *Param,
                                     uint32 KeyUsage,
                                     uint32 KeyAttr,
                                     const CSSM_DATA_PTR KeyLabel,
                                     CSSM_KEY_PTR DerivedKey)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    CSSM_RETURN ret;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(CSSM_FAIL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle(hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(CSSM_FAIL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->DeriveKey))
		ret = CallBack->DeriveKey (hCSP, CCHandle, Context, BaseKey, Param,
		KeyUsage, KeyAttr, KeyLabel, DerivedKey);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_CSP_PassThrough
 *
 *Description:
 *   Exported API for handling CSP specific operations not covered
 *   in the crypto API
 *
 *Parameters:
 *  CCHandle (input) - the context handle
 *  PassThroughId (input) - CSP specific ID for identifying operation
 *  InData (input) - pointer to input date for the operation
 *
 *Returns:
 *   not NULL - pointer to output results from operation
 *   NULL - CSP wasn't able to complete function
 *
 *-------------------------------------------------------------*/
void * CSSMAPI CSSM_CSP_PassThrough (CSSM_CC_HANDLE CCHandle,
                                         uint32 PassThroughId,
                                         const void * InData)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_CONTEXT_PTR Context = NULL;
    CSSM_CSP_HANDLE hCSP;
    void * ret = NULL;
    CSSM_MUTEX retMutex;
    CSSM_CSP_MANIFEST_PTR cspManifest = NULL;

    /* get CSP handle and actual context information */

    if ((Context = cssm_GetCSPContext (CCHandle, &hCSP)) == NULL) {
        return(NULL);
    }

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle (hCSP,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL) {
		cssm_FreeContext (Context);
		return(NULL);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			cssm_FreeContext (Context);
            return(NULL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->PassThrough))
		ret = CallBack->PassThrough (hCSP, CCHandle, Context, PassThroughId,
		InData);
	else {
		ret = NULL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}

    if(cssm_CheckThreadSafe (hCSP, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (hCSP,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			// panic and do not free
			ret = NULL;
   		}
    }

    cssm_FreeContext (Context);
    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_CSP_Login
 *
 *Description:
 *   Exported API for Loging into CSPs.
 *
 *Parameters:
 *  CSPHandle (input) - the target CSP handle
 *  Password (input) - passphrase for login
 *  pReserved (input) - pointer to input date for the operation
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_CSP_Login (CSSM_CSP_HANDLE CSPHandle,
                                    const CSSM_CRYPTO_DATA_PTR Password,
                                    const CSSM_DATA_PTR pReserved)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle (CSPHandle,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL)
		return(CSSM_FAIL);

    if(cssm_CheckThreadSafe (CSPHandle, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (CSPHandle,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->Login))
		ret = CallBack->Login (CSPHandle, Password, pReserved);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}


    if(cssm_CheckThreadSafe (CSPHandle, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (CSPHandle,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_CSP_Logout
 *
 *Description:
 *   Exported API for Loging of out a CSP.
 *
 *Parameters:
 *  CSPHandle (input) - the target CSP handle
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_CSP_Logout  (CSSM_CSP_HANDLE CSPHandle)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle (CSPHandle,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL)
		return(CSSM_FAIL);

    if(cssm_CheckThreadSafe (CSPHandle, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (CSPHandle,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->Logout))
		ret = CallBack->Logout (CSPHandle);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}


    if(cssm_CheckThreadSafe (CSPHandle, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (CSPHandle,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    return(ret);
}

/*---------------------------------------------------------------
 *
 *Name: CSSM_CSP_ChangeLoginPassword
 *
 *Description:
 *   Exported API for Loging of out a CSP.
 *
 *Parameters:
 *  CSPHandle (input) - the target CSP handle
 *  OldPassword (input) - old passphrase for login
 *  NewPassword (input) - new passphrase for login
 *
 *Returns:
 *   CSSM_FAIL - CSP wasn't able to complete function
 *   CSSM_OK - Call successful executed by CSP add-in
 *
 *-------------------------------------------------------------*/
CSSM_RETURN CSSMAPI CSSM_CSP_ChangeLoginPassword (CSSM_CSP_HANDLE CSPHandle,
                                        const CSSM_CRYPTO_DATA_PTR OldPassword,
                                        const CSSM_CRYPTO_DATA_PTR NewPassword)
{
    CSSM_SPI_CSP_FUNCS_PTR CallBack = NULL;
    CSSM_RETURN ret = CSSM_FAIL;
    CSSM_MUTEX retMutex;

    CallBack  = (CSSM_SPI_CSP_FUNCS_PTR)cssm_GetAddInCallBackByHandle (CSPHandle,
                       CSSM_SERVICE_CSP);

	if (CallBack == NULL)
		return(CSSM_FAIL);

    if(cssm_CheckThreadSafe (CSPHandle, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_LockMutex(cssm_GetMultitaskMutexHandle (CSPHandle,CSSM_SERVICE_CSP),CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
            return(CSSM_FAIL);
        }
    }

    /* Make sure that function pointer is valid */
	if (!cssm_IsBadCodePtr ((CSSM_CALLBACK)CallBack->ChangeLoginPassword))
		ret = CallBack->ChangeLoginPassword (CSPHandle, OldPassword, NewPassword);
	else {
		ret = CSSM_FAIL;
		CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
	}


    if(cssm_CheckThreadSafe (CSPHandle, CSSM_SERVICE_CSP) == CSSM_FALSE) {
        retMutex = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (CSPHandle,CSSM_SERVICE_CSP));
 		if (retMutex != CSSM_MUTEX_UNLOCKED) {
			ret = CSSM_FAIL;
   		}
    }

    return(ret);
}
