From 32e11ecf9a2addfe52757ef818ccbd35c33765f0 Mon Sep 17 00:00:00 2001 From: Frank Voorburg Date: Thu, 26 Oct 2017 14:06:17 +0000 Subject: [PATCH] Refs #320. Implemented support for the seed/key protection in the XCP loader module. git-svn-id: https://svn.code.sf.net/p/openblt/code/trunk@381 5dc33758-31d5-4daf-9ae8-b24bf3d40d73 --- Host/Source/BootCommander/CMakeLists.txt | 4 +- Host/Source/LibOpenBLT/CMakeLists.txt | 12 +- Host/Source/LibOpenBLT/openblt.c | 1 + .../Source/LibOpenBLT/port/linux/xcpprotect.c | 194 +++++++++ .../LibOpenBLT/port/windows/xcpprotect.c | 198 +++++++++ Host/Source/LibOpenBLT/xcploader.c | 388 +++++++++++++++++- Host/Source/LibOpenBLT/xcploader.h | 2 + Host/Source/LibOpenBLT/xcpprotect.h | 61 +++ Host/Source/LibOpenBLT/xcptpuart.c | 2 +- Host/Source/SeedNKey/seednkey.c | 2 +- 10 files changed, 856 insertions(+), 8 deletions(-) create mode 100644 Host/Source/LibOpenBLT/port/linux/xcpprotect.c create mode 100644 Host/Source/LibOpenBLT/port/windows/xcpprotect.c create mode 100644 Host/Source/LibOpenBLT/xcpprotect.h diff --git a/Host/Source/BootCommander/CMakeLists.txt b/Host/Source/BootCommander/CMakeLists.txt index 678e7183..9a056de3 100644 --- a/Host/Source/BootCommander/CMakeLists.txt +++ b/Host/Source/BootCommander/CMakeLists.txt @@ -136,7 +136,9 @@ add_executable( if(CMAKE_C_COMPILER_ID MATCHES GNU) # According to the CMake docs, item names starting with '-', but not '-l' or # '-framework', are treated as linker flags. This means "-Wl" type linker flags can be - # specified here. + # specified here. Use this to add the path of the executable to the library search + # path. This way the LibOpenBLT shared library can simply be in the same directory as + # the BootCommander executable. target_link_libraries(BootCommander ${LIBOPENBLT_LIBNAME} "-Wl,-rpath,.") elseif(CMAKE_C_COMPILER_ID MATCHES MSVC) target_link_libraries(BootCommander ${LIBOPENBLT_LIBNAME}) diff --git a/Host/Source/LibOpenBLT/CMakeLists.txt b/Host/Source/LibOpenBLT/CMakeLists.txt index 694ea62c..42f1327b 100644 --- a/Host/Source/LibOpenBLT/CMakeLists.txt +++ b/Host/Source/LibOpenBLT/CMakeLists.txt @@ -144,8 +144,8 @@ set( # Only generate the static library taget if the option is enabled. Use # "make openblt_static" to individually build the static library. # Note that when you link your own application to the static library of LibOpenBLT under -# Unix, you need to also link the LibUsb library by adding usb-1.0 to the linker library -# dependencies. +# Unix, you need to also link the LibUsb and LibDL libraries by adding usb-1.0 and dl to +# the linker library dependencies. if(BUILD_STATIC) add_library(openblt_static STATIC ${LIB_SRCS}) SET_TARGET_PROPERTIES(openblt_static PROPERTIES OUTPUT_NAME openblt CLEAN_DIRECT_OUTPUT 1) @@ -160,7 +160,13 @@ if(BUILD_SHARED) # Make sure the libusb-1.0-0 and libusb-1.0-0-dev packages are installed to be able to # build LibOpenBLT. Example under Debian/Ubuntu: # sudo apt-get install libusb-1.0-0 libusb-1.0-0-dev - target_link_libraries(openblt_shared usb-1.0) + # Additionally, the LibDL is needed for dynamic library loading. + # According to the CMake docs, item names starting with '-', but not '-l' or + # '-framework', are treated as linker flags. This means "-Wl" type linker flags can be + # specified here. Use this to add the path of the shared library to the library search + # path. This way an (optional) seed and key shared library file can simply be in the + # same directory as the LibOpenBLT shared library. + target_link_libraries(openblt_shared usb-1.0 dl "-Wl,-rpath,.") endif(UNIX) if(CMAKE_C_COMPILER_ID MATCHES MSVC) # Microsoft Visual Studio does not add "lib" to the name of the DLL, whereas GCC diff --git a/Host/Source/LibOpenBLT/openblt.c b/Host/Source/LibOpenBLT/openblt.c index f771d436..a0f78042 100644 --- a/Host/Source/LibOpenBLT/openblt.c +++ b/Host/Source/LibOpenBLT/openblt.c @@ -139,6 +139,7 @@ LIBOPENBLT_EXPORT void BltSessionInit(uint32_t sessionType, xcpLoaderSettings.timeoutT4 = bltSessionSettingsXcpV10Ptr->timeoutT4; xcpLoaderSettings.timeoutT5 = bltSessionSettingsXcpV10Ptr->timeoutT5; xcpLoaderSettings.timeoutT7 = bltSessionSettingsXcpV10Ptr->timeoutT7; + xcpLoaderSettings.seedKeyFile = bltSessionSettingsXcpV10Ptr->seedKeyFile; xcpLoaderSettings.connectMode = bltSessionSettingsXcpV10Ptr->connectMode; xcpLoaderSettings.transport = NULL; xcpLoaderSettings.transportSettings = NULL; diff --git a/Host/Source/LibOpenBLT/port/linux/xcpprotect.c b/Host/Source/LibOpenBLT/port/linux/xcpprotect.c new file mode 100644 index 00000000..78aea757 --- /dev/null +++ b/Host/Source/LibOpenBLT/port/linux/xcpprotect.c @@ -0,0 +1,194 @@ +/************************************************************************************//** +* \file port/linux/xcpprotect.c +* \brief XCP Protection module source file. +* \ingroup XcpLoader +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or +* modify it under the terms of the GNU General Public License as published by the Free +* Software Foundation, either version 3 of the License, or (at your option) any later +* version. +* +* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You have received a copy of the GNU General Public License along with OpenBLT. It +* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy. +* +* \endinternal +****************************************************************************************/ + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for assertions */ +#include /* for standard integer types */ +#include /* for NULL declaration */ +#include /* for boolean type */ +#include /* for dynamic loading */ +#include "xcpprotect.h" /* XCP protection module */ + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +/* Seed and key shared library function types. */ +typedef uint32_t ( * tXcpProtectLibComputeKey)(uint8_t resource, uint8_t seedLen, + uint8_t const * seedPtr, + uint8_t * keyLenPtr, uint8_t * keyPtr); +typedef uint32_t ( * tXcpProtectLibGetPrivileges)(uint8_t * resourcePtr); + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Handle to the dynamically loaded seed and key shared library. It can also be + * used as a flag to determine if the shared library was specified and success- + * fully loaded. + */ +static void * seedNKeyLibraryHandle; + +/** \brief Function pointer to the XCP_ComputeKeyFromSeed shared library function. */ +static tXcpProtectLibComputeKey xcpProtectLibComputeKey; + +/** \brief Function pointer to the XCP_GetAvailablePrivileges shared library function. */ +static tXcpProtectLibGetPrivileges xcpProtectLibGetPrivileges; + + +/************************************************************************************//** +** \brief Initializes the XCP protection module. +** \param seedKeyFile Filename of the seed and key shared library that contains the +** following functions: +** - XCP_ComputeKeyFromSeed() +** - XCP_GetAvailablePrivileges() +** +****************************************************************************************/ +void XcpProtectInit(char const * seedKeyFile) +{ + /* Init locals. */ + seedNKeyLibraryHandle = NULL; + /* Reset library function pointers. */ + xcpProtectLibComputeKey = NULL; + xcpProtectLibGetPrivileges = NULL; + + /* Only load the shared library is a valid file was specified. */ + if (seedKeyFile != NULL) + { + /* Attempt to load the shared library. */ + seedNKeyLibraryHandle = dlopen(seedKeyFile, RTLD_LAZY); + /* Load the function pointers from the shared library. */ + if (seedNKeyLibraryHandle != NULL) + { + xcpProtectLibComputeKey = dlsym(seedNKeyLibraryHandle, + "XCP_ComputeKeyFromSeed"); + xcpProtectLibGetPrivileges = dlsym(seedNKeyLibraryHandle, + "XCP_GetAvailablePrivileges"); + } + } +} /*** end of XcpProtectInit ***/ + + +/************************************************************************************//** +** \brief Terminates the XCP protection module. +** +****************************************************************************************/ +void XcpProtectTerminate(void) +{ + /* Reset library function pointers. */ + xcpProtectLibComputeKey = NULL; + xcpProtectLibGetPrivileges = NULL; + /* Only unload the shared library if one was loaded. */ + if (seedNKeyLibraryHandle != NULL) + { + /* Unload the shared library. */ + (void)dlclose(seedNKeyLibraryHandle); + /* Reset the handle. */ + seedNKeyLibraryHandle = NULL; + } +} /*** end of XcpProtectTerminate ***/ + + +/************************************************************************************//** +** \brief Computes the key for the requested resource. +** \param resource resource for which the unlock key is requested +** \param seedLen length of the seed +** \param seedPtr pointer to the seed data +** \param keyLenPtr pointer where to store the key length +** \param keyPtr pointer where to store the key data +** \return True if successful, false otherwise. +** +****************************************************************************************/ +bool XCPProtectComputeKeyFromSeed(uint8_t resource, uint8_t seedLen, + uint8_t const * seedPtr, uint8_t * keyLenPtr, + uint8_t * keyPtr) +{ + bool result = false; + + /* Check parameters. */ + assert(seedLen > 0); + assert(seedPtr != NULL); + assert(keyLenPtr != NULL); + assert(keyPtr != NULL); + + /* Only continue if the parameters are valid. */ + if ( (seedLen > 0) && (seedPtr != NULL) && (keyLenPtr != NULL) && + (keyPtr != NULL) ) /*lint !e774 */ + { + /* Only continue with a valid function pointer into the shared library. */ + if (xcpProtectLibComputeKey != NULL) + { + /* Call the library function. */ + if (xcpProtectLibComputeKey(resource, seedLen, seedPtr, keyLenPtr, keyPtr) == 0) + { + /* All good so update the result value accordingly. */ + result = true; + } + } + } + /* Give the result back to the caller. */ + return result; +} /*** end of XCPProtectComputeKeyFromSeed ***/ + + +/************************************************************************************//** +** \brief Obtains a bitmask of the resources for which an key algorithm is available. +** \param resourcePtr pointer where to store the supported resources for the key +** computation. +** \return XCP_RESULT_OK on success, otherwise XCP_RESULT_ERROR. +** +****************************************************************************************/ +bool XcpProtectGetPrivileges(uint8_t * resourcePtr) +{ + bool result = false; + + /* Check parameters. */ + assert(resourcePtr != NULL); + + /* Only continue if the parameter is valid. */ + if (resourcePtr != NULL) /*lint !e774 */ + { + /* Only continue with a valid function pointer into the shared library. */ + if (xcpProtectLibGetPrivileges != NULL) + { + /* Call the library function. */ + if (xcpProtectLibGetPrivileges(resourcePtr) == 0) + { + /* All good so update the result value accordingly. */ + result = true; + } + } + } + /* Give the result back to the caller. */ + return result; +} /*** end of XcpProtectGetPrivileges ***/ + + +/*********************************** end of xcpprotect.c *******************************/ diff --git a/Host/Source/LibOpenBLT/port/windows/xcpprotect.c b/Host/Source/LibOpenBLT/port/windows/xcpprotect.c new file mode 100644 index 00000000..828088de --- /dev/null +++ b/Host/Source/LibOpenBLT/port/windows/xcpprotect.c @@ -0,0 +1,198 @@ +/************************************************************************************//** +* \file port/windows/xcpprotect.c +* \brief XCP Protection module source file. +* \ingroup XcpLoader +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or +* modify it under the terms of the GNU General Public License as published by the Free +* Software Foundation, either version 3 of the License, or (at your option) any later +* version. +* +* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You have received a copy of the GNU General Public License along with OpenBLT. It +* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy. +* +* \endinternal +****************************************************************************************/ + +/**************************************************************************************** +* Include files +****************************************************************************************/ +#include /* for assertions */ +#include /* for standard integer types */ +#include /* for NULL declaration */ +#include /* for boolean type */ +#include /* for Windows API */ +#include "xcpprotect.h" /* XCP protection module */ + + +/**************************************************************************************** +* Type definitions +****************************************************************************************/ +/* Seed and key shared library function types. */ +typedef uint32_t (* tXcpProtectLibComputeKey)(uint8_t resource, + uint8_t seedLen, + uint8_t const * seedPtr, + uint8_t * keyLenPtr, + uint8_t * keyPtr); +typedef uint32_t (* tXcpProtectLibGetPrivileges)(uint8_t * resourcePtr); + + +/**************************************************************************************** +* Local data declarations +****************************************************************************************/ +/** \brief Handle to the dynamically loaded seed and key shared library. It can also be + * used as a flag to determine if the shared library was specified and success- + * fully loaded. + */ +static HINSTANCE seedNKeyLibraryHandle; + +/** \brief Function pointer to the XCP_ComputeKeyFromSeed shared library function. */ +static tXcpProtectLibComputeKey xcpProtectLibComputeKey; + +/** \brief Function pointer to the XCP_GetAvailablePrivileges shared library function. */ +static tXcpProtectLibGetPrivileges xcpProtectLibGetPrivileges; + + +/************************************************************************************//** +** \brief Initializes the XCP protection module. +** \param seedKeyFile Filename of the seed and key shared library that contains the +** following functions: +** - XCP_ComputeKeyFromSeed() +** - XCP_GetAvailablePrivileges() +** +****************************************************************************************/ +void XcpProtectInit(char const * seedKeyFile) +{ + /* Init locals. */ + seedNKeyLibraryHandle = NULL; + /* Reset library function pointers. */ + xcpProtectLibComputeKey = NULL; + xcpProtectLibGetPrivileges = NULL; + + /* Only load the shared library is a valid file was specified. */ + if (seedKeyFile != NULL) + { + /* Attempt to load the shared library. */ + seedNKeyLibraryHandle = LoadLibrary(seedKeyFile); + /* Load the function pointers from the shared library. */ + if (seedNKeyLibraryHandle != NULL) + { + xcpProtectLibComputeKey = (tXcpProtectLibComputeKey)GetProcAddress( + seedNKeyLibraryHandle, + "XCP_ComputeKeyFromSeed"); + xcpProtectLibGetPrivileges = (tXcpProtectLibGetPrivileges)GetProcAddress( + seedNKeyLibraryHandle, + "XCP_GetAvailablePrivileges"); + } + } +} /*** end of XcpProtectInit ***/ + + +/************************************************************************************//** +** \brief Terminates the XCP protection module. +** +****************************************************************************************/ +void XcpProtectTerminate(void) +{ + /* Reset library function pointers. */ + xcpProtectLibComputeKey = NULL; + xcpProtectLibGetPrivileges = NULL; + /* Only unload the shared library if one was loaded. */ + if (seedNKeyLibraryHandle != NULL) + { + /* Unload the shared library. */ + (void)FreeLibrary(seedNKeyLibraryHandle); + /* Reset the handle. */ + seedNKeyLibraryHandle = NULL; + } +} /*** end of XcpProtectTerminate ***/ + + +/************************************************************************************//** +** \brief Computes the key for the requested resource. +** \param resource resource for which the unlock key is requested +** \param seedLen length of the seed +** \param seedPtr pointer to the seed data +** \param keyLenPtr pointer where to store the key length +** \param keyPtr pointer where to store the key data +** \return True if successful, false otherwise. +** +****************************************************************************************/ +bool XCPProtectComputeKeyFromSeed(uint8_t resource, uint8_t seedLen, + uint8_t const * seedPtr, uint8_t * keyLenPtr, + uint8_t * keyPtr) +{ + bool result = false; + + /* Check parameters. */ + assert(seedLen > 0); + assert(seedPtr != NULL); + assert(keyLenPtr != NULL); + assert(keyPtr != NULL); + + /* Only continue if the parameters are valid. */ + if ( (seedLen > 0) && (seedPtr != NULL) && (keyLenPtr != NULL) && + (keyPtr != NULL) ) /*lint !e774 */ + { + /* Only continue with a valid function pointer into the shared library. */ + if (xcpProtectLibComputeKey != NULL) + { + /* Call the library function. */ + if (xcpProtectLibComputeKey(resource, seedLen, seedPtr, keyLenPtr, keyPtr) == 0) + { + /* All good so update the result value accordingly. */ + result = true; + } + } + } + /* Give the result back to the caller. */ + return result; +} /*** end of XCPProtectComputeKeyFromSeed ***/ + + +/************************************************************************************//** +** \brief Obtains a bitmask of the resources for which an key algorithm is available. +** \param resourcePtr pointer where to store the supported resources for the key +** computation. +** \return XCP_RESULT_OK on success, otherwise XCP_RESULT_ERROR. +** +****************************************************************************************/ +bool XcpProtectGetPrivileges(uint8_t * resourcePtr) +{ + bool result = false; + + /* Check parameters. */ + assert(resourcePtr != NULL); + + /* Only continue if the parameter is valid. */ + if (resourcePtr != NULL) /*lint !e774 */ + { + /* Only continue with a valid function pointer into the shared library. */ + if (xcpProtectLibGetPrivileges != NULL) + { + /* Call the library function. */ + if (xcpProtectLibGetPrivileges(resourcePtr) == 0) + { + /* All good so update the result value accordingly. */ + result = true; + } + } + } + /* Give the result back to the caller. */ + return result; +} /*** end of XcpProtectGetPrivileges ***/ + + +/*********************************** end of xcpprotect.c *******************************/ diff --git a/Host/Source/LibOpenBLT/xcploader.c b/Host/Source/LibOpenBLT/xcploader.c index baa84ac6..d53cdd94 100644 --- a/Host/Source/LibOpenBLT/xcploader.c +++ b/Host/Source/LibOpenBLT/xcploader.c @@ -33,8 +33,11 @@ #include /* for standard integer types */ #include /* for NULL declaration */ #include /* for boolean type */ +#include /* for standard library */ +#include /* for string library */ #include "session.h" /* Communication session module */ #include "xcploader.h" /* XCP loader module */ +#include "xcpprotect.h" /* XCP protection module */ /**************************************************************************************** @@ -42,6 +45,9 @@ ****************************************************************************************/ /* XCP command codes as defined by the protocol currently supported by this module */ #define XCPLOADER_CMD_CONNECT (0xFFu) /**< XCP connect command code. */ +#define XCPLOADER_CMD_GET_STATUS (0xFDu) /**< XCP get status command code. */ +#define XCPLOADER_CMD_GET_SEED (0xF8u) /**< XCP get seed command code. */ +#define XCPLOADER_CMD_UNLOCK (0xF7u) /**< XCP unlock command code. */ #define XCPLOADER_CMD_SET_MTA (0xF6u) /**< XCP set mta command code. */ #define XCPLOADER_CMD_UPLOAD (0xF5u) /**< XCP upload command code. */ #define XCPLOADER_CMD_PROGRAM_START (0xD2u) /**< XCP program start command code. */ @@ -73,8 +79,14 @@ static bool XcpLoaderWriteData(uint32_t address, uint32_t len, uint8_t const * d static bool XcpLoaderReadData(uint32_t address, uint32_t len, uint8_t * data); /* General module specific utility functions. */ static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data); +static uint16_t XcpLoaderGetOrderedWord(uint8_t const * data); /* XCP command functions. */ 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 XcpLoaderSendCmdUnlock(uint8_t const * key, uint8_t keyLen, + uint8_t * protectedResources); static bool XcpLoaderSendCmdSetMta(uint32_t address); static bool XcpLoaderSendCmdUpload(uint8_t * data, uint8_t length); static bool XcpLoaderSendCmdProgramStart(void); @@ -143,6 +155,8 @@ tSessionProtocol const * XcpLoaderGetProtocol(void) ****************************************************************************************/ static void XcpLoaderInit(void const * settings) { + char * seedNKeyFileName; + /* Initialize locals. */ xcpConnected = false; xcpSlaveIsIntel = false; @@ -150,14 +164,39 @@ static void XcpLoaderInit(void const * settings) xcpMaxProgCto = 0; xcpMaxDto = 0; + /* Reset the XCP session layer settings. */ + xcpSettings.timeoutT1 = 1000; + xcpSettings.timeoutT3 = 2000; + xcpSettings.timeoutT4 = 10000; + xcpSettings.timeoutT5 = 1000; + xcpSettings.timeoutT7 = 2000; + xcpSettings.connectMode = 0; + xcpSettings.seedKeyFile = NULL; + xcpSettings.transport = NULL; + xcpSettings.transportSettings = NULL; + /* Check parameter. */ assert(settings != NULL); - /* Only continue with valid parameter. */ if (settings != NULL) /*lint !e774 */ { /* shallow copy the XCP settings for later usage */ xcpSettings = *(tXcpLoaderSettings *)settings; + + /* The seedKeyFile is a pointer and it is not guaranteed that it stays valid so we + * need to deep copy this one. note the +1 for '\0' in malloc. Note that it is okay + * for this value to be NULL. + */ + if (((tXcpLoaderSettings *)settings)->seedKeyFile != NULL) /*lint !e774 */ + { + seedNKeyFileName = malloc(strlen(((tXcpLoaderSettings *)settings)->seedKeyFile) + 1); + assert(seedNKeyFileName != NULL); + if (seedNKeyFileName != NULL) /*lint !e774 */ + { + strcpy(seedNKeyFileName, ((tXcpLoaderSettings *)settings)->seedKeyFile); + xcpSettings.seedKeyFile = seedNKeyFileName; + } + } /* Check that a valid transport layer was specified. */ assert(xcpSettings.transport != NULL); /* Only access the transport layer if it is valid. */ @@ -171,6 +210,8 @@ static void XcpLoaderInit(void const * settings) */ xcpSettings.transportSettings = NULL; } + /* Initialize the XCP protection module. */ + XcpProtectInit(xcpSettings.seedKeyFile); } /*** end of XcpLoaderInit ***/ @@ -183,6 +224,8 @@ static void XcpLoaderTerminate(void) /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); + /* Terminate the XCP protection module. */ + XcpProtectTerminate(); /* Only continue with a valid transport layer. */ if (xcpSettings.transport != NULL) /*lint !e774 */ { @@ -193,6 +236,21 @@ static void XcpLoaderTerminate(void) /* Unlink the transport layer. */ xcpSettings.transport = NULL; } + /* Release memory that was allocated for storing the seedKeyFile. */ + if (xcpSettings.seedKeyFile != NULL) + { + free((char *)xcpSettings.seedKeyFile); + } + /* Reset the XCP session layer settings. */ + xcpSettings.timeoutT1 = 1000; + xcpSettings.timeoutT3 = 2000; + xcpSettings.timeoutT4 = 10000; + xcpSettings.timeoutT5 = 1000; + xcpSettings.timeoutT7 = 2000; + xcpSettings.connectMode = 0; + xcpSettings.seedKeyFile = NULL; + xcpSettings.transport = NULL; + xcpSettings.transportSettings = NULL; } /*** end of XcpLoaderTerminate ***/ @@ -206,6 +264,7 @@ static bool XcpLoaderStart(void) { bool result = false; uint8_t retryCnt; + uint8_t protectedResources = 0; /* Make sure a valid transport layer is linked. */ assert(xcpSettings.transport != NULL); @@ -248,7 +307,79 @@ static bool XcpLoaderStart(void) result = false; } } - + /* Obtain the current resource protection status. */ + if (result) + { + if (!XcpLoaderSendCmdGetStatus(NULL, &protectedResources, NULL)) + { + result = false; + } + } + /* Check if the programming resource needs to be unlocked. */ + 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; + /* Make sure the XCP protection module contains an unlock algorithm for the + * programming resource. + */ + if (result) + { + if (!XcpProtectGetPrivileges(&availableResources)) + { + /* Could not obtain the supported resource privileges from the XCP protection + * module. + */ + result = false; + } + else if ((availableResources & XCPPROTECT_RESOURCE_PGM) == 0) + { + /* No unlock algorithm available for the programming resource in the XCP + * protection module. + */ + result = false; + } + } + /* Request the seed for unlocking the programming resources. */ + if (result) + { + if (!XcpLoaderSendCmdGetSeed(XCPPROTECT_RESOURCE_PGM, seed, &seedLen)) + { + result = false; + } + } + /* Only continue with resource unlock operation if not already unlocked, which + * is indicated by a seed length of 0. + */ + if ( (result) && (seedLen > 0) ) + { + /* Compute the key using the XCP protection module. */ + if (!XCPProtectComputeKeyFromSeed(XCPPROTECT_RESOURCE_PGM, seedLen, seed, + &keyLen, key)) + { + result = false; + } + /* Unlock the resource now that the key is available. */ + if (result) + { + uint8_t currentlyProtectedResources = 0; + /* Send the key to unlock the resource. */ + if (!XcpLoaderSendCmdUnlock(key, keyLen, ¤tlyProtectedResources)) + { + 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; + } + } + } + } /* Place the target in programming mode if connected. */ if (result) { @@ -508,6 +639,39 @@ static void XcpLoaderSetOrderedLong(uint32_t value, uint8_t *data) } /*** end of XcpLoaderSetOrderedLong ***/ +/************************************************************************************//** +** \brief Obtains a 16-bit value from a byte buffer taking into account Intel +** or Motorola byte ordering. +** \param data Array to the buffer with the word value stored as bytes. +** \return The 16-bit value. +** +****************************************************************************************/ +static uint16_t XcpLoaderGetOrderedWord(uint8_t const * data) +{ + uint16_t result = 0; + + /* Check parameters. */ + assert(data != NULL); + + /* Only continue with valid parameters. */ + if (data != NULL) /*lint !e774 */ + { + if (xcpSlaveIsIntel) + { + result |= (uint16_t)data[0]; + result |= (uint16_t)(data[1] << 8); + } + else + { + result |= (uint16_t)data[1]; + result |= (uint16_t)(data[0] << 8); + } + } + /* Give the result back to the caller. */ + return result; +} /*** end of XcpLoaderGetOrderedWord ***/ + + /************************************************************************************//** ** \brief Sends the XCP Connect command. ** \return True if successful, false otherwise. @@ -592,6 +756,226 @@ static bool XcpLoaderSendCmdConnect(void) } /*** end of XcpLoaderSendCmdConnect ***/ +/************************************************************************************//** +** \brief Sends the XCP Get Status command. Note that it is okay to specify a NULL +** value for the parameters if you are not interested in a particular one. +** \param session Current session status. +** \param protectedResources Current resource protection status. +** \param configId Session configuration identifier. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +static bool XcpLoaderSendCmdGetStatus(uint8_t * session, uint8_t * protectedResources, + uint16_t * configId) +{ + bool result = false; + tXcpTransportPacket cmdPacket; + tXcpTransportPacket resPacket; + + /* Make sure a valid transport layer is linked. */ + assert(xcpSettings.transport != NULL); + + /* Only continue with a valid transport layer. */ + if (xcpSettings.transport != 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_GET_STATUS; + cmdPacket.len = 1; + /* Send the packet. */ + if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, + xcpSettings.timeoutT1)) + { + /* Could not send packet or receive response within the specified timeout. */ + result = false; + } + /* Only continue if a response was received. */ + if (result) + { + /* Check if the response was valid. */ + if ( (resPacket.len != 6) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* Not a valid or positive response. */ + result = false; + } + } + /* Extract and store the received status information. */ + if (result) + { + /* Store the current session status. */ + if (session != NULL) + { + *session = resPacket.data[1]; + } + /* Store the current resource protection status. */ + if (protectedResources != NULL) + { + *protectedResources = resPacket.data[2]; + } + /* Store the session configuration id. */ + if (configId != NULL) + { + *configId = XcpLoaderGetOrderedWord(&resPacket.data[4]); + } + } + } + /* Give the result back to the caller. */ + return result; +} /*** end of XcpLoaderSendCmdGetStatus ***/ + + +/************************************************************************************//** +** \brief Sends the XCP Get Seed command. +** \param resource The resource to unlock (XCPPROTECT_RESOURCE_xxx). +** \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) +{ + bool result = false; + tXcpTransportPacket cmdPacket; + tXcpTransportPacket resPacket; + + /* Make sure a valid transport layer is linked and that the parameters are valid. */ + assert(xcpSettings.transport != NULL); + assert(seed != NULL); + assert(seedLen != NULL); + + /* Only continue with a valid transport layer and parameters. */ + if ( (xcpSettings.transport != NULL) && (seed != NULL) && + (seedLen != NULL) ) /*lint !e774 */ + { + /* Only continue with a valid resource value. */ + if ( (resource == XCPPROTECT_RESOURCE_PGM) || + (resource == XCPPROTECT_RESOURCE_STIM)|| + (resource == XCPPROTECT_RESOURCE_DAQ) || + (resource == XCPPROTECT_RESOURCE_CALPAG)) + { + /* 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_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[2] = resource; + cmdPacket.len = 3; + /* Send the packet. */ + if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, + xcpSettings.timeoutT1)) + { + /* Could not send packet or receive response within the specified timeout. */ + result = false; + } + /* Only continue if a response was received. */ + if (result) + { + /* Check if the response was valid. */ + if ( (resPacket.len <= 2) || (resPacket.len > xcpMaxCto) || + (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* Not a valid or positive response. */ + result = false; + } + } + /* Extract and store the seed. */ + if (result) + { + /* Make sure the seed length is valid. */ + if (resPacket.data[1] > (xcpMaxCto - 2)) + { + result = false; + } + else + { + /* 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]; + } + } + } + } + } + /* Give the result back to the caller. */ + return result; +} /*** end of XcpLoaderSendCmdGetSeed ***/ + + +/************************************************************************************//** +** \brief Sends the XCP Unlock command. +** \param key Pointer to a byte array containing the key. +** \param keyLen The length of the key in bytes. +** \param protectedResources Current resource protection status. +** \return True if successful, false otherwise. +** +****************************************************************************************/ +static bool XcpLoaderSendCmdUnlock(uint8_t const * key, uint8_t keyLen, + uint8_t * protectedResources) +{ + bool result = false; + tXcpTransportPacket cmdPacket; + tXcpTransportPacket resPacket; + + /* Make sure a valid transport layer is linked and that the parameters are valid. */ + 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 */ + { + /* 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++) + { + cmdPacket.data[idx + 2] = key[idx]; + } + cmdPacket.len = keyLen + 2; + /* Send the packet. */ + if (!xcpSettings.transport->SendPacket(&cmdPacket, &resPacket, + xcpSettings.timeoutT1)) + { + /* Could not send packet or receive response within the specified timeout. */ + result = false; + } + /* Only continue if a response was received. */ + if (result) + { + /* Check if the response was valid. */ + if ( (resPacket.len != 2) || (resPacket.data[0] != XCPLOADER_CMD_PID_RES) ) + { + /* Not a valid or positive response. */ + result = false; + } + } + /* Store the current resource protection status. */ + if (result) + { + *protectedResources = resPacket.data[1]; + } + } + /* Give the result back to the caller. */ + return result; +} /*** end of XcpLoaderSendCmdUnlock ***/ + + /************************************************************************************//** ** \brief Sends the XCP Set MTA command. ** \param address New MTA address for the slave. diff --git a/Host/Source/LibOpenBLT/xcploader.h b/Host/Source/LibOpenBLT/xcploader.h index 84b60907..52261f02 100644 --- a/Host/Source/LibOpenBLT/xcploader.h +++ b/Host/Source/LibOpenBLT/xcploader.h @@ -94,6 +94,8 @@ typedef struct t_xcp_loader_settings uint16_t timeoutT7; /** \brief Connection mode used in the XCP connect command. */ uint8_t connectMode; + /** \brief Seed/key algorithm library filename. */ + char const * seedKeyFile; /** \brief Pointer to the transport layer to use during protocol communications. */ tXcpTransport const * transport; /** \brief Pointer to the settings for the transport layer. */ diff --git a/Host/Source/LibOpenBLT/xcpprotect.h b/Host/Source/LibOpenBLT/xcpprotect.h new file mode 100644 index 00000000..b146dfa2 --- /dev/null +++ b/Host/Source/LibOpenBLT/xcpprotect.h @@ -0,0 +1,61 @@ +/************************************************************************************//** +* \file xcpprotect.h +* \brief XCP Protection module header file. +* \ingroup XcpLoader +* \internal +*---------------------------------------------------------------------------------------- +* C O P Y R I G H T +*---------------------------------------------------------------------------------------- +* Copyright (c) 2017 by Feaser http://www.feaser.com All rights reserved +* +*---------------------------------------------------------------------------------------- +* L I C E N S E +*---------------------------------------------------------------------------------------- +* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or +* modify it under the terms of the GNU General Public License as published by the Free +* Software Foundation, either version 3 of the License, or (at your option) any later +* version. +* +* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU General Public License for more details. +* +* You have received a copy of the GNU General Public License along with OpenBLT. It +* should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy. +* +* \endinternal +****************************************************************************************/ +#ifndef XCPPROTECT_H +#define XCPPROTECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************************** +* Macro definitions +****************************************************************************************/ +/* XCP supported resources. */ +#define XCPPROTECT_RESOURCE_PGM (0x10u) /**< ProGraMing resource. */ +#define XCPPROTECT_RESOURCE_STIM (0x08u) /**< data STIMulation resource. */ +#define XCPPROTECT_RESOURCE_DAQ (0x04u) /**< Data AcQuisition resource. */ +#define XCPPROTECT_RESOURCE_CALPAG (0x01u) /**< CALibration and PAGing resource. */ + + +/**************************************************************************************** +* Function prototypes +****************************************************************************************/ +void XcpProtectInit(char const * seedKeyFile); +void XcpProtectTerminate(void); +bool XCPProtectComputeKeyFromSeed(uint8_t resource, uint8_t seedLen, + uint8_t const * seedPtr, uint8_t * keyLenPtr, + uint8_t * keyPtr); +bool XcpProtectGetPrivileges(uint8_t * resourcePtr); + + +#ifdef __cplusplus +} +#endif + +#endif /* XCPPROTECT_H */ +/*********************************** end of xcpprotect.h *******************************/ diff --git a/Host/Source/LibOpenBLT/xcptpuart.c b/Host/Source/LibOpenBLT/xcptpuart.c index d66ccffb..ec3634ea 100644 --- a/Host/Source/LibOpenBLT/xcptpuart.c +++ b/Host/Source/LibOpenBLT/xcptpuart.c @@ -108,7 +108,7 @@ static void XcpTpUartInit(void const * settings) { /* Shallow copy the transport layer settings for layer usage. */ tpUartSettings = *((tXcpTpUartSettings *)settings); - /* The portname is a pointer and it is not gauranteed that it stays valid so we need + /* The portname is a pointer and it is not guaranteed that it stays valid so we need * to deep copy this one. note the +1 for '\0' in malloc. */ assert(((tXcpTpUartSettings *)settings)->portname != NULL); diff --git a/Host/Source/SeedNKey/seednkey.c b/Host/Source/SeedNKey/seednkey.c index fe9029f8..6f4894c4 100644 --- a/Host/Source/SeedNKey/seednkey.c +++ b/Host/Source/SeedNKey/seednkey.c @@ -85,7 +85,7 @@ LIBOPENBLT_EXPORT uint32_t XCP_ComputeKeyFromSeed(uint8_t resource, uint8_t seed /************************************************************************************//** -** \brief Computes the key for the requested resource. +** \brief Obtains a bitmask of the resources for which an key algorithm is available. ** \param resourcePtr pointer where to store the supported resources for the key ** computation. ** \return XCP_RESULT_OK on success, otherwise XCP_RESULT_ERROR.