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