fix: restore MF after fast-init probing so eUICC cards init cleanly (v2.8.1)

With an eUICC in the reader the fast init raised SwMatchError twice and
fell back to the stock pysim init: pick_profile_no_reset() disables the
physical resets that CardProfile.match_with_card() normally performs, so
the successful SGP.22 probe leaves the ISD-R ADF selected.  RuntimeState
then selects MF by FID (00 A4 00 04 02 3F00) from within the ADF, which
this card answers with 6A82.

- _restore_mf_after_probe() re-selects MF after the profile pick: the
  cheap select keeps the reset-free path for normal cards, a physical
  reset covers cards that refuse the MF select from an ADF.
- The EID read restores with rs.reset() (soft reset, escalating to a
  physical reset) instead of rs.soft_reset(), which had the same trap.
- tests: FakeScc mf_select_error mode + two _restore_mf_after_probe
  cases (no reset / exactly one physical reset).
This commit is contained in:
2026-09-21 23:20:50 +03:00
parent a4d5415034
commit 69b4caf5d8
6 changed files with 42 additions and 6 deletions
+20 -1
View File
@@ -80,6 +80,18 @@ def pick_profile_no_reset(scc):
scc.reset_card = original_reset
def _restore_mf_after_probe(scc):
"""Probing can leave an ADF (e.g. ISD-R on an eUICC) selected. The
RuntimeState construction selects MF by FID, which some cards refuse from
within an ADF (6A82), so restore it here: the cheap select keeps the
reset-free path for normal cards, the physical reset covers the rest."""
try:
scc.select_file('3f00')
except SwMatchError:
sys.stderr.write('FAST-INIT: MF restore after probing failed; physical reset\n')
scc.reset_card()
def init_card_fast(sl, skip_card_init=False, wait=True):
"""Replacement for pySim.app.init_card() that avoids redundant resets.
@@ -112,6 +124,11 @@ def _init_card_once(sl, skip_card_init, wait):
if profile is None:
return None, card
# A successful probe may leave an ADF selected (e.g. ISD-R on an eUICC);
# RuntimeState selects MF by FID and would fail on cards that refuse that
# from within an ADF.
_restore_mf_after_probe(scc)
if generic_card and isinstance(profile, CardProfileUICC):
card._adm_chv_num = 0x0A
@@ -137,7 +154,9 @@ def _init_card_once(sl, skip_card_init, wait):
except SwMatchError:
pass
finally:
rs.soft_reset()
# rs.reset() tries the reset-free soft reset first and escalates
# to a physical reset when MF cannot be selected from the ADF.
rs.reset()
return rs, card
+1 -1
View File
@@ -27,7 +27,7 @@ from osmocom.tlv import BER_TLV_IE
from osmocom.utils import rpad
VERSION = '2.8.0'
VERSION = '2.8.1'
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE