update FSM state before sending an HCI command or L2CAP packet to avoid theoretical race-condition of response arriving before state was updated

This commit is contained in:
matthias.ringwald@gmail.com 2014-10-16 15:02:48 +00:00
parent aadd57f4bc
commit 254e71e6e7

118
ble/sm.c
View File

@ -707,14 +707,13 @@ int sm_cmac_ready(){
static void sm_cmac_handle_aes_engine_ready(){
switch (sm_cmac_state){
case CMAC_CALC_SUBKEYS:
{
case CMAC_CALC_SUBKEYS: {
sm_key_t const_zero;
memset(const_zero, 0, 16);
sm_aes128_start(sm_cmac_k, const_zero);
sm_cmac_next_state();
sm_aes128_start(sm_cmac_k, const_zero);
break;
}
}
case CMAC_CALC_MI: {
int j;
sm_key_t y;
@ -722,8 +721,8 @@ static void sm_cmac_handle_aes_engine_ready(){
y[j] = sm_cmac_x[j] ^ sm_cmac_message[sm_cmac_block_current*16 + j];
}
sm_cmac_block_current++;
sm_aes128_start(sm_cmac_k, y);
sm_cmac_next_state();
sm_aes128_start(sm_cmac_k, y);
break;
}
case CMAC_CALC_MLAST: {
@ -734,8 +733,8 @@ static void sm_cmac_handle_aes_engine_ready(){
}
log_key("Y", y);
sm_cmac_block_current++;
sm_aes128_start(sm_cmac_k, y);
sm_cmac_next_state();
sm_aes128_start(sm_cmac_k, y);
break;
}
default:
@ -870,25 +869,26 @@ static void sm_run(void){
switch (dkg_state){
case DKG_CALC_IRK:
// already busy?
if (sm_aes128_state == SM_AES128_ACTIVE) break;
{
// IRK = d1(IR, 1, 0)
sm_key_t d1_prime;
sm_d1_d_prime(1, 0, d1_prime); // plaintext
sm_aes128_start(sm_persistent_ir, d1_prime);
dkg_next_state();
if (sm_aes128_state == SM_AES128_IDLE) {
// IRK = d1(IR, 1, 0)
sm_key_t d1_prime;
sm_d1_d_prime(1, 0, d1_prime); // plaintext
dkg_next_state();
sm_aes128_start(sm_persistent_ir, d1_prime);
return;
}
break;
case DKG_CALC_DHK:
// already busy?
if (sm_aes128_state == SM_AES128_ACTIVE) break;
{
// DHK = d1(IR, 3, 0)
sm_key_t d1_prime;
sm_d1_d_prime(3, 0, d1_prime); // plaintext
sm_aes128_start(sm_persistent_ir, d1_prime);
dkg_next_state();
if (sm_aes128_state == SM_AES128_IDLE) {
// DHK = d1(IR, 3, 0)
sm_key_t d1_prime;
sm_d1_d_prime(3, 0, d1_prime); // plaintext
dkg_next_state();
sm_aes128_start(sm_persistent_ir, d1_prime);
return;
}
return;
break;
default:
break;
}
@ -896,23 +896,23 @@ static void sm_run(void){
// random address updates
switch (rau_state){
case RAU_GET_RANDOM:
hci_send_cmd(&hci_le_rand);
rau_next_state();
hci_send_cmd(&hci_le_rand);
return;
case RAU_GET_ENC:
// already busy?
if (sm_aes128_state == SM_AES128_ACTIVE) break;
{
sm_key_t r_prime;
sm_ah_r_prime(sm_random_address, r_prime);
sm_aes128_start(sm_persistent_irk, r_prime);
rau_next_state();
if (sm_aes128_state == SM_AES128_IDLE) {
sm_key_t r_prime;
sm_ah_r_prime(sm_random_address, r_prime);
rau_next_state();
sm_aes128_start(sm_persistent_irk, r_prime);
return;
}
return;
break;
case RAU_SET_ADDRESS:
log_info("New random address: %s", bd_addr_to_str(sm_random_address));
hci_send_cmd(&hci_le_set_random_address, sm_random_address);
rau_state = RAU_IDLE;
hci_send_cmd(&hci_le_set_random_address, sm_random_address);
return;
default:
break;
@ -951,8 +951,8 @@ static void sm_run(void){
sm_key_t r_prime;
sm_ah_r_prime(sm_central_device_address, r_prime);
sm_aes128_start(irk, r_prime);
sm_central_ah_calculation_active = 1;
sm_aes128_start(irk, r_prime);
return;
}
@ -986,9 +986,9 @@ static void sm_run(void){
// initiator side
case SM_INITIATOR_PH1_SEND_PAIRING_REQUEST:
setup->sm_m_preq.code = SM_CODE_PAIRING_REQUEST;
connection->sm_engine_state = SM_INITIATOR_PH1_W4_PAIRING_RESPONSE;
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) &setup->sm_m_preq, sizeof(sm_pairing_packet_t));
sm_2timeout_reset();
connection->sm_engine_state = SM_INITIATOR_PH1_W4_PAIRING_RESPONSE;
break;
// responder side
@ -997,8 +997,8 @@ static void sm_run(void){
uint8_t buffer[2];
buffer[0] = SM_CODE_SECURITY_REQUEST;
buffer[1] = SM_AUTHREQ_BONDING;
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
connection->sm_engine_state = SM_GENERAL_IDLE;
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
return;
}
@ -1009,27 +1009,27 @@ static void sm_run(void){
setup->sm_s_pres.initiator_key_distribution = setup->sm_m_preq.initiator_key_distribution;
setup->sm_s_pres.responder_key_distribution = setup->sm_m_preq.responder_key_distribution;
connection->sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_CONFIRM;
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) &setup->sm_s_pres, sizeof(sm_pairing_packet_t));
sm_2timeout_reset();
sm_trigger_user_response();
connection->sm_engine_state = SM_RESPONDER_PH1_W4_PAIRING_CONFIRM;
return;
}
case SM_RESPONDER_SEND_LTK_REQUESTED_NEGATIVE_REPLY:
hci_send_cmd(&hci_le_long_term_key_negative_reply, connection->sm_handle);
connection->sm_engine_state = SM_GENERAL_IDLE;
hci_send_cmd(&hci_le_long_term_key_negative_reply, connection->sm_handle);
return;
case SM_GENERAL_SEND_PAIRING_FAILED: {
uint8_t buffer[2];
buffer[0] = SM_CODE_PAIRING_FAILED;
buffer[1] = setup->sm_pairing_failed_reason;
connection->sm_engine_state = SM_GENERAL_IDLE;
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
sm_2timeout_stop();
connection->sm_engine_state = SM_GENERAL_IDLE;
break;
}
@ -1037,13 +1037,13 @@ static void sm_run(void){
uint8_t buffer[17];
buffer[0] = SM_CODE_PAIRING_RANDOM;
swap128(setup->sm_local_random, &buffer[1]);
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
sm_2timeout_reset();
if (connection->sm_role){
connection->sm_engine_state = SM_RESPONDER_PH2_W4_LTK_REQUEST;
} else {
connection->sm_engine_state = SM_INITIATOR_PH2_W4_PAIRING_RANDOM;
}
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
sm_2timeout_reset();
break;
}
@ -1052,56 +1052,56 @@ static void sm_run(void){
case SM_PH2_C1_GET_RANDOM_B:
case SM_PH3_GET_RANDOM:
case SM_PH3_GET_DIV:
hci_send_cmd(&hci_le_rand);
sm_next_responding_state();
hci_send_cmd(&hci_le_rand);
return;
case SM_PH2_C1_GET_ENC_B:
case SM_PH2_C1_GET_ENC_D:
// already busy?
if (sm_aes128_state == SM_AES128_ACTIVE) break;
sm_aes128_start(setup->sm_tk, setup->sm_c1_t3_value);
sm_next_responding_state();
sm_aes128_start(setup->sm_tk, setup->sm_c1_t3_value);
return;
case SM_PH3_LTK_GET_ENC:
case SM_PH4_LTK_GET_ENC:
// already busy?
if (sm_aes128_state == SM_AES128_ACTIVE) break;
{
if (sm_aes128_state == SM_AES128_IDLE) {
sm_key_t d_prime;
sm_d1_d_prime(setup->sm_local_div, 0, d_prime);
sm_next_responding_state();
sm_aes128_start(sm_persistent_er, d_prime);
return;
}
sm_next_responding_state();
return;
break;
case SM_PH3_CSRK_GET_ENC:
// already busy?
if (sm_aes128_state == SM_AES128_ACTIVE) break;
{
if (sm_aes128_state == SM_AES128_IDLE) {
sm_key_t d_prime;
sm_d1_d_prime(setup->sm_local_div, 1, d_prime);
sm_next_responding_state();
sm_aes128_start(sm_persistent_er, d_prime);
return;
}
sm_next_responding_state();
return;
break;
case SM_PH2_C1_GET_ENC_C:
// already busy?
if (sm_aes128_state == SM_AES128_ACTIVE) break;
// calculate m_confirm using aes128 engine - step 1
sm_c1_t1(setup->sm_peer_random, (uint8_t*) &setup->sm_m_preq, (uint8_t*) &setup->sm_s_pres, setup->sm_m_addr_type, setup->sm_s_addr_type, plaintext);
sm_aes128_start(setup->sm_tk, plaintext);
sm_next_responding_state();
sm_aes128_start(setup->sm_tk, plaintext);
break;
case SM_PH2_C1_GET_ENC_A:
// already busy?
if (sm_aes128_state == SM_AES128_ACTIVE) break;
// calculate confirm using aes128 engine - step 1
sm_c1_t1(setup->sm_local_random, (uint8_t*) &setup->sm_m_preq, (uint8_t*) &setup->sm_s_pres, setup->sm_m_addr_type, setup->sm_s_addr_type, plaintext);
sm_aes128_start(setup->sm_tk, plaintext);
sm_next_responding_state();
sm_aes128_start(setup->sm_tk, plaintext);
break;
case SM_PH2_CALC_STK:
// already busy?
@ -1112,8 +1112,8 @@ static void sm_run(void){
} else {
sm_s1_r_prime(setup->sm_peer_random, setup->sm_local_random, plaintext);
}
sm_aes128_start(setup->sm_tk, plaintext);
sm_next_responding_state();
sm_aes128_start(setup->sm_tk, plaintext);
break;
case SM_PH3_Y_GET_ENC:
// already busy?
@ -1121,41 +1121,41 @@ static void sm_run(void){
// PH3B2 - calculate Y from - enc
// Y = dm(DHK, Rand)
sm_dm_r_prime(setup->sm_local_rand, plaintext);
sm_aes128_start(sm_persistent_dhk, plaintext);
sm_next_responding_state();
sm_aes128_start(sm_persistent_dhk, plaintext);
return;
case SM_PH2_C1_SEND_PAIRING_CONFIRM: {
uint8_t buffer[17];
buffer[0] = SM_CODE_PAIRING_CONFIRM;
swap128(setup->sm_local_confirm, &buffer[1]);
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
sm_2timeout_reset();
if (connection->sm_role){
connection->sm_engine_state = SM_RESPONDER_PH2_W4_PAIRING_RANDOM;
} else {
connection->sm_engine_state = SM_INITIATOR_PH2_W4_PAIRING_CONFIRM;
}
l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer));
sm_2timeout_reset();
return;
}
case SM_RESPONDER_PH2_SEND_LTK_REPLY: {
sm_key_t stk_flipped;
swap128(setup->sm_ltk, stk_flipped);
hci_send_cmd(&hci_le_long_term_key_request_reply, connection->sm_handle, stk_flipped);
connection->sm_engine_state = SM_PH2_W4_CONNECTION_ENCRYPTED;
hci_send_cmd(&hci_le_long_term_key_request_reply, connection->sm_handle, stk_flipped);
return;
}
case SM_INITIATOR_PH3_SEND_START_ENCRYPTION: {
sm_key_t stk_flipped;
swap128(setup->sm_ltk, stk_flipped);
hci_send_cmd(&hci_le_start_encryption, connection->sm_handle, 0, 0, 0, stk_flipped);
connection->sm_engine_state = SM_PH2_W4_CONNECTION_ENCRYPTED;
hci_send_cmd(&hci_le_start_encryption, connection->sm_handle, 0, 0, 0, stk_flipped);
return;
}
case SM_PH4_SEND_LTK: {
sm_key_t ltk_flipped;
swap128(setup->sm_ltk, ltk_flipped);
hci_send_cmd(&hci_le_long_term_key_request_reply, connection->sm_handle, ltk_flipped);
connection->sm_engine_state = SM_GENERAL_IDLE;
hci_send_cmd(&hci_le_long_term_key_request_reply, connection->sm_handle, ltk_flipped);
return;
}
case SM_PH4_Y_GET_ENC:
@ -1164,8 +1164,8 @@ static void sm_run(void){
log_info("LTK Request: recalculating with ediv 0x%04x", setup->sm_local_ediv);
// Y = dm(DHK, Rand)
sm_dm_r_prime(setup->sm_local_rand, plaintext);
sm_aes128_start(sm_persistent_dhk, plaintext);
sm_next_responding_state();
sm_aes128_start(sm_persistent_dhk, plaintext);
return;
case SM_PH3_DISTRIBUTE_KEYS:
@ -1684,6 +1684,8 @@ static void sm_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *pac
return;
}
log_debug("sm_packet_handler: staate %u, pdu 0x%02x", connection->sm_engine_state, packet[0]);
switch (connection->sm_engine_state){
// a sm timeout requries a new physical connection