fix LTK setup using ediv and rand

This commit is contained in:
matthias.ringwald@gmail.com 2015-02-27 15:53:53 +00:00
parent d19b56e8be
commit dc438c837d

View File

@ -60,6 +60,7 @@ typedef enum {
} derived_key_generation_t; } derived_key_generation_t;
typedef enum { typedef enum {
RAU_W4_WORKING,
RAU_IDLE, RAU_IDLE,
RAU_GET_RANDOM, RAU_GET_RANDOM,
RAU_W4_RANDOM, RAU_W4_RANDOM,
@ -120,13 +121,13 @@ static sm_key_t sm_persistent_ir;
static sm_key_t sm_persistent_dhk; static sm_key_t sm_persistent_dhk;
static sm_key_t sm_persistent_irk; static sm_key_t sm_persistent_irk;
static uint8_t sm_persistent_irk_ready = 0; // used for testing static uint8_t sm_persistent_irk_ready = 0; // used for testing
static derived_key_generation_t dkg_state = DKG_W4_WORKING; static derived_key_generation_t dkg_state;
// derived from sm_persistent_er // derived from sm_persistent_er
// .. // ..
// random address update // random address update
static random_address_update_t rau_state = RAU_IDLE; static random_address_update_t rau_state;
static bd_addr_t sm_random_address; static bd_addr_t sm_random_address;
// CMAC calculation // CMAC calculation
@ -1005,17 +1006,29 @@ static void sm_run(void){
hci_connection_t * hci_connection = (hci_connection_t *) linked_list_iterator_next(&it); hci_connection_t * hci_connection = (hci_connection_t *) linked_list_iterator_next(&it);
sm_connection_t * sm_connection = &hci_connection->sm_connection; sm_connection_t * sm_connection = &hci_connection->sm_connection;
// - if no connection locked and we're ready/waiting for setup context, fetch it and start // - if no connection locked and we're ready/waiting for setup context, fetch it and start
int done = 0; int done = 1;
switch (sm_connection->sm_engine_state) { switch (sm_connection->sm_engine_state) {
case SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED: case SM_RESPONDER_PH1_PAIRING_REQUEST_RECEIVED:
sm_responder_setup(sm_connection); sm_responder_setup(sm_connection);
done = 1; break;
case SM_RESPONDER_RECEIVED_LTK:
// re-establish previously used LTK using Rand and EDIV
memcpy(setup->sm_local_rand, sm_connection->sm_local_rand, 8);
setup->sm_local_ediv = sm_connection->sm_local_ediv;
// re-establish used key encryption size
// no db for encryption size hack: encryption size is stored in lowest nibble of setup->sm_local_rand
sm_connection->sm_actual_encryption_key_size = (setup->sm_local_rand[7] & 0x0f) + 1;
// no db for authenticated flag hack: flag is stored in bit 4 of LSB
sm_connection->sm_connection_authenticated = (setup->sm_local_rand[7] & 0x10) >> 4;
log_info("sm: received ltk request with key size %u, authenticated %u",
sm_connection->sm_actual_encryption_key_size, sm_connection->sm_connection_authenticated);
sm_connection->sm_engine_state = SM_PH4_Y_GET_ENC;
break; break;
case SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST: case SM_INITIATOR_PH1_W2_SEND_PAIRING_REQUEST:
sm_initiator_setup(sm_connection); sm_initiator_setup(sm_connection);
done = 1;
break; break;
default: default:
done = 0;
break; break;
} }
if (done){ if (done){
@ -1553,6 +1566,7 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
if (packet[2] == HCI_STATE_WORKING) { if (packet[2] == HCI_STATE_WORKING) {
log_info("HCI Working!"); log_info("HCI Working!");
dkg_state = sm_persistent_irk_ready ? DKG_CALC_DHK : DKG_CALC_IRK; dkg_state = sm_persistent_irk_ready ? DKG_CALC_DHK : DKG_CALC_IRK;
rau_state = RAU_IDLE;
sm_run(); sm_run();
return; // don't notify app packet handler just yet return; // don't notify app packet handler just yet
@ -1618,25 +1632,17 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
break; break;
} }
// re-establish previously used LTK using Rand and EDIV
swap64(&packet[5], setup->sm_local_rand);
setup->sm_local_ediv = READ_BT_16(packet, 13);
// assume that we don't have a LTK for ediv == 0 and random == null // assume that we don't have a LTK for ediv == 0 and random == null
if (setup->sm_local_ediv == 0 && sm_is_null_random(setup->sm_local_rand)){ if (READ_BT_16(packet, 13) == 0 && sm_is_null_random(&packet[5])){
log_info("LTK Request: ediv & random are empty"); log_info("LTK Request: ediv & random are empty");
sm_conn->sm_engine_state = SM_RESPONDER_SEND_LTK_REQUESTED_NEGATIVE_REPLY; sm_conn->sm_engine_state = SM_RESPONDER_SEND_LTK_REQUESTED_NEGATIVE_REPLY;
break; break;
} }
// re-establish used key encryption size // store rand and ediv
// no db for encryption size hack: encryption size is stored in lowest nibble of setup->sm_local_rand swap64(&packet[5], sm_conn->sm_local_rand);
sm_conn->sm_actual_encryption_key_size = (setup->sm_local_rand[7] & 0x0f) + 1; sm_conn->sm_local_ediv = READ_BT_16(packet, 13);
sm_conn->sm_engine_state = SM_RESPONDER_RECEIVED_LTK;
// no db for authenticated flag hack: flag is stored in bit 4 of LSB
sm_conn->sm_connection_authenticated = (setup->sm_local_rand[7] & 0x10) >> 4;
sm_conn->sm_engine_state = SM_PH4_Y_GET_ENC;
break; break;
default: default:
@ -1650,8 +1656,10 @@ static void sm_event_packet_handler (uint8_t packet_type, uint16_t channel, uint
if (!sm_conn) break; if (!sm_conn) break;
sm_conn->sm_connection_encrypted = packet[5]; sm_conn->sm_connection_encrypted = packet[5];
log_info("Encryption state change: %u", sm_conn->sm_connection_encrypted); log_info("Encryption state change: %u, key size %u", sm_conn->sm_connection_encrypted,
sm_conn->sm_actual_encryption_key_size);
if (!sm_conn->sm_connection_encrypted) break; if (!sm_conn->sm_connection_encrypted) break;
// continue if part of initial pairing
if (sm_conn->sm_engine_state == SM_PH2_W4_CONNECTION_ENCRYPTED) { if (sm_conn->sm_engine_state == SM_PH2_W4_CONNECTION_ENCRYPTED) {
if (sm_conn->sm_role){ if (sm_conn->sm_role){
sm_conn->sm_engine_state = SM_PH3_GET_RANDOM; sm_conn->sm_engine_state = SM_PH3_GET_RANDOM;
@ -2013,6 +2021,8 @@ void sm_init(){
sm_min_encryption_key_size = 7; sm_min_encryption_key_size = 7;
sm_cmac_state = CMAC_IDLE; sm_cmac_state = CMAC_IDLE;
dkg_state = DKG_W4_WORKING;
rau_state = RAU_W4_WORKING;
sm_aes128_state = SM_AES128_IDLE; sm_aes128_state = SM_AES128_IDLE;
sm_central_device_test = -1; // no private address to resolve yet sm_central_device_test = -1; // no private address to resolve yet
sm_central_ah_calculation_active = 0; sm_central_ah_calculation_active = 0;
@ -2032,7 +2042,8 @@ static sm_connection_t * sm_get_connection_for_handle(uint16_t con_handle){
} }
static sm_connection_t * sm_get_connection(uint8_t addr_type, bd_addr_t address){ static sm_connection_t * sm_get_connection(uint8_t addr_type, bd_addr_t address){
hci_connection_t * hci_con = hci_connection_for_bd_addr_and_type( (bd_addr_t *) &address, addr_type); // TODO figure out why the cast is needed. (using the address operator makes the code fail)
hci_connection_t * hci_con = hci_connection_for_bd_addr_and_type( (bd_addr_t*) address, addr_type);
if (!hci_con) return NULL; if (!hci_con) return NULL;
return &hci_con->sm_connection; return &hci_con->sm_connection;
} }