Files
mykad-reader-api/.venv/lib/python3.9/site-packages/smartcard/pcsc/PCSCPart10.py
T
ISMAIL MASSERAN ca6e55f853 first init
2026-09-01 10:12:31 +08:00

275 lines
9.1 KiB
Python

"""PCSCPart10: PC/SC Part 10 (pinpad)
__author__ = "Ludovic Rousseau"
Copyright 2009-2010 Ludovic Rosseau
Author: Ludovic Rousseau, mailto:ludovic.rousseau@free.fr
This file is part of pyscard.
pyscard is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
pyscard is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with pyscard; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
from smartcard.scard import SCARD_CTL_CODE, SCARD_SHARE_DIRECT
# constants defined in PC/SC v2 Part 10
CM_IOCTL_GET_FEATURE_REQUEST = SCARD_CTL_CODE(3400)
FEATURE_VERIFY_PIN_START = 0x01
FEATURE_VERIFY_PIN_FINISH = 0x02
FEATURE_MODIFY_PIN_START = 0x03
FEATURE_MODIFY_PIN_FINISH = 0x04
FEATURE_GET_KEY_PRESSED = 0x05
FEATURE_VERIFY_PIN_DIRECT = 0x06
FEATURE_MODIFY_PIN_DIRECT = 0x07
FEATURE_MCT_READER_DIRECT = 0x08
FEATURE_MCT_UNIVERSAL = 0x09
FEATURE_IFD_PIN_PROPERTIES = 0x0A
FEATURE_ABORT = 0x0B
FEATURE_SET_SPE_MESSAGE = 0x0C
FEATURE_VERIFY_PIN_DIRECT_APP_ID = 0x0D
FEATURE_MODIFY_PIN_DIRECT_APP_ID = 0x0E
FEATURE_WRITE_DISPLAY = 0x0F
FEATURE_GET_KEY = 0x10
FEATURE_IFD_DISPLAY_PROPERTIES = 0x11
FEATURE_GET_TLV_PROPERTIES = 0x12
FEATURE_CCID_ESC_COMMAND = 0x13
Features = {
"FEATURE_VERIFY_PIN_START": FEATURE_VERIFY_PIN_START,
"FEATURE_VERIFY_PIN_FINISH": FEATURE_VERIFY_PIN_FINISH,
"FEATURE_MODIFY_PIN_START": FEATURE_MODIFY_PIN_START,
"FEATURE_MODIFY_PIN_FINISH": FEATURE_MODIFY_PIN_FINISH,
"FEATURE_GET_KEY_PRESSED": FEATURE_GET_KEY_PRESSED,
"FEATURE_VERIFY_PIN_DIRECT": FEATURE_VERIFY_PIN_DIRECT,
"FEATURE_MODIFY_PIN_DIRECT": FEATURE_MODIFY_PIN_DIRECT,
"FEATURE_MCT_READER_DIRECT": FEATURE_MCT_READER_DIRECT,
"FEATURE_MCT_UNIVERSAL": FEATURE_MCT_UNIVERSAL,
"FEATURE_IFD_PIN_PROPERTIES": FEATURE_IFD_PIN_PROPERTIES,
"FEATURE_ABORT": FEATURE_ABORT,
"FEATURE_SET_SPE_MESSAGE": FEATURE_SET_SPE_MESSAGE,
"FEATURE_VERIFY_PIN_DIRECT_APP_ID": FEATURE_VERIFY_PIN_DIRECT_APP_ID,
"FEATURE_MODIFY_PIN_DIRECT_APP_ID": FEATURE_MODIFY_PIN_DIRECT_APP_ID,
"FEATURE_WRITE_DISPLAY": FEATURE_WRITE_DISPLAY,
"FEATURE_GET_KEY": FEATURE_GET_KEY,
"FEATURE_IFD_DISPLAY_PROPERTIES": FEATURE_IFD_DISPLAY_PROPERTIES,
"FEATURE_GET_TLV_PROPERTIES": FEATURE_GET_TLV_PROPERTIES,
"FEATURE_CCID_ESC_COMMAND": FEATURE_CCID_ESC_COMMAND,
}
# properties returned by FEATURE_GET_TLV_PROPERTIES
PCSCv2_PART10_PROPERTY_wLcdLayout = 1
PCSCv2_PART10_PROPERTY_bEntryValidationCondition = 2
PCSCv2_PART10_PROPERTY_bTimeOut2 = 3
PCSCv2_PART10_PROPERTY_wLcdMaxCharacters = 4
PCSCv2_PART10_PROPERTY_wLcdMaxLines = 5
PCSCv2_PART10_PROPERTY_bMinPINSize = 6
PCSCv2_PART10_PROPERTY_bMaxPINSize = 7
PCSCv2_PART10_PROPERTY_sFirmwareID = 8
PCSCv2_PART10_PROPERTY_bPPDUSupport = 9
PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize = 10
PCSCv2_PART10_PROPERTY_wIdVendor = 11
PCSCv2_PART10_PROPERTY_wIdProduct = 12
Properties = {
"PCSCv2_PART10_PROPERTY_wLcdLayout": PCSCv2_PART10_PROPERTY_wLcdLayout,
"PCSCv2_PART10_PROPERTY_bEntryValidationCondition": PCSCv2_PART10_PROPERTY_bEntryValidationCondition, # pylint: disable=line-too-long
"PCSCv2_PART10_PROPERTY_bTimeOut2": PCSCv2_PART10_PROPERTY_bTimeOut2,
"PCSCv2_PART10_PROPERTY_wLcdMaxCharacters": PCSCv2_PART10_PROPERTY_wLcdMaxCharacters,
"PCSCv2_PART10_PROPERTY_wLcdMaxLines": PCSCv2_PART10_PROPERTY_wLcdMaxLines,
"PCSCv2_PART10_PROPERTY_bMinPINSize": PCSCv2_PART10_PROPERTY_bMinPINSize,
"PCSCv2_PART10_PROPERTY_bMaxPINSize": PCSCv2_PART10_PROPERTY_bMaxPINSize,
"PCSCv2_PART10_PROPERTY_sFirmwareID": PCSCv2_PART10_PROPERTY_sFirmwareID,
"PCSCv2_PART10_PROPERTY_bPPDUSupport": PCSCv2_PART10_PROPERTY_bPPDUSupport,
"PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize": PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize,
"PCSCv2_PART10_PROPERTY_wIdVendor": PCSCv2_PART10_PROPERTY_wIdVendor,
"PCSCv2_PART10_PROPERTY_wIdProduct": PCSCv2_PART10_PROPERTY_wIdProduct,
}
# we already have: Features['FEATURE_x'] = FEATURE_x
# we will now also have: Features[FEATURE_x] = 'FEATURE_x'
for k in list(Features.keys()):
Features[Features[k]] = k
for k in list(Properties.keys()):
Properties[Properties[k]] = k
def parseFeatureRequest(response):
"""Get the list of Part10 features supported by the reader.
@param response: result of L{CM_IOCTL_GET_FEATURE_REQUEST} command
@rtype: list
@return: a list of list C{[[tag1, value1], [tag2, value2]]}
"""
features = []
while len(response) > 0:
tag = response[0]
control = (
((((response[2] << 8) + response[3]) << 8) + response[4]) << 8
) + response[5]
try:
features.append([Features[tag], control])
except KeyError:
pass
del response[:6]
return features
def getFeatureRequest(cardConnection):
"""Get the list of Part10 features supported by the reader.
@param cardConnection: L{CardConnection} object
@rtype: list
@return: a list of list C{[[tag1, value1], [tag2, value2]]}
"""
response = cardConnection.control(CM_IOCTL_GET_FEATURE_REQUEST, [])
return parseFeatureRequest(response)
def hasFeature(featureList, feature):
"""return the controlCode for a feature or None
@param feature: feature to look for
@param featureList: feature list as returned by L{getFeatureRequest()}
@return: feature value or None
"""
for f in featureList:
if feature in (f[0], Features[f[0]]):
return f[1]
return None
def getPinProperties(cardConnection, featureList=None, controlCode=None):
"""return the C{PIN_PROPERTIES} structure
@param cardConnection: L{CardConnection} object
@param featureList: feature list as returned by L{getFeatureRequest()}
@param controlCode: control code for L{FEATURE_IFD_PIN_PROPERTIES}
@rtype: dict
@return: a dict"""
if controlCode is None:
if featureList is None:
featureList = getFeatureRequest(cardConnection)
controlCode = hasFeature(featureList, FEATURE_IFD_PIN_PROPERTIES)
if controlCode is None:
return {"raw": []}
response = cardConnection.control(controlCode, [])
d = {
"raw": response,
"LcdLayoutX": response[0],
"LcdLayoutY": response[1],
"EntryValidationCondition": response[2],
"TimeOut2": response[3],
}
return d
def getTlvProperties(cardConnection, featureList=None, controlCode=None):
"""return the C{GET_TLV_PROPERTIES} structure
@param cardConnection: L{CardConnection} object
@param featureList: feature list as returned by L{getFeatureRequest()}
@param controlCode: control code for L{FEATURE_GET_TLV_PROPERTIES}
@rtype: dict
@return: a dict"""
if controlCode is None:
if featureList is None:
featureList = getFeatureRequest(cardConnection)
controlCode = hasFeature(featureList, FEATURE_GET_TLV_PROPERTIES)
if controlCode is None:
return {"raw": []}
response = cardConnection.control(controlCode, [])
return parseTlvProperties(response)
def parseTlvProperties(response):
"""return the GET_TLV_PROPERTIES structure
@param response: result of L{FEATURE_GET_TLV_PROPERTIES}
@rtype: dict
@return: a dict"""
d = {
"raw": response,
}
# create a new list to consume it
tmp = list(response)
while tmp:
tag = tmp[0]
length = tmp[1]
data = tmp[2 : 2 + length]
if PCSCv2_PART10_PROPERTY_sFirmwareID == tag:
# convert to a string
data = "".join([chr(c) for c in data])
# we now suppose the value is an integer
elif 1 == length:
# byte
data = data[0]
elif 2 == length:
# 16 bits value
data = data[1] * 256 + data[0]
elif 4 == length:
# 32 bits value
data = ((data[3] * 256 + data[2]) * 256 + data[1]) * 256 + data[0]
# store the value in the dictionary
try:
d[Properties[tag]] = data
except KeyError:
d["UNKNOWN"] = data
del tmp[0 : 2 + length]
return d
if __name__ == "__main__":
# Small sample illustrating the use of PCSCPart10.
from smartcard.pcsc.PCSCReader import PCSCReader
cc = PCSCReader.readers()[0].createConnection()
cc.connect(mode=SCARD_SHARE_DIRECT)
# print(cc.control(CM_IOCTL_GET_FEATURE_REQUEST))
_features = getFeatureRequest(cc)
print(_features)
print(hasFeature(_features, FEATURE_VERIFY_PIN_START))
print(hasFeature(_features, FEATURE_VERIFY_PIN_DIRECT))
properties = getPinProperties(cc)
print("\nPinProperties:")
for k, v in list(properties.items()):
print(f" {k}: {v}")
print("\nTlvProperties:")
properties = getTlvProperties(cc)
for k, v in list(properties.items()):
print(f" {k}: {v}")