Discussion:
Attribute security permissions and CCC descriptors in shared/gatt-server.
Arman Uguray
2014-10-22 20:12:10 UTC
Permalink
Hi all,

I have some unresolved questions about two aspects of
shared/gatt-server and I thought it might be better to discuss them
before moving on with the related parts of the implementation.

*** 1. Who will be responsible for Attribute Permission checks? ***

These mainly come in play when the remote end wants to read or write
the value of a characteristic/descriptor. We currently have read &
write callbacks that get assigned by the upper-layer to a
characteristic/descriptor definition in shared/gatt-db. Since these
callbacks already handle the read/write it initially made sense to me
that this is where encryption/authentication/authorization permission
checks can be performed. I then realized that there are cases where we
may want to perform this check before we invoke the read/write
callback. For instance, the Prepare Write request requires attribute
permission checks to be performed, however (in the current design) we
wouldn't actually call the write callback until a subsequent Execute
Write request is received.

The main problem here is the fact that shared/att is designed to be
transport agnostic: it doesn't know whether the underlying connection
is AF_BLUETOOTH or something else, so it can't make assumptions on the
nature of the connection to obtain security level information. We
could add some sort of delegate callback to this end, perhaps
something like:

static uint8_t my_sec_handler(void *user_data)
{
....
return sec;
}
...
bt_att_register_security_handler(att, my_sec_handler);

And then bt_gatt_server can obtain the current security level like this:

uint8_t sec = bt_att_get_security_level(att);

where bt_att_get_security_level is implemented as:

static uint8_t bt_att_get_security_level(struct bt_att *att)
{
if (!att || !att->security_callback)
return 0;

return att->security_callback(att->security_data);
}


I'm mostly thinking out loud here; would something like this make sense?


*** 2. Is shared/gatt-server responsible for keeping track of Client
Characteristic Configuration descriptor states for each bonded client?
***

Currently, the descriptor read/write operations need to be handled by
the upper layer via the read/write callbacks anyway, since the
side-effects of a writing to a particular CCC descriptor need to be
implemented by the related profile. In the bonding case, the
read/write callbacks could determine what value to return and how to
cache the value on a per-device basis without shared/gatt-db having a
notion of "per-client CCC descriptors".

Does this make sense? If so, is there a point of keeping the "bdaddr_t
*bdaddr" arguments of gatt_db_read_t, gatt_db_write_t, gatt_db_read,
and gatt_db_write? Note that I'm currently passing NULL to all of
these calls for this parameter in shared/gatt-server, since bt_att
doesn't have a notion of a BD_ADDR.

Thanks,
Arman
Luiz Augusto von Dentz
2014-10-23 07:51:45 UTC
Permalink
Hi Arman,
Post by Arman Uguray
Hi all,
I have some unresolved questions about two aspects of
shared/gatt-server and I thought it might be better to discuss them
before moving on with the related parts of the implementation.
*** 1. Who will be responsible for Attribute Permission checks? ***
These mainly come in play when the remote end wants to read or write
the value of a characteristic/descriptor. We currently have read &
write callbacks that get assigned by the upper-layer to a
characteristic/descriptor definition in shared/gatt-db. Since these
callbacks already handle the read/write it initially made sense to me
that this is where encryption/authentication/authorization permission
checks can be performed. I then realized that there are cases where we
may want to perform this check before we invoke the read/write
callback. For instance, the Prepare Write request requires attribute
permission checks to be performed, however (in the current design) we
wouldn't actually call the write callback until a subsequent Execute
Write request is received.
I believe this should be handle by the db, perhaps with a dedicated
prepare function that should probably call a callback so the
implementation can really tell when a write is about to happen. The
weird thing here is that the gatt_db_add_characteristic take
permissions but never really use it for anything except in
gatt_db_get_attribute_permissions, I thought the idea would be to do
the permission checks with it or Im missing something.
Post by Arman Uguray
The main problem here is the fact that shared/att is designed to be
transport agnostic: it doesn't know whether the underlying connection
is AF_BLUETOOTH or something else, so it can't make assumptions on the
nature of the connection to obtain security level information. We
could add some sort of delegate callback to this end, perhaps
Then we should probably have some functions to set and get the
security level, but Im sure it needs to be a callback as it does not
looks like it gonna change without us noticing it, then we can
automatically check with security level against the permissions
provided by the profile when registering the characteristic.
Post by Arman Uguray
static uint8_t my_sec_handler(void *user_data)
{
....
return sec;
}
...
bt_att_register_security_handler(att, my_sec_handler);
uint8_t sec = bt_att_get_security_level(att);
static uint8_t bt_att_get_security_level(struct bt_att *att)
{
if (!att || !att->security_callback)
return 0;
return att->security_callback(att->security_data);
}
I'm mostly thinking out loud here; would something like this make sense?
*** 2. Is shared/gatt-server responsible for keeping track of Client
Characteristic Configuration descriptor states for each bonded client?
***
Currently, the descriptor read/write operations need to be handled by
the upper layer via the read/write callbacks anyway, since the
side-effects of a writing to a particular CCC descriptor need to be
implemented by the related profile. In the bonding case, the
read/write callbacks could determine what value to return and how to
cache the value on a per-device basis without shared/gatt-db having a
notion of "per-client CCC descriptors".
Well making gatt_db have the notion of CCC would make things a little
bit simpler for storing and reloading but it would probably force us
to rethink how the db access the values, perhaps the db could cache
CCC values per client so it could detect changes and send
notifications automatically whenever the profiles tell it values has
changed or when a write succeeds.
Post by Arman Uguray
Does this make sense? If so, is there a point of keeping the "bdaddr_t
*bdaddr" arguments of gatt_db_read_t, gatt_db_write_t, gatt_db_read,
and gatt_db_write? Note that I'm currently passing NULL to all of
these calls for this parameter in shared/gatt-server, since bt_att
doesn't have a notion of a BD_ADDR.
I guess this was inspired by Android, I would agree that if you
register a characteristic and set the permission properly then it does
not matter who is attempting to read/write as long as they are fulfill
the requirements it should be okay but perhaps Android have pushed the
notion of CCC up in the stack which force it to expose the remote
address. Anyway for unit test I will have to address it since that
will be using a socket pair, perhaps passing NULL is fine if we have
CCC caching but in case of Android I don't think we can do much about
it.
--
Luiz Augusto von Dentz
Vinícius Costa Gomes
2014-10-23 13:53:13 UTC
Permalink
Hi Luiz,

On Thu, Oct 23, 2014 at 5:51 AM, Luiz Augusto von Dentz
<luiz.dentz-***@public.gmane.org> wrote:

[...]
Post by Luiz Augusto von Dentz
Post by Arman Uguray
*** 2. Is shared/gatt-server responsible for keeping track of Client
Characteristic Configuration descriptor states for each bonded client?
***
Currently, the descriptor read/write operations need to be handled by
the upper layer via the read/write callbacks anyway, since the
side-effects of a writing to a particular CCC descriptor need to be
implemented by the related profile. In the bonding case, the
read/write callbacks could determine what value to return and how to
cache the value on a per-device basis without shared/gatt-db having a
notion of "per-client CCC descriptors".
Well making gatt_db have the notion of CCC would make things a little
bit simpler for storing and reloading but it would probably force us
to rethink how the db access the values, perhaps the db could cache
CCC values per client so it could detect changes and send
notifications automatically whenever the profiles tell it values has
changed or when a write succeeds.
Post by Arman Uguray
Does this make sense? If so, is there a point of keeping the "bdaddr_t
*bdaddr" arguments of gatt_db_read_t, gatt_db_write_t, gatt_db_read,
and gatt_db_write? Note that I'm currently passing NULL to all of
these calls for this parameter in shared/gatt-server, since bt_att
doesn't have a notion of a BD_ADDR.
I guess this was inspired by Android, I would agree that if you
register a characteristic and set the permission properly then it does
not matter who is attempting to read/write as long as they are fulfill
the requirements it should be okay but perhaps Android have pushed the
notion of CCC up in the stack which force it to expose the remote
address. Anyway for unit test I will have to address it since that
will be using a socket pair, perhaps passing NULL is fine if we have
CCC caching but in case of Android I don't think we can do much about
it.
Don't know if I am following correctly here. But I guess that even
that, we would
need to have a way for the profile to identify who is writing in the CCC.

For example, in a (imaginary) Temperature profile that the client may
choose the unit (degrees Celsius or Fahrenheit) that is used for
indications/notifications. Each client would receive a different
notification value depending on what's written on the CCC.

Another solution would be for the "view" of the database that the profile has
depends on the device "operating" (not a very good word, because a
operation may be something like receiving a notification) on it. Just thinking
out loud.
Post by Luiz Augusto von Dentz
--
Luiz Augusto von Dentz
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
Cheers,
--
Vinicius
Loading...