/**
* MIT License
*
* Copyright (c) 2018 Infineon Technologies AG
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE
*
*
* \file DtlsHandshakeProtocol.c
*
* \brief This file implements the DTLS Handshake protocol.
*
* \addtogroup grMutualAuth
* @{
*/
#include "optiga/dtls/DtlsHandshakeProtocol.h"
#include "optiga/dtls/AlertProtocol.h"
#include "optiga/optiga_dtls.h"
#include "optiga/dtls/DtlsRecordLayer.h"
#include "optiga/dtls/DtlsFlightHandler.h"
#ifdef MODULE_ENABLE_DTLS_MUTUAL_AUTH
///Flight retransmission timeout default value for the first time
#define DEFAULT_TIMEOUT 2
///Maximum Timeout value
#define MAX_FLIGHT_TIMEOUT 60
/// @cond hidden
///Offset for message type
#define OFFSET_MSG_TYPE (0)
///Offset for Total length
#define OFFSET_MSG_TOTAL_LENGTH (OFFSET_MSG_TYPE + 1) //1
///Offset for message sequence
#define OFFSET_MSG_SEQUENCE (OFFSET_MSG_TOTAL_LENGTH + 3) //4
///Offset for fragment offset
#define OFFSET_MSG_FRAGMENT_OFFSET (OFFSET_MSG_SEQUENCE + 2) //6
///Offset for message fragment length
#define OFFSET_MSG_FRAG_LENGTH (OFFSET_MSG_FRAGMENT_OFFSET+ 3) //9
///Offset for message data
#define OFFSET_MSG_DATA (OFFSET_MSG_FRAG_LENGTH + 3) //12
///Message header length
#define LENGTH_MSG_HEADER (OFFSET_MSG_DATA)
///Offset for second byte of message fragment length field
#define OFFSET_MSG_FRAG_LENGTH_2BYTE (OFFSET_MSG_FRAG_LENGTH + 1)
///Macro for Receive Flight
#ifndef DISABLE_RECEIVE_FLIGHT
#define REC_FLIGHT_INITIALIZE(PbLastProcFlight, PppsFlightHead, PpsMessageLayer) DtlsHS_RFlightInitialise(PbLastProcFlight, PppsFlightHead, PpsMessageLayer)
#define REC_FLIGHT_PROCESS(PpbLastProcFlight, PppsRFlightHead, PpsMessageLayer, PbFlightTimeout) DtlsHS_RFlightProcess(PpbLastProcFlight, PppsRFlightHead, PpsMessageLayer, PbFlightTimeout)
#else
extern int32_t StubRFlightInitialise(uint8_t PbLastProcFlight, sFlightDetails_d** PppsFlightHead, sMsgLyr_d* PpsMessageLayer);
extern int32_t StubRFlightProcess(uint8_t* PpbLastProcFlight, sFlightDetails_d** PppsRFlightHead, sMsgLyr_d* PpsMessageLayer, uint8_t PbFlightTimeout);
#define REC_FLIGHT_INITIALIZE(PbLastProcFlight, PppsFlightHead, PpsMessageLayer) StubRFlightInitialise(PbLastProcFlight, PppsFlightHead, PpsMessageLayer)
#define REC_FLIGHT_PROCESS(PpbLastProcFlight, PppsRFlightHead, PpsMessageLayer, PbFlightTimeout) StubRFlightProcess(PpbLastProcFlight, PppsRFlightHead, PpsMessageLayer, PbFlightTimeout)
#endif
///Macro for Send Flight
#ifndef DISABLE_SEND_FLIGHT
#define SEND_FLIGHT_INITIALIZE(PbLastProcFlight, PppsFlightHead, PpsMessageLayer) DtlsHS_SFlightInitialise(PbLastProcFlight, PppsFlightHead, PpsMessageLayer)
#define SEND_FLIGHT_PROCESS(PpbLastProcFlight, PpsSFlightHead, PpsMessageLayer) DtlsHS_SFlightProcess(PpbLastProcFlight, PpsSFlightHead, PpsMessageLayer)
#else
extern int32_t StubSFlightInitialise(uint8_t PbLastProcFlight, sFlightDetails_d** PppsFlightHead, sMsgLyr_d* PpsMessageLayer);
extern int32_t StubSFlightProcess(uint8_t *PpbLastProcFlight, sFlightDetails_d* PpsSFlightHead, sMsgLyr_d* PpsMessageLayer);
#define SEND_FLIGHT_INITIALIZE(PbLastProcFlight, PppsFlightHead, PpsMessageLayer) StubSFlightInitialise(PbLastProcFlight, PppsFlightHead, PpsMessageLayer)
#define SEND_FLIGHT_PROCESS(PpbLastProcFlight, PpsSFlightHead, PpsMessageLayer) StubSFlightProcess(PpbLastProcFlight, PpsSFlightHead, PpsMessageLayer)
#endif
#define FLIGHTLoHi(x,y) ((x) | (y<<8))
#define MSGLoHi(x,y) ((x) | (y<<8))
#define IsEVEN_FLIGHT(X) (((X%2) == 0) ? 1 : 0)
///Flight mapping table for the send flights
const sFlightTable_d rgsSFlightInfo[] = {
{FLIGHTLoHi((uint8_t)eFlight1, \
(uint8_t)eMandatory), {MSGLoHi((uint8_t)eClientHello, (uint8_t)eMandatory), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF)},\
DtlsHS_Flight1Handler},
{FLIGHTLoHi((uint8_t)eFlight3, \
(uint8_t)eOptional), {MSGLoHi((uint8_t)eClientHello, (uint8_t)eOptional), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF)}, \
DtlsHS_Flight3Handler},
{FLIGHTLoHi((uint8_t)eFlight5, (uint8_t)eMandatory), \
{MSGLoHi((uint8_t)eClientCertificate, (uint8_t)eOptional), MSGLoHi((uint8_t)eClientKeyExchange, (uint8_t)eMandatory), MSGLoHi((uint8_t)eCertificateVerify, (uint8_t)eOptional), MSGLoHi((uint8_t)eChangeCipherSpec, (uint8_t)eMandatory), MSGLoHi((uint8_t)eClientFinished, (uint8_t)eMandatory), MSGLoHi(0xFF, 0xFF)}, \
DtlsHS_Flight5Handler},
};
///Flight mapping table for the receive flights
const sFlightTable_d rgsRFlightInfo[] = {
{FLIGHTLoHi((uint8_t)eFlight2, (uint8_t)eOptional), \
{MSGLoHi((uint8_t)eHelloVerifyRequest, (uint8_t)eOptional), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF)}, \
DtlsHS_Flight2Handler},
{FLIGHTLoHi((uint8_t)eFlight4, (uint8_t)eMandatory), \
{MSGLoHi((uint8_t)eServerHello, (uint8_t)eMandatory), MSGLoHi((uint8_t)eServerCertificate, (uint8_t)eMandatory), MSGLoHi((uint8_t)eServerKeyExchange, (uint8_t)eMandatory), MSGLoHi((uint8_t)eCertificateRequest, (uint8_t)eOptional), MSGLoHi((uint8_t)eServerHelloDone, (uint8_t)eMandatory), MSGLoHi(0xFF, 0xFF)}, \
DtlsHS_Flight4Handler},
{FLIGHTLoHi((uint8_t)eFlight6, (uint8_t)eMandatory), \
{MSGLoHi((uint8_t)eChangeCipherSpec, (uint8_t)eMandatory), MSGLoHi((uint8_t)eServerFinished, (uint8_t)eMandatory), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF), MSGLoHi(0xFF, 0xFF)}, \
DtlsHS_Flight6Handler},
};
/// @endcond
/**
* \brief Fragments a handshake message into smaller fragments.
*/
_STATIC_H int32_t DtlsHS_FragmentMsg(sFragmentMsg_d* PpsFragmentMsg);
/**
* \brief Frees the complete message list of a flight.
*/
_STATIC_H void DtlsHS_FreeMessageList(sMsgInfo_d **PppsMsgListPtr);
/**
* \brief Frees flight list except the flight node of interest.
*/
_STATIC_H void DtlsHS_FreeFlightList(uint8_t PbFlightID, sFlightDetails_d** PppsFlightHead);
/**
* \brief Frees specified flight node.
*/
_STATIC_H void DtlsHS_FreeFlightNode(uint8_t PbFlightID, sFlightDetails_d** PppsFlightHead);
/**
* \brief Receives a handshake messages from the server.
*/
_STATIC_H int32_t DtlsHS_ReceiveFlightMessage(uint8_t* PpbLastProcFlight, sFlightDetails_d** PppsRFlightHead, sMsgLyr_d* PpsMessageLayer, uint8_t PbFlightTimeout,uint32_t PdwBasetime);
/**
* \brief Frees flight node.
*/
_STATIC_H void DtlsHS_ClearBuffer(sFlightDetails_d** PppsFlightHead);
/**
* \brief Checks a flight is in the list or not.
*/
_STATIC_H int32_t DtlsHS_CheckFlightList(sFlightDetails_d* PpsFlightHead, uint8_t PbFlightID);
/**
* \brief Initialises the Flight List for Send.
*/
_STATIC_H int32_t DtlsHS_SFlightInitialise(uint8_t PbLastProcFlight, sFlightDetails_d** PppsFlightHead, sMsgLyr_d* PpsMessageLayer);
/**
* \brief Initialises the Flight List for Receive.
*/
_STATIC_H int32_t DtlsHS_RFlightInitialise(uint8_t PbLastProcFlight, sFlightDetails_d** PppsFlightHead, sMsgLyr_d* PpsMessageLayer);
/**
* \brief Processes the send Flight.
*/
_STATIC_H int32_t DtlsHS_SFlightProcess(uint8_t *PpbLastProcFlight, sFlightDetails_d* PpsSFlightHead, sMsgLyr_d* PpsMessageLayer);
/**
* \brief Processes the receive Flight.
*/
_STATIC_H int32_t DtlsHS_RFlightProcess(uint8_t* PpbLastProcFlight, sFlightDetails_d** PppsRFlightHead, sMsgLyr_d* PpsMessageLayer, uint8_t PbFlightTimeout);
/**
* \brief Appends a Flight Node to the end of the list.
*/
_STATIC_H void DtlsHS_CreateFlightList(sFlightDetails_d** PppsFlightHead, sFlightDetails_d* PpsFlightNode);
/**
* \brief Creates a flight node based on the last processed flight and inserts the node to the head node.
*/
_STATIC_H int32_t DtlsHS_CreateFlightNode(uint8_t PbLastProcFlight, sFlightDetails_d** PppsFlightHead, sMsgLyr_d* PpsMessageLayer);
/**
* Fragments a handshake message into smaller fragments.
* Returns a fragment of the handshake message.
*
* \param[in,out] PpsFragmentMsg Pointer to a structure containing handshake message, fragment size and other
* information required for fragmentation
*
* \retval #OCP_HL_OK Successful execution
* \retval #OCP_HL_ERROR Failure in execution
\if ENABLE_NULL_CHECKS
* \retval #OCP_HL_NULL_PARAM Null parameter(s)
\endif
* \retval #OCP_HL_LENZERO_ERROR Length of input parameter is zero
* \retval #OCP_HL_INVALID_FRAGMENT_SIZE Invalid fragment size
* \retval #OCP_HL_INVALID_OFFSET_LEN Invalid offset length
* \retval #OCP_HL_INSUFFICIENT_MEMORY Insufficient buffer size
*/
_STATIC_H int32_t DtlsHS_FragmentMsg(sFragmentMsg_d* PpsFragmentMsg)
{
int32_t i4Status = (int32_t)OCP_HL_ERROR;
puint8_t prgbSrcBuf;
puint8_t prgbDesBuf;
uint16_t wLength;
do
{
#ifdef ENABLE_NULL_CHECKS
//Null Check for input parameters
if((NULL == PpsFragmentMsg) || (NULL == PpsFragmentMsg->psCompleteMsg) || (NULL == PpsFragmentMsg->psMsgFrag)
|| (NULL == PpsFragmentMsg->psCompleteMsg->prgbStream) ||(NULL == PpsFragmentMsg->psMsgFrag->prgbStream))
{
i4Status = (int32_t)OCP_HL_NULL_PARAM;
break;
}
#endif
//Length validation for input parameters
if((0 == PpsFragmentMsg->psCompleteMsg->wLen) || (0 == PpsFragmentMsg->psMsgFrag->wLen))
{
i4Status = (int32_t)OCP_HL_LENZERO_ERROR;
break;
}
//Invalid Fragment size
if(0 == PpsFragmentMsg->wFragmentSize)
{
i4Status = (int32_t)OCP_HL_INVALID_FRAGMENT_SIZE;
break;
}
//Check for sufficient buffer size
if(PpsFragmentMsg->psMsgFrag->wLen < PpsFragmentMsg->wFragmentSize)
{
i4Status = (int32_t)OCP_HL_INSUFFICIENT_MEMORY;
break;
}
//Current offset check
if(PpsFragmentMsg->wCurrentOffset >= PpsFragmentMsg->psCompleteMsg->wLen)
{
i4Status = (int32_t)OCP_HL_INVALID_OFFSET_LEN;
break;
}
if(0 == PpsFragmentMsg->wRemainingLen)
{
i4Status = (int32_t)OCP_HL_LENZERO_ERROR;
break;
}
if( 0 == PpsFragmentMsg->wCurrentOffset)
{
//Assign the address to copy the message
prgbSrcBuf = PpsFragmentMsg->psCompleteMsg->prgbStream;
prgbDesBuf = PpsFragmentMsg->psMsgFrag->prgbStream;
//If the fragment size is greater than complete message size
//Length is set to message size
//else
//Length is set to fragment size
wLength = (PpsFragmentMsg->wFragmentSize > PpsFragmentMsg->psCompleteMsg->wLen)? PpsFragmentMsg->psCompleteMsg->wLen : PpsFragmentMsg->wFragmentSize;
PpsFragmentMsg->psMsgFrag->wLen = wLength;
}
else
{
//Copy the message header to psMsgFrag
Utility_Memmove(PpsFragmentMsg->psMsgFrag->prgbStream, PpsFragmentMsg->psCompleteMsg->prgbStream,
LENGTH_MSG_HEADER);
prgbSrcBuf = PpsFragmentMsg->psCompleteMsg->prgbStream + OFFSET_MSG_DATA + PpsFragmentMsg->wCurrentOffset;
prgbDesBuf = PpsFragmentMsg->psMsgFrag->prgbStream + OFFSET_MSG_DATA;
//If the remaining length is less than fragment size(Last fragment)
if(PpsFragmentMsg->wFragmentSize > (PpsFragmentMsg->wRemainingLen + LENGTH_MSG_HEADER))
{
//Assign the address to copy the message of size (wRemainingLen) from current offset to psMsgFrag at index msgHeaderLen
wLength = (uint16_t)PpsFragmentMsg->wRemainingLen;
PpsFragmentMsg->psMsgFrag->wLen = (uint16_t)(PpsFragmentMsg->wRemainingLen + LENGTH_MSG_HEADER);
}
else
{
//Assign the address to copy the message of size (wFragmentSize - msgHeaderLen) from current offset to psMsgFrag at index msgHeaderLen
wLength = PpsFragmentMsg->wFragmentSize - LENGTH_MSG_HEADER;
PpsFragmentMsg->psMsgFrag->wLen = PpsFragmentMsg->wFragmentSize;
}
}
//To copy the Fragmented message to psMsgFrag
Utility_Memmove(prgbDesBuf, prgbSrcBuf, wLength);
if(PpsFragmentMsg->wFragmentSize < PpsFragmentMsg->psCompleteMsg->wLen)
{
//Update the fragment header with current offset at index fragment offset
Utility_SetUint24 ((PpsFragmentMsg->psMsgFrag->prgbStream + OFFSET_MSG_FRAGMENT_OFFSET),PpsFragmentMsg->wCurrentOffset);
if(PpsFragmentMsg->wFragmentSize > (PpsFragmentMsg->wRemainingLen + LENGTH_MSG_HEADER))
{
//Update the fragment length with wRemainingLen at index fragment length(Last Fragment)
Utility_SetUint16((PpsFragmentMsg->psMsgFrag->prgbStream + OFFSET_MSG_FRAG_LENGTH_2BYTE),(uint16_t)PpsFragmentMsg->wRemainingLen);
}
else
{
//Update the fragment length with (fragment size - header length) at index fragment length
Utility_SetUint16((PpsFragmentMsg->psMsgFrag->prgbStream + OFFSET_MSG_FRAG_LENGTH_2BYTE),(PpsFragmentMsg->wFragmentSize - LENGTH_MSG_HEADER));
}
}
//Update the current offset and remaining length
//If Last Fragment
if(PpsFragmentMsg->wFragmentSize > (PpsFragmentMsg->wRemainingLen + LENGTH_MSG_HEADER))
{
PpsFragmentMsg->wCurrentOffset += PpsFragmentMsg->wRemainingLen;
PpsFragmentMsg->wRemainingLen = 0 ;
}
//For other fragment
else
{
PpsFragmentMsg->wCurrentOffset += (uint16_t)(PpsFragmentMsg->wFragmentSize - LENGTH_MSG_HEADER);
PpsFragmentMsg->wRemainingLen -= (uint16_t)(PpsFragmentMsg->wFragmentSize - LENGTH_MSG_HEADER);
}
i4Status = (int32_t)OCP_HL_OK;
}while(0);
return i4Status;
}
/**
* Frees the complete message list of a flight.
*
* \param[in,out] PppsMsgListPtr Pointer to Message list
*
*/
_STATIC_H void DtlsHS_FreeMessageList(sMsgInfo_d **PppsMsgListPtr)
{
sMsgInfo_d *pMsgNodeAPtr;
sMsgInfo_d *pMsgNodeBPtr = NULL;
do
{
if((NULL == PppsMsgListPtr) || (NULL == *PppsMsgListPtr))
{
break;
}
pMsgNodeAPtr = *PppsMsgListPtr;
do
{
if(NULL != pMsgNodeAPtr->psMsgMapPtr)
{
OCP_FREE(pMsgNodeAPtr->psMsgMapPtr);
pMsgNodeAPtr->psMsgMapPtr = NULL;
}
if(NULL != pMsgNodeAPtr->psMsgHolder)
{
OCP_FREE(pMsgNodeAPtr->psMsgHolder);
pMsgNodeAPtr->psMsgHolder = NULL;
}
pMsgNodeBPtr = pMsgNodeAPtr->psNext;
OCP_FREE(pMsgNodeAPtr);
pMsgNodeAPtr = pMsgNodeBPtr;
}while(pMsgNodeBPtr != NULL);
*PppsMsgListPtr = NULL;
}while(0);
}
/**
* Frees all flight node from flight list except the flight node of interest.
*
* \param[in] PbFlightID Flight ID of the flight to be freed
* \param[in,out] PppsFlightHead Pointer to beginning of flight list
*
*/
_STATIC_H void DtlsHS_FreeFlightList(uint8_t PbFlightID, sFlightDetails_d** PppsFlightHead)
{
sFlightDetails_d *pNodeToFreePtr = NULL;
sFlightDetails_d *pCurrentNode = NULL, *pPreviousNode = NULL;
do
{
if(NULL != PppsFlightHead)
{
pCurrentNode = *PppsFlightHead;
pPreviousNode = pCurrentNode;
if(NULL != pCurrentNode)
{
do
{
if(FLIGHTID(pCurrentNode->wFlightDecp) != PbFlightID)
{
if(NULL != pCurrentNode->sFlightStats.psMessageList)
{
DtlsHS_FreeMessageList(&(pCurrentNode->sFlightStats.psMessageList));
}
pNodeToFreePtr = pCurrentNode;
if(pNodeToFreePtr == *PppsFlightHead)
{
*PppsFlightHead = pNodeToFreePtr->psNext;
}
else
{
pPreviousNode->psNext = pCurrentNode->psNext;
}
OCP_FREE(pNodeToFreePtr);
break;
}
pPreviousNode = pCurrentNode;
pCurrentNode = pCurrentNode->psNext;
}while(NULL != pCurrentNode);
}
}
}while(NULL != pCurrentNode);
}
/**
* Frees a flight node from the flight list which as two flight node at a time.
*
* \param[in] PbFlightID Flight ID of the flight to be freed
* \param[in,out] PppsFlightHead Pointer to beginning of flight list
*/
_STATIC_H void DtlsHS_FreeFlightNode(uint8_t PbFlightID, sFlightDetails_d** PppsFlightHead)
{
sFlightDetails_d* pFlightTrav = NULL;
sFlightDetails_d *pNodeToFreePtr = NULL;
if((NULL != PppsFlightHead) && (NULL != *PppsFlightHead))
{
pFlightTrav = *PppsFlightHead;
while(NULL != pFlightTrav)
{
if(FLIGHTID(pFlightTrav->wFlightDecp) == PbFlightID)
{
if(NULL != pFlightTrav->sFlightStats.psMessageList)
{
DtlsHS_FreeMessageList(&(pFlightTrav->sFlightStats.psMessageList));
}
pNodeToFreePtr = pFlightTrav;
if(pNodeToFreePtr == *PppsFlightHead)
{
*PppsFlightHead = pNodeToFreePtr->psNext;
}
OCP_FREE(pNodeToFreePtr);
break;
}
pFlightTrav = pFlightTrav->psNext;
}
}
}
/**
* Receives a handshake message from the server.
* Under some erroneous conditions, error codes from Record Layer and Handshake Layer can also be returned.
*
* \param[in] PpbLastProcFlight pointer to the last processed flight number
* \param[in] PppsRFlightHead Flight head node for the receive message
* \param[in,out] PpsMessageLayer Pointer to structure containing information required for Message Layer
* \param[in] PbFlightTimeout Flight timeout value
* \param[in] PdwBasetime Time at which State changed to receive mode
*
* \retval #OCP_HL_OK Successful Execution
* \retval #OCP_HL_ERROR Failure Execution
*/
_STATIC_H int32_t DtlsHS_ReceiveFlightMessage(uint8_t* PpbLastProcFlight, sFlightDetails_d** PppsRFlightHead, sMsgLyr_d* PpsMessageLayer, uint8_t PbFlightTimeout,uint32_t PdwBasetime)
{
int32_t i4Status = (int32_t)OCP_HL_OK;
int32_t i4Alert ;
uint32_t dwFragLen = 0;
uint16_t wTotalMsgLen;
sbBlob_d sMessage;
uint8_t bRecvCCSRecord;
sbBlob_d sBlobMessage;
sFlightDetails_d *pRNextFlight;
sFlightDetails_d *pRFlightTrav;
/// @cond hidden
#define B_MULTIPLERECORD (PpsMessageLayer->psConfigRL->sRL.bMultipleRecord)
/// @endcond
do
{
//Assign buffer to store the received message from record layer interface
sMessage.prgbStream = PpsMessageLayer->sTLMsg.prgbStream;
sMessage.wLen = PpsMessageLayer->sTLMsg.wLen;
do
{
PpsMessageLayer->psConfigRL->sRL.bContentType = CONTENTTYPE_HANDSHAKE;
//Invoke Record Layer interface to get the message over UDP
i4Status = PpsMessageLayer->psConfigRL->pfRecv(&PpsMessageLayer->psConfigRL->sRL, sMessage.prgbStream, &sMessage.wLen);
//Enter Flight Handler only if its a valid record
if((int32_t)OCP_RL_OK == i4Status)
{
wTotalMsgLen = sMessage.wLen;
sBlobMessage.prgbStream = sMessage.prgbStream;
sBlobMessage.wLen = wTotalMsgLen;
i4Status = DtlsHS_MsgCheck(*PpbLastProcFlight, &sBlobMessage, PpsMessageLayer);
if(OCP_FL_OK != i4Status)
{
i4Status = (int32_t)OCP_HL_IGNORE_RECORD;
}
if(OCP_FL_OK == i4Status)
{
bRecvCCSRecord = PpsMessageLayer->psConfigRL->sRL.bRecvCCSRecord;
while(0 != wTotalMsgLen)
{
pRNextFlight = *PppsRFlightHead;
if(bRecvCCSRecord != CCS_RECORD_RECV)
{
dwFragLen = Utility_GetUint24(sBlobMessage.prgbStream + OFFSET_MSG_FRAG_LENGTH);
PpsMessageLayer->sMsg.wLen = (uint16_t)dwFragLen + LENGTH_MSG_HEADER;
}
else
{
PpsMessageLayer->sMsg.wLen = 0x01;
}
PpsMessageLayer->sMsg.prgbStream = sBlobMessage.prgbStream;
do
{
pRFlightTrav = pRNextFlight ;
//Invoke the Flight Handler
i4Status = pRFlightTrav->pFlightHndlr(*PpbLastProcFlight, &(pRFlightTrav->sFlightStats), PpsMessageLayer);
if((int32_t)OCP_FL_MSG_NOT_IN_FLIGHT != i4Status)
{
DtlsHS_FreeFlightList(FLIGHTID(pRFlightTrav->wFlightDecp), PppsRFlightHead);
}
pRNextFlight = pRFlightTrav->psNext;
}while(NULL != pRNextFlight);
//Error checks to be added
if(((int32_t)OCP_HL_MALLOC_FAILURE == i4Status) || ((int32_t)OCP_FL_MSG_MAXCOUNT == i4Status) || ((int32_t)OCP_HL_BUFFER_OVERFLOW == i4Status) ||
((int32_t)OCP_FL_MALLOC_FAILURE == i4Status) || (((int32_t)OCP_FL_ERROR == i4Status)) || ((int32_t)OCP_FL_INT_ERROR == i4Status) || ((int32_t)OCP_FL_HS_ERROR == i4Status))
{
break;
}
if((((int32_t)DEV_ERROR_CODE_MASK & i4Status) == (int32_t)CMD_DEV_ERROR) || ((int32_t)OCP_FL_SEND_MSG_TO_OPTIGA_ERROR == i4Status))
{
break;
}
if(((int32_t)OCP_FL_OK == i4Status))
{
break;
}
if(bRecvCCSRecord != CCS_RECORD_RECV)
{
wTotalMsgLen -= (uint16_t)dwFragLen + LENGTH_MSG_HEADER;
if(wTotalMsgLen != 0x00)
{
sBlobMessage.prgbStream += dwFragLen + LENGTH_MSG_HEADER;
}
}
else
{
wTotalMsgLen-= PpsMessageLayer->sMsg.wLen;
}
sBlobMessage.wLen = wTotalMsgLen;
}
}
//Error checks to be added
if(((int32_t)OCP_HL_MALLOC_FAILURE == i4Status) || ((int32_t)OCP_FL_MSG_MAXCOUNT == i4Status) || ((int32_t)OCP_HL_BUFFER_OVERFLOW == i4Status) ||
((int32_t)OCP_FL_MALLOC_FAILURE == i4Status) || (((int32_t)OCP_FL_ERROR == i4Status)) || ((int32_t)OCP_FL_INT_ERROR == i4Status) || ((int32_t)OCP_FL_HS_ERROR == i4Status))
{
break;
}
//Device error from Security Chip
if((((int32_t)DEV_ERROR_CODE_MASK & i4Status) == (int32_t)CMD_DEV_ERROR) || ((int32_t)OCP_FL_SEND_MSG_TO_OPTIGA_ERROR == i4Status))
{
break;
}
//If complete flight is received come out of the loop
if((int32_t)OCP_FL_OK == i4Status)
{
*PpbLastProcFlight = FLIGHTID((*PppsRFlightHead)->wFlightDecp);
B_MULTIPLERECORD = 0;
i4Status = (int32_t)OCP_HL_OK;
break;
}
}
//Malloc failure
if(((int32_t)OCP_RL_MALLOC_FAILURE == i4Status))
{
//Exit the state machine
break;
}
//Alert record received
if((int32_t)OCP_RL_ALERT_RECEIVED == i4Status)
{
i4Status = Alert_ProcessMsg(&sMessage,&i4Alert);
if(((int32_t)OCP_AL_FATAL_ERROR == i4Alert))
{
i4Status = i4Alert;
break;
}
}
//Sequence overflow
if((int32_t)OCP_RL_SEQUENCE_OVERFLOW == i4Status)
{
//Exit the state machine
break;
}
if(((int32_t)OCP_RL_NO_DATA != i4Status) && ((int32_t)OCP_FL_RXING != i4Status))
{
i4Status = (int32_t)OCP_HL_IGNORE_RECORD;
}
//If timeout expired return timeout error and exit if flight status is not efreceived
if(!TIMEELAPSED(PdwBasetime, PbFlightTimeout) && (((*PppsRFlightHead)->sFlightStats.bFlightState < (uint8_t)efReceived) || ((*PppsRFlightHead)->sFlightStats.bFlightState == (uint8_t)efReReceive)
|| ((*PppsRFlightHead)->sFlightStats.bFlightState == (uint8_t)efProcessed)))
{
i4Status = (int32_t)OCP_HL_TIMEOUT;
break;
}
//Dynamically setting the UDP timeout
PpsMessageLayer->psConfigRL->sRL.psConfigTL->sTL.wTimeout = (uint16_t)((PbFlightTimeout*1000) - (uint32_t)(pal_os_timer_get_time_in_milliseconds() - PdwBasetime));
//If multiple record is received in a single datagram loop back and receive other records
}while(0 != B_MULTIPLERECORD);
}while(FALSE);
/// @cond hidden
#undef B_MULTIPLERECORD
/// @endcond
return i4Status;
}
/**
* Prepares Handshake message header
*
* \param[in,out] PpbMsgHeader Pointer to buffer where handshake message header is formed
* \param[in] PpsMsgInfo Pointer to #sMsgInfo_d
*
* \retval #OCP_HL_OK Successful execution
\if ENABLE_NULL_CHECKS
* \retval #OCP_HL_NULL_PARAM Null Parameters
\endif
*/
int32_t DtlsHS_PrepareMsgHeader(uint8_t* PpbMsgHeader, const sMsgInfo_d *PpsMsgInfo)
{
int32_t i4Status = (int32_t)OCP_HL_NULL_PARAM;
do
{
#ifdef ENABLE_NULL_CHECKS
if((NULL == PpbMsgHeader)||(NULL == PpsMsgInfo))
{
break;
}
#endif
*(PpbMsgHeader+OFFSET_MSG_TYPE) = PpsMsgInfo->bMsgType;
Utility_SetUint24(PpbMsgHeader+OFFSET_MSG_TOTAL_LENGTH, PpsMsgInfo->dwMsgLength);
Utility_SetUint16(PpbMsgHeader+OFFSET_MSG_SEQUENCE,PpsMsgInfo->wMsgSequence);
Utility_SetUint24(PpbMsgHeader+OFFSET_MSG_FRAGMENT_OFFSET,(uint32_t)0x00);
Utility_SetUint24(PpbMsgHeader+OFFSET_MSG_FRAG_LENGTH, PpsMsgInfo->dwMsgLength);
i4Status = (int32_t)OCP_HL_OK;
}while(FALSE);
return i4Status;
}
/**
* Frees flight node.
*
* \param[in,out] PppsFlightHead Pointer to beginning of flight list
*
*/
_STATIC_H void DtlsHS_ClearBuffer(sFlightDetails_d** PppsFlightHead)
{
sFlightDetails_d* pFlightTrav = *PppsFlightHead;
sFlightDetails_d *pNodeToFreePtr = NULL;
do
{
if(NULL != pFlightTrav)
{
if(NULL != pFlightTrav->sFlightStats.psMessageList)
{
DtlsHS_FreeMessageList(&(pFlightTrav->sFlightStats.psMessageList));
}
pNodeToFreePtr = pFlightTrav;
pFlightTrav = pFlightTrav->psNext;
OCP_FREE(pNodeToFreePtr);
}
}while(NULL != pFlightTrav);
*PppsFlightHead = NULL ;
}
/**
* Checks a flight is in the list or not.
*
* \param[in] PpsFlightHead Pointer to list of Flights
* \param[in] PbFlightID Flight number
*
* \retval #OCP_HL_OK Successful Execution
* \retval #OCP_HL_ERROR Failure Execution
*/
_STATIC_H int32_t DtlsHS_CheckFlightList(sFlightDetails_d* PpsFlightHead, uint8_t PbFlightID)
{
int32_t i4Status = (int32_t)OCP_HL_ERROR;
sFlightDetails_d* psFlightList = PpsFlightHead;
do
{
if(NULL == PpsFlightHead)
{
break;
}
do
{
if(FLIGHTID(psFlightList->wFlightDecp) == PbFlightID)
{
i4Status = (int32_t)OCP_HL_OK;
}
psFlightList = psFlightList->psNext;
}while(NULL != psFlightList);
}while(0);
return i4Status;
}
/**
* Appends a Flight Node to the end of the list.
*
* \param[in,out] PppsFlightHead Pointer to Flight head node list
* \param[in] PpsFlightNode Pointer to new Flight node
*
*/
_STATIC_H void DtlsHS_CreateFlightList(sFlightDetails_d** PppsFlightHead, sFlightDetails_d* PpsFlightNode)
{
sFlightDetails_d* psFlightTrav = *PppsFlightHead;
do
{
if(NULL == psFlightTrav)
{
PpsFlightNode->psNext = NULL;
*PppsFlightHead = PpsFlightNode;
}
else
{
while(psFlightTrav->psNext != NULL)
{
psFlightTrav = psFlightTrav->psNext;
}
psFlightTrav->psNext = PpsFlightNode;
PpsFlightNode->psNext = NULL;
}
}while(0);
}
/**
* Creates a flight node based on the last processed flight and inserts the node to the head node..
*
* \param[in,out] PbLastProcFlight Last processed flight number
* \param[in] PppsFlightHead Pointer to the flight head node
* \param[in] PpsMessageLayer Pointer to message information
*
* \retval #OCP_HL_OK Successful Execution
* \retval #OCP_HL_MALLOC_FAILURE Malloc failure
* \retval #OCP_HL_ERROR Failure Execution
*/
_STATIC_H int32_t DtlsHS_CreateFlightNode(uint8_t PbLastProcFlight, sFlightDetails_d** PppsFlightHead, sMsgLyr_d* PpsMessageLayer)
{
int32_t i4Status = (int32_t)OCP_HL_OK;
sFlightDetails_d* pFlightNode = NULL;
do
{
pFlightNode = (sFlightDetails_d*)OCP_MALLOC(sizeof(sFlightDetails_d));
if(NULL == pFlightNode)
{
i4Status = (int32_t)OCP_HL_MALLOC_FAILURE;
break;
}
else
{
if((int32_t)OCP_FL_ERROR == DtlsHS_FlightNodeInit(pFlightNode, PbLastProcFlight))
{
OCP_FREE(pFlightNode);
i4Status = (int32_t)OCP_HL_ERROR;
break;
}
i4Status = pFlightNode->pFlightHndlr(PbLastProcFlight, &pFlightNode->sFlightStats, PpsMessageLayer);
if(OCP_FL_OK != i4Status)
{
break;
}
DtlsHS_CreateFlightList(PppsFlightHead, pFlightNode);
i4Status = (int32_t)OCP_HL_OK;
}
}while(0);
return i4Status;
}
/**
* Initialises the Flight List for Send.
*
* \param[in] PbLastProcFlight Last processed flight ID
* \param[in,out] PppsFlightHead Pointer to list of Flight nodes
* \param[in] PpsMessageLayer Pointer to message information
*
* \retval #OCP_HL_OK Successful Execution
* \retval #OCP_HL_ERROR Failure Execution
*/
_STATIC_H int32_t DtlsHS_SFlightInitialise(uint8_t PbLastProcFlight, sFlightDetails_d** PppsFlightHead, sMsgLyr_d* PpsMessageLayer)
{
sFlightDetails_d* pFlightNode = NULL;
sFlightDetails_d* pFlightTrav ;
int32_t i4Status = (int32_t)OCP_HL_OK;
do
{
#ifdef ENABLE_NULL_CHECKS
if((NULL == PppsFlightHead) || (NULL == PpsMessageLayer) ||(NULL == PpsMessageLayer->psConfigRL->pfSend))
{
i4Status = (int32_t)OCP_HL_NULL_PARAM;
break;
}
#endif
pFlightTrav = *PppsFlightHead;
if((NULL != pFlightTrav))
{
do
{
pFlightNode = pFlightTrav;
pFlightTrav = pFlightTrav->psNext;
if(PbLastProcFlight > FLIGHTID(pFlightNode->wFlightDecp))
{
if((int32_t)OCP_FL_OK == pFlightNode->pFlightHndlr(PbLastProcFlight, &pFlightNode->sFlightStats, PpsMessageLayer))
{
if(efDone == (eFlightState_d)pFlightNode->sFlightStats.bFlightState)
{
DtlsHS_FreeFlightNode(FLIGHTID(pFlightNode->wFlightDecp), PppsFlightHead);
}
}
}
else if(PbLastProcFlight == FLIGHTID(pFlightNode->wFlightDecp))
{
if(efTransmitted == (eFlightState_d)pFlightNode->sFlightStats.bFlightState)
{
pFlightNode->sFlightStats.bFlightState = (uint8_t)efReTransmit;
}
}
}while(NULL != pFlightTrav);
}
//Create Flight List
if(IsEVEN_FLIGHT(PbLastProcFlight))
{
if((int32_t)OCP_HL_ERROR == DtlsHS_CheckFlightList(*PppsFlightHead, PbLastProcFlight+1))
{
i4Status = DtlsHS_CreateFlightNode(PbLastProcFlight, PppsFlightHead, PpsMessageLayer);
if(OCP_HL_OK != i4Status)
{
break;
}
}
}
}while(0);
return i4Status;
}
/**
* Initialises the Flight List for Receive.
*
* \param[in] PbLastProcFlight Last processed flight ID
* \param[in,out] PppsFlightHead Pointer to list of Flight nodes
* \param[in] PpsMessageLayer Pointer to message information
*
* \retval #OCP_HL_OK Successful Execution
* \retval #OCP_HL_ERROR Failure Execution
*/
_STATIC_H int32_t DtlsHS_RFlightInitialise(uint8_t PbLastProcFlight, sFlightDetails_d** PppsFlightHead, sMsgLyr_d* PpsMessageLayer)
{
uint8_t bFlightA = 0;
uint8_t bFlightB = 0;
int32_t i4Status = (int32_t)OCP_HL_OK;
do
{
//Create Flight List
if((PbLastProcFlight == 1) || (PbLastProcFlight == 3))
{
bFlightA = (uint8_t)eFlight2;
bFlightB = (uint8_t)eFlight4;
}
else if(PbLastProcFlight == 5)
{
bFlightA = (uint8_t)eFlight4;
bFlightB = (uint8_t)eFlight6;
}
else
{
i4Status = (int32_t)OCP_HL_ERROR;
break;
}
if((int32_t)OCP_HL_ERROR == DtlsHS_CheckFlightList(*PppsFlightHead, bFlightA))
{
//CreateFlightNode expects last processed flight ID, hence flight corrected with offset 1
i4Status = DtlsHS_CreateFlightNode(bFlightA-1, PppsFlightHead, PpsMessageLayer);
if(OCP_HL_OK != i4Status)
{
break;
}
if((int32_t)OCP_HL_ERROR == DtlsHS_CheckFlightList(*PppsFlightHead, bFlightB))
{
//CreateFlightNode expects last processed flight ID, hence flight corrected with offset 1
i4Status = DtlsHS_CreateFlightNode(bFlightB-1, PppsFlightHead, PpsMessageLayer);
if(OCP_HL_OK != i4Status)
{
break;
}
}
}
else if((uint8_t)efProcessed ==(*PppsFlightHead)->sFlightStats.bFlightState)
{
if((int32_t)OCP_HL_ERROR == DtlsHS_CheckFlightList(*PppsFlightHead, bFlightB))
{
//CreateFlightNode expects last processed flight ID, hence flight corrected with offset 1
i4Status = DtlsHS_CreateFlightNode(bFlightB-1, PppsFlightHead, PpsMessageLayer);
if(OCP_HL_OK != i4Status)
{
break;
}
}
}
}while(0);
return i4Status;
}
/**
* Processes the send Flight.
*
* \param[in] PpbLastProcFlight Pointer to last processed flight ID
* \param[in,out] PpsSFlightHead Pointer to list of Send Flight list
* \param[in] PpsMessageLayer Message layer information
*
* \retval #OCP_HL_OK Successful Execution
* \retval #OCP_HL_ERROR Failure Execution
* \retval #OCP_FL_NOT_LISTED Flight not found in the list
*/
_STATIC_H int32_t DtlsHS_SFlightProcess(uint8_t *PpbLastProcFlight, sFlightDetails_d* PpsSFlightHead, sMsgLyr_d* PpsMessageLayer)
{
int32_t i4Status = (int32_t)OCP_HL_ERROR;
sFlightDetails_d* pSFlightTrav = PpsSFlightHead;
do
{
if(NULL == pSFlightTrav)
{
i4Status = (int32_t)OCP_FL_NOT_LISTED;
break;
}
do
{
i4Status = pSFlightTrav->pFlightHndlr(*PpbLastProcFlight, &pSFlightTrav->sFlightStats, PpsMessageLayer);
if((int32_t)OCP_FL_OK != i4Status)
{
break;
}
if((uint8_t)efTransmitted == pSFlightTrav->sFlightStats.bFlightState)
{
*PpbLastProcFlight = FLIGHTID(pSFlightTrav->wFlightDecp);
}
pSFlightTrav = pSFlightTrav->psNext;
}while(NULL != pSFlightTrav);
if((int32_t)OCP_FL_OK == i4Status)
{
i4Status = (int32_t)OCP_HL_OK;
}
}while(0);
return i4Status;
}
/**
* Processes the receive Flight.
* Under some erroneous conditions, error codes from respective layer can also be returned.
*
* \param[in] PpbLastProcFlight pointer to the last processed flight ID
* \param[in] PppsRFlightHead Pointer to list of receivable Flight list
* \param[in] PpsMessageLayer Message layer information
* \param[in] PbFlightTimeout Flight time out value
*
* \retval #OCP_HL_OK Successful Execution
* \retval #OCP_HL_ERROR Failure Execution
\if ENABLE_NULL_CHECKS
* \retval #OCP_HL_NULL_PARAM NULL parameters
\endif
*/
_STATIC_H int32_t DtlsHS_RFlightProcess(uint8_t* PpbLastProcFlight, sFlightDetails_d** PppsRFlightHead, sMsgLyr_d* PpsMessageLayer, uint8_t PbFlightTimeout)
{
int32_t i4Status = (int32_t)OCP_HL_ERROR;
uint32_t dwBasetime;
do
{
#ifdef ENABLE_NULL_CHECKS
//NULL check
if((NULL == PppsRFlightHead) || (NULL == PpsMessageLayer) || (NULL == PpsMessageLayer->psConfigRL) || (NULL == PpsMessageLayer->psConfigRL->pfRecv))
{
i4Status = (int32_t)OCP_HL_NULL_PARAM;
break;
}
#endif
//Start value for the Flight timeout
dwBasetime = (uint32_t)pal_os_timer_get_time_in_milliseconds();
do
{
i4Status = DtlsHS_ReceiveFlightMessage(PpbLastProcFlight, PppsRFlightHead, PpsMessageLayer, PbFlightTimeout, dwBasetime);
//If timeout expired and complete flight is not received then return timeout error and come out of loop
if((!TIMEELAPSED(dwBasetime, PbFlightTimeout) || ((int32_t)OCP_HL_TIMEOUT == i4Status)) && \
((int32_t)OCP_HL_OK != i4Status) && (((*PppsRFlightHead)->sFlightStats.bFlightState < (uint8_t)efReceived) ||
((*PppsRFlightHead)->sFlightStats.bFlightState == (uint8_t)efReReceive) || ((*PppsRFlightHead)->sFlightStats.bFlightState == (uint8_t)efProcessed)))
{
i4Status = (int32_t)OCP_HL_TIMEOUT;
break;
}
//If complete flight message is not received or if no data is received from record layer loop back to get remaining message
}while((i4Status == (int32_t)OCP_FL_RXING) || (i4Status == (int32_t)OCP_RL_NO_DATA) || (i4Status == (int32_t)OCP_HL_IGNORE_RECORD));
}while(FALSE);
return i4Status;
}
/**
* Sends Handshake message to the server.Fragments the message if the message is greater than PMTU.
* Under some erroneous conditions, error codes from respective Layer can also be returned.
*
* \param[in] PpsMsgPtr pointer to the structure containing message information
* \param[in] PpsMessageLayer Pointer to the structure containing list of message
*
* \retval #OCP_HL_OK Successful Execution
* \retval #OCP_HL_ERROR Failure Execution
*/
int32_t DtlsHS_FSendMessage(const sMsgInfo_d* PpsMsgPtr, const sMsgLyr_d* PpsMessageLayer)
{
int32_t i4Status = (int32_t)OCP_HL_ERROR;
uint8_t* pbTotalFragMem = NULL;
sFragmentMsg_d sFragmentMsg;
sbBlob_d sMessage;
sbBlob_d sbBlobMessage;
/// @cond hidden
#define CHANGE_CIPHERSPEC_MSGSIZE 1
/// @endcond
do{
if(PpsMsgPtr->bMsgType == (uint8_t)eChangeCipherSpec)
{
pbTotalFragMem = (uint8_t*)OCP_MALLOC(CHANGE_CIPHERSPEC_MSGSIZE + LENGTH_RL_HEADER);
if(NULL == pbTotalFragMem)
{
i4Status = (int32_t)OCP_HL_MALLOC_FAILURE;
break;
}
OCP_MEMCPY((pbTotalFragMem + LENGTH_RL_HEADER), PpsMsgPtr->psMsgHolder, PpsMsgPtr->dwMsgLength);
PpsMessageLayer->psConfigRL->sRL.bContentType = CONTENTTYPE_CIPHER_SPEC;
PpsMessageLayer->psConfigRL->sRL.bMemoryAllocated = TRUE;
//Send Data
i4Status = PpsMessageLayer->psConfigRL->pfSend(&PpsMessageLayer->psConfigRL->sRL,
pbTotalFragMem,(uint16_t)(PpsMsgPtr->dwMsgLength + LENGTH_RL_HEADER));
if(OCP_RL_OK != i4Status)
{
break;
}
i4Status = (int32_t)OCP_HL_OK;
}
else
{
//Assign pointer of the buffer where the message is buffered
sbBlobMessage.prgbStream = PpsMsgPtr->psMsgHolder;
sbBlobMessage.wLen = (uint16_t)PpsMsgPtr->dwMsgLength + OVERHEAD_LEN;
//Move the pointer to the Handshake message header location
sbBlobMessage.prgbStream+= (OVERHEAD_LEN - MSG_HEADER_LEN);
sbBlobMessage.wLen-= (OVERHEAD_LEN - MSG_HEADER_LEN);
//If the length of the message is within the given PMTU value
if(sbBlobMessage.wLen <= PpsMessageLayer->wMaxPmtu - UDP_RECORD_OVERHEAD)
{
//Assign Buffer
pbTotalFragMem = (uint8_t*)OCP_MALLOC(sbBlobMessage.wLen + LENGTH_RL_HEADER);
if(NULL == pbTotalFragMem)
{
i4Status = (int32_t)OCP_HL_MALLOC_FAILURE;
break;
}
Utility_Memmove(pbTotalFragMem + LENGTH_RL_HEADER, sbBlobMessage.prgbStream, sbBlobMessage.wLen);
PpsMessageLayer->psConfigRL->sRL.bContentType = CONTENTTYPE_HANDSHAKE;
PpsMessageLayer->psConfigRL->sRL.bMemoryAllocated = TRUE;
//Send Data
i4Status = PpsMessageLayer->psConfigRL->pfSend(&PpsMessageLayer->psConfigRL->sRL,
pbTotalFragMem,sbBlobMessage.wLen + LENGTH_RL_HEADER);
if(OCP_RL_OK != i4Status)
{
break;
}
i4Status = (int32_t)OCP_HL_OK;
break;
}
else
{
sFragmentMsg.psCompleteMsg = &sbBlobMessage;
sFragmentMsg.wFragmentSize = PpsMessageLayer->wMaxPmtu - UDP_RECORD_OVERHEAD;
//Assign Buffer
pbTotalFragMem = (uint8_t*)OCP_MALLOC(sFragmentMsg.wFragmentSize + LENGTH_RL_HEADER);
if(NULL == pbTotalFragMem)
{
i4Status = (int32_t)OCP_HL_MALLOC_FAILURE;
break;
}
sFragmentMsg.psMsgFrag = &sMessage;
sMessage.prgbStream = pbTotalFragMem + LENGTH_RL_HEADER;
sMessage.wLen = sFragmentMsg.wFragmentSize;
sFragmentMsg.wRemainingLen = sbBlobMessage.wLen - LENGTH_MSG_HEADER;
sFragmentMsg.wCurrentOffset = 0;
do
{
i4Status = (int32_t)OCP_HL_ERROR;
//Fragment the message
i4Status = DtlsHS_FragmentMsg(&sFragmentMsg);
if(OCP_HL_OK != i4Status)
{
break;
}
PpsMessageLayer->psConfigRL->sRL.bContentType = CONTENTTYPE_HANDSHAKE;
PpsMessageLayer->psConfigRL->sRL.bMemoryAllocated = TRUE;
//Send Data
i4Status = PpsMessageLayer->psConfigRL->pfSend(&PpsMessageLayer->psConfigRL->sRL,
pbTotalFragMem,sMessage.wLen + LENGTH_RL_HEADER);
if(OCP_RL_OK != i4Status)
{
break;
}
i4Status = (int32_t)OCP_HL_OK;
}while(0 != sFragmentMsg.wRemainingLen);
}
}
}while(FALSE);
//Clear the message header list
if(NULL != pbTotalFragMem)
{
OCP_FREE(pbTotalFragMem);
}
/// @cond hidden
#undef CHANGE_CIPHERSPEC_MSGSIZE
/// @endcond
return i4Status;
}
/**
*
* Process and validates Handshake message header.
*
* \param[in] PsBlobMessage Pointer to a blob with Message including header.
*
* \retval #OCP_HL_OK Successful execution
* \retval #OCP_HL_ERROR Failure in execution
* \retval #OCP_HL_LEN_MISMATCH Fragment length mismatch
* \retval #OCP_HL_TOTALLEN_MISMATCH Total length mismatch
* \retval #OCP_HL_BUFFER_OVERFLOW Message length exceeded the limit
*
*/
int32_t DtlsHS_ProcHeader(sbBlob_d PsBlobMessage)
{
int32_t i4Status = (int32_t)OCP_HL_ERROR;
uint32_t dwFragLen;
uint32_t dwFragOffset;
do
{
if(!((((uint8_t)eServer_Certificate <=*PsBlobMessage.prgbStream) && ((uint8_t)eServer_Hello_Done >= *PsBlobMessage.prgbStream)) ||
((uint8_t)eServer_Hello == *PsBlobMessage.prgbStream) || ((uint8_t)eHello_Verify_Request == *PsBlobMessage.prgbStream)||
((uint8_t)eServer_Finished == *PsBlobMessage.prgbStream)))
{
i4Status = (int32_t)OCP_HL_INVALID_MSGTYPE;
break;
}
dwFragLen = Utility_GetUint24(PsBlobMessage.prgbStream + OFFSET_MSG_FRAG_LENGTH);
//check if length fragment len + hmsg header is less than total stream length
if((dwFragLen + LENGTH_MSG_HEADER) > PsBlobMessage.wLen)
{
//Length indicated by fragment length not available
i4Status = (int32_t)OCP_HL_LEN_MISMATCH;
break;
}
//Fragment offset,3 bytes
dwFragOffset = Utility_GetUint24(PsBlobMessage.prgbStream+OFFSET_MSG_FRAGMENT_OFFSET);
if((dwFragOffset+ dwFragLen) > Utility_GetUint24(PsBlobMessage.prgbStream+OFFSET_MSG_TOTAL_LENGTH))
{
i4Status = (int32_t)OCP_HL_TOTALLEN_MISMATCH;
break;
}
i4Status = (int32_t)OCP_HL_OK;
}while(0);
return i4Status;
}
/**
*
* Validates the Hello request message.
*
* \param[in] PprgbData Pointer to the Hello Request Message.
* \param[in] PwLen Length of the Message.
*
* \retval #OCP_HL_OK Successful execution
* \retval #OCP_HL_INVALID_HRMSG Invalid Handshake message
*
*/
int32_t DtlsHS_VerifyHR(const uint8_t* PprgbData, uint16_t PwLen)
{
int32_t i4Status = (int32_t)OCP_HL_INVALID_HRMSG;
uint32_t dwFragLen;
uint32_t dwFragOffset;
uint32_t dwTotalLen;
do
{
if(0x00 != *PprgbData)
{
//Invalid Msg type
break;
}
//Fragment Length,3 bytes
dwFragLen = Utility_GetUint24(PprgbData + OFFSET_MSG_FRAG_LENGTH);
//Fragment offset,3 bytes
dwFragOffset = Utility_GetUint24(PprgbData + OFFSET_MSG_FRAGMENT_OFFSET);
//Total Length,3 bytes
dwTotalLen = Utility_GetUint24(PprgbData + OFFSET_MSG_TOTAL_LENGTH);
if(PwLen != LENGTH_MSG_HEADER)
{
//Incorrect length
break;
}
if(0x00 != Utility_GetUint24(PprgbData + OFFSET_MSG_SEQUENCE))
{
//Incorrect Msg sequence
break;
}
//check if length fragment len + fragment 0ffset + total len is less than total stream length
if((dwFragLen + dwFragOffset + dwTotalLen) > 0x00)
{
//Length fields indicated in the message are incorrect
break;
}
i4Status = (int32_t)OCP_HL_OK;
}while(0);
return i4Status;
}
/**
* Performs a DTLS handshake.
* The state machine is configurable as a client or as a server based on the selected protocol.Currently server configuration is not supported.
*
* \param[in,out] PphHandshake Pointer to structure containing data to perform handshake
*
* \retval #OCP_HL_OK Successful Execution
* \retval #OCP_HL_ERROR Failure Execution
*/
int32_t DtlsHS_Handshake(sHandshake_d* PphHandshake)
{
/// @cond hidden
#define STATE_SEND 0x11
#define STATE_RECV 0x22
#define STATE_EXIT 0x33
/// @endcond
uint8_t bLastProcFlight=0;
uint8_t bSmMode = STATE_RECV;
uint8_t bIndex;
uint8_t bFlightTimeout = DEFAULT_TIMEOUT;
sFlightDetails_d* pSFlightHead=NULL;
sFlightDetails_d* pRFlightHead=NULL;
sMsgLyr_d sMessageLayer;
int32_t i4Status = (int32_t)OCP_HL_ERROR;
if(eClient == PphHandshake->eMode)
{
bSmMode = STATE_SEND;
}
else
{
bSmMode = STATE_EXIT;
}
//Populate structure to be passed to MessageLayer
sMessageLayer.psConfigRL = PphHandshake->psConfigRL;
sMessageLayer.wSessionID = PphHandshake->wSessionOID;
((sRecordLayer_d*)PphHandshake->psConfigRL->sRL.phRLHdl)->wSessionKeyOID = PphHandshake->wSessionOID;
sMessageLayer.wMaxPmtu = PphHandshake->wMaxPmtu;
sMessageLayer.wOIDDevCertificate = PphHandshake->wOIDDevCertificate;
sMessageLayer.pfGetUnixTIme = PphHandshake->pfGetUnixTIme;
sMessageLayer.eFlight = eFlight0;
sMessageLayer.dwRMsgSeqNum = 0xFFFFFFFF;
sMessageLayer.sTLMsg.prgbStream = (uint8_t*)OCP_MALLOC(TLBUFFER_SIZE);
if(NULL == sMessageLayer.sTLMsg.prgbStream)
{
i4Status = (int32_t)OCP_LIB_MALLOC_FAILURE;
bSmMode = STATE_EXIT;
}
sMessageLayer.sTLMsg.wLen = (uint16_t)TLBUFFER_SIZE;
for(bIndex = 0; bIndex < (sizeof(sMessageLayer.rgbOptMsgList)/sizeof(sMessageLayer.rgbOptMsgList[0])); bIndex++)
{
sMessageLayer.rgbOptMsgList[bIndex] = 0xFF;
}
//Start state machine
do
{
switch(bSmMode)
{
case STATE_SEND:
{
i4Status = SEND_FLIGHT_INITIALIZE(bLastProcFlight, &pSFlightHead, &sMessageLayer);
if((int32_t)OCP_HL_OK != i4Status)
{
if(PphHandshake->eAuthState == eAuthStarted)
{
PphHandshake->fFatalError = TRUE;
SEND_ALERT(sMessageLayer.psConfigRL, i4Status);
}
DtlsHS_ClearBuffer(&pRFlightHead);
DtlsHS_ClearBuffer(&pSFlightHead);
bSmMode = STATE_EXIT;
break;
}
i4Status = SEND_FLIGHT_PROCESS(&bLastProcFlight, pSFlightHead, &sMessageLayer);
if(OCP_HL_OK == i4Status)
{
if(PphHandshake->eAuthState == eAuthInitialised)
{
PphHandshake->eAuthState = eAuthStarted;
}
bSmMode = STATE_RECV;
}
else
{
if(PphHandshake->eAuthState == eAuthStarted)
{
PphHandshake->fFatalError = TRUE;
SEND_ALERT(sMessageLayer.psConfigRL, i4Status);
}
bSmMode = STATE_EXIT;
DtlsHS_ClearBuffer(&pRFlightHead);
DtlsHS_ClearBuffer(&pSFlightHead);
}
break;
}
case STATE_RECV:
{
i4Status = REC_FLIGHT_INITIALIZE(bLastProcFlight, &pRFlightHead, &sMessageLayer);
if((int32_t)OCP_HL_OK != i4Status)
{
PphHandshake->fFatalError = TRUE;
DtlsHS_ClearBuffer(&pRFlightHead);
DtlsHS_ClearBuffer(&pSFlightHead);
SEND_ALERT(sMessageLayer.psConfigRL, i4Status);
bSmMode = STATE_EXIT;
break;
}
i4Status = REC_FLIGHT_PROCESS(&bLastProcFlight, &pRFlightHead, &sMessageLayer, bFlightTimeout);
if ((int32_t)OCP_HL_TIMEOUT == i4Status)
{
bFlightTimeout = ((bFlightTimeout*2) == 64)?(uint8_t)MAX_FLIGHT_TIMEOUT: (uint8_t)(bFlightTimeout*2);
//Check for Maximum Flight timeout value
if(bFlightTimeout > MAX_FLIGHT_TIMEOUT)
{
PphHandshake->fFatalError = FALSE;
DtlsHS_ClearBuffer(&pRFlightHead);
DtlsHS_ClearBuffer(&pSFlightHead);
bSmMode = STATE_EXIT;
break;
}
sMessageLayer.psConfigRL->sRL.psConfigTL->sTL.wTimeout = (uint16_t)(bFlightTimeout * 1000);
bSmMode = STATE_SEND;
}
//Fatal Alert received
else if((int32_t)OCP_AL_FATAL_ERROR == i4Status)
{
PphHandshake->fFatalError = FALSE;
DtlsHS_ClearBuffer(&pRFlightHead);
DtlsHS_ClearBuffer(&pSFlightHead);
bSmMode = STATE_EXIT;
}
else if(OCP_HL_OK != i4Status)
{
PphHandshake->fFatalError = TRUE;
SEND_ALERT(sMessageLayer.psConfigRL, i4Status);
DtlsHS_ClearBuffer(&pRFlightHead);
DtlsHS_ClearBuffer(&pSFlightHead);
bSmMode = STATE_EXIT;
}
else if(bLastProcFlight != (uint8_t)eFlight6)
{
bFlightTimeout = DEFAULT_TIMEOUT;
//Initial UDP Time out
sMessageLayer.psConfigRL->sRL.psConfigTL->sTL.wTimeout = 200;
Dtls_SlideWindow(&sMessageLayer.psConfigRL->sRL, PphHandshake->eAuthState);
bSmMode = STATE_SEND;
}
else
{
//state machine is over
PphHandshake->eAuthState = eAuthCompleted;
Dtls_SlideWindow(&sMessageLayer.psConfigRL->sRL, PphHandshake->eAuthState);
PphHandshake->fFatalError = FALSE;
bSmMode = STATE_EXIT;
DtlsHS_ClearBuffer(&pRFlightHead);
DtlsHS_ClearBuffer(&pSFlightHead);
}
break;
}
default:
{
PphHandshake->fFatalError = TRUE;
bSmMode = STATE_EXIT;
}
break;
}
}while(STATE_EXIT != bSmMode);
/// @cond hidden
#undef STATE_SEND
#undef STATE_RECV
#undef STATE_EXIT
/// @endcond
if(sMessageLayer.sTLMsg.prgbStream != NULL)
{
OCP_FREE(sMessageLayer.sTLMsg.prgbStream);
}
return i4Status;
}
/**
* @}
*/
#endif /*MODULE_ENABLE_DTLS_MUTUAL_AUTH*/