From 446a8c36fb5bcf34ca84a2363815358ac5b4151b Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Thu, 12 May 2016 14:33:08 +0200 Subject: [PATCH] sm: support Numeric Comparison --- example/le_counter.c | 12 +++++++-- src/ble/sm.c | 62 +++++++++++++++++++++++++++++++++++--------- src/hci.h | 1 + 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/example/le_counter.c b/example/le_counter.c index 339a4eaaa..1ac7df30a 100644 --- a/example/le_counter.c +++ b/example/le_counter.c @@ -69,6 +69,7 @@ static int le_notification_enabled; static btstack_timer_source_t heartbeat; static btstack_packet_callback_registration_t hci_event_callback_registration; +static btstack_packet_callback_registration_t sm_event_callback_registration; static hci_con_handle_t con_handle; static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); @@ -98,8 +99,11 @@ static void le_counter_setup(void){ // setup SM: Display only sm_init(); + sm_event_callback_registration.callback = &packet_handler; + sm_add_event_handler(&sm_event_callback_registration); + sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_YES_NO); #ifdef ENABLE_LE_SECURE_CONNECTIONS - sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION); + sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION|SM_AUTHREQ_MITM_PROTECTION); #endif // setup ATT server @@ -173,7 +177,11 @@ static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *pack case ATT_EVENT_CAN_SEND_NOW: att_server_notify(con_handle, ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE, (uint8_t*) counter_string, counter_string_len); break; - } + case SM_EVENT_PASSKEY_DISPLAY_NUMBER: + printf("LE Secure Connection - Numeric Comparison: %u\n", sm_event_passkey_display_number_get_passkey(packet)); + sm_just_works_confirm(sm_event_passkey_display_number_get_handle(packet)); + break; + } break; } } diff --git a/src/ble/sm.c b/src/ble/sm.c index 4acfe6d88..7a8356f78 100644 --- a/src/ble/sm.c +++ b/src/ble/sm.c @@ -254,10 +254,12 @@ typedef struct sm_setup_context { #ifdef ENABLE_LE_SECURE_CONNECTIONS uint8_t sm_peer_qx[32]; uint8_t sm_peer_qy[32]; - sm_key_t sm_peer_nonce; - sm_key_t sm_local_nonce; + sm_key_t sm_peer_nonce; // might be combined with sm_peer_random + sm_key_t sm_local_nonce; // might be combined with sm_local_random sm_key_t sm_peer_dhkey_check; sm_key_t sm_local_dhkey_check; + sm_key_t sm_ra; + sm_key_t sm_rb; #endif // Phase 3 @@ -677,7 +679,6 @@ static void f6(sm_key_t res, const sm_key_t w, const sm_key_t n1, const sm_key_t aes_cmac(res, w, buffer,sizeof(buffer)); } -#if 0 // g2(U, V, X, Y) = AES-CMACX(U || V || Y) mod 2^32 // - U is 256 bits // - V is 256 bits @@ -689,10 +690,17 @@ static uint32_t g2(const sm_key256_t u, const sm_key256_t v, const sm_key_t x, c memcpy(buffer+32, v, 32); memcpy(buffer+64, y, 16); sm_key_t cmac; + log_info("g2 key"); + log_info_hexdump(x, 16); + log_info("g2 message"); + log_info_hexdump(buffer, sizeof(buffer)); aes_cmac(cmac, x, buffer, sizeof(buffer)); - return big_endian_read_32(buffer, 12); + log_info("g2 result"); + log_info_hexdump(x, 16); + return big_endian_read_32(cmac, 12); } +#if 0 // h6(W, keyID) = AES-CMACW(keyID) // - W is 128 bits // - keyID is 32 bits @@ -766,6 +774,8 @@ static void sm_setup_tk(void){ setup->sm_use_secure_connections = ( sm_pairing_packet_get_auth_req(setup->sm_m_preq) & sm_pairing_packet_get_auth_req(setup->sm_s_pres) & SM_AUTHREQ_SECURE_CONNECTION ) != 0; + memset(setup->sm_ra, 0, 16); + memset(setup->sm_rb, 0, 16); #else setup->sm_use_secure_connections = 0; #endif @@ -1053,7 +1063,7 @@ static void sm_cmac_handle_encryption_result(sm_key_t data){ } static void sm_trigger_user_response(sm_connection_t * sm_conn){ - // notify client for: JUST WORKS confirm, PASSKEY display or input + // notify client for: JUST WORKS confirm, Numeric comparison confirm, PASSKEY display or input setup->sm_user_response = SM_USER_RESPONSE_IDLE; switch (setup->sm_stk_generation_method){ case PK_RESP_INPUT: @@ -1077,7 +1087,8 @@ static void sm_trigger_user_response(sm_connection_t * sm_conn){ sm_notify_client_base(SM_EVENT_PASSKEY_INPUT_NUMBER, sm_conn->sm_handle, sm_conn->sm_peer_addr_type, sm_conn->sm_peer_address); break; case NK_BOTH_INPUT: - log_error("LE SC - numeric comparison not implemented yet"); + setup->sm_user_response = SM_USER_RESPONSE_PENDING; + sm_notify_client_passkey(SM_EVENT_PASSKEY_DISPLAY_NUMBER, sm_conn->sm_handle, sm_conn->sm_peer_addr_type, sm_conn->sm_peer_address, big_endian_read_32(setup->sm_tk, 12)); break; case JUST_WORKS: setup->sm_user_response = SM_USER_RESPONSE_PENDING; @@ -1670,8 +1681,16 @@ static void sm_run(void){ reverse_128(setup->sm_local_nonce, &buffer[1]); if (connection->sm_role){ // responder - // TODO: calculate verification number if Numerical Comparison connection->sm_engine_state = SM_PH2_W4_DHKEY_CHECK_COMMAND; + if (setup->sm_stk_generation_method == NK_BOTH_INPUT){ + // calc Vb if numeric comparison + // TODO: use AES Engine to calculate g2 + uint8_t value[32]; + mbedtls_mpi_write_binary(&le_keypair.Q.X, value, sizeof(value)); + uint32_t vb = g2(setup->sm_peer_qx, value, setup->sm_peer_nonce, setup->sm_local_nonce) % 1000000; + big_endian_store_32(setup->sm_tk, 12, vb); + sm_trigger_user_response(connection); + } } else { // TODO: next initiator state // connection->sm_engine_state = SM_INITIATOR_PH2_W4_PAIRING_RANDOM; @@ -1739,11 +1758,9 @@ static void sm_run(void){ iocap_b[0] = sm_pairing_packet_get_auth_req(setup->sm_s_pres); iocap_b[1] = sm_pairing_packet_get_oob_data_flag(setup->sm_s_pres); iocap_b[2] = sm_pairing_packet_get_io_capability(setup->sm_s_pres); - sm_key_t ra; - memset(ra, 0, 16); if (connection->sm_role){ // responder - f6(setup->sm_local_dhkey_check, mackey, setup->sm_local_nonce, setup->sm_peer_nonce, ra, iocap_b, bd_addr_slave, bd_addr_master); + f6(setup->sm_local_dhkey_check, mackey, setup->sm_local_nonce, setup->sm_peer_nonce, setup->sm_ra, iocap_b, bd_addr_slave, bd_addr_master); } else { // initiator // @@ -1777,7 +1794,10 @@ static void sm_run(void){ #endif l2cap_send_connectionless(connection->sm_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) &setup->sm_s_pres, sizeof(sm_pairing_packet_t)); sm_timeout_reset(connection); - sm_trigger_user_response(connection); + // SC Numeric Comparison will trigger user response after public keys & nonces have been exchanged + if (setup->sm_stk_generation_method != NK_BOTH_INPUT){ + sm_trigger_user_response(connection); + } return; case SM_PH2_SEND_PAIRING_RANDOM: { @@ -2466,6 +2486,9 @@ static int sm_validate_stk_generation_method(void){ return (sm_accepted_stk_generation_methods & SM_STK_GENERATION_METHOD_PASSKEY) != 0; case OOB: return (sm_accepted_stk_generation_methods & SM_STK_GENERATION_METHOD_OOB) != 0; + case NK_BOTH_INPUT: + // TODO check sm_accepted_stk_generation_methods + return 1; default: return 0; } @@ -2625,7 +2648,13 @@ static void sm_pdu_handler(uint8_t packet_type, hci_con_handle_t con_handle, uin } // store DHKey Check reverse_128(&packet[01], setup->sm_peer_dhkey_check); - sm_conn->sm_engine_state = SM_PH2_SEND_DHKEY_CHECK_COMMAND; + + // for numeric comparison, we need to wait for user confirm + if (setup->sm_stk_generation_method == NK_BOTH_INPUT && setup->sm_user_response != SM_USER_RESPONSE_CONFIRM){ + sm_conn->sm_engine_state = SM_PH2_W4_USER_RESPONSE; + } else { + sm_conn->sm_engine_state = SM_PH2_SEND_DHKEY_CHECK_COMMAND; + } break; #endif @@ -2957,6 +2986,15 @@ void sm_just_works_confirm(hci_con_handle_t con_handle){ if (sm_conn->sm_engine_state == SM_PH1_W4_USER_RESPONSE){ sm_conn->sm_engine_state = SM_PH2_C1_GET_RANDOM_A; } + if (sm_conn->sm_engine_state == SM_PH2_W4_USER_RESPONSE){ + if (sm_conn->sm_role){ + // responder + sm_conn->sm_engine_state = SM_PH2_SEND_DHKEY_CHECK_COMMAND; + } else { + // initiator + // TODO handle intiator role + } + } sm_run(); } diff --git a/src/hci.h b/src/hci.h index 01a8ba024..45533119d 100644 --- a/src/hci.h +++ b/src/hci.h @@ -255,6 +255,7 @@ typedef enum { SM_PH2_SEND_PAIRING_RANDOM_SC, SM_PH2_SEND_DHKEY_CHECK_COMMAND, SM_PH2_W4_PAIRING_RANDOM, + SM_PH2_W4_USER_RESPONSE, SM_PH2_W4_DHKEY_CHECK_COMMAND, // Phase 3: Transport Specific Key Distribution