blob: ddad3ec5b95ddec3edb183cb98a6859e89863f75 [file] [log] [blame]
/*
*
* Copyright (c) 2022 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef SL_WFX_USE_SECURE_LINK
/* Includes */
#include "sl_wfx.h"
#include <stdio.h>
#include "mbedtls/ccm.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/entropy.h"
#include "mbedtls/md.h"
#include "mbedtls/sha256.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "semphr.h"
#include "task.h"
// Secure link MAC key location for WGM160P (in DI page in flash)
#ifdef EFM32GG11B820F2048GM64 // WGM160PX22KGA2
#define SL_WFX_FCCC_BASE_ADDR ((void *) 0x0fe08000ul)
#define SL_WFX_FCCC_DI_OFFSET 0x1B0ul
#define SL_WFX_FCCC_DI_ADDR ((void *) (SL_WFX_FCCC_BASE_ADDR + SL_WFX_FCCC_DI_OFFSET))
#define SL_WFX_SECURE_LINK_MAC_KEY_LOCATION ((void *) (SL_WFX_FCCC_BASE_ADDR + 0x3D0))
#endif
/******************************************************
* Macros
******************************************************/
#define MAC_KEY_FAIL_BYTE 0XFF
#define KEY_DIGEST_SIZE 92
#define MEMCMP_FAIL 0
#define MPI_SET 1
#define SUCCESS_STATUS_WIFI_SECURE_LINK_EXCHANGE 0
#define SHA224_0 0
#define HMAC_SIZE 92
#define MEMSET_LEN 1
#define LABLE_LEN 24
#define ADDRESS_LENGTH 0
#define CCM_STATUS_SUCCESS 0
/******************************************************
* Constants
******************************************************/
/* Semaphore to signal wfx driver available */
extern TaskHandle_t wfx_securelink_task;
extern SemaphoreHandle_t wfx_securelink_rx_mutex;
/******************************************************
* Enumerations
******************************************************/
/******************************************************
* Type Definitions
******************************************************/
/******************************************************
* Structures
******************************************************/
/******************************************************
* Function Declarations
******************************************************/
static inline void reverse_bytes(uint8_t * src, uint8_t length);
/******************************************************
* Variable Definitions
******************************************************/
#if SL_WFX_SLK_CURVE25519
static mbedtls_ecdh_context mbedtls_host_context;
static mbedtls_ctr_drbg_context host_drbg_context;
#endif
static mbedtls_entropy_context entropy;
uint8_t temp_key_location[SL_WFX_HOST_PUB_KEY_MAC_SIZE];
#ifdef EFM32GG11B820F2048GM64 // WGM160PX22KGA2
static const uint8_t * const secure_link_mac_key = (uint8_t *) SL_WFX_SECURE_LINK_MAC_KEY_LOCATION;
#else
static const uint8_t secure_link_mac_key[SL_WFX_SECURE_LINK_MAC_KEY_LENGTH] = { 0x2B, 0x49, 0xFD, 0x66, 0xCB, 0x74, 0x6D, 0x6B,
0x4F, 0xDC, 0xC3, 0x79, 0x4E, 0xC5, 0x9A, 0x86,
0xE5, 0x48, 0x2A, 0x41, 0x22, 0x87, 0x8B, 0x12,
0x1A, 0x7C, 0x3E, 0xEF, 0xB7, 0x04, 0x9E, 0xB3 };
#endif
/******************************************************
* Function Definitions
******************************************************/
/****************************************************************************
* @fn sl_status_t sl_wfx_host_get_secure_link_mac_key(uint8_t *sl_mac_key)
* @brief
* Get secure link mac key
* @param[in] sl_mac_key:
* @return returns SL_STATUS_OK
*****************************************************************************/
sl_status_t sl_wfx_host_get_secure_link_mac_key(uint8_t * sl_mac_key)
{
sl_status_t result = SL_STATUS_WIFI_SECURE_LINK_MAC_KEY_ERROR;
memcpy(sl_mac_key, secure_link_mac_key, SL_WFX_SECURE_LINK_MAC_KEY_LENGTH);
for (uint8_t index = 0; index < SL_WFX_SECURE_LINK_MAC_KEY_LENGTH; ++index)
{
// Assuming 0xFF... when not written
if (sl_mac_key[index] != MAC_KEY_FAIL_BYTE)
{
result = SL_STATUS_OK;
break;
}
}
return result;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_compute_pub_key(sl_wfx_securelink_exchange_pub_keys_req_body_t *request,
const uint8_t *sl_mac_key)
* @brief
* compute host public key
* @param[in] request :
* @param[in] sl_mac_key :
* @return returns SL_STATUS_OK
*****************************************************************************/
sl_status_t sl_wfx_host_compute_pub_key(sl_wfx_securelink_exchange_pub_keys_req_body_t * request, const uint8_t * sl_mac_key)
{
sl_status_t status = SL_STATUS_OK;
#if SL_WFX_SLK_CURVE25519
const char identifier[] = "ecdh";
mbedtls_ecdh_init(&mbedtls_host_context);
mbedtls_ctr_drbg_init(&host_drbg_context);
mbedtls_entropy_init(&entropy);
status = mbedtls_ctr_drbg_seed(&host_drbg_context, mbedtls_entropy_func, &entropy, (const unsigned char *) identifier,
sizeof(identifier));
status += mbedtls_ecp_group_load(&mbedtls_host_context.grp, MBEDTLS_ECP_DP_CURVE25519);
status += mbedtls_ecdh_gen_public(&mbedtls_host_context.grp, &mbedtls_host_context.d, &mbedtls_host_context.Q,
mbedtls_ctr_drbg_random, &host_drbg_context);
status += mbedtls_mpi_write_binary(&mbedtls_host_context.Q.X, request->host_pub_key, SL_WFX_HOST_PUB_KEY_SIZE);
#else
mbedtls_entropy_init(&entropy);
status = mbedtls_entropy_func(&entropy, request->host_pub_key, SL_WFX_HOST_PUB_KEY_SIZE);
#endif
reverse_bytes(request->host_pub_key, SL_WFX_HOST_PUB_KEY_SIZE);
SL_WFX_ERROR_CHECK(status);
// Generate SHA512 digest of public key
status = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), sl_mac_key, SL_WFX_HOST_PUB_KEY_SIZE,
request->host_pub_key, SL_WFX_HOST_PUB_KEY_SIZE, request->host_pub_key_mac);
SL_WFX_ERROR_CHECK(status);
error_handler:
if (status != SL_STATUS_OK)
{
return SL_STATUS_WIFI_SECURE_LINK_EXCHANGE_FAILED;
}
return status;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_verify_pub_key(sl_wfx_securelink_exchange_pub_keys_ind_t *response_packet,
const uint8_t *sl_mac_key,
uint8_t *sl_host_pub_key)
* @brief
* verify host public key
* @param[in] response_packet:
* @param[in] sl_mac_key:
* @param[in] sl_host_pub_key:
* @return returns SL_STATUS_OK if successful,
* SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_verify_pub_key(sl_wfx_securelink_exchange_pub_keys_ind_t * response_packet, const uint8_t * sl_mac_key,
uint8_t * sl_host_pub_key)
{
sl_status_t status = SL_STATUS_OK;
uint8_t shared_key_digest[KEY_DIGEST_SIZE];
if (xSemaphoreTake(wfx_securelink_rx_mutex, portMAX_DELAY) != pdTRUE)
{
return SL_STATUS_WIFI_SECURE_LINK_EXCHANGE_FAILED;
}
// Compute the Hash and verify the public key/hashing
status = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), sl_mac_key, SL_WFX_NCP_PUB_KEY_SIZE,
response_packet->body.ncp_pub_key, SL_WFX_NCP_PUB_KEY_SIZE, temp_key_location);
SL_WFX_ERROR_CHECK(status);
// Calculate session key if public key/SHA512 digest matches
if (memcmp(temp_key_location, response_packet->body.ncp_pub_key_mac, SL_WFX_HOST_PUB_KEY_MAC_SIZE) != MEMCMP_FAIL)
{
status = SL_STATUS_WIFI_SECURE_LINK_EXCHANGE_FAILED;
goto error_handler;
}
#if SL_WFX_SLK_CURVE25519
SL_WFX_UNUSED_PARAMETER(sl_host_pub_key);
mbedtls_mpi_lset(&mbedtls_host_context.Qp.Z, MPI_SET);
// Read Ineo public key
reverse_bytes(response_packet->body.ncp_pub_key, SL_WFX_NCP_PUB_KEY_SIZE);
mbedtls_mpi_read_binary(&mbedtls_host_context.Qp.X, response_packet->body.ncp_pub_key, SL_WFX_NCP_PUB_KEY_SIZE);
// Calculate shared secret
if (mbedtls_ecdh_compute_shared(&mbedtls_host_context.grp, &mbedtls_host_context.z, &mbedtls_host_context.Qp,
&mbedtls_host_context.d, mbedtls_ctr_drbg_random,
&host_drbg_context) != SUCCESS_STATUS_WIFI_SECURE_LINK_EXCHANGE)
{
status = SL_STATUS_WIFI_SECURE_LINK_EXCHANGE_FAILED;
goto error_handler;
}
// Generate session key
mbedtls_mpi_write_binary(&mbedtls_host_context.z, temp_key_location, SL_WFX_HOST_PUB_KEY_SIZE);
reverse_bytes(temp_key_location, SL_WFX_HOST_PUB_KEY_SIZE);
mbedtls_sha256(temp_key_location, SL_WFX_HOST_PUB_KEY_SIZE, shared_key_digest, SHA224_0);
#else
uint8_t hmac_input[HMAC_SIZE] = { 0 };
char label[LABLE_LEN] = "SecureLink!KeyDerivation";
memset((uint16_t *) &hmac_input[0], (uint16_t) sl_wfx_htole16(1), MEMSET_LEN);
memcpy((uint8_t *) &hmac_input[2], (uint8_t *) label, LABLE_LEN);
memcpy((uint8_t *) &hmac_input[26], sl_host_pub_key, SL_WFX_NCP_PUB_KEY_SIZE);
memcpy((uint8_t *) &hmac_input[58], (uint8_t *) response_packet->body.ncp_pub_key, SL_WFX_NCP_PUB_KEY_SIZE);
memset((uint16_t *) &hmac_input[90], (uint16_t) sl_wfx_htole16(128), 1);
// Generate SHA256 digest of hmac_input
status = mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), sl_mac_key, SL_WFX_HOST_PUB_KEY_SIZE,
(uint8_t *) hmac_input, HMAC_SIZE, shared_key_digest);
#endif
memcpy(sl_wfx_context->secure_link_session_key, shared_key_digest,
SL_WFX_SECURE_LINK_SESSION_KEY_LENGTH); // Use the lower 16 bytes of the sha256
sl_wfx_context->secure_link_nonce.hp_packet_count = 0;
sl_wfx_context->secure_link_nonce.rx_packet_count = 0;
sl_wfx_context->secure_link_nonce.tx_packet_count = 0;
error_handler:
if (xSemaphoreGive(wfx_securelink_rx_mutex) != pdTRUE)
{
printf("ERROR: sl_wfx_securelink_rx_mutex. unable to post.\n");
}
return status;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_free_crypto_context(void)
* @brief
* Free host crypto context
* @param[in] None
* @return returns SL_STATUS_OK
*****************************************************************************/
sl_status_t sl_wfx_host_free_crypto_context(void)
{
#if SL_WFX_SLK_CURVE25519
mbedtls_ecdh_free(&mbedtls_host_context);
mbedtls_ctr_drbg_free(&host_drbg_context);
#endif
mbedtls_entropy_free(&entropy);
return SL_STATUS_OK;
}
/********************************************************************************
* @fn sl_status_t sl_wfx_host_decode_secure_link_data(uint8_t *buffer, uint32_t length, uint8_t *session_key)
* @brief
* Decode receive data
* Length excludes size of CCM tag and secure link header
* @param[in] buffer:
* @param[in] length:
* @param[in] session_key:
* @return returns SL_STATUS_OK if successful,
* SL_STATUS_FAIL otherwise
********************************************************************************/
sl_status_t sl_wfx_host_decode_secure_link_data(uint8_t * buffer, uint32_t length, uint8_t * session_key)
{
mbedtls_ccm_context ccm_context;
sl_status_t status = SL_STATUS_SECURITY_DECRYPT_ERROR;
int crypto_status;
sl_wfx_nonce_t nonce = { 0, 0, 0 };
if (xSemaphoreTake(wfx_securelink_rx_mutex, portMAX_DELAY) != pdTRUE)
{
return SL_STATUS_FAIL;
}
// Nonce for decryption should have TX and HP counters 0, only use RX counter
nonce.rx_packet_count = sl_wfx_context->secure_link_nonce.rx_packet_count;
// Init context
mbedtls_ccm_init(&ccm_context);
// Set the crypto key
crypto_status = mbedtls_ccm_setkey(&ccm_context, MBEDTLS_CIPHER_ID_AES, session_key, SL_WFX_SECURE_LINK_SESSION_KEY_BIT_COUNT);
SL_WFX_ERROR_CHECK(crypto_status);
// Decrypt the data
if (!mbedtls_ccm_auth_decrypt(&ccm_context, length, (uint8_t *) &nonce, SL_WFX_SECURE_LINK_NONCE_SIZE_BYTES, NULL,
ADDRESS_LENGTH, (uint8_t *) buffer, (uint8_t *) buffer, (uint8_t *) buffer + length,
SL_WFX_SECURE_LINK_CCM_TAG_SIZE))
{
status = SL_STATUS_OK;
}
error_handler:
mbedtls_ccm_free(&ccm_context);
if (xSemaphoreGive(wfx_securelink_rx_mutex) != pdTRUE)
{
printf("ERROR: sl_wfx_securelink_rx_mutex. unable to post.\n");
}
return status;
}
/*********************************************************************
* @fn sl_status_t sl_wfx_host_encode_secure_link_data(sl_wfx_generic_message_t *buffer,
uint32_t data_length,
uint8_t *session_key,
uint8_t *nonce)
* @brief
* Encode transmit data
* Length excludes size of CCM tag and secure link header
* @param[in] buffer:
* @param[in] data_length:
* @param[in] session_key:
* @param[in] nonce:
* @return returns SL_STATUS_OK if successful,
* SL_STATUS_FAIL otherwise
*************************************************************************/
sl_status_t sl_wfx_host_encode_secure_link_data(sl_wfx_generic_message_t * buffer, uint32_t data_length, uint8_t * session_key,
uint8_t * nonce)
{
mbedtls_ccm_context ccm_context;
sl_status_t status = SL_STATUS_FAIL;
mbedtls_ccm_init(&ccm_context);
if (mbedtls_ccm_setkey(&ccm_context, MBEDTLS_CIPHER_ID_AES, session_key, SL_WFX_SECURE_LINK_SESSION_KEY_BIT_COUNT) ==
CCM_STATUS_SUCCESS)
{
mbedtls_ccm_encrypt_and_tag(&ccm_context, data_length, nonce, SL_WFX_SECURE_LINK_NONCE_SIZE_BYTES, NULL, ADDRESS_LENGTH,
(uint8_t *) &buffer->header.id, (uint8_t *) &buffer->header.id,
(uint8_t *) &buffer->header.id + data_length, SL_WFX_SECURE_LINK_CCM_TAG_SIZE);
status = SL_STATUS_OK;
}
mbedtls_ccm_free(&ccm_context);
return status;
}
/****************************************************************************
* @fn sl_status_t sl_wfx_host_schedule_secure_link_renegotiation(void)
* @brief
* Called when the driver needs to schedule secure link renegotiation
* @param[in] None
* @returns Returns SL_STATUS_OK if successful,
* SL_STATUS_FAIL otherwise
*****************************************************************************/
sl_status_t sl_wfx_host_schedule_secure_link_renegotiation(void)
{
// call sl_wfx_secure_link_renegotiate_session_key() as soon as it makes sense for the host to do so
xTaskNotifyGive(wfx_securelink_task);
return SL_STATUS_OK;
}
/****************************************************************************
* @fn static inline void reverse_bytes(uint8_t *src, uint8_t length)
* @brief
* reverse the bytes
* @param[in] src: source
* @param[in] length:
* @returns None
*****************************************************************************/
static inline void reverse_bytes(uint8_t * src, uint8_t length)
{
uint8_t * lo = src;
uint8_t * hi = src + length - 1;
uint8_t swap;
while (lo < hi)
{
swap = *lo;
*lo++ = *hi;
*hi-- = swap;
}
}
/********************************************************************************************************
********************************************************************************************************
* DEPENDENCIES & AVAIL CHECK(S)
********************************************************************************************************
*******************************************************************************************************/
#endif // SL_WFX_USE_SECURE_LINK