fix sending of Connection Result - Pending, request authentication if security level isn't enough

This commit is contained in:
matthias.ringwald@gmail.com 2014-01-17 09:30:07 +00:00
parent ea8b28d601
commit 34d2123c9e
4 changed files with 75 additions and 36 deletions

View File

@ -80,7 +80,11 @@ typedef enum {
* @praram enabled
*/
void gap_set_bondable_mode(int enabled);
gap_security_level_t gap_security_level_for_link_key_type(link_key_type_t link_key_type);
gap_security_level_t gap_security_level_for_connection(hci_connection_t * connection);
gap_security_level_t gap_security_level(hci_con_handle_t con_handle);
void gap_request_security_level(hci_con_handle_t con_handle, gap_security_level_t level);
#if defined __cplusplus

View File

@ -130,6 +130,7 @@ static hci_connection_t * create_connection_for_addr(bd_addr_t addr){
conn->con_handle = 0xffff;
conn->authentication_flags = AUTH_FLAGS_NONE;
conn->bonding_flags = 0;
conn->requested_security_level = LEVEL_0;
linked_item_set_user(&conn->timeout.item, conn);
conn->timeout.process = hci_connection_timeout_handler;
hci_connection_timestamp(conn);
@ -704,6 +705,16 @@ static void event_handler(uint8_t *packet, int size){
}
break;
case HCI_EVENT_AUTHENTICATION_COMPLETE:
handle = READ_BT_16(packet, 3);
conn = hci_connection_for_handle(handle);
if (!conn) break;
if (conn->bonding_flags->BONDING_REQUESTED){
gap_security_level_t level = gap_security_level_for_connection(conn);
hci_emit_security_level(handle, packet[2], level);
}
break;
#ifndef EMBEDDED
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
if (!hci_stack.remote_device_db) break;
@ -1220,63 +1231,70 @@ void hci_run(){
if (connection->state == RECEIVED_CONNECTION_REQUEST){
log_info("sending hci_accept_connection_request\n");
hci_send_cmd(&hci_accept_connection_request, connection->address, 1);
connection->state = ACCEPTED_CONNECTION_REQUEST;
hci_send_cmd(&hci_accept_connection_request, connection->address, 1);
return;
}
if (connection->authentication_flags & HANDLE_LINK_KEY_REQUEST){
log_info("responding to link key request\n");
connectionClearAuthenticationFlags(connection, HANDLE_LINK_KEY_REQUEST);
link_key_t link_key;
link_key_type_t link_key_type;
log_info("responding to link key request\n");
if ( hci_stack.bondable && hci_stack.remote_device_db && hci_stack.remote_device_db->get_link_key( &connection->address, &link_key, &link_key_type)){
if ( hci_stack.remote_device_db
&& hci_stack.remote_device_db->get_link_key( &connection->address, &link_key, &link_key_type)
&& gap_security_level_for_link_key_type(link_key_type) >= connection->requested_security_level){
connection->link_key_type = link_key_type;
hci_send_cmd(&hci_link_key_request_reply, connection->address, &link_key);
} else {
hci_send_cmd(&hci_link_key_request_negative_reply, connection->address);
}
connectionClearAuthenticationFlags(connection, HANDLE_LINK_KEY_REQUEST);
return;
}
if (connection->authentication_flags & HANDLE_PIN_CODE_REQUEST){
log_info("denying to pin request\n");
hci_send_cmd(&hci_pin_code_request_negative_reply, connection->address);
connectionClearAuthenticationFlags(connection, HANDLE_PIN_CODE_REQUEST);
hci_send_cmd(&hci_pin_code_request_negative_reply, connection->address);
return;
}
if (connection->authentication_flags & SEND_IO_CAPABILITIES_REPLY){
connectionClearAuthenticationFlags(connection, SEND_IO_CAPABILITIES_REPLY);
if (hci_stack.bondable && hci_stack.ssp_io_capability != SSP_IO_CAPABILITY_UNKNOWN){
hci_send_cmd(&hci_io_capability_request_reply, &connection->address, hci_stack.ssp_io_capability, NULL, hci_stack.ssp_authentication_requirement);
} else {
hci_send_cmd(&hci_io_capability_request_negative_reply, &connection->address, ERROR_CODE_PAIRING_NOT_ALLOWED);
}
connectionClearAuthenticationFlags(connection, SEND_IO_CAPABILITIES_REPLY);
return;
}
if (connection->authentication_flags & SEND_USER_CONFIRM_REPLY){
hci_send_cmd(&hci_user_confirmation_request_reply, &connection->address);
connectionClearAuthenticationFlags(connection, SEND_USER_CONFIRM_REPLY);
hci_send_cmd(&hci_user_confirmation_request_reply, &connection->address);
return;
}
if (connection->authentication_flags & SEND_USER_PASSKEY_REPLY){
hci_send_cmd(&hci_user_passkey_request_reply, &connection->address, 000000);
connectionClearAuthenticationFlags(connection, SEND_USER_PASSKEY_REPLY);
hci_send_cmd(&hci_user_passkey_request_reply, &connection->address, 000000);
return;
}
if (connection->bonding_flags & BONDING_REQUEST_REMOTE_FEATURES){
hci_send_cmd(&hci_read_remote_supported_features_command, connection->con_handle);
connection->bonding_flags &= ~BONDING_REQUEST_REMOTE_FEATURES;
hci_send_cmd(&hci_read_remote_supported_features_command, connection->con_handle);
return;
}
if (connection->bonding_flags & BONDING_DISCONNECT_SECURITY_BLOCK){
hci_send_cmd(&hci_disconnect, connection->con_handle, 0x0005); // authentication failure
connection->bonding_flags &= ~BONDING_DISCONNECT_SECURITY_BLOCK;
hci_send_cmd(&hci_disconnect, connection->con_handle, 0x0005); // authentication failure
return;
}
if (connection->bonding_flags & BONDING_SEND_AUTHENTICATE_REQUEST){
connection->bonding_flags &= ~BONDING_SEND_AUTHENTICATE_REQUEST;
hci_send_cmd(&hci_authentication_requested, connection->con_handle);
return;
}
}
@ -1747,41 +1765,53 @@ void gap_set_bondable_mode(int enable){
}
/**
* @brief get current security level
* @brief map link keys to security levels
*/
gap_security_level_t gap_security_level(hci_con_handle_t con_handle){
hci_connection_t * connection = hci_connection_for_handle(con_handle);
if (!connection) return LEVEL_0;
if ((connection->authentication_flags & CONNECTION_ENCRYPTED) == 0) return LEVEL_0;
switch (connection->link_key_type){
gap_security_level_t gap_security_level_for_link_key_type(link_key_type_t link_key_type){
switch (link_key_type){
case AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P256:
return LEVEL_4;
case COMBINATION_KEY:
case AUTHENTICATED_COMBINATION_KEY_GENERATED_FROM_P192:
return LEVEL_3;
case DEBUG_COMBINATION_KEY:
default:
return LEVEL_2;
}
}
gap_security_level_t gap_security_level_for_connection(hci_connection_t * connection){
if (!connection) return LEVEL_0;
if ((connection->authentication_flags & CONNECTION_ENCRYPTED) == 0) return LEVEL_0;
return gap_security_level_for_link_key_type(connection->link_key_type);
}
/**
* @brief get current security level
*/
gap_security_level_t gap_security_level(hci_con_handle_t con_handle){
hci_connection_t * connection = hci_connection_for_handle(con_handle);
if (!connection) return LEVEL_0;
return gap_security_level_for_connection(connection);
}
/**
* @brief request connection to device to
* @result GAP_AUTHENTICATION_RESULT
*/
void gap_request_security_level(hci_con_handle_t con_handle, gap_security_level_t level){
// hci_connection_t * connection = hci_connection_for_handle(con_handle);
// if (!connection){
// hci_emit_security_level(con_handle, ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, LEVEL_0);
// return;
// }
// gap_security_level_t current_level = gap_security_level(con_handle);
// if (ggap_security_level_t >= level){
// hci_emit_security_level(con_handle, 0, gap_security_level_t);
// return;
// }
// connection->bonding_flags |=
// magic!
hci_emit_security_level(con_handle, 0, level);
void gap_request_security_level(hci_con_handle_t con_handle, gap_security_level_t requested_level){
hci_connection_t * connection = hci_connection_for_handle(con_handle);
if (!connection){
hci_emit_security_level(con_handle, ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER, LEVEL_0);
return;
}
gap_security_level_t current_level = gap_security_level(con_handle);
log_info("gap_request_security_level %u, current level %u", requested_level, current_level);
if (current_level >= requested_level){
hci_emit_security_level(con_handle, 0, current_level);
return;
}
connection->requested_security_level = requested_level;
connection->bonding_flags |= BONDING_REQUESTED;
connection->bonding_flags |= BONDING_SEND_AUTHENTICATE_REQUEST;
}

View File

@ -233,10 +233,12 @@ typedef enum {
} CONNECTION_STATE;
typedef enum {
BONDING_REQUEST_REMOTE_FEATURES = 0x01,
BONDING_RECEIVED_REMOTE_FEATURES = 0x02,
BONDING_REMOTE_SUPPORTS_SSP = 0x04,
BONDING_REQUEST_REMOTE_FEATURES = 0x01,
BONDING_RECEIVED_REMOTE_FEATURES = 0x02,
BONDING_REMOTE_SUPPORTS_SSP = 0x04,
BONDING_DISCONNECT_SECURITY_BLOCK = 0x08,
BONDING_REQUESTED = 0x10,
BONDING_SEND_AUTHENTICATE_REQUEST = 0x20,
} bonding_flags_t;
typedef enum {
@ -261,6 +263,9 @@ typedef struct {
// bonding
bonding_flags_t bonding_flags;
// requested security level
gap_security_level_t requested_security_level;
//
link_key_type_t link_key_type;

View File

@ -496,7 +496,7 @@ void l2cap_run(void){
switch (channel->state){
case L2CAP_STATE_WAIT_CLIENT_ACCEPT_OR_REJECT:
if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND) {
if (channel->state_var & L2CAP_STATE_WAIT_AUTHENTICATION_RESULT) {
channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONN_RESP_PEND);
l2cap_send_signaling_packet(channel->handle, CONNECTION_RESPONSE, channel->remote_sig_id, 0, 0, 1, 0);
}