component/bt: Fixed the vulnerability released by Bluetooth org when using public key not check in the process of ECDH encryption.
1. Add the 100 times test when the private key is generated by the random number; 2. Add the bt components to the unit-test-app/config directory. 3. Added the bt unit test case to CI.
This commit is contained in:
parent
cf3e89c1b2
commit
fa8dc32800
12 changed files with 171 additions and 3 deletions
|
@ -1009,6 +1009,12 @@ UT_010_04:
|
||||||
- UT_T1_RMT
|
- UT_T1_RMT
|
||||||
- psram
|
- psram
|
||||||
|
|
||||||
|
UT_601_01:
|
||||||
|
<<: *unit_test_template
|
||||||
|
tags:
|
||||||
|
- ESP32_IDF
|
||||||
|
- UT_T1_1
|
||||||
|
|
||||||
IT_001_01:
|
IT_001_01:
|
||||||
<<: *test_template
|
<<: *test_template
|
||||||
tags:
|
tags:
|
||||||
|
|
|
@ -58,6 +58,8 @@ extern elliptic_curve_t curve_p256;
|
||||||
|
|
||||||
void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
|
void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
|
||||||
|
|
||||||
|
bool ECC_CheckPointIsInElliCur_P256(Point *p);
|
||||||
|
|
||||||
#define ECC_PointMult(q, p, n, keyLength) ECC_PointMult_Bin_NAF(q, p, n, keyLength)
|
#define ECC_PointMult(q, p, n, keyLength) ECC_PointMult_Bin_NAF(q, p, n, keyLength)
|
||||||
|
|
||||||
void p_256_init_curve(UINT32 keyLength);
|
void p_256_init_curve(UINT32 keyLength);
|
||||||
|
|
|
@ -240,4 +240,40 @@ void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength)
|
||||||
multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
|
multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ECC_CheckPointIsInElliCur_P256(Point *p)
|
||||||
|
{
|
||||||
|
/* y^2 % q */
|
||||||
|
DWORD y_y_q[KEY_LENGTH_DWORDS_P256] = {0x0};
|
||||||
|
/* x^2 % q */
|
||||||
|
DWORD x_x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
|
||||||
|
/* x % q */
|
||||||
|
DWORD x_q[KEY_LENGTH_DWORDS_P256] = {0x0};
|
||||||
|
/* x^2, To prevent overflow, the length of the x square here needs to
|
||||||
|
be expanded to two times the original one. */
|
||||||
|
DWORD x_x[2*KEY_LENGTH_DWORDS_P256] = {0x0};
|
||||||
|
/* y_y_q =(p->y)^2(mod q) */
|
||||||
|
multiprecision_mersenns_squa_mod(y_y_q, p->y, KEY_LENGTH_DWORDS_P256);
|
||||||
|
/* Calculate the value of p->x square, x_x = (p->x)^2 */
|
||||||
|
multiprecision_mult(x_x, p->x, p->x, KEY_LENGTH_DWORDS_P256);
|
||||||
|
/* The function of the elliptic curve is y^2 = x^3 - 3x + b (mod q) ==>
|
||||||
|
y^2 = (x^2 - 3)*x + b (mod q),
|
||||||
|
so we calculate the x^2 - 3 value here */
|
||||||
|
x_x[0] -= 3;
|
||||||
|
/* Using math relations. (a*b) % q = ((a%q)*(b%q)) % q ==>
|
||||||
|
(x^2 - 3)*x = (((x^2 - 3) % q) * x % q) % q */
|
||||||
|
multiprecision_fast_mod_P256(x_x_q, x_x);
|
||||||
|
/* x_x = x_x_q * x_q */
|
||||||
|
multiprecision_mult(x_x, x_x_q, p->x, KEY_LENGTH_DWORDS_P256);
|
||||||
|
/* x_q = x_x % q */
|
||||||
|
multiprecision_fast_mod_P256(x_q, x_x);
|
||||||
|
/* Save the result in x_x_q */
|
||||||
|
multiprecision_add_mod(x_x_q, x_q, curve_p256.b, KEY_LENGTH_DWORDS_P256);
|
||||||
|
/* compare the y_y_q and x_x_q, see if they are on a given elliptic curve. */
|
||||||
|
if (multiprecision_compare(y_y_q, x_x_q, KEY_LENGTH_DWORDS_P256)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "btm_int.h"
|
#include "btm_int.h"
|
||||||
#include "stack/l2c_api.h"
|
#include "stack/l2c_api.h"
|
||||||
#include "smp_int.h"
|
#include "smp_int.h"
|
||||||
|
#include "p_256_ecc_pp.h"
|
||||||
//#include "utils/include/bt_utils.h"
|
//#include "utils/include/bt_utils.h"
|
||||||
|
|
||||||
#if SMP_INCLUDED == TRUE
|
#if SMP_INCLUDED == TRUE
|
||||||
|
@ -668,6 +669,12 @@ void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
|
||||||
|
|
||||||
STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
|
STREAM_TO_ARRAY(p_cb->peer_publ_key.x, p, BT_OCTET32_LEN);
|
||||||
STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
|
STREAM_TO_ARRAY(p_cb->peer_publ_key.y, p, BT_OCTET32_LEN);
|
||||||
|
/* In order to prevent the x and y coordinates of the public key from being modified,
|
||||||
|
we need to check whether the x and y coordinates are on the given elliptic curve. */
|
||||||
|
if (!ECC_CheckPointIsInElliCur_P256((Point *)&p_cb->peer_publ_key)) {
|
||||||
|
SMP_TRACE_ERROR("%s, Invalid Public key.", __func__);
|
||||||
|
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
|
||||||
|
}
|
||||||
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
|
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
|
||||||
|
|
||||||
smp_wait_for_both_public_keys(p_cb, NULL);
|
smp_wait_for_both_public_keys(p_cb, NULL);
|
||||||
|
|
5
components/bt/test/component.mk
Normal file
5
components/bt/test/component.mk
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#
|
||||||
|
#Component Makefile
|
||||||
|
#
|
||||||
|
|
||||||
|
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
107
components/bt/test/test_smp.c
Normal file
107
components/bt/test/test_smp.c
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
Tests for the BLE SMP implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <esp_types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "freertos/xtensa_api.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "freertos/ringbuf.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
#include "esp_bt.h"
|
||||||
|
#include "esp_bt_main.h"
|
||||||
|
#include "esp_bt_device.h"
|
||||||
|
#include "esp_gap_ble_api.h"
|
||||||
|
|
||||||
|
#define TAG "ble_smp_test"
|
||||||
|
|
||||||
|
#define KEY_LENGTH_DWORDS_P256 8
|
||||||
|
|
||||||
|
typedef unsigned long DWORD;
|
||||||
|
typedef uint32_t UINT32;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DWORD x[KEY_LENGTH_DWORDS_P256];
|
||||||
|
DWORD y[KEY_LENGTH_DWORDS_P256];
|
||||||
|
DWORD z[KEY_LENGTH_DWORDS_P256];
|
||||||
|
} Point;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// curve's coefficients
|
||||||
|
DWORD a[KEY_LENGTH_DWORDS_P256];
|
||||||
|
DWORD b[KEY_LENGTH_DWORDS_P256];
|
||||||
|
|
||||||
|
//whether a is -3
|
||||||
|
int a_minus3;
|
||||||
|
|
||||||
|
// prime modulus
|
||||||
|
DWORD p[KEY_LENGTH_DWORDS_P256];
|
||||||
|
|
||||||
|
// Omega, p = 2^m -omega
|
||||||
|
DWORD omega[KEY_LENGTH_DWORDS_P256];
|
||||||
|
|
||||||
|
// base point, a point on E of order r
|
||||||
|
Point G;
|
||||||
|
|
||||||
|
} elliptic_curve_t;
|
||||||
|
|
||||||
|
extern void ECC_PointMult_Bin_NAF(Point *q, Point *p, DWORD *n, uint32_t keyLength);
|
||||||
|
extern bool ECC_CheckPointIsInElliCur_P256(Point *p);
|
||||||
|
extern void p_256_init_curve(UINT32 keyLength);
|
||||||
|
extern elliptic_curve_t curve_p256;
|
||||||
|
|
||||||
|
static void bt_rand(void *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (!len) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Reset the buf value to the fixed value.
|
||||||
|
memset(buf, 0x55, len);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)(len / sizeof(uint32_t)); i++) {
|
||||||
|
uint32_t rand = esp_random();
|
||||||
|
memcpy(buf + i*sizeof(uint32_t), &rand, sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ble_smp_public_key_check", "[ble_smp]")
|
||||||
|
{
|
||||||
|
/* We wait init finish 200ms here */
|
||||||
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||||
|
Point public_key;
|
||||||
|
DWORD private_key[KEY_LENGTH_DWORDS_P256] = {[0 ... (KEY_LENGTH_DWORDS_P256 - 1)] = 0x12345678};
|
||||||
|
p_256_init_curve(KEY_LENGTH_DWORDS_P256);
|
||||||
|
ECC_PointMult_Bin_NAF(&public_key, &(curve_p256.G), private_key, KEY_LENGTH_DWORDS_P256);
|
||||||
|
/* Check Is the public key generated by the system on the given elliptic curve */
|
||||||
|
TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key));
|
||||||
|
/* We simulate the attacker and set the y coordinate of the public key to 0. */
|
||||||
|
for (int i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
|
||||||
|
public_key.y[i] = 0x0;
|
||||||
|
}
|
||||||
|
/* At this point the public key should not be on the given elliptic curve. */
|
||||||
|
TEST_ASSERT(!ECC_CheckPointIsInElliCur_P256(&public_key));
|
||||||
|
/* Test whether the G point on the protocol is on a given elliptic curve */
|
||||||
|
TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&(curve_p256.G)));
|
||||||
|
/* test 100 times when the private key is generated by the random number. */
|
||||||
|
for (int j = 0; j < 100; j++) {
|
||||||
|
bt_rand(private_key, sizeof(DWORD)*KEY_LENGTH_DWORDS_P256);
|
||||||
|
ECC_PointMult_Bin_NAF(&public_key, &(curve_p256.G), private_key, KEY_LENGTH_DWORDS_P256);
|
||||||
|
/* Check Is the public key generated by the system on the given elliptic curve */
|
||||||
|
TEST_ASSERT(ECC_CheckPointIsInElliCur_P256(&public_key));
|
||||||
|
}
|
||||||
|
}
|
3
tools/unit-test-app/configs/bt
Normal file
3
tools/unit-test-app/configs/bt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
TEST_COMPONENTS=bt
|
||||||
|
CONFIG_BT_ENABLED=y
|
||||||
|
CONFIG_UNITY_FREERTOS_STACK_SIZE=12288
|
|
@ -1 +1 @@
|
||||||
EXCLUDE_COMPONENTS=libsodium
|
EXCLUDE_COMPONENTS=libsodium bt
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
TEST_COMPONENTS=libsodium
|
TEST_COMPONENTS=libsodium
|
||||||
|
EXCLUDE_COMPONENTS=bt
|
||||||
CONFIG_UNITY_FREERTOS_STACK_SIZE=12288
|
CONFIG_UNITY_FREERTOS_STACK_SIZE=12288
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
EXCLUDE_COMPONENTS=libsodium
|
EXCLUDE_COMPONENTS=libsodium bt
|
||||||
CONFIG_SPIRAM_SUPPORT=y
|
CONFIG_SPIRAM_SUPPORT=y
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
|
EXCLUDE_COMPONENTS=bt
|
||||||
CONFIG_OPTIMIZATION_LEVEL_RELEASE=y
|
CONFIG_OPTIMIZATION_LEVEL_RELEASE=y
|
||||||
CONFIG_OPTIMIZATION_ASSERTIONS_SILENT=y
|
CONFIG_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
EXCLUDE_COMPONENTS=libsodium
|
EXCLUDE_COMPONENTS=libsodium bt
|
||||||
CONFIG_MEMMAP_SMP=n
|
CONFIG_MEMMAP_SMP=n
|
||||||
CONFIG_FREERTOS_UNICORE=y
|
CONFIG_FREERTOS_UNICORE=y
|
||||||
|
|
Loading…
Reference in a new issue