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