v3.22.8: the text/dcs load-time validation (review follow-ups)

The review of the v3.22.7 fix asked when an expect can raise after its
FETCH: the realistic case is the scripted TERMINAL RESPONSE encoding -
_encode_text raises UnicodeEncodeError when respond.text has a non-GSM
character while dcs is 00 (the default) or 04, i.e. after the command was
fetched and with the card's proactive session left unanswered.  The other
candidates are guarded (the TPDU/PoR/file-list parsers, the PLI dictionary)
or need the card to be gone (a transport failure between the FETCH and the
TR).

normalise_respond now runs the same coding the TR builder uses and refuses
the script at load with an actionable message ("use dcs 08 (UCS2) for
non-GSM characters"), so the failure happens at save/run start, before any
FETCH; UCS2, ASCII and the empty answer are unaffected.

Also from the review: the guide's run-log line now documents the v3.22.7
format (TEST-RUN step N failed (<level>): ...), and the "unguarded item
text decode" observation proved a non-issue - _decode_stk_text is internally
tolerant (odd UCS2 / unknown prefixes fall back without raising), so the
item parsers are left alone.

Tests: a non-GSM text with the default dcs and with 04 is refused (the
message names dcs 08), UCS2/ASCII/empty pass, and a whole script is refused
with the same message.  843 frontend + 822 Python; sw cache simple-v412.
This commit is contained in:
2026-10-07 01:03:44 +03:00
parent 00675ca09c
commit eee2888a2b
7 changed files with 41 additions and 6 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ from osmocom.tlv import BER_TLV_IE
from osmocom.utils import rpad
VERSION = '3.22.7'
VERSION = '3.22.8'
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
+10
View File
@@ -568,6 +568,16 @@ def normalise_respond(respond, cmd_type=None):
out['text'] = str(respond['text'])
dcs = respond.get('dcs')
out['dcs'] = _int(dcs, 'respond dcs', 0, 255) if dcs is not None else 0x00
# The same coding the TERMINAL RESPONSE builder uses: a text the
# selected dcs cannot code (a non-GSM character with 00/04) must fail
# the script at load, not mid-run after the command was fetched
# (v3.22.8 review).
try:
_encode_text(out['text'], out['dcs'])
except Exception:
raise ScriptError(
'respond: the text cannot be coded with dcs %02X - use dcs 08 '
'(UCS2) for non-GSM characters' % out['dcs'])
extra = respond.get('raw')
if extra not in (None, ''):
out['raw'] = _data_hex(extra, 'respond raw')