blob: 8a99e9f5336b24ea15f5ffaa9f4870ca70dd2806 [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>
Harald Weltead002792023-11-03 11:42:18 +01004# Copyright (C) 2010-2023 Harald Welte <laforge@gnumonks.org>
Sylvain Munaut76504e02010-12-07 00:24:32 +01005#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19
Philipp Maier8c823782023-10-23 10:44:44 +020020import argparse
Harald Weltead002792023-11-03 11:42:18 +010021import re
22from typing import Optional, Union
Harald Welteab6897c2023-07-09 16:21:23 +020023
Vadim Yanitskiyfa617ac2020-02-26 22:33:08 +070024from smartcard.CardConnection import CardConnection
Sylvain Munautbdca2522010-12-09 13:31:58 +010025from smartcard.CardRequest import CardRequest
Harald Welte2db843e2021-05-21 22:51:28 +020026from smartcard.Exceptions import NoCardException, CardRequestTimeoutException, CardConnectionException, CardConnectionException
Sylvain Munaut76504e02010-12-07 00:24:32 +010027from smartcard.System import readers
Sylvain Munaut76504e02010-12-07 00:24:32 +010028
Harald Welte2db843e2021-05-21 22:51:28 +020029from pySim.exceptions import NoCardError, ProtocolError, ReaderError
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010030from pySim.transport import LinkBase
Harald Weltef9f8d7a2023-07-09 17:06:16 +020031from pySim.utils import h2i, i2h, Hexstr, ResTuple
Sylvain Munaut76504e02010-12-07 00:24:32 +010032
33
Sylvain Munaute7c15cd2010-12-07 10:01:55 +010034class PcscSimLink(LinkBase):
Harald Weltec91085e2022-02-10 18:05:45 +010035 """ pySim: PCSC reader transport link."""
Harald Weltebaec4e92023-11-03 11:49:54 +010036 name = 'PC/SC'
Sylvain Munaut76504e02010-12-07 00:24:32 +010037
Harald Welte0f177c12023-12-17 12:38:29 +010038 def __init__(self, opts: argparse.Namespace = argparse.Namespace(pcsc_dev=0), **kwargs):
Harald Weltec91085e2022-02-10 18:05:45 +010039 super().__init__(**kwargs)
Harald Weltead002792023-11-03 11:42:18 +010040 self._reader = None
41 r = readers()
42 if opts.pcsc_dev is not None:
43 # actual reader index number (integer)
44 reader_number = opts.pcsc_dev
45 if reader_number >= len(r):
46 raise ReaderError('No reader found for number %d' % reader_number)
47 self._reader = r[reader_number]
48 else:
49 # reader regex string
50 cre = re.compile(opts.pcsc_regex)
51 for reader in r:
52 if cre.search(reader.name):
53 self._reader = reader
54 break
55 if not self._reader:
56 raise ReaderError('No matching reader found for regex %s' % opts.pcsc_regex)
57
58 self._con = self._reader.createConnection()
59
Harald Weltec91085e2022-02-10 18:05:45 +010060 def __del__(self):
61 try:
62 # FIXME: this causes multiple warnings in Python 3.5.3
63 self._con.disconnect()
64 except:
65 pass
66 return
Sylvain Munaut76504e02010-12-07 00:24:32 +010067
Harald Welteab6897c2023-07-09 16:21:23 +020068 def wait_for_card(self, timeout: Optional[int] = None, newcardonly: bool = False):
Harald Weltec91085e2022-02-10 18:05:45 +010069 cr = CardRequest(readers=[self._reader],
70 timeout=timeout, newcardonly=newcardonly)
71 try:
72 cr.waitforcard()
73 except CardRequestTimeoutException:
74 raise NoCardError()
75 self.connect()
Sylvain Munautbdca2522010-12-09 13:31:58 +010076
Harald Weltec91085e2022-02-10 18:05:45 +010077 def connect(self):
78 try:
79 # To avoid leakage of resources, make sure the reader
80 # is disconnected
81 self.disconnect()
Philipp Maier8bf21252021-09-22 15:30:21 +020082
Harald Weltec91085e2022-02-10 18:05:45 +010083 # Explicitly select T=0 communication protocol
84 self._con.connect(CardConnection.T0_protocol)
85 except CardConnectionException:
86 raise ProtocolError()
87 except NoCardException:
88 raise NoCardError()
Sylvain Munautbdca2522010-12-09 13:31:58 +010089
Harald Welteab6897c2023-07-09 16:21:23 +020090 def get_atr(self) -> Hexstr:
Harald Weltec91085e2022-02-10 18:05:45 +010091 return self._con.getATR()
Alexander Chemerisd2d660a2017-07-18 16:52:25 +030092
Harald Weltec91085e2022-02-10 18:05:45 +010093 def disconnect(self):
94 self._con.disconnect()
Sylvain Munautbdca2522010-12-09 13:31:58 +010095
Harald Weltec91085e2022-02-10 18:05:45 +010096 def reset_card(self):
97 self.disconnect()
98 self.connect()
99 return 1
Sylvain Munaut76504e02010-12-07 00:24:32 +0100100
Harald Weltef9f8d7a2023-07-09 17:06:16 +0200101 def _send_apdu_raw(self, pdu: Hexstr) -> ResTuple:
Sylvain Munaut76504e02010-12-07 00:24:32 +0100102
Harald Weltec91085e2022-02-10 18:05:45 +0100103 apdu = h2i(pdu)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100104
Harald Weltec91085e2022-02-10 18:05:45 +0100105 data, sw1, sw2 = self._con.transmit(apdu)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100106
Harald Weltec91085e2022-02-10 18:05:45 +0100107 sw = [sw1, sw2]
Sylvain Munaut76504e02010-12-07 00:24:32 +0100108
Harald Weltec91085e2022-02-10 18:05:45 +0100109 # Return value
110 return i2h(data), i2h(sw)
Philipp Maier6bfa8a82023-10-09 13:32:49 +0200111
Philipp Maier58e89eb2023-10-10 11:59:03 +0200112 def __str__(self) -> str:
Harald Weltead002792023-11-03 11:42:18 +0100113 return "PCSC[%s]" % (self._reader)
Philipp Maier8c823782023-10-23 10:44:44 +0200114
115 @staticmethod
116 def argparse_add_reader_args(arg_parser: argparse.ArgumentParser):
117 pcsc_group = arg_parser.add_argument_group('PC/SC Reader')
Harald Weltead002792023-11-03 11:42:18 +0100118 dev_group = pcsc_group.add_mutually_exclusive_group()
119 dev_group.add_argument('-p', '--pcsc-device', type=int, dest='pcsc_dev', metavar='PCSC', default=None,
120 help='Number of PC/SC reader to use for SIM access')
121 dev_group.add_argument('--pcsc-regex', type=str, dest='pcsc_regex', metavar='REGEX', default=None,
122 help='Regex matching PC/SC reader to use for SIM access')