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