From 200f4687e06eb3b83a41759ca9abb9502d5b0429 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Thu, 19 Nov 2020 09:26:34 +0100 Subject: [PATCH] Bluetooth: host: Log security keys needed by sniffer Log the security keys that the sniffer needs in order to sucessfully decrypt the connection. This option allows the sniffer to work in the cases where enabling using the SMP debug keys is not wanted, either because it changes the way the peer behaves or is denied by the peer. It also enables the sniffer to decrypt a connection where the bond already exists. Signed-off-by: Joakim Andersson --- scripts/kconfig/hardened.csv | 1 + subsys/bluetooth/host/CMakeLists.txt | 6 +-- subsys/bluetooth/host/Kconfig | 11 +++++ subsys/bluetooth/host/hci_core.c | 66 ++++++++++++++++++++++++++-- subsys/bluetooth/host/hci_ecc.c | 4 ++ subsys/bluetooth/host/keys.c | 25 +++++++++++ subsys/bluetooth/host/keys.h | 2 + subsys/bluetooth/host/smp.c | 15 +++++++ 8 files changed, 123 insertions(+), 7 deletions(-) diff --git a/scripts/kconfig/hardened.csv b/scripts/kconfig/hardened.csv index 1f11da6af58..3c2b250ec3a 100644 --- a/scripts/kconfig/hardened.csv +++ b/scripts/kconfig/hardened.csv @@ -52,6 +52,7 @@ BT_DEBUG_SMP,n BT_OOB_DATA_FIXED,n BT_FIXED_PASSKEY,n BT_DEBUG_KEYS,n +BT_LOG_SNIFFER_INFO,n BT_USE_DEBUG_KEYS,n BT_STORE_DEBUG_KEYS,n BT_CONN_DISABLE_SECURITY,n diff --git a/subsys/bluetooth/host/CMakeLists.txt b/subsys/bluetooth/host/CMakeLists.txt index a56ff6b8c53..404011e7c69 100644 --- a/subsys/bluetooth/host/CMakeLists.txt +++ b/subsys/bluetooth/host/CMakeLists.txt @@ -76,9 +76,9 @@ if(CONFIG_BT_HCI_HOST) endif() endif() -if(CONFIG_BT_DEBUG_SMP OR CONFIG_BT_DEBUG_KEYS) - message(WARNING "One or both these options are enabled: - CONFIG_BT_DEBUG_SMP CONFIG_BT_DEBUG_KEYS. +if(CONFIG_BT_DEBUG_SMP OR CONFIG_BT_DEBUG_KEYS OR CONFIG_BT_LOG_SNIFFER_INFO) + message(WARNING "One of these options are enabled: + CONFIG_BT_DEBUG_SMP CONFIG_BT_DEBUG_KEYS CONFIG_BT_LOG_SNIFFER_INFO. Private security keys such as the LTK will be printed out, do not use in production." ) diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index afc82375bf1..326d7d1f347 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -754,6 +754,17 @@ config BT_DEBUG_SERVICE endif # BT_DEBUG +config BT_LOG_SNIFFER_INFO + bool "Bluetooth log information for sniffer" + help + This option enables the Bluetooth stack to log information such as + DH private key and LTK keys, which can be used by sniffers to decrypt + the connection without the use of Debug keys. + + WARNING: This option prints out private security keys such as + the Long Term Key. + Use of this feature in production is strongly discouraged + config BT_TESTING bool "Bluetooth Testing" help diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index f33884df645..93e29c1186c 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -664,7 +664,16 @@ static int le_set_private_addr(uint8_t id) } le_rpa_timeout_submit(); - return err; + + if (err) { + return err; + } + + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { + BT_INFO("RPA: %s", bt_addr_str(&rpa)); + } + + return 0; } static int le_adv_set_private_addr(struct bt_le_ext_adv *adv) @@ -711,7 +720,15 @@ static int le_adv_set_private_addr(struct bt_le_ext_adv *adv) le_rpa_timeout_submit(); } - return err; + if (err) { + return err; + } + + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { + BT_INFO("RPA: %s", bt_addr_str(&rpa)); + } + + return 0; } #else static int le_set_private_addr(uint8_t id) @@ -726,7 +743,16 @@ static int le_set_private_addr(uint8_t id) BT_ADDR_SET_NRPA(&nrpa); - return set_random_address(&nrpa); + err = set_random_address(&nrpa); + if (err) { + return err; + } + + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { + BT_INFO("NRPA: %s", bt_addr_str(&nrpa)); + } + + return 0; } static int le_adv_set_private_addr(struct bt_le_ext_adv *adv) @@ -741,7 +767,16 @@ static int le_adv_set_private_addr(struct bt_le_ext_adv *adv) BT_ADDR_SET_NRPA(&nrpa); - return set_adv_random_address(adv, &nrpa); + err = set_adv_random_address(adv, &nrpa); + if (err) { + return err; + } + + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { + BT_INFO("NRPA: %s", bt_addr_str(&nrpa)); + } + + return 0; } #endif /* defined(CONFIG_BT_PRIVACY) */ @@ -6017,9 +6052,32 @@ static void bt_dev_show_info(void) BT_INFO("Identity%s: %s", bt_dev.id_count > 1 ? "[0]" : "", bt_addr_le_str(&bt_dev.id_addr[0])); + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { +#if defined(CONFIG_BT_PRIVACY) + uint8_t irk[16]; + + sys_memcpy_swap(irk, bt_dev.irk[0], 16); + BT_INFO("IRK%s: 0x%s", bt_dev.id_count > 1 ? "[0]" : "", + bt_hex(irk, 16)); +#endif + } + for (i = 1; i < bt_dev.id_count; i++) { BT_INFO("Identity[%d]: %s", i, bt_addr_le_str(&bt_dev.id_addr[i])); + + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { +#if defined(CONFIG_BT_PRIVACY) + uint8_t irk[16]; + + sys_memcpy_swap(irk, bt_dev.irk[i], 16); + BT_INFO("IRK[%d]: 0x%s", i, bt_hex(irk, 16)); +#endif + } + } + + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { + bt_keys_foreach(BT_KEYS_ALL, bt_keys_show_sniffer_info, NULL); } BT_INFO("HCI: version %s (0x%02x) revision 0x%04x, manufacturer 0x%04x", diff --git a/subsys/bluetooth/host/hci_ecc.c b/subsys/bluetooth/host/hci_ecc.c index 517d9516a00..e8cd262d803 100644 --- a/subsys/bluetooth/host/hci_ecc.c +++ b/subsys/bluetooth/host/hci_ecc.c @@ -111,6 +111,10 @@ 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); + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { + BT_INFO("SC private key 0x%s", bt_hex(ecc.private_key_be, 32)); + } + return 0; } diff --git a/subsys/bluetooth/host/keys.c b/subsys/bluetooth/host/keys.c index 7560d722e7a..97869b908ab 100644 --- a/subsys/bluetooth/host/keys.c +++ b/subsys/bluetooth/host/keys.c @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -435,3 +436,27 @@ void bt_keys_update_usage(uint8_t id, const bt_addr_le_t *addr) } #endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */ + +#if defined(CONFIG_BT_LOG_SNIFFER_INFO) +void bt_keys_show_sniffer_info(struct bt_keys *keys, void *data) +{ + uint8_t ltk[16]; + + if (keys->keys & BT_KEYS_LTK_P256) { + sys_memcpy_swap(ltk, keys->ltk.val, keys->enc_size); + BT_INFO("SC LTK: 0x%s", bt_hex(ltk, keys->enc_size)); + } + + if (keys->keys & BT_KEYS_SLAVE_LTK) { + sys_memcpy_swap(ltk, keys->slave_ltk.val, keys->enc_size); + BT_INFO("Legacy LTK: 0x%s (peripheral)", + bt_hex(ltk, keys->enc_size)); + } + + if (keys->keys & BT_KEYS_LTK) { + sys_memcpy_swap(ltk, keys->ltk.val, keys->enc_size); + BT_INFO("Legacy LTK: 0x%s (central)", + bt_hex(ltk, keys->enc_size)); + } +} +#endif /* defined(CONFIG_BT_LOG_SNIFFER_INFO) */ diff --git a/subsys/bluetooth/host/keys.h b/subsys/bluetooth/host/keys.h index 0798bef3eca..e51329d68c4 100644 --- a/subsys/bluetooth/host/keys.h +++ b/subsys/bluetooth/host/keys.h @@ -124,3 +124,5 @@ void bt_keys_link_key_store(struct bt_keys_link_key *link_key); /* BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING is enabled */ void bt_keys_update_usage(uint8_t id, const bt_addr_le_t *addr); void bt_keys_link_key_update_usage(const bt_addr_t *addr); + +void bt_keys_show_sniffer_info(struct bt_keys *keys, void *data); diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 75020fd85b1..dfb9231ce41 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -1839,6 +1839,10 @@ static void smp_pairing_complete(struct bt_smp *smp, uint8_t status) #endif /* CONFIG_BT_BREDR */ bool bond_flag = atomic_test_bit(smp->flags, SMP_FLAG_BOND); + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { + bt_keys_show_sniffer_info(conn->le.keys, NULL); + } + if (bond_flag) { bt_keys_store(conn->le.keys); } @@ -2339,6 +2343,10 @@ static uint8_t legacy_request_tk(struct bt_smp *smp) passkey %= 1000000; } + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { + BT_INFO("Legacy passkey %u", passkey); + } + if (bt_auth && bt_auth->passkey_display) { atomic_set_bit(smp->flags, SMP_FLAG_DISPLAY); bt_auth->passkey_display(conn, passkey); @@ -5287,6 +5295,13 @@ int bt_smp_le_oob_set_tk(struct bt_conn *conn, const uint8_t *tk) return -EINVAL; } + if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { + uint8_t oob[16]; + + sys_memcpy_swap(oob, tk, 16); + BT_INFO("Legacy OOB data 0x%s", bt_hex(oob, 16)); + } + memcpy(smp->tk, tk, 16*sizeof(uint8_t)); legacy_user_tk_entry(smp);