mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'fix/support_gcm_soft_fallback_for_non_aes_ciphers' into 'master'
fix(mbedtls/gcm): Add support for software fallback for non-AES ciphers in a GCM operation Closes IDF-8494 See merge request espressif/esp-idf!28007
This commit is contained in:
commit
603bc0536c
@ -428,6 +428,29 @@ menu "mbedTLS"
|
||||
mbedTLS will still use the hardware accelerated AES block operation, but
|
||||
on a single block at a time.
|
||||
|
||||
config MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER
|
||||
bool "Enable support for non-AES ciphers in GCM operation"
|
||||
depends on MBEDTLS_HARDWARE_AES
|
||||
default y
|
||||
help
|
||||
Enable this config to support fallback to software definitions for a non-AES
|
||||
cipher GCM operation as we support hardware acceleration only for AES cipher.
|
||||
Some of the non-AES ciphers used in a GCM operation are DES, ARIA, CAMELLIA,
|
||||
CHACHA20, BLOWFISH.
|
||||
|
||||
If this config is disabled, performing a non-AES cipher GCM operation with
|
||||
the config MBEDTLS_HARDWARE_AES enabled will result in calculation of an
|
||||
AES-GCM operation instead for the given input values and thus could lead
|
||||
to failure in certificate validation which would ultimately lead to a SSL
|
||||
handshake failure.
|
||||
|
||||
This config being by-default enabled leads to an increase in binary size
|
||||
footprint of ~2.5KB.
|
||||
In case you are sure that your use case (for example, client and server
|
||||
configurations in case of a TLS handshake) would not involve any GCM
|
||||
operations using a non-AES cipher, you can safely disable this config,
|
||||
leading to reduction in binary size footprint.
|
||||
|
||||
config MBEDTLS_HARDWARE_MPI
|
||||
bool "Enable hardware MPI (bignum) acceleration"
|
||||
default y
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 89cc7af4bb9cfaeac9c4aa08d1e8cf550fa0c155
|
||||
Subproject commit 09bba150d0d822aad2e58d71723f5407da5c21e0
|
@ -251,6 +251,27 @@ int esp_aes_gcm_setkey( esp_gcm_context *ctx,
|
||||
const unsigned char *key,
|
||||
unsigned int keybits )
|
||||
{
|
||||
/* Fallback to software implementation of GCM operation when a non-AES
|
||||
* cipher is selected, as we support hardware acceleration only for a
|
||||
* GCM operation using AES cipher.
|
||||
*/
|
||||
#if defined(MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK)
|
||||
if (ctx->ctx_soft != NULL) {
|
||||
mbedtls_gcm_free_soft(ctx->ctx_soft);
|
||||
free(ctx->ctx_soft);
|
||||
ctx->ctx_soft = NULL;
|
||||
}
|
||||
|
||||
if (cipher != MBEDTLS_CIPHER_ID_AES) {
|
||||
ctx->ctx_soft = (mbedtls_gcm_context_soft*) malloc(sizeof(mbedtls_gcm_context_soft));
|
||||
if (ctx->ctx_soft == NULL) {
|
||||
return MBEDTLS_ERR_CIPHER_ALLOC_FAILED;
|
||||
}
|
||||
mbedtls_gcm_init_soft(ctx->ctx_soft);
|
||||
return mbedtls_gcm_setkey_soft(ctx->ctx_soft, cipher, key, keybits);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !SOC_AES_SUPPORT_AES_192
|
||||
if (keybits == 192) {
|
||||
return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
|
||||
@ -332,6 +353,14 @@ void esp_aes_gcm_free( esp_gcm_context *ctx)
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
#if defined(MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK)
|
||||
if (ctx->ctx_soft != NULL) {
|
||||
mbedtls_gcm_free_soft(ctx->ctx_soft);
|
||||
free(ctx->ctx_soft);
|
||||
/* Note that the value of ctx->ctx_soft should be NULL'ed out
|
||||
and here it is taken care by the bzero call below */
|
||||
}
|
||||
#endif
|
||||
bzero(ctx, sizeof(esp_gcm_context));
|
||||
}
|
||||
|
||||
@ -341,6 +370,11 @@ int esp_aes_gcm_starts( esp_gcm_context *ctx,
|
||||
const unsigned char *iv,
|
||||
size_t iv_len )
|
||||
{
|
||||
#if defined(MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK)
|
||||
if (ctx->ctx_soft != NULL) {
|
||||
return mbedtls_gcm_starts_soft(ctx->ctx_soft, mode, iv, iv_len);
|
||||
}
|
||||
#endif
|
||||
/* IV is limited to 2^32 bits, so 2^29 bytes */
|
||||
/* IV is not allowed to be zero length */
|
||||
if ( iv_len == 0 ||
|
||||
@ -407,6 +441,11 @@ int esp_aes_gcm_update_ad( esp_gcm_context *ctx,
|
||||
const unsigned char *aad,
|
||||
size_t aad_len )
|
||||
{
|
||||
#if defined(MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK)
|
||||
if (ctx->ctx_soft != NULL) {
|
||||
return mbedtls_gcm_update_ad_soft(ctx->ctx_soft, aad, aad_len);
|
||||
}
|
||||
#endif
|
||||
/* AD are limited to 2^32 bits, so 2^29 bytes */
|
||||
if ( ( (uint32_t) aad_len ) >> 29 != 0 ) {
|
||||
return ( MBEDTLS_ERR_GCM_BAD_INPUT );
|
||||
@ -442,6 +481,11 @@ int esp_aes_gcm_update( esp_gcm_context *ctx,
|
||||
unsigned char *output, size_t output_size,
|
||||
size_t *output_length )
|
||||
{
|
||||
#if defined(MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK)
|
||||
if (ctx->ctx_soft != NULL) {
|
||||
return mbedtls_gcm_update_soft(ctx->ctx_soft, input, input_length, output, output_size, output_length);
|
||||
}
|
||||
#endif
|
||||
size_t nc_off = 0;
|
||||
uint8_t nonce_counter[AES_BLOCK_BYTES] = {0};
|
||||
uint8_t stream[AES_BLOCK_BYTES] = {0};
|
||||
@ -512,6 +556,11 @@ int esp_aes_gcm_finish( esp_gcm_context *ctx,
|
||||
size_t *output_length,
|
||||
unsigned char *tag, size_t tag_len )
|
||||
{
|
||||
#if defined(MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK)
|
||||
if (ctx->ctx_soft != NULL) {
|
||||
return mbedtls_gcm_finish_soft(ctx->ctx_soft, output, output_size, output_length, tag, tag_len);
|
||||
}
|
||||
#endif
|
||||
size_t nc_off = 0;
|
||||
uint8_t len_block[AES_BLOCK_BYTES] = {0};
|
||||
uint8_t stream[AES_BLOCK_BYTES] = {0};
|
||||
@ -607,6 +656,11 @@ int esp_aes_gcm_crypt_and_tag( esp_gcm_context *ctx,
|
||||
size_t tag_len,
|
||||
unsigned char *tag )
|
||||
{
|
||||
#if defined(MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK)
|
||||
if (ctx->ctx_soft != NULL) {
|
||||
return mbedtls_gcm_crypt_and_tag_soft(ctx->ctx_soft, mode, length, iv, iv_len, aad, aad_len, input, output, tag_len, tag);
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_MBEDTLS_HARDWARE_GCM
|
||||
int ret;
|
||||
lldesc_t aad_desc[2] = {};
|
||||
@ -727,6 +781,11 @@ int esp_aes_gcm_auth_decrypt( esp_gcm_context *ctx,
|
||||
const unsigned char *input,
|
||||
unsigned char *output )
|
||||
{
|
||||
#if defined(MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK)
|
||||
if (ctx->ctx_soft != NULL) {
|
||||
return mbedtls_gcm_auth_decrypt_soft(ctx->ctx_soft, length, iv, iv_len, aad, aad_len, tag, tag_len, input, output);
|
||||
}
|
||||
#endif
|
||||
int ret;
|
||||
unsigned char check_tag[16];
|
||||
size_t i;
|
||||
|
@ -42,6 +42,8 @@ typedef struct {
|
||||
const unsigned char *aad; /*!< The additional data. */
|
||||
esp_aes_context aes_ctx;
|
||||
esp_aes_gcm_state gcm_state;
|
||||
/* Software context needed for soft fallback for non-AES ciphers */
|
||||
void *ctx_soft;
|
||||
} esp_gcm_context;
|
||||
|
||||
|
||||
|
@ -155,6 +155,12 @@
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_HARDWARE_AES
|
||||
#define MBEDTLS_GCM_ALT
|
||||
#ifdef CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER
|
||||
/* Prefer hardware and fallback to software */
|
||||
#define MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK
|
||||
#else
|
||||
#undef MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* MBEDTLS_SHAxx_ALT to enable hardware SHA support
|
||||
|
81
components/mbedtls/port/include/mbedtls/gcm.h
Normal file
81
components/mbedtls/port/include/mbedtls/gcm.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include_next "mbedtls/gcm.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_GCM_ALT) && defined(MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK)
|
||||
|
||||
/**
|
||||
* When the MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK is defined, for non-AES GCM
|
||||
* operations we need to fallback to the software function definitions of the
|
||||
* mbedtls GCM layer.
|
||||
* Thus in this case we need declarations for the software funtions.
|
||||
* Please refer mbedtls/include/mbedtls/gcm.h for function documentations
|
||||
*/
|
||||
|
||||
void mbedtls_gcm_init_soft(mbedtls_gcm_context_soft *ctx);
|
||||
|
||||
|
||||
int mbedtls_gcm_setkey_soft(mbedtls_gcm_context_soft *ctx,
|
||||
mbedtls_cipher_id_t cipher,
|
||||
const unsigned char *key,
|
||||
unsigned int keybits);
|
||||
|
||||
int mbedtls_gcm_starts_soft(mbedtls_gcm_context_soft *ctx,
|
||||
int mode,
|
||||
const unsigned char *iv, size_t iv_len);
|
||||
|
||||
int mbedtls_gcm_update_ad_soft(mbedtls_gcm_context_soft *ctx,
|
||||
const unsigned char *add, size_t add_len);
|
||||
|
||||
int mbedtls_gcm_update_soft(mbedtls_gcm_context_soft *ctx,
|
||||
const unsigned char *input, size_t input_length,
|
||||
unsigned char *output, size_t output_size,
|
||||
size_t *output_length);
|
||||
|
||||
int mbedtls_gcm_finish_soft(mbedtls_gcm_context_soft *ctx,
|
||||
unsigned char *output, size_t output_size,
|
||||
size_t *output_length,
|
||||
unsigned char *tag, size_t tag_len);
|
||||
|
||||
|
||||
int mbedtls_gcm_crypt_and_tag_soft(mbedtls_gcm_context_soft *ctx,
|
||||
int mode,
|
||||
size_t length,
|
||||
const unsigned char *iv,
|
||||
size_t iv_len,
|
||||
const unsigned char *add,
|
||||
size_t add_len,
|
||||
const unsigned char *input,
|
||||
unsigned char *output,
|
||||
size_t tag_len,
|
||||
unsigned char *tag);
|
||||
|
||||
|
||||
int mbedtls_gcm_auth_decrypt_soft(mbedtls_gcm_context_soft *ctx,
|
||||
size_t length,
|
||||
const unsigned char *iv,
|
||||
size_t iv_len,
|
||||
const unsigned char *add,
|
||||
size_t add_len,
|
||||
const unsigned char *tag,
|
||||
size_t tag_len,
|
||||
const unsigned char *input,
|
||||
unsigned char *output);
|
||||
|
||||
void mbedtls_gcm_free_soft(mbedtls_gcm_context_soft *ctx);
|
||||
|
||||
#endif /* MBEDTLS_GCM_ALT && MBEDTLS_GCM_NON_AES_CIPHER_SOFT_FALLBACK*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
144
components/mbedtls/test_apps/main/test_gcm.c
Normal file
144
components/mbedtls/test_apps/main/test_gcm.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sys/param.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "mbedtls/gcm.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
|
||||
|
||||
#if CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER
|
||||
|
||||
typedef struct {
|
||||
uint8_t *plaintext;
|
||||
size_t plaintext_length;
|
||||
uint8_t *aad_buf;
|
||||
size_t aad_length;
|
||||
uint8_t *iv;
|
||||
size_t iv_length;
|
||||
uint8_t *key;
|
||||
size_t key_bits;
|
||||
size_t tag_len;
|
||||
} gcm_test_cfg_t;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *expected_tag;
|
||||
const uint8_t *ciphertext_last_block; // Last block of the ciphertext
|
||||
} gcm_test_expected_res_t;
|
||||
|
||||
typedef enum {
|
||||
GCM_TEST_CRYPT_N_TAG,
|
||||
GCM_TEST_START_UPDATE_FINISH,
|
||||
} gcm_test_type_t;
|
||||
|
||||
static void gcm_test(gcm_test_cfg_t *cfg, gcm_test_expected_res_t *res, gcm_test_type_t gcm_type)
|
||||
{
|
||||
mbedtls_gcm_context ctx;
|
||||
mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_ARIA;
|
||||
|
||||
uint8_t tag_buf_encrypt[16] = {};
|
||||
uint8_t tag_buf_decrypt[16] = {};
|
||||
uint8_t iv_buf[16] = {};
|
||||
uint8_t *ciphertext = malloc(cfg->plaintext_length);
|
||||
uint8_t *output = malloc(cfg->plaintext_length);
|
||||
size_t olen;
|
||||
|
||||
if (cfg->plaintext_length != 0) {
|
||||
TEST_ASSERT_NOT_NULL(ciphertext);
|
||||
TEST_ASSERT_NOT_NULL(output);
|
||||
}
|
||||
|
||||
memset(ciphertext, 0, cfg->plaintext_length);
|
||||
memset(output, 0, cfg->plaintext_length);
|
||||
memcpy(iv_buf, cfg->iv, cfg->iv_length);
|
||||
|
||||
mbedtls_gcm_init(&ctx);
|
||||
TEST_ASSERT(mbedtls_gcm_setkey(&ctx, cipher, cfg->key, cfg->key_bits) == 0);
|
||||
|
||||
if (gcm_type == GCM_TEST_CRYPT_N_TAG) {
|
||||
mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_GCM_ENCRYPT, cfg->plaintext_length, iv_buf, cfg->iv_length, cfg->aad_buf, cfg->aad_length, cfg->plaintext, ciphertext, cfg->tag_len, tag_buf_encrypt);
|
||||
} else if (gcm_type == GCM_TEST_START_UPDATE_FINISH) {
|
||||
TEST_ASSERT(mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_ENCRYPT, iv_buf, cfg->iv_length) == 0);
|
||||
TEST_ASSERT(mbedtls_gcm_update_ad(&ctx, cfg->aad_buf, cfg->aad_length) == 0);
|
||||
TEST_ASSERT(mbedtls_gcm_update(&ctx, cfg->plaintext, cfg->plaintext_length, ciphertext, cfg->plaintext_length, &olen) == 0);
|
||||
TEST_ASSERT(mbedtls_gcm_finish(&ctx, ciphertext, cfg->plaintext_length, &olen, tag_buf_encrypt, cfg->tag_len) == 0);
|
||||
}
|
||||
|
||||
size_t offset = cfg->plaintext_length > 16 ? cfg->plaintext_length - 16 : 0;
|
||||
/* Sanity check: make sure the last ciphertext block matches what we expect to see. */
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(res->ciphertext_last_block, ciphertext + offset, MIN(16, cfg->plaintext_length));
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(res->expected_tag, tag_buf_encrypt, cfg->tag_len);
|
||||
|
||||
|
||||
if (gcm_type == GCM_TEST_CRYPT_N_TAG) {
|
||||
TEST_ASSERT(mbedtls_gcm_auth_decrypt(&ctx, cfg->plaintext_length, iv_buf, cfg->iv_length, cfg->aad_buf, cfg->aad_length, res->expected_tag, cfg->tag_len, ciphertext, output) == 0);
|
||||
} else if (gcm_type == GCM_TEST_START_UPDATE_FINISH) {
|
||||
TEST_ASSERT(mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, iv_buf, cfg->iv_length) == 0);
|
||||
TEST_ASSERT(mbedtls_gcm_update_ad(&ctx, cfg->aad_buf, cfg->aad_length) == 0);
|
||||
TEST_ASSERT(mbedtls_gcm_update(&ctx, ciphertext, cfg->plaintext_length, output, cfg->plaintext_length, &olen) == 0);
|
||||
TEST_ASSERT(mbedtls_gcm_finish(&ctx, output, cfg->plaintext_length, &olen, tag_buf_decrypt, cfg->tag_len) == 0);
|
||||
|
||||
/* mbedtls_gcm_auth_decrypt already checks tag so only needed for GCM_TEST_START_UPDATE_FINISH */
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(res->expected_tag, tag_buf_decrypt, cfg->tag_len);
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(cfg->plaintext, output, cfg->plaintext_length);
|
||||
|
||||
mbedtls_gcm_free(&ctx);
|
||||
free(ciphertext);
|
||||
free(output);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("mbedtls ARIA GCM test", "[gcm]")
|
||||
{
|
||||
const unsigned SZ = 1600;
|
||||
uint8_t aad[16];
|
||||
uint8_t iv[16];
|
||||
uint8_t key[16];
|
||||
|
||||
const uint8_t expected_last_block[] = {
|
||||
0xbe, 0x96, 0xf1, 0x57, 0x34, 0x07, 0x3f, 0x9d,
|
||||
0x87, 0x6b, 0x39, 0x22, 0xe4, 0xef, 0xff, 0xf0,
|
||||
};
|
||||
const uint8_t expected_tag[] = {
|
||||
0xef, 0x4e, 0xa8, 0x24, 0x07, 0x65, 0x36, 0x12,
|
||||
0xb1, 0xde, 0x7e, 0x23, 0xda, 0xea, 0x7c, 0x6b,
|
||||
};
|
||||
|
||||
uint8_t *plaintext = malloc(SZ);
|
||||
TEST_ASSERT_NOT_NULL(plaintext);
|
||||
|
||||
memset(plaintext, 0xAA, SZ);
|
||||
memset(iv, 0xEE, 16);
|
||||
memset(key, 0x44, 16);
|
||||
memset(aad, 0x76, 16);
|
||||
|
||||
gcm_test_cfg_t cfg = {
|
||||
.plaintext = plaintext,
|
||||
.plaintext_length = SZ,
|
||||
.iv = iv,
|
||||
.iv_length = sizeof(iv),
|
||||
.key = key,
|
||||
.key_bits = 8 * sizeof(key),
|
||||
.aad_buf = aad,
|
||||
.aad_length = sizeof(aad),
|
||||
.tag_len = 16
|
||||
};
|
||||
|
||||
gcm_test_expected_res_t res = {
|
||||
.expected_tag = expected_tag,
|
||||
.ciphertext_last_block = expected_last_block,
|
||||
};
|
||||
|
||||
gcm_test(&cfg, &res, GCM_TEST_CRYPT_N_TAG);
|
||||
gcm_test(&cfg, &res, GCM_TEST_START_UPDATE_FINISH);
|
||||
free(plaintext);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MBEDTLS_GCM_SUPPORT_NON_AES_CIPHER */
|
Loading…
Reference in New Issue
Block a user