I have bluez 5.48 running on embedded device and I am able to connect Apple and Windows devices over the bluetooth. I have also been able to get Bluetooth pairing working using DisplayOnly custom agent which generates random pin/pass for pairing.
The embedded device has no Input/Output peripherals so I need to return fixed pin for all connections but for some reason I am not finding the right way to do it. So far I have created custom agent, registered it on dbus, which receives the calls RequestPinCode
and DisplayPasskey
(but they are set to return auto generated pins.)
here is code snippet from my set up
static void bluez_agent_method_call(GDBusConnection *con,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *method,
GVariant *params,
GDBusMethodInvocation *invocation,
void *userdata)
{
int pass;
int entered;
char *opath;
GVariant *p= g_dbus_method_invocation_get_parameters(invocation);
g_print("Agent method call: %s.%s()\n", interface, method);
if(!strcmp(method, "RequestPinCode")) {
;
}
else if(!strcmp(method, "DisplayPinCode")) {
;
}
else if(!strcmp(method, "RequestPasskey")) {
g_print("Getting the Pin from user: ");
fscanf(stdin, "%d", &pass);
g_print("\n");
g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", pass));
}
else if(!strcmp(method, "DisplayPasskey")) {
g_variant_get(params, "(ouq)", &opath, &pass, &entered);
cout << "== pass = " << pass << endl;
pass=1234; // Changing value here does not change the actual Pin for some reason.
cout << "== pass = " << pass << "opath = " << opath << endl;
g_dbus_method_invocation_return_value(invocation, NULL);
}
else if(!strcmp(method, "RequestConfirmation")) {
g_variant_get(params, "(ou)", &opath, &pass);
g_dbus_method_invocation_return_value(invocation, NULL);
}
else if(!strcmp(method, "RequestAuthorization")) {
;
}
else if(!strcmp(method, "AuthorizeService")) {
;
}
else if(!strcmp(method, "Cancel")) {
;
}
else
g_print("We should not come here, unknown method\n");
}
I tried changing the pass variable in DisplayPasskey function to set new pin but bluetooth still connects with the auto generated pin only.
I found this stack overflow question which is exactly what I need How to setup Bluez 5 to ask pin code during pairing and from the comments, there seems to be solution to return the fixed pins.
It would be great if somebody can provide me with some examples to return fix pin in DisplayPasskey
and RequestPinCode
functions.
The Bluetooth standard does not contain a fixed key association model. The standard does not use a PAKE (https://en.m.wikipedia.org/wiki/Password-authenticated_key_agreement) but a custom ad-hoc weaker protocol. The custom protocol used during passkey pairing is only secure for one time passkeys (in particular, a passive eavesdropper learns the passkey used after a successful pairing attempt and can also be brute forced in at most 20 pairing attempts).
BlueZ follows the Bluetooth standard, which says the passkey should be randomly generated. Therefore you cannot set your own fixed passkey. If you don't have the required I/O capabilities, you shall use the "Just Works" association model instead (which unfortunately does not give you MITM protection). If you want higher security by using a fixed passkey for MITM protection, you must implement your own security layer on top of the (insecure) Application layer. This is for example what Apple's Homekit does.
Please also see my post at https://stackoverflow.com/a/59282315.
This article is also worth reading that explains why a static passkey is insecure: https://insinuator.net/2021/10/change-your-ble-passkey-like-you-change-your-underwear/.