diff --git a/bumble/device.py b/bumble/device.py index 65eba878..21ca31df 100644 --- a/bumble/device.py +++ b/bumble/device.py @@ -2159,6 +2159,7 @@ class DeviceConfiguration: ) eatt_enabled: bool = False gatt_services: list[dict[str, Any]] = field(init=False) + smp_debug_mode: bool = False def __post_init__(self) -> None: self.gatt_services = [] @@ -2571,6 +2572,7 @@ def __init__( ), ), ) + self.smp_manager.debug_mode = self.config.smp_debug_mode self.l2cap_channel_manager.register_fixed_channel(smp.SMP_CID, self.on_smp_pdu) diff --git a/bumble/smp.py b/bumble/smp.py index 9d0bb7ca..0f400941 100644 --- a/bumble/smp.py +++ b/bumble/smp.py @@ -178,6 +178,16 @@ def from_booleans( SMP_CTKD_H7_LEBR_SALT = bytes.fromhex('000000000000000000000000746D7031') SMP_CTKD_H7_BRLE_SALT = bytes.fromhex('000000000000000000000000746D7032') +# Diffie-Hellman private / public key pair in Debug Mode (Core - Vol. 3, Part H) +SMP_DEBUG_KEY_PRIVATE = bytes.fromhex( + '3f49f6d4 a3c55f38 74c9b3e3 d2103f50 4aff607b eb40b799 5899b8a6 cd3c1abd' + ) +SMP_DEBUG_KEY_PUBLIC_X = bytes.fromhex( + '20b003d2 f297be2c 5e2c83a7 e9f9a5b9 eff49111 acf4fddb cc030148 0e359de6' + ) +SMP_DEBUG_KEY_PUBLIC_Y= bytes.fromhex( + 'dc809c49 652aeb6d 63329abf 5a52155c 766345c2 8fed3024 741c8ed0 1589d28b' + ) # fmt: on # pylint: enable=line-too-long # pylint: disable=invalid-name @@ -1919,6 +1929,7 @@ def __init__( self._ecc_key = None self.pairing_config_factory = pairing_config_factory self.session_proxy = Session + self.debug_mode = False def send_command(self, connection: Connection, command: SMP_Command) -> None: logger.debug( @@ -1965,6 +1976,13 @@ def on_smp_pdu(self, connection: Connection, pdu: bytes) -> None: @property def ecc_key(self) -> crypto.EccKey: + if self.debug_mode: + # Core - Vol 3, Part H: + # When the Security Manager is placed in a Debug mode it shall use the + # following Diffie-Hellman private / public key pair: + debug_key = crypto.EccKey.from_private_key_bytes(SMP_DEBUG_KEY_PRIVATE) + return debug_key + if self._ecc_key is None: self._ecc_key = crypto.EccKey.generate() assert self._ecc_key diff --git a/tests/smp_test.py b/tests/smp_test.py index f48c309b..f3b5e96f 100644 --- a/tests/smp_test.py +++ b/tests/smp_test.py @@ -24,7 +24,7 @@ from bumble import crypto, pairing, smp from bumble.core import AdvertisingData from bumble.crypto import EccKey, aes_cmac, ah, c1, f4, f5, f6, g2, h6, h7, s1 -from bumble.device import Device +from bumble.device import Device, DeviceConfiguration from bumble.hci import Address from bumble.pairing import LeRole, OobData, OobSharedData @@ -312,3 +312,17 @@ async def test_send_identity_address_command( actual_command = mock_method.call_args.args[0] assert actual_command.addr_type == expected_identity_address.address_type assert actual_command.bd_addr == expected_identity_address + + +@pytest.mark.asyncio +async def test_smp_debug_mode(): + config = DeviceConfiguration(smp_debug_mode=True) + device = Device(config=config) + + assert device.smp_manager.ecc_key.x == smp.SMP_DEBUG_KEY_PUBLIC_X + assert device.smp_manager.ecc_key.y == smp.SMP_DEBUG_KEY_PUBLIC_Y + + device.smp_manager.debug_mode = False + + assert not device.smp_manager.ecc_key.x == smp.SMP_DEBUG_KEY_PUBLIC_X + assert not device.smp_manager.ecc_key.y == smp.SMP_DEBUG_KEY_PUBLIC_Y