feat(mbedtls): fix build errors with PSA migration

This commit is contained in:
Ashish Sharma
2025-12-18 21:18:58 +08:00
parent b0da66f7e1
commit a088d2ccdc
72 changed files with 1032 additions and 804 deletions
+77 -85
View File
@@ -66,27 +66,21 @@ typedef struct session {
uint8_t sym_key[PUBLIC_KEY_LEN];
uint8_t rand[SZ_RANDOM];
/* Operation counter for CTR mode nonce */
uint32_t op_counter;
/* mbedtls context data for AES */
psa_cipher_operation_t ctx_aes;
psa_key_id_t key_id;
psa_key_id_t key_id_sym;
unsigned char stb[16];
size_t nc_off;
} session_t;
static void flip_endian(uint8_t *data, size_t len)
{
uint8_t swp_buf;
for (int i = 0; i < len/2; i++) {
swp_buf = data[i];
data[i] = data[len - i - 1];
data[len - i - 1] = swp_buf;
}
}
static void hexdump(const char *msg, uint8_t *buf, int len)
{
ESP_LOGD(TAG, "%s:", msg);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, buf, len, ESP_LOG_DEBUG);
ESP_LOGI(TAG, "%s:", msg);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, buf, len, ESP_LOG_INFO);
}
static esp_err_t handle_session_command1(session_t *cur_session,
@@ -95,8 +89,6 @@ static esp_err_t handle_session_command1(session_t *cur_session,
{
ESP_LOGD(TAG, "Request to handle setup1_command");
Sec1Payload *in = (Sec1Payload *) req->sec1;
uint8_t check_buf[PUBLIC_KEY_LEN];
// int mbed_err;
if (cur_session->state != SESSION_STATE_CMD1) {
ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD1, cur_session->state);
@@ -106,46 +98,66 @@ static esp_err_t handle_session_command1(session_t *cur_session,
/* Initialize crypto context */
memset(cur_session->stb, 0, sizeof(cur_session->stb));
cur_session->nc_off = 0;
cur_session->op_counter = 0;
hexdump("Client verifier", in->sc1->client_verify_data.data,
hexdump("Data to decrypt", in->sc1->client_verify_data.data,
in->sc1->client_verify_data.len);
hexdump("Symmetric key:", cur_session->sym_key, sizeof(cur_session->sym_key));
hexdump("Client rand", cur_session->rand,
sizeof(cur_session->rand));
psa_status_t status;
psa_key_id_t key_id = 0;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_algorithm_t alg = PSA_ALG_CTR;
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT);
psa_set_key_algorithm(&key_attributes, alg);
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&key_attributes, 128);
psa_set_key_bits(&key_attributes, sizeof(cur_session->sym_key) * 8);
status = psa_import_key(&key_attributes, cur_session->sym_key, sizeof(cur_session->sym_key), &key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_import_key failed with status=%d", status);
return ESP_FAIL;
}
cur_session->key_id_sym = key_id;
psa_reset_key_attributes(&key_attributes);
size_t output_len = 0;
size_t cipher_size = PSA_CIPHER_DECRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, alg, in->sc1->client_verify_data.len);
uint8_t check_buf[cipher_size];
cur_session->ctx_aes = psa_cipher_operation_init();
status = psa_cipher_encrypt_setup(&cur_session->ctx_aes, key_id, alg);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_cipher_encrypt_setup failed with status=%d", status);
psa_destroy_key(key_id);
return ESP_FAIL;
}
size_t output_len = 0;
status = psa_cipher_encrypt(key_id, alg, in->sc1->client_verify_data.data,
in->sc1->client_verify_data.len, check_buf, sizeof(check_buf), &output_len);
if (status != PSA_SUCCESS || output_len != sizeof(check_buf)) {
ESP_LOGE(TAG, "psa_cipher_encrypt failed with status=%d", status);
psa_cipher_abort(&cur_session->ctx_aes);
psa_destroy_key(key_id);
return ESP_FAIL;
}
status = psa_cipher_set_iv(&cur_session->ctx_aes, cur_session->rand, sizeof(cur_session->rand));
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_cipher_set_iv failed with status=%d", status);
psa_cipher_abort(&cur_session->ctx_aes);
psa_destroy_key(key_id);
return ESP_FAIL;
}
status = psa_cipher_update(&cur_session->ctx_aes, in->sc1->client_verify_data.data,
in->sc1->client_verify_data.len, check_buf, sizeof(check_buf), &output_len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_cipher_update failed with status=%d", status);
psa_cipher_abort(&cur_session->ctx_aes);
psa_destroy_key(key_id);
return ESP_FAIL;
}
hexdump("Dec Client verifier", check_buf, sizeof(check_buf));
hexdump("Device pubkey", cur_session->device_pubkey, sizeof(cur_session->device_pubkey));
/* constant time memcmp */
if (mbedtls_ct_memcmp(check_buf, cur_session->device_pubkey,
sizeof(cur_session->device_pubkey)) != 0) {
ESP_LOGE(TAG, "Key mismatch. Close connection");
psa_cipher_abort(&cur_session->ctx_aes);
psa_destroy_key(key_id);
if (esp_event_post(PROTOCOMM_SECURITY_SESSION_EVENT, PROTOCOMM_SECURITY_SESSION_CREDENTIALS_MISMATCH, NULL, 0, portMAX_DELAY) != ESP_OK) {
ESP_LOGE(TAG, "Failed to post credential mismatch event");
@@ -174,15 +186,11 @@ static esp_err_t handle_session_command1(session_t *cur_session,
return ESP_ERR_NO_MEM;
}
status = psa_cipher_encrypt(key_id, alg, cur_session->client_pubkey,
PUBLIC_KEY_LEN, outbuf, PUBLIC_KEY_LEN, &output_len);
if (status != PSA_SUCCESS || output_len != PUBLIC_KEY_LEN) {
ESP_LOGE(TAG, "psa_cipher_encrypt failed with status=%d", status);
size_t outlen = 0;
status = psa_cipher_update(&cur_session->ctx_aes, cur_session->client_pubkey, sizeof(cur_session->client_pubkey), outbuf, PUBLIC_KEY_LEN, &outlen);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed at psa_cipher_update with error code : %d", status);
free(outbuf);
free(out);
free(out_resp);
psa_cipher_abort(&cur_session->ctx_aes);
psa_destroy_key(key_id);
return ESP_FAIL;
}
@@ -202,7 +210,7 @@ static esp_err_t handle_session_command1(session_t *cur_session,
ESP_LOGE(TAG, "Failed to post secure session setup success event");
}
ESP_LOGD(TAG, "Secure session established successfully");
ESP_LOGI(TAG, "Secure session established successfully");
return ESP_OK;
}
@@ -231,22 +239,11 @@ static esp_err_t handle_session_command0(session_t *cur_session,
return ESP_ERR_INVALID_ARG;
}
mbedtls_ecdh_context *ctx_server = malloc(sizeof(mbedtls_ecdh_context));
mbedtls_entropy_context *entropy = malloc(sizeof(mbedtls_entropy_context));
mbedtls_ctr_drbg_context *ctr_drbg = malloc(sizeof(mbedtls_ctr_drbg_context));
if (!ctx_server || !entropy || !ctr_drbg) {
ESP_LOGE(TAG, "Failed to allocate memory for mbedtls context");
free(ctx_server);
free(entropy);
free(ctr_drbg);
return ESP_ERR_NO_MEM;
}
psa_status_t status;
psa_key_id_t key_id = 0;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY));
psa_set_key_bits(&key_attributes, 256);
psa_set_key_bits(&key_attributes, 255);
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDH);
@@ -259,7 +256,12 @@ static esp_err_t handle_session_command0(session_t *cur_session,
psa_reset_key_attributes(&key_attributes);
size_t olen = 0;
flip_endian(cur_session->device_pubkey, PUBLIC_KEY_LEN);
status = psa_export_public_key(key_id, cur_session->device_pubkey, PUBLIC_KEY_LEN, &olen);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_export_public_key failed with status=%d", status);
psa_reset_key_attributes(&key_attributes);
return ESP_FAIL;
}
memcpy(cur_session->client_pubkey, in->sc0->client_pubkey.data, PUBLIC_KEY_LEN);
@@ -283,43 +285,33 @@ static esp_err_t handle_session_command0(session_t *cur_session,
}
cur_session->key_id = key_id;
flip_endian(cur_session->sym_key, PUBLIC_KEY_LEN);
if (pop != NULL && pop->data != NULL && pop->len != 0) {
ESP_LOGD(TAG, "Adding proof of possession");
uint8_t sha_out[PUBLIC_KEY_LEN];
// mbed_err = mbedtls_sha256((const unsigned char *) pop->data, pop->len, sha_out, 0);
// if (mbed_err != 0) {
// ESP_LOGE(TAG, "Failed at mbedtls_sha256_ret with error code : -0x%x", -mbed_err);
// ret = ESP_FAIL;
// goto exit_cmd0;
// }
psa_mac_operation_t mac_operation = PSA_MAC_OPERATION_INIT;
status = psa_mac_sign_setup(&mac_operation, key_id, PSA_ALG_SHA_256);
psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
status = psa_hash_setup(&hash_operation, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_mac_sign_setup failed with status=%d", status);
ESP_LOGE(TAG, "psa_hash_setup failed with status=%d", status);
ret = ESP_FAIL;
goto exit_cmd0;
}
status = psa_mac_update(&mac_operation, pop->data, pop->len);
status = psa_hash_update(&hash_operation, pop->data, pop->len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_mac_update failed with status=%d", status);
psa_mac_abort(&mac_operation);
ESP_LOGE(TAG, "psa_hash_update failed with status=%d", status);
psa_hash_abort(&hash_operation);
ret = ESP_FAIL;
goto exit_cmd0;
}
status = psa_mac_sign_finish(&mac_operation, sha_out, sizeof(sha_out), &olen);
status = psa_hash_finish(&hash_operation, sha_out, sizeof(sha_out), &olen);
if (status != PSA_SUCCESS || olen != sizeof(sha_out)) {
ESP_LOGE(TAG, "psa_mac_sign_finish failed with status=%d", status);
psa_mac_abort(&mac_operation);
ESP_LOGE(TAG, "psa_hash_finish failed with status=%d", status);
psa_hash_abort(&hash_operation);
ret = ESP_FAIL;
goto exit_cmd0;
}
for (int i = 0; i < PUBLIC_KEY_LEN; i++) {
cur_session->sym_key[i] ^= sha_out[i];
}
@@ -366,7 +358,7 @@ static esp_err_t handle_session_command0(session_t *cur_session,
cur_session->state = SESSION_STATE_CMD1;
ESP_LOGD(TAG, "Session setup phase1 done");
ESP_LOGI(TAG, "Session setup phase1 done");
ret = ESP_OK;
exit_cmd0:
@@ -449,20 +441,24 @@ static esp_err_t sec1_close_session(protocomm_security_handle_t handle, uint32_t
return ESP_ERR_INVALID_STATE;
}
if (cur_session->state == SESSION_STATE_DONE) {
// if (cur_session->state == SESSION_STATE_DONE) {
/* Free AES context data */
// mbedtls_aes_free(&cur_session->ctx_aes);
psa_status_t status = psa_destroy_key(cur_session->id);
psa_status_t status = psa_destroy_key(cur_session->key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_destroy_key failed with status=%d", status);
return ESP_FAIL;
// return ESP_FAIL;
}
status = psa_destroy_key(cur_session->key_id_sym);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_destroy_key failed with status=%d", status);
// return ESP_FAIL;
}
status = psa_cipher_abort(&cur_session->ctx_aes);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_cipher_abort failed with status=%d", status);
return ESP_FAIL;
// return ESP_FAIL;
}
}
// }
memset(cur_session, 0, sizeof(session_t));
cur_session->id = -1;
@@ -511,7 +507,7 @@ static esp_err_t sec1_cleanup(protocomm_security_handle_t handle)
return ESP_OK;
}
static esp_err_t sec1_decrypt(protocomm_security_handle_t handle,
static esp_err_t sec1_crypt(protocomm_security_handle_t handle,
uint32_t session_id,
const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen)
@@ -538,17 +534,13 @@ static esp_err_t sec1_decrypt(protocomm_security_handle_t handle,
return ESP_ERR_NO_MEM;
}
psa_status_t status;
size_t output_len = 0;
psa_algorithm_t alg = PSA_ALG_CTR;
status = psa_cipher_decrypt(cur_session->key_id, alg, inbuf, inlen, *outbuf, *outlen, &output_len);
if (status != PSA_SUCCESS || output_len != *outlen) {
ESP_LOGE(TAG, "psa_cipher_decrypt failed with status=%d", status);
size_t out_len = 0;
psa_status_t status = psa_cipher_update(&cur_session->ctx_aes, inbuf, inlen, *outbuf, *outlen, &out_len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_cipher_update failed with status=%d", status);
free(*outbuf);
return ESP_FAIL;
}
return ESP_OK;
}
@@ -615,6 +607,6 @@ const protocomm_security_t protocomm_security1 = {
.new_transport_session = sec1_new_session,
.close_transport_session = sec1_close_session,
.security_req_handler = sec1_req_handler,
.encrypt = sec1_decrypt, /* Encrypt == decrypt for AES-CTR */
.decrypt = sec1_decrypt,
.encrypt = sec1_crypt, /* Encrypt == decrypt for AES-CTR */
.decrypt = sec1_crypt,
};
+24 -24
View File
@@ -21,36 +21,36 @@
/* setUp runs before every test */
void setUp(void)
{
#if SOC_SHA_SUPPORTED
// Execute esp_sha operation to allocate internal SHA semaphore (in case of ESP32)
// and initial DMA setup memory which is considered as leaked otherwise
const uint8_t input_buffer[64] = {0};
uint8_t output_buffer[64];
#if SOC_SHA_SUPPORT_SHA256
esp_sha(SHA2_256, input_buffer, sizeof(input_buffer), output_buffer);
#endif // SOC_SHA_SUPPORT_SHA256
#if SOC_SHA_SUPPORT_SHA512
esp_sha(SHA2_512, input_buffer, sizeof(input_buffer), output_buffer);
#endif // SOC_SHA_SUPPORT_SHA512
#endif // SOC_SHA_SUPPORTED
// #if SOC_SHA_SUPPORTED
// // Execute esp_sha operation to allocate internal SHA semaphore (in case of ESP32)
// // and initial DMA setup memory which is considered as leaked otherwise
// const uint8_t input_buffer[64] = {0};
// uint8_t output_buffer[64];
// #if SOC_SHA_SUPPORT_SHA256
// esp_sha(SHA2_256, input_buffer, sizeof(input_buffer), output_buffer);
// #endif // SOC_SHA_SUPPORT_SHA256
// #if SOC_SHA_SUPPORT_SHA512
// esp_sha(SHA2_512, input_buffer, sizeof(input_buffer), output_buffer);
// #endif // SOC_SHA_SUPPORT_SHA512
// #endif // SOC_SHA_SUPPORTED
#if defined(CONFIG_MBEDTLS_HARDWARE_MPI)
esp_mpi_enable_hardware_hw_op();
esp_mpi_disable_hardware_hw_op();
#endif // CONFIG_MBEDTLS_HARDWARE_MPI
#if SOC_AES_SUPPORTED
// Execute mbedtls_aes_init operation to allocate AES interrupt
// allocation memory which is considered as leak otherwise
const uint8_t plaintext[16] = {0};
uint8_t ciphertext[16];
const uint8_t key[16] = { 0 };
mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, key, 128);
mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, ciphertext);
mbedtls_aes_free(&ctx);
#endif // SOC_AES_SUPPORTED
// #if SOC_AES_SUPPORTED
// // Execute mbedtls_aes_init operation to allocate AES interrupt
// // allocation memory which is considered as leak otherwise
// const uint8_t plaintext[16] = {0};
// uint8_t ciphertext[16];
// const uint8_t key[16] = { 0 };
// mbedtls_aes_context ctx;
// mbedtls_aes_init(&ctx);
// mbedtls_aes_setkey_enc(&ctx, key, 128);
// mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, ciphertext);
// mbedtls_aes_free(&ctx);
// #endif // SOC_AES_SUPPORTED
test_utils_record_free_mem();
TEST_ESP_OK(test_utils_set_leak_level(0, ESP_LEAK_TYPE_CRITICAL, ESP_COMP_LEAK_GENERAL));
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "psa/crypto_struct.h"
#include "psa/crypto_types.h"
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
@@ -28,13 +30,14 @@
#define ACCESS_ECDH(S, var) S.MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(var)
#endif
#define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS
#include <mbedtls/aes.h>
#include <mbedtls/sha256.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecdh.h>
#include <mbedtls/error.h>
#include "psa/crypto.h"
#include <protocomm.h>
#include <protocomm_security.h>
#include <protocomm_security0.h>
@@ -62,15 +65,15 @@ typedef struct {
uint8_t sym_key[PUBLIC_KEY_LEN];
uint8_t rand[SZ_RANDOM];
/* mbedtls context data for Curve25519 */
mbedtls_ecdh_context ctx_client;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
/* mbedtls context data for AES */
mbedtls_aes_context ctx_aes;
psa_cipher_operation_t ctx_aes;
psa_key_id_t client_key_id;
psa_key_id_t key_id;
unsigned char stb[16];
size_t nc_off;
/* Operation counter for CTR mode nonce */
uint32_t op_counter;
} session_t;
static const char *TAG = "protocomm_test";
@@ -80,16 +83,6 @@ static const protocomm_security_t *test_sec = NULL;
protocomm_security_handle_t sec_inst = NULL;
static uint32_t test_priv_data = 1234;
static void flip_endian(uint8_t *data, size_t len)
{
uint8_t swp_buf;
for (int i = 0; i < len/2; i++) {
swp_buf = data[i];
data[i] = data[len - i - 1];
data[len - i - 1] = swp_buf;
}
}
static void hexdump(const char *msg, uint8_t *buf, int len)
{
ESP_LOGI(TAG, "%s:", msg);
@@ -142,7 +135,6 @@ static esp_err_t verify_response0(session_t *session, SessionData *resp)
return ESP_ERR_INVALID_ARG;
}
int ret;
Sec1Payload *in = (Sec1Payload *) resp->sec1;
if (in->sr0->device_pubkey.len != PUBLIC_KEY_LEN) {
@@ -159,50 +151,42 @@ static esp_err_t verify_response0(session_t *session, SessionData *resp)
uint8_t *dev_pubkey = session->device_pubkey;
memcpy(session->device_pubkey, in->sr0->device_pubkey.data, in->sr0->device_pubkey.len);
hexdump("Device pubkey", dev_pubkey, PUBLIC_KEY_LEN);
hexdump("Client pubkey", cli_pubkey, PUBLIC_KEY_LEN);
hexdump("Device pubkey0", dev_pubkey, PUBLIC_KEY_LEN);
hexdump("Client pubkey0", cli_pubkey, PUBLIC_KEY_LEN);
ret = mbedtls_mpi_lset(ACCESS_ECDH(&session->ctx_client, Qp).MBEDTLS_PRIVATE(Z), 1);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_mpi_lset with error code : %d", ret);
size_t olen = 0;
psa_status_t status = psa_raw_key_agreement(
PSA_ALG_ECDH, session->client_key_id, dev_pubkey,
PUBLIC_KEY_LEN, session->sym_key, sizeof(session->sym_key), &olen);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed at psa_raw_key_agreement with error code : %d", status);
return ESP_FAIL;
}
flip_endian(session->device_pubkey, PUBLIC_KEY_LEN);
ret = mbedtls_mpi_read_binary(ACCESS_ECDH(&session->ctx_client, Qp).MBEDTLS_PRIVATE(X), dev_pubkey, PUBLIC_KEY_LEN);
flip_endian(session->device_pubkey, PUBLIC_KEY_LEN);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_mpi_read_binary with error code : %d", ret);
return ESP_FAIL;
}
ret = mbedtls_ecdh_compute_shared(ACCESS_ECDH(&session->ctx_client, grp),
ACCESS_ECDH(&session->ctx_client, z),
ACCESS_ECDH(&session->ctx_client, Qp),
ACCESS_ECDH(&session->ctx_client, d),
mbedtls_ctr_drbg_random,
&session->ctr_drbg);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_ecdh_compute_shared with error code : %d", ret);
return ESP_FAIL;
}
ret = mbedtls_mpi_write_binary(ACCESS_ECDH(&session->ctx_client, z), session->sym_key, PUBLIC_KEY_LEN);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_mpi_write_binary with error code : %d", ret);
return ESP_FAIL;
}
flip_endian(session->sym_key, PUBLIC_KEY_LEN);
const protocomm_security1_params_t *pop = session->pop;
if (pop != NULL && pop->data != NULL && pop->len != 0) {
ESP_LOGD(TAG, "Adding proof of possession");
uint8_t sha_out[PUBLIC_KEY_LEN];
ret = mbedtls_sha256((const unsigned char *) pop->data, pop->len, sha_out, 0);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_sha256_ret with error code : %d", ret);
return ESP_FAIL;
psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
status = psa_hash_setup(&hash_operation, PSA_ALG_SHA_256);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_hash_setup failed with status=%d", status);
// ret = ESP_FAIL;
}
status = psa_hash_update(&hash_operation, pop->data, pop->len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_hash_update failed with status=%d", status);
psa_hash_abort(&hash_operation);
// ret = ESP_FAIL;
}
status = psa_hash_finish(&hash_operation, sha_out, sizeof(sha_out), &olen);
if (status != PSA_SUCCESS || olen != sizeof(sha_out)) {
ESP_LOGE(TAG, "psa_hash_finish failed with status=%d", status);
psa_hash_abort(&hash_operation);
// ret = ESP_FAIL;
}
for (int i = 0; i < PUBLIC_KEY_LEN; i++) {
@@ -219,7 +203,6 @@ static esp_err_t verify_response0(session_t *session, SessionData *resp)
static esp_err_t prepare_command1(session_t *session, SessionData *req)
{
int ret;
uint8_t *outbuf = (uint8_t *) malloc(PUBLIC_KEY_LEN);
if (!outbuf) {
ESP_LOGE(TAG, "Error allocating ciphertext buffer");
@@ -227,26 +210,44 @@ static esp_err_t prepare_command1(session_t *session, SessionData *req)
}
/* Initialise crypto context */
mbedtls_aes_init(&session->ctx_aes);
memset(session->stb, 0, sizeof(session->stb));
session->nc_off = 0;
ret = mbedtls_aes_setkey_enc(&session->ctx_aes, session->sym_key,
sizeof(session->sym_key)*8);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_aes_setkey_enc with error code : %d", ret);
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id;
psa_algorithm_t alg = PSA_ALG_CTR;
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&key_attributes, 256);
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
psa_set_key_algorithm(&key_attributes, alg);
status = psa_import_key(&key_attributes, session->sym_key, sizeof(session->sym_key), &key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed at psa_import_key with error code : %d", status);
free(outbuf);
return ESP_FAIL;
}
psa_reset_key_attributes(&key_attributes);
session->ctx_aes = psa_cipher_operation_init();
status = psa_cipher_encrypt_setup(&session->ctx_aes, key_id, alg);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed at psa_cipher_encrypt_setup with error code : %d", status);
free(outbuf);
return ESP_FAIL;
}
status = psa_cipher_set_iv(&session->ctx_aes, session->rand, sizeof(session->rand));
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed at psa_cipher_set_iv with error code : %d", status);
free(outbuf);
return ESP_FAIL;
}
size_t outlen = 0;
status = psa_cipher_update(&session->ctx_aes, session->device_pubkey, sizeof(session->device_pubkey), outbuf, PUBLIC_KEY_LEN, &outlen);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed at psa_cipher_update with error code : %d", status);
free(outbuf);
return ESP_FAIL;
}
ret = mbedtls_aes_crypt_ctr(&session->ctx_aes, PUBLIC_KEY_LEN,
&session->nc_off, session->rand,
session->stb, session->device_pubkey, outbuf);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_aes_crypt_ctr with error code : %d", ret);
free(outbuf);
return ESP_FAIL;
}
session->key_id = key_id;
Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload));
if (!out) {
@@ -292,8 +293,8 @@ static esp_err_t verify_response1(session_t *session, SessionData *resp)
uint8_t *cli_pubkey = session->client_pubkey;
uint8_t *dev_pubkey = session->device_pubkey;
hexdump("Device pubkey", dev_pubkey, PUBLIC_KEY_LEN);
hexdump("Client pubkey", cli_pubkey, PUBLIC_KEY_LEN);
hexdump("Device pubkey1", dev_pubkey, PUBLIC_KEY_LEN);
hexdump("Client pubkey1", cli_pubkey, PUBLIC_KEY_LEN);
if ((resp->proto_case != SESSION_DATA__PROTO_SEC1) ||
(resp->sec1->msg != SEC1_MSG_TYPE__Session_Response1)) {
@@ -304,13 +305,17 @@ static esp_err_t verify_response1(session_t *session, SessionData *resp)
uint8_t check_buf[PUBLIC_KEY_LEN];
Sec1Payload *in = (Sec1Payload *) resp->sec1;
int ret = mbedtls_aes_crypt_ctr(&session->ctx_aes, PUBLIC_KEY_LEN,
&session->nc_off, session->rand, session->stb,
in->sr1->device_verify_data.data, check_buf);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_aes_crypt_ctr with error code : %d", ret);
hexdump("Device verify data", in->sr1->device_verify_data.data, in->sr1->device_verify_data.len);
hexdump("Rand: ", session->rand, sizeof(session->rand));
size_t out_len = 0;
psa_status_t status = psa_cipher_update(&session->ctx_aes, in->sr1->device_verify_data.data, in->sr1->device_verify_data.len, check_buf, sizeof(check_buf), &out_len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed at psa_cipher_update with error code : %d", status);
return ESP_FAIL;
}
hexdump("Dec Device verifier", check_buf, sizeof(check_buf));
if (memcmp(check_buf, session->client_pubkey, sizeof(session->client_pubkey)) != 0) {
@@ -318,6 +323,9 @@ static esp_err_t verify_response1(session_t *session, SessionData *resp)
return ESP_FAIL;
}
/* Initialize operation counter after successful handshake */
session->op_counter = 0;
return ESP_OK;
}
@@ -358,6 +366,14 @@ static esp_err_t test_delete_session(session_t *session)
if (test_sec->cleanup && (test_sec->cleanup(sec_inst) != ESP_OK)) {
return ESP_FAIL;
}
psa_destroy_key(session->client_key_id);
session->client_key_id = 0;
psa_destroy_key(session->key_id);
session->key_id = 0;
psa_cipher_abort(&session->ctx_aes);
return ESP_OK;
}
@@ -377,52 +393,43 @@ static esp_err_t test_sec_endpoint(session_t *session)
ssize_t outlen = 0;
uint8_t *outbuf = NULL;
mbedtls_ecdh_init(&session->ctx_client);
mbedtls_ecdh_setup(&session->ctx_client, MBEDTLS_ECP_DP_CURVE25519);
mbedtls_ctr_drbg_init(&session->ctr_drbg);
psa_status_t status;
mbedtls_entropy_init(&session->entropy);
ret = mbedtls_ctr_drbg_seed(&session->ctr_drbg, mbedtls_entropy_func,
&session->entropy, NULL, 0);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_ctr_drbg_seed with error code : %d", ret);
goto abort_test_sec_endpoint;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
if (session->client_key_id != 0) {
psa_destroy_key(session->client_key_id);
session->client_key_id = 0;
}
ret = mbedtls_ecp_group_load(ACCESS_ECDH(&session->ctx_client, grp), MBEDTLS_ECP_DP_CURVE25519);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_ecp_group_load with error code : %d", ret);
goto abort_test_sec_endpoint;
}
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY));
psa_set_key_bits(&key_attributes, 255);
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_DERIVE);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDH);
ret = mbedtls_ecdh_gen_public(ACCESS_ECDH(&session->ctx_client, grp),
ACCESS_ECDH(&session->ctx_client, d),
ACCESS_ECDH(&session->ctx_client, Q),
mbedtls_ctr_drbg_random,
&session->ctr_drbg);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_ecdh_gen_public with error code : %d", ret);
goto abort_test_sec_endpoint;
status = psa_generate_key(&key_attributes, &session->client_key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_generate_key failed with status=%d", status);
psa_reset_key_attributes(&key_attributes);
return ESP_FAIL;
}
psa_reset_key_attributes(&key_attributes);
size_t olen = 0;
if (session->weak) {
/* Read zero client public key */
ret = mbedtls_mpi_read_binary(ACCESS_ECDH(&session->ctx_client, Q).MBEDTLS_PRIVATE(X),
session->client_pubkey,
PUBLIC_KEY_LEN);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_mpi_read_binary with error code : %d", ret);
goto abort_test_sec_endpoint;
// If weak key is request, just set the session->client_pubkey to be 0
memset(session->client_pubkey, 0, PUBLIC_KEY_LEN);
} else {
status = psa_export_public_key(session->client_key_id, session->client_pubkey, PUBLIC_KEY_LEN, &olen);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_export_public_key failed with status=%d", status);
psa_reset_key_attributes(&key_attributes);
return ESP_FAIL;
}
}
ret = mbedtls_mpi_write_binary(ACCESS_ECDH(&session->ctx_client, Q).MBEDTLS_PRIVATE(X),
session->client_pubkey,
PUBLIC_KEY_LEN);
if (ret != 0) {
ESP_LOGE(TAG, "Failed at mbedtls_mpi_write_binary with error code : %d", ret);
goto abort_test_sec_endpoint;
}
flip_endian(session->client_pubkey, PUBLIC_KEY_LEN);
hexdump("Client public key", session->client_pubkey, PUBLIC_KEY_LEN);
/*********** Transaction0 = SessionCmd0 + SessionResp0 ****************/
session_data__init(&req);
@@ -511,17 +518,14 @@ static esp_err_t test_sec_endpoint(session_t *session)
}
session_data__free_unpacked(resp, NULL);
mbedtls_ecdh_free(&session->ctx_client);
mbedtls_ctr_drbg_free(&session->ctr_drbg);
mbedtls_entropy_free(&session->entropy);
psa_destroy_key(session->client_key_id);
session->client_key_id = 0;
return ESP_OK;
abort_test_sec_endpoint:
mbedtls_ecdh_free(&session->ctx_client);
mbedtls_ctr_drbg_free(&session->ctr_drbg);
mbedtls_entropy_free(&session->entropy);
psa_destroy_key(session->client_key_id);
session->client_key_id = 0;
return ESP_FAIL;
}
@@ -564,11 +568,17 @@ static esp_err_t test_req_endpoint(session_t *session)
// Check if the AES key is correctly set before calling the software encryption
// API. Without this check, the code will crash, resulting in a test case failure.
// For hardware AES, portability layer takes care of this.
if (session->ctx_aes.MBEDTLS_PRIVATE(nr) > 0) {
// if (session->ctx_aes.MBEDTLS_PRIVATE(nr) > 0) {
if (session->ctx_aes.MBEDTLS_PRIVATE(id) > 0) {
#endif
mbedtls_aes_crypt_ctr(&session->ctx_aes, sizeof(rand_test_data), &session->nc_off,
session->rand, session->stb, rand_test_data, enc_test_data);
size_t out_len = 0;
psa_status_t status = psa_cipher_update(&session->ctx_aes, rand_test_data, sizeof(rand_test_data), enc_test_data, sizeof(enc_test_data), &out_len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Error updating cipher, status: %d", status);
return ESP_FAIL;
}
#if !CONFIG_MBEDTLS_HARDWARE_AES
}
#endif
@@ -597,8 +607,14 @@ static esp_err_t test_req_endpoint(session_t *session)
memcpy(verify_data, enc_verify_data, verify_data_len);
}
else if (session->sec_ver == 1) {
mbedtls_aes_crypt_ctr(&session->ctx_aes, verify_data_len, &session->nc_off,
session->rand, session->stb, enc_verify_data, verify_data);
size_t out_len = 0;
psa_status_t status = psa_cipher_update(&session->ctx_aes, enc_verify_data, verify_data_len, verify_data, verify_data_len, &out_len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "psa_cipher_update failed");
free(verify_data);
free(enc_verify_data);
return ESP_FAIL;
}
}
free(enc_verify_data);
@@ -1126,6 +1142,7 @@ TEST_CASE("leak test", "[PROTOCOMM]")
* time allocations to happen (not related to protocomm) */
test_security0();
test_security1();
mbedtls_psa_crypto_free();
usleep(1000);
#ifdef CONFIG_HEAP_TRACING
@@ -1136,7 +1153,7 @@ TEST_CASE("leak test", "[PROTOCOMM]")
/* Run all tests passively. Any leaks due
* to protocomm should show up now */
unsigned pre_start_mem = esp_get_free_heap_size();
psa_crypto_init();
test_security0();
test_security1();
test_security1_no_encryption();
@@ -1144,6 +1161,7 @@ TEST_CASE("leak test", "[PROTOCOMM]")
test_security1_wrong_pop();
test_security1_insecure_client();
test_security1_weak_session();
mbedtls_psa_crypto_free();
usleep(1000);
@@ -1163,30 +1181,36 @@ TEST_CASE("security 0 basic test", "[PROTOCOMM]")
TEST_CASE("security 1 basic test", "[PROTOCOMM]")
{
psa_crypto_init();
TEST_ASSERT(test_security1() == ESP_OK);
}
TEST_CASE("security 1 no encryption test", "[PROTOCOMM]")
{
psa_crypto_init();
TEST_ASSERT(test_security1_no_encryption() == ESP_OK);
}
TEST_CASE("security 1 session overflow test", "[PROTOCOMM]")
{
psa_crypto_init();
TEST_ASSERT(test_security1_session_overflow() == ESP_OK);
}
TEST_CASE("security 1 wrong pop test", "[PROTOCOMM]")
{
psa_crypto_init();
TEST_ASSERT(test_security1_wrong_pop() == ESP_OK);
}
TEST_CASE("security 1 insecure client test", "[PROTOCOMM]")
{
psa_crypto_init();
TEST_ASSERT(test_security1_insecure_client() == ESP_OK);
}
TEST_CASE("security 1 weak session test", "[PROTOCOMM]")
{
psa_crypto_init();
TEST_ASSERT(test_security1_weak_session() == ESP_OK);
}