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);
return ltk;
}
-static GSList *get_ltk_info(GKeyFile *key_file, const char *peer,
+static struct smp_ltk_info *get_ltk_info(GKeyFile *key_file, const char *peer,
+ uint8_t bdaddr_type)
+{
+ DBG("%s", peer);
+
+ return get_ltk(key_file, peer, bdaddr_type, "LongTermKey");
+}
+
+static struct smp_ltk_info *get_slave_ltk_info(GKeyFile *key_file,
+ const char *peer,
uint8_t bdaddr_type)
{
struct smp_ltk_info *ltk;
- GSList *l = NULL;
DBG("%s", peer);
- ltk = get_ltk(key_file, peer, bdaddr_type, "LongTermKey");
- if (ltk)
- l = g_slist_append(l, ltk);
-
ltk = get_ltk(key_file, peer, bdaddr_type, "SlaveLongTermKey");
- if (ltk) {
+ if (ltk)
ltk->master = false;
- l = g_slist_append(l, ltk);
- }
- return l;
+ return ltk;
}
static struct irk_info *get_irk_info(GKeyFile *key_file, const char *peer,
GKeyFile *key_file;
#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
struct link_key_info *key_info = NULL;
- GSList *list, *ltk_info = NULL;
+ struct smp_ltk_info *ltk_info = NULL;
+ struct smp_ltk_info *slave_ltk_info = NULL;
+ GSList *list = NULL;
struct device_addr_type addr;
#else
struct link_key_info *key_info;
- GSList *list, *ltk_info;
+ struct smp_ltk_info *ltk_info;
+ struct smp_ltk_info *slave_ltk_info;
+ GSList *list;
#endif
struct irk_info *irk_info;
struct conn_param *param;
bdaddr_type = get_le_addr_type(key_file);
ltk_info = get_ltk_info(key_file, entry->d_name, bdaddr_type);
- ltks = g_slist_concat(ltks, ltk_info);
+ if (ltk_info)
+ ltks = g_slist_append(ltks, ltk_info);
+
+ slave_ltk_info = get_slave_ltk_info(key_file, entry->d_name,
+ bdaddr_type);
+ if (slave_ltk_info)
+ ltks = g_slist_append(ltks, slave_ltk_info);
irk_info = get_irk_info(key_file, entry->d_name, bdaddr_type);
if (irk_info)
ltks = g_slist_remove(ltks, ltk_info);
ltk_info = get_ltk_info(key_file,
idaddr, bdaddr_type);
- ltks = g_slist_concat(ltks, ltk_info);
+ if (ltk_info)
+ ltks = g_slist_append(ltks, ltk_info);
}
if (irk_info) {
device_set_bonded(device, BDADDR_BREDR);
}
- if (ltk_info) {
+ if (ltk_info || slave_ltk_info) {
device_set_paired(device, bdaddr_type);
device_set_bonded(device, bdaddr_type);
+
+ if (ltk_info)
+ device_set_ltk_enc_size(device,
+ ltk_info->enc_size);
+ else if (slave_ltk_info)
+ device_set_ltk_enc_size(device,
+ slave_ltk_info->enc_size);
}
free:
device_set_bonded(device, addr->type);
}
+ device_set_ltk_enc_size(device, ev->key.enc_size);
+
bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
}
struct csrk_info *local_csrk;
struct csrk_info *remote_csrk;
+ uint8_t ltk_enc_size;
sdp_list_t *tmp_records;
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];
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);
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);
bt_mode_t mode;
bt_gatt_cache_t gatt_cache;
+
+ uint8_t min_enc_key_size;
};
extern struct main_opts main_opts;
static const char *gatt_options[] = {
"Cache",
+ "MinEncKeySize",
NULL
};
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)
# 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
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;
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) {
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;
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;
}
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)
{
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);
/* Only use signed write if unencrypted */
if (signed_write) {
- security = bt_att_get_security(client->att);
+ security = bt_att_get_security(client->att, NULL);
opcode = security > BT_SECURITY_LOW ? BT_ATT_OP_WRITE_CMD :
BT_ATT_OP_SIGNED_WRITE_CMD;
} else
/* 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
if (!client)
return -1;
- return bt_att_get_security(client->att);
+ return bt_att_get_security(client->att, NULL);
}
#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
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;
process_read_by_type(op);
}
+static bool check_min_key_size(uint8_t min_size, uint8_t size)
+{
+ if (!min_size || !size)
+ return true;
+
+ return min_size <= size;
+}
+
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;
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 (security < 0)
+ return BT_ATT_ERROR_UNLIKELY;
- if (perm & BT_ATT_PERM_AUTHEN && security < BT_ATT_SECURITY_HIGH)
- return BT_ATT_ERROR_AUTHENTICATION;
+ if (perm & BT_ATT_PERM_SECURE) {
+ if (security < BT_ATT_SECURITY_FIPS)
+ return BT_ATT_ERROR_AUTHENTICATION;
- if (perm & BT_ATT_PERM_ENCRYPT && security < BT_ATT_SECURITY_MEDIUM)
- return BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION;
+ if (!check_min_key_size(server->min_enc_size, enc_size))
+ return BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE;
+ }
+
+ if (perm & BT_ATT_PERM_AUTHEN) {
+ if (security < BT_ATT_SECURITY_HIGH)
+ return BT_ATT_ERROR_AUTHENTICATION;
+
+ if (!check_min_key_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 (!check_min_key_size(server->min_enc_size, enc_size))
+ return BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE;
+ }
return 0;
}
}
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;
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);
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);
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;
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,