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);