1 """PCSCPart10: PC/SC Part 10 (pinpad)
2
3 __author__ = "Ludovic Rousseau"
4
5 Copyright 2009-2010 Ludovic Rosseau
6 Author: Ludovic Rousseau, mailto:ludovic.rousseau@free.fr
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.scard import *
27
28
29 CM_IOCTL_GET_FEATURE_REQUEST = SCARD_CTL_CODE(3400)
30
31 FEATURE_VERIFY_PIN_START = 0x01
32 FEATURE_VERIFY_PIN_FINISH = 0x02
33 FEATURE_MODIFY_PIN_START = 0x03
34 FEATURE_MODIFY_PIN_FINISH = 0x04
35 FEATURE_GET_KEY_PRESSED = 0x05
36 FEATURE_VERIFY_PIN_DIRECT = 0x06
37 FEATURE_MODIFY_PIN_DIRECT = 0x07
38 FEATURE_MCT_READER_DIRECT = 0x08
39 FEATURE_MCT_UNIVERSAL = 0x09
40 FEATURE_IFD_PIN_PROPERTIES = 0x0A
41 FEATURE_ABORT = 0x0B
42 FEATURE_SET_SPE_MESSAGE = 0x0C
43 FEATURE_VERIFY_PIN_DIRECT_APP_ID = 0x0D
44 FEATURE_MODIFY_PIN_DIRECT_APP_ID = 0x0E
45 FEATURE_WRITE_DISPLAY = 0x0F
46 FEATURE_GET_KEY = 0x10
47 FEATURE_IFD_DISPLAY_PROPERTIES = 0x11
48 FEATURE_GET_TLV_PROPERTIES = 0x12
49 FEATURE_CCID_ESC_COMMAND = 0x13
50
51 Features = {
52 "FEATURE_VERIFY_PIN_START": FEATURE_VERIFY_PIN_START,
53 "FEATURE_VERIFY_PIN_FINISH": FEATURE_VERIFY_PIN_FINISH,
54 "FEATURE_MODIFY_PIN_START": FEATURE_MODIFY_PIN_START,
55 "FEATURE_MODIFY_PIN_FINISH": FEATURE_MODIFY_PIN_FINISH,
56 "FEATURE_GET_KEY_PRESSED": FEATURE_GET_KEY_PRESSED,
57 "FEATURE_VERIFY_PIN_DIRECT": FEATURE_VERIFY_PIN_DIRECT,
58 "FEATURE_MODIFY_PIN_DIRECT": FEATURE_MODIFY_PIN_DIRECT,
59 "FEATURE_MCT_READER_DIRECT": FEATURE_MCT_READER_DIRECT,
60 "FEATURE_MCT_UNIVERSAL": FEATURE_MCT_UNIVERSAL,
61 "FEATURE_IFD_PIN_PROPERTIES": FEATURE_IFD_PIN_PROPERTIES,
62 "FEATURE_ABORT": FEATURE_ABORT,
63 "FEATURE_SET_SPE_MESSAGE": FEATURE_SET_SPE_MESSAGE,
64 "FEATURE_VERIFY_PIN_DIRECT_APP_ID": FEATURE_VERIFY_PIN_DIRECT_APP_ID,
65 "FEATURE_MODIFY_PIN_DIRECT_APP_ID": FEATURE_MODIFY_PIN_DIRECT_APP_ID,
66 "FEATURE_WRITE_DISPLAY": FEATURE_WRITE_DISPLAY,
67 "FEATURE_GET_KEY": FEATURE_GET_KEY,
68 "FEATURE_IFD_DISPLAY_PROPERTIES": FEATURE_IFD_DISPLAY_PROPERTIES,
69 "FEATURE_GET_TLV_PROPERTIES": FEATURE_GET_TLV_PROPERTIES,
70 "FEATURE_CCID_ESC_COMMAND": FEATURE_CCID_ESC_COMMAND}
71
72
73 PCSCv2_PART10_PROPERTY_wLcdLayout = 1
74 PCSCv2_PART10_PROPERTY_bEntryValidationCondition = 2
75 PCSCv2_PART10_PROPERTY_bTimeOut2 = 3
76 PCSCv2_PART10_PROPERTY_wLcdMaxCharacters = 4
77 PCSCv2_PART10_PROPERTY_wLcdMaxLines = 5
78 PCSCv2_PART10_PROPERTY_bMinPINSize = 6
79 PCSCv2_PART10_PROPERTY_bMaxPINSize = 7
80 PCSCv2_PART10_PROPERTY_sFirmwareID = 8
81 PCSCv2_PART10_PROPERTY_bPPDUSupport = 9
82 PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize = 10
83 PCSCv2_PART10_PROPERTY_wIdVendor = 11
84 PCSCv2_PART10_PROPERTY_wIdProduct = 12
85
86 Properties = {
87 "PCSCv2_PART10_PROPERTY_wLcdLayout": PCSCv2_PART10_PROPERTY_wLcdLayout,
88 "PCSCv2_PART10_PROPERTY_bEntryValidationCondition": \
89 PCSCv2_PART10_PROPERTY_bEntryValidationCondition,
90 "PCSCv2_PART10_PROPERTY_bTimeOut2": PCSCv2_PART10_PROPERTY_bTimeOut2,
91 "PCSCv2_PART10_PROPERTY_wLcdMaxCharacters": \
92 PCSCv2_PART10_PROPERTY_wLcdMaxCharacters,
93 "PCSCv2_PART10_PROPERTY_wLcdMaxLines": PCSCv2_PART10_PROPERTY_wLcdMaxLines,
94 "PCSCv2_PART10_PROPERTY_bMinPINSize": PCSCv2_PART10_PROPERTY_bMinPINSize,
95 "PCSCv2_PART10_PROPERTY_bMaxPINSize": PCSCv2_PART10_PROPERTY_bMaxPINSize,
96 "PCSCv2_PART10_PROPERTY_sFirmwareID": PCSCv2_PART10_PROPERTY_sFirmwareID,
97 "PCSCv2_PART10_PROPERTY_bPPDUSupport": PCSCv2_PART10_PROPERTY_bPPDUSupport,
98 "PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize": PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize,
99 "PCSCv2_PART10_PROPERTY_wIdVendor": PCSCv2_PART10_PROPERTY_wIdVendor,
100 "PCSCv2_PART10_PROPERTY_wIdProduct": PCSCv2_PART10_PROPERTY_wIdProduct}
101
102
103
104 for k in list(Features.keys()):
105 Features[Features[k]] = k
106
107 for k in list(Properties.keys()):
108 Properties[Properties[k]] = k
109
110
112 """ Get the list of Part10 features supported by the reader.
113
114 @param cardConnection: L{CardConnection} object
115
116 @rtype: list
117 @return: a list of list [[tag1, value1], [tag2, value2]]
118 """
119 response = cardConnection.control(CM_IOCTL_GET_FEATURE_REQUEST, [])
120 features = []
121 while (len(response) > 0):
122 tag = response[0]
123 control = (((((response[2] << 8) + \
124 response[3]) << 8) + \
125 response[4]) << 8) + \
126 response[5]
127 try:
128 features.append([Features[tag], control])
129 except KeyError:
130 pass
131 del response[:6]
132 return features
133
134
136 """ return the controlCode for a feature or None
137
138 @param feature: feature to look for
139 @param featureList: feature list as returned by L{getFeatureRequest()}
140
141 @return: feature value or None
142 """
143 for f in featureList:
144 if f[0] == feature or Features[f[0]] == feature:
145 return f[1]
146
147
149 """ return the PIN_PROPERTIES structure
150
151 @param cardConnection: L{CardConnection} object
152 @param featureList: feature list as returned by L{getFeatureRequest()}
153 @param controlCode: control code for L{FEATURE_IFD_PIN_PROPERTIES}
154
155 @rtype: dict
156 @return: a dict """
157 if controlCode is None:
158 if featureList is None:
159 featureList = getFeatureRequest(cardConnection)
160 controlCode = hasFeature(featureList, FEATURE_IFD_PIN_PROPERTIES)
161
162 if controlCode is None:
163 return {'raw': []}
164
165 response = cardConnection.control(controlCode, [])
166 d = {
167 'raw': response,
168 'LcdLayoutX': response[0],
169 'LcdLayoutY': response[1],
170 'EntryValidationCondition': response[2],
171 'TimeOut2': response[3]}
172
173 return d
174
175
177 """ return the GET_TLV_PROPERTIES structure
178
179 @param cardConnection: L{CardConnection} object
180 @param featureList: feature list as returned by L{getFeatureRequest()}
181 @param controlCode: control code for L{FEATURE_GET_TLV_PROPERTIES}
182
183 @rtype: dict
184 @return: a dict """
185 if controlCode is None:
186 if featureList is None:
187 featureList = getFeatureRequest(cardConnection)
188 controlCode = hasFeature(featureList, FEATURE_GET_TLV_PROPERTIES)
189
190 if controlCode is None:
191 return {'raw': []}
192
193 response = cardConnection.control(controlCode, [])
194 d = {
195 'raw': response,
196 }
197
198
199 tmp = list(response)
200 while tmp:
201 tag = tmp[0]
202 len = tmp[1]
203 data = tmp[2:2 + len]
204
205 if PCSCv2_PART10_PROPERTY_sFirmwareID == tag:
206
207 data = "".join([chr(c) for c in data])
208
209 elif 1 == len:
210
211 data = data[0]
212 elif 2 == len:
213
214 data = data[1] * 256 + data[0]
215 elif 4 == len:
216
217 data = ((data[3] * 256 + data[2]) * 256 + data[1]) * 256 + data[0]
218
219
220 try:
221 d[Properties[tag]] = data
222 except KeyError:
223 d["UNKNOWN"] = data
224
225 del tmp[0:2 + len]
226
227 return d
228
229 if __name__ == '__main__':
230 """Small sample illustrating the use of PCSCPart10."""
231 from smartcard.pcsc.PCSCReader import PCSCReader
232 cc = PCSCReader.readers()[0].createConnection()
233 cc.connect(mode=SCARD_SHARE_DIRECT)
234
235
236 features = getFeatureRequest(cc)
237 print(features)
238
239 print(hasFeature(features, FEATURE_VERIFY_PIN_START))
240 print(hasFeature(features, FEATURE_VERIFY_PIN_DIRECT))
241
242 properties = getPinProperties(cc)
243 print("\nPinProperties:")
244 for k, v in list(properties.items()):
245 print(" %s: %s" % (k, v))
246
247 print("\nTlvProperties:")
248 properties = getTlvProperties(cc)
249 for k, v in list(properties.items()):
250 print(" %s: %s" % (k, v))
251