fix: use the card's own SimCardCommands for ADM and AUTHENTICATE (v2.7.20)
/api/verify-adm sent VERIFY with CLA A0 on a UICC (SW 6E00) while pySim-shell's verify_adm worked: fast init builds the card on its own SimCardCommands instance, but __main__ kept server.scc at the startup placeholder left at the SIM defaults; only an equip repointed it. - __main__ adopts card._scc after init (cat_cla still set on it), so server.scc carries the card's cla_byte/sel_ctrl from startup on. - _verify_adm prefers app.rs.lchan[0].scc / app.card._scc, exactly like pySim-shell's verify_adm, independent of server.scc. - netsim AUTHENTICATE follows the card class: a UICC gets 00 88 00 81 22 (RAND+AUTN, DB/DC response), a SIM gets A0 88 00 00 10 (RAND only, SRES+Kc); the 61xx GET RESPONSE uses the same CLA. - tests: ADM with a stale placeholder scc; 2G builder/parser; SIM-CLA runner case; help EN/RU and AGENTS updated.
This commit is contained in:
@@ -77,6 +77,23 @@ class AdmVerifyTests(unittest.TestCase):
|
||||
self.assertEqual(out, {'adm': '<redacted>', 'psk_hex': '<redacted>', 'other': 'x'})
|
||||
self.assertEqual(server._redact_psk_fields({'adm': ''}), {'adm': ''})
|
||||
|
||||
def test_verify_adm_uses_the_cards_own_channel(self):
|
||||
# server.scc can be the startup placeholder left at the SIM CLA ('a0')
|
||||
# while the card is a UICC: the VERIFY must go out through the card's
|
||||
# own channel (CLA 00), exactly like pySim-shell's verify_adm.
|
||||
stale = FakeScc('6E00')
|
||||
stale.cla_byte = 'a0'
|
||||
card_scc = FakeScc('9000')
|
||||
card_scc.cla_byte = '00'
|
||||
app = SimpleNamespace(
|
||||
card=SimpleNamespace(_adm_chv_num=0x0A, _scc=card_scc),
|
||||
rs=SimpleNamespace(adm_verified=False,
|
||||
lchan=[SimpleNamespace(scc=card_scc)]))
|
||||
res = server._verify_adm(stale, app, '0011')
|
||||
self.assertEqual(res, {'ok': True, 'sw': '9000'})
|
||||
self.assertEqual(card_scc.apdus, ['0020000A08' + '0011' + 'f' * 12])
|
||||
self.assertEqual(stale.apdus, [])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -191,6 +191,17 @@ class BuilderTests(unittest.TestCase):
|
||||
self.assertEqual(sync['objects'], ['CC' * 16])
|
||||
self.assertIsNone(netsim.parse_auth_response('9000'))
|
||||
|
||||
def test_authenticate_2g_apdu_and_response(self):
|
||||
# SIM cards use the 2G AUTHENTICATE: P1/P2 00, RAND only
|
||||
self.assertEqual(netsim.build_auth_apdu_gsm('11' * 16),
|
||||
'A088000010' + '11' * 16)
|
||||
parsed = netsim.parse_auth_response('AABBCCDD' + '1122334455667788',
|
||||
gsm=True)
|
||||
self.assertEqual(parsed, {'type': 'gsm', 'sres': 'AABBCCDD',
|
||||
'kc': '1122334455667788'})
|
||||
# a truncated 2G response is not parsed
|
||||
self.assertIsNone(netsim.parse_auth_response('AABBCCDD', gsm=True))
|
||||
|
||||
|
||||
class FakeFileInfo:
|
||||
def __init__(self, size=None, record_len=None, num=1, data=''):
|
||||
@@ -430,6 +441,23 @@ class RunnerTests(unittest.TestCase):
|
||||
self.assertEqual(step['sw'], '9000')
|
||||
self.assertEqual(step['parsed']['type'], 'success')
|
||||
|
||||
def test_authenticate_uses_the_2g_command_for_a_sim_cla(self):
|
||||
runner, lchan, srv = make_runner()
|
||||
scc = srv._server_ref.scc
|
||||
scc.cla_byte = 'a0' # a SIM card session
|
||||
sent = []
|
||||
def _send(apdu):
|
||||
sent.append(apdu)
|
||||
return 'AABBCCDD' + '11' * 8, '9000'
|
||||
scc._tp.send_apdu = _send
|
||||
out = runner.run('authenticate')
|
||||
self.assertTrue(out['success'])
|
||||
self.assertTrue(sent[0].startswith('A088000010'), sent[0])
|
||||
step = [s for s in out['steps'] if s['action'] == 'authenticate'][0]
|
||||
self.assertEqual(step['sw'], '9000')
|
||||
self.assertEqual(step['parsed'],
|
||||
{'type': 'gsm', 'sres': 'AABBCCDD', 'kc': '11' * 8})
|
||||
|
||||
def test_unknown_scenario_raises(self):
|
||||
runner, _lchan, _srv = make_runner()
|
||||
with self.assertRaises(ValueError):
|
||||
|
||||
Reference in New Issue
Block a user