Add support for requiring min key size for access GATT characteristics
PATCH v3 1/1 Add support for requiring min key size for access GATT characteristics
This allows to configure bluetoothd to require minimum encryption key size when accessing GATT server characteristics. It is a global configuration option affecting whole GATT database.
--- peripheral/gatt.c | 2 +- src/adapter.c | 45 ++++++++++++++++++++++++++++++++------------- src/device.c | 15 +++++++++++++-- src/device.h | 1 + src/hcid.h | 2 ++ src/main.c | 17 ++++++++++++++--- src/main.conf | 5 +++++ src/shared/att.c | 22 +++++++++++++++++++--- src/shared/att.h | 3 ++- src/shared/gatt-client.c | 4 ++-- src/shared/gatt-server.c | 36 ++++++++++++++++++++++++++++-------- src/shared/gatt-server.h | 3 ++- tools/btgatt-server.c | 2 +- unit/test-gatt.c | 2 +- 14 files changed, 123 insertions(+), 36 deletions(-)
peripheral/gatt.c +1 -1
@@ -128,7 +128,7 @@ static struct gatt_conn *gatt_conn_new(int fd)bt_att_set_security (conn->att,BT_SECURITY_MEDIUM ); - conn->gatt =bt_gatt_server_new (gatt_db, conn->att, mtu); + conn->gatt =bt_gatt_server_new (gatt_db, conn->att, mtu,0 );if (!conn->gatt) {fprintf (stderr,"Failed to create GATT server\n" );bt_att_unref (conn->att);
src/adapter.c +32 -13
86 lines not on this page · raw message
src/device.c +13 -2
@@ -243,6 +243,7 @@ struct btd_device {struct csrk_info *local_csrk;struct csrk_info *remote_csrk; +uint8_t ltk_enc_size;sdp_list_t *tmp_records;
@@ -1460,6 +1461,12 @@ bool device_is_disconnecting(struct btd_device *device)return device->disconn_timer >0 ; } +void device_set_ltk_enc_size (struct btd_device *device,uint8_t enc_size) +{ + device->ltk_enc_size = enc_size; +bt_att_set_enc_key_size (device->att, device->ltk_enc_size); +} +static void device_set_auto_connect (struct btd_device *device,gboolean enable) {char addr[18 ];
@@ -4834,10 +4841,14 @@ static void gatt_server_init(struct btd_device *device, struct gatt_db *db)gatt_server_cleanup (device); - device->server =bt_gatt_server_new (db, device->att, device->att_mtu); -if (!device->server) + device->server =bt_gatt_server_new (db, device->att, device->att_mtu, + main_opts.min_enc_key_size); +if (!device->server) {error ("Failed to initialize bt_gatt_server" ); +return ; + } +bt_att_set_enc_key_size (device->att, device->ltk_enc_size);bt_gatt_server_set_debug (device->server, gatt_debug,NULL ,NULL ); }
src/device.h +1 -0
@@ -130,6 +130,7 @@ void device_add_connection(struct btd_device *dev, uint8_t bdaddr_type);void device_remove_connection (struct btd_device *device,uint8_t bdaddr_type);void device_request_disconnect (struct btd_device *device,DBusMessage *msg);bool device_is_disconnecting (struct btd_device *device); +void device_set_ltk_enc_size (struct btd_device *device,uint8_t enc_size);typedef void (*disconnect_watch ) (struct btd_device *device,gboolean removal,void *user_data);
src/hcid.h +2 -0
@@ -54,6 +54,8 @@ struct main_opts {bt_mode_t mode;bt_gatt_cache_t gatt_cache; + +uint8_t min_enc_key_size; };extern struct main_opts main_opts;
src/main.c +14 -3
@@ -103,6 +103,7 @@ static const char *policy_options[] = {static const char *gatt_options[] = {"Cache" , +"MinEncKeySize" ,NULL };
@@ -402,12 +403,22 @@ static void parse_config(GKeyFile *config)if (err) {g_clear_error (&err); main_opts.gatt_cache =BT_GATT_CACHE_ALWAYS ; -return ; + }else { + main_opts.gatt_cache =parse_gatt_cache (str); +g_free (str); } - main_opts.gatt_cache =parse_gatt_cache (str); + val =g_key_file_get_integer (config,"GATT" , +"MinEncKeySize" , &err); +if (err) { +DBG ("%s" , err->message); +g_clear_error (&err); + }else { +DBG ("MinEncKeySize=%d" , val); -g_free (str); +if (val >=7 && val <=16 ) + main_opts.min_enc_key_size = val; + } }static void init_defaults (void )
src/main.conf +5 -0
@@ -77,6 +77,11 @@ # Default: always #Cache = always +# Minimum required Encryption Key Size for accessing secured characteristics. +# Possible values: 0 and 7-16. 0 means don't care. +# Defaults to 0 +# MinEncKeySize = 0 + [Policy] # # The ReconnectUUIDs defines the set of remote services that should try
src/shared/att.c +19 -3
@@ -55,6 +55,7 @@ struct bt_att {struct io *io;bool io_on_l2cap;int io_sec_level;/* Only used for non-L2CAP */ +uint8_t enc_size;struct queue *req_queue;/* Queued ATT protocol requests */ struct att_send_op *pending_req;
@@ -602,7 +603,7 @@ static bool change_security(struct bt_att *att, uint8_t ecode)if (att->io_sec_level !=BT_ATT_SECURITY_AUTO )return false; - security =bt_att_get_security (att); + security =bt_att_get_security (att,NULL );if (ecode ==BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION && security <BT_ATT_SECURITY_MEDIUM ) {
@@ -1454,7 +1455,7 @@ bool bt_att_unregister_all(struct bt_att *att)return true; } -int bt_att_get_security (struct bt_att *att) +int bt_att_get_security (struct bt_att *att,uint8_t *enc_size) {struct bt_security sec;socklen_t len;
@@ -1462,14 +1463,21 @@ int bt_att_get_security(struct bt_att *att)if (!att)return -EINVAL ; -if (!att->io_on_l2cap) +if (!att->io_on_l2cap) { +if (enc_size) + *enc_size = att->enc_size; +return att->io_sec_level; + }memset (&sec,0 ,sizeof (sec)); len =sizeof (sec);if (getsockopt (att->fd,SOL_BLUETOOTH ,BT_SECURITY , &sec, &len) <0 )return -EIO ; +if (enc_size) + *enc_size = att->enc_size; +return sec.level; }
@@ -1496,6 +1504,14 @@ bool bt_att_set_security(struct bt_att *att, int level)return true; } +void bt_att_set_enc_key_size (struct bt_att *att,uint8_t enc_size) +{ +if (!att) +return ; + + att->enc_size = enc_size; +} +static bool sign_set_key (struct sign_info **sign,uint8_t key[16 ],bt_att_counter_func_t func,void *user_data) {
src/shared/att.h +2 -1
@@ -84,8 +84,9 @@ bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id);bool bt_att_unregister_all (struct bt_att *att); -int bt_att_get_security (struct bt_att *att); +int bt_att_get_security (struct bt_att *att,uint8_t *enc_size);bool bt_att_set_security (struct bt_att *att,int level); +void bt_att_set_enc_key_size (struct bt_att *att,uint8_t enc_size);bool bt_att_set_local_key (struct bt_att *att,uint8_t sign_key[16 ],bt_att_counter_func_t func,void *user_data);
src/shared/gatt-client.c +2 -2
@@ -2466,7 +2466,7 @@ unsigned int bt_gatt_client_write_without_response(/* Only use signed write if unencrypted */ if (signed_write) { - security =bt_att_get_security (client->att); + security =bt_att_get_security (client->att,NULL ); op = security >BT_SECURITY_LOW ?BT_ATT_OP_WRITE_CMD :BT_ATT_OP_SIGNED_WRITE_CMD ; }else
@@ -3182,5 +3182,5 @@ int bt_gatt_client_get_security(struct bt_gatt_client *client)if (!client)return -1 ; -return bt_att_get_security (client->att); +return bt_att_get_security (client->att,NULL ); }
src/shared/gatt-server.c +28 -8
@@ -103,6 +103,8 @@ struct bt_gatt_server {unsigned int prep_write_id;unsigned int exec_write_id; +uint8_t min_enc_size; +struct queue *prep_queue;unsigned int max_prep_queue_len;
@@ -382,6 +384,7 @@ done:static uint8_t check_permissions (struct bt_gatt_server *server,struct gatt_db_attribute *attr,uint32_t mask) { +uint8_t enc_size;uint32_t perm;int security;
@@ -397,15 +400,30 @@ static uint8_t check_permissions(struct bt_gatt_server *server,if (!perm)return 0 ; - security =bt_att_get_security (server->att); -if (perm &BT_ATT_PERM_SECURE && security <BT_ATT_SECURITY_FIPS ) -return BT_ATT_ERROR_AUTHENTICATION ; + security =bt_att_get_security (server->att, &enc_size); +if (perm &BT_ATT_PERM_SECURE ) { +if (security <BT_ATT_SECURITY_FIPS ) +return BT_ATT_ERROR_AUTHENTICATION ; + +if (server->min_enc_size && server->min_enc_size > enc_size) +return BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE ; + } -if (perm &BT_ATT_PERM_AUTHEN && security <BT_ATT_SECURITY_HIGH ) -return BT_ATT_ERROR_AUTHENTICATION ; +if (perm &BT_ATT_PERM_AUTHEN ) { +if (security <BT_ATT_SECURITY_HIGH ) +return BT_ATT_ERROR_AUTHENTICATION ; -if (perm &BT_ATT_PERM_ENCRYPT && security <BT_ATT_SECURITY_MEDIUM ) -return BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION ; +if (server->min_enc_size && server->min_enc_size > enc_size) +return BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE ; + } + +if (perm &BT_ATT_PERM_ENCRYPT ) { +if (security <BT_ATT_SECURITY_MEDIUM ) +return BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION ; + +if (server->min_enc_size && server->min_enc_size > enc_size) +return BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE ; + }return 0 ; }
@@ -1481,7 +1499,8 @@ static bool gatt_server_register_att_handlers(struct bt_gatt_server *server) }struct bt_gatt_server *bt_gatt_server_new (struct gatt_db *db, -struct bt_att *att,uint16_t mtu) +struct bt_att *att,uint16_t mtu, +uint8_t min_enc_size) {struct bt_gatt_server *server;
@@ -1494,6 +1513,7 @@ struct bt_gatt_server *bt_gatt_server_new(struct gatt_db *db, server->mtu =MAX (mtu,BT_ATT_DEFAULT_LE_MTU ); server->max_prep_queue_len =DEFAULT_MAX_PREP_QUEUE_LEN ; server->prep_queue =queue_new (); + server->min_enc_size = min_enc_size;if (!gatt_server_register_att_handlers (server)) {bt_gatt_server_free (server);
src/shared/gatt-server.h +2 -1
@@ -26,7 +26,8 @@struct bt_gatt_server ;struct bt_gatt_server *bt_gatt_server_new (struct gatt_db *db, -struct bt_att *att,uint16_t mtu); +struct bt_att *att,uint16_t mtu, +uint8_t min_enc_size);uint16_t bt_gatt_server_get_mtu (struct bt_gatt_server *server);struct bt_gatt_server *bt_gatt_server_ref (struct bt_gatt_server *server);
tools/btgatt-server.c +1 -1
@@ -583,7 +583,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible) goto fail; } - server->gatt =bt_gatt_server_new (server->db, server->att, mtu); + server->gatt =bt_gatt_server_new (server->db, server->att, mtu,0 );if (!server->gatt) {fprintf (stderr,"Failed to create GATT server\n" ); goto fail;
unit/test-gatt.c +1 -1
@@ -667,7 +667,7 @@ static struct context *create_context(uint16_t mtu, gconstpointer data)g_assert (context->server_db); context->server =bt_gatt_server_new (context->server_db, - context->att, mtu); + context->att, mtu,0 );g_assert (context->server); bt_gatt_server_set_debug(context->server, print_debug,
Signature · 1 line
2.14.3