- Object orientated refactoring of CardGenerator

- PassportOS class in VirtualSmartcard.py is no longer needed, because all the functionallity is now in CardGenerator
- Removed hard coded image
- Added version number and type to file format


git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@38 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
oepen
2010-02-01 16:40:27 +00:00
parent 638e5301d0
commit 5e9a299eaa
3 changed files with 172 additions and 178 deletions

View File

@@ -17,11 +17,11 @@
# virtualsmartcard. If not, see <http://www.gnu.org/licenses/>. # virtualsmartcard. If not, see <http://www.gnu.org/licenses/>.
# #
import sys, getpass, anydbm import sys, getpass, anydbm, readline, os, dircache
from pickle import loads, dumps from pickle import loads, dumps
from TLVutils import pack from TLVutils import pack
from utils import inttostring from utils import inttostring
from SmartcardFilesystem import MF, TransparentStructureEF from SmartcardFilesystem import *
# pgp directory # pgp directory
#self.mf.append(DF(parent=self.mf, #self.mf.append(DF(parent=self.mf,
@@ -34,133 +34,164 @@ from SmartcardFilesystem import MF, TransparentStructureEF
#self.mf.append(DF(parent=self.mf, #self.mf.append(DF(parent=self.mf,
#fid=3, dfname='\xa0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00')) #fid=3, dfname='\xa0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00'))
def generate_iso_card(): class CardGenerator(object):
from SmartcardSAM import SAM
print "Using default SAM. Insecure!!!" def __init__(self, type='iso7816', sam=None, mf=None):
sam = SAM("1234", "1234567890") #FIXME: Use user provided data types = ['iso7816', 'ePass', 'cryptoflex']
if not type in types:
raise ValueError, "Unsupported type " % type
mf = MF(filedescriptor=FDB["DF"], lifecycle=LCB["ACTIVATED"], dfname=None) self.type = type
self.SAM.set_MF(self.mf) self.mf = None
self.sam = None
return mf, sam def __generate_iso_card(self):
from SmartcardSAM import SAM
def generate_ePass(): print "Using default SAM. Insecure!!!"
from PIL import Image self.sam = SAM("1234", "1234567890") #FIXME: Use user provided data
from SmartcardFilesystem import DF
from SmartcardSAM import PassportSAM
MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<" self.mf = MF(filedescriptor=FDB["DF"], lifecycle=LCB["ACTIVATED"], dfname=None)
MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14" self.sam.set_MF(self.mf)
MRZ = MRZ1 + MRZ2
picturepath = "jp2.jpg" def __generate_ePass(self):
try: from PIL import Image
im = Image.open(picturepath) from SmartcardSAM import PassportSAM
pic_width, pic_height = im.size
fd = open(picturepath,"rb")
picture = fd.read()
fd.close()
except IOError:
print "Could not find picture %s" % picturepath
pic_width = 0
pic_height = 0
picture = None
mf = MF() MRZ = raw_input("Please enter the MRZ as one string: ") #TODO: Sanity checks
#We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01 readline.set_completer_delims("")
mf.append(DF(parent=mf, fid=4, dfname='\xa0\x00\x00\x02G\x10\x01', bertlv_data=[])) readline.parse_and_bind("tab: complete")
df = mf.currentDF()
mf.append(TransparentStructureEF(parent=df, fid=0x011E, filedescriptor=0, data=""))#EF.COM
mf.append(TransparentStructureEF(parent=df, fid=0x0101, filedescriptor=0, data=""))#EF.DG1
mf.append(TransparentStructureEF(parent=df, fid=0x0102, filedescriptor=0, data=""))#EF.DG2
mf.append(TransparentStructureEF(parent=df, fid=0x010D, filedescriptor=0, data=""))#EF.SOD
#EF.COM
COM = pack([(0x5F01,4,"0107"),(0x5F36,6,"040000"),(0x5C,2,"6175")])
COM = pack(((0x60,len(COM),COM),))
fid = df.select("fid",0x011E)
fid.writebinary([0],[COM])
#EF.DG1
DG1 = pack([(0x5F1F,len(MRZ),MRZ)])
DG1 = pack([(0x61,len(DG1),DG1)])
fid = df.select("fid",0x0101)
fid.writebinary([0],[DG1])
#EF.DG2
if picture != None:
IIB = "\x00\x01" + inttostring(pic_width,2) + inttostring(pic_height,2) + 6 * "\x00"
length = 32 + len(picture) #32 is the length of IIB + FIB
FIB = inttostring(length,4) + 16 * "\x00"
FRH = "FAC" + "\x00" + "010" + "\x00" + inttostring(14+length,4) + inttostring(1,2)
picture = FRH + FIB + IIB + picture
DG2 = pack([(0xA1,8,"\x87\x02\x01\x01\x88\x02\x05\x01"),(0x5F2E,len(picture),picture)])
DG2 = pack([(0x02,1,"\x01"),(0x7F60,len(DG2),DG2)])
DG2 = pack([(0x7F61,len(DG2),DG2)])
fid = df.select("fid",0x0102)
fid.writebinary([0],[DG2])
sam = PassportSAM(mf) picturepath = raw_input("Please enter the path to an image: ")
return mf, sam picturepath = picturepath.rstrip() #FIXME
def generate_cryptoflex(): #MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<"
from SmartcardFilesystem import CryptoflexMF #MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14"
from SmartcardSAM import CryptoflexSAM #MRZ = MRZ1 + MRZ2
mf = CryptoflexMF() try:
mf.append(TransparentStructureEF(parent=mf, fid=0x0002, filedescriptor=0x01, im = Image.open(picturepath)
data="\x00\x00\x00\x01\x00\x01\x00\x00")) #EF.ICCSN pic_width, pic_height = im.size
sam = CryptoflexSAM(mf) fd = open(picturepath,"rb")
picture = fd.read()
fd.close()
except IOError:
print "Failed to open file: " + picturepath
pic_width = 0
pic_height = 0
picture = None
return mf, sam mf = MF()
def loadCard(filename, password=None): #We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01
from CryptoUtils import read_protected_string mf.append(DF(parent=mf, fid=4, dfname='\xa0\x00\x00\x02G\x10\x01', bertlv_data=[]))
df = mf.currentDF()
mf.append(TransparentStructureEF(parent=df, fid=0x011E, filedescriptor=0, data=""))#EF.COM
mf.append(TransparentStructureEF(parent=df, fid=0x0101, filedescriptor=0, data=""))#EF.DG1
mf.append(TransparentStructureEF(parent=df, fid=0x0102, filedescriptor=0, data=""))#EF.DG2
mf.append(TransparentStructureEF(parent=df, fid=0x010D, filedescriptor=0, data=""))#EF.SOD
#EF.COM
COM = pack([(0x5F01,4,"0107"),(0x5F36,6,"040000"),(0x5C,2,"6175")])
COM = pack(((0x60,len(COM),COM),))
fid = df.select("fid",0x011E)
fid.writebinary([0],[COM])
#EF.DG1
DG1 = pack([(0x5F1F,len(MRZ),MRZ)])
DG1 = pack([(0x61,len(DG1),DG1)])
fid = df.select("fid",0x0101)
fid.writebinary([0],[DG1])
#EF.DG2
if picture != None:
IIB = "\x00\x01" + inttostring(pic_width,2) + inttostring(pic_height,2) + 6 * "\x00"
length = 32 + len(picture) #32 is the length of IIB + FIB
FIB = inttostring(length,4) + 16 * "\x00"
FRH = "FAC" + "\x00" + "010" + "\x00" + inttostring(14+length,4) + inttostring(1,2)
picture = FRH + FIB + IIB + picture
DG2 = pack([(0xA1,8,"\x87\x02\x01\x01\x88\x02\x05\x01"),(0x5F2E,len(picture),picture)])
DG2 = pack([(0x02,1,"\x01"),(0x7F60,len(DG2),DG2)])
DG2 = pack([(0x7F61,len(DG2),DG2)])
fid = df.select("fid",0x0102)
fid.writebinary([0],[DG2])
try: self.mf = mf
db = anydbm.open(filename, 'r') self.sam = PassportSAM(self.mf)
except anydbm.error:
print "Failed to open " + filename
if password is None: def __generate_cryptoflex(self):
password = getpass.getpass("Please enter your password.") from SmartcardSAM import CryptoflexSAM
serializedMF = read_protected_string(db["mf"], password) self.mf = CryptoflexMF()
serializedSAM = read_protected_string(db["sam"], password) self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x0002, filedescriptor=0x01,
SAM = loads(serializedSAM) data="\x00\x00\x00\x01\x00\x01\x00\x00")) #EF.ICCSN
MF = loads(serializedMF) self.sam = CryptoflexSAM(self.mf)
#self.type = db["type"]
return SAM, MF def generateCard(self):
if self.type == 'iso7816':
def saveCard(mf, sam, filename, password=None): self.__generate_iso_card()
from CryptoUtils import protect_string elif self.type == 'ePass':
self.__generate_ePass()
if filename != None: elif self.type == 'cryptoflex':
print "Saving smartcard configuration to %s" % filename self.__generate_cryptoflex()
else: #TODO: Ask user for filename
pass
if password is None:
passwd1 = getpass.getpass("Please enter a password.")
passwd2 = getpass.getpass("Please retype your password.")
if (passwd1 != passwd2):
raise ValueError, "Passwords did not match. Will now exit"
else: else:
password = passwd1 raise ValueError, "Unsupported card type " % self.type
mf_string = dumps(mf) def getCard(self):
sam_string = dumps(sam) if self.sam is None or self.mf is None:
protectedMF = protect_string(mf_string, password) self.generateCard()
protectedSAM = protect_string(sam_string, password) return self.mf, self.sam
try: def setCard(self, mf=None, sam=None):
db = anydbm.open(filename, 'c') if mf != None:
db["mf"] = protectedMF self.mf = mf
db["sam"] = protectedSAM if sam != None:
#db["type"] = self.type self.sam = sam
db.close()
except anydbm.error:
print "Failed to write data to disk" def loadCard(self, filename, password=None):
from CryptoUtils import read_protected_string
try:
db = anydbm.open(filename, 'r')
except anydbm.error:
print "Failed to open " + filename
if password is None:
password = getpass.getpass("Please enter your password.")
serializedMF = read_protected_string(db["mf"], password)
serializedSAM = read_protected_string(db["sam"], password)
self.sam = loads(serializedSAM)
self.mf = loads(serializedMF)
self.type = db["type"]
def saveCard(self, filename, password=None):
from CryptoUtils import protect_string
if password is None:
passwd1 = getpass.getpass("Please enter a password.")
passwd2 = getpass.getpass("Please retype your password.")
if (passwd1 != passwd2):
raise ValueError, "Passwords did not match. Will now exit"
else:
password = passwd1
if self.mf == None or self.sam == None: #TODO: Sanity checks
raise ValueError, "Card Generator was not set up properly (missing mf or sam)"
mf_string = dumps(self.mf)
sam_string = dumps(self.sam)
protectedMF = protect_string(mf_string, password)
protectedSAM = protect_string(sam_string, password)
try:
db = anydbm.open(filename, 'c')
db["mf"] = protectedMF
db["sam"] = protectedSAM
db["type"] = self.type
db["version"] = "0.1"
db.close()
except anydbm.error:
print "Failed to write data to disk"
if __name__ == "__main__": if __name__ == "__main__":
from optparse import OptionParser from optparse import OptionParser
@@ -178,11 +209,7 @@ if __name__ == "__main__":
print "You have to provide a filename using the -f option" print "You have to provide a filename using the -f option"
sys.exit() sys.exit()
if options.type == 'iso7816': generator = CardGenerator(options.type)
mf, sam = generate_iso_card() generator.generateCard()
elif options.type == 'ePass': generator.saveCard(options.filename)
mf, sam = generate_ePass()
elif options.type == 'cryptoflex':
mf, sam = generate_cryptoflex()
saveCard(mf, sam, options.filename)

View File

@@ -21,21 +21,21 @@ from TLVutils import *
from SWutils import SwError, SW from SWutils import SwError, SW
from SmartcardFilesystem import prettyprint_anything, MF, DF, CryptoflexMF, TransparentStructureEF from SmartcardFilesystem import prettyprint_anything, MF, DF, CryptoflexMF, TransparentStructureEF
from utils import C_APDU, R_APDU, hexdump, inttostring from utils import C_APDU, R_APDU, hexdump, inttostring
from SmartcardSAM import CardContainer, SAM, PassportSAM, CryptoflexSAM from SmartcardSAM import SAM, PassportSAM, CryptoflexSAM
import CardGenerator
from pickle import dumps, loads from pickle import dumps, loads
import socket, struct, sys, signal, atexit, traceback import socket, struct, sys, signal, atexit, traceback
import struct import struct, getpass, anydbm
import getpass
import shelve, anydbm
class SmartcardOS(object): # {{{ class SmartcardOS(object): # {{{
def __init__(self, mf=None, sam=None, ins2handler=None, maxle=MAX_SHORT_LE): def __init__(self, mf, sam, ins2handler=None, maxle=MAX_SHORT_LE):
from CardGenerator import generate_iso_card
self.mf = mf self.mf = mf
self.SAM = sam self.SAM = sam
if self.mf == None and self.SAM == None: #if self.mf == None and self.SAM == None:
self.mf, self.SAM = generate_iso_card() # self.mf, self.SAM = generate_iso_card()
if not ins2handler: if not ins2handler:
self.ins2handler = { self.ins2handler = {
@@ -295,39 +295,8 @@ class SmartcardOS(object): # {{{
return answer return answer
# }}} # }}}
class PassportOS(SmartcardOS):
"""
The PassportOS emulates a Passport Application according to ICAO MRTD standard.
It generates a data structure ...
It also integrates a SAM derived from the standard SmartcardSAM, providing the
Basic Access Control (BAC) mechanisms.
"""
def __init__(self, mf=None, sam=None, ins2handler=None, maxle=MAX_SHORT_LE):
from CardGenerator import generate_ePass
if mf == None and sam == None:
mf, sam = generate_ePass()
else: #TODO: Sanity check if mf or sam are provided
if mf == None:
mf, tmp = generate_ePass()
if sam == None:
sam = PassportSAM(mf)
SmartcardOS.__init__(self, mf=mf, sam=sam, ins2handler=ins2handler, maxle=maxle)
class CryptoflexOS(SmartcardOS): # {{{ class CryptoflexOS(SmartcardOS): # {{{
def __init__(self, mf=None, sam=None, ins2handler=None, maxle=MAX_SHORT_LE): def __init__(self, mf, sam, ins2handler=None, maxle=MAX_SHORT_LE):
from GenerateCard import generate_cryptoflex
if mf == None and sam == None:
mf, sam = generate_cryptoflex()
else:
if mf == None:
mf, tmp = generate_cryptoflex()
del tmp
if sam == None:
sam = CryptoflexSAM(mf)
SmartcardOS.__init__(self, mf, sam, ins2handler, maxle) SmartcardOS.__init__(self, mf, sam, ins2handler, maxle)
self.atr = '\x3B\xE2\x00\x00\x40\x20\x49\x06' self.atr = '\x3B\xE2\x00\x00\x40\x20\x49\x06'
@@ -387,11 +356,9 @@ class VirtualICC(object): # {{{
def __init__(self, filename, type, lenlen=3, host="localhost", port=35963): def __init__(self, filename, type, lenlen=3, host="localhost", port=35963):
from os.path import exists from os.path import exists
from CardGenerator import loadCard
self.filename = None self.filename = None
SAM = None self.cardGenerator = CardGenerator.CardGenerator(type)
MF = None
#If a filename is specified, try to load the card from disk #If a filename is specified, try to load the card from disk
if filename == None: if filename == None:
@@ -399,16 +366,15 @@ class VirtualICC(object): # {{{
else: else:
self.filename = filename self.filename = filename
if exists(filename): if exists(filename):
print "Found existing card " + filename + ". Will try to open it" self.cardGenerator.loadCard(self.filename)
SAM, MF = loadCard(filename)
else: else:
print "No file " + filename + " found. Will create new file at termination of program." print "No file " + self.filename + " found. Will create new file at termination of program."
MF, SAM = self.cardGenerator.getCard()
#Generate an OS object of the correct type #Generate an OS object of the correct type
if type == "iso7816": if type == "iso7816" or type == "ePass":
self.os = SmartcardOS(MF, SAM) self.os = SmartcardOS(MF, SAM)
elif type == "ePass":
self.os = PassportOS(MF, SAM)
elif type == "cryptoflex": elif type == "cryptoflex":
self.os = CryptoflexOS(MF, SAM) self.os = CryptoflexOS(MF, SAM)
else: else:
@@ -431,9 +397,10 @@ class VirtualICC(object): # {{{
#atexit.register(saveCard) #atexit.register(saveCard)
def signalHandler(self, signal=None, frame=None): def signalHandler(self, signal=None, frame=None):
from CardGenerator import saveCard
self.sock.close() self.sock.close()
saveCard(self.os.mf, self.os.SAM, self.filename) if self.filename != None:
self.cardGenerator.setCard(self.os.mf, self.os.SAM)
self.cardGenerator.saveCard(self.filename)
sys.exit() sys.exit()
@staticmethod @staticmethod

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB