/** * 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*/