/* * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD * All rights reserved. * * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use * exclusively with CVA's microcontroller products. This file can be freely * distributed within development tools that are supporting such microcontroller * products. * * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. */ /******************************************************************************* * the includes ******************************************************************************/ #include #include "uds_service27.h" /******************************************************************************* * the defines ******************************************************************************/ #define SUPPORT_LEVEL_NUM 4 /* supported security level number */ #define MAX_ALLOW_ERROR_NUM 5 /* the max allow number of key error */ #define STARTUP_DELAY_MS 2000 /* the service allow access time delay after UDS start */ #define ERR_EXCEED_DELAY_MS 10000 /* the service allow access time delay after error number exceed */ /******************************************************************************* * the typedefs ******************************************************************************/ typedef struct _SecurityLevel_Param_ { uint8_t level; uint8_t keyErrorCnt; uint8_t maxErrNum; int64_t MaxErrTimeStamp; } SecurityLevel_Param; /******************************************************************************* * the globals ******************************************************************************/ SecurityLevel_Param scrtParam[SUPPORT_LEVEL_NUM] = { {UDS_SA_LEVEL_1, 0, MAX_ALLOW_ERROR_NUM, 0}, {UDS_SA_LEVEL_3, 0, MAX_ALLOW_ERROR_NUM, 0}, {UDS_SA_LEVEL_11, 0, MAX_ALLOW_ERROR_NUM, 0}, {UDS_SA_LEVEL_63, 0, MAX_ALLOW_ERROR_NUM, 0}, }; /******************************************************************************* * the constants ******************************************************************************/ /******************************************************************************* * the functions ******************************************************************************/ static void UdsSecurityAccess_GenerateSeed(UdsType *obj, uint8_t newLevel, uint8_t *outData, uint8_t outBufsize, uint16_t *outLen) { /* seed is defined by user, It's usually a random value */ uint8_t seed[4] = {1, 2, 3, 4}; if(outBufsize < sizeof(seed)) { return; } *outLen = sizeof(seed); if(newLevel == obj->securityLevel) { memset(outData, 0, sizeof(seed)); } else { memcpy(outData, seed, sizeof(seed)); } } static bool UdsSecurityAccess_ValidateKey(uint8_t seedLevel, const uint8_t *seed, uint16_t seedLen, const uint8_t *key, uint16_t keyLen) { /* The encryption algorithm is provided by the vehicle manufacturer */ return true; } void UdsService27_SecurityAccess(UdsType *obj, const uint8_t msgBuf[], uint16_t msgLen) { static uint8_t seedLevel = 0; static uint8_t seedValue[8] = {0}; static uint16_t seedLen = 0; uint8_t subFunction; uint8_t udx = 0; uint8_t rspBuffer[8] = {0}; uint16_t dataLen = 0, remainSize = 0; bool ret = false; if(msgLen < obj->seviceTable[obj->curServiceIdx].minLen) { Uds_NegativeResponse(obj, 0x27, NRC_INVALID_MESSAGE_LENGTH_OR_FORMAT); return; } if(obj->session == UDS_SESSION_DEFAULT) { Uds_NegativeResponse(obj, 0x27, NRC_CONDITIONS_NOT_CORRECT); return; } if(obj->timeStamp_ms < STARTUP_DELAY_MS) { Uds_NegativeResponse(obj, 0x27, NRC_REQUIRED_TIME_DELAY_NOT_EXPIRED); return; } subFunction = UDS_GET_SUB_FUNCTION(msgBuf[1]); rspBuffer[0] = UDS_GET_POSITIVE_RSP(0x27); rspBuffer[1] = subFunction; if(subFunction % 2) { seedLevel = 0; for(udx = 0; udx < SUPPORT_LEVEL_NUM; udx++) { if(subFunction == scrtParam[udx].level) { if(scrtParam[udx].keyErrorCnt > scrtParam[udx].maxErrNum) { if(obj->timeStamp_ms - scrtParam[udx].MaxErrTimeStamp < ERR_EXCEED_DELAY_MS) { Uds_NegativeResponse(obj, 0x27, NRC_EXCEEDED_NUMBER_OF_ATTEMPTS); return; } else { scrtParam[udx].keyErrorCnt = 0; } } break; } } if(udx >= SUPPORT_LEVEL_NUM) { Uds_NegativeResponse(obj, 0x27, NRC_REQUEST_OUT_OF_RANGE); return; } remainSize = sizeof(rspBuffer) - 2; UdsSecurityAccess_GenerateSeed(obj, subFunction, &rspBuffer[2], remainSize, &dataLen); if(dataLen > 0) { Uds_PositiveResponse(obj, rspBuffer, dataLen + 2); seedLevel = subFunction; seedLen = dataLen; memcpy(seedValue, &rspBuffer[2], dataLen); } else { Uds_NegativeResponse(obj, 0x27, NRC_REQUEST_OUT_OF_RANGE); } } else { if(subFunction != seedLevel + 1) { Uds_NegativeResponse(obj, 0x27, NRC_REQUEST_SEQUENCE_ERROR); return; } /* polyspace-begin DEFECT:DEAD_CODE [No action planned:Low] "Still reserve though it's maybe unreachable" */ ret = UdsSecurityAccess_ValidateKey(seedLevel, seedValue, seedLen, &msgBuf[2], msgLen - 2); if(ret == true) { Uds_PositiveResponse(obj, rspBuffer, 2); seedLevel = 0; obj->securityLevel = subFunction - 1; for(udx = 0; udx < SUPPORT_LEVEL_NUM; udx++) { if(subFunction == scrtParam[udx].level) { scrtParam[udx].keyErrorCnt = 0; } } } else { Uds_NegativeResponse(obj, 0x27, NRC_INVALID_KEY); for(udx = 0; udx < SUPPORT_LEVEL_NUM; udx++) { if(seedLevel == scrtParam[udx].level) { scrtParam[udx].keyErrorCnt++; if(scrtParam[udx].keyErrorCnt > scrtParam[udx].maxErrNum) { scrtParam[udx].MaxErrTimeStamp = obj->timeStamp_ms; } } } } /* polyspace-end DEFECT:DEAD_CODE [No action planned:Low] "Still reserve though it's maybe unreachable" */ } }