blob: 3313a5e1ba89c67f47b65f0ad07bc95bb5305831 [file] [log] [blame]
Sylvain Munaut76504e02010-12-07 00:24:32 +01001# -*- coding: utf-8 -*-
2
Sylvain Munaut76504e02010-12-07 00:24:32 +01003# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17#
18
Sylvain Munaut76504e02010-12-07 00:24:32 +010019import serial
20import time
Philipp Maier92bdd5e2021-02-22 16:14:47 +010021import os.path
Sylvain Munaut76504e02010-12-07 00:24:32 +010022
23from pySim.exceptions import NoCardError, ProtocolError
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010024from pySim.transport import LinkBase
Sylvain Munaut76504e02010-12-07 00:24:32 +010025from pySim.utils import h2b, b2h
26
27
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010028class SerialSimLink(LinkBase):
Harald Weltec91085e2022-02-10 18:05:45 +010029 """ pySim: Transport Link for serial (RS232) based readers included with simcard"""
Sylvain Munaut76504e02010-12-07 00:24:32 +010030
Harald Weltec91085e2022-02-10 18:05:45 +010031 def __init__(self, device: str = '/dev/ttyUSB0', baudrate: int = 9600, rst: str = '-rts',
32 debug: bool = False, **kwargs):
33 super().__init__(**kwargs)
34 if not os.path.exists(device):
35 raise ValueError("device file %s does not exist -- abort" % device)
36 self._sl = serial.Serial(
37 port=device,
38 parity=serial.PARITY_EVEN,
39 bytesize=serial.EIGHTBITS,
40 stopbits=serial.STOPBITS_TWO,
41 timeout=1,
42 xonxoff=0,
43 rtscts=0,
44 baudrate=baudrate,
45 )
46 self._rst_pin = rst
47 self._debug = debug
48 self._atr = None
Sylvain Munaut76504e02010-12-07 00:24:32 +010049
Harald Weltec91085e2022-02-10 18:05:45 +010050 def __del__(self):
51 if (hasattr(self, "_sl")):
52 self._sl.close()
Sylvain Munautbdca2522010-12-09 13:31:58 +010053
Harald Weltec91085e2022-02-10 18:05:45 +010054 def wait_for_card(self, timeout=None, newcardonly=False):
55 # Direct try
56 existing = False
Sylvain Munautbdca2522010-12-09 13:31:58 +010057
Harald Weltec91085e2022-02-10 18:05:45 +010058 try:
59 self.reset_card()
60 if not newcardonly:
61 return
62 else:
63 existing = True
64 except NoCardError:
65 pass
Sylvain Munautbdca2522010-12-09 13:31:58 +010066
Harald Weltec91085e2022-02-10 18:05:45 +010067 # Poll ...
68 mt = time.time() + timeout if timeout is not None else None
69 pe = 0
Sylvain Munautbdca2522010-12-09 13:31:58 +010070
Harald Weltec91085e2022-02-10 18:05:45 +010071 while (mt is None) or (time.time() < mt):
72 try:
73 time.sleep(0.5)
74 self.reset_card()
75 if not existing:
76 return
77 except NoCardError:
78 existing = False
79 except ProtocolError:
80 if existing:
81 existing = False
82 else:
83 # Tolerate a couple of protocol error ... can happen if
84 # we try when the card is 'half' inserted
85 pe += 1
86 if (pe > 2):
87 raise
Sylvain Munautbdca2522010-12-09 13:31:58 +010088
Harald Weltec91085e2022-02-10 18:05:45 +010089 # Timed out ...
90 raise NoCardError()
Sylvain Munautbdca2522010-12-09 13:31:58 +010091
Harald Weltec91085e2022-02-10 18:05:45 +010092 def connect(self):
93 self.reset_card()
Sylvain Munautbdca2522010-12-09 13:31:58 +010094
Harald Weltec91085e2022-02-10 18:05:45 +010095 def get_atr(self):
96 return self._atr
Alexander Chemerisd2d660a2017-07-18 16:52:25 +030097
Harald Weltec91085e2022-02-10 18:05:45 +010098 def disconnect(self):
99 pass # Nothing to do really ...
Sylvain Munautbdca2522010-12-09 13:31:58 +0100100
Harald Weltec91085e2022-02-10 18:05:45 +0100101 def reset_card(self):
102 rv = self._reset_card()
103 if rv == 0:
104 raise NoCardError()
105 elif rv < 0:
106 raise ProtocolError()
Philipp Maier621f78c2023-06-01 18:00:54 +0200107 return rv
Sylvain Munaut76504e02010-12-07 00:24:32 +0100108
Harald Weltec91085e2022-02-10 18:05:45 +0100109 def _reset_card(self):
110 self._atr = None
111 rst_meth_map = {
112 'rts': self._sl.setRTS,
113 'dtr': self._sl.setDTR,
114 }
115 rst_val_map = {'+': 0, '-': 1}
Sylvain Munaut76504e02010-12-07 00:24:32 +0100116
Harald Weltec91085e2022-02-10 18:05:45 +0100117 try:
118 rst_meth = rst_meth_map[self._rst_pin[1:]]
119 rst_val = rst_val_map[self._rst_pin[0]]
120 except:
121 raise ValueError('Invalid reset pin %s' % self._rst_pin)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100122
Harald Weltec91085e2022-02-10 18:05:45 +0100123 rst_meth(rst_val)
124 time.sleep(0.1) # 100 ms
125 self._sl.flushInput()
126 rst_meth(rst_val ^ 1)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100127
Harald Weltec91085e2022-02-10 18:05:45 +0100128 b = self._rx_byte()
129 if not b:
130 return 0
131 if ord(b) != 0x3b:
132 return -1
133 self._dbg_print("TS: 0x%x Direct convention" % ord(b))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100134
Harald Weltec91085e2022-02-10 18:05:45 +0100135 while ord(b) == 0x3b:
136 b = self._rx_byte()
Sylvain Munaut76504e02010-12-07 00:24:32 +0100137
Harald Weltec91085e2022-02-10 18:05:45 +0100138 if not b:
139 return -1
140 t0 = ord(b)
141 self._dbg_print("T0: 0x%x" % t0)
142 self._atr = [0x3b, ord(b)]
Sylvain Munaut76504e02010-12-07 00:24:32 +0100143
Harald Weltec91085e2022-02-10 18:05:45 +0100144 for i in range(4):
145 if t0 & (0x10 << i):
146 b = self._rx_byte()
147 self._atr.append(ord(b))
148 self._dbg_print("T%si = %x" % (chr(ord('A')+i), ord(b)))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100149
Harald Weltec91085e2022-02-10 18:05:45 +0100150 for i in range(0, t0 & 0xf):
151 b = self._rx_byte()
152 self._atr.append(ord(b))
153 self._dbg_print("Historical = %x" % ord(b))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100154
Harald Weltec91085e2022-02-10 18:05:45 +0100155 while True:
156 x = self._rx_byte()
157 if not x:
158 break
159 self._atr.append(ord(x))
160 self._dbg_print("Extra: %x" % ord(x))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100161
Harald Weltec91085e2022-02-10 18:05:45 +0100162 return 1
Sylvain Munaut76504e02010-12-07 00:24:32 +0100163
Harald Weltec91085e2022-02-10 18:05:45 +0100164 def _dbg_print(self, s):
165 if self._debug:
166 print(s)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100167
Harald Weltec91085e2022-02-10 18:05:45 +0100168 def _tx_byte(self, b):
169 self._sl.write(b)
170 r = self._sl.read()
171 if r != b: # TX and RX are tied, so we must clear the echo
172 raise ProtocolError("Bad echo value. Expected %02x, got %s)" % (
173 ord(b), '%02x' % ord(r) if r else '(nil)'))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100174
Harald Weltec91085e2022-02-10 18:05:45 +0100175 def _tx_string(self, s):
176 """This is only safe if it's guaranteed the card won't send any data
177 during the time of tx of the string !!!"""
178 self._sl.write(s)
179 r = self._sl.read(len(s))
180 if r != s: # TX and RX are tied, so we must clear the echo
181 raise ProtocolError(
182 "Bad echo value (Expected: %s, got %s)" % (b2h(s), b2h(r)))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100183
Harald Weltec91085e2022-02-10 18:05:45 +0100184 def _rx_byte(self):
185 return self._sl.read()
Sylvain Munaut76504e02010-12-07 00:24:32 +0100186
Harald Weltec91085e2022-02-10 18:05:45 +0100187 def _send_apdu_raw(self, pdu):
Sylvain Munaut76504e02010-12-07 00:24:32 +0100188
Harald Weltec91085e2022-02-10 18:05:45 +0100189 pdu = h2b(pdu)
190 data_len = pdu[4] # P3
Sylvain Munaut76504e02010-12-07 00:24:32 +0100191
Harald Weltec91085e2022-02-10 18:05:45 +0100192 # Send first CLASS,INS,P1,P2,P3
193 self._tx_string(pdu[0:5])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100194
Harald Weltec91085e2022-02-10 18:05:45 +0100195 # Wait ack which can be
196 # - INS: Command acked -> go ahead
197 # - 0x60: NULL, just wait some more
198 # - SW1: The card can apparently proceed ...
199 while True:
200 b = self._rx_byte()
201 if ord(b) == pdu[1]:
202 break
203 elif b != '\x60':
204 # Ok, it 'could' be SW1
205 sw1 = b
206 sw2 = self._rx_byte()
207 nil = self._rx_byte()
208 if (sw2 and not nil):
209 return '', b2h(sw1+sw2)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100210
Harald Weltec91085e2022-02-10 18:05:45 +0100211 raise ProtocolError()
Sylvain Munaut76504e02010-12-07 00:24:32 +0100212
Harald Weltec91085e2022-02-10 18:05:45 +0100213 # Send data (if any)
214 if len(pdu) > 5:
215 self._tx_string(pdu[5:])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100216
Harald Weltec91085e2022-02-10 18:05:45 +0100217 # Receive data (including SW !)
218 # length = [P3 - tx_data (=len(pdu)-len(hdr)) + 2 (SW1//2) ]
219 to_recv = data_len - len(pdu) + 5 + 2
Sylvain Munaut76504e02010-12-07 00:24:32 +0100220
Harald Weltec91085e2022-02-10 18:05:45 +0100221 data = bytes(0)
222 while (len(data) < to_recv):
223 b = self._rx_byte()
224 if (to_recv == 2) and (b == '\x60'): # Ignore NIL if we have no RX data (hack ?)
225 continue
226 if not b:
227 break
228 data += b
Sylvain Munaut76504e02010-12-07 00:24:32 +0100229
Harald Weltec91085e2022-02-10 18:05:45 +0100230 # Split datafield from SW
231 if len(data) < 2:
232 return None, None
233 sw = data[-2:]
234 data = data[0:-2]
Sylvain Munaut76504e02010-12-07 00:24:32 +0100235
Harald Weltec91085e2022-02-10 18:05:45 +0100236 # Return value
237 return b2h(data), b2h(sw)