blob: e253e69f0dcda4e49f175724bb4ed7729662d841 [file] [log] [blame]
#!/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=(?<io_cap>\d+)
\s
oob_data_flag=(?<oob_data_flag>\d+)
\s
authreq=(?<authreq>0x[0-9a-f]+)
\s
mac_enc_key_size=(?<max_enc_key_size>\d+)
\s
init_key_dist=(?<init_key_dist>\d+)
\s
resp_key_dist=(?<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(&params);'
else
puts ' ble_sm_test_util_peer_sc_good(&params);'
end
else
if $ctxt[:we_are_init]
puts ' ble_sm_test_util_us_lgcy_good(&params);'
else
puts ' ble_sm_test_util_peer_lgcy_good(&params);'
end
end
puts '}'