From 4a25fb71369be03b39e5425e85153cabd5f93ad1 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Mon, 1 Feb 2021 13:57:18 +0100 Subject: [PATCH] Bluetooth: host: Remove dependency on host emulation for debug ECC keys Remove the depency on host emulation of ECC for the Use debug keys option. This allows the application to use debug keys without shifting the ECC from the controller to the host, which could potentially alter the behavior of the application and make debugging this way less useful. Signed-off-by: Joakim Andersson --- subsys/bluetooth/host/Kconfig | 1 - subsys/bluetooth/host/ecc.h | 11 ++++ subsys/bluetooth/host/hci_core.c | 81 ++++++++++++++++++++++--- subsys/bluetooth/host/hci_ecc.c | 100 ++++++++++++++++++------------- subsys/bluetooth/host/smp.c | 11 +--- 5 files changed, 141 insertions(+), 63 deletions(-) diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index de46fe3fd70..91594f70b53 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -429,7 +429,6 @@ config BT_FIXED_PASSKEY config BT_USE_DEBUG_KEYS bool "Enable Security Manager Debug Mode" - depends on BT_TINYCRYPT_ECC help This option places Security Manager in a Debug Mode. In this mode predefined Diffie-Hellman private/public key pair is used as described diff --git a/subsys/bluetooth/host/ecc.h b/subsys/bluetooth/host/ecc.h index 418f0361b49..29257e51ecd 100644 --- a/subsys/bluetooth/host/ecc.h +++ b/subsys/bluetooth/host/ecc.h @@ -21,6 +21,17 @@ struct bt_pub_key_cb { struct bt_pub_key_cb *_next; }; +/* @brief Check if public key is equal to the debug public key. + * + * Compare the Public key to the Bluetooth specification defined debug public + * key. + * + * @param pub_key The public key to compare. + * + * @return True if the public key is the debug public key. + */ +bool bt_pub_key_is_debug(uint8_t *pub_key); + /* @brief Generate a new Public Key. * * Generate a new ECC Public Key. The callback will persist even after the diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index bc1ceb2a8d3..69151061357 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -9312,6 +9312,24 @@ int bt_br_set_discoverable(bool enable) #endif /* CONFIG_BT_BREDR */ #if defined(CONFIG_BT_ECC) +static const uint8_t debug_public_key[64] = { + /* X */ + 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, + 0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef, + 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, + 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20, + /* Y */ + 0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74, + 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76, + 0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63, + 0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc +}; + +bool bt_pub_key_is_debug(uint8_t *pub_key) +{ + return memcmp(pub_key, debug_public_key, 64) == 0; +} + int bt_pub_key_gen(struct bt_pub_key_cb *new_cb) { int err; @@ -9328,6 +9346,16 @@ int bt_pub_key_gen(struct bt_pub_key_cb *new_cb) return -ENOTSUP; } + if (IS_ENABLED(CONFIG_BT_USE_DEBUG_KEYS)) { + if (!BT_CMD_TEST(bt_dev.supported_commands, 41, 2)) { + BT_WARN("ECC Debug keys HCI command not available"); + } else { + atomic_set_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY); + new_cb->func(debug_public_key); + return 0; + } + } + new_cb->_next = pub_key_cb; pub_key_cb = new_cb; @@ -9350,6 +9378,11 @@ int bt_pub_key_gen(struct bt_pub_key_cb *new_cb) const uint8_t *bt_pub_key_get(void) { + if (IS_ENABLED(CONFIG_BT_USE_DEBUG_KEYS) && + BT_CMD_TEST(bt_dev.supported_commands, 41, 2)) { + return debug_public_key; + } + if (atomic_test_bit(bt_dev.flags, BT_DEV_HAS_PUB_KEY)) { return pub_key; } @@ -9357,10 +9390,41 @@ const uint8_t *bt_pub_key_get(void) return NULL; } -int bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb) +static int hci_generate_dhkey_v1(const uint8_t *remote_pk) { struct bt_hci_cp_le_generate_dhkey *cp; struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_GENERATE_DHKEY, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + memcpy(cp->key, remote_pk, sizeof(cp->key)); + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_GENERATE_DHKEY, buf, NULL); +} + +static int hci_generate_dhkey_v2(const uint8_t *remote_pk, uint8_t key_type) +{ + struct bt_hci_cp_le_generate_dhkey_v2 *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_GENERATE_DHKEY_V2, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + memcpy(cp->key, remote_pk, sizeof(cp->key)); + cp->key_type = key_type; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_GENERATE_DHKEY_V2, buf, NULL); +} + +int bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb) +{ int err; if (dh_key_cb == cb) { @@ -9377,18 +9441,17 @@ int bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb) dh_key_cb = cb; - buf = bt_hci_cmd_create(BT_HCI_OP_LE_GENERATE_DHKEY, sizeof(*cp)); - if (!buf) { - dh_key_cb = NULL; - return -ENOBUFS; + if (IS_ENABLED(CONFIG_BT_USE_DEBUG_KEYS) && + BT_CMD_TEST(bt_dev.supported_commands, 41, 2)) { + err = hci_generate_dhkey_v2(remote_pk, + BT_HCI_LE_KEY_TYPE_DEBUG); + } else { + err = hci_generate_dhkey_v1(remote_pk); } - cp = net_buf_add(buf, sizeof(*cp)); - memcpy(cp->key, remote_pk, sizeof(cp->key)); - - err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_GENERATE_DHKEY, buf, NULL); if (err) { dh_key_cb = NULL; + BT_WARN("Failed to generate DHKey (err %d)", err); return err; } diff --git a/subsys/bluetooth/host/hci_ecc.c b/subsys/bluetooth/host/hci_ecc.c index 6db491ceb44..517d9516a00 100644 --- a/subsys/bluetooth/host/hci_ecc.c +++ b/subsys/bluetooth/host/hci_ecc.c @@ -46,21 +46,12 @@ static const uint8_t debug_private_key_be[32] = { 0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd, }; -#if defined(CONFIG_BT_USE_DEBUG_KEYS) -static const uint8_t debug_public_key[64] = { - 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, 0xdb, 0xfd, 0xf4, 0xac, - 0x11, 0x91, 0xf4, 0xef, 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, - 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20, 0x8b, 0xd2, 0x89, 0x15, - 0xd0, 0x8e, 0x1c, 0x74, 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76, - 0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63, 0x6d, 0xeb, 0x2a, 0x65, - 0x49, 0x9c, 0x80, 0xdc -}; -#endif - enum { PENDING_PUB_KEY, PENDING_DHKEY, + USE_DEBUG_KEY, + /* Total number of flags - must be at the end of the enum */ NUM_FLAGS, }; @@ -107,7 +98,6 @@ static void send_cmd_status(uint16_t opcode, uint8_t status) static uint8_t generate_keys(void) { -#if !defined(CONFIG_BT_USE_DEBUG_KEYS) do { int rc; @@ -120,11 +110,7 @@ static uint8_t generate_keys(void) /* make sure generated key isn't debug key */ } while (memcmp(ecc.private_key_be, debug_private_key_be, 32) == 0); -#else - sys_memcpy_swap(ecc.public_key_be, debug_public_key, 32); - sys_memcpy_swap(&ecc.public_key_be[32], &debug_public_key[32], 32); - memcpy(ecc.private_key_be, debug_private_key_be, 32); -#endif + return 0; } @@ -180,7 +166,11 @@ static void emulate_le_generate_dhkey(void) BT_ERR("public key is not valid (ret %d)", ret); ret = TC_CRYPTO_FAIL; } else { - ret = uECC_shared_secret(ecc.public_key_be, ecc.private_key_be, + bool use_debug = atomic_test_bit(flags, USE_DEBUG_KEY); + + ret = uECC_shared_secret(ecc.public_key_be, + use_debug ? debug_private_key_be : + ecc.private_key_be, ecc.dhkey_be, &curve_secp256r1); } @@ -240,40 +230,58 @@ static void clear_ecc_events(struct net_buf *buf) cmd->events[1] &= ~0x01; /* LE Generate DHKey Compl Event */ } -static void le_gen_dhkey(struct net_buf *buf) +static uint8_t le_gen_dhkey(uint8_t *key, uint8_t key_type) +{ + if (atomic_test_bit(flags, PENDING_PUB_KEY)) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + + if (key_type > BT_HCI_LE_KEY_TYPE_DEBUG) { + return BT_HCI_ERR_INVALID_PARAM; + } + + if (atomic_test_and_set_bit(flags, PENDING_DHKEY)) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + + /* Convert X and Y coordinates from little-endian HCI to + * big-endian (expected by the crypto API). + */ + sys_memcpy_swap(ecc.public_key_be, key, 32); + sys_memcpy_swap(&ecc.public_key_be[32], &key[32], 32); + + atomic_set_bit_to(flags, USE_DEBUG_KEY, + key_type == BT_HCI_LE_KEY_TYPE_DEBUG); + + k_sem_give(&cmd_sem); + + return BT_HCI_ERR_SUCCESS; +} + +static void le_gen_dhkey_v1(struct net_buf *buf) { struct bt_hci_cp_le_generate_dhkey *cmd; uint8_t status; - if (atomic_test_bit(flags, PENDING_PUB_KEY)) { - status = BT_HCI_ERR_CMD_DISALLOWED; - goto send_status; - } - - if (buf->len < sizeof(struct bt_hci_cp_le_generate_dhkey)) { - status = BT_HCI_ERR_INVALID_PARAM; - goto send_status; - } - - if (atomic_test_and_set_bit(flags, PENDING_DHKEY)) { - status = BT_HCI_ERR_CMD_DISALLOWED; - goto send_status; - } - cmd = (void *)buf->data; - /* Convert X and Y coordinates from little-endian HCI to - * big-endian (expected by the crypto API). - */ - sys_memcpy_swap(ecc.public_key_be, cmd->key, 32); - sys_memcpy_swap(&ecc.public_key_be[32], &cmd->key[32], 32); - k_sem_give(&cmd_sem); - status = BT_HCI_ERR_SUCCESS; + status = le_gen_dhkey(cmd->key, BT_HCI_LE_KEY_TYPE_GENERATED); -send_status: net_buf_unref(buf); send_cmd_status(BT_HCI_OP_LE_GENERATE_DHKEY, status); } +static void le_gen_dhkey_v2(struct net_buf *buf) +{ + struct bt_hci_cp_le_generate_dhkey_v2 *cmd; + uint8_t status; + + cmd = (void *)buf->data; + status = le_gen_dhkey(cmd->key, cmd->key_type); + + net_buf_unref(buf); + send_cmd_status(BT_HCI_OP_LE_GENERATE_DHKEY_V2, status); +} + static void le_p256_pub_key(struct net_buf *buf) { uint8_t status; @@ -304,7 +312,11 @@ int bt_hci_ecc_send(struct net_buf *buf) return 0; case BT_HCI_OP_LE_GENERATE_DHKEY: net_buf_pull(buf, sizeof(*chdr)); - le_gen_dhkey(buf); + le_gen_dhkey_v1(buf); + return 0; + case BT_HCI_OP_LE_GENERATE_DHKEY_V2: + net_buf_pull(buf, sizeof(*chdr)); + le_gen_dhkey_v2(buf); return 0; case BT_HCI_OP_LE_SET_EVENT_MASK: clear_ecc_events(buf); @@ -323,6 +335,8 @@ void bt_hci_ecc_supported_commands(uint8_t *supported_commands) supported_commands[34] |= BIT(1); /* LE Generate DH Key v1 */ supported_commands[34] |= BIT(2); + /* LE Generate DH Key v2 */ + supported_commands[41] |= BIT(2); } int default_CSPRNG(uint8_t *dst, unsigned int len) diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 8dd0740914b..f5321f8e2a0 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -236,15 +236,6 @@ static const uint8_t gen_method_sc[5 /* remote */][5 /* local */] = { }; #endif /* !CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY */ -static const uint8_t sc_debug_public_key[64] = { - 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, 0xdb, 0xfd, 0xf4, 0xac, - 0x11, 0x91, 0xf4, 0xef, 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, - 0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20, 0x8b, 0xd2, 0x89, 0x15, - 0xd0, 0x8e, 0x1c, 0x74, 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76, - 0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63, 0x6d, 0xeb, 0x2a, 0x65, - 0x49, 0x9c, 0x80, 0xdc -}; - #if defined(CONFIG_BT_BREDR) /* SMP over BR/EDR channel specific context */ struct bt_smp_br { @@ -4159,7 +4150,7 @@ static uint8_t smp_public_key(struct bt_smp *smp, struct net_buf *buf) memcpy(&smp->pkey[32], req->y, 32); /* mark key as debug if remote is using it */ - if (memcmp(smp->pkey, sc_debug_public_key, 64) == 0) { + if (bt_pub_key_is_debug(smp->pkey)) { BT_INFO("Remote is using Debug Public key"); atomic_set_bit(smp->flags, SMP_FLAG_SC_DEBUG_KEY);