fix: SCP80 RC/CPL parity, file-life-cycle labels, EF.ARR and PS template decoders (v3.5.1)
Three fixes found while filling the ETSI/3GPP registry gaps against the SIMalliance Stepping Stones R7: - SCP80 builder/verification parity (TS 31.115 Table 1 NOTE / 4.2 / 4.3): the CPL is now transmitted whenever the packet is ciphered or carries RC/CC/DS - it is part of their input - and whenever the packet needs SMS concatenation; a single unprotected SM keeps pySim's CHL-first form. Before, the JS dropped the CPL for every unciphered packet while the server reference re-added it, so "Verify vs pySim" reported a false MISMATCH for every unciphered RC/CC packet (SPI1 01/02/0A/12/1A...). All ten offered SPI1 values now match the server reference byte-for-byte. - RC (SPI1 b2b1 = 01) was offered but not built: the JS now computes CRC-32 (TS 102 225 5.1.3.2, pySim zlib.crc32 parity) over the same CPL frame as the CC; the packet no longer silently omits the 4-byte RC field. - Server: _build_secured_packet/_ota_reference add the CPL to a concatenated unprotected packet too (Table 1 NOTE / 4.3). - fcpLifeCycle: unlisted values with b8 clear are RFU, b8 set is proprietary (Table 11.7b); previously all unmatched values were labelled proprietary. - EF.ARR decoder now decodes the expanded format (AM_DO/SC_DO per ISO 7816-4 5.4.3.2 + TS 102 221 9.2.7): operation bit masks, INCREASE/RESIZE AM_DO 0x84, OR/AND/NOT templates, PIN key references with usage qualifiers. - FCP 'C6' PS template DO decoded (PS_DO bitmap + key references + usage qualifiers, TS 102 221 11.1.1.4.10/9.5.2) with a shared key-reference map. Tests: sp.test.js (CPL/RC vectors + crc32 known answer), ef_decode.test.js (expanded-format ARR vectors), profiler.test.js (LCSI RFU/proprietary, C6), test_ota_helpers.py (RC reference, unprotected single-SM vs concatenated). Help EN/RU and READMEs: CPL size 2 (SMS), RC/CC/DS 4-8, RC bullet, CPL rule. 547 frontend / 397 Python green; version 3.5.1; sw cache simple-v253.
This commit is contained in:
@@ -59,6 +59,8 @@ REFERENCE_VECTORS = {
|
||||
'00201516011515b00000e42573469e68a8462a57a505b0e2b1c09c1928c7a182311f',
|
||||
('02', '09'):
|
||||
'001d1502091515b0000000000000010085a8ca1a9828b0bb00a40000023f00',
|
||||
('01', '09'):
|
||||
'00191101091515b0000000000000010050c942dc00a40000023f00',
|
||||
}
|
||||
|
||||
# AES-128 reference vectors (public synthetic keys from pySim test_ota.py).
|
||||
@@ -153,6 +155,10 @@ class TestOtaReference(unittest.TestCase):
|
||||
out, _ = _ota_reference('02', '09', '15', '15', 'b00000', '0000000001', APDU, K, K)
|
||||
self.assertEqual(out, REFERENCE_VECTORS[('02', '09')])
|
||||
|
||||
def test_unciphered_rc_reference(self):
|
||||
out, _ = _ota_reference('01', '09', '15', '15', 'b00000', '0000000001', APDU, K, K)
|
||||
self.assertEqual(out, REFERENCE_VECTORS[('01', '09')])
|
||||
|
||||
def test_unciphered_cpl_is_0x001d(self):
|
||||
# Regression: CPL counts octets from the CHL octet to the last octet
|
||||
# of the secured data (29 here), it must NOT be len(out)-2 (27/0x001b).
|
||||
@@ -229,6 +235,22 @@ class TestSmsConcatenation(unittest.TestCase):
|
||||
self.assertEqual(_split_secured_packet(b'A' * 140, include_cpi=False),
|
||||
[b'A' * 140])
|
||||
|
||||
def test_unprotected_single_sm_keeps_the_chl_first_form(self):
|
||||
# TS 31.115 Table 1 NOTE: the CPL is "not absolutely necessary" in a
|
||||
# single SM - an unprotected packet keeps pySim's CHL-first form.
|
||||
out, _ = _build_secured_packet('00', '09', '15', '15', 'b00000',
|
||||
'0000000001', APDU, K, K)
|
||||
self.assertEqual(out[:2], '0d')
|
||||
|
||||
def test_unprotected_concatenated_packet_gains_the_cpl(self):
|
||||
# ... but it is required once the packet needs concatenation
|
||||
# (TS 31.115 Table 1 NOTE / 4.3).
|
||||
out, _ = _build_secured_packet('00', '09', '15', '15', 'b00000',
|
||||
'0000000001', 'A0' * 200, K, K)
|
||||
self.assertEqual(len(out) // 2, 216)
|
||||
self.assertEqual(out[:4], '00d6') # CPL = 214 = CHL..end
|
||||
self.assertEqual(int(out[:4], 16), len(out) // 2 - 2)
|
||||
|
||||
def test_240_byte_load_block_encodes_and_fits_the_card_buffer(self):
|
||||
# The RAM path no longer clamps LOAD blocks to one SMS: a 240-byte
|
||||
# block (the GP maximum) becomes a concatenated command.
|
||||
|
||||
Reference in New Issue
Block a user