diff --git a/Host/Source/LibOpenBLT/xcploader.c b/Host/Source/LibOpenBLT/xcploader.c index bf3a82e4..42879168 100644 --- a/Host/Source/LibOpenBLT/xcploader.c +++ b/Host/Source/LibOpenBLT/xcploader.c @@ -81,7 +81,7 @@ static uint16_t XcpLoaderGetOrderedWord(uint8_t const * data); static bool XcpLoaderSendCmdConnect(void); static bool XcpLoaderSendCmdGetStatus(uint8_t * session, uint8_t * protectedResources, uint16_t * configId); -static bool XcpLoaderSendCmdGetSeed(uint8_t resource, uint8_t * seed, uint8_t * seedLen); +static bool XcpLoaderSendCmdGetSeed(uint8_t resource, uint8_t mode, uint8_t * seed, uint8_t * seedLen); static bool XcpLoaderSendCmdUnlock(uint8_t const * key, uint8_t keyLen, uint8_t * protectedResources); static bool XcpLoaderSendCmdSetMta(uint32_t address); @@ -316,10 +316,16 @@ static bool XcpLoaderStart(void) if ( (protectedResources & XCPPROTECT_RESOURCE_PGM) != 0) { uint8_t availableResources = 0; - uint8_t seed[XCPLOADER_PACKET_SIZE_MAX-2] = { 0 }; - uint8_t seedLen = 0; - uint8_t key[XCPLOADER_PACKET_SIZE_MAX-2] = { 0 }; - uint8_t keyLen = 0; + uint8_t seed[256] = { 0 }; + uint8_t *seedPtr = &seed[0]; + uint8_t seedTotalLen = 0; + uint8_t seedRemainingLen = 0; + uint8_t key[256] = { 0 }; + uint8_t keyTotalLen = 0; + uint8_t keyRemainingLen = 0; + uint8_t keyCurrentLen = 0; + uint8_t *keyPtr = &key[0]; + /* Make sure the XCP protection module contains an unlock algorithm for the * programming resource. */ @@ -340,22 +346,41 @@ static bool XcpLoaderStart(void) result = false; } } - /* Request the seed for unlocking the programming resources. */ + /* Request (first part of) the seed for unlocking the programming resources. */ if (result) { - if (!XcpLoaderSendCmdGetSeed(XCPPROTECT_RESOURCE_PGM, seed, &seedLen)) + if (!XcpLoaderSendCmdGetSeed(XCPPROTECT_RESOURCE_PGM, 0, seedPtr, &seedRemainingLen)) { result = false; } + else + { + /* store the total seed length */ + seedTotalLen = seedRemainingLen; + } + } + /* Check if more parts of the seed need to be requested. */ + if (result) + { + while (seedRemainingLen > (xcpMaxDto - 2)) + { + /* update the seed pointer for the next part */ + seedPtr += (xcpMaxDto - 2); + if (!XcpLoaderSendCmdGetSeed(XCPPROTECT_RESOURCE_PGM, 1, seedPtr, &seedRemainingLen)) + { + result = false; + break; + } + } } /* Only continue with resource unlock operation if not already unlocked, which * is indicated by a seed length of 0. */ - if ( (result) && (seedLen > 0) ) + if ( (result) && (seedTotalLen > 0) ) { /* Compute the key using the XCP protection module. */ - if (!XCPProtectComputeKeyFromSeed(XCPPROTECT_RESOURCE_PGM, seedLen, seed, - &keyLen, key)) + if (!XCPProtectComputeKeyFromSeed(XCPPROTECT_RESOURCE_PGM, seedTotalLen, seed, + &keyTotalLen, key)) { result = false; } @@ -363,16 +388,38 @@ static bool XcpLoaderStart(void) if (result) { uint8_t currentlyProtectedResources = 0; - /* Send the key to unlock the resource. */ - if (!XcpLoaderSendCmdUnlock(key, keyLen, ¤tlyProtectedResources)) + + /* Initialize remaining length */ + keyRemainingLen = keyTotalLen; + + /* Send the key to unlock the resource */ + while (keyRemainingLen > 0) { - result = false; - } - /* Double-check that the programming resource is now unlocked. */ - else if ((currentlyProtectedResources & XCPPROTECT_RESOURCE_PGM) != 0) - { - /* Programming resource unlock operation failed. */ - result = false; + /* Determine how many key bytes are about to be sent. */ + keyCurrentLen = keyRemainingLen; + if (keyCurrentLen > (xcpMaxCto - 2)) + { + keyCurrentLen = (xcpMaxCto - 2); + } + /* The the (possible partial) unlock command. */ + if (!XcpLoaderSendCmdUnlock(keyPtr, keyRemainingLen, ¤tlyProtectedResources)) + { + result = false; + break; + } + /* Update key pointer and the remaining length */ + keyRemainingLen -= keyCurrentLen; + keyPtr += keyCurrentLen; + /* Check if the key was now completely sent. */ + if (keyRemainingLen == 0) + { + /* Double-check that the programming resource is now unlocked. */ + if ((currentlyProtectedResources & XCPPROTECT_RESOURCE_PGM) != 0) + { + /* Programming resource unlock operation failed. */ + result = false; + } + } } } } @@ -825,14 +872,17 @@ static bool XcpLoaderSendCmdGetStatus(uint8_t * session, uint8_t * protectedReso /************************************************************************************//** ** \brief Sends the XCP Get Seed command. ** \param resource The resource to unlock (XCPPROTECT_RESOURCE_xxx). +** \param mode 0 for the first part of the seed, 1 for the remaining part. ** \param seed Pointer to byte array where the received seed is stored. ** \param seedLen Length of the seed in bytes. ** \return True if successful, false otherwise. ** ****************************************************************************************/ -static bool XcpLoaderSendCmdGetSeed(uint8_t resource, uint8_t * seed, uint8_t * seedLen) +static bool XcpLoaderSendCmdGetSeed(uint8_t resource, uint8_t mode, uint8_t * seed, + uint8_t * seedLen) { bool result = false; + uint8_t currentSeedLen; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; @@ -857,12 +907,7 @@ static bool XcpLoaderSendCmdGetSeed(uint8_t resource, uint8_t * seed, uint8_t * result = true; /* Prepare the command packet. */ cmdPacket.data[0] = XCPLOADER_CMD_GET_SEED; - /* Always use mode 0 because only seeds up to 48-bit are supported currently. - * This fits in 6-bytes, making it work with the all currently supported transport - * layers. CAN is the limiting one, because the max packet length is 8-bytes for - * this transport layer. - */ - cmdPacket.data[1] = 0; + cmdPacket.data[1] = mode; cmdPacket.data[2] = resource; cmdPacket.len = 3; /* Send the packet. */ @@ -886,20 +931,18 @@ static bool XcpLoaderSendCmdGetSeed(uint8_t resource, uint8_t * seed, uint8_t * /* Extract and store the seed. */ if (result) { - /* Make sure the seed length is valid. */ - if (resPacket.data[1] > (xcpMaxCto - 2)) + /* Store the seed length. */ + *seedLen = resPacket.data[1]; + /* Determine the number of seed bytes in the current response */ + currentSeedLen = *seedLen; + if (currentSeedLen > (xcpMaxCto - 2)) { - result = false; + currentSeedLen = (xcpMaxCto - 2); } - else + /* Store the seed bytes. */ + for (uint8_t idx = 0; idx < currentSeedLen; idx++) { - /* Store the seed length. */ - *seedLen = resPacket.data[1]; - /* Store the seed. */ - for (uint8_t idx = 0; idx < *seedLen; idx++) - { - seed[idx] = resPacket.data[idx + 2]; - } + seed[idx] = resPacket.data[idx + 2]; } } } @@ -921,6 +964,7 @@ static bool XcpLoaderSendCmdUnlock(uint8_t const * key, uint8_t keyLen, uint8_t * protectedResources) { bool result = false; + uint8_t keyCurrentLen; tXcpTransportPacket cmdPacket; tXcpTransportPacket resPacket; @@ -928,23 +972,29 @@ static bool XcpLoaderSendCmdUnlock(uint8_t const * key, uint8_t keyLen, assert(xcpSettings.transport != NULL); assert(key != NULL); assert(keyLen > 0); - assert(keyLen <= (xcpMaxCto - 2)); assert(protectedResources != NULL); /* Only continue with a valid transport layer and parameters. */ if ( (xcpSettings.transport != NULL) && (key != NULL) && (keyLen > 0) && - (keyLen <= (xcpMaxCto - 2)) && (protectedResources != NULL) ) /*lint !e774 */ + (protectedResources != NULL) ) /*lint !e774 */ { /* Init the result value to okay and only set it to error when a problem occurred. */ result = true; /* Prepare the command packet. */ cmdPacket.data[0] = XCPLOADER_CMD_UNLOCK; cmdPacket.data[1] = keyLen; - for (uint8_t idx = 0; idx < keyLen; idx++) + /* Determine number of key bytes for the packet. */ + keyCurrentLen = keyLen; + if (keyCurrentLen > (xcpMaxCto - 2)) + { + keyCurrentLen = xcpMaxCto - 2; + } + /* Copy key bytes. */ + for (uint8_t idx = 0; idx < keyCurrentLen; idx++) { cmdPacket.data[idx + 2] = key[idx]; } - cmdPacket.len = keyLen + 2; + cmdPacket.len = keyCurrentLen + 2; /* Send the packet. */ if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, xcpSettings.timeoutT1)) diff --git a/Host/libopenblt.dll b/Host/libopenblt.dll index 4079a48b..5ff3dc9f 100644 Binary files a/Host/libopenblt.dll and b/Host/libopenblt.dll differ diff --git a/Target/Source/plausibility.h b/Target/Source/plausibility.h index d4efd24f..a7af4061 100644 --- a/Target/Source/plausibility.h +++ b/Target/Source/plausibility.h @@ -499,6 +499,21 @@ #error "BOOT_XCP_PACKET_RECEIVED_HOOK must be 0 or 1" #endif +#ifndef BOOT_XCP_SEED_MAX_LEN +#define BOOT_XCP_SEED_MAX_LEN (64) +#endif + +#if (BOOT_XCP_SEED_MAX_LEN <= 0) +#error "BOOT_XCP_SEED_MAX_LEN must be > 0" +#endif + +#ifndef BOOT_XCP_KEY_MAX_LEN +#define BOOT_XCP_KEY_MAX_LEN (64) +#endif + +#if (BOOT_XCP_KEY_MAX_LEN <= 0) +#error "BOOT_XCP_KEY_MAX_LEN must be > 0" +#endif #endif /* PLAUSIBILITY_H */ /*********************************** end of plausibility.h *****************************/ diff --git a/Target/Source/xcp.c b/Target/Source/xcp.c index e4a688e5..cbaa1c09 100644 --- a/Target/Source/xcp.c +++ b/Target/Source/xcp.c @@ -915,68 +915,120 @@ static void XcpCmdBuildCheckSum(blt_int8u *data) static void XcpCmdGetSeed(blt_int8u *data) { blt_int8u resourceOK; - - /* init resource check variable as if an illegal resource is requested */ - resourceOK = 0; - - /* check if calibration/paging resource is requested for seed/key and make - * sure this is the only requested resource - */ - if (((data[2] & XCP_RES_CALPAG) > 0) && ((data[2] & ~XCP_RES_CALPAG) == 0)) - { - resourceOK = 1; - } - - /* check if programming resource is requested for seed/key and make - * sure this is the only requested resource - */ - if (((data[2] & XCP_RES_PGM) > 0) && ((data[2] & ~XCP_RES_PGM) == 0)) - { - resourceOK = 1; - } - - /* check if data acquisition resource is requested for seed/key and make - * sure this is the only requested resource - */ - if (((data[2] & XCP_RES_DAQ) > 0) && ((data[2] & ~XCP_RES_DAQ) == 0)) - { - resourceOK = 1; - } - - /* check if data stimulation resource is requested for seed/key and make - * sure this is the only requested resource - */ - if (((data[2] & XCP_RES_STIM) > 0) && ((data[2] & ~XCP_RES_STIM) == 0)) - { - resourceOK = 1; - } - - /* now process the resource validation */ - if (resourceOK == 0) - { - XcpSetCtoError(XCP_ERR_OUT_OF_RANGE); - return; - } - - /* store resource for which the seed/key sequence is started */ - xcpInfo.s_n_k_resource = data[2]; + /* made seed buffer static to lower stack load */ + static blt_int8u seedBuffer[XCP_SEED_MAX_LEN]; + static blt_int8u seedRemainderLen = 0; + static blt_int8u *seedCurrentPtr; + static blt_bool sequenceInProgress = BLT_FALSE; + blt_int8u seedCurrentLen; /* set packet id to command response packet */ xcpInfo.ctoData[0] = XCP_PID_RES; - /* request the seed from the application */ - xcpInfo.ctoData[1] = XcpGetSeed(xcpInfo.s_n_k_resource, &xcpInfo.ctoData[2]); - - /* seed cannot be longer than XCP_CTO_PACKET_LEN-2 */ - if (xcpInfo.ctoData[1] > (XCP_CTO_PACKET_LEN-2)) + /* validate requested resource in case the mode flag equals 0 */ + if (data[1] == 0) { - /* seed length is too long */ - XcpSetCtoError(XCP_ERR_OUT_OF_RANGE); - return; + /* init resource check variable as if an illegal resource is requested */ + resourceOK = 0; + + /* check if calibration/paging resource is requested for seed/key and make + * sure this is the only requested resource + */ + if (((data[2] & XCP_RES_CALPAG) > 0) && ((data[2] & ~XCP_RES_CALPAG) == 0)) + { + resourceOK = 1; + } + + /* check if programming resource is requested for seed/key and make + * sure this is the only requested resource + */ + if (((data[2] & XCP_RES_PGM) > 0) && ((data[2] & ~XCP_RES_PGM) == 0)) + { + resourceOK = 1; + } + + /* check if data acquisition resource is requested for seed/key and make + * sure this is the only requested resource + */ + if (((data[2] & XCP_RES_DAQ) > 0) && ((data[2] & ~XCP_RES_DAQ) == 0)) + { + resourceOK = 1; + } + + /* check if data stimulation resource is requested for seed/key and make + * sure this is the only requested resource + */ + if (((data[2] & XCP_RES_STIM) > 0) && ((data[2] & ~XCP_RES_STIM) == 0)) + { + resourceOK = 1; + } + + /* now process the resource validation */ + if (resourceOK == 0) + { + XcpSetCtoError(XCP_ERR_OUT_OF_RANGE); + return; + } + + /* check if the resource is already unlocked */ + if ((xcpInfo.protection & data[2]) == 0) + { + /* set the seed length to 0 to indicate that the resource is already unlocked */ + xcpInfo.ctoData[1] = 0; + /* set packet length */ + xcpInfo.ctoLen = 2; + /* no need to continue processing */ + return; + } + + /* store resource for which the seed/key sequence is started */ + xcpInfo.s_n_k_resource = data[2]; } + /* process the mode flag. 0 is first part of the seed, 1 is remainder of the seed */ + if (data[1] == 0) + { + /* set flag that a seed reading sequence is now in progress */ + sequenceInProgress = BLT_TRUE; + /* obtain the seed and store it in the buffer */ + seedRemainderLen = XcpGetSeed(xcpInfo.s_n_k_resource, seedBuffer); + /* protect against buffer overrun */ + ASSERT_RT(seedRemainderLen <= XCP_SEED_MAX_LEN); + /* set seed pointer */ + seedCurrentPtr = &seedBuffer[0]; + } + /* seed remainder is requested */ + else + { + /* this is only allowed if a sequence is in progress */ + if (sequenceInProgress == BLT_FALSE) + { + /* invalid sequence */ + XcpSetCtoError(XCP_ERR_SEQUENCE); + /* reset seed/key resource variable for possible next unlock */ + xcpInfo.s_n_k_resource = 0; + return; + } + } + /* determine number of seed bytes that fit in the first response */ + seedCurrentLen = seedRemainderLen; + if (seedCurrentLen > (XCP_CTO_PACKET_LEN-2)) + { + seedCurrentLen = XCP_CTO_PACKET_LEN-2; + } + /* store the first part of the seed in the response */ + CpuMemCopy((blt_addr)(&xcpInfo.ctoData[2]), (blt_addr)seedCurrentPtr, seedCurrentLen); + xcpInfo.ctoData[1] = seedRemainderLen; + /* update control variables */ + seedRemainderLen -= seedCurrentLen; + seedCurrentPtr += seedCurrentLen; + /* reset sequence flag at the end of the sequence */ + if (seedRemainderLen == 0) + { + sequenceInProgress = BLT_FALSE; + } /* set packet length */ - xcpInfo.ctoLen = xcpInfo.ctoData[1] + 2; + xcpInfo.ctoLen = seedCurrentLen + 2; } /*** end of XcpCmdGetSeed ***/ @@ -989,41 +1041,82 @@ static void XcpCmdGetSeed(blt_int8u *data) ****************************************************************************************/ static void XcpCmdUnlock(blt_int8u *data) { - /* key cannot be longer than XCP_CTO_PACKET_LEN-2 */ - if (data[1] > (XCP_CTO_PACKET_LEN-2)) + /* made key buffer static to lower stack load */ + static blt_int8u keyBuffer[XCP_KEY_MAX_LEN]; + static blt_int8u keyPreviousRemainder = 0; + static blt_int8u keyTotalLen = 0; + static blt_int8u *keyCurrentPtr; + static blt_int8u keyReceivedLen = 0; + blt_int8u keyCurrentLen; + + /* verify that the key will actually fit in the buffer */ + if (data[1] > XCP_KEY_MAX_LEN) { - /* key is too long incorrect */ - XcpSetCtoError(XCP_ERR_SEQUENCE); + /* reset previous remainder for the next loop iteration */ + keyPreviousRemainder = 0; + /* key is too long */ + XcpSetCtoError(XCP_ERR_OUT_OF_RANGE); + /* reset seed/key resource variable for possible next unlock */ + xcpInfo.s_n_k_resource = 0; return; } - /* verify the key */ - if (XcpVerifyKey(xcpInfo.s_n_k_resource, &data[2], data[1]) == 0) + /* is this the start of a key reception? the first unlock message contains the total + * length of the key and subsequent messages the remainder length. if the received + * length is >= than the previously received remainder, it must be the reception + * start of a new key. + */ + if (data[1] >= keyPreviousRemainder) { - /* invalid key so inform the master and do a disconnect */ - XcpSetCtoError(XCP_ERR_ACCESS_LOCKED); + /* store the total length of the key */ + keyTotalLen = data[1]; + /* initialize pointer to key reception buffer */ + keyCurrentPtr = &keyBuffer[0]; + /* reset number of received key bytes */ + keyReceivedLen = 0; - /* indicate that the xcp connection is disconnected */ - xcpInfo.connected = 0; - - /* enable resource protection */ - XcpProtectResources(); - - return; } - - /* key correct so unlock the resource */ - xcpInfo.protection &= ~xcpInfo.s_n_k_resource; - - /* reset seed/key resource variable for possible next unlock */ - xcpInfo.s_n_k_resource = 0; + /* store length / remainder for checking during the next iteration */ + keyPreviousRemainder = data[1]; + /* determine how many key bytes were received */ + keyCurrentLen = data[1]; + if (keyCurrentLen > (XCP_CTO_PACKET_LEN-2)) + { + keyCurrentLen = XCP_CTO_PACKET_LEN-2; + } + /* store the received key bytes to the buffer */ + CpuMemCopy((blt_addr)keyCurrentPtr, (blt_addr)(&data[2]), keyCurrentLen); + /* update control variables */ + keyCurrentPtr += keyCurrentLen; + keyReceivedLen += keyCurrentLen; + /* check if the entire key was received */ + if (keyReceivedLen >= keyTotalLen) + { + /* reset previous remainder for the next loop iteration */ + keyPreviousRemainder = 0; + /* verify the key */ + if (XcpVerifyKey(xcpInfo.s_n_k_resource, keyBuffer, keyTotalLen) == 0) + { + /* invalid key so inform the master and do a disconnect */ + XcpSetCtoError(XCP_ERR_ACCESS_LOCKED); + /* indicate that the xcp connection is disconnected */ + xcpInfo.connected = 0; + /* reset seed/key resource variable for possible next unlock */ + xcpInfo.s_n_k_resource = 0; + /* enable resource protection */ + XcpProtectResources(); + return; + } + /* key correct so unlock the resource */ + xcpInfo.protection &= ~xcpInfo.s_n_k_resource; + /* reset seed/key resource variable for possible next unlock */ + xcpInfo.s_n_k_resource = 0; + } /* set packet id to command response packet */ xcpInfo.ctoData[0] = XCP_PID_RES; - /* report the current resource protection */ xcpInfo.ctoData[1] = xcpInfo.protection; - /* set packet length */ xcpInfo.ctoLen = 2; } /*** end of XcpCmdUnlock ***/ diff --git a/Target/Source/xcp.h b/Target/Source/xcp.h index f4ea99cd..39065f60 100644 --- a/Target/Source/xcp.h +++ b/Target/Source/xcp.h @@ -53,10 +53,10 @@ #if (BOOT_CPU_BYTE_ORDER_MOTOROLA > 0) /** \brief XCP byte ordering according to the Motorola (big-endian). */ -#define XCP_MOTOROLA_FORMAT (0x01) +#define XCP_MOTOROLA_FORMAT (0x01) #else /** \brief XCP byte ordering according to the Intel (little-endian). */ -#define XCP_MOTOROLA_FORMAT (0x00) +#define XCP_MOTOROLA_FORMAT (0x00) #endif /** \brief Enable (=1) or disable (=0) support for the calibration resource. This is @@ -240,6 +240,11 @@ /** \brief Use user defined algorithm. */ #define XCP_CS_USER (0xff) +/** \brief Maximum number of bytes of a seed for the seed/key security feature. */ +#define XCP_SEED_MAX_LEN (BOOT_XCP_SEED_MAX_LEN) +/** \brief Maximum number of bytes of a key for the seed/key security feature. */ +#define XCP_KEY_MAX_LEN (BOOT_XCP_KEY_MAX_LEN) + /**************************************************************************************** * Function prototypes