blob: c176f8aa47923feeebdb9a12d44b9c8ac90d2650 [file] [log] [blame]
Sylvain Munaute7c15cd2010-12-07 10:01:55 +01001# -*- coding: utf-8 -*-
2
3""" pySim: PCSC reader transport link base
4"""
5
Harald Welte6e0458d2021-04-03 11:52:37 +02006from typing import Optional
7
Harald Weltee79cc802021-01-21 14:10:43 +01008from pySim.exceptions import *
Harald Welte67d551a2021-01-21 14:50:01 +01009from pySim.utils import sw_match
Harald Weltee79cc802021-01-21 14:10:43 +010010
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010011#
12# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
13#
14# This program is free software: you can redistribute it and/or modify
15# it under the terms of the GNU General Public License as published by
16# the Free Software Foundation, either version 2 of the License, or
17# (at your option) any later version.
18#
19# This program is distributed in the hope that it will be useful,
20# but WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22# GNU General Public License for more details.
23#
24# You should have received a copy of the GNU General Public License
25# along with this program. If not, see <http://www.gnu.org/licenses/>.
26#
27
28class LinkBase(object):
Harald Welteee3501f2021-04-02 13:00:18 +020029 """Base class for link/transport to card."""
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010030
Harald Welteeb05b2f2021-04-10 11:01:56 +020031 def __init__(self, sw_interpreter=None):
32 self.sw_interpreter = sw_interpreter
Harald Welte4f2c5462021-04-03 11:48:22 +020033
34 def set_sw_interpreter(self, interp):
35 """Set an (optional) status word interpreter."""
36 self.sw_interpreter = interp
37
Harald Welteee3501f2021-04-02 13:00:18 +020038 def wait_for_card(self, timeout:int=None, newcardonly:bool=False):
39 """Wait for a card and connect to it
Sylvain Munautbdca2522010-12-09 13:31:58 +010040
Harald Welteee3501f2021-04-02 13:00:18 +020041 Args:
42 timeout : Maximum wait time in seconds (None=no timeout)
43 newcardonly : Should we wait for a new card, or an already inserted one ?
Sylvain Munautbdca2522010-12-09 13:31:58 +010044 """
45 pass
46
47 def connect(self):
Harald Welteee3501f2021-04-02 13:00:18 +020048 """Connect to a card immediately
Sylvain Munautbdca2522010-12-09 13:31:58 +010049 """
50 pass
51
52 def disconnect(self):
Harald Welteee3501f2021-04-02 13:00:18 +020053 """Disconnect from card
Sylvain Munautbdca2522010-12-09 13:31:58 +010054 """
55 pass
56
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010057 def reset_card(self):
Harald Welteee3501f2021-04-02 13:00:18 +020058 """Resets the card (power down/up)
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010059 """
60 pass
61
Harald Welteee3501f2021-04-02 13:00:18 +020062 def send_apdu_raw(self, pdu:str):
63 """Sends an APDU with minimal processing
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010064
Harald Welteee3501f2021-04-02 13:00:18 +020065 Args:
66 pdu : string of hexadecimal characters (ex. "A0A40000023F00")
67 Returns:
68 tuple(data, sw), where
69 data : string (in hex) of returned data (ex. "074F4EFFFF")
70 sw : string (in hex) of status word (ex. "9000")
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010071 """
Harald Weltec34f9402021-04-10 10:55:24 +020072 return self._send_apdu_raw(pdu)
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010073
74 def send_apdu(self, pdu):
Harald Welteee3501f2021-04-02 13:00:18 +020075 """Sends an APDU and auto fetch response data
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010076
Harald Welteee3501f2021-04-02 13:00:18 +020077 Args:
78 pdu : string of hexadecimal characters (ex. "A0A40000023F00")
79 Returns:
80 tuple(data, sw), where
81 data : string (in hex) of returned data (ex. "074F4EFFFF")
82 sw : string (in hex) of status word (ex. "9000")
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010083 """
84 data, sw = self.send_apdu_raw(pdu)
85
Philipp Maier859e0fd2018-06-12 18:40:24 +020086 # When whe have sent the first APDU, the SW may indicate that there are response bytes
87 # available. There are two SWs commonly used for this 9fxx (sim) and 61xx (usim), where
88 # xx is the number of response bytes available.
89 # See also:
90 # SW1=9F: 3GPP TS 51.011 9.4.1, Responses to commands which are correctly executed
91 # SW1=61: ISO/IEC 7816-4, Table 5 — General meaning of the interindustry values of SW1-SW2
92 if (sw is not None) and ((sw[0:2] == '9f') or (sw[0:2] == '61')):
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010093 pdu_gr = pdu[0:2] + 'c00000' + sw[2:4]
94 data, sw = self.send_apdu_raw(pdu_gr)
95
96 return data, sw
97
98 def send_apdu_checksw(self, pdu, sw="9000"):
Harald Welteee3501f2021-04-02 13:00:18 +020099 """Sends an APDU and check returned SW
Sylvain Munaute7c15cd2010-12-07 10:01:55 +0100100
Harald Welteee3501f2021-04-02 13:00:18 +0200101 Args:
102 pdu : string of hexadecimal characters (ex. "A0A40000023F00")
103 sw : string of 4 hexadecimal characters (ex. "9000"). The user may mask out certain
104 digits using a '?' to add some ambiguity if needed.
105 Returns:
106 tuple(data, sw), where
107 data : string (in hex) of returned data (ex. "074F4EFFFF")
108 sw : string (in hex) of status word (ex. "9000")
Sylvain Munaute7c15cd2010-12-07 10:01:55 +0100109 """
110 rv = self.send_apdu(pdu)
Philipp Maierd4ebb6f2018-06-12 17:56:07 +0200111
Harald Welte67d551a2021-01-21 14:50:01 +0100112 if not sw_match(rv[1], sw):
Harald Welte4f2c5462021-04-03 11:48:22 +0200113 raise SwMatchError(rv[1], sw.lower(), self.sw_interpreter)
Sylvain Munaute7c15cd2010-12-07 10:01:55 +0100114 return rv
Harald Welte6e0458d2021-04-03 11:52:37 +0200115
Harald Welteeb05b2f2021-04-10 11:01:56 +0200116def init_reader(opts, **kwargs) -> Optional[LinkBase]:
Harald Welte6e0458d2021-04-03 11:52:37 +0200117 """
118 Init card reader driver
119 """
120 sl = None # type : :Optional[LinkBase]
121 try:
122 if opts.pcsc_dev is not None:
123 print("Using PC/SC reader interface")
124 from pySim.transport.pcsc import PcscSimLink
Harald Welteeb05b2f2021-04-10 11:01:56 +0200125 sl = PcscSimLink(opts.pcsc_dev, **kwargs)
Harald Welte6e0458d2021-04-03 11:52:37 +0200126 elif opts.osmocon_sock is not None:
127 print("Using Calypso-based (OsmocomBB) reader interface")
128 from pySim.transport.calypso import CalypsoSimLink
Harald Welteeb05b2f2021-04-10 11:01:56 +0200129 sl = CalypsoSimLink(sock_path=opts.osmocon_sock, **kwargs)
Harald Welte6e0458d2021-04-03 11:52:37 +0200130 elif opts.modem_dev is not None:
131 print("Using modem for Generic SIM Access (3GPP TS 27.007)")
132 from pySim.transport.modem_atcmd import ModemATCommandLink
Harald Welteeb05b2f2021-04-10 11:01:56 +0200133 sl = ModemATCommandLink(device=opts.modem_dev, baudrate=opts.modem_baud, **kwargs)
Harald Welte6e0458d2021-04-03 11:52:37 +0200134 else: # Serial reader is default
135 print("Using serial reader interface")
136 from pySim.transport.serial import SerialSimLink
Harald Welteeb05b2f2021-04-10 11:01:56 +0200137 sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate, **kwargs)
Harald Welte6e0458d2021-04-03 11:52:37 +0200138 return sl
139 except Exception as e:
140 print("Card reader initialization failed with exception:\n" + str(e))
141 return None