/** * 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 AlertProtocol.c * * \brief This file implements the DTLS Alert Protocol. * * \addtogroup grMutualAuth * @{ */ #include "optiga/dtls/DtlsRecordLayer.h" #include "optiga/dtls/AlertProtocol.h" #include "optiga/dtls/DtlsFlightHandler.h" #ifdef MODULE_ENABLE_DTLS_MUTUAL_AUTH /// @cond hidden /// Maximum size of Alert Message #define LENGTH_ALERT_MSG 0x02 /// Offset for Alert Message #define OFFSET_ALERT_MSG 0x01 //Device Error codes ///Invalid OID #define INVALID_OID 0x01 ///Invalid param field in the command #define INVALID_PARAM_FIELD 0x03 ///Invalid length field in the command #define INVALID_LENGTH_FIELD 0x04 ///Invalid parameter in the data field #define INVALID_PARAMETER_DATA_FIELD 0x05 ///Device internal error #define INTERNAL_PROCESS_ERROR 0x06 ///Invalid command field #define INVALID_COMMAND_FIELD 0x0A ///Command out of sequence #define COMMAND_OUT_SEQUENCE 0x0B ///Command not available #define COMMAND_NOT_AVAILABLE 0x0C ///Illegal parameter in the Handshake header #define INVALID_HANDSHAKE_MESSAGE 0x21 ///DTLS Protocol version mismatch #define VERSION_MISMATCH 0x22 ///Cipher suite mismatch between client and server #define INSUFFICIENT_UNSUPPORTED_CIPHERSUITE 0x23 ///Unsupported extension #define UNSUPPORTED_EXTENSION 0x24 ///Unsupported parameters #define UNSUPPORTED_PARAMETERS 0x25 ///Invalid Trust Anchor #define INVALID_TRUST_ANCHOR 0x26 ///Trust Anchor expired #define TRUST_ANCHOR_EXPIRED 0x27 ///Unsupported Trust Anchor #define UNSUPPORTED_TRUST_ANCHOR 0x28 ///Invalid Certificate format #define INVALID_CERTIFICATE_FORMAT 0x29 ///Unsupported certificate/Unsupported Hash or Sign Algorithm #define UNSUPPORTED_CERTIFICATE_HASHSIGN 0x2A ///Certificate expired #define CERTIFICATE_EXPIRED 0x2B ///Signature verification failed #define SIGNATURE_VERIFICATION_FAILURE 0x2C /** * \brief DTLS Alert Level. */ typedef enum eAlertLevel_d { ///Connection can continue eWARNING = 0x01, ///Terminate the connection eFATAL = 0x02 }eAlertLevel_d; /** * \brief DTLS Alert Types. */ typedef enum eAlertMsg_d { /// Notifies the recipient that the sender will not send any more messages on this connection eCLOSE_NOTIFY = 0x00, /// Inappropriate message was received eUNEXPECTED_MESSAGE = 0x0A , /// Notifies record is received with an incorrect MAC eBAD_RECORD_MAC = 0x14, ///Decryption Failure eDECRYPTION_FAILURE = 0x15, /// Notifies record received length is more than 2^14+2048 eRECORD_OVERFLOW = 0x16, /// Notifies decompression function received improper input eDECOMPRESSION_FAILURE = 0x1E, /// Indicates sender was not able to negotiate with the security parameters eHANDSHAKE_FAILURE = 0x28, /// Notifies certificate was corrupt eBAD_CERTIFICATE = 0x2A, ///No certificate eNO_CERTIFICATE = 0x29, /// Notifies certificate was unsupported type eUNSUPPORTED_CERTIFICATE = 0x2B, /// Notifies the certificate was revoked by signer eCERTIFICATE_REVOKED = 0x2C, /// Indicates the certificate is Expired eCERTIFICATE_EXPIRED = 0x2D, /// Indicates unknown issue in processing the certificate eCERTIFICATE_UNKNOWN = 0x2E, /// Notifies field in handshake is out of range or inconsistent eILLEGAL_PARAMETER = 0x2F, /// Indicates CA certificate could not be found or not matched eUNKNOWN_CA = 0x30, /// Notifies the access denied eACCESS_DENIED = 0x31, /// Notifies message could not be decoded or some field is missing eDECODE_ERROR = 0x32, /// Notifies cryptographic operation failed eDECRYPT_ERROR = 0x33, ///Export restriction eEXPORT_RESTRICTION = 0x3C, /// Notifies protocol version attempted to negotiate is not supported ePROTOCOL_VERSION = 0x46, /// Notifies negotiation has failed specifically because the server requires ciphers more secure eINSUFFICIENT_SECURITY = 0x47, /// Notifies error is unrelated to peer or protocol eINTERNAL_ERROR = 0x50, /// Indicates that the handshake is canceled eUSER_CANCELLED = 0x5A, /// Notifies that the renegotiation is not initiated eNO_RENEGOTIATION = 0x64, /// Notifies unsupported extension was sent to server eUNSUPPORTED_EXTENSION = 0x6E }eAlertMsg_d; /// @endcond /** * \brief Maps the Alert types and level to error code.
*/ _STATIC_H int32_t DtlsAlertErrorMapping(const sbBlob_d* PpsAlertMsg, int32_t* Ppi4ErrorCode); //Alert protocol is defined by default. To disable define DISABLE_ALERT #ifndef DISABLE_ALERT /** * \brief Maps the error code to Alert types and level.
*/ _STATIC_H Void DtlsErrorAlertMapping(int32_t Pi4ErrorCode, sbBlob_d* PpsAlertMsg); /** * \brief Forms the alert message based on the given internal error code.
*/ _STATIC_H Void Alert_FormMsg(int32_t Pi4ErrorCode,sbBlob_d* PpsAlertMsg); /** * Maps the error code to Alert types and level.
* * \param[in] Pi4ErrorCode DTLS Internal error code * \param[in,out] PpsAlertMsg Pointer to a blob containing Alert message as per DTLS Specification * */ _STATIC_H Void DtlsErrorAlertMapping(int32_t Pi4ErrorCode, sbBlob_d* PpsAlertMsg) { do { if((int32_t)OCP_LIB_NO_RENEGOTIATE == Pi4ErrorCode) { *PpsAlertMsg->prgbStream = (uint8_t)eWARNING; } else { *PpsAlertMsg->prgbStream = (uint8_t)eFATAL; } //Set the Blob length to Alert message length PpsAlertMsg->wLen = LENGTH_ALERT_MSG; switch(Pi4ErrorCode) { case (int32_t)OCP_RL_ERROR: case (int32_t)OCP_FL_MSG_MAXCOUNT: //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eCLOSE_NOTIFY; break; case (int32_t)(CMD_DEV_ERROR | INVALID_HANDSHAKE_MESSAGE): case (int32_t)(CMD_DEV_ERROR | UNSUPPORTED_PARAMETERS): case (int32_t)(CMD_DEV_ERROR | VERSION_MISMATCH): case (int32_t) OCP_FL_HS_ERROR: //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eILLEGAL_PARAMETER; break; case (int32_t)OCP_LIB_NO_RENEGOTIATE: //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eNO_RENEGOTIATION; break; case (int32_t)(CMD_DEV_ERROR | INSUFFICIENT_UNSUPPORTED_CIPHERSUITE): //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eINSUFFICIENT_SECURITY; break; case (int32_t)(CMD_DEV_ERROR | UNSUPPORTED_EXTENSION): //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eUNSUPPORTED_EXTENSION; break; case (int32_t)(CMD_DEV_ERROR | INVALID_TRUST_ANCHOR): //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eUNKNOWN_CA; break; case (int32_t)(CMD_DEV_ERROR | TRUST_ANCHOR_EXPIRED): //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eCERTIFICATE_EXPIRED; break; case (int32_t)(CMD_DEV_ERROR | UNSUPPORTED_TRUST_ANCHOR): //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eUNSUPPORTED_CERTIFICATE; break; case (int32_t)(CMD_DEV_ERROR | INVALID_CERTIFICATE_FORMAT): //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eBAD_CERTIFICATE; break; case (int32_t)(CMD_DEV_ERROR | UNSUPPORTED_CERTIFICATE_HASHSIGN): //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eUNSUPPORTED_CERTIFICATE; break; case (int32_t)(CMD_DEV_ERROR | CERTIFICATE_EXPIRED): //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eCERTIFICATE_EXPIRED; break; case (int32_t)(CMD_DEV_ERROR | SIGNATURE_VERIFICATION_FAILURE): //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eDECRYPT_ERROR; break; default: //lint -e750 "The remaining errors returned by the security chip is mapped to Internal error Alert" //Prepare Alert Message *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG) = (uint8_t)eINTERNAL_ERROR; break; } }while(0); } /** * Forms the alert message based on the given internal error code.
* * \param[in] Pi4ErrorCode DTLS Internal error code * \param[in,out] PpsAlertMsg Pointer to a blob containing Alert message as per DTLS Specification * */ _STATIC_H Void Alert_FormMsg(int32_t Pi4ErrorCode,sbBlob_d* PpsAlertMsg) { //Maps the internal error code to the Alert messages DtlsErrorAlertMapping(Pi4ErrorCode,PpsAlertMsg); } #endif //DISABLE_ALERT /** * Maps the Alert types and level to error code.
* * \param[in] PpsAlertMsg Pointer to a blob containing Alert message as per DTLS Specification * \param[in,out] Ppi4ErrorCode Pointer to the DTLS Internal error code * * \retval #OCP_AL_OK Successful execution * \retval #OCP_AL_ERROR Failure in execution * */ _STATIC_H int32_t DtlsAlertErrorMapping(const sbBlob_d* PpsAlertMsg, int32_t* Ppi4ErrorCode) { int32_t i4Status = (int32_t)OCP_AL_ERROR; do { //Check for the Alert level type if(eFATAL == (eAlertLevel_d)*PpsAlertMsg->prgbStream) { //Check for various fatal alert messages switch((eAlertMsg_d) *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG)) { case eCLOSE_NOTIFY: case eUNEXPECTED_MESSAGE: case eBAD_RECORD_MAC: case eDECRYPTION_FAILURE: case eRECORD_OVERFLOW: case eDECOMPRESSION_FAILURE: case eHANDSHAKE_FAILURE: case eBAD_CERTIFICATE: case eUNSUPPORTED_CERTIFICATE: case eNO_CERTIFICATE: case eCERTIFICATE_REVOKED: case eCERTIFICATE_EXPIRED: case eCERTIFICATE_UNKNOWN: case eUSER_CANCELLED: case eNO_RENEGOTIATION: case eILLEGAL_PARAMETER: case eUNKNOWN_CA: case eACCESS_DENIED: case eDECODE_ERROR: case eDECRYPT_ERROR: case eEXPORT_RESTRICTION: case ePROTOCOL_VERSION: case eINSUFFICIENT_SECURITY: case eINTERNAL_ERROR: case eUNSUPPORTED_EXTENSION: { *Ppi4ErrorCode = (int32_t)OCP_AL_FATAL_ERROR; i4Status = (int32_t)OCP_AL_OK; } break; default: //Indicates the received Alert is not a valid Fatal Error break; } } //Check for Warning Alert level type else if (eWARNING == (eAlertLevel_d)*PpsAlertMsg->prgbStream) { //Check for various warning alert messages switch((eAlertMsg_d) *(PpsAlertMsg->prgbStream + OFFSET_ALERT_MSG)) { case eBAD_CERTIFICATE: case eUNSUPPORTED_CERTIFICATE: case eCERTIFICATE_REVOKED: case eCERTIFICATE_EXPIRED: case eCERTIFICATE_UNKNOWN: case eUSER_CANCELLED: case eNO_RENEGOTIATION: { *Ppi4ErrorCode = (int32_t)OCP_AL_WARNING_ERROR; i4Status = (int32_t)OCP_AL_OK; break; } default: //lint -e788 suppress "As the enum values are divided between Fatal and warning levels" //Indicates the received Alert is not a valid warning Error break; } } }while(0); return i4Status; } #ifndef DISABLE_ALERT /** * Sends Alert based on the internal error code via the Record Layer.
* * \param[in] PpsConfigRL Pointer to structure containing Record Layer information. * \param[in] Pi4ErrorCode DTLS Internal error code * */ void Alert_Send(sConfigRL_d *PpsConfigRL,int32_t Pi4ErrorCode) { int32_t i4Status = (int32_t)OCP_AL_ERROR; sbBlob_d sAlertMsg; uint8_t bEncFlag = 0; uint8_t bFlagIncr = 0; uint8_t rgbAlertMsg[LENGTH_ALERT_MSG]; //Null checks if((NULL != PpsConfigRL) && (NULL != PpsConfigRL->pfSend) && (NULL != PpsConfigRL->sRL.phRLHdl)) { do { /// @cond hidden #define PS_RECORDLAYER ((sRecordLayer_d*)PpsConfigRL->sRL.phRLHdl) /// @endcond sAlertMsg.prgbStream = rgbAlertMsg; sAlertMsg.wLen = LENGTH_ALERT_MSG; //Form the Alert message based on internal error code Alert_FormMsg(Pi4ErrorCode, &sAlertMsg); PpsConfigRL->sRL.bMemoryAllocated = FALSE; PpsConfigRL->sRL.bContentType = CONTENTTYPE_ALERT; //Until successful completion of Mutual Authentication Public Key Scheme (DTLS) the Client should use previous epoch and messages must not be encrypted if(((PS_RECORDLAYER->wServerEpoch != PS_RECORDLAYER->wClientNextEpoch) && (*PS_RECORDLAYER->pbDec != 0x01)) || (Pi4ErrorCode == (int32_t)OCP_FL_INT_ERROR) || (Pi4ErrorCode == (int32_t)OCP_FL_HS_ERROR)) { if((PS_RECORDLAYER->bEncDecFlag == ENC_DEC_ENABLED) && (PS_RECORDLAYER->wClientEpoch != PS_RECORDLAYER->wClientNextEpoch)) { bEncFlag = PS_RECORDLAYER->bEncDecFlag; PS_RECORDLAYER->bEncDecFlag = ENC_DEC_DISABLED; PS_RECORDLAYER->wClientNextEpoch--; bFlagIncr = 0x01; } } //Send the Alert message via record layer i4Status = PpsConfigRL->pfSend(&PpsConfigRL->sRL, sAlertMsg.prgbStream, sAlertMsg.wLen); if(bFlagIncr == 0x01) { PS_RECORDLAYER->bEncDecFlag = bEncFlag; PS_RECORDLAYER->wClientNextEpoch++; } if(OCP_RL_OK != i4Status) { break; } }while(FALSE); /// @cond hidden #undef PS_RECORDLAYER /// @endcond } } #endif //DISABLE_ALERT /** * Processes the received Alert Message
* Returns the corresponding internal error code.
* * \param[in] PpsAlertMsg Pointer to a blob containing Alert message as per DTLS Specification * \param[in,out] Ppi4ErrorCode Pointer to the DTLS Internal error code * * \retval #OCP_AL_OK Successful execution * \retval #OCP_AL_ERROR Failure in execution \if ENABLE_NULL_CHECKS * \retval #OCP_AL_NULL_PARAM Null parameter(s) \endif * \retval #OCP_AL_LENZERO_ERROR Length of input parameter is zero * */ int32_t Alert_ProcessMsg(const sbBlob_d* PpsAlertMsg,int32_t* Ppi4ErrorCode) { int32_t i4Status = (int32_t)OCP_AL_ERROR; do { #ifdef ENABLE_NULL_CHECKS //NULL check for the input parameters if((NULL == PpsAlertMsg) || (NULL == Ppi4ErrorCode)|| (NULL == PpsAlertMsg->prgbStream)) { i4Status = (int32_t)OCP_AL_NULL_PARAM; break; } #endif //Check for length is less than Alert message size if(LENGTH_ALERT_MSG != PpsAlertMsg->wLen) { break; } //Maps the received Alert messages to the internal error codes i4Status = DtlsAlertErrorMapping(PpsAlertMsg, Ppi4ErrorCode); }while(0); return i4Status; } /** * @} */ #endif /*MODULE_ENABLE_DTLS_MUTUAL_AUTH */