Refs #618. Added support for splitting the XCP seed/key over multiple packets to make larger seed/key values possible, specifically on CAN.

git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@630 5dc33758-31d5-4daf-9ae8-b24bf3d40d73
This commit is contained in:
Frank Voorburg 2018-10-19 20:22:27 +00:00
parent 6345a5433d
commit 5ababf911d
5 changed files with 283 additions and 120 deletions

View File

@ -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, &currentlyProtectedResources))
/* 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, &currentlyProtectedResources))
{
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))

Binary file not shown.

View File

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

View File

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

View File

@ -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