#!/usr/bin/env ruby # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # ### This script converts a bletiny log into a security manager unit test. The ### input log must contain the connection establishment and complete pairing ### procedure. ### ### Arguments: None ### Stdin: bletiny log file $PAIR_ALG_STRINGS = { 0 => [ 'BLE_SM_PAIR_ALG_JW', 'just works', 'jw' ], 1 => [ 'BLE_SM_PAIR_ALG_PASSKEY', 'passkey entry', 'pk' ], 2 => [ 'BLE_SM_PAIR_ALG_OOB', 'out of band', 'ob' ], 3 => [ 'BLE_SM_PAIR_ALG_NUMCMP', 'numeric comparison', 'nc' ] } $ADDR_TYPE_STRINGS = { 0 => 'BLE_ADDR_TYPE_PUBLIC', 1 => 'BLE_ADDR_TYPE_RANDOM', 2 => 'BLE_ADDR_TYPE_RPA_PUB_DEFAULT', 3 => 'BLE_ADDR_TYPE_RPA_RND_DEFAULT', } $ACTION_STRINGS = { 0 => 'BLE_SM_IOACT_NONE', 1 => 'BLE_SM_IOACT_OOB', 2 => 'BLE_SM_IOACT_INPUT', 3 => 'BLE_SM_IOACT_DISP', 4 => 'BLE_SM_IOACT_NUMCMP', } $prev_idx = 0 $ctxt = {} def test_case_name type_str = $ctxt[:sc] ? "sc" : "lgcy" init_str = $ctxt[:we_are_init] ? "us" : "peer" alg_str = $PAIR_ALG_STRINGS[$ctxt[:pair_alg]][2] iio_cap_str = "iio#{$ctxt[:pair_req][:io_cap]}" rio_cap_str = "rio#{$ctxt[:pair_rsp][:io_cap]}" bonding_str = "b#{$ctxt[:bonding] ? 1 : 0}" iat_str = "iat#{$ctxt[:addrs][:init_type]}" rat_str = "rat#{$ctxt[:addrs][:resp_type]}" ikey_str = "ik#{$ctxt[:pair_rsp][:init_key_dist]}" rkey_str = "rk#{$ctxt[:pair_rsp][:resp_key_dist]}" "ble_sm_" + "#{type_str}_#{init_str}_#{alg_str}_#{iio_cap_str}_#{rio_cap_str}_" + "#{bonding_str}_#{iat_str}_#{rat_str}_#{ikey_str}_#{rkey_str}" end def test_case_comment <<-eos /** * #{$ctxt[:sc] ? 'Secure connections' : 'Legacy'} pairing * Master: #{$ctxt[:we_are_init] ? "us" : "peer"} * Pair algorithm: #{$PAIR_ALG_STRINGS[$ctxt[:pair_alg]][1]} * Initiator IO capabilities: #{$ctxt[:pair_req][:io_cap]} * Responder IO capabilities: #{$ctxt[:pair_rsp][:io_cap]} * Bonding: #{$ctxt[:bonding]} * Initiator address type: #{$ADDR_TYPE_STRINGS[$ctxt[:addrs][:init_type]]} * Responder address type: #{$ADDR_TYPE_STRINGS[$ctxt[:addrs][:resp_type]]} * Initiator key distribution: #{$ctxt[:pair_rsp][:init_key_dist]} * Responder key distribution: #{$ctxt[:pair_rsp][:resp_key_dist]} */ eos end def to_hex_s(byte) if byte.is_a?(String) byte = s_to_i(byte) end "0x#{byte.to_s(16).rjust(2, '0')}" end # to_i(0) but interpret leading zeros as decimal. def s_to_i(s) if s[0..1] == "0x" return s.to_i(16) else return s.to_i(10) end end def invalid_byte_line(msg, line) str = "invalid byte line" if msg != nil str += ": #{msg}" end str += "; line=#{line}" raise str end def token_string_to_bytes(line, delim = ' ') tokens = line.split(delim) bytes = [] tokens.each do |token| begin byte = token.to_i(16) bytes << byte rescue invalid_byte_line("token=#{token}", line) end end return bytes end def txrx_prefix(is_tx) if is_tx return "tx" else return "rx" end end def reqrsp_s(is_req) reqrsp = nil if is_req return "req" else return "rsp" end end def bytes_to_arr_body(bytes, indent) lines = [] idx = 0 while idx < bytes.size slice_len = nil if bytes.size - idx >= 8 slice_len = 8 else slice_len = bytes.size - idx end slice = bytes[idx...(idx + slice_len)] line = ' ' * indent + slice.map{|b| to_hex_s(b)}.join(", ") + "," lines << line idx += slice_len end return lines.join("\n") << "\n" end def bytes_to_arr(bytes, name, indent) str = "#{' ' * indent}.#{name} = {\n" str << bytes_to_arr_body(bytes, indent + 4) str << "#{' ' * indent}}," return str end def addr_string_to_bytes(addr_string) token_string_to_bytes(addr_string, ':').reverse end def parse_pair_cmd(line, is_req) suffix = reqrsp_s(is_req) re = %r{ pair\s#{suffix}; \s conn=\d+ \s io_cap=(?\d+) \s oob_data_flag=(?\d+) \s authreq=(?0x[0-9a-f]+) \s mac_enc_key_size=(?\d+) \s init_key_dist=(?\d+) \s resp_key_dist=(?\d+) }x m = re.match(line) if m == nil return nil end cmd = {} cmd[:io_cap] = s_to_i(m[:io_cap]) cmd[:oob_data_flag] = s_to_i(m[:oob_data_flag]) cmd[:authreq] = s_to_i(m[:authreq]) cmd[:max_enc_key_size] = s_to_i(m[:max_enc_key_size]) cmd[:init_key_dist] = s_to_i(m[:init_key_dist]) cmd[:resp_key_dist] = s_to_i(m[:resp_key_dist]) return cmd end def parse_privkey(line) if !(line =~ /our privkey=(.+)/) return nil end return token_string_to_bytes($1) end def parse_public_key(line, is_tx) prefix = txrx_prefix(is_tx) if !(line =~ /#{prefix}ed sm command: public key; conn=\d+ x=(.+) y=(.+)/) return nil end pubkey = {} pubkey[:x] = token_string_to_bytes($1) pubkey[:y] = token_string_to_bytes($2) if pubkey[:x].size != 32 raise "invalid public key: x length incorrect; line=#{line}" end if pubkey[:y].size != 32 raise "invalid public key: y length incorrect; line=#{line}" end return pubkey end def parse_confirm(line, is_tx) prefix = txrx_prefix(is_tx) if !(line =~ /#{prefix}ed sm command: confirm; conn=\d+ value=(.+)/) return nil end bytes = token_string_to_bytes($1) if bytes.size != 16 raise "invalid confirm line (length mismatch): #{line}" end return { :value => bytes } end def parse_random(line, is_tx) prefix = txrx_prefix(is_tx) if !(line =~ /#{prefix}ed sm command: random; conn=\d+ value=(.+)/) return nil end bytes = token_string_to_bytes($1) if bytes.size != 16 raise "invalid random line (length mismatch): #{line}" end return { :value => bytes } end def parse_stk(line) if !(line =~ /^ out=(.+)/) return nil end bytes = token_string_to_bytes($1) if bytes.size != 16 raise "invalid stk line (length mismatch): #{line}" end return bytes end def parse_dhkey_check(line, is_tx) prefix = txrx_prefix(is_tx) if !(line =~ /#{prefix}ed sm command: dhkey check; conn=\d+ value=(.+)/) return nil end bytes = token_string_to_bytes($1) if bytes.size != 16 raise "invalid dhkey_check line (length mismatch): #{line}" end return { :value => bytes } end def parse_ltk(line) if !(line =~ /persisting.+ltk=([^ ]+)/) return nil end bytes = $1.split(":") if bytes.size != 16 raise "invalid ltk line (length mismatch): exp=16 got=#{bytes.size} " + "line=#{line}" end return bytes end def parse_enc_info(line, is_tx) prefix = txrx_prefix(is_tx) if !(line =~ /#{prefix}ed sm command: enc info; conn=\d+ ltk=(.+)/) return nil end bytes = token_string_to_bytes($1) if bytes.size != 16 raise "invalid enc info line (length mismatch): #{line}" end return { :ltk => bytes } end def parse_master_id(line, is_tx) prefix = txrx_prefix(is_tx) if !(line =~ /#{prefix}ed sm command: master id; conn=\d+ ediv=(.+) rand=(.+)/) return nil end return { :ediv => s_to_i($1), :rand => s_to_i($2), } end def parse_id_info(line, is_tx) prefix = txrx_prefix(is_tx) if !(line =~ /#{prefix}ed sm command: id info; conn=\d+ irk=(.+)/) return nil end bytes = token_string_to_bytes($1) if bytes.size != 16 raise "invalid id info line (length mismatch): #{line}" end return { :irk => bytes } end def parse_id_addr_info(line, is_tx) prefix = txrx_prefix(is_tx) if !(line =~ /#{prefix}ed sm command: id addr info; conn=\d+ addr_type=(\d+) addr=(.+)/) return nil end bytes = addr_string_to_bytes($2) if bytes.size != 6 raise "invalid id addr info line (length mismatch): #{line}" end return { :addr_type => s_to_i($1), :addr => bytes, } end def parse_sign_info(line, is_tx) prefix = txrx_prefix(is_tx) if !(line =~ /#{prefix}ed sm command: sign info; conn=\d+ sig_key=(.+)/) return nil end bytes = token_string_to_bytes($1) if bytes.size != 16 raise "invalid sign info line (length mismatch): #{line}" end return { :sig_key => bytes, } end def parse_passkey_info(line) passkey_info = {} case line when /passkey action event; action=4 numcmp=(\d+)/ passkey_info[:action] = 4 passkey_info[:numcmp] = $1.to_i(10) when /^b passkey conn=\d+ action=1 oob=(\S+)/ passkey_info[:action] = 1 passkey_info[:oob] = token_string_to_bytes($1, ':') when /^b passkey conn=\d+ action=2 key=(\d+)/ passkey_info[:action] = 2 passkey_info[:key] = $1.to_i(10) when /b passkey conn=\d+ action=3 key=(\d+)/ passkey_info[:action] = 3 passkey_info[:key] = $1.to_i(10) else return nil end return passkey_info end def parse_addrs(line) if !(line =~ /our_ota_addr_type=(\d+) our_ota_addr=(\S+) our_id_addr_type=(\d+) our_id_addr=(\S+) peer_ota_addr_type=(\d+) peer_ota_addr=(\S+) peer_id_addr_type=(\d+) peer_id_addr=(\S+)/) return nil end our_ota_addr_bytes = addr_string_to_bytes($2) our_id_addr_bytes = addr_string_to_bytes($4) peer_ota_addr_bytes = addr_string_to_bytes($6) peer_id_addr_bytes = addr_string_to_bytes($8) if $ctxt[:we_are_init] init_id_bytes = our_id_addr_bytes init_ota_bytes = our_ota_addr_bytes resp_id_bytes = peer_id_addr_bytes resp_ota_bytes = peer_ota_addr_bytes init_addr_type = s_to_i($1) resp_addr_type = s_to_i($5) else init_id_bytes = peer_id_addr_bytes init_ota_bytes = peer_ota_addr_bytes resp_id_bytes = our_id_addr_bytes resp_ota_bytes = our_ota_addr_bytes init_addr_type = s_to_i($5) resp_addr_type = s_to_i($1) end if init_id_bytes == init_ota_bytes init_ota_bytes = [0] * 6 end if resp_id_bytes == resp_ota_bytes resp_ota_bytes = [0] * 6 end return { :init_type => init_addr_type, :resp_type => resp_addr_type, :init_id_addr => init_id_bytes, :resp_id_addr => resp_id_bytes, :init_rpa => init_ota_bytes, :resp_rpa => resp_ota_bytes, } end def detect_initiator(lines) lines.each do |line| if line =~ /txed sm command: pair req/ $ctxt[:we_are_init] = true elsif line =~ /txed sm command: pair rsp/ $ctxt[:we_are_init] = false end end if $ctxt[:we_are_init] == nil raise "could not detect which peer is the initiator" end end def pair_cmd_to_s(cmd, is_req) suffix = reqrsp_s(is_req) return <<-eos .pair_#{suffix} = { .io_cap = #{to_hex_s(cmd[:io_cap])}, .oob_data_flag = #{to_hex_s(cmd[:oob_data_flag])}, .authreq = #{to_hex_s(cmd[:authreq])}, .max_enc_key_size = #{to_hex_s(cmd[:max_enc_key_size])}, .init_key_dist = #{to_hex_s(cmd[:init_key_dist])}, .resp_key_dist = #{to_hex_s(cmd[:resp_key_dist])}, }, eos end def privkey_to_s(privkey) return bytes_to_arr(privkey, "our_priv_key", 8) end def public_key_to_s(public_key, is_req) suffix = reqrsp_s(is_req) return <<-eos .public_key_#{suffix} = { #{bytes_to_arr(public_key[:x], "x", 12)} #{bytes_to_arr(public_key[:y], "y", 12)} }, eos end def confirm_to_s(confirm, is_req, idx) return <<-eos .confirm_#{reqrsp_s(is_req)}[#{idx}] = { #{bytes_to_arr(confirm[:value], "value", 12)} }, eos end def random_to_s(random, is_req, idx) return <<-eos .random_#{reqrsp_s(is_req)}[#{idx}] = { #{bytes_to_arr(random[:value], "value", 12)} }, eos end def ltk_to_s(ltk) return bytes_to_arr(ltk, "ltk", 8) end def stk_to_s(stk) return bytes_to_arr(stk, "stk", 8) end def enc_info_to_s(id_info, is_req) return <<-eos .enc_info_#{reqrsp_s(is_req)} = { #{bytes_to_arr(id_info[:ltk], "ltk", 12)} }, eos end def master_id_to_s(master_id, is_req) return <<-eos .master_id_#{reqrsp_s(is_req)} = { .ediv = 0x#{master_id[:ediv].to_s(16)}, .rand_val = 0x#{master_id[:rand].to_s(16)}, }, eos end def id_info_to_s(id_info, is_req) return <<-eos .id_info_#{reqrsp_s(is_req)} = { #{bytes_to_arr(id_info[:irk], "irk", 12)} }, eos end def id_addr_info_to_s(id_addr_info, is_req) return <<-eos .id_addr_info_#{reqrsp_s(is_req)} = { .addr_type = #{id_addr_info[:addr_type]}, #{bytes_to_arr(id_addr_info[:addr], "bd_addr", 12)} }, eos end def sign_info_to_s(sign_info, is_req) return <<-eos .sign_info_#{reqrsp_s(is_req)} = { #{bytes_to_arr(sign_info[:sig_key], "sig_key", 12)} }, eos end def passkey_info_fill(passkey_info) case passkey_info[:action] # None when 0 $ctxt[:pair_alg] = 0 $ctxt[:authenticated] = false # OOB when 1 $ctxt[:pair_alg] = 2 $ctxt[:authenticated] = true # Input when 2 $ctxt[:pair_alg] = 1 $ctxt[:authenticated] = true # Display when 3 $ctxt[:pair_alg] = 1 $ctxt[:authenticated] = true # Numeric comparison when 4 $ctxt[:pair_alg] = 3 $ctxt[:authenticated] = true else raise "invalid MITM action: #{passkey_info[:action]}" end end def passkey_info_s passkey_info = $ctxt[:passkey_info] action_str = $ACTION_STRINGS[passkey_info[:action]] result = <<-eos .pair_alg = #{$ctxt[:pair_alg]}, .authenticated = #{$ctxt[:authenticated]}, .passkey_info = { .passkey = { .action = #{action_str}, eos if passkey_info[:key] != nil result << <<-eos .passkey = #{passkey_info[:key].to_i}, eos end if passkey_info[:oob] != nil result << <<-eos #{bytes_to_arr(passkey_info[:oob], "oob", 16)} eos end if passkey_info[:numcmp] != nil result << <<-eos .numcmp_accept = 1, eos end result << <<-eos }, eos if passkey_info[:numcmp] != nil result << <<-eos .exp_numcmp = #{passkey_info[:numcmp].to_i}, eos end result << <<-eos }, eos end def addrs_to_s(addrs) s = '' init_type = addrs[:init_type] resp_type = addrs[:resp_type] if init_type != 0 s += " .init_addr_type = #{$ADDR_TYPE_STRINGS[init_type]},\n" end s += bytes_to_arr(addrs[:init_id_addr], "init_id_addr", 8) + "\n" if init_type >= 2 s += bytes_to_arr(addrs[:init_rpa], "init_rpa", 8) + "\n" end if resp_type != 0 s += " .resp_addr_type = #{$ADDR_TYPE_STRINGS[resp_type]},\n" end s += bytes_to_arr(addrs[:resp_id_addr], "resp_id_addr", 8) + "\n" if resp_type >= 2 s += bytes_to_arr(addrs[:resp_rpa], "resp_rpa", 8) + "\n" end return s end def dhkey_check_to_s(dhkey_check, is_req) return <<-eos .dhkey_check_#{reqrsp_s(is_req)} = { #{bytes_to_arr(dhkey_check[:value], "value", 12)} }, eos end def extract_one(lines, ignore_prev = false) if ignore_prev start = 0 else start = $prev_idx end (start...lines.size).each do |idx| line = lines[idx] result = yield(line) if result != nil if !ignore_prev $prev_idx = idx end return result end end return nil end def extract_pair_req(lines) return extract_one(lines) {|line| parse_pair_cmd(line, true)} end def extract_pair_rsp(lines) return extract_one(lines) {|line| parse_pair_cmd(line, false)} end def extract_privkey(lines) return extract_one(lines) {|line| parse_privkey(line)} end def extract_public_key_req(lines) return extract_one(lines) do |line| parse_public_key(line, $ctxt[:we_are_init]) end end def extract_public_key_rsp(lines) return extract_one(lines) do |line| parse_public_key(line, !$ctxt[:we_are_init]) end end def extract_confirm_req(lines) return extract_one(lines) do |line| parse_confirm(line, $ctxt[:we_are_init]) end end def extract_confirm_rsp(lines) return extract_one(lines) do |line| parse_confirm(line, !$ctxt[:we_are_init]) end end def extract_random_req(lines) return extract_one(lines) do |line| parse_random(line, $ctxt[:we_are_init]) end end def extract_random_rsp(lines) return extract_one(lines) do |line| parse_random(line, !$ctxt[:we_are_init]) end end def extract_confirm_random(lines) confirm_reqs = [] confirm_rsps = [] random_reqs = [] random_rsps = [] idx = 0 loop do confirm_req = extract_confirm_req(lines) if confirm_req != nil confirm_reqs << confirm_req end confirm_rsp = extract_confirm_rsp(lines) break if confirm_rsp == nil if idx >= 20 raise "too many confirm rsps (>20)" end confirm_rsps << confirm_rsp random_req = extract_random_req(lines) break if random_req == nil random_reqs << random_req random_rsp = extract_random_rsp(lines) break if random_rsp == nil random_rsps << random_rsp idx += 1 end return confirm_reqs, confirm_rsps, random_reqs, random_rsps end def extract_stk(lines) return extract_one(lines, true) do |line| parse_stk(line) end end def extract_dhkey_check_req(lines) return extract_one(lines) do |line| parse_dhkey_check(line, $ctxt[:we_are_init]) end end def extract_dhkey_check_rsp(lines) return extract_one(lines) do |line| parse_dhkey_check(line, !$ctxt[:we_are_init]) end end def extract_enc_info_req(lines) return extract_one(lines) do |line| parse_enc_info(line, !$ctxt[:we_are_init]) end end def extract_enc_info_rsp(lines) return extract_one(lines) do |line| parse_enc_info(line, $ctxt[:we_are_init]) end end def extract_master_id_req(lines) return extract_one(lines) do |line| parse_master_id(line, !$ctxt[:we_are_init]) end end def extract_master_id_rsp(lines) return extract_one(lines) do |line| parse_master_id(line, $ctxt[:we_are_init]) end end def extract_id_info_req(lines) return extract_one(lines) do |line| parse_id_info(line, !$ctxt[:we_are_init]) end end def extract_id_info_rsp(lines) return extract_one(lines) do |line| parse_id_info(line, $ctxt[:we_are_init]) end end def extract_id_addr_info_req(lines) return extract_one(lines) do |line| parse_id_addr_info(line, !$ctxt[:we_are_init]) end end def extract_id_addr_info_rsp(lines) return extract_one(lines) do |line| parse_id_addr_info(line, $ctxt[:we_are_init]) end end def extract_sign_info_req(lines) return extract_one(lines) do |line| parse_sign_info(line, !$ctxt[:we_are_init]) end end def extract_sign_info_rsp(lines) return extract_one(lines) do |line| parse_sign_info(line, $ctxt[:we_are_init]) end end def extract_ltk(lines) return extract_one(lines) do |line| parse_ltk(line) end end def extract_passkey_info(lines) passkey_info = extract_one(lines, true) do |line| parse_passkey_info(line) end if passkey_info == nil passkey_info = { :action => 0 } end return passkey_info end def extract_addrs(lines) return extract_one(lines) do |line| parse_addrs(line) end end lines = STDIN.readlines detect_initiator(lines) $ctxt[:pair_req] = extract_pair_req(lines) $ctxt[:pair_rsp] = extract_pair_rsp(lines) $ctxt[:privkey] = extract_privkey(lines) $ctxt[:public_key_req] = extract_public_key_req(lines) $ctxt[:public_key_rsp] = extract_public_key_rsp(lines) $ctxt[:confirm_reqs], $ctxt[:confirm_rsps], $ctxt[:random_reqs], $ctxt[:random_rsps] = extract_confirm_random(lines) $ctxt[:passkey_info] = extract_passkey_info(lines) $ctxt[:dhkey_check_req] = extract_dhkey_check_req(lines) $ctxt[:dhkey_check_rsp] = extract_dhkey_check_rsp(lines) $ctxt[:enc_info_req] = extract_enc_info_req(lines) $ctxt[:master_id_req] = extract_master_id_req(lines) $ctxt[:id_info_req] = extract_id_info_req(lines) $ctxt[:id_addr_info_req] = extract_id_addr_info_req(lines) $ctxt[:sign_info_req] = extract_sign_info_req(lines) $ctxt[:enc_info_rsp] = extract_enc_info_rsp(lines) $ctxt[:master_id_rsp] = extract_master_id_rsp(lines) $ctxt[:id_info_rsp] = extract_id_info_rsp(lines) $ctxt[:id_addr_info_rsp] = extract_id_addr_info_rsp(lines) $ctxt[:sign_info_rsp] = extract_sign_info_rsp(lines) $ctxt[:addrs] = extract_addrs(lines) $ctxt[:ltk] = extract_ltk(lines) $ctxt[:stk] = extract_stk(lines) expected_confirm_rsps = nil expected_random_reqs = nil expected_random_rsps = nil if $ctxt[:confirm_reqs].size == 0 expected_confirm_rsps = 1 expected_random_reqs = 1 expected_random_rsps = 1 else expected_confirm_rsps = $ctxt[:confirm_reqs].size expected_random_reqs = $ctxt[:random_reqs].size expected_random_rsps = $ctxt[:random_rsps].size end if $ctxt[:confirm_rsps].size != expected_confirm_rsps raise "wrong number of confirm responses " + "(exp=#{expected_confirm_rsps}; got=#{$ctxt[:confirm_rsps].size}" end if $ctxt[:random_reqs].size != expected_random_reqs raise "wrong number of random requests " + "(exp=#{expected_random_reqs}; got=#{$ctxt[:random_reqs].size}" end if $ctxt[:random_rsps].size != expected_random_rsps raise "wrong number of random responses " + "(exp=#{expected_random_rsps}; got=#{$ctxt[:random_rsps].size}" end passkey_info_fill($ctxt[:passkey_info]) $ctxt[:sc] = $ctxt[:public_key_req] != nil $ctxt[:bonding] = $ctxt[:pair_req][:authreq] & 1 == 1 && $ctxt[:pair_rsp][:authreq] & 1 == 1 puts test_case_comment() puts <<-eos TEST_CASE(#{test_case_name()}) { struct ble_sm_test_params params; params = (struct ble_sm_test_params) { eos puts addrs_to_s($ctxt[:addrs]) puts pair_cmd_to_s($ctxt[:pair_req], true) puts pair_cmd_to_s($ctxt[:pair_rsp], false) if $ctxt[:sc] puts privkey_to_s($ctxt[:privkey]) puts public_key_to_s($ctxt[:public_key_req], true) puts public_key_to_s($ctxt[:public_key_req], false) end $ctxt[:confirm_rsps].size.times do |i| confirm_req = $ctxt[:confirm_reqs][i] confirm_rsp = $ctxt[:confirm_rsps][i] random_req = $ctxt[:random_reqs][i] random_rsp = $ctxt[:random_rsps][i] if confirm_req != nil puts confirm_to_s(confirm_req, true, i) end puts confirm_to_s(confirm_rsp, false, i) puts random_to_s(random_req, true, i) puts random_to_s(random_rsp, false, i) end if $ctxt[:sc] puts dhkey_check_to_s($ctxt[:dhkey_check_req], true) puts dhkey_check_to_s($ctxt[:dhkey_check_rsp], false) end if $ctxt[:enc_info_req] != nil puts enc_info_to_s($ctxt[:enc_info_req], true) end if $ctxt[:master_id_req] != nil puts master_id_to_s($ctxt[:master_id_req], true) end if $ctxt[:id_info_req] != nil puts id_info_to_s($ctxt[:id_info_req], true) end if $ctxt[:id_addr_info_req] != nil puts id_addr_info_to_s($ctxt[:id_addr_info_req], true) end if $ctxt[:sign_info_req] != nil puts sign_info_to_s($ctxt[:sign_info_req], true) end if $ctxt[:enc_info_rsp] != nil puts enc_info_to_s($ctxt[:enc_info_rsp], false) end if $ctxt[:master_id_rsp] != nil puts master_id_to_s($ctxt[:master_id_rsp], false) end if $ctxt[:id_info_rsp] != nil puts id_info_to_s($ctxt[:id_info_rsp], false) end if $ctxt[:id_addr_info_rsp] != nil puts id_addr_info_to_s($ctxt[:id_addr_info_rsp], false) end if $ctxt[:sign_info_rsp] != nil puts sign_info_to_s($ctxt[:sign_info_rsp], false) end if $ctxt[:sc] puts ltk_to_s($ctxt[:ltk]) else puts stk_to_s($ctxt[:stk]) end puts passkey_info_s() puts ' };' if $ctxt[:sc] if $ctxt[:we_are_init] puts ' ble_sm_test_util_us_sc_good(¶ms);' else puts ' ble_sm_test_util_peer_sc_good(¶ms);' end else if $ctxt[:we_are_init] puts ' ble_sm_test_util_us_lgcy_good(¶ms);' else puts ' ble_sm_test_util_peer_lgcy_good(¶ms);' end end puts '}'