1 """PCSCCardConnection class manages connections thru a PCSC reader.
2
3 __author__ = "http://www.gemalto.com"
4
5 Copyright 2001-2012 gemalto
6 Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com
7
8 This file is part of pyscard.
9
10 pyscard is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14
15 pyscard is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with pyscard; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 """
24
25 from __future__ import print_function
26 from smartcard.CardConnection import CardConnection
27 from smartcard.Exceptions import (CardConnectionException,
28 NoCardException, SmartcardException)
29
30 from smartcard.scard import *
31
32
46
47
59
60 dictProtocolHeader = {SCARD_PCI_T0: 'T0', SCARD_PCI_T1: 'T1',
61 SCARD_PCI_RAW: 'RAW'}
62 dictProtocol = {SCARD_PROTOCOL_T0: 'T0', SCARD_PROTOCOL_T1: 'T1',
63 SCARD_PROTOCOL_RAW: 'RAW', SCARD_PROTOCOL_T15: 'T15',
64 SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1: 'T0 or T1'}
65
66
68 """PCSCCard connection class. Handles connection with a card thru a
69 PCSC reader."""
70
83
95
96 - def connect(self, protocol=None, mode=None, disposition=None):
97 """Connect to the card.
98
99 If protocol is not specified, connect with the default
100 connection protocol.
101
102 If mode is not specified, connect with SCARD_SHARE_SHARED."""
103 CardConnection.connect(self, protocol)
104 pcscprotocol = translateprotocolmask(protocol)
105 if 0 == pcscprotocol:
106 pcscprotocol = self.getProtocol()
107
108 if mode == None:
109 mode = SCARD_SHARE_SHARED
110
111
112 if disposition == None:
113 disposition = SCARD_UNPOWER_CARD
114 self.disposition = disposition
115
116 hresult, self.hcard, dwActiveProtocol = SCardConnect(
117 self.hcontext, str(self.reader), mode, pcscprotocol)
118 if hresult != 0:
119 self.hcard = None
120 if hresult in (SCARD_W_REMOVED_CARD, SCARD_E_NO_SMARTCARD):
121 raise NoCardException(
122 'Unable to connect: ' + \
123 SCardGetErrorMessage(hresult))
124 else:
125 raise CardConnectionException(
126 'Unable to connect with protocol: ' + \
127 dictProtocol[pcscprotocol] + '. ' + \
128 SCardGetErrorMessage(hresult))
129
130 protocol = 0
131 if dwActiveProtocol == SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1:
132
133
134
135 protocol = CardConnection.T0_protocol | CardConnection.T1_protocol
136 else:
137 for p in dictProtocol:
138 if p == dwActiveProtocol:
139 protocol = eval("CardConnection.%s_protocol" % dictProtocol[p])
140 PCSCCardConnection.setProtocol(self, protocol)
141
160
172
174 """Transmit an apdu to the card and return response apdu.
175
176 @param bytes: command apdu to transmit (list of bytes)
177
178 @param protocol: the transmission protocol, from
179 CardConnection.T0_protocol, CardConnection.T1_protocol, or
180 CardConnection.RAW_protocol
181
182 @return: a tuple (response, sw1, sw2) where
183 sw1 is status word 1, e.g. 0x90
184 sw2 is status word 2, e.g. 0x1A
185 response are the response bytes excluding status words
186 """
187 if None == protocol:
188 protocol = self.getProtocol()
189 CardConnection.doTransmit(self, bytes, protocol)
190 pcscprotocolheader = translateprotocolheader(protocol)
191 if 0 == pcscprotocolheader:
192 raise CardConnectionException(
193 'Invalid protocol in transmit: must be ' + \
194 'CardConnection.T0_protocol, ' + \
195 'CardConnection.T1_protocol, or ' + \
196 'CardConnection.RAW_protocol')
197 if None == self.hcard:
198 raise CardConnectionException('Card not connected')
199 hresult, response = SCardTransmit(
200 self.hcard, pcscprotocolheader, bytes)
201 if hresult != 0:
202 raise CardConnectionException(
203 'Failed to transmit with protocol ' + \
204 dictProtocolHeader[pcscprotocolheader] + '. ' + \
205 SCardGetErrorMessage(hresult))
206
207 sw1 = (response[-2] + 256) % 256
208 sw2 = (response[-1] + 256) % 256
209
210 data = [(x + 256) % 256 for x in response[:-2]]
211 return list(data), sw1, sw2
212
214 """Transmit a control command to the reader and return response.
215
216 controlCode: control command
217
218 bytes: command data to transmit (list of bytes)
219
220 return: response are the response bytes (if any)
221 """
222 CardConnection.doControl(self, controlCode, bytes)
223 hresult, response = SCardControl(self.hcard, controlCode, bytes)
224 if hresult != 0:
225 raise SmartcardException(
226 'Failed to control ' + SCardGetErrorMessage(hresult))
227
228 data = [(x + 256) % 256 for x in response]
229 return list(data)
230
244
245
246 if __name__ == '__main__':
247 """Small sample illustrating the use of CardConnection."""
248 SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
249 DF_TELECOM = [0x7F, 0x10]
250 from smartcard.pcsc.PCSCReader import PCSCReader
251 from smartcard.pcsc.PCSCPart10 import CM_IOCTL_GET_FEATURE_REQUEST
252 cc = PCSCReader.readers()[0].createConnection()
253 cc.connect()
254 print("%r %x %x" % cc.transmit(SELECT + DF_TELECOM))
255
256 print(cc.control(CM_IOCTL_GET_FEATURE_REQUEST, []))
257