From d5aa963caa89ea804aa86a098c6ccc41d30e2840 Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Mon, 23 Mar 2026 17:32:12 +0100 Subject: [PATCH] pysim/pcsc: do not use getProtocol for protocol selection The documentation of the getProtocol provided by pyscard says: "Return bit mask for the protocol of connection, or None if no protocol set. The return value is a bit mask of CardConnection.T0_protocol, CardConnection.T1_protocol, CardConnection.RAW_protocol, CardConnection.T15_protocol" This suggests that the purpose of getProtocol is not to determine which protocols are supported. Its purpose is to determine which protocol is currently selected (either through auto selection or through the explicit selection made by the API user). This means we are using getProtocol wrong. So far this was no problem, since the auto-selected protocol should be a supported protocol anyway. However, the automatic protocol selection may not always return a correct result (see bug report from THD-siegfried [1]). Let's not trust the automatic protocol selection. Instead let's parse the ATR and make the decision based on the TD1/TD2 bytes). [1] https://osmocom.org/issues/6952 Related: OS#6952 Change-Id: Ib119948aa68c430e42ac84daec8b9bd542db7963 --- pySim/transport/pcsc.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pySim/transport/pcsc.py b/pySim/transport/pcsc.py index c92a3ba2..21d3ce4d 100644 --- a/pySim/transport/pcsc.py +++ b/pySim/transport/pcsc.py @@ -26,6 +26,7 @@ from smartcard.CardRequest import CardRequest from smartcard.Exceptions import NoCardException, CardRequestTimeoutException, CardConnectionException from smartcard.System import readers from smartcard.ExclusiveConnectCardConnection import ExclusiveConnectCardConnection +from smartcard.ATR import ATR from osmocom.utils import h2i, i2h, Hexstr @@ -84,18 +85,21 @@ class PcscSimLink(LinkBaseTpdu): self.disconnect() # Make card connection and select a suitable communication protocol + # (Even though pyscard provides an automatic protocol selection, we will make an independent decision + # based on the ATR. There are two reasons for that: + # 1) In case a card supports T=0 and T=1, we perfer to use T=0. + # 2) The automatic protocol selection may be unreliabe on some platforms + # see also: https://osmocom.org/issues/6952) self._con.connect() - supported_protocols = self._con.getProtocol(); - self.disconnect() - if (supported_protocols & CardConnection.T0_protocol): - protocol = CardConnection.T0_protocol + atr = ATR(self._con.getATR()) + if atr.isT0Supported(): + self._con.setProtocol(CardConnection.T0_protocol) self.set_tpdu_format(0) - elif (supported_protocols & CardConnection.T1_protocol): - protocol = CardConnection.T1_protocol + elif atr.isT1Supported(): + self._con.setProtocol(CardConnection.T1_protocol) self.set_tpdu_format(1) else: raise ReaderError('Unsupported card protocol') - self._con.connect(protocol) except CardConnectionException as exc: raise ProtocolError() from exc except NoCardException as exc: