mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-01 22:20:58 +00:00
basic pairing with key distribution and reconnects mostly works
This commit is contained in:
parent
c9af4d3f19
commit
311a7e6675
@ -93,11 +93,17 @@ typedef enum {
|
|||||||
#define SM_REASON_CONFIRM_VALUE_FAILED 0x04
|
#define SM_REASON_CONFIRM_VALUE_FAILED 0x04
|
||||||
#define SM_REASON_PAIRING_NOT_SUPPORTED 0x05
|
#define SM_REASON_PAIRING_NOT_SUPPORTED 0x05
|
||||||
#define SM_REASON_ENCRYPTION_KEY_SIZE 0x06
|
#define SM_REASON_ENCRYPTION_KEY_SIZE 0x06
|
||||||
|
#define SM_REASON_COMMAND_NOT_SUPPORTED 0x07
|
||||||
|
#define SM_REASON_UNSPECIFIED_REASON 0x08
|
||||||
|
#define SM_REASON_REPEATED_ATTEMPTS 0x09
|
||||||
|
// also, invalid parameters
|
||||||
|
// and reserved
|
||||||
|
|
||||||
typedef uint8_t key_t[16];
|
typedef uint8_t key_t[16];
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SM_STATE_IDLE,
|
SM_STATE_IDLE,
|
||||||
|
|
||||||
SM_STATE_C1_GET_RANDOM_A,
|
SM_STATE_C1_GET_RANDOM_A,
|
||||||
SM_STATE_C1_W4_RANDOM_A,
|
SM_STATE_C1_W4_RANDOM_A,
|
||||||
SM_STATE_C1_GET_RANDOM_B,
|
SM_STATE_C1_GET_RANDOM_B,
|
||||||
@ -107,6 +113,15 @@ typedef enum {
|
|||||||
SM_STATE_C1_GET_ENC_B,
|
SM_STATE_C1_GET_ENC_B,
|
||||||
SM_STATE_C1_W4_ENC_B,
|
SM_STATE_C1_W4_ENC_B,
|
||||||
SM_STATE_C1_SEND,
|
SM_STATE_C1_SEND,
|
||||||
|
|
||||||
|
SM_STATE_W4_LTK_REQUEST,
|
||||||
|
SM_STATE_W4_CONNECTION_ENCRYPTED,
|
||||||
|
|
||||||
|
SM_STATE_PH3_GET_RANDOM,
|
||||||
|
SM_STATE_PH3_W4_RANDOM,
|
||||||
|
SM_STATE_PH3_GET_DIV,
|
||||||
|
SM_STATE_PH3_W4_DIV,
|
||||||
|
|
||||||
} security_manager_state_t;
|
} security_manager_state_t;
|
||||||
|
|
||||||
static att_connection_t att_connection;
|
static att_connection_t att_connection;
|
||||||
@ -118,6 +133,13 @@ static uint8_t att_response_buffer[28];
|
|||||||
static key_t sm_persistent_er;
|
static key_t sm_persistent_er;
|
||||||
static key_t sm_persistent_ir;
|
static key_t sm_persistent_ir;
|
||||||
|
|
||||||
|
// derived from sm_persistent_ir
|
||||||
|
static key_t sm_persistent_dhk;
|
||||||
|
static key_t sm_persistent_irk;
|
||||||
|
|
||||||
|
// derived from sm_persistent_er
|
||||||
|
|
||||||
|
|
||||||
static uint16_t sm_response_handle = 0;
|
static uint16_t sm_response_handle = 0;
|
||||||
static uint16_t sm_response_size = 0;
|
static uint16_t sm_response_size = 0;
|
||||||
static uint8_t sm_response_buffer[28];
|
static uint8_t sm_response_buffer[28];
|
||||||
@ -148,10 +170,13 @@ static key_t sm_m_confirm;
|
|||||||
static uint8_t sm_preq[7];
|
static uint8_t sm_preq[7];
|
||||||
static uint8_t sm_pres[7];
|
static uint8_t sm_pres[7];
|
||||||
|
|
||||||
|
static key_t sm_stk;
|
||||||
|
|
||||||
static key_t sm_s_random;
|
static key_t sm_s_random;
|
||||||
static key_t sm_s_confirm;
|
static key_t sm_s_confirm;
|
||||||
|
|
||||||
static uint8_t sm_pairing_failed_reason = 0;
|
static uint8_t sm_pairing_failed_reason = 0;
|
||||||
|
static uint16_t sm_s_div;
|
||||||
|
|
||||||
// key distribution, slave sends
|
// key distribution, slave sends
|
||||||
static key_t sm_s_ltk;
|
static key_t sm_s_ltk;
|
||||||
@ -192,23 +217,6 @@ static void att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *pa
|
|||||||
|
|
||||||
// SECURITY MANAGER (SM) MATERIALIZES HERE
|
// SECURITY MANAGER (SM) MATERIALIZES HERE
|
||||||
|
|
||||||
void sm_init(){
|
|
||||||
// set some (BTstack default) ER and IR
|
|
||||||
int i;
|
|
||||||
for (i=0;i<16;i++){
|
|
||||||
sm_persistent_er[i] = 0x30 + i;
|
|
||||||
sm_persistent_ir[i] = 0x90 + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sm_set_er(key_t er){
|
|
||||||
memcpy(sm_persistent_er, er, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sm_set_ir(key_t ir){
|
|
||||||
memcpy(sm_persistent_ir, ir, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void swap128(uint8_t src[16], uint8_t dst[16]){
|
static inline void swap128(uint8_t src[16], uint8_t dst[16]){
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
@ -482,6 +490,8 @@ static void sm_run(void){
|
|||||||
switch (sm_state_responding){
|
switch (sm_state_responding){
|
||||||
case SM_STATE_C1_GET_RANDOM_A:
|
case SM_STATE_C1_GET_RANDOM_A:
|
||||||
case SM_STATE_C1_GET_RANDOM_B:
|
case SM_STATE_C1_GET_RANDOM_B:
|
||||||
|
case SM_STATE_PH3_GET_RANDOM:
|
||||||
|
case SM_STATE_PH3_GET_DIV:
|
||||||
hci_send_cmd(&hci_le_rand);
|
hci_send_cmd(&hci_le_rand);
|
||||||
sm_state_responding++;
|
sm_state_responding++;
|
||||||
return;
|
return;
|
||||||
@ -493,7 +503,7 @@ static void sm_run(void){
|
|||||||
buffer[0] = SM_CODE_PAIRING_CONFIRM;
|
buffer[0] = SM_CODE_PAIRING_CONFIRM;
|
||||||
memcpy(&buffer[1], sm_s_confirm, 16);
|
memcpy(&buffer[1], sm_s_confirm, 16);
|
||||||
l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
|
l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
|
||||||
sm_state_responding = SM_STATE_IDLE;
|
sm_state_responding = SM_STATE_W4_LTK_REQUEST;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -670,6 +680,46 @@ void sm_reset_tk(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sm_distribute_keys(){
|
||||||
|
|
||||||
|
// TODO: handle initiator case here
|
||||||
|
|
||||||
|
// distribute keys as requested by initiator
|
||||||
|
if (sm_key_distribution_set & SM_KEYDIST_ENC_KEY)
|
||||||
|
sm_send_encryption_information = 1;
|
||||||
|
sm_send_master_identification = 1;
|
||||||
|
if (sm_key_distribution_set & SM_KEYDIST_ID_KEY)
|
||||||
|
sm_send_identity_information = 1;
|
||||||
|
sm_send_identity_address_information = 1;
|
||||||
|
if (sm_key_distribution_set & SM_KEYDIST_SIGN)
|
||||||
|
sm_send_signing_identification = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_set_er(key_t er){
|
||||||
|
memcpy(sm_persistent_er, er, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_set_ir(key_t ir){
|
||||||
|
memcpy(sm_persistent_ir, ir, 16);
|
||||||
|
sm_dhk(sm_persistent_ir, sm_persistent_dhk);
|
||||||
|
sm_irk(sm_persistent_ir, sm_persistent_irk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_init(){
|
||||||
|
// set some (BTstack default) ER and IR
|
||||||
|
int i;
|
||||||
|
key_t er;
|
||||||
|
key_t ir;
|
||||||
|
for (i=0;i<16;i++){
|
||||||
|
er[i] = 0x30 + i;
|
||||||
|
ir[i] = 0x90 + i;
|
||||||
|
}
|
||||||
|
sm_set_er(er);
|
||||||
|
sm_set_ir(ir);
|
||||||
|
sm_state_responding = SM_STATE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// END OF SM
|
// END OF SM
|
||||||
|
|
||||||
// enable LE, setup ADV data
|
// enable LE, setup ADV data
|
||||||
@ -706,7 +756,8 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
|||||||
// TODO support private addresses
|
// TODO support private addresses
|
||||||
sm_s_addr_type = 0;
|
sm_s_addr_type = 0;
|
||||||
BD_ADDR_COPY(sm_s_address, hci_local_bd_addr());
|
BD_ADDR_COPY(sm_s_address, hci_local_bd_addr());
|
||||||
|
printf("Incoming connection, own address ");
|
||||||
|
print_bd_addr(sm_s_address);
|
||||||
// request security
|
// request security
|
||||||
sm_send_security_request = 1;
|
sm_send_security_request = 1;
|
||||||
|
|
||||||
@ -715,9 +766,23 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST:
|
case HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST:
|
||||||
// sm_s1(sm_tk, sm_m_random, sm_m_random, sm_s_ltk);
|
log_info("LTK Request, state %u", sm_state_responding);
|
||||||
// hci_send_cmd(&hci_le_long_term_key_request_reply, READ_BT_16(packet, 3), sm_s_ltk);
|
if (sm_state_responding == SM_STATE_W4_LTK_REQUEST){
|
||||||
hci_send_cmd(&hci_le_long_term_key_negative_reply, READ_BT_16(packet, 3));
|
// calculate STK
|
||||||
|
log_info("calculating STK");
|
||||||
|
sm_s1(sm_tk, sm_s_random, sm_m_random, sm_stk);
|
||||||
|
hci_send_cmd(&hci_le_long_term_key_request_reply, READ_BT_16(packet, 3), sm_stk);
|
||||||
|
sm_state_responding = SM_STATE_W4_CONNECTION_ENCRYPTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// re-establish previously used LTK using Rand and EDIV
|
||||||
|
log_info("recalculating LTK");
|
||||||
|
memcpy(sm_s_rand, &packet[5], 8);
|
||||||
|
sm_s_ediv = READ_BT_16(packet, 13);
|
||||||
|
sm_s_div = sm_div(sm_persistent_dhk, sm_s_rand, sm_s_ediv);
|
||||||
|
sm_ltk(sm_persistent_er, sm_s_div, sm_s_ltk);
|
||||||
|
hci_send_cmd(&hci_le_long_term_key_request_reply, READ_BT_16(packet, 3), sm_s_ltk);
|
||||||
|
sm_state_responding = SM_STATE_IDLE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -726,16 +791,10 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_EVENT_ENCRYPTION_CHANGE:
|
case HCI_EVENT_ENCRYPTION_CHANGE:
|
||||||
// distribute keys as requested by initiator
|
log_info("Connection encrypted");
|
||||||
// TODO: handle initiator case here
|
if (sm_state_responding == SM_STATE_W4_CONNECTION_ENCRYPTED) {
|
||||||
if (sm_key_distribution_set & SM_KEYDIST_ENC_KEY)
|
sm_state_responding = SM_STATE_PH3_GET_RANDOM;
|
||||||
sm_send_encryption_information = 1;
|
}
|
||||||
sm_send_master_identification = 1;
|
|
||||||
if (sm_key_distribution_set & SM_KEYDIST_ID_KEY)
|
|
||||||
sm_send_identity_information = 1;
|
|
||||||
sm_send_identity_address_information = 1;
|
|
||||||
if (sm_key_distribution_set & SM_KEYDIST_SIGN)
|
|
||||||
sm_send_signing_identification = 1;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_EVENT_DISCONNECTION_COMPLETE:
|
case HCI_EVENT_DISCONNECTION_COMPLETE:
|
||||||
@ -774,9 +833,29 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha
|
|||||||
|
|
||||||
// calculate s_confirm
|
// calculate s_confirm
|
||||||
sm_c1(sm_tk, sm_s_random, sm_preq, sm_pres, sm_m_addr_type, sm_s_addr_type, sm_m_address, sm_s_address, sm_s_confirm);
|
sm_c1(sm_tk, sm_s_random, sm_preq, sm_pres, sm_m_addr_type, sm_s_addr_type, sm_m_address, sm_s_address, sm_s_confirm);
|
||||||
|
|
||||||
// send s_confirm
|
// send s_confirm
|
||||||
sm_state_responding = SM_STATE_C1_SEND;
|
sm_state_responding = SM_STATE_C1_SEND;
|
||||||
break;
|
break;
|
||||||
|
case SM_STATE_PH3_W4_RANDOM:
|
||||||
|
memcpy(sm_s_rand, &packet[6], 8);
|
||||||
|
sm_state_responding = SM_STATE_PH3_GET_DIV;
|
||||||
|
break;
|
||||||
|
case SM_STATE_PH3_W4_DIV:
|
||||||
|
// use 16 bit from random value as div
|
||||||
|
sm_s_div = READ_NET_16(packet, 6);
|
||||||
|
|
||||||
|
// done
|
||||||
|
sm_state_responding = SM_STATE_IDLE;
|
||||||
|
|
||||||
|
// calculate EDIV and LTK
|
||||||
|
sm_s_ediv = sm_ediv(sm_persistent_dhk, sm_s_rand, sm_s_div);
|
||||||
|
sm_ltk(sm_persistent_er, sm_s_div, sm_s_ltk);
|
||||||
|
|
||||||
|
// distribute keys
|
||||||
|
sm_distribute_keys();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user