/*! \file 
**********************************************************************************
*Title:                         Discretix OMA DRM v2 Toolkit source file
*
* Filename:                     tlk_odrm_llf_kmng_host.c
*
* Project, Target, subsystem:   Toolkit, OMA DRM
* 
* Created:                      26.11.2007
*
* Modified:                     26.11.2007
*
* \Author                       Ira Boguslavsky
*
* \Remarks
*           Copyright (C) 2007 by Discretix Technologies Ltd. All Rights reserved.
**********************************************************************************/

#include "DX_VOS_BaseTypes.h"

#include "SEPDriver.h"

#include "tlk_odrm_def.h"
#include "tlk_odrm_types.h"
#include "tlk_odrm_errors.h"
#include "tlk_odrm_host_op_code.h"
#include "error.h"

#ifdef TLK_ODRM_SEP_SIMULATOR
#include "tlk_odrm_api_duplicate_wrapper.h"
    #include "tlk_odrm_llf_duplicate_wrapper.h"
    #define TLK_ODRM_START_OFFSET                       0x8
#else
    #define TLK_ODRM_START_OFFSET                       0x0
#endif

/* New ODRM API*/
#include "tlk_cert_types.h"
#include "tlk_sclk_api_types.h"
#include "DX_VOS_String.h"

DxStatus WriteODRMBuffer(TLK_ODRM_Buffer_t* odrmBuffer, DxUint32_t* sramOffset)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS);
	result = SEPDriver_WriteParamater((DxUint32_t)odrmBuffer->buff_ptr,
		odrmBuffer->buffSizeInBytes,
		TLK_ODRM_LLF_WORD_ALLIGN(odrmBuffer->buffSizeInBytes),
		sramOffset,
		DX_FALSE);
	if (result != DX_SUCCESS)
		RETURN_VAR_STATUS(result);
	DX_RETURN(DX_SUCCESS);
}

DxStatus WriteODRMXmlBuffer(TLK_ODRM_Buffer_t* odrmBuffer, DxUint32_t* sramOffset)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS);
	DxUint32 virtualAddress = DX_NULL;
	DxUint32 physicalAddress = DX_NULL;

	result = SEPDriver_AllocateDataPoolMemory(odrmBuffer->buff_ptr,odrmBuffer->buffSizeInBytes + 1,&physicalAddress,&virtualAddress);
	if (result != DX_SUCCESS)
		RETURN_VAR_STATUS(result);
	DX_VOS_FastMemCpy(virtualAddress,odrmBuffer->buff_ptr,odrmBuffer->buffSizeInBytes);

	result = SEPDriver_WriteParamater((DxUint32_t)&physicalAddress,
		sizeof(physicalAddress),
		TLK_ODRM_LLF_WORD_ALLIGN(sizeof(physicalAddress)),
		sramOffset,
		DX_FALSE);
	if (result != DX_SUCCESS)
		RETURN_VAR_STATUS(result);
	DX_RETURN(DX_SUCCESS);
}


DxStatus WriteODRMKeyDataAndPassword(TLK_ODRM_Key_t* key, DxUint32_t* sramOffset)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS);
	result = SEPDriver_WriteParamater((DxUint32_t)key->key.buff_ptr,
		key->key.buffSizeInBytes,
		TLK_ODRM_LLF_WORD_ALLIGN(key->key.buffSizeInBytes),
		sramOffset,
		DX_FALSE);
	if(result != DX_SUCCESS)
		RETURN_VAR_STATUS(result);

	/* Write keyKmngPassword Buffer */
	result = SEPDriver_WriteParamater((DxUint32_t)key->keyKmngPassword.buff_ptr,
		key->keyKmngPassword.buffSizeInBytes,
		TLK_ODRM_LLF_WORD_ALLIGN(key->keyKmngPassword.buffSizeInBytes),
		sramOffset,
		DX_FALSE);
	if(result != DX_SUCCESS)
		RETURN_VAR_STATUS(result);

	DX_RETURN(DX_SUCCESS);
}

DxStatus WriteODRMKeyPassword(TLK_ODRM_Key_t* key, DxUint32_t* sramOffset)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS);
	result = SEPDriver_WriteParamater((DxUint32_t)key->keyKmngPassword.buff_ptr,
		key->keyKmngPassword.buffSizeInBytes,
		TLK_ODRM_LLF_WORD_ALLIGN(key->keyKmngPassword.buffSizeInBytes),
		sramOffset,
		DX_FALSE);
	if (result != DX_SUCCESS)
		RETURN_VAR_STATUS(result);
	DX_RETURN(DX_SUCCESS);
}

DxStatus WriteODRMParameter(const void * bufferToWrite, DxUint32 bufferSize, DxUint32* sramOffset)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS);
	result = SEPDriver_WriteParamater((DxUint32_t)bufferToWrite,
		bufferSize,
		TLK_ODRM_LLF_WORD_ALLIGN(bufferSize),
		sramOffset,
		DX_FALSE);
	if(result != DX_SUCCESS)
		RETURN_VAR_STATUS(result);
	DX_RETURN(DX_SUCCESS);
}

DxStatus ReadODRMParam(void* outputBuffer,DxUint32 size, DxUint32* sramOffset)
{
	DX_DECLARE(DxStatus, result, DX_SUCCESS);
	result = SEPDriver_ReadParamater((DxUint32_t)outputBuffer,
		size,
		TLK_ODRM_LLF_WORD_ALLIGN(size),
		sramOffset ,
		DX_FALSE);
	if(result != DX_SUCCESS)
		RETURN_VAR_STATUS(result);
	DX_RETURN(DX_SUCCESS);
}


DxError_t TLK_ODRM_LLF_ProcessJoinDomain(TLK_ODRM_Buffer_t            * domainXml,   
										 TLK_ODRM_Key_t				  * deviceKeyRingKey,
										 TLK_ODRM_Key_t				  * devicePrivateKey,
										 TLK_ODRM_Key_t				  * domainKeyRingKey,
										 TLK_ODRM_Key_t				  * domainKey,
										 DxByte_t                     * workspace_ptr, /*workspace_ptr*/
										 DxUint32_t					    workspaceSizeInBytes) /*workspaceSizeInBytes*/

{
	DxError_t    result = TLK_ODRM_RC_OK;
	DxUint32_t   sramOffset = TLK_ODRM_START_OFFSET; /* offset into SRAM */
	DxUint32_t   paramInBuffer [DX_9_WORDS_PARAMS];                              

	DxUint32_t   paramOutBuffer[DX_3_WORDS_PARAMS];
	/************************************************************************/
	/*  Lock access to SEP                                                  */
	/************************************************************************/
	SEPDriver_Lock();

	/************************************************************************/
	/* Start sending message to SeP                                         */
	/************************************************************************/
	SEPDriver_StartMessage(&sramOffset);

	paramInBuffer[0]  = TLK_ODRM_PROCESS_JOIN_DOMAIN_MSG_OP_CODE;
	paramInBuffer[1]  = domainXml->buffSizeInBytes;
	paramInBuffer[2]  = deviceKeyRingKey->key.buffSizeInBytes;
	paramInBuffer[3]  = deviceKeyRingKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[4]  = devicePrivateKey->key.buffSizeInBytes;
	paramInBuffer[5]  = devicePrivateKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[6]  = domainKeyRingKey->key.buffSizeInBytes;
	paramInBuffer[7]  = domainKeyRingKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[8]  = domainKey->keyKmngPassword.buffSizeInBytes;

	/* Send constant part */
	result = WriteODRMParameter(paramInBuffer, sizeof(paramInBuffer), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMXmlBuffer(domainXml, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(deviceKeyRingKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(devicePrivateKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(domainKeyRingKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyPassword(domainKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/************************************************************************/
	/* End message                                                          */
	/************************************************************************/
	SEPDriver_EndMessage(sramOffset);

	/************************************************************************/
	/* Wait for the response                                                */
	/************************************************************************/
	result = SEPDriver_POLL_FOR_REPONSE();
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/************************************************************************/
	/* Start reading message from the SEP                                   */
	/************************************************************************/
	/* Start the message */
	result = SEPDriver_StartIncomingMessage(&sramOffset);
	if(result)
		GOTO_END_WITH_VAR_STATUS(result);

	/* Read opcode + status  */
	result = ReadODRMParam(paramOutBuffer, sizeof(paramOutBuffer), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/* check the opcode */
	if(paramOutBuffer[0] != TLK_ODRM_PROCESS_JOIN_DOMAIN_MSG_OP_CODE)
	{
		result = DX_WRONG_OPCODE_FROM_SEP_ERR;
		GOTO_END_WITH_VAR_STATUS(result);
	}

	/* check the status */
	if(paramOutBuffer[1] != CRYS_OK)
	{
		result = paramOutBuffer[1];
		GOTO_END_WITH_VAR_STATUS(result);
	}

	/* Get doaminkey buffer*/
	domainKey->key.buffSizeInBytes = paramOutBuffer[2];
	result = ReadODRMParam(domainKey->key.buff_ptr, domainKey->key.buffSizeInBytes, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

end:   

	/* lock access to the SEP */
	SEPDriver_Unlock();

	DX_RETURN(result);
}

DxError_t TLK_ODRM_LLF_VerifyDeviceRoBeforeInstall(TLK_ODRM_Buffer_t              *roXml_ptr,               
												   TLK_ODRM_Key_t			      *deviceKeyRingKey,
												   TLK_ODRM_Key_t			      *devicePrivateKey,
												   TLK_ODRM_Key_t			      *outputKeyRingKey,
												   TLK_ODRM_Key_t			      *kMacKey,
												   TLK_ODRM_Key_t			      *kRecKey,                     
												   DxByte_t                       *workspace_ptr,              /*workspace_ptr*/
												   DxUint32_t					   nextWorkspaceSizeInBytes)      /*workspaceSizeInBytes*/
{
	DxError_t    result = TLK_ODRM_RC_OK;
	DxUint32_t   sramOffset = TLK_ODRM_START_OFFSET; /* offset into SRAM */
	DxUint32_t   paramInBuffer [10];                              

	DxUint32_t   paramOutBuffer[DX_4_WORDS_PARAMS];
	/************************************************************************/
	/*  Lock access to SEP                                                  */
	/************************************************************************/
	SEPDriver_Lock();

	/************************************************************************/
	/* Start sending message to SeP                                         */
	/************************************************************************/
	SEPDriver_StartMessage(&sramOffset);

	paramInBuffer[0]  = TLK_ODRM_VERIFY_DEVICE_RO_BEFORE_INSTALL_MSG_OP_CODE;
	paramInBuffer[1]  = roXml_ptr->buffSizeInBytes;
	paramInBuffer[2]  = deviceKeyRingKey->key.buffSizeInBytes;
	paramInBuffer[3]  = deviceKeyRingKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[4]  = devicePrivateKey->key.buffSizeInBytes;
	paramInBuffer[5]  = devicePrivateKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[6]  = outputKeyRingKey->key.buffSizeInBytes;
	paramInBuffer[7]  = outputKeyRingKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[8]  = kMacKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[9]  = kRecKey->keyKmngPassword.buffSizeInBytes;

	/* Send constant part */
	result = WriteODRMParameter(paramInBuffer, sizeof(paramInBuffer), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMXmlBuffer(roXml_ptr, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(deviceKeyRingKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(devicePrivateKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(outputKeyRingKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyPassword(kMacKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyPassword(kRecKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/************************************************************************/
	/* End message                                                          */
	/************************************************************************/
	SEPDriver_EndMessage(sramOffset);

	/************************************************************************/
	/* Wait for the response                                                */
	/************************************************************************/
	result = SEPDriver_POLL_FOR_REPONSE();
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/************************************************************************/
	/* Start reading message from the SEP                                   */
	/************************************************************************/
	/* Start the message */
	result = SEPDriver_StartIncomingMessage(&sramOffset);
	if(result)
		GOTO_END_WITH_VAR_STATUS(result);

	/* Read opcode + status  */
	result = ReadODRMParam(paramOutBuffer, sizeof(paramOutBuffer), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/* check the opcode */
	if(paramOutBuffer[0] != TLK_ODRM_VERIFY_DEVICE_RO_BEFORE_INSTALL_MSG_OP_CODE)
	{
		result = DX_WRONG_OPCODE_FROM_SEP_ERR;
		GOTO_END_WITH_VAR_STATUS(result);
	}

	/* check the status */
	if(paramOutBuffer[1] != CRYS_OK)
	{
		result = paramOutBuffer[1];
		GOTO_END_WITH_VAR_STATUS(result);
	}

	/* Get kmac buffer*/
	kMacKey->key.buffSizeInBytes = paramOutBuffer[2];
	result = ReadODRMParam(kMacKey->key.buff_ptr, kMacKey->key.buffSizeInBytes, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/* Get krek buffer*/
	kRecKey->key.buffSizeInBytes = paramOutBuffer[3];
	result = ReadODRMParam(kRecKey->key.buff_ptr, kRecKey->key.buffSizeInBytes, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

end:   

	/* lock access to the SEP */
	SEPDriver_Unlock();

	DX_RETURN(result);
}


DxError_t TLK_ODRM_LLF_VerifyDomainRoBeforeInstall(TLK_ODRM_Buffer_t              * roXml_ptr,               
												   TLK_ODRM_Key_t				  * domainRingKey,
												   TLK_ODRM_Key_t				  * domainKey,
												   TLK_ODRM_DomainGeneration_t      domainGeneration,
												   TLK_ODRM_Key_t				  * outputKeyRingKey,
												   TLK_ODRM_Key_t				  * kMacKey,
												   TLK_ODRM_Key_t				  * kRecKey,                     
												   DxByte_t                       * workspace_ptr,              /*workspace_ptr*/
												   DxUint32_t                       workspaceSizeInBytes)       /*workspaceSizeInBytes*/
{
	DxError_t    result = TLK_ODRM_RC_OK;
	DxUint32_t   sramOffset = TLK_ODRM_START_OFFSET; /* offset into SRAM */
	DxUint32_t   paramInBuffer [11];                              

	DxUint32_t   paramOutBuffer[DX_4_WORDS_PARAMS];
	/************************************************************************/
	/*  Lock access to SEP                                                  */
	/************************************************************************/
	SEPDriver_Lock();

	/************************************************************************/
	/* Start sending message to SeP                                         */
	/************************************************************************/
	SEPDriver_StartMessage(&sramOffset);

	paramInBuffer[0]  = TLK_ODRM_VERIFY_DOMAIN_RO_BEFORE_INSTALL_MSG_OP_CODE;
	paramInBuffer[1]  = roXml_ptr->buffSizeInBytes;
	paramInBuffer[2]  = domainRingKey->key.buffSizeInBytes;
	paramInBuffer[3]  = domainRingKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[4]  = domainKey->key.buffSizeInBytes;
	paramInBuffer[5]  = domainKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[6]  = domainGeneration;
	paramInBuffer[7]  = outputKeyRingKey->key.buffSizeInBytes;
	paramInBuffer[8]  = outputKeyRingKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[9]  = kMacKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[10] = kRecKey->keyKmngPassword.buffSizeInBytes;

	/* Send constant part */
	result = WriteODRMParameter(paramInBuffer, sizeof(paramInBuffer), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMXmlBuffer(roXml_ptr, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(domainRingKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(domainKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(outputKeyRingKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyPassword(kMacKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyPassword(kRecKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/************************************************************************/
	/* End message                                                          */
	/************************************************************************/
	SEPDriver_EndMessage(sramOffset);

	/************************************************************************/
	/* Wait for the response                                                */
	/************************************************************************/
	result = SEPDriver_POLL_FOR_REPONSE();
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/************************************************************************/
	/* Start reading message from the SEP                                   */
	/************************************************************************/
	/* Start the message */
	result = SEPDriver_StartIncomingMessage(&sramOffset);
	if(result)
		GOTO_END_WITH_VAR_STATUS(result);

	/* Read opcode + status  */
	result = ReadODRMParam(paramOutBuffer, sizeof(paramOutBuffer), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/* check the opcode */
	if(paramOutBuffer[0] != TLK_ODRM_VERIFY_DOMAIN_RO_BEFORE_INSTALL_MSG_OP_CODE)
	{
		result = DX_WRONG_OPCODE_FROM_SEP_ERR;
		GOTO_END_WITH_VAR_STATUS(result);
	}

	/* check the status */
	if(paramOutBuffer[1] != CRYS_OK)
	{
		result = paramOutBuffer[1];
		GOTO_END_WITH_VAR_STATUS(result);
	}

	/* Get kmac buffer*/
	kMacKey->key.buffSizeInBytes = paramOutBuffer[2];
	result = ReadODRMParam(kMacKey->key.buff_ptr, kMacKey->key.buffSizeInBytes, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/* Get krec buffer*/
	kRecKey->key.buffSizeInBytes = paramOutBuffer[3];
	result = ReadODRMParam(kRecKey->key.buff_ptr, kRecKey->key.buffSizeInBytes, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

end:   

	/* lock access to the SEP */
	SEPDriver_Unlock();

	DX_RETURN(result);
}

DxError_t TLK_ODRM_LLF_RetrieveKey( TLK_ODRM_Buffer_t				  * roXml_ptr,
								   TLK_ODRM_Key_t                     * kMacAndKRekKeyRingKey,                   
								   TLK_ODRM_Key_t                     * kMacKey,              
								   TLK_ODRM_Key_t                     * kRecKey,               
								   const DxChar_t                     * assetId_ptr,
								   TLK_SCLK_ServiceClockDescriptor_t  * serviceDescr_ptr,
								   TLK_ODRM_Buffer_t				  * parentRoXml_ptr,                          
								   TLK_ODRM_Key_t                     * parentKeyRingKey,                       
								   TLK_ODRM_Key_t                     * parentKMacKey,                      
								   TLK_ODRM_Buffer_t                  * groupKey,
								   TLK_ODRM_GROUP_KEY_ENCRYPTION_TYPE   groupKeyEncryptionType,
								   KMNG_AES_WrappedKey_t                contentAesWrappedKey_ptr,
								   DxByte_t                           * workspace_ptr,              /*workspace_ptr*/
								   DxUint32_t                           workspaceSizeInBytes)      /*workspaceSizeInBytes*/
{
	DxError_t    result = TLK_ODRM_RC_OK;
	DxUint32_t   sramOffset = TLK_ODRM_START_OFFSET; /* offset into SRAM */
	DxUint32_t   paramInBuffer [17];                              


	DxUint32_t   paramOutBuffer[DX_2_WORDS_PARAMS];
	/************************************************************************/
	/*  Lock access to SEP                                                  */
	/************************************************************************/
	SEPDriver_Lock();

	/************************************************************************/
	/* Start sending message to SeP                                         */
	/************************************************************************/
	SEPDriver_StartMessage(&sramOffset);

	paramInBuffer[0]  = TLK_ODRM_RETRIEVE_KEY_MSG_OP_CODE;
	paramInBuffer[1]  = roXml_ptr->buffSizeInBytes;
	paramInBuffer[2]  = kMacAndKRekKeyRingKey->key.buffSizeInBytes;
	paramInBuffer[3]  = kMacAndKRekKeyRingKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[4]  = kMacKey->key.buffSizeInBytes;
	paramInBuffer[5]  = kMacKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[6]  = kRecKey->key.buffSizeInBytes;
	paramInBuffer[7]  = kRecKey->keyKmngPassword.buffSizeInBytes;
	paramInBuffer[8]  = DX_VOS_StrLen(assetId_ptr)+1;
	paramInBuffer[9]  = sizeof(TLK_SCLK_ServiceClockDescriptor_t);
	if (parentRoXml_ptr != DX_NULL)
	{
		paramInBuffer[10]  = parentRoXml_ptr->buffSizeInBytes;
		paramInBuffer[11]  = parentKeyRingKey->key.buffSizeInBytes;
		paramInBuffer[12]  = parentKeyRingKey->keyKmngPassword.buffSizeInBytes;
		paramInBuffer[13]  = parentKMacKey->key.buffSizeInBytes;
		paramInBuffer[14]  = parentKMacKey->keyKmngPassword.buffSizeInBytes;
	}
	else
	{
		paramInBuffer[10]  = 0;
		paramInBuffer[11]  = 0;
		paramInBuffer[12]  = 0;
		paramInBuffer[13]  = 0;
		paramInBuffer[14]  = 0;
	}
	if (groupKey != DX_NULL)
	{
		paramInBuffer[15]  = groupKey->buffSizeInBytes;
		paramInBuffer[16]  = groupKeyEncryptionType;
	}
	else
	{
		paramInBuffer[15]  = 0;
		paramInBuffer[16]  = 0;
	}
	/* Send constant part */
	result = WriteODRMParameter(paramInBuffer, sizeof(paramInBuffer), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMXmlBuffer(roXml_ptr, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(kMacAndKRekKeyRingKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(kMacKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMKeyDataAndPassword(kRecKey, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMParameter(assetId_ptr, DX_VOS_StrLen(assetId_ptr)+1, &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	result = WriteODRMParameter(serviceDescr_ptr, sizeof(TLK_SCLK_ServiceClockDescriptor_t), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	if (parentRoXml_ptr != DX_NULL)
	{
		result = WriteODRMXmlBuffer(parentRoXml_ptr, &sramOffset);
		if(result != DX_SUCCESS)
			GOTO_END_WITH_VAR_STATUS(result);

		result = WriteODRMKeyDataAndPassword(parentKeyRingKey, &sramOffset);
		if(result != DX_SUCCESS)
			GOTO_END_WITH_VAR_STATUS(result);

		result = WriteODRMKeyDataAndPassword(parentKMacKey, &sramOffset);
		if(result != DX_SUCCESS)
			GOTO_END_WITH_VAR_STATUS(result);
	}
	if (groupKey != DX_NULL)
	{
		result = WriteODRMBuffer(groupKey, &sramOffset);
		if(result != DX_SUCCESS)
			GOTO_END_WITH_VAR_STATUS(result);
	}
	/************************************************************************/
	/* End message                                                          */
	/************************************************************************/
	SEPDriver_EndMessage(sramOffset);

	/************************************************************************/
	/* Wait for the response                                                */
	/************************************************************************/
	result = SEPDriver_POLL_FOR_REPONSE();
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/************************************************************************/
	/* Start reading message from the SEP                                   */
	/************************************************************************/
	/* Start the message */
	result = SEPDriver_StartIncomingMessage(&sramOffset);
	if(result)
		GOTO_END_WITH_VAR_STATUS(result);

	/* Read opcode + status  */
	result = ReadODRMParam(paramOutBuffer, sizeof(paramOutBuffer), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

	/* check the opcode */
	if(paramOutBuffer[0] != TLK_ODRM_RETRIEVE_KEY_MSG_OP_CODE)
	{
		result = DX_WRONG_OPCODE_FROM_SEP_ERR;
		GOTO_END_WITH_VAR_STATUS(result);
	}

	/* check the status */
	if(paramOutBuffer[1] != CRYS_OK)
	{
		result = paramOutBuffer[1];
		GOTO_END_WITH_VAR_STATUS(result);
	}

	/* Get contentAesWrappedKey_ptr */
	result = ReadODRMParam(contentAesWrappedKey_ptr, sizeof(KMNG_AES_WrappedKey_t), &sramOffset);
	if(result != DX_SUCCESS)
		GOTO_END_WITH_VAR_STATUS(result);

end:   

	/* lock access to the SEP */
	SEPDriver_Unlock();

	DX_RETURN(result);
}