MCUX CLNS
MCUX Crypto Library Normal Secure
 
Loading...
Searching...
No Matches
Security and Integration Guidance Manual

When you write software which makes calls to CLNS, please follow these integration requirements. Not following them will most likely make your software vulnerable to attacks.

Checking the correctness of return values

In general, the return values of all CLNS API functions must be checked. These checks should ideally be written in such a way that, on an assembly code level, the code for the error condition is executed by default. This means that skipping all branch instructions must lead to an error condition, which helps avoid fault injection vulnerabilities. Depending on the architecture, the compiler may generate branch instructions or conditional instructions to reach the code for the success condition. We encourage that you check this manually.

Code-flow monitoring

Most CLNS API functions monitor the code path taken internally and calculate a protection value that must be verified by the caller of the library. This can be done with e.g. the following code snippet:

#include <nxpCsslFlowProtection.h>
#include <nxpClEls.h>
int main(void)
{
/* Enable the ELS.
*
* This macro opens a new scope `{}`.
* `result` and `token` are variables which are only valid in this scope.
*
* - `result` contains the function's return value.
* - `token`, referred to in the documentation as the protection token, contains the monitored code path check value.
* Under normal circumstances, this token must be equal to the reference value `NXP_CSSL_FP_FUNCTION_CALLED(nxpClEls_WaitForOperation)`.
* If the two differ, the code path has been altered, pointing to a fault injection attack.
*/
NXP_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, nxpClEls_Enable_Async());
/* Check the protection token and result. If an attack occurred, handle it here. */
if(NXP_CSSL_FP_FUNCTION_CALLED(nxpClEls_WaitForOperation) != token || NXPCLELS_STATUS_SW_FAULT == result || NXPCLELS_STATUS_HW_FAULT == result)
{
/* Attack handling */
resetDevice();
}
/* Check the result for functional errors. */
if(NXPCLELS_STATUS_OK != result)
{
/* Error handling */
return false;
}
/* This macro closes the scope `{}`. After this point, the variables `result` and `token` are no longer visible. */
NXP_CSSL_FP_FUNCTION_CALL_END();
/* Don't forget to do the same for nxpClEls_WaitForOperation()! */
return 0;
}

In cases where the attack handling and error handling methods are identical, the two if-statements may be merged like this:

#include <nxpCsslFlowProtection.h>
#include <nxpClEls.h>
int main(void)
{
/* Enable the ELS. */
NXP_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, nxpClEls_Enable_Async());
/* Check for attacks and/or errors. */
if(NXP_CSSL_FP_FUNCTION_CALLED(nxpClEls_WaitForOperation) != token || NXPCLELS_STATUS_OK != result)
{
/* Attack and error handling */
resetDevice();
}
NXP_CSSL_FP_FUNCTION_CALL_END();
/* Don't forget to do the same for nxpClEls_WaitForOperation()! */
return 0;
}

CLNS API functions which support this feature can be identified by their declaration: if NXP_CSSL_FP_FUNCTION_DECL is part of the declaration, the function supports code flow monitoring.

The underlying monitoring functionality is provided by a library called CSSL, which is bundled together with CLNS. For details, you may want to check the CSSL documentation.

Parameter integrity protection

Some CLNS API functions use parameter integrity protection, which provides additional assurance against fault injection attacks. The first parameter of such functions has the type nxpCsslParamIntegrity_Checksum_t. In order to call these functions correctly, you must first calculate the parameter checksum. See the example below:

#include <stdint.h>
#include <nxpCsslMemory.h>
#include <nxpCsslFlowProtection.h>
#include <nxpCsslParamIntegrity.h>
int main(void) {
uint8_t arr1[33U] = {0xe4u, 0xf9u, 0x26u, 0x4cu, 0x65u, 0xe2u, 0x13u, 0xa3u, 0x9au, 0x40u, 0xd7u, 0x87u, 0xccu, 0x0bu, 0x31u, 0x18u, 0xacu, 0x55u, 0xb5u, 0x7du, 0x06u, 0x7fu, 0xceu, 0xe4u, 0xb2u, 0x7eu, 0xd5u, 0xaau, 0x90u, 0x9au, 0x42u, 0x56u, 0x76u};
/* Compare arr1 with itself. Compute the parameter checksum and pass it to the function.
* The first parameter here is the number of arguments, and is followed by the actual arguments.
*/
nxpCsslParamIntegrity_Checksum_t checksum = nxpCsslParamIntegrity_Protect(3U, arr1, arr1, sizeof(arr1));
NXP_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, nxpCsslMemory_Compare(checksum, arr1, arr1, sizeof(arr1)));
/* Check for attacks and/or errors. */
if(NXP_CSSL_FP_FUNCTION_CALLED(nxpCsslMemory_Compare) != token || NXPCSSLMEMORY_STATUS_EQUAL != result)
{
/* Attack and error handling */
return -1;
}
NXP_CSSL_FP_FUNCTION_CALL_END();
return 0;
}

Alignment of sensitive data

All sensitive data (such as private keys), including sensitive CLNS API function parameters, should be aligned on a 4-byte (or CPU word size, whichever is greater) boundary to provide some protection against side-channel analysis.

Input sanitization and preventing privilege escalation

Do not use unsanitized input to compute input values to CLNS functions.

If you integrate CLNS so that it runs at a privileged execution level and can be called from a lower privileged level, take special care that the following types of input, which are directly used as pointers by CLNS (and called at the privilege level of CLNS), are not derived in any way from unsanitized input:

  • (callback) function pointers passed to CLNS functions
  • mode pointers passed to CLNS functions (e.g. MAC, Hash or Cipher algorithms)

Otherwise privilege escalation attacks will be possible.