From f4487237dfc4509b0b24edb7725253c8530e8bc9 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Tue, 3 Apr 2018 15:43:51 +0200 Subject: [PATCH] pts/sm_test: simulate OOB data exchange, trigger pairing manually as well --- test/pts/sm_test.c | 117 ++++++++++++++++++++++++++++++++++---------- test/pts/sm_test.py | 40 +++++++++++---- 2 files changed, 121 insertions(+), 36 deletions(-) diff --git a/test/pts/sm_test.c b/test/pts/sm_test.c index 6d694b44a..3bbc534df 100644 --- a/test/pts/sm_test.c +++ b/test/pts/sm_test.c @@ -80,14 +80,24 @@ static uint8_t sm_have_oob_data = 0; static uint8_t sm_io_capabilities = 0; static uint8_t sm_auth_req = 0; static uint8_t sm_failure = 0; -// static uint8_t * sm_oob_data = (uint8_t *) "0123456789012345"; // = { 0x30...0x39, 0x30..0x35} -static uint8_t sm_oob_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + +// legacy pairing oob +static uint8_t sm_oob_tk_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + +// sc pairing oob +static uint8_t sm_oob_local_random[16]; +static uint8_t sm_oob_peer_random[16]; +static uint8_t sm_oob_peer_confirm[16]; static int we_are_central = 0; static bd_addr_t peer_address; static int ui_passkey = 0; static int ui_digits_for_passkey = 0; +static int ui_oob_confirm; +static int ui_oob_random; +static int ui_oob_pos; +static int ui_oob_nibble; static btstack_timer_source_t heartbeat; static uint8_t counter = 0; @@ -123,6 +133,34 @@ static void heartbeat_handler(struct btstack_timer_source *ts){ counter++; } +static int get_oob_data_callback(uint8_t address_type, bd_addr_t addr, uint8_t * oob_data){ + UNUSED(address_type); + (void)addr; + log_info("get_oob_data_callback for %s", bd_addr_to_str(addr)); + if(!sm_have_oob_data) return 0; + memcpy(oob_data, sm_oob_tk_data, 16); + return 1; +} + +static int get_sc_oob_data_callback(uint8_t address_type, bd_addr_t addr, uint8_t * oob_sc_peer_confirm, uint8_t * oob_sc_peer_random){ + UNUSED(address_type); + (void)addr; + log_info("get_sc_oob_data_callback for %s", bd_addr_to_str(addr)); + if(!sm_have_oob_data) return 0; + memcpy(oob_sc_peer_confirm, sm_oob_peer_confirm, 16); + memcpy(oob_sc_peer_random, sm_oob_peer_random, 16); + return 1; +} + +static void sc_local_oob_generated_callback(const uint8_t * confirm_value, const uint8_t * random_value){ + printf("LOCAL_OOB_CONFIRM: "); + printf_hexdump(confirm_value, 16); + printf("LOCAL_OOB_RANDOM: "); + printf_hexdump(random_value, 16); + fflush(stdout); + memcpy(sm_oob_local_random, random_value, 16); +} + // ATT Client Read Callback for Dynamic Data // - if buffer == NULL, don't copy data, just return size of value // - if buffer != NULL, copy data and return number bytes copied @@ -234,14 +272,6 @@ static void handle_gatt_client_event(uint8_t packet_type, uint16_t channel, uint fflush(stdout); } -static void sc_oob_callback(const uint8_t * confirm_value, const uint8_t * random_value){ - printf("OOB_CONFIRM: "); - printf_hexdump(confirm_value, 16); - printf("OOB_RANDOM: "); - printf_hexdump(random_value, 16); - fflush(stdout); -} - static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ UNUSED(channel); UNUSED(size); @@ -255,7 +285,7 @@ static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t * gap_local_bd_addr(local_addr); printf("BD_ADDR: %s\n", bd_addr_to_str(local_addr)); // generate OOB data - sm_generate_sc_oob_data(sc_oob_callback); + sm_generate_sc_oob_data(sc_local_oob_generated_callback); } break; case HCI_EVENT_LE_META: @@ -263,10 +293,6 @@ static void app_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t * case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: connection_handle = little_endian_read_16(packet, 4); printf("CONNECTED: Connection handle 0x%04x\n", connection_handle); - if (we_are_central){ - printf("REQUEST_PAIRING\n"); - sm_request_pairing(connection_handle); - } break; default: break; @@ -333,6 +359,41 @@ static void stdin_process(char c){ return; } + if (ui_oob_confirm){ + if (c == ' ') return; + ui_oob_nibble = (ui_oob_nibble << 4) | nibble_for_char(c); + if ((ui_oob_pos & 1) == 1){ + sm_oob_peer_confirm[ui_oob_pos >> 1] = ui_oob_nibble; + ui_oob_nibble = 0; + } + ui_oob_pos++; + if (ui_oob_pos == 32){ + ui_oob_confirm = 0; + printf("PEER_OOB_CONFIRM: "); + printf_hexdump(sm_oob_peer_confirm, 16); + fflush(stdout); + } + return; + } + + if (ui_oob_random){ + if (c == ' ') return; + ui_oob_nibble = (ui_oob_nibble << 4) | nibble_for_char(c); + if ((ui_oob_pos & 1) == 1){ + sm_oob_peer_random[ui_oob_pos >> 1] = ui_oob_nibble; + ui_oob_nibble = 0; + } + ui_oob_pos++; + if (ui_oob_pos == 32){ + ui_oob_random = 0; + printf("PEER_OOB_RANDOM: "); + printf_hexdump(sm_oob_peer_random, 16); + fflush(stdout); + } + return; + } + + switch (c){ case 'a': // accept just works printf("accepting just works\n"); @@ -346,9 +407,19 @@ static void stdin_process(char c){ printf("decline bonding\n"); sm_bonding_decline(connection_handle); break; - case 'g': - printf("generate oob data\n"); - sm_generate_sc_oob_data(sc_oob_callback); + case 'o': + printf("receive oob confirm value\n"); + ui_oob_confirm = 1; + ui_oob_pos = 0; + break; + case 'r': + printf("receive oob random value\n"); + ui_oob_random = 1; + ui_oob_pos = 0; + break; + case 'p': + printf("REQUEST_PAIRING\n"); + sm_request_pairing(connection_handle); break; case 'x': printf("Exit\n"); @@ -361,15 +432,6 @@ static void stdin_process(char c){ return; } -static int get_oob_data_callback(uint8_t address_type, bd_addr_t addr, uint8_t * oob_data){ - UNUSED(address_type); - log_info("get_oob_data_callback for %s", bd_addr_to_str(addr)); - (void)addr; - if(!sm_have_oob_data) return 0; - memcpy(oob_data, sm_oob_data, 16); - return 1; -} - int btstack_main(int argc, const char * argv[]); int btstack_main(int argc, const char * argv[]){ @@ -440,6 +502,7 @@ int btstack_main(int argc, const char * argv[]){ sm_set_io_capabilities(sm_io_capabilities); sm_set_authentication_requirements(sm_auth_req); sm_register_oob_data_callback(get_oob_data_callback); + sm_register_sc_oob_data_callback(get_sc_oob_data_callback); if (sm_failure < SM_REASON_NUMERIC_COMPARISON_FAILED && sm_failure != SM_REASON_PASSKEY_ENTRY_FAILED){ sm_test_set_pairing_failure(sm_failure); diff --git a/test/pts/sm_test.py b/test/pts/sm_test.py index a2c3d5afb..f2e00f6ea 100755 --- a/test/pts/sm_test.py +++ b/test/pts/sm_test.py @@ -48,8 +48,8 @@ failures = [ # tester config debug = False regenerate = False -usb_paths = ['4', '6'] -# usb_paths = ['3', '5'] +# usb_paths = ['4', '6'] +usb_paths = ['3', '5'] class Node: @@ -137,9 +137,7 @@ class Node: self.peer_addr = addr def write(self, string): - for c in string: - self.stdin.write(string) - time.sleep (0.1); + self.stdin.write(string) def terminate(self): self.write('x') @@ -184,18 +182,39 @@ def run(test_descriptor, nodes): master.set_failure(test_descriptor['tester_failure']) master.start_process() nodes.append(master) - if state == 'W4_MASTER_BD_ADDR': + # + if node.get_name() == 'iut': + iut_node = node + tester_node = master + else: + iut_node = master + tester_node = node + elif state == 'W4_MASTER_BD_ADDR': # central started, start connecting node.write('c') - elif line.startswith('OOB_CONFIRM:'): + print('start to connect') + state = 'W4_CONNECTED' + elif line.startswith('LOCAL_OOB_CONFIRM:'): confirm = line.split('OOB_CONFIRM: ')[1] test_descriptor[node.get_name()+'_oob_confirm'] = confirm - elif line.startswith('OOB_RANDOM:'): + elif line.startswith('LOCAL_OOB_RANDOM:'): random = line.split('OOB_RANDOM: ')[1] test_descriptor[node.get_name()+'_oob_random'] = random elif line.startswith('CONNECTED:'): print('%s connected' % node.get_name()) - if state == 'W4_CONNECTED': + if state == 'W4_CONNECTED' and node == nodes[1]: + # simulate OOK exchange if requested + if test_descriptor['tester_oob_data'] == '1': + print('Simulate IUT -> Tester OOB') + tester_node.write('o' + test_descriptor['iut_oob_confirm']) + tester_node.write('r' + test_descriptor['iut_oob_random']) + test_descriptor['method'] = 'OOB' + if test_descriptor['iut_oob_data'] == '1': + print('Simulate Tester -> IUT OOB') + iut_node.write('o' + test_descriptor['tester_oob_confirm']) + iut_node.write('r' + test_descriptor['tester_oob_random']) + test_descriptor['method'] = 'OOB' + node.write('p') state = 'W4_PAIRING' elif line.startswith('JUST_WORKS_REQUEST'): print('%s just works requested' % node.get_name()) @@ -411,6 +430,7 @@ def run_test(test_descriptor): except KeyboardInterrupt: print('Interrupted') + test_descriptor['interrupted'] = 'EXIT' # shutdown for node in nodes: @@ -444,3 +464,5 @@ with open('sm_test.csv') as csvfile: print(test_descriptor) run_test(test_descriptor) + if 'interrupted' in test_descriptor: + break