ukBaz / python-bluezero

A simple Python interface to Bluez
MIT License
395 stars 112 forks source link

Method to retrieve remote device path in StartNotify and StopNotify #401

Closed xzZero closed 11 months ago

xzZero commented 11 months ago

I'm working on a project where I want to know which device uses write, read and notify methods. As for ReadValue(dict options) and WriteValue(array{byte} value, dict options), the GATT server can retrieve device path through options. Is there a way for the GATT server to retrieve the device path of the device which invokes StartNotify() and StopNotify()?

ukBaz commented 11 months ago

I don't have time to look at this in detail right now. However I did a project that had four buttons and needed to know which one was activated. Take a look and let me know if you have questions still.

Be warned, it doesn't use Bluezero

https://ukbaz.github.io/howto/proj_big_btn.html

xzZero commented 11 months ago

Thanks for your quick reply and suggestion. As far as I know, in your project the device runs the python script is the GATT client, thus, it knows which GATT server (the Button) or address (with Dbus path) it writes to or gets notified from. What I want to achieve is in the opposite direction, where the GATT server knows the address of the GATT client to notify.

ukBaz commented 11 months ago

OK, I'm not sure I understand the question.

The code can see what devices are connected using the org.bluez.Device1 interface on D-Bus ObjectManager. The org.bluez.GattCharacteristic interface has a notifying property that is True, if notifications or indications on the characteristic are currently enabled. The setup is that the GATT server doesn't know which device it needs to notified. It just does the notification and the connected and notifying properties define if that device gets a notification.

Examples of monitoring changes in interfaces or properties are at: https://github.com/ukBaz/python-bluezero/blob/2b0aba891655bae44c1f281852d5669d5dc9db19/bluezero/adapter.py#L91-L103

xzZero commented 11 months ago

Sorry for the unclear question. I think you got it correctly, I want to design a GATT Server that it knows the address of which devices that use the read, write and notify methods. Thanks to bluez, for read and write methods, this can be done with options argument, but there's no such thing like that for notify. That's why I wonder if there's another way to do this.

At first, I wanted to go with LE Secure Connection paring/bonding by using secure- flags (secure-read, secure-write) for characteristics and authenticating the connections with a customized agent similar to simple-agent. However, I caught an issue that the pairing/bonding dialog would pop up everytime the client in iOS tries to issue a connection to the GATT Server (in Raspberry Pi 4) even if the client and the server was successfully bonded and the long term key was generated in the previous bonding/pairing. I raised an issue with bluez here.

Because of this, I decided to go with unauthenticated connection (without using paring/bonding) and applied an additional software encryption on top of the unauthenticated connection. The GATT server has a characteristic used for authentication (encrypted passcode for example). Whenever a right passcode is written to the server via this characteristic, the client will be able to access other characteristics. To sum up, I want to design a filter to prevent those clients that are not in the whitelist to access the server, which leads to the question I raised above.

Thanks for your time and constructive comments. Please let me if you know how to resolve the problem with the unexpected LE Secure Connection pairing/bonding dialog.

ukBaz commented 11 months ago

For the unwanted pairing request on ios, could it be the following issue? https://github.com/ukBaz/python-bluezero/issues/336

xzZero commented 11 months ago

No, in #336 the pairing dialog is sent repeatedly, and I already fixed it by disabling the battery plugin. But this issue is different, the pairing/bonding dialog would pop up just like 2 devices have never been paired, even if they was successfully paired. When I tracked down the btmon trace, the exchange of the Long Term Key was successful, but somehow the iOS device still requested for a new pairing. This also happens when I manually advertised a characteristic with secure-write and secure-read flags (the same issue happens also for encrypt- flags) in bluetoothctl. To avoid duplicates, could you have a look at this?

ukBaz commented 11 months ago

I have taken a look at the BlueZ issue you linked to and it seems similar to: https://github.com/bluez/bluez/issues/153

This looks like it is something more fundamental than a Bluezero issue so I'm not sure that I can help.

I'm not sure how actively issues on the BlueZ github repo are monitored. You might be better raising this on the BlueZ Slack http://www.bluez.org/contact/

xzZero commented 11 months ago

Thanks for suggestions, I'll try to raise the issue on bluez Slack. An interesting thing that I figured out recently is that the Local Signature Key and Remote Signature Key weren't generated for the iOS device despite the successful pairing/bonding and being able to connect and send/receive packets from each other. Below is the content of the info from /var/lib/bluetooth/<adapter address>/<remote device address>/info

Android:

[IdentityResolvingKey]
Key=99FE463029B3757BA52B3CF1CBF3DE21

[RemoteSignatureKey]
Key=7B2A1EDD02692198D0E2696ED0AC7FC4
Counter=0
Authenticated=true

[LocalSignatureKey]
Key=4D30B0B91F4A8F3B26DFEA9212E16FC3
Counter=0
Authenticated=true

[SlaveLongTermKey]
Key=32D173B88A2AF7B31FDD72AF2B0B9982
Authenticated=3
EncSize=16
EDiv=0
Rand=0

[General]
Name=
AddressType=public
SupportedTechnologies=LE;
Trusted=false
Blocked=false

[ServiceChanged]
CCC_LE=2

iOS:

[IdentityResolvingKey]
Key=BE56BC749F700F69C9B7C90EC59A3C87

[SlaveLongTermKey]
Key=B42A588FEB434F2937F6696519C0FD4D
Authenticated=3
EncSize=16
EDiv=0
Rand=0

[General]
Name=
AddressType=public
SupportedTechnologies=LE;
Trusted=false
Blocked=false

[ServiceChanged]
CCC_LE=2
xzZero commented 11 months ago

The re-pairing/re-bonding pop up is because the iOS device I connected to has less secure method (legacy bonding or no Man-In-The-Middle MITM). The solution is to disable LE Secure Connection btmgmt sc off (https://lore.kernel.org/all/7493ca64-e4e5-49bb-0d11-719dc212a6bc@jajcus.net/T/) and use encrypt- flags. Thank you so much @ukBaz for your wonderful support.