/*! \file 
**********************************************************************************
*Title:                        Discretix OMA DRM v2 Toolkit source file
*
* Filename:                     tlk_odrm_api.c
*
* Project, Target, subsystem:   Toolkit, OMA DRM
* 
* Created:                      22.11.2007
*
* Modified:                     22.11.2007
*
* \Author                       Ira Boguslavsky
*
* \Remarks
*           Copyright (C) 2007 by Discretix Technologies Ltd. All Rights reserved.
**********************************************************************************/
/*----------- External include files ----------------------------------------*/
#include "DX_VOS_Mem.h"
#include "DX_VOS_String.h"
#include "DX_VOS_Stdio.h"
#include "DX_VOS_BaseTypes.h"
#include "CRYS.h"
#include "CRYS_KMNG.h"
#include "CRYS_KDF.h"

#include "KMNG_API.h"
#include "KMNG_base_error.h"

#include "DX_VOS_Rng.h"

#ifdef TLK_ODRM_SEP_SIMULATOR
#include "tlk_odrm_llf_duplicate_wrapper.h"
#endif
/*----------- Local include files -------------------------------------------*/
#include "tlk_odrm_api.h"
#include "tlk_odrm_errors.h"
#include "tlk_odrm_llf_kmng.h"
#include "tlk_odrm_def.h"

DxError_t TLK_ODRM_WorkspaceCheck(DxByte_t			            *workspace_ptr,
								  DxUint32_t			         workspaceSizeInBytes,
								  DxUint32_t			         requiredWorkspaceSize);

DxError_t TLK_ODRM_WorkspaceCheckAlignment(DxByte_t                      *workspace_ptr);


/*---------------------------------------------------------------------------*/
/*               API FUNCTIONS                                               */
/*---------------------------------------------------------------------------*/

/*------------------------------- New ODRM APIs -----------------------------*/
#include "tlk_cert_types.h"
#include "tlk_sclk_api_types.h"


/************************************************************************/
/* TLK_ODRM NEW APIs                                                    */
/************************************************************************/

static DxError_t ExtractKeyFromKeyRing(TLK_ODRM_Key_t* outputKey, TLK_ODRM_KMNGKeyRing_t* keyRing, TLK_ODRM_KMNGKey_t* keyPtr, DxUint32 keySize, DxByte **nextWorkspace_ptr, DxUint32* workspaceSizeLeft)
{
	DxError_t result = CRYS_OK;
	if (*workspaceSizeLeft < keySize)
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_WORKSPACE);
	outputKey->key.buff_ptr                       = *nextWorkspace_ptr;
	outputKey->key.buffSizeInBytes                = keySize;
	outputKey->keyKmngPassword.buff_ptr           = keyPtr->keyPassword_ptr;
	outputKey->keyKmngPassword.buffSizeInBytes    = keyPtr->keyPasswordLenInBytes;

	/* Get wrapped devicePrivateKey key from the key ring */
	result = KMNG_GetKeyFromKeyRing(    keyRing->keyKmngRing_ptr,        /*keyRing_ptr*/
		keyPtr->keyId,               /*keyId*/
		outputKey->key.buff_ptr,             /*wrappedKey_ptr*/
		&outputKey->key.buffSizeInBytes);    /*wrappedKeySizeInBytes_ptr*/
	if (CRYS_OK != result) 
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_KEY_FROM_KEY_RING);

	*nextWorkspace_ptr += keySize;
	*workspaceSizeLeft -= keySize;
	DX_RETURN(DX_SUCCESS);
}

static DxError_t VerifyKeyUsage(TLK_ODRM_KMNGKeyRing_t* keyRing, TLK_ODRM_KMNGKey_t* keyPtr, DxUint32 keySize, DxUint32 desiredUsage)
{
	DxError_t result = CRYS_OK;
	KMNG_UserSpecificKeyData_t keyData = {0};
	DxUint32 keyRestriction = 0;
	DxUint32 keyUsage = 0;
	KMNG_KeyType_t keyType = KMNG_KeyTypeLast;

	result =  KMNG_RetrieveUserKeyInform(keyPtr->keyId, &keyType, &keySize, &keyUsage, &keyRestriction, keyData, keyRing->keyKmngRing_ptr);
	if (CRYS_OK != result) 
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_KEY_FROM_KEY_RING);

	if ((TLK_ODRM_KEY_RESTRICTION != keyRestriction)||(desiredUsage != keyUsage))
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_INCORRECT_KEY_PERMISSIONS);
	DX_RETURN(DX_SUCCESS);
}

DxError_t ExtractProtectionKeyFromKeyRing(TLK_ODRM_Key_t* outputKey, TLK_ODRM_KMNGKeyRing_t* keyRing, DxByte **nextWorkspace_ptr, DxUint32* workspaceSizeLeft)
{
	DxError_t result = CRYS_OK;
	DxUint32 keySize = KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES;
	if (*workspaceSizeLeft < keySize)
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_WORKSPACE);

	outputKey->keyKmngPassword.buff_ptr         = keyRing->keyKmngRingPassword_ptr;
	outputKey->keyKmngPassword.buffSizeInBytes  = keyRing->keyKmngRingPasswordLenInBytes;
	outputKey->key.buff_ptr                     = *nextWorkspace_ptr;
	outputKey->key.buffSizeInBytes              = keySize; 
	
	result =  KMNG_GetProtectionKeyFromKeyRing( keyRing->keyKmngRing_ptr, 
		outputKey->key.buff_ptr,
		&outputKey->key.buffSizeInBytes);
	if (KMNG_OK != result)
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_PROT_KEY_FROM_KEY_RING);

	*nextWorkspace_ptr += keySize;
	*workspaceSizeLeft -= keySize;
	DX_RETURN(DX_SUCCESS);
}



DxError_t SetOutputKeyData(TLK_ODRM_Key_t* outputKey, DxUint32 keySize, TLK_ODRM_KMNGKey_t* keyPtr, DxByte **nextWorkspace_ptr, DxUint32* workspaceSizeLeft)
{
	if (*workspaceSizeLeft < keySize)
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_WORKSPACE);
	outputKey->key.buff_ptr                       = *nextWorkspace_ptr;
	outputKey->key.buffSizeInBytes                = keySize;
	outputKey->keyKmngPassword.buff_ptr           = keyPtr->keyPassword_ptr;
	outputKey->keyKmngPassword.buffSizeInBytes    = keyPtr->keyPasswordLenInBytes;

	*nextWorkspace_ptr +=  keySize;
	*workspaceSizeLeft -= keySize;
	DX_RETURN(DX_SUCCESS);
}

/************************************************************************/
/* TLK_ODRM_ProcessJoinDomain			                                */
/************************************************************************/
DxError_t TLK_ODRM_ProcessJoinDomain(TLK_ODRM_Buffer_t           *domainXml,   
									 TLK_ODRM_KMNGKeyRing_t      *deviceKeyRing_ptr,
									 TLK_ODRM_KMNGKey_t          *devicePrivateKey_ptr,
									 TLK_ODRM_KMNGKeyRing_t      *domainKeyRing_ptr, 
									 TLK_ODRM_KMNGKey_t          *domainKeyId_ptr, 
									 DxByte_t                    *workspace_ptr,
									 DxUint32_t                   workspaceSizeInBytes)
{

	DxError_t                  result;
	TLK_ODRM_Key_t             devicePrivateKey; 
	TLK_ODRM_Key_t             deviceKeyRingKey;
	TLK_ODRM_Key_t             domainKeyRingKey;
	TLK_ODRM_Key_t             domainKey; 
	DxByte_t                  *nextWorkspace_ptr = workspace_ptr;
	DxUint32_t                 nextWorkspaceSizeInBytes = workspaceSizeInBytes;

	DxUint32_t                 keyId;

	/* Check mandatory input parameters */
	TLK_ODRM_CHECK_BUFFER_PTR_VALIDITY(domainXml);
	TLK_ODRM_CHECK_KEY_RING_PTR_VALIDITY(deviceKeyRing_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(devicePrivateKey_ptr);
	TLK_ODRM_CHECK_KEY_RING_PTR_VALIDITY(domainKeyRing_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(domainKeyId_ptr);


	/* Check workspace */
	result = TLK_ODRM_WorkspaceCheck( workspace_ptr, workspaceSizeInBytes, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES * 3 + sizeof(CRYS_RSAPrimeData_t));
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result =   VerifyKeyUsage(deviceKeyRing_ptr, devicePrivateKey_ptr, TLK_ODRM_RSA_WRAPPED_KEY_SIZE_IN_BYTES, KMNG_KEY_USAGE_ODRM | KMNG_KEY_USAGE_SIGNING);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result =  ExtractKeyFromKeyRing( &devicePrivateKey, deviceKeyRing_ptr, devicePrivateKey_ptr, TLK_ODRM_RSA_WRAPPED_KEY_SIZE_IN_BYTES, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);



	/* Call LLF Toolkit layer */
	/* Prepare parameters */
	result = SetOutputKeyData(&domainKey, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, domainKeyId_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = ExtractProtectionKeyFromKeyRing(&deviceKeyRingKey, deviceKeyRing_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (KMNG_OK != result)
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_PROT_KEY_FROM_KEY_RING);

	result = ExtractProtectionKeyFromKeyRing(&domainKeyRingKey, domainKeyRing_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (KMNG_OK != result)
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_PROT_KEY_FROM_KEY_RING);


	/* Call LLF Toolkit layer */
	result = TLK_ODRM_LLF_ProcessJoinDomain(
		domainXml,   
		&deviceKeyRingKey,
		&devicePrivateKey,
		&domainKeyRingKey,
		&domainKey,
		nextWorkspace_ptr,
		nextWorkspaceSizeInBytes);

	if (TLK_ODRM_RC_OK != result) 
		GOTO_END_WITH_VAR_STATUS(result);


	///* Fill output parameters */

	/* Import encoded first key into key ring */
	result = KMNG_StoreKeyInKeyRing(     domainKeyRing_ptr->keyKmngRing_ptr,
		KMNG_KeyTypeAES,
		domainKey.key.buff_ptr,
		domainKey.key.buffSizeInBytes,
		&keyId);
	if (CRYS_OK != result) 
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_STORE_KEY_IN_KEY_RING);


	/* Fill key ID for the first key */
	domainKeyId_ptr->keyId  = keyId;

end:
    /* Delete intermediate data which was used during the current API */
	DX_VOS_MemSetZero(workspace_ptr, workspaceSizeInBytes);
	DX_RETURN(result);

}

/************************************************************************/
/* TLK_ODRM_VerifyDeviceRoBeforeInstall	                                */
/************************************************************************/
DxError_t TLK_ODRM_VerifyDeviceRoBeforeInstall(TLK_ODRM_Buffer_t           *roXml_ptr, 
											   TLK_ODRM_KMNGKeyRing_t      *deviceKeyRing_ptr,
											   TLK_ODRM_KMNGKey_t          *devicePrivateKey_ptr,
											   TLK_ODRM_KMNGKeyRing_t      *outputKeyRing_ptr,
											   TLK_ODRM_KMNGKey_t          *kMacId_ptr,
											   TLK_ODRM_KMNGKey_t          *kRekId_ptr,
											   DxByte_t                    *workspace_ptr,
											   DxUint32_t                   workspaceSizeInBytes
											   )
{
	DxError_t                  result;

	TLK_ODRM_Key_t             KmacKey;  
	TLK_ODRM_Key_t             KrecKey;
	TLK_ODRM_Key_t             outputKeyRingKey; 
	TLK_ODRM_Key_t             devicePrivateKey; 
	TLK_ODRM_Key_t             deviceKeyRingKey;
	DxByte_t                  *nextWorkspace_ptr = workspace_ptr;
	DxUint32_t                 nextWorkspaceSizeInBytes = workspaceSizeInBytes;
	DxUint32_t                 keyId;

	/* Check mandatory input parameters */
	TLK_ODRM_CHECK_BUFFER_PTR_VALIDITY(roXml_ptr);
	TLK_ODRM_CHECK_KEY_RING_PTR_VALIDITY(deviceKeyRing_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(devicePrivateKey_ptr);
	TLK_ODRM_CHECK_KEY_RING_PTR_VALIDITY(outputKeyRing_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(kMacId_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(kRekId_ptr);

	/* Check workspace */
	result = TLK_ODRM_WorkspaceCheck(    workspace_ptr, workspaceSizeInBytes, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES * 4 + sizeof(CRYS_RSAPrimeData_t));
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result =   VerifyKeyUsage(deviceKeyRing_ptr, devicePrivateKey_ptr, TLK_ODRM_RSA_WRAPPED_KEY_SIZE_IN_BYTES, KMNG_KEY_USAGE_ODRM | KMNG_KEY_USAGE_SIGNING);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result =  ExtractKeyFromKeyRing( &devicePrivateKey, deviceKeyRing_ptr, devicePrivateKey_ptr, TLK_ODRM_RSA_WRAPPED_KEY_SIZE_IN_BYTES, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);


	/* Call LLF Toolkit layer */
	/* Prepare parameters */

	result = SetOutputKeyData(&KmacKey, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, kMacId_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = SetOutputKeyData(&KrecKey, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, kRekId_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = ExtractProtectionKeyFromKeyRing(&deviceKeyRingKey, deviceKeyRing_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (KMNG_OK != result)
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_PROT_KEY_FROM_KEY_RING);

	result = ExtractProtectionKeyFromKeyRing(&outputKeyRingKey, outputKeyRing_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (KMNG_OK != result)
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_PROT_KEY_FROM_KEY_RING);

	/************************************************************************/
	/* Call Low level                                                       */
	/************************************************************************/
	result = TLK_ODRM_LLF_VerifyDeviceRoBeforeInstall( roXml_ptr,               
		&deviceKeyRingKey,
		&devicePrivateKey,
		&outputKeyRingKey,
		&KmacKey,
		&KrecKey,                     
		nextWorkspace_ptr,             
		nextWorkspaceSizeInBytes);     

	if (TLK_ODRM_RC_OK != result) 
		GOTO_END_WITH_VAR_STATUS(result);

	/* Import encoded first key into key ring */
	result = KMNG_StoreKeyInKeyRing(     outputKeyRing_ptr->keyKmngRing_ptr,
		KMNG_KeyTypeHMAC,
		KmacKey.key.buff_ptr,
		KmacKey.key.buffSizeInBytes,
		&keyId);
	if (CRYS_OK != result) 
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_STORE_KEY_IN_KEY_RING);

	/* Fill key ID for the first key */
	kMacId_ptr->keyId  = keyId;

	/* Import encoded second key into key ring */
	result = KMNG_StoreKeyInKeyRing(     outputKeyRing_ptr->keyKmngRing_ptr,
		KMNG_KeyTypeAES,
		KrecKey.key.buff_ptr,
		KrecKey.key.buffSizeInBytes,
		&keyId);
	if (CRYS_OK != result) 
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_STORE_KEY_IN_KEY_RING);

	/* Fill key ID for the first key */
	kRekId_ptr->keyId  = keyId;

end:
    /* Delete intermediate data which was used during the current API */
	DX_VOS_MemSetZero(workspace_ptr, workspaceSizeInBytes);
	DX_RETURN(result);
}


/************************************************************************/
/* TLK_ODRM_VerifyDomainRoBeforeInstall	                                */
/************************************************************************/
DxError_t TLK_ODRM_VerifyDomainRoBeforeInstall(TLK_ODRM_Buffer_t           *roXml_ptr, 
											   TLK_ODRM_KMNGKeyRing_t      *domainKeyRing_ptr,
											   TLK_ODRM_KMNGKey_t          *domainKeyId_ptr,
											   TLK_ODRM_DomainGeneration_t  domainGeneration,
											   TLK_ODRM_KMNGKeyRing_t      *outputKeyRing_ptr,
											   TLK_ODRM_KMNGKey_t          *kMacId_ptr,
											   TLK_ODRM_KMNGKey_t          *kRekId_ptr,
											   DxByte_t                    *workspace_ptr,
											   DxUint32_t                   workspaceSizeInBytes
											   )
{
	DxError_t                  result;
	TLK_ODRM_Key_t             KmacKey;  
	TLK_ODRM_Key_t             KrecKey;
	TLK_ODRM_Key_t             outputKeyRingKey; 
	TLK_ODRM_Key_t             domainKey; 
	TLK_ODRM_Key_t             domainRingKey;
	DxByte_t                  *nextWorkspace_ptr = workspace_ptr;
	DxUint32_t                 nextWorkspaceSizeInBytes = workspaceSizeInBytes;
	DxUint32_t                 keyId;

	
	/* Check mandatory input parameters */
	TLK_ODRM_CHECK_BUFFER_PTR_VALIDITY(roXml_ptr);
	TLK_ODRM_CHECK_KEY_RING_PTR_VALIDITY(domainKeyRing_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(domainKeyId_ptr);
	TLK_ODRM_CHECK_KEY_RING_PTR_VALIDITY(outputKeyRing_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(kMacId_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(kRekId_ptr);

	/* Check workspace */
	result = TLK_ODRM_WorkspaceCheck(    workspace_ptr, workspaceSizeInBytes, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES * 4 + sizeof(CRYS_RSAPrimeData_t));
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result =   VerifyKeyUsage(domainKeyRing_ptr, domainKeyId_ptr, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, KMNG_KEY_USAGE_ODRM);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/* Fill domainKey struct */
	result =  ExtractKeyFromKeyRing( &domainKey, domainKeyRing_ptr, domainKeyId_ptr, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/* Call LLF Toolkit layer */
	/* Prepare parameters */

	result = SetOutputKeyData(&KmacKey, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, kMacId_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = SetOutputKeyData(&KrecKey, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, kRekId_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = ExtractProtectionKeyFromKeyRing(&domainRingKey, domainKeyRing_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (KMNG_OK != result)
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_PROT_KEY_FROM_KEY_RING);

	result = ExtractProtectionKeyFromKeyRing(&outputKeyRingKey, outputKeyRing_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (KMNG_OK != result)
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_PROT_KEY_FROM_KEY_RING);

	/************************************************************************/
	/* Call Low level                                                       */
	/************************************************************************/

	result = TLK_ODRM_LLF_VerifyDomainRoBeforeInstall( roXml_ptr,               
		&domainRingKey,
		&domainKey,
		domainGeneration,
		&outputKeyRingKey,
		&KmacKey,
		&KrecKey,                     
		nextWorkspace_ptr,              
		nextWorkspaceSizeInBytes);      

	if (TLK_ODRM_RC_OK != result) 
		GOTO_END_WITH_VAR_STATUS(result);

	/* Import encoded first key into key ring */
	result = KMNG_StoreKeyInKeyRing(     outputKeyRing_ptr->keyKmngRing_ptr,
		KMNG_KeyTypeHMAC,
		KmacKey.key.buff_ptr,
		KmacKey.key.buffSizeInBytes,
		&keyId);
	if (CRYS_OK != result) 
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_STORE_KEY_IN_KEY_RING);

	/* Fill key ID for the first key */
	kMacId_ptr->keyId  = keyId;

	/* Import encoded second key into key ring */
	result = KMNG_StoreKeyInKeyRing(     outputKeyRing_ptr->keyKmngRing_ptr,
		KMNG_KeyTypeAES,
		KrecKey.key.buff_ptr,
		KrecKey.key.buffSizeInBytes,
		&keyId);
	if (CRYS_OK != result) 
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_STORE_KEY_IN_KEY_RING);

	/* Fill key ID for the first key */
	kRekId_ptr->keyId  = keyId;

end:
    /* Delete intermediate data which was used during the current API */
	DX_VOS_MemSetZero(workspace_ptr, workspaceSizeInBytes);
	DX_RETURN(result);
}


/************************************************************************/
/* TLK_ODRM_RetrieveKey					                                */
/************************************************************************/
DxError_t TLK_ODRM_RetrieveKey(TLK_ODRM_Buffer_t				   *roXml_ptr,
							   TLK_ODRM_KMNGKeyRing_t              *kMacKRekKeyRing_ptr,
							   TLK_ODRM_KMNGKey_t                  *kMacId_ptr,
							   TLK_ODRM_KMNGKey_t                  *kRekId_ptr,
							   const DxChar_t                      *assetId_ptr,
							   TLK_SCLK_ServiceClockDescriptor_t   *serviceDescr_ptr,
							   TLK_ODRM_Buffer_t                   *parentRoXml_ptr, //[optional]
							   TLK_ODRM_KMNGKeyRing_t              *parentKMaxKRekKeyRing_ptr, //[optional]
							   TLK_ODRM_KMNGKey_t                  *parentKMacId_ptr, //[optional]
							   TLK_ODRM_Buffer_t                   *groupKey, //[optional]
							   TLK_ODRM_GROUP_KEY_ENCRYPTION_TYPE    groupKeyEncryptionType, //[optional]
							   KMNG_AES_WrappedKey_t	            contentAesWrappedKey_ptr, //[output]
							   DxByte_t                            *workspace_ptr,
							   DxUint32_t                           workspaceSizeInBytes
							   )
{

	DxError_t                  result;

	TLK_ODRM_Key_t             KmacKey;  
	TLK_ODRM_Key_t             KrecKey;
	TLK_ODRM_Key_t             outputKeyRingKey; 
	TLK_ODRM_Key_t             parentKeyRingKey;
	TLK_ODRM_Key_t             parentKMacKey;
	DxByte_t                  *nextWorkspace_ptr = workspace_ptr;
	DxUint32_t                 nextWorkspaceSizeInBytes = workspaceSizeInBytes;

	/* Check mandatory input parameters */
	TLK_ODRM_CHECK_BUFFER_PTR_VALIDITY(roXml_ptr);
	TLK_ODRM_CHECK_KEY_RING_PTR_VALIDITY(kMacKRekKeyRing_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(kMacId_ptr);
	TLK_ODRM_CHECK_KEY_PTR_VALIDITY(kRekId_ptr);

	if (TLK_ODRM_IS_NULL_3PARAMS(assetId_ptr, serviceDescr_ptr, contentAesWrappedKey_ptr))
	{
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_NULL_POINTER);
	}


	/* Check optional input parameters */
	if (parentRoXml_ptr != DX_NULL) /* if optional parent ro is given all optional fields become mandatory except group key.*/
	{
		TLK_ODRM_CHECK_BUFFER_PTR_VALIDITY(parentRoXml_ptr);
		TLK_ODRM_CHECK_KEY_RING_PTR_VALIDITY(parentKMaxKRekKeyRing_ptr);
		TLK_ODRM_CHECK_KEY_PTR_VALIDITY(parentKMacId_ptr);
	}
	TLK_ODRM_CHECK_OPTIONAL_BUFFER_PTR_VALIDITY(groupKey);

	if ((DX_VOS_StrNCmp(assetId_ptr,"gid:",4) == 0) && (groupKey == DX_NULL))
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_MISSING_GROUP_KEY);

	if ((groupKey != DX_NULL) && (groupKey->buff_ptr != DX_NULL) && (groupKey->buffSizeInBytes < 32))
		RETURN_CONST_STATUS(TLK_ODRM_RC_ERROR_INVALID_GROUP_KEY_SIZE);

	/* Check workspace */
	result = TLK_ODRM_WorkspaceCheck(    workspace_ptr, workspaceSizeInBytes, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES * 5);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result =   VerifyKeyUsage(kMacKRekKeyRing_ptr, kMacId_ptr, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, KMNG_KEY_USAGE_SIGNING);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result =  ExtractKeyFromKeyRing( &KmacKey, kMacKRekKeyRing_ptr, kMacId_ptr, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result =   VerifyKeyUsage(kMacKRekKeyRing_ptr, kRekId_ptr, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, KMNG_KEY_USAGE_ODRM);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result =  ExtractKeyFromKeyRing( &KrecKey, kMacKRekKeyRing_ptr, kRekId_ptr, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);


	if (parentKMaxKRekKeyRing_ptr != DX_NULL)
	{
		result =  ExtractKeyFromKeyRing( &parentKMacKey, parentKMaxKRekKeyRing_ptr, parentKMacId_ptr, KMNG_SYM_ENCR_KEY_BUFF_SIZE_IN_BYTES, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
		if (result != DX_SUCCESS)
			GOTO_END_WITH_VAR_STATUS(result);
	}

	result = ExtractProtectionKeyFromKeyRing(&outputKeyRingKey, kMacKRekKeyRing_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
	if (KMNG_OK != result)
		GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_PROT_KEY_FROM_KEY_RING);

	if (parentKMaxKRekKeyRing_ptr != DX_NULL)
	{
		result = ExtractProtectionKeyFromKeyRing(&parentKeyRingKey, parentKMaxKRekKeyRing_ptr, &nextWorkspace_ptr, &nextWorkspaceSizeInBytes);
		if (KMNG_OK != result)
			GOTO_END_WITH_CONST_STATUS(TLK_ODRM_RC_ERROR_GET_PROT_KEY_FROM_KEY_RING);
	}
	/************************************************************************/
	/* Call Low level                                                       */
	/************************************************************************/
	result = TLK_ODRM_LLF_RetrieveKey( roXml_ptr,
		&outputKeyRingKey,                   
		&KmacKey,              
		&KrecKey,               
		assetId_ptr,
		serviceDescr_ptr,
		parentRoXml_ptr,                          
		&parentKeyRingKey,                       /*firstKey_ptr*/
		&parentKMacKey,                      /*secondKey_ptr*/
		groupKey,
		groupKeyEncryptionType,
		contentAesWrappedKey_ptr,
		nextWorkspace_ptr,              /*workspace_ptr*/
		nextWorkspaceSizeInBytes);      /*workspaceSizeInBytes*/

	if (TLK_ODRM_RC_OK != result) 
		GOTO_END_WITH_VAR_STATUS(result);

end:
    /* Delete intermediate data which was used during the current API */
	DX_VOS_MemSetZero(workspace_ptr, workspaceSizeInBytes);
	DX_RETURN(result);
}





/************************************************************************/
/* TLK_ODRM_WorkspaceSizeGet                                            */
/************************************************************************/
/*lint -save -e715*/
/* Disable PCLINT Info Msg 715: header_ref not referenced 
-- The named formal parameter was not referenced.*/
DxError_t TLK_ODRM_WorkspaceSizeGet(                  TLK_ODRMWorkspaceOp_t        workspaceOp,
									DxUint32_t                  *workspaceMinSize_ptr)
{
	if (workspaceOp != TLK_ODRM_MIN_WORKSPACE)
		return TLK_ODRM_RC_ERROR_WORKSPACE;
	else
		*workspaceMinSize_ptr = ODRMTLK_TST_WORKSPACE_SIZE;
	return TLK_ODRM_RC_OK;
}


/*lint -restore */
/************************************************************************/
/* TLK_ODRM_WorkspaceCheck                                              */
/************************************************************************/
DxError_t TLK_ODRM_WorkspaceCheck(DxByte_t                      *workspace_ptr,
								  DxUint32_t                     workspaceSizeInBytes,
								  DxUint32_t                     requiredWorkspaceSize)
{
	if (workspace_ptr == DX_NULL)
	{
		return TLK_ODRM_RC_ERROR_WORKSPACE;
	}
	/*check if workspace is align*/
	if (TLK_ODRM_SIZE_IN_BYTES_ALIGN(workspace_ptr))
	{
		return TLK_ODRM_RC_ERROR_WORKSPACE_NOT_ALIGN;
	}

	if (workspaceSizeInBytes < requiredWorkspaceSize)
	{
		return TLK_ODRM_RC_ERROR_WORKSPACE;
	}

	return TLK_ODRM_RC_OK;
}

/************************************************************************/
/* TLK_ODRM_WorkspaceCheck                                              */
/************************************************************************/
DxError_t TLK_ODRM_WorkspaceCheckAlignment(DxByte_t                      *workspace_ptr)
{
	if (workspace_ptr == DX_NULL)
	{
		return TLK_ODRM_RC_ERROR_WORKSPACE;
	}
	/*check if workspace is align*/
	if (TLK_ODRM_SIZE_IN_BYTES_ALIGN(workspace_ptr))
	{
		return TLK_ODRM_RC_ERROR_WORKSPACE_NOT_ALIGN;
	}

	return TLK_ODRM_RC_OK;
}

 


