2022-01-03 10:14:55 +05:30
|
|
|
/*
|
|
|
|
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
2018-07-30 21:33:10 +05:30
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <esp_err.h>
|
|
|
|
#include <esp_log.h>
|
2022-12-21 11:30:50 +05:30
|
|
|
#include <inttypes.h>
|
2018-07-30 21:33:10 +05:30
|
|
|
|
2022-09-15 12:40:53 +05:30
|
|
|
/* TODO: Currently MBEDTLS_ECDH_LEGACY_CONTEXT is enabled by default
|
|
|
|
* when MBEDTLS_ECP_RESTARTABLE is enabled.
|
2022-02-11 07:55:31 +05:30
|
|
|
* This is a temporary workaround to allow that.
|
2022-09-15 12:40:53 +05:30
|
|
|
*
|
|
|
|
* The legacy option is soon going to be removed in future mbedtls
|
|
|
|
* versions and this workaround will be removed once the appropriate
|
|
|
|
* solution is available.
|
2022-02-11 07:55:31 +05:30
|
|
|
*/
|
|
|
|
#ifdef CONFIG_MBEDTLS_ECDH_LEGACY_CONTEXT
|
2022-09-15 12:40:53 +05:30
|
|
|
#define ACCESS_ECDH(S, var) S->MBEDTLS_PRIVATE(var)
|
2022-02-11 07:55:31 +05:30
|
|
|
#else
|
2022-09-15 12:40:53 +05:30
|
|
|
#define ACCESS_ECDH(S, var) S->MBEDTLS_PRIVATE(ctx).MBEDTLS_PRIVATE(mbed_ecdh).MBEDTLS_PRIVATE(var)
|
2022-02-11 07:55:31 +05:30
|
|
|
#endif
|
|
|
|
|
2018-07-30 21:33:10 +05:30
|
|
|
#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>
|
2022-01-03 10:14:55 +05:30
|
|
|
#include <mbedtls/constant_time.h>
|
2018-07-30 21:33:10 +05:30
|
|
|
|
|
|
|
#include <protocomm_security.h>
|
|
|
|
#include <protocomm_security1.h>
|
|
|
|
|
|
|
|
#include "session.pb-c.h"
|
|
|
|
#include "sec1.pb-c.h"
|
|
|
|
#include "constants.pb-c.h"
|
|
|
|
|
|
|
|
static const char* TAG = "security1";
|
|
|
|
|
|
|
|
#define PUBLIC_KEY_LEN 32
|
|
|
|
#define SZ_RANDOM 16
|
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
#define SESSION_STATE_CMD0 0 /* Session is not setup */
|
|
|
|
#define SESSION_STATE_CMD1 1 /* Session is not setup */
|
|
|
|
#define SESSION_STATE_DONE 2 /* Session setup successful */
|
2018-07-30 21:33:10 +05:30
|
|
|
|
|
|
|
typedef struct session {
|
|
|
|
/* Session data */
|
|
|
|
uint32_t id;
|
|
|
|
uint8_t state;
|
|
|
|
uint8_t device_pubkey[PUBLIC_KEY_LEN];
|
|
|
|
uint8_t client_pubkey[PUBLIC_KEY_LEN];
|
|
|
|
uint8_t sym_key[PUBLIC_KEY_LEN];
|
|
|
|
uint8_t rand[SZ_RANDOM];
|
|
|
|
|
|
|
|
/* mbedtls context data for AES */
|
|
|
|
mbedtls_aes_context ctx_aes;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static esp_err_t handle_session_command1(session_t *cur_session,
|
|
|
|
uint32_t session_id,
|
2018-07-30 21:33:10 +05:30
|
|
|
SessionData *req, SessionData *resp)
|
|
|
|
{
|
|
|
|
ESP_LOGD(TAG, "Request to handle setup1_command");
|
|
|
|
Sec1Payload *in = (Sec1Payload *) req->sec1;
|
|
|
|
uint8_t check_buf[PUBLIC_KEY_LEN];
|
|
|
|
int mbed_err;
|
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
if (cur_session->state != SESSION_STATE_CMD1) {
|
|
|
|
ESP_LOGE(TAG, "Invalid state of session %d (expected %d)", SESSION_STATE_CMD1, cur_session->state);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_ERR_INVALID_STATE;
|
|
|
|
}
|
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
/* Initialize crypto context */
|
2018-07-30 21:33:10 +05:30
|
|
|
mbedtls_aes_init(&cur_session->ctx_aes);
|
|
|
|
memset(cur_session->stb, 0, sizeof(cur_session->stb));
|
|
|
|
cur_session->nc_off = 0;
|
|
|
|
|
|
|
|
hexdump("Client verifier", in->sc1->client_verify_data.data,
|
|
|
|
in->sc1->client_verify_data.len);
|
|
|
|
|
|
|
|
mbed_err = mbedtls_aes_setkey_enc(&cur_session->ctx_aes, cur_session->sym_key,
|
|
|
|
sizeof(cur_session->sym_key)*8);
|
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failure at mbedtls_aes_setkey_enc with error code : -0x%x", -mbed_err);
|
2019-02-08 14:42:49 +05:30
|
|
|
mbedtls_aes_free(&cur_session->ctx_aes);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
mbed_err = mbedtls_aes_crypt_ctr(&cur_session->ctx_aes,
|
|
|
|
PUBLIC_KEY_LEN, &cur_session->nc_off,
|
|
|
|
cur_session->rand, cur_session->stb,
|
|
|
|
in->sc1->client_verify_data.data, check_buf);
|
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failure at mbedtls_aes_crypt_ctr with error code : -0x%x", -mbed_err);
|
2019-02-08 14:42:49 +05:30
|
|
|
mbedtls_aes_free(&cur_session->ctx_aes);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
hexdump("Dec Client verifier", check_buf, sizeof(check_buf));
|
|
|
|
|
|
|
|
/* constant time memcmp */
|
2022-01-03 10:14:55 +05:30
|
|
|
if (mbedtls_ct_memcmp(check_buf, cur_session->device_pubkey,
|
2018-07-30 21:33:10 +05:30
|
|
|
sizeof(cur_session->device_pubkey)) != 0) {
|
|
|
|
ESP_LOGE(TAG, "Key mismatch. Close connection");
|
2019-02-08 14:42:49 +05:30
|
|
|
mbedtls_aes_free(&cur_session->ctx_aes);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload));
|
|
|
|
SessionResp1 *out_resp = (SessionResp1 *) malloc(sizeof(SessionResp1));
|
2019-02-08 14:42:49 +05:30
|
|
|
if (!out || !out_resp) {
|
|
|
|
ESP_LOGE(TAG, "Error allocating memory for response1");
|
|
|
|
free(out);
|
|
|
|
free(out_resp);
|
|
|
|
mbedtls_aes_free(&cur_session->ctx_aes);
|
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
}
|
2018-07-30 21:33:10 +05:30
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
sec1_payload__init(out);
|
|
|
|
session_resp1__init(out_resp);
|
2018-07-30 21:33:10 +05:30
|
|
|
out_resp->status = STATUS__Success;
|
|
|
|
|
|
|
|
uint8_t *outbuf = (uint8_t *) malloc(PUBLIC_KEY_LEN);
|
|
|
|
if (!outbuf) {
|
|
|
|
ESP_LOGE(TAG, "Error allocating ciphertext buffer");
|
2019-02-08 14:42:49 +05:30
|
|
|
free(out);
|
|
|
|
free(out_resp);
|
|
|
|
mbedtls_aes_free(&cur_session->ctx_aes);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
mbed_err = mbedtls_aes_crypt_ctr(&cur_session->ctx_aes,
|
|
|
|
PUBLIC_KEY_LEN, &cur_session->nc_off,
|
|
|
|
cur_session->rand, cur_session->stb,
|
|
|
|
cur_session->client_pubkey, outbuf);
|
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failure at mbedtls_aes_crypt_ctr with error code : -0x%x", -mbed_err);
|
2019-02-08 14:42:49 +05:30
|
|
|
free(outbuf);
|
|
|
|
free(out);
|
|
|
|
free(out_resp);
|
|
|
|
mbedtls_aes_free(&cur_session->ctx_aes);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
out_resp->device_verify_data.data = outbuf;
|
|
|
|
out_resp->device_verify_data.len = PUBLIC_KEY_LEN;
|
|
|
|
hexdump("Device verify data", outbuf, PUBLIC_KEY_LEN);
|
|
|
|
|
|
|
|
out->msg = SEC1_MSG_TYPE__Session_Response1;
|
|
|
|
out->payload_case = SEC1_PAYLOAD__PAYLOAD_SR1;
|
|
|
|
out->sr1 = out_resp;
|
|
|
|
|
|
|
|
resp->proto_case = SESSION_DATA__PROTO_SEC1;
|
|
|
|
resp->sec1 = out;
|
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
cur_session->state = SESSION_STATE_DONE;
|
|
|
|
ESP_LOGD(TAG, "Secure session established successfully");
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
2021-01-06 15:49:11 +05:30
|
|
|
static esp_err_t sec1_new_session(protocomm_security_handle_t handle, uint32_t session_id);
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static esp_err_t handle_session_command0(session_t *cur_session,
|
|
|
|
uint32_t session_id,
|
2018-07-30 21:33:10 +05:30
|
|
|
SessionData *req, SessionData *resp,
|
2022-05-20 09:58:07 +05:30
|
|
|
const protocomm_security1_params_t *pop)
|
2018-07-30 21:33:10 +05:30
|
|
|
{
|
2019-02-08 14:42:49 +05:30
|
|
|
ESP_LOGD(TAG, "Request to handle setup0_command");
|
2018-07-30 21:33:10 +05:30
|
|
|
Sec1Payload *in = (Sec1Payload *) req->sec1;
|
|
|
|
esp_err_t ret;
|
|
|
|
int mbed_err;
|
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
if (cur_session->state != SESSION_STATE_CMD0) {
|
2021-01-06 15:49:11 +05:30
|
|
|
ESP_LOGW(TAG, "Invalid state of session %d (expected %d). Restarting session.",
|
|
|
|
SESSION_STATE_CMD0, cur_session->state);
|
|
|
|
sec1_new_session(cur_session, session_id);
|
2018-07-30 21:33:10 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (in->sc0->client_pubkey.len != PUBLIC_KEY_LEN) {
|
|
|
|
ESP_LOGE(TAG, "Invalid public key length");
|
|
|
|
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));
|
2019-05-28 14:41:49 +05:30
|
|
|
if (!ctx_server || !entropy || !ctr_drbg) {
|
2018-07-30 21:33:10 +05:30
|
|
|
ESP_LOGE(TAG, "Failed to allocate memory for mbedtls context");
|
|
|
|
free(ctx_server);
|
|
|
|
free(entropy);
|
|
|
|
free(ctr_drbg);
|
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
mbedtls_ecdh_init(ctx_server);
|
2022-02-22 11:22:46 +05:30
|
|
|
mbedtls_ecdh_setup(ctx_server, MBEDTLS_ECP_DP_CURVE25519);
|
2018-07-30 21:33:10 +05:30
|
|
|
mbedtls_ctr_drbg_init(ctr_drbg);
|
|
|
|
mbedtls_entropy_init(entropy);
|
|
|
|
|
|
|
|
mbed_err = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func,
|
|
|
|
entropy, NULL, 0);
|
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_ctr_drbg_seed with error code : -0x%x", -mbed_err);
|
|
|
|
ret = ESP_FAIL;
|
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
|
2022-02-11 07:55:31 +05:30
|
|
|
mbed_err = mbedtls_ecp_group_load(ACCESS_ECDH(&ctx_server, grp), MBEDTLS_ECP_DP_CURVE25519);
|
2018-07-30 21:33:10 +05:30
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_ecp_group_load with error code : -0x%x", -mbed_err);
|
|
|
|
ret = ESP_FAIL;
|
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
|
2022-02-11 07:55:31 +05:30
|
|
|
mbed_err = mbedtls_ecdh_gen_public(ACCESS_ECDH(&ctx_server, grp), ACCESS_ECDH(&ctx_server, d), ACCESS_ECDH(&ctx_server, Q),
|
2018-07-30 21:33:10 +05:30
|
|
|
mbedtls_ctr_drbg_random, ctr_drbg);
|
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_ecdh_gen_public with error code : -0x%x", -mbed_err);
|
|
|
|
ret = ESP_FAIL;
|
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
|
2022-09-15 12:40:53 +05:30
|
|
|
mbed_err = mbedtls_mpi_write_binary(ACCESS_ECDH(&ctx_server, Q).MBEDTLS_PRIVATE(X),
|
2018-07-30 21:33:10 +05:30
|
|
|
cur_session->device_pubkey,
|
|
|
|
PUBLIC_KEY_LEN);
|
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_mpi_write_binary with error code : -0x%x", -mbed_err);
|
|
|
|
ret = ESP_FAIL;
|
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
flip_endian(cur_session->device_pubkey, PUBLIC_KEY_LEN);
|
|
|
|
|
|
|
|
memcpy(cur_session->client_pubkey, in->sc0->client_pubkey.data, PUBLIC_KEY_LEN);
|
|
|
|
|
|
|
|
uint8_t *dev_pubkey = cur_session->device_pubkey;
|
|
|
|
uint8_t *cli_pubkey = cur_session->client_pubkey;
|
|
|
|
hexdump("Device pubkey", dev_pubkey, PUBLIC_KEY_LEN);
|
|
|
|
hexdump("Client pubkey", cli_pubkey, PUBLIC_KEY_LEN);
|
|
|
|
|
2022-09-15 12:40:53 +05:30
|
|
|
mbed_err = mbedtls_mpi_lset(ACCESS_ECDH(&ctx_server, Qp).MBEDTLS_PRIVATE(Z), 1);
|
2018-07-30 21:33:10 +05:30
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_mpi_lset with error code : -0x%x", -mbed_err);
|
|
|
|
ret = ESP_FAIL;
|
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
|
|
|
|
flip_endian(cur_session->client_pubkey, PUBLIC_KEY_LEN);
|
2022-09-15 12:40:53 +05:30
|
|
|
mbed_err = mbedtls_mpi_read_binary(ACCESS_ECDH(&ctx_server, Qp).MBEDTLS_PRIVATE(X), cli_pubkey, PUBLIC_KEY_LEN);
|
2018-07-30 21:33:10 +05:30
|
|
|
flip_endian(cur_session->client_pubkey, PUBLIC_KEY_LEN);
|
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_mpi_read_binary with error code : -0x%x", -mbed_err);
|
|
|
|
ret = ESP_FAIL;
|
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
|
2022-02-11 07:55:31 +05:30
|
|
|
mbed_err = mbedtls_ecdh_compute_shared(ACCESS_ECDH(&ctx_server, grp), ACCESS_ECDH(&ctx_server, z), ACCESS_ECDH(&ctx_server, Qp),
|
|
|
|
ACCESS_ECDH(&ctx_server, d), mbedtls_ctr_drbg_random, ctr_drbg);
|
2018-07-30 21:33:10 +05:30
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_ecdh_compute_shared with error code : -0x%x", -mbed_err);
|
|
|
|
ret = ESP_FAIL;
|
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
|
2022-02-11 07:55:31 +05:30
|
|
|
mbed_err = mbedtls_mpi_write_binary(ACCESS_ECDH(&ctx_server, z), cur_session->sym_key, PUBLIC_KEY_LEN);
|
2018-07-30 21:33:10 +05:30
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_mpi_write_binary with error code : -0x%x", -mbed_err);
|
|
|
|
ret = ESP_FAIL;
|
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
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];
|
|
|
|
|
2021-08-09 15:28:36 +05:30
|
|
|
mbed_err = mbedtls_sha256((const unsigned char *) pop->data, pop->len, sha_out, 0);
|
2018-07-30 21:33:10 +05:30
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < PUBLIC_KEY_LEN; i++) {
|
|
|
|
cur_session->sym_key[i] ^= sha_out[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hexdump("Shared key", cur_session->sym_key, PUBLIC_KEY_LEN);
|
|
|
|
|
|
|
|
mbed_err = mbedtls_ctr_drbg_random(ctr_drbg, cur_session->rand, SZ_RANDOM);
|
|
|
|
if (mbed_err != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_ctr_drbg_random with error code : -0x%x", -mbed_err);
|
|
|
|
ret = ESP_FAIL;
|
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
|
|
|
|
hexdump("Device random", cur_session->rand, SZ_RANDOM);
|
|
|
|
|
|
|
|
Sec1Payload *out = (Sec1Payload *) malloc(sizeof(Sec1Payload));
|
|
|
|
SessionResp0 *out_resp = (SessionResp0 *) malloc(sizeof(SessionResp0));
|
|
|
|
if (!out || !out_resp) {
|
2019-02-08 14:42:49 +05:30
|
|
|
ESP_LOGE(TAG, "Error allocating memory for response0");
|
|
|
|
ret = ESP_ERR_NO_MEM;
|
|
|
|
free(out);
|
|
|
|
free(out_resp);
|
2018-07-30 21:33:10 +05:30
|
|
|
goto exit_cmd0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sec1_payload__init(out);
|
|
|
|
session_resp0__init(out_resp);
|
|
|
|
|
|
|
|
out_resp->status = STATUS__Success;
|
|
|
|
|
|
|
|
out_resp->device_pubkey.data = dev_pubkey;
|
|
|
|
out_resp->device_pubkey.len = PUBLIC_KEY_LEN;
|
|
|
|
|
|
|
|
out_resp->device_random.data = (uint8_t *) cur_session->rand;
|
|
|
|
out_resp->device_random.len = SZ_RANDOM;
|
|
|
|
|
|
|
|
out->msg = SEC1_MSG_TYPE__Session_Response0;
|
|
|
|
out->payload_case = SEC1_PAYLOAD__PAYLOAD_SR0;
|
|
|
|
out->sr0 = out_resp;
|
|
|
|
|
|
|
|
resp->proto_case = SESSION_DATA__PROTO_SEC1;
|
|
|
|
resp->sec1 = out;
|
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
cur_session->state = SESSION_STATE_CMD1;
|
|
|
|
|
2018-07-30 21:33:10 +05:30
|
|
|
ESP_LOGD(TAG, "Session setup phase1 done");
|
|
|
|
ret = ESP_OK;
|
|
|
|
|
|
|
|
exit_cmd0:
|
|
|
|
mbedtls_ecdh_free(ctx_server);
|
|
|
|
free(ctx_server);
|
|
|
|
|
|
|
|
mbedtls_ctr_drbg_free(ctr_drbg);
|
|
|
|
free(ctr_drbg);
|
|
|
|
|
|
|
|
mbedtls_entropy_free(entropy);
|
|
|
|
free(entropy);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static esp_err_t sec1_session_setup(session_t *cur_session,
|
|
|
|
uint32_t session_id,
|
2018-07-30 21:33:10 +05:30
|
|
|
SessionData *req, SessionData *resp,
|
2022-05-20 09:58:07 +05:30
|
|
|
const protocomm_security1_params_t *pop)
|
2018-07-30 21:33:10 +05:30
|
|
|
{
|
|
|
|
Sec1Payload *in = (Sec1Payload *) req->sec1;
|
|
|
|
esp_err_t ret;
|
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
if (!in) {
|
|
|
|
ESP_LOGE(TAG, "Empty session data");
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2018-07-30 21:33:10 +05:30
|
|
|
switch (in->msg) {
|
|
|
|
case SEC1_MSG_TYPE__Session_Command0:
|
2019-04-12 17:32:38 +05:30
|
|
|
ret = handle_session_command0(cur_session, session_id, req, resp, pop);
|
2018-07-30 21:33:10 +05:30
|
|
|
break;
|
|
|
|
case SEC1_MSG_TYPE__Session_Command1:
|
2019-04-12 17:32:38 +05:30
|
|
|
ret = handle_session_command1(cur_session, session_id, req, resp);
|
2018-07-30 21:33:10 +05:30
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ESP_LOGE(TAG, "Invalid security message type");
|
|
|
|
ret = ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static void sec1_session_setup_cleanup(session_t *cur_session, uint32_t session_id, SessionData *resp)
|
2018-07-30 21:33:10 +05:30
|
|
|
{
|
|
|
|
Sec1Payload *out = resp->sec1;
|
|
|
|
|
|
|
|
if (!out) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (out->msg) {
|
|
|
|
case SEC1_MSG_TYPE__Session_Response0:
|
|
|
|
{
|
|
|
|
SessionResp0 *out_resp0 = out->sr0;
|
|
|
|
if (out_resp0) {
|
|
|
|
free(out_resp0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SEC1_MSG_TYPE__Session_Response1:
|
|
|
|
{
|
|
|
|
SessionResp1 *out_resp1 = out->sr1;
|
|
|
|
if (out_resp1) {
|
|
|
|
free(out_resp1->device_verify_data.data);
|
|
|
|
free(out_resp1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(out);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static esp_err_t sec1_close_session(protocomm_security_handle_t handle, uint32_t session_id)
|
2018-07-30 21:33:10 +05:30
|
|
|
{
|
2019-04-12 17:32:38 +05:30
|
|
|
session_t *cur_session = (session_t *) handle;
|
|
|
|
if (!cur_session) {
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
if (!cur_session || cur_session->id != session_id) {
|
|
|
|
ESP_LOGE(TAG, "Attempt to close invalid session");
|
2019-04-12 17:32:38 +05:30
|
|
|
return ESP_ERR_INVALID_STATE;
|
2019-02-08 14:42:49 +05:30
|
|
|
}
|
2018-07-30 21:33:10 +05:30
|
|
|
|
2019-02-08 14:42:49 +05:30
|
|
|
if (cur_session->state == SESSION_STATE_DONE) {
|
|
|
|
/* Free AES context data */
|
2018-07-30 21:33:10 +05:30
|
|
|
mbedtls_aes_free(&cur_session->ctx_aes);
|
|
|
|
}
|
2019-02-08 14:42:49 +05:30
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
memset(cur_session, 0, sizeof(session_t));
|
|
|
|
cur_session->id = -1;
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static esp_err_t sec1_new_session(protocomm_security_handle_t handle, uint32_t session_id)
|
2018-07-30 21:33:10 +05:30
|
|
|
{
|
2019-04-12 17:32:38 +05:30
|
|
|
session_t *cur_session = (session_t *) handle;
|
|
|
|
if (!cur_session) {
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
2018-07-30 21:33:10 +05:30
|
|
|
}
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
if (cur_session->id != -1) {
|
|
|
|
/* Only one session is allowed at a time */
|
2022-12-21 11:30:50 +05:30
|
|
|
ESP_LOGE(TAG, "Closing old session with id %" PRIu32, cur_session->id);
|
2019-04-12 17:32:38 +05:30
|
|
|
sec1_close_session(cur_session, session_id);
|
2018-07-30 21:33:10 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
cur_session->id = session_id;
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static esp_err_t sec1_init(protocomm_security_handle_t *handle)
|
2018-07-30 21:33:10 +05:30
|
|
|
{
|
2019-04-12 17:32:38 +05:30
|
|
|
if (!handle) {
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
session_t *cur_session = (session_t *) calloc(1, sizeof(session_t));
|
|
|
|
if (!cur_session) {
|
|
|
|
ESP_LOGE(TAG, "Error allocating new session");
|
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
}
|
|
|
|
cur_session->id = -1;
|
|
|
|
*handle = (protocomm_security_handle_t) cur_session;
|
2019-02-08 14:42:49 +05:30
|
|
|
return ESP_OK;
|
|
|
|
}
|
2018-07-30 21:33:10 +05:30
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static esp_err_t sec1_cleanup(protocomm_security_handle_t handle)
|
2019-02-08 14:42:49 +05:30
|
|
|
{
|
2019-04-12 17:32:38 +05:30
|
|
|
session_t *cur_session = (session_t *) handle;
|
2019-02-08 14:42:49 +05:30
|
|
|
if (cur_session) {
|
2019-04-12 17:32:38 +05:30
|
|
|
sec1_close_session(handle, cur_session->id);
|
2019-02-08 14:42:49 +05:30
|
|
|
}
|
2019-04-12 17:32:38 +05:30
|
|
|
free(handle);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static esp_err_t sec1_decrypt(protocomm_security_handle_t handle,
|
|
|
|
uint32_t session_id,
|
2018-07-30 21:33:10 +05:30
|
|
|
const uint8_t *inbuf, ssize_t inlen,
|
2022-05-20 09:58:07 +05:30
|
|
|
uint8_t **outbuf, ssize_t *outlen)
|
2018-07-30 21:33:10 +05:30
|
|
|
{
|
2019-04-12 17:32:38 +05:30
|
|
|
session_t *cur_session = (session_t *) handle;
|
|
|
|
if (!cur_session) {
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2018-07-30 21:33:10 +05:30
|
|
|
if (!cur_session || cur_session->id != session_id) {
|
2022-12-21 11:30:50 +05:30
|
|
|
ESP_LOGE(TAG, "Session with ID %" PRId32 "not found", session_id);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_ERR_INVALID_STATE;
|
|
|
|
}
|
2019-02-08 14:42:49 +05:30
|
|
|
|
|
|
|
if (cur_session->state != SESSION_STATE_DONE) {
|
|
|
|
ESP_LOGE(TAG, "Secure session not established");
|
|
|
|
return ESP_ERR_INVALID_STATE;
|
|
|
|
}
|
|
|
|
|
2018-07-30 21:33:10 +05:30
|
|
|
*outlen = inlen;
|
2022-05-20 09:58:07 +05:30
|
|
|
*outbuf = (uint8_t *) malloc(*outlen);
|
|
|
|
if (!*outbuf) {
|
|
|
|
ESP_LOGE(TAG, "Failed to allocate encrypt/decrypt buf len %d", *outlen);
|
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
}
|
|
|
|
|
2018-07-30 21:33:10 +05:30
|
|
|
int ret = mbedtls_aes_crypt_ctr(&cur_session->ctx_aes, inlen, &cur_session->nc_off,
|
2022-05-20 09:58:07 +05:30
|
|
|
cur_session->rand, cur_session->stb, inbuf, *outbuf);
|
2018-07-30 21:33:10 +05:30
|
|
|
if (ret != 0) {
|
|
|
|
ESP_LOGE(TAG, "Failed at mbedtls_aes_crypt_ctr with error code : %d", ret);
|
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
static esp_err_t sec1_req_handler(protocomm_security_handle_t handle,
|
2022-05-20 09:58:07 +05:30
|
|
|
const void *sec_params,
|
2019-04-12 17:32:38 +05:30
|
|
|
uint32_t session_id,
|
2018-07-30 21:33:10 +05:30
|
|
|
const uint8_t *inbuf, ssize_t inlen,
|
|
|
|
uint8_t **outbuf, ssize_t *outlen,
|
|
|
|
void *priv_data)
|
|
|
|
{
|
2019-04-12 17:32:38 +05:30
|
|
|
session_t *cur_session = (session_t *) handle;
|
|
|
|
if (!cur_session) {
|
|
|
|
ESP_LOGE(TAG, "Invalid session context data");
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session_id != cur_session->id) {
|
2022-12-21 11:30:50 +05:30
|
|
|
ESP_LOGE(TAG, "Invalid session ID:%" PRId32 "(expected %" PRId32 ")", session_id, cur_session->id);
|
2019-04-12 17:32:38 +05:30
|
|
|
return ESP_ERR_INVALID_STATE;
|
|
|
|
}
|
|
|
|
|
2018-07-30 21:33:10 +05:30
|
|
|
SessionData *req;
|
|
|
|
SessionData resp;
|
|
|
|
esp_err_t ret;
|
|
|
|
|
|
|
|
req = session_data__unpack(NULL, inlen, inbuf);
|
|
|
|
if (!req) {
|
|
|
|
ESP_LOGE(TAG, "Unable to unpack setup_req");
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
if (req->sec_ver != protocomm_security1.ver) {
|
|
|
|
ESP_LOGE(TAG, "Security version mismatch. Closing connection");
|
2019-02-08 14:42:49 +05:30
|
|
|
session_data__free_unpacked(req, NULL);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
|
|
|
session_data__init(&resp);
|
2022-05-20 09:58:07 +05:30
|
|
|
ret = sec1_session_setup(cur_session, session_id, req, &resp, (protocomm_security1_params_t *) sec_params);
|
2018-07-30 21:33:10 +05:30
|
|
|
if (ret != ESP_OK) {
|
|
|
|
ESP_LOGE(TAG, "Session setup error %d", ret);
|
2019-02-08 14:42:49 +05:30
|
|
|
session_data__free_unpacked(req, NULL);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
resp.sec_ver = req->sec_ver;
|
2019-02-08 14:42:49 +05:30
|
|
|
session_data__free_unpacked(req, NULL);
|
2018-07-30 21:33:10 +05:30
|
|
|
|
|
|
|
*outlen = session_data__get_packed_size(&resp);
|
|
|
|
*outbuf = (uint8_t *) malloc(*outlen);
|
|
|
|
if (!*outbuf) {
|
|
|
|
ESP_LOGE(TAG, "System out of memory");
|
|
|
|
return ESP_ERR_NO_MEM;
|
|
|
|
}
|
|
|
|
session_data__pack(&resp, *outbuf);
|
|
|
|
|
2019-04-12 17:32:38 +05:30
|
|
|
sec1_session_setup_cleanup(cur_session, session_id, &resp);
|
2018-07-30 21:33:10 +05:30
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
const protocomm_security_t protocomm_security1 = {
|
|
|
|
.ver = 1,
|
|
|
|
.init = sec1_init,
|
|
|
|
.cleanup = sec1_cleanup,
|
|
|
|
.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,
|
|
|
|
};
|