added serial number to cryptoflex. opensc can read it.
git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@14 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
@@ -219,7 +219,6 @@ def make_property(prop, doc): # {{{
|
|||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class File(object): # {{{
|
class File(object): # {{{
|
||||||
"""Template class for a smartcard file."""
|
"""Template class for a smartcard file."""
|
||||||
bertlv_data = make_property("bertlv_data", "list of (tag, length, value)-tuples of BER-TLV coded data objects (encrypted)")
|
bertlv_data = make_property("bertlv_data", "list of (tag, length, value)-tuples of BER-TLV coded data objects (encrypted)")
|
||||||
@@ -398,16 +397,13 @@ class DF(File): # {{{
|
|||||||
data = make_property("data", "unknown")
|
data = make_property("data", "unknown")
|
||||||
content = make_property("content", "list of files of the DF")
|
content = make_property("content", "list of files of the DF")
|
||||||
dfname = make_property("dfname", "string with up to 16 bytes. DF name, which can also be used as application identifier.")
|
dfname = make_property("dfname", "string with up to 16 bytes. DF name, which can also be used as application identifier.")
|
||||||
def __init__(self, parent, fid, filedescriptor=FDB["NOTSHAREABLEFILE"],
|
def __init__(self, parent, fid, filedescriptor=FDB["NOTSHAREABLEFILE"]|FDB["DF"],
|
||||||
lifecycle=LCB["ACTIVATED"],
|
lifecycle=LCB["ACTIVATED"],
|
||||||
simpletlv_data=None, bertlv_data=None, dfname=None, data=""):
|
simpletlv_data=None, bertlv_data=None, dfname=None, data=""):
|
||||||
"""
|
"""
|
||||||
The flag FDB["DF"] is automatically added to the file descriptor byte
|
|
||||||
filedescriptor.
|
|
||||||
|
|
||||||
See File for more.
|
See File for more.
|
||||||
"""
|
"""
|
||||||
File.__init__(self, parent, fid, filedescriptor|FDB["DF"], lifecycle,
|
File.__init__(self, parent, fid, filedescriptor, lifecycle,
|
||||||
simpletlv_data, bertlv_data)
|
simpletlv_data, bertlv_data)
|
||||||
if dfname:
|
if dfname:
|
||||||
if len(dfname)>16:
|
if len(dfname)>16:
|
||||||
@@ -501,16 +497,14 @@ class MF(DF): # {{{
|
|||||||
current = make_property("current", "the currently selected file")
|
current = make_property("current", "the currently selected file")
|
||||||
firstSFT = make_property("firstSFT", "string of length 1. The first software function table from the historical bytes.")
|
firstSFT = make_property("firstSFT", "string of length 1. The first software function table from the historical bytes.")
|
||||||
secondSFT = make_property("secondSFT", "string of length 1. The second software function table from the historical bytes.")
|
secondSFT = make_property("secondSFT", "string of length 1. The second software function table from the historical bytes.")
|
||||||
def __init__(self, filedescriptor=FDB["NOTSHAREABLEFILE"],
|
def __init__(self, filedescriptor=FDB["NOTSHAREABLEFILE"]|FDB["DF"],
|
||||||
lifecycle=LCB["ACTIVATED"],
|
lifecycle=LCB["ACTIVATED"],
|
||||||
simpletlv_data=None, bertlv_data=None, dfname=None):
|
simpletlv_data=None, bertlv_data=None, dfname=None):
|
||||||
"""The flag FDB["DF"] is automatically added to the file descriptor
|
"""The file identifier FID["MF"] is automatically added.
|
||||||
bytey filedescriptor. The file identifier FID["MF"] is automatically
|
|
||||||
added.
|
|
||||||
|
|
||||||
See DF for more.
|
See DF for more.
|
||||||
"""
|
"""
|
||||||
DF.__init__(self, None, FID["MF"], filedescriptor|FDB["DF"], lifecycle,
|
DF.__init__(self, None, FID["MF"], filedescriptor, lifecycle,
|
||||||
simpletlv_data, bertlv_data, dfname)
|
simpletlv_data, bertlv_data, dfname)
|
||||||
self.current = self
|
self.current = self
|
||||||
self.firstSFT = inttostring(MF.makeFirstSoftwareFunctionTable(), 1)
|
self.firstSFT = inttostring(MF.makeFirstSoftwareFunctionTable(), 1)
|
||||||
@@ -635,7 +629,7 @@ class MF(DF): # {{{
|
|||||||
|
|
||||||
return "".join(fdm)
|
return "".join(fdm)
|
||||||
|
|
||||||
def __selectFile(self, p1, p2, data):
|
def _selectFile(self, p1, p2, data):
|
||||||
"""
|
"""
|
||||||
Returns the file specified by 'p1' and 'data' from the select
|
Returns the file specified by 'p1' and 'data' from the select
|
||||||
file command APDU.
|
file command APDU.
|
||||||
@@ -698,7 +692,7 @@ class MF(DF): # {{{
|
|||||||
P2_FCP = 1<<2
|
P2_FCP = 1<<2
|
||||||
P2_FMD = 2<<2
|
P2_FMD = 2<<2
|
||||||
P2_NONE = 3<<2
|
P2_NONE = 3<<2
|
||||||
file = self.__selectFile(p1, p2, data)
|
file = self._selectFile(p1, p2, data)
|
||||||
|
|
||||||
if p2 == P2_NONE:
|
if p2 == P2_NONE:
|
||||||
data = ""
|
data = ""
|
||||||
@@ -1107,7 +1101,7 @@ class MF(DF): # {{{
|
|||||||
tlv_data = []
|
tlv_data = []
|
||||||
isSimpleTlv = True
|
isSimpleTlv = True
|
||||||
else:
|
else:
|
||||||
raise SwError(SW["ERR_INCORRECTP1P2"])
|
raise SwError(SW["ERR_NOTSUPPORTED"])
|
||||||
|
|
||||||
return file, isSimpleTlv, tlv_data
|
return file, isSimpleTlv, tlv_data
|
||||||
|
|
||||||
@@ -1295,7 +1289,7 @@ class MF(DF): # {{{
|
|||||||
integers and 'data' as binary string. Returns the status bytes as two
|
integers and 'data' as binary string. Returns the status bytes as two
|
||||||
byte long integer and the response data as binary string.
|
byte long integer and the response data as binary string.
|
||||||
"""
|
"""
|
||||||
file = self.__selectFile(p1, p2, data)
|
file = self._selectFile(p1, p2, data)
|
||||||
file.parent.content.remove(file)
|
file.parent.content.remove(file)
|
||||||
# FIXME: free memory of file and remove its content from the security device
|
# FIXME: free memory of file and remove its content from the security device
|
||||||
|
|
||||||
@@ -1334,18 +1328,15 @@ class EF(File): # {{{
|
|||||||
class TransparentStructureEF(EF): # {{{
|
class TransparentStructureEF(EF): # {{{
|
||||||
"""Class for an elementary file with transparent structure."""
|
"""Class for an elementary file with transparent structure."""
|
||||||
data = make_property("data", "string (encrypted). The file's data.")
|
data = make_property("data", "string (encrypted). The file's data.")
|
||||||
def __init__(self, parent, fid, filedescriptor,
|
def __init__(self, parent, fid, filedescriptor=FDB["EFSTRUCTURE_TRANSPARENT"],
|
||||||
lifecycle=LCB["ACTIVATED"],
|
lifecycle=LCB["ACTIVATED"],
|
||||||
simpletlv_data=None, bertlv_data=None,
|
simpletlv_data=None, bertlv_data=None,
|
||||||
datacoding=DCB["ONETIMEWRITE"], shortfid=0, data=""):
|
datacoding=DCB["ONETIMEWRITE"], shortfid=0, data=""):
|
||||||
"""
|
"""
|
||||||
The flag FDB["EFSTRUCTURE_TRANSPARENT"] is automatically added to
|
|
||||||
'filedescriptor'.
|
|
||||||
|
|
||||||
See EF for more.
|
See EF for more.
|
||||||
"""
|
"""
|
||||||
EF.__init__(self, parent, fid,
|
EF.__init__(self, parent, fid,
|
||||||
filedescriptor|FDB["EFSTRUCTURE_TRANSPARENT"], lifecycle,
|
filedescriptor, lifecycle,
|
||||||
simpletlv_data, bertlv_data,
|
simpletlv_data, bertlv_data,
|
||||||
datacoding, shortfid)
|
datacoding, shortfid)
|
||||||
self.setdec('data', data)
|
self.setdec('data', data)
|
||||||
@@ -1701,4 +1692,68 @@ class CryptoflexMF(MF): # {{{
|
|||||||
|
|
||||||
datalist = [data]
|
datalist = [data]
|
||||||
return ef, offsets, datalist
|
return ef, offsets, datalist
|
||||||
|
|
||||||
|
def selectFile(self, p1, p2, data):
|
||||||
|
"""
|
||||||
|
Function for instruction 0xa4. Takes the parameter bytes 'p1', 'p2' as
|
||||||
|
integers and 'data' as binary string. Returns the status bytes as two
|
||||||
|
byte long integer and the response data as binary string.
|
||||||
|
"""
|
||||||
|
P2_FCI = 0
|
||||||
|
P2_FCP = 1<<2
|
||||||
|
P2_FMD = 2<<2
|
||||||
|
P2_NONE = 3<<2
|
||||||
|
file = self._selectFile(p1, p2, data)
|
||||||
|
|
||||||
|
if isinstance(file, EF):
|
||||||
|
size = inttostring(min(0xffff, len(file.getenc('data'))), 2) # File size (body only)
|
||||||
|
extra = chr(0) # RFU
|
||||||
|
if isinstance(file, RecordStructureEF) and file.hasFixedRecordSize() and not file.isCyclic():
|
||||||
|
extra += chr(0) + chr(min(file.records, 0xff)) # Length of records
|
||||||
|
elif isinstance(file, DF):
|
||||||
|
size = inttostring(0xffff, 2) # Number of unused EEPROM bytes available in the DF
|
||||||
|
efcount = 0
|
||||||
|
dfcount = 0
|
||||||
|
chv1 = None
|
||||||
|
chv2 = None
|
||||||
|
chv1lifecycle = 0
|
||||||
|
chv2lifecycle = 0
|
||||||
|
for f in self.content:
|
||||||
|
if f.fid == 0x0000:
|
||||||
|
chv1 = f
|
||||||
|
chv1lifecycle = f.lifecycle & 1
|
||||||
|
if f.fid == 0x0100:
|
||||||
|
chv2 = f
|
||||||
|
chv2lifecycle = f.lifecycle & 1
|
||||||
|
if isinstance(f, EF):
|
||||||
|
efcount += 1
|
||||||
|
if isinstance(f, DF):
|
||||||
|
dfcount += 1
|
||||||
|
if chv1:
|
||||||
|
extra = chr(1) # TODO LSB correct?
|
||||||
|
else:
|
||||||
|
extra = chr(0) # TODO LSB correct?
|
||||||
|
extra += chr(efcount)
|
||||||
|
extra += chr(dfcount)
|
||||||
|
extra += chr(0) # TODO Number of PINs and unblock CHV PINs
|
||||||
|
extra += chr(0) # RFU
|
||||||
|
if chv1:
|
||||||
|
extra += chr(0) # TODO Number of remaining CHV1 attempts
|
||||||
|
extra += chr(0) # TODO Number of remaining unblock CHV1 attempts
|
||||||
|
if chv2:
|
||||||
|
extra += chr(0) # TODO CHV2 key status
|
||||||
|
extra += chr(0) # TODO CHV2 unblocking key status
|
||||||
|
|
||||||
|
data = inttostring(0, 2) # RFU
|
||||||
|
data += size
|
||||||
|
data += inttostring(file.fid, 2)
|
||||||
|
data += inttostring(file.filedescriptor) # File type
|
||||||
|
data += inttostring(0, 4) # ACs TODO
|
||||||
|
data += chr(file.lifecycle & 1) # File status
|
||||||
|
data += chr(len(extra))
|
||||||
|
data += extra
|
||||||
|
|
||||||
|
self.current = file
|
||||||
|
|
||||||
|
return SW["NORMAL"], data
|
||||||
# }}}
|
# }}}
|
||||||
|
|||||||
@@ -418,17 +418,12 @@ class CryptoflexOS(SmartcardOS): # {{{
|
|||||||
def __init__(self, filename, mf=None, ins2handler=None, maxle=MAX_SHORT_LE):
|
def __init__(self, filename, mf=None, ins2handler=None, maxle=MAX_SHORT_LE):
|
||||||
if filename == None and mf == None:
|
if filename == None and mf == None:
|
||||||
mf = CryptoflexMF()
|
mf = CryptoflexMF()
|
||||||
|
mf.append(TransparentStructureEF(parent=mf, fid=0x0002, filedescriptor=0x01,
|
||||||
|
data="\x00\x00\x00\x01\x00\x01\x00\x00"))#EF.ICCSN
|
||||||
#TODO: Load objects from disk
|
#TODO: Load objects from disk
|
||||||
self.firstrun = True
|
|
||||||
SmartcardOS.__init__(self, None,mf=mf, ins2handler=ins2handler, maxle=maxle,
|
SmartcardOS.__init__(self, None,mf=mf, ins2handler=ins2handler, maxle=maxle,
|
||||||
sam=CryptoflexSAM("testconfig.sam","DUMMYKEYDUMMYKEY"))
|
sam=CryptoflexSAM("testconfig.sam","DUMMYKEYDUMMYKEY"))
|
||||||
card_capabilities = self.mf.firstSFT + self.mf.secondSFT + SmartcardOS.makeThirdSoftwareFunctionTable()
|
self.atr = '\x3B\xE2\x00\x00\x40\x20\x49\x06'
|
||||||
SmartcardOS.atr = SmartcardOS.makeATR(T=0, directConvention = True, TA1=0x13,
|
|
||||||
histChars = chr(0x80) + chr(0x70 + len(card_capabilities)) +
|
|
||||||
card_capabilities)
|
|
||||||
|
|
||||||
def powerUp(self):
|
|
||||||
self.firstrun = True
|
|
||||||
|
|
||||||
def execute(self, msg):
|
def execute(self, msg):
|
||||||
def notImplemented(*argz, **args):
|
def notImplemented(*argz, **args):
|
||||||
@@ -452,20 +447,15 @@ class CryptoflexOS(SmartcardOS): # {{{
|
|||||||
# cryptoflex does not inpterpret le==0 as maxle
|
# cryptoflex does not inpterpret le==0 as maxle
|
||||||
self.lastCommandSW = sw
|
self.lastCommandSW = sw
|
||||||
self.lastCommandOffcut = data
|
self.lastCommandOffcut = data
|
||||||
return inttostring(SW["ERR_WRONGLENGTH"]|min(0xff,len(data)))
|
r = R_APDU(inttostring(SW["ERR_WRONGLENGTH"] + min(0xff,len(data)))).render()
|
||||||
else:
|
else:
|
||||||
r = SmartcardOS.formatResult(self, le, data, sw, False)
|
if ins == 0xa4 and len(data):
|
||||||
|
# get response should be followed by select file
|
||||||
if self.firstrun:
|
self.lastCommandSW = sw
|
||||||
# FIXME: other than Cryptoflex Access TM Software Development Kit
|
self.lastCommandOffcut = data
|
||||||
# Release 3C, smartcard_login-0.1.1 requires:
|
r = R_APDU(inttostring(SW["NORMAL_REST"] + min(0xff, len(data)))).render()
|
||||||
self.firstrun = False
|
else:
|
||||||
if ord(r[0]) == SW["NORMAL_REST"]>>8:
|
r = SmartcardOS.formatResult(self, le, data, sw, False)
|
||||||
r = inttostring(SW["NORMAL"])
|
|
||||||
|
|
||||||
# be fully successfull if at least one databyte has been returned
|
|
||||||
if len(r) > 2 and r[-2] == chr(SW["NORMAL_REST"]>>8):
|
|
||||||
return r[:-2] + inttostring(SW["NORMAL"])
|
|
||||||
|
|
||||||
return r
|
return r
|
||||||
# }}}
|
# }}}
|
||||||
|
|||||||
Reference in New Issue
Block a user