Commit 880384a2 authored by Johan Hedberg's avatar Johan Hedberg Committed by Benjamin Cabé
Browse files

Bluetooth: Host: SMP: Verify public key before usage

Add a separate test for public key validity. This needs to be done
synchronously so that we can respond with an early failure message to the
peer device.

Fixes #80218

Signed-off-by: default avatarJohan Hedberg <johan.hedberg@silabs.com>
parent 81ad6ecc
Loading
Loading
Loading
Loading
+32 −0
Changes for subsys/bluetooth/host/ecc.c: 32 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -7,9 +7,12 @@

#include <stdint.h>

#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/check.h>
#include <zephyr/bluetooth/hci.h>

#include <psa/crypto.h>

#include "ecc.h"
#include "hci_core.h"

@@ -39,6 +42,35 @@ bool bt_pub_key_is_debug(uint8_t *cmp_pub_key)
	return memcmp(cmp_pub_key, debug_public_key, BT_PUB_KEY_LEN) == 0;
}

bool bt_pub_key_is_valid(const uint8_t key[BT_PUB_KEY_LEN])
{
	uint8_t key_be[BT_PUB_KEY_LEN + 1];
	psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
	psa_status_t ret;
	psa_key_id_t handle;

	psa_set_key_type(&attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
	psa_set_key_bits(&attr, 256);
	psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DERIVE);
	psa_set_key_algorithm(&attr, PSA_ALG_ECDH);

	/* PSA expects secp256r1 public key to start with a predefined 0x04 byte */
	key_be[0] = 0x04;
	sys_memcpy_swap(&key_be[1], key, BT_PUB_KEY_COORD_LEN);
	sys_memcpy_swap(&key_be[1 + BT_PUB_KEY_COORD_LEN], &key[BT_PUB_KEY_COORD_LEN],
			BT_PUB_KEY_COORD_LEN);

	ret = psa_import_key(&attr, key_be, sizeof(key_be), &handle);
	psa_reset_key_attributes(&attr);

	if (ret == PSA_SUCCESS) {
		psa_destroy_key(handle);
		return true;
	}

	return false;
}

int bt_pub_key_gen(struct bt_pub_key_cb *new_cb)
{
	struct bt_pub_key_cb *cb;
+10 −0
Changes for subsys/bluetooth/host/ecc.h: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -44,6 +44,16 @@ struct bt_pub_key_cb {
 */
bool bt_pub_key_is_debug(uint8_t *cmp_pub_key);

/*  @brief Check if public key is valid.
 *
 *  Verify that the public key is valid, e.g. that its coordinates lie on the eliptic curve.
 *
 *  @param key The public key to validate.
 *
 *  @return True if the public key is valid.
 */
bool bt_pub_key_is_valid(const uint8_t key[BT_PUB_KEY_LEN]);

/*  @brief Generate a new Public Key.
 *
 *  Generate a new ECC Public Key. Provided cb must persists until callback
+3 −0
Changes for subsys/bluetooth/host/smp.c: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -4311,6 +4311,9 @@ static uint8_t smp_public_key(struct bt_smp *smp, struct net_buf *buf)
		if (!update_debug_keys_check(smp)) {
			return BT_SMP_ERR_AUTH_REQUIREMENTS;
		}
	} else if (!bt_pub_key_is_valid(smp->pkey)) {
		LOG_WRN("Received invalid public key");
		return BT_SMP_ERR_INVALID_PARAMS;
	}

	if (IS_ENABLED(CONFIG_BT_CENTRAL) &&