MCUX CLNS MCUX Crypto Library Normal Secure |

tls_master_key_session_keys.c

TLS key derivation example

/*--------------------------------------------------------------------------*/
/* Copyright 2020 NXP */
/* */
/* NXP Confidential. This software is owned or controlled by NXP and may */
/* only be used strictly in accordance with the applicable license terms. */
/* By expressly accepting such terms or by downloading, installing, */
/* activating and/or otherwise using the software, you are agreeing that */
/* you have read, and that you agree to comply with and are bound by, such */
/* license terms. If you do not agree to be bound by the applicable license */
/* terms, then you may not retain, install, activate or otherwise use the */
/* software. */
/*--------------------------------------------------------------------------*/
#include <mcuxClCss.h> // Interface to the entire mcuxClCss component
#include <mcuxClMemory.h>
#include <mcuxCsslFlowProtection.h> // Code flow protection
#include <stdbool.h> // bool type for the example's return code
static mcuxClCss_EccByte_t ecc_public_key_client[MCUXCLCSS_ECC_PUBLICKEY_SIZE];
static mcuxClCss_EccByte_t ecc_public_key_server[MCUXCLCSS_ECC_PUBLICKEY_SIZE];
static uint8_t derivation_data[MCUXCLCSS_TLS_DERIVATIONDATA_SIZE];
static uint8_t client_random[MCUXCLCSS_TLS_RANDOM_SIZE];
static uint8_t server_random[MCUXCLCSS_TLS_RANDOM_SIZE];
static uint8_t master_key_string[] = "master secret";
static uint8_t key_expansion_string[] = "key expansion";
bool tls_master_key_session_keys(
void)
{
/* Enable Css */
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Enable_Async()); // Enable the CSSv2.
// mcuxClCss_Enable_Async is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Enable_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_Enable_Async operation to complete.
// mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
/* Generate client key pair */
mcuxClCss_EccKeyGenOption_t KeyGenOptions = {0};
KeyGenOptions.bits.kgsrc = MCUXCLCSS_ECC_OUTPUTKEY_RANDOM; // Configure that a non-deterministic key is generated.
KeyGenOptions.bits.kgtypedh = MCUXCLCSS_ECC_OUTPUTKEY_KEYEXCHANGE; //Key will be used for Key Exchange
mcuxClCss_KeyProp_t GenKeyProp = {0};
GenKeyProp.bits.upprot_priv = MCUXCLCSS_KEYPROPERTY_PRIVILEGED_FALSE; // Configure that user access rights: non-privileged access
GenKeyProp.bits.upprot_sec = MCUXCLCSS_KEYPROPERTY_SECURE_TRUE; // Configure that user access rights: secure access
mcuxClCss_KeyIndex_t keyIdxPrivClient = 0u; // Set keystore index at which mcuxClCss_EccKeyGen_Async is storing the private key.
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_EccKeyGen_Async( // Perform key generation.
KeyGenOptions, // Set the prepared configuration.
(mcuxClCss_KeyIndex_t) 0U, // This parameter (signingKeyIdx) is ignored, since no signature is requested in the configuration.
keyIdxPrivClient, // Keystore index at which the generated private key is stored.
GenKeyProp, // Set the generated key properties.
NULL,
ecc_public_key_client // Output buffer, which the operation will write the public key to.
));
// mcuxClCss_EccKeyGen_Async is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_EccKeyGen_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
return false; // Expect that no error occurred, meaning that the mcuxClCss_EccKeyGen_Async operation was started.
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_LimitedWaitForOperation(0x00100000U, MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_EccKeyGen_Async operation to complete.
// mcuxClCss_LimitedWaitForOperation is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_LimitedWaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
/* Generate server key pair */
mcuxClCss_KeyIndex_t keyIdxPrivServer = 2u; // Set keystore index at which mcuxClCss_EccKeyGen_Async is storing the private key.
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_EccKeyGen_Async( // Perform key generation.
KeyGenOptions, // Set the prepared configuration.
(mcuxClCss_KeyIndex_t) 0U, // This parameter (signingKeyIdx) is ignored, since no signature is requested in the configuration.
keyIdxPrivServer, // Keystore index at which the generated private key is stored.
GenKeyProp, // Set the generated key properties.
NULL,
ecc_public_key_server // Output buffer, which the operation will write the public key to.
));
// mcuxClCss_EccKeyGen_Async is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_EccKeyGen_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
return false; // Expect that no error occurred, meaning that the mcuxClCss_EccKeyGen_Async operation was started.
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_LimitedWaitForOperation(0x00100000U, MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_EccKeyGen_Async operation to complete.
// mcuxClCss_LimitedWaitForOperation is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_LimitedWaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
//Perform Key Exchange
mcuxClCss_KeyIndex_t sharedSecretIdx = 10U; // Set shared key index
mcuxClCss_KeyProp_t SharedSecretProp = {0}; // Initialize a new configuration for the mcuxClCss_EccKeyExchange_Async generated key properties.
SharedSecretProp.bits.upprot_priv = MCUXCLCSS_KEYPROPERTY_PRIVILEGED_FALSE; // Configure that user access rights: non-privileged access
SharedSecretProp.bits.upprot_sec = MCUXCLCSS_KEYPROPERTY_SECURE_TRUE; // Configure that user access rights: secure access
SharedSecretProp.bits.utlpsms = MCUXCLCSS_KEYPROPERTY_TLS_PREMASTER_SECRET_TRUE; //Shared Secret is used as pre-master secret for TLS
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_EccKeyExchange_Async(
keyIdxPrivClient,
ecc_public_key_server,
sharedSecretIdx,
SharedSecretProp));
// mcuxClCss_EccKeyGen_Async is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_EccKeyExchange_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
return false; // Expect that no error occurred, meaning that the mcuxClCss_EccKeyExchange_Async operation was started.
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_LimitedWaitForOperation(0x00100000U, MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_EccKeyExchange_Async operation to complete.
// mcuxClCss_LimitedWaitForOperation is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_LimitedWaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
// PRNG needs to be initialized; this can be done by calling mcuxClCss_KeyDelete_Async (delete any key slot, can be empty)
// However mcuxClCss_EccKeyExchange_Async also guarantees PRNG is initialized
//generate server random
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Prng_GetRandom(server_random, 32U));
// mcuxClCss_Prng_GetRandom is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Prng_GetRandom) != token) || (MCUXCLCSS_STATUS_OK != result))
return false; // Expect that no error occurred, meaning that the mcuxClCss_Prng_GetRandom operation was started.
MCUX_CSSL_FP_FUNCTION_CALL_END();
//generate client random
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Prng_GetRandom(client_random, 32U));
// mcuxClCss_Prng_GetRandom is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Prng_GetRandom) != token) || (MCUXCLCSS_STATUS_OK != result))
return false; // Expect that no error occurred, meaning that the mcuxClCss_Prng_GetRandom operation was started.
MCUX_CSSL_FP_FUNCTION_CALL_END();
//perpare derivation data for master key
//the derivation data has a fixed length of 640 bits and is composed as follows
//"key expansion"||server random||client random||800000
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_copy(
derivation_data,
key_expansion_string,
sizeof(key_expansion_string),
sizeof(key_expansion_string)
));
// mcuxClMemory_copy is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_copy) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_copy(
derivation_data+sizeof(key_expansion_string),
server_random,
sizeof(server_random),
sizeof(server_random)
));
// mcuxClMemory_copy is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_copy) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_copy(
derivation_data+sizeof(key_expansion_string)+32U,
client_random,
sizeof(client_random),
sizeof(client_random)
));
// mcuxClMemory_set is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_copy) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_set(
derivation_data+sizeof(key_expansion_string)+32U+32U,
0x80,
1U,
1U
));
// mcuxClMemory_copy is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_set) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_set(
derivation_data+sizeof(key_expansion_string)+32U+32U+1U,
0x00,
2U,
2U
));
// mcuxClMemory_set is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_set) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
mcuxClCss_KeyProp_t tlsMasterKeyProp = {0};
tlsMasterKeyProp.bits.upprot_priv = MCUXCLCSS_KEYPROPERTY_PRIVILEGED_FALSE; // Configure that user access rights: non-privileged access
tlsMasterKeyProp.bits.upprot_sec = MCUXCLCSS_KEYPROPERTY_SECURE_TRUE; // Configure that user access rights: secure access
tlsMasterKeyProp.bits.utlsms = MCUXCLCSS_KEYPROPERTY_TLS_MASTER_SECRET_TRUE;
//Generate TLS master key
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_TlsGenerateMasterKeyFromPreMasterKey_Async(
derivation_data,
tlsMasterKeyProp,
sharedSecretIdx
));
// mcuxClCss_TlsGenerateMasterKeyFromPreMasterKey_Async is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_TlsGenerateMasterKeyFromPreMasterKey_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_LimitedWaitForOperation(0x00100000U, MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_TlsGenerateMasterKeyFromPreMasterKey_Async operation to complete.
// mcuxClCss_LimitedWaitForOperation is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_LimitedWaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
//perpare derivation data for session keys
//the derivation data has a fixed length of 640 bits and is composed as follows
//"master secret"||client random||server random||800000
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_copy(
derivation_data,
master_key_string,
sizeof(master_key_string),
sizeof(master_key_string)
));
// mcuxClMemory_copy is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_copy) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_copy(
derivation_data+sizeof(master_key_string),
client_random,
sizeof(client_random),
sizeof(client_random)
));
// mcuxClMemory_copy is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_copy) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_copy(
derivation_data+sizeof(master_key_string)+32U,
server_random,
sizeof(server_random),
sizeof(server_random)
));
// mcuxClMemory_set is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_copy) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_set(
derivation_data+sizeof(master_key_string)+32U+32U,
0x80,
1U,
1U
));
// mcuxClMemory_copy is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_set) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClMemory_set(
derivation_data+sizeof(master_key_string)+32U+32U+1U,
0x00,
2U,
2U
));
// mcuxClMemory_set is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClMemory_set) != token) || (0U != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
mcuxClCss_KeyProp_t KeyProp = {0};
mcuxClCss_GetKeyProperties(sharedSecretIdx, &KeyProp);
//Generate TLS session keys
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_TlsGenerateSessionKeysFromMasterKey_Async(
derivation_data,
GenKeyProp,
sharedSecretIdx
));
// mcuxClCss_EccKeyGen_Async is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_TlsGenerateSessionKeysFromMasterKey_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_LimitedWaitForOperation(0x00100000U, MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_TlsGenerateSessionKeysFromMasterKey_Async operation to complete.
// mcuxClCss_LimitedWaitForOperation is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_LimitedWaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
//Delete all keys from keystore
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_KeyDelete_Async(keyIdxPrivClient));
// mcuxClCss_KeyDelete_Async is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_KeyDelete_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
return false; // Expect that no error occurred, meaning that the mcuxClCss_KeyDelete_Async operation was started.
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_KeyDelete_Async operation to complete.
// mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_KeyDelete_Async(keyIdxPrivServer));
// mcuxClCss_KeyDelete_Async is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_KeyDelete_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
return false; // Expect that no error occurred, meaning that the mcuxClCss_KeyDelete_Async operation was started.
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_KeyDelete_Async operation to complete.
// mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
for(uint8_t i = sharedSecretIdx;i<sharedSecretIdx + 6;i++)
{
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_KeyDelete_Async(i));
// mcuxClCss_KeyDelete_Async is a flow-protected function: Check the protection token and the return value
if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_KeyDelete_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
return false; // Expect that no error occurred, meaning that the mcuxClCss_KeyDelete_Async operation was started.
MCUX_CSSL_FP_FUNCTION_CALL_END();
MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_KeyDelete_Async operation to complete.
// mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
return false;
MCUX_CSSL_FP_FUNCTION_CALL_END();
}
//Now the session keys are stored in the key store as follows:
//Client Mac Key : sharedSecretIdx (2-3)
//Server Mac Key : sharedSecretIdx+2 (4-5)
//Client Encryption Key : sharedSecretIdx+4 (6)
//Server Encryption Key : sharedSecretIdx+6 (7)
return true;
}