Low-counter reporting, counter sync probe, Bad-format decode, expanded forms
Live findings that drove this: the "card counter 0000000000" the low-counter notice showed is not the card's counter at all (the PoR's CNTR is a copy of the command's counter, TS 102 225 5.2 table 3, and a rejection leaves it zeroed); and an earlier "no card accepts the expanded format" observation was a hand-made template whose declared length did not match its body - the card validates the lengths and answers with a Bad format TLV. - _cntr_low_fields(status) reports the verdict as a flag; card_cntr/ suggested_cntr and the UI's "(card counter ...)" text are gone - the value is not observable. The notice offers a bounded Sync counter probe instead. - POST /api/counter-probe: a doubling counter ladder (start+1, +2, +4, ...) with a read-only command until the card accepts one, then accepted+1 is persisted (monotonic, source counter-probe). Rejected attempts change nothing on the card; the search stops at a ceiling (default FFFFFFFF, far below the 40-bit maximum where the counter blocks) and after max_attempts (default 40, clamped 1-64); a non-cntr_low failure stops it at once. - _parse_response_scripting decodes the Bad format TLV (90, TS 101 220 table 7.20; error types per TS 102 226 table 5.12) and returns a dict; the PoR carries bad_format/bad_format_name and _ram_step_result fails the step with "bad format 02 (wrong length)" instead of falling through to the compact decoder (which read the AB tag as 171 commands). - _wrap_expanded_apdu(apdu, form) emits the definite (AA) or the indefinite (AE 80 ... 00 00) scripting template; the RAM command formats are compact/ expanded/expanded-ae and _ram_detect_format probes compact, then both expanded codings (the expanded probes use Le='00' and no chained GET RESPONSE, TS 102 226 5.2.1.1). The RAM form gains a Format selector. - Live-verified: the verdict carries no value; the probe walked 0x1000001/0x1000003 (low) then 0x1000007 (accepted, stored 0x1000008); the ISD executes both expanded codings (R-APDU 08A0000000030000000F80, SW 9000) and a length-mismatched template answers bad_format 02 - decoded now. - Tests: the ladder, the probe walk + persistence, params validation, both template forms, the Bad-format TLV (definite and plain tag styles), the live ISD response through _decode_por, the step-result failure, and the PWA guards; help EN/RU, docs/api.md, the repo AGENTS.md; sw cache simple-v352.
This commit is contained in:
@@ -389,8 +389,10 @@ class CntrLowGuardHttpTests(unittest.TestCase):
|
||||
p.stop()
|
||||
self.assertEqual(status, 200, resp)
|
||||
self.assertTrue(resp['cntr_low'], resp)
|
||||
self.assertEqual(resp['card_cntr'], '00000000BB')
|
||||
self.assertEqual(resp['suggested_cntr'], '00000000BC')
|
||||
# the PoR's CNTR is a copy of the command's counter, not the card's:
|
||||
# the verdict is reported without a value (v3.9.x)
|
||||
self.assertNotIn('card_cntr', resp)
|
||||
self.assertNotIn('suggested_cntr', resp)
|
||||
|
||||
def test_the_ram_chain_stops_at_a_low_counter(self):
|
||||
calls = []
|
||||
@@ -425,8 +427,10 @@ class CntrLowGuardHttpTests(unittest.TestCase):
|
||||
self.assertFalse(resp['success'], resp)
|
||||
self.assertEqual(len(calls), 2, calls) # nothing after the verdict
|
||||
self.assertTrue(resp['cntr_low'], resp)
|
||||
self.assertEqual(resp['card_cntr'], '00000000BB')
|
||||
self.assertEqual(resp['suggested_cntr'], '00000000BC')
|
||||
# the PoR's CNTR is a copy of the command's counter, not the card's:
|
||||
# the verdict is reported without a value (v3.9.x)
|
||||
self.assertNotIn('card_cntr', resp)
|
||||
self.assertNotIn('suggested_cntr', resp)
|
||||
|
||||
|
||||
class TarProbeListTests(unittest.TestCase):
|
||||
|
||||
Reference in New Issue
Block a user