- 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!!!"
sam = SAM("1234", "1234567890") #FIXME: Use user provided data
mf = MF(filedescriptor=FDB["DF"], lifecycle=LCB["ACTIVATED"], dfname=None) def __init__(self, type='iso7816', sam=None, mf=None):
self.SAM.set_MF(self.mf) types = ['iso7816', 'ePass', 'cryptoflex']
if not type in types:
return mf, sam raise ValueError, "Unsupported type " % type
def generate_ePass():
from PIL import Image
from SmartcardFilesystem import DF
from SmartcardSAM import PassportSAM
MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<" self.type = type
MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14" self.mf = None
MRZ = MRZ1 + MRZ2 self.sam = None
picturepath = "jp2.jpg" def __generate_iso_card(self):
try: from SmartcardSAM import SAM
im = Image.open(picturepath)
pic_width, pic_height = im.size print "Using default SAM. Insecure!!!"
fd = open(picturepath,"rb") self.sam = SAM("1234", "1234567890") #FIXME: Use user provided data
picture = fd.read()
fd.close()
except IOError:
print "Could not find picture %s" % picturepath
pic_width = 0
pic_height = 0
picture = None
mf = MF()
#We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01 self.mf = MF(filedescriptor=FDB["DF"], lifecycle=LCB["ACTIVATED"], dfname=None)
mf.append(DF(parent=mf, fid=4, dfname='\xa0\x00\x00\x02G\x10\x01', bertlv_data=[])) self.sam.set_MF(self.mf)
df = mf.currentDF()
mf.append(TransparentStructureEF(parent=df, fid=0x011E, filedescriptor=0, data=""))#EF.COM def __generate_ePass(self):
mf.append(TransparentStructureEF(parent=df, fid=0x0101, filedescriptor=0, data=""))#EF.DG1 from PIL import Image
mf.append(TransparentStructureEF(parent=df, fid=0x0102, filedescriptor=0, data=""))#EF.DG2 from SmartcardSAM import PassportSAM
mf.append(TransparentStructureEF(parent=df, fid=0x010D, filedescriptor=0, data=""))#EF.SOD
#EF.COM MRZ = raw_input("Please enter the MRZ as one string: ") #TODO: Sanity checks
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)
return mf, sam
def generate_cryptoflex():
from SmartcardFilesystem import CryptoflexMF
from SmartcardSAM import CryptoflexSAM
mf = CryptoflexMF()
mf.append(TransparentStructureEF(parent=mf, fid=0x0002, filedescriptor=0x01,
data="\x00\x00\x00\x01\x00\x01\x00\x00")) #EF.ICCSN
sam = CryptoflexSAM(mf)
return mf, sam readline.set_completer_delims("")
readline.parse_and_bind("tab: complete")
def loadCard(filename, password=None):
from CryptoUtils import read_protected_string picturepath = raw_input("Please enter the path to an image: ")
picturepath = picturepath.rstrip() #FIXME
#MRZ1 = "P<UTOERIKSSON<<ANNA<MARIX<<<<<<<<<<<<<<<<<<<"
#MRZ2 = "L898902C<3UTO6908061F9406236ZE184226B<<<<<14"
#MRZ = MRZ1 + MRZ2
try: try:
db = anydbm.open(filename, 'r') im = Image.open(picturepath)
except anydbm.error: pic_width, pic_height = im.size
print "Failed to open " + filename 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
if password is None: mf = MF()
password = getpass.getpass("Please enter your password.")
#We need a MF with Application DF \xa0\x00\x00\x02G\x10\x01
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])
serializedMF = read_protected_string(db["mf"], password) self.mf = mf
serializedSAM = read_protected_string(db["sam"], password) self.sam = PassportSAM(self.mf)
SAM = loads(serializedSAM)
MF = loads(serializedMF)
#self.type = db["type"]
return SAM, MF def __generate_cryptoflex(self):
from SmartcardSAM import CryptoflexSAM
def saveCard(mf, sam, filename, password=None):
from CryptoUtils import protect_string self.mf = CryptoflexMF()
self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x0002, filedescriptor=0x01,
if filename != None: data="\x00\x00\x00\x01\x00\x01\x00\x00")) #EF.ICCSN
print "Saving smartcard configuration to %s" % filename self.sam = CryptoflexSAM(self.mf)
else: #TODO: Ask user for filename
pass def generateCard(self):
if self.type == 'iso7816':
if password is None: self.__generate_iso_card()
passwd1 = getpass.getpass("Please enter a password.") elif self.type == 'ePass':
passwd2 = getpass.getpass("Please retype your password.") self.__generate_ePass()
if (passwd1 != passwd2): elif self.type == 'cryptoflex':
raise ValueError, "Passwords did not match. Will now exit" self.__generate_cryptoflex()
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 = {
@@ -294,40 +294,9 @@ 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