Refactored the python files in the cards directory according to PEP8

This commit is contained in:
Dominik
2016-03-19 07:40:35 +01:00
parent 33dc00e175
commit de683869b4
5 changed files with 277 additions and 203 deletions

View File

@@ -32,16 +32,18 @@ class HandlerTestOS(SmartcardOS):
lastCommandOffcut = '' lastCommandOffcut = ''
def getATR(self): def getATR(self):
return '\x3B\xD6\x18\x00\x80\xB1\x80\x6D\x1F\x03\x80\x51\x00\x61\x10\x30\x9E' return '\x3B\xD6\x18\x00\x80\xB1\x80\x6D\x1F\x03\x80\x51\x00\x61' + \
'\x10\x30\x9E'
def __output_from_le(self, msg): def __output_from_le(self, msg):
le = (ord(msg[2])<<8)+ord(msg[3]) le = (ord(msg[2]) << 8) + ord(msg[3])
return ''.join([chr(num&0xff) for num in xrange(le)]) return ''.join([chr(num & 0xff) for num in xrange(le)])
def execute(self, msg): def execute(self, msg):
ok = '\x90\x00' ok = '\x90\x00'
error = '\x6d\x00' error = '\x6d\x00'
if msg == '\x00\xA4\x04\x00\x06\xA0\x00\x00\x00\x18\x50' or msg == '\x00\xA4\x04\x00\x06\xA0\x00\x00\x00\x18\xFF': if (msg == '\x00\xA4\x04\x00\x06\xA0\x00\x00\x00\x18\x50' or
msg == '\x00\xA4\x04\x00\x06\xA0\x00\x00\x00\x18\xFF'):
logging.info('Select applet') logging.info('Select applet')
return ok return ok
elif msg.startswith('\x80\x38\x00'): elif msg.startswith('\x80\x38\x00'):
@@ -65,7 +67,7 @@ class HandlerTestOS(SmartcardOS):
self.lastCommandOffcut = self.__output_from_le(msg) self.lastCommandOffcut = self.__output_from_le(msg)
if len(self.lastCommandOffcut) > 0xFF: if len(self.lastCommandOffcut) > 0xFF:
return '\x61\x00' return '\x61\x00'
return '' + chr(len(self.lastCommandOffcut)&0xFF) return '' + chr(len(self.lastCommandOffcut) & 0xFF)
elif len(msg) == 6+ord(msg[4]): elif len(msg) == 6+ord(msg[4]):
logging.info('Case 4, APDU') logging.info('Case 4, APDU')
return self.__output_from_le(msg) + ok return self.__output_from_le(msg) + ok

View File

@@ -17,8 +17,11 @@
# virtualsmartcard. If not, see <http://www.gnu.org/licenses/>. # virtualsmartcard. If not, see <http://www.gnu.org/licenses/>.
# #
import atexit
import logging
import smartcard
import sys
from virtualsmartcard.VirtualSmartcard import SmartcardOS from virtualsmartcard.VirtualSmartcard import SmartcardOS
import smartcard, logging, sys, atexit
class RelayOS(SmartcardOS): class RelayOS(SmartcardOS):
@@ -30,7 +33,8 @@ class RelayOS(SmartcardOS):
""" """
def __init__(self, readernum): def __init__(self, readernum):
""" """
Initialize the connection to the (physical) smart card via a given reader Initialize the connection to the (physical) smart card via a given
reader
""" """
# See which readers are available # See which readers are available

View File

@@ -27,7 +27,8 @@ from virtualsmartcard.SmartcardFilesystem import MF, TransparentStructureEF, \
RecordStructureEF, DF, EF RecordStructureEF, DF, EF
from virtualsmartcard.ConstantDefinitions import FDB, MAX_SHORT_LE from virtualsmartcard.ConstantDefinitions import FDB, MAX_SHORT_LE
import struct, logging import struct
import logging
class CryptoflexOS(Iso7816OS): class CryptoflexOS(Iso7816OS):
@@ -43,14 +44,17 @@ class CryptoflexOS(Iso7816OS):
c = C_APDU(msg) c = C_APDU(msg)
except ValueError as e: except ValueError as e:
logging.debug("Failed to parse APDU %s", msg) logging.debug("Failed to parse APDU %s", msg)
return self.formatResult(False, 0, 0, "", SW["ERR_INCORRECTPARAMETERS"]) return self.formatResult(False, 0, 0, "",
SW["ERR_INCORRECTPARAMETERS"])
try: try:
sw, result = self.ins2handler.get(c.ins, notImplemented)(c.p1, c.p2, c.data) sw, result = self.ins2handler.get(c.ins, notImplemented)(c.p1,
#print type(result) c.p2,
c.data)
# print type(result)
except SwError as e: except SwError as e:
logging.info(e.message) logging.info(e.message)
#traceback.print_exception(*sys.exc_info()) # traceback.print_exception(*sys.exc_info())
sw = e.sw sw = e.sw
result = "" result = ""
@@ -62,20 +66,22 @@ class CryptoflexOS(Iso7816OS):
# 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
r = R_APDU(inttostring(SW["ERR_WRONGLENGTH"] +\ r = R_APDU(inttostring(SW["ERR_WRONGLENGTH"] +
min(0xff, len(data)))).render() min(0xff, len(data)))).render()
else: else:
if ins == 0xa4 and len(data): if ins == 0xa4 and len(data):
# get response should be followed by select file # get response should be followed by select file
self.lastCommandSW = sw self.lastCommandSW = sw
self.lastCommandOffcut = data self.lastCommandOffcut = data
r = R_APDU(inttostring(SW["NORMAL_REST"] +\ r = R_APDU(inttostring(SW["NORMAL_REST"] +
min(0xff, len(data)))).render() min(0xff, len(data)))).render()
else: else:
r = Iso7816OS.formatResult(self, Iso7816OS.seekable(ins), le, data, sw, False) r = Iso7816OS.formatResult(self, Iso7816OS.seekable(ins), le,
data, sw, False)
return r return r
class CryptoflexSE(Security_Environment): class CryptoflexSE(Security_Environment):
def __init__(self, MF, SAM): def __init__(self, MF, SAM):
Security_Environment.__init__(self, MF, SAM) Security_Environment.__init__(self, MF, SAM)
@@ -95,11 +101,11 @@ class CryptoflexSE(Security_Environment):
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from Crypto.Util.randpool import RandomPool from Crypto.Util.randpool import RandomPool
keynumber = p1 #TODO: Check if key exists keynumber = p1 # TODO: Check if key exists
keylength_dict = {0x40: 256, 0x60: 512, 0x80: 1024} keylength_dict = {0x40: 256, 0x60: 512, 0x80: 1024}
if not keylength_dict.has_key(p2): if p2 not in keylength_dict:
raise SwError(SW["ERR_INCORRECTP1P2"]) raise SwError(SW["ERR_INCORRECTP1P2"])
else: else:
keylength = keylength_dict[p2] keylength = keylength_dict[p2]
@@ -110,31 +116,31 @@ class CryptoflexSE(Security_Environment):
e_in = struct.unpack("<i", data) e_in = struct.unpack("<i", data)
if e_in[0] != 65537: if e_in[0] != 65537:
logging.warning("Warning: Exponents different from 65537 are ignored!" +\ logging.warning("Warning: Exponents different from 65537 are " +
"The Exponent given is %i" % e_in[0]) "ignored! The Exponent given is %i" % e_in[0])
#Encode Public key # Encode Public key
n = PublicKey.__getstate__()['n'] n = PublicKey.__getstate__()['n']
n_str = inttostring(n) n_str = inttostring(n)
n_str = n_str[::-1] n_str = n_str[::-1]
e = PublicKey.__getstate__()['e'] e = PublicKey.__getstate__()['e']
e_str = inttostring(e, 4) e_str = inttostring(e, 4)
e_str = e_str[::-1] e_str = e_str[::-1]
pad = 187 * '\x30' #We don't have CRT components, so we need to pad pad = 187 * '\x30' # We don't have CRT components, so we need to pad
pk_n = TLVutils.bertlv_pack(((0x81, len(n_str), n_str), pk_n = TLVutils.bertlv_pack(((0x81, len(n_str), n_str),
(0x01, len(pad), pad), (0x01, len(pad), pad),
(0x82, len(e_str), e_str))) (0x82, len(e_str), e_str)))
#Private key # Private key
d = PublicKey.__getstate__()['d'] d = PublicKey.__getstate__()['d']
#Write result to FID 10 12 EF-PUB-KEY # Write result to FID 10 12 EF-PUB-KEY
df = self.mf.currentDF() df = self.mf.currentDF()
ef_pub_key = df.select("fid", 0x1012) ef_pub_key = df.select("fid", 0x1012)
ef_pub_key.writebinary([0], [pk_n]) ef_pub_key.writebinary([0], [pk_n])
data = ef_pub_key.getenc('data') data = ef_pub_key.getenc('data')
#Write private key to FID 00 12 EF-PRI-KEY (not necessary?) # Write private key to FID 00 12 EF-PRI-KEY (not necessary?)
#How to encode the private key? # How to encode the private key?
ef_priv_key = df.select("fid", 0x0012) ef_priv_key = df.select("fid", 0x0012)
ef_priv_key.writebinary([0], [inttostring(d)]) ef_priv_key.writebinary([0], [inttostring(d)])
data = ef_priv_key.getenc('data') data = ef_priv_key.getenc('data')
@@ -148,11 +154,11 @@ class CryptoflexSAM(SAM):
def generate_public_key_pair(self, p1, p2, data): def generate_public_key_pair(self, p1, p2, data):
asym_key = self.current_SE.generate_public_key_pair(p1, p2, data) asym_key = self.current_SE.generate_public_key_pair(p1, p2, data)
#TODO: Use SE instead (and remove SAM.set_asym_algorithm) # TODO: Use SE instead (and remove SAM.set_asym_algorithm)
self.set_asym_algorithm(asym_key, 0x07) self.set_asym_algorithm(asym_key, 0x07)
return SW["NORMAL"], "" return SW["NORMAL"], ""
def perform_security_operation(self, p1, p2, data): def pezorform_security_operation(self, p1, p2, data):
""" """
In the cryptoflex card, this is the verify key command. A key is send In the cryptoflex card, this is the verify key command. A key is send
to the card in plain text and compared to a key stored in the card. to the card in plain text and compared to a key stored in the card.
@@ -163,21 +169,22 @@ class CryptoflexSAM(SAM):
""" """
return SW["NORMAL"], "" return SW["NORMAL"], ""
#FIXME # FIXME
#key = self._get_referenced_key(p1,p2) # key = self._get_referenced_key(p1,p2)
#if key == data: # if key == data:
# return SW["NORMAL"], "" # return SW["NORMAL"], ""
#else: # else:
# return SW["WARN_NOINFO63"], "" # return SW["WARN_NOINFO63"], ""
def internal_authenticate(self, p1, p2, data): def internal_authenticate(self, p1, p2, data):
data = data[::-1] #Reverse Byte order data = data[::-1] # Reverse Byte order
sw, data = SAM.internal_authenticate(self, p1, p2, data) sw, data = SAM.internal_authenticate(self, p1, p2, data)
if data != "": if data != "":
data = data[::-1] data = data[::-1]
return sw, data return sw, data
class CryptoflexMF(MF): # {{{
class CryptoflexMF(MF): # {{{
@staticmethod @staticmethod
def create(p1, p2, data): def create(p1, p2, data):
@@ -195,15 +202,17 @@ class CryptoflexMF(MF): # {{{
args["filedescriptor"] = FDB["EFSTRUCTURE_TRANSPARENT"] args["filedescriptor"] = FDB["EFSTRUCTURE_TRANSPARENT"]
new_file = TransparentStructureEF(**args) new_file = TransparentStructureEF(**args)
elif data[6] == "\x02": elif data[6] == "\x02":
if len(data)>16: if len(data) > 16:
args["maxrecordsize"] = stringtoint(data[16]) args["maxrecordsize"] = stringtoint(data[16])
elif p2: elif p2:
# if given a number of records # if given a number of records
args["maxrecordsize"] = (stringtoint(data[2:4])/p2) args["maxrecordsize"] = (stringtoint(data[2:4]) / p2)
args["filedescriptor"] = FDB["EFSTRUCTURE_LINEAR_FIXED_NOFURTHERINFO"] args["filedescriptor"] = FDB["EFSTRUCTURE_LINEAR_FIXED_"
"NOFURTHERINFO"]
new_file = RecordStructureEF(**args) new_file = RecordStructureEF(**args)
elif data[6] == "\x03": elif data[6] == "\x03":
args["filedescriptor"] = FDB["EFSTRUCTURE_LINEAR_VARIABLE_NOFURTHERINFO"] args["filedescriptor"] = FDB["EFSTRUCTURE_LINEAR_VARIABLE_"
"NOFURTHERINFO"]
new_file = RecordStructureEF(**args) new_file = RecordStructureEF(**args)
elif data[6] == "\x04": elif data[6] == "\x04":
args["filedescriptor"] = FDB["EFSTRUCTURE_CYCLIC_NOFURTHERINFO"] args["filedescriptor"] = FDB["EFSTRUCTURE_CYCLIC_NOFURTHERINFO"]
@@ -216,7 +225,6 @@ class CryptoflexMF(MF): # {{{
logging.error("unknown type: 0x%x" % ord(data[6])) logging.error("unknown type: 0x%x" % ord(data[6]))
raise SwError(SW["ERR_INCORRECTPARAMETERS"]) raise SwError(SW["ERR_INCORRECTPARAMETERS"])
return [new_file] return [new_file]
def recordHandlingDecode(self, p1, p2): def recordHandlingDecode(self, p1, p2):
@@ -225,7 +233,6 @@ class CryptoflexMF(MF): # {{{
return MF.recordHandlingDecode(self, p1, p2) return MF.recordHandlingDecode(self, p1, p2)
def dataUnitsDecodePlain(self, p1, p2, data): def dataUnitsDecodePlain(self, p1, p2, data):
ef = self.currentEF() ef = self.currentEF()
# FIXME: Cyberflex Access TM Software Development Kit Release 3C # FIXME: Cyberflex Access TM Software Development Kit Release 3C
@@ -243,19 +250,23 @@ class CryptoflexMF(MF): # {{{
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.
""" """
P2_FCI = 0 P2_FCI = 0
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 isinstance(file, EF): if isinstance(file, EF):
size = inttostring(min(0xffff, len(file.getenc('data'))), 2) # File size (body only) # File size (body only)
extra = chr(0) # RFU size = inttostring(min(0xffff, len(file.getenc('data'))), 2)
if isinstance(file, RecordStructureEF) and file.hasFixedRecordSize() and not file.isCyclic(): extra = chr(0) # RFU
extra += chr(0) + chr(min(file.records, 0xff)) # Length of records if (isinstance(file, RecordStructureEF) and
file.hasFixedRecordSize() and not file.isCyclic()):
# Length of records
extra += chr(0) + chr(min(file.records, 0xff))
elif isinstance(file, DF): elif isinstance(file, DF):
size = inttostring(0xffff, 2) # Number of unused EEPROM bytes available in the DF # Number of unused EEPROM bytes available in the DF
size = inttostring(0xffff, 2)
efcount = 0 efcount = 0
dfcount = 0 dfcount = 0
chv1 = None chv1 = None
@@ -274,26 +285,26 @@ class CryptoflexMF(MF): # {{{
if isinstance(f, DF): if isinstance(f, DF):
dfcount += 1 dfcount += 1
if chv1: if chv1:
extra = chr(1) # TODO LSB correct? extra = chr(1) # TODO LSB correct?
else: else:
extra = chr(0) # TODO LSB correct? extra = chr(0) # TODO LSB correct?
extra += chr(efcount) extra += chr(efcount)
extra += chr(dfcount) extra += chr(dfcount)
extra += chr(0) # TODO Number of PINs and unblock CHV PINs extra += chr(0) # TODO Number of PINs and unblock CHV PINs
extra += chr(0) # RFU extra += chr(0) # RFU
if chv1: if chv1:
extra += chr(0) # TODO Number of remaining CHV1 attempts extra += chr(0) # TODO remaining CHV1 attempts
extra += chr(0) # TODO Number of remaining unblock CHV1 attempts extra += chr(0) # TODO remaining unblock CHV1 attempts
if chv2: if chv2:
extra += chr(0) # TODO CHV2 key status extra += chr(0) # TODO CHV2 key status
extra += chr(0) # TODO CHV2 unblocking key status extra += chr(0) # TODO CHV2 unblocking key status
data = inttostring(0, 2) # RFU data = inttostring(0, 2) # RFU
data += size data += size
data += inttostring(file.fid, 2) data += inttostring(file.fid, 2)
data += inttostring(file.filedescriptor) # File type data += inttostring(file.filedescriptor) # File type
data += inttostring(0, 4) # ACs TODO data += inttostring(0, 4) # ACs TODO
data += chr(file.lifecycle & 1) # File status data += chr(file.lifecycle & 1) # File status
data += chr(len(extra)) data += chr(len(extra))
data += extra data += extra

View File

@@ -22,9 +22,11 @@ import virtualsmartcard.CryptoUtils as vsCrypto
from virtualsmartcard.SWutils import SwError, SW from virtualsmartcard.SWutils import SwError, SW
from virtualsmartcard.utils import stringtoint from virtualsmartcard.utils import stringtoint
import hashlib, struct import hashlib
import struct
from os import urandom from os import urandom
class ePass_SE(Security_Environment): class ePass_SE(Security_Environment):
"""This class implements the Security Environment of the ICAO Passports. It """This class implements the Security Environment of the ICAO Passports. It
is required in order to use the send sequence counter for secure messaging. is required in order to use the send sequence counter for secure messaging.
@@ -46,10 +48,11 @@ class ePass_SE(Security_Environment):
self.ssc += 1 self.ssc += 1
checksum = vsCrypto.crypto_checksum(self.cct.algorithm, self.cct.key, checksum = vsCrypto.crypto_checksum(self.cct.algorithm, self.cct.key,
data, self.cct.iv, self.ssc) data, self.cct.iv, self.ssc)
return checksum return checksum
class PassportSAM(SAM): class PassportSAM(SAM):
""" """
SAM for ICAO ePassport. Implements Basic access control and key derivation SAM for ICAO ePassport. Implements Basic access control and key derivation
@@ -58,7 +61,7 @@ class PassportSAM(SAM):
def __init__(self, mf): def __init__(self, mf):
import virtualsmartcard.SmartcardFilesystem as vsFS import virtualsmartcard.SmartcardFilesystem as vsFS
SAM.__init__(self, None, None, mf, default_se = ePass_SE) SAM.__init__(self, None, None, mf, default_se=ePass_SE)
ef_dg1 = vsFS.walk(mf, "\x00\x04\x01\x01") ef_dg1 = vsFS.walk(mf, "\x00\x04\x01\x01")
dg1 = ef_dg1.readbinary(5) dg1 = ef_dg1.readbinary(5)
@@ -77,7 +80,7 @@ class PassportSAM(SAM):
""" """
MRZ_information = self.mrz2[0:10] + self.mrz2[13:20] + self.mrz2[21:28] MRZ_information = self.mrz2[0:10] + self.mrz2[13:20] + self.mrz2[21:28]
H = hashlib.sha1(MRZ_information).digest() #pylint: disable=E1101 H = hashlib.sha1(MRZ_information).digest() # pylint: disable=E1101
self.KSeed = H[:16] self.KSeed = H[:16]
self.KEnc = self.derive_key(self.KSeed, 1) self.KEnc = self.derive_key(self.KSeed, 1)
self.KMac = self.derive_key(self.KSeed, 2) self.KMac = self.derive_key(self.KSeed, 2)
@@ -91,7 +94,7 @@ class PassportSAM(SAM):
Returns: Ka + Kb Returns: Ka + Kb
Note: Does not adjust parity. Nobody uses that anyway ...""" Note: Does not adjust parity. Nobody uses that anyway ..."""
D = seed + struct.pack(">i", c) D = seed + struct.pack(">i", c)
H = hashlib.sha1(D).digest() #pylint: disable=E1101 H = hashlib.sha1(D).digest() # pylint: disable=E1101
Ka = H[0:8] Ka = H[0:8]
Kb = H[8:16] Kb = H[8:16]
return Ka + Kb return Ka + Kb
@@ -101,29 +104,31 @@ class PassportSAM(SAM):
the ICAO MRTD standard""" the ICAO MRTD standard"""
rnd_icc = self.last_challenge rnd_icc = self.last_challenge
#Receive Mutual Authenticate APDU from terminal # Receive Mutual Authenticate APDU from terminal
#Decrypt data and check MAC # Decrypt data and check MAC
Eifd = resp_data[:-8] Eifd = resp_data[:-8]
padded_Eifd = vsCrypto.append_padding(self.current_SE.cct.blocklength, Eifd) padded_Eifd = vsCrypto.append_padding(self.current_SE.cct.blocklength,
Eifd)
Mifd = vsCrypto.crypto_checksum("CC", self.KMac, padded_Eifd) Mifd = vsCrypto.crypto_checksum("CC", self.KMac, padded_Eifd)
#Check the MAC # Check the MAC
if not Mifd == resp_data[-8:]: if not Mifd == resp_data[-8:]:
raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"]) raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"])
#Decrypt the data # Decrypt the data
plain = vsCrypto.decrypt("DES3-CBC", self.KEnc, resp_data[:-8]) plain = vsCrypto.decrypt("DES3-CBC", self.KEnc, resp_data[:-8])
if plain[8:16] != rnd_icc: if plain[8:16] != rnd_icc:
raise SwError(SW["WARN_NOINFO63"]) raise SwError(SW["WARN_NOINFO63"])
#Extract keying material from IFD, generate ICC keying material # Extract keying material from IFD, generate ICC keying material
Kifd = plain[16:] Kifd = plain[16:]
rnd_ifd = plain[:8] rnd_ifd = plain[:8]
Kicc = urandom(16) Kicc = urandom(16)
#Generate Answer # Generate Answer
data = plain[8:16] + plain[:8] + Kicc data = plain[8:16] + plain[:8] + Kicc
Eicc = vsCrypto.encrypt("DES3-CBC", self.KEnc, data) Eicc = vsCrypto.encrypt("DES3-CBC", self.KEnc, data)
padded_Eicc = vsCrypto.append_padding(self.current_SE.cct.blocklength, Eicc) padded_Eicc = vsCrypto.append_padding(self.current_SE.cct.blocklength,
Eicc)
Micc = vsCrypto.crypto_checksum("CC", self.KMac, padded_Eicc) Micc = vsCrypto.crypto_checksum("CC", self.KMac, padded_Eicc)
#Derive the final keys and set the current SE # Derive the final keys and set the current SE
KSseed = vsCrypto.operation_on_string(Kicc, Kifd, lambda a, b: a^b) KSseed = vsCrypto.operation_on_string(Kicc, Kifd, lambda a, b: a ^ b)
self.current_SE.ct.key = self.derive_key(KSseed, 1) self.current_SE.ct.key = self.derive_key(KSseed, 1)
self.current_SE.cct.key = self.derive_key(KSseed, 2) self.current_SE.cct.key = self.derive_key(KSseed, 2)
self.current_SE.ssc = stringtoint(rnd_icc[-4:] + rnd_ifd[-4:]) self.current_SE.ssc = stringtoint(rnd_icc[-4:] + rnd_ifd[-4:])

View File

@@ -18,30 +18,42 @@
from virtualsmartcard.SmartcardSAM import SAM from virtualsmartcard.SmartcardSAM import SAM
from virtualsmartcard.VirtualSmartcard import Iso7816OS from virtualsmartcard.VirtualSmartcard import Iso7816OS
from virtualsmartcard.SEutils import ControlReferenceTemplate, Security_Environment from virtualsmartcard.SEutils import ControlReferenceTemplate, \
Security_Environment
from virtualsmartcard.SWutils import SwError, SW from virtualsmartcard.SWutils import SwError, SW
from virtualsmartcard.ConstantDefinitions import CRT_TEMPLATE, SM_Class, ALGO_MAPPING, MAX_EXTENDED_LE, MAX_SHORT_LE from virtualsmartcard.ConstantDefinitions import CRT_TEMPLATE, SM_Class, \
from virtualsmartcard.TLVutils import unpack, bertlv_pack, decodeDiscretionaryDataObjects, tlv_find_tag ALGO_MAPPING, MAX_EXTENDED_LE, MAX_SHORT_LE
from virtualsmartcard.TLVutils import unpack, bertlv_pack, \
decodeDiscretionaryDataObjects, tlv_find_tag
from virtualsmartcard.SmartcardFilesystem import make_property from virtualsmartcard.SmartcardFilesystem import make_property
from virtualsmartcard.utils import inttostring, R_APDU from virtualsmartcard.utils import inttostring, R_APDU
import virtualsmartcard.CryptoUtils as vsCrypto import virtualsmartcard.CryptoUtils as vsCrypto
from chat import CHAT, CVC, PACE_SEC, EAC_CTX from chat import CHAT, CVC, PACE_SEC, EAC_CTX
import binascii
import eac import eac
import logging, binascii import logging
import sys
import traceback
class NPAOS(Iso7816OS): class NPAOS(Iso7816OS):
def __init__(self, mf, sam, ins2handler=None, maxle=MAX_EXTENDED_LE, ef_cardsecurity=None, ef_cardaccess=None, ca_key=None, cvca=None, disable_checks=False, esign_key=None, esign_ca_cert=None, esign_cert=None): def __init__(self, mf, sam, ins2handler=None, maxle=MAX_EXTENDED_LE,
ef_cardsecurity=None, ef_cardaccess=None, ca_key=None,
cvca=None, disable_checks=False, esign_key=None,
esign_ca_cert=None, esign_cert=None):
Iso7816OS.__init__(self, mf, sam, ins2handler, maxle) Iso7816OS.__init__(self, mf, sam, ins2handler, maxle)
self.ins2handler[0x86] = self.SAM.general_authenticate self.ins2handler[0x86] = self.SAM.general_authenticate
self.ins2handler[0x2c] = self.SAM.reset_retry_counter self.ins2handler[0x2c] = self.SAM.reset_retry_counter
# different ATR (Answer To Reset) values depending on used Chip version # different ATR (Answer To Reset) values depending on used Chip version
# It's just a playground, because in past one of all those eID clients did not recognize the card correctly with newest ATR values # It's just a playground, because in past one of all those eID clients
self.atr = '\x3B\x8A\x80\x01\x80\x31\xF8\x73\xF7\x41\xE0\x82\x90\x00\x75' # did not recognize the card correctly with newest ATR values
#self.atr = '\x3B\x8A\x80\x01\x80\x31\xB8\x73\x84\x01\xE0\x82\x90\x00\x06' self.atr = '\x3B\x8A\x80\x01\x80\x31\xF8\x73\xF7\x41\xE0\x82\x90' + \
#self.atr = '\x3B\x88\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x09' '\x00\x75'
#self.atr = '\x3B\x87\x80\x01\x80\x31\xB8\x73\x84\x01\xE0\x19' # self.atr = '\x3B\x8A\x80\x01\x80\x31\xB8\x73\x84\x01\xE0\x82\x90' + \
# '\x00\x06'
# self.atr = '\x3B\x88\x80\x01\x00\x00\x00\x00\x00\x00\x00\x00\x09'
# self.atr = '\x3B\x87\x80\x01\x80\x31\xB8\x73\x84\x01\xE0\x19'
self.SAM.current_SE.disable_checks = disable_checks self.SAM.current_SE.disable_checks = disable_checks
if ef_cardsecurity: if ef_cardsecurity:
@@ -54,7 +66,8 @@ class NPAOS(Iso7816OS):
self.SAM.current_SE.cvca = cvca self.SAM.current_SE.cvca = cvca
if ca_key: if ca_key:
self.SAM.current_SE.ca_key = ca_key self.SAM.current_SE.ca_key = ca_key
esign = self.mf.select('dfname', '\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E') esign = self.mf.select('dfname',
'\xA0\x00\x00\x01\x67\x45\x53\x49\x47\x4E')
if esign_ca_cert: if esign_ca_cert:
ef = esign.select('fid', 0xC000) ef = esign.select('fid', 0xC000)
ef.data = esign_ca_cert ef.data = esign_ca_cert
@@ -62,7 +75,6 @@ class NPAOS(Iso7816OS):
ef = esign.select('fid', 0xC001) ef = esign.select('fid', 0xC001)
ef.data = esign_cert ef.data = esign_cert
def formatResult(self, seekable, le, data, sw, sm): def formatResult(self, seekable, le, data, sw, sm):
if seekable: if seekable:
# when le = 0 then we want to have 0x9000. here we only have the # when le = 0 then we want to have 0x9000. here we only have the
@@ -72,7 +84,7 @@ class NPAOS(Iso7816OS):
if le > len(data) and le != MAX_EXTENDED_LE and le != MAX_SHORT_LE: if le > len(data) and le != MAX_EXTENDED_LE and le != MAX_SHORT_LE:
sw = SW["WARN_EOFBEFORENEREAD"] sw = SW["WARN_EOFBEFORENEREAD"]
if le != None: if le is not None:
result = data[:le] result = data[:le]
else: else:
result = data[:0] result = data[:0]
@@ -81,7 +93,6 @@ class NPAOS(Iso7816OS):
sw, result = self.SAM.protect_result(sw, result) sw, result = self.SAM.protect_result(sw, result)
except SwError as e: except SwError as e:
logging.info(e.message) logging.info(e.message)
import traceback, sys
traceback.print_exception(*sys.exc_info()) traceback.print_exception(*sys.exc_info())
sw = e.sw sw = e.sw
result = "" result = ""
@@ -105,22 +116,22 @@ class nPA_AT_CRT(ControlReferenceTemplate):
CommunityID = None CommunityID = None
def keyref_is_mrz(self): def keyref_is_mrz(self):
if self.keyref_secret_key == '%c'% self.PACE_MRZ: if self.keyref_secret_key == '%c' % self.PACE_MRZ:
return True return True
return False return False
def keyref_is_can(self): def keyref_is_can(self):
if self.keyref_secret_key == '%c'% self.PACE_CAN: if self.keyref_secret_key == '%c' % self.PACE_CAN:
return True return True
return False return False
def keyref_is_pin(self): def keyref_is_pin(self):
if self.keyref_secret_key == '%c'% self.PACE_PIN: if self.keyref_secret_key == '%c' % self.PACE_PIN:
return True return True
return False return False
def keyref_is_puk(self): def keyref_is_puk(self):
if self.keyref_secret_key == '%c'% self.PACE_PUK: if self.keyref_secret_key == '%c' % self.PACE_PUK:
return True return True
return False return False
@@ -145,13 +156,16 @@ class nPA_AT_CRT(ControlReferenceTemplate):
mapped_algo = ALGO_MAPPING[oidvalue] mapped_algo = ALGO_MAPPING[oidvalue]
if mapped_algo == "DateOfBirth": if mapped_algo == "DateOfBirth":
self.DateOfBirth = int(reference) self.DateOfBirth = int(reference)
logging.info("Found reference DateOfBirth: " + str(self.DateOfBirth)) logging.info("Found reference DateOfBirth: " +
str(self.DateOfBirth))
elif mapped_algo == "DateOfExpiry": elif mapped_algo == "DateOfExpiry":
self.DateOfExpiry = int(reference) self.DateOfExpiry = int(reference)
logging.info("Found reference DateOfExpiry: " + str(self.DateOfExpiry)) logging.info("Found reference DateOfExpiry: " +
str(self.DateOfExpiry))
elif mapped_algo == "CommunityID": elif mapped_algo == "CommunityID":
self.CommunityID = binascii.hexlify(reference) self.CommunityID = binascii.hexlify(reference)
logging.info("Found reference CommunityID: " + str(self.CommunityID)) logging.info("Found reference CommunityID: " +
str(self.CommunityID))
except: except:
pass pass
elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91: elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
@@ -170,7 +184,7 @@ class nPA_SE(Security_Environment):
def __init__(self, MF, SAM): def __init__(self, MF, SAM):
Security_Environment.__init__(self, MF, SAM) Security_Environment.__init__(self, MF, SAM)
self.at = nPA_AT_CRT() self.at = nPA_AT_CRT()
#This breaks support for 3DES # This breaks support for 3DES
self.cct.blocklength = 16 self.cct.blocklength = 16
self.cct.algorithm = "CC" self.cct.algorithm = "CC"
self.eac_step = 0 self.eac_step = 0
@@ -206,7 +220,7 @@ class nPA_SE(Security_Environment):
if (p1, p2) != (0x00, 0x00): if (p1, p2) != (0x00, 0x00):
raise SwError(SW["ERR_INCORRECTPARAMETERS"]) raise SwError(SW["ERR_INCORRECTPARAMETERS"])
if self.eac_step == 0 and self.at.algorithm == "PACE": if self.eac_step == 0 and self.at.algorithm == "PACE":
return self.__eac_pace_step1(data) return self.__eac_pace_step1(data)
elif self.eac_step == 1 and self.at.algorithm == "PACE": elif self.eac_step == 1 and self.at.algorithm == "PACE":
return self.__eac_pace_step2(data) return self.__eac_pace_step2(data)
@@ -217,8 +231,12 @@ class nPA_SE(Security_Environment):
elif self.eac_step == 5 and self.at.algorithm == "CA": elif self.eac_step == 5 and self.at.algorithm == "CA":
return self.__eac_ca(data) return self.__eac_ca(data)
elif self.eac_step == 6: elif self.eac_step == 6:
# TODO implement RI "\x7c\x22\x81\x20\" is some prefix and the rest is our RI # TODO implement RI
return SW["NORMAL"], "\x7c\x22\x81\x20\x48\x1e\x58\xd1\x7c\x12\x9a\x0a\xb4\x63\x7d\x43\xc7\xf7\xeb\x2b\x06\x10\x6f\x26\x90\xe3\x00\xc4\xe7\x03\x54\xa0\x41\xf0\xd3\x90" # "\x7c\x22\x81\x20\" is some prefix and the rest is our RI
return SW["NORMAL"], "\x7c\x22\x81\x20\x48\x1e\x58\xd1\x7c\x12" + \
"\x9a\x0a\xb4\x63\x7d\x43\xc7\xf7\xeb\x2b" + \
"\x06\x10\x6f\x26\x90\xe3\x00\xc4\xe7\x03" + \
"\x54\xa0\x41\xf0\xd3\x90"
raise SwError(SW["ERR_INCORRECTPARAMETERS"]) raise SwError(SW["ERR_INCORRECTPARAMETERS"])
@@ -241,7 +259,7 @@ class nPA_SE(Security_Environment):
def __eac_pace_step1(self, data): def __eac_pace_step1(self, data):
tlv_data = nPA_SE.__unpack_general_authenticate(data) tlv_data = nPA_SE.__unpack_general_authenticate(data)
if tlv_data != []: if tlv_data != []:
raise SwError(SW["WARN_NOINFO63"]) raise SwError(SW["WARN_NOINFO63"])
if self.at.keyref_is_mrz(): if self.at.keyref_is_mrz():
@@ -277,27 +295,33 @@ class nPA_SE(Security_Environment):
ef_card_security = self.mf.select('fid', 0x011d) ef_card_security = self.mf.select('fid', 0x011d)
ef_card_security_data = ef_card_security.data ef_card_security_data = ef_card_security.data
eac.EAC_CTX_init_ef_cardsecurity(ef_card_security_data, self.eac_ctx) eac.EAC_CTX_init_ef_cardsecurity(ef_card_security_data,
self.eac_ctx)
if self.ca_key: if self.ca_key:
ca_pubkey = eac.CA_get_pubkey(self.eac_ctx, ef_card_security_data) ca_pubkey = eac.CA_get_pubkey(self.eac_ctx,
ef_card_security_data)
if 1 != eac.CA_set_key(self.eac_ctx, self.ca_key, ca_pubkey): if 1 != eac.CA_set_key(self.eac_ctx, self.ca_key, ca_pubkey):
eac.print_ossl_err() eac.print_ossl_err()
raise SwError(SW["WARN_NOINFO63"]) raise SwError(SW["WARN_NOINFO63"])
else: else:
# we don't have a good CA key, so we simply generate an ephemeral one # we don't have a good CA key, so we simply generate an
# ephemeral one
comp_pubkey = eac.TA_STEP3_generate_ephemeral_key(self.eac_ctx) comp_pubkey = eac.TA_STEP3_generate_ephemeral_key(self.eac_ctx)
pubkey = eac.CA_STEP2_get_eph_pubkey(self.eac_ctx) pubkey = eac.CA_STEP2_get_eph_pubkey(self.eac_ctx)
if not comp_pubkey or not pubkey: if not comp_pubkey or not pubkey:
eac.print_ossl_err() eac.print_ossl_err()
raise SwError(SW["WARN_NOINFO63"]) raise SwError(SW["WARN_NOINFO63"])
# save public key in EF.CardSecurity (and invalidate the signature) # save public key in EF.CardSecurity (and invalidate the
# signature)
# FIXME this only works for the default EF.CardSecurity. # FIXME this only works for the default EF.CardSecurity.
# Better use an ASN.1 parser to do this manipulation # Better use an ASN.1 parser to do this manipulation
ef_card_security = self.mf.select('fid', 0x011d) ef_card_security = self.mf.select('fid', 0x011d)
ef_card_security_data = ef_card_security.data ef_card_security_data = ef_card_security.data
ef_card_security_data = ef_card_security_data[:61+4+239+2+1] + pubkey + ef_card_security_data[61+4+239+2+1+len(pubkey):] ef_card_security_data = \
ef_card_security_data[:61+4+239+2+1] + pubkey + \
ef_card_security_data[61+4+239+2+1+len(pubkey):]
ef_card_security.data = ef_card_security_data ef_card_security.data = ef_card_security_data
nonce = eac.PACE_STEP1_enc_nonce(self.eac_ctx, self.sec) nonce = eac.PACE_STEP1_enc_nonce(self.eac_ctx, self.sec)
@@ -327,12 +351,14 @@ class nPA_SE(Security_Environment):
self.eac_step += 1 self.eac_step += 1
return 0x9000, nPA_SE.__pack_general_authenticate([[0x82, len(pubkey), pubkey]]) return 0x9000, \
nPA_SE.__pack_general_authenticate([[0x82, len(pubkey), pubkey]])
def __eac_pace_step3(self, data): def __eac_pace_step3(self, data):
tlv_data = nPA_SE.__unpack_general_authenticate(data) tlv_data = nPA_SE.__unpack_general_authenticate(data)
self.my_pace_eph_pubkey = eac.PACE_STEP3B_generate_ephemeral_key(self.eac_ctx) self.my_pace_eph_pubkey = \
eac.PACE_STEP3B_generate_ephemeral_key(self.eac_ctx)
if not self.my_pace_eph_pubkey: if not self.my_pace_eph_pubkey:
eac.print_ossl_err() eac.print_ossl_err()
raise SwError(SW["WARN_NOINFO63"]) raise SwError(SW["WARN_NOINFO63"])
@@ -341,18 +367,23 @@ class nPA_SE(Security_Environment):
for tag, length, value in tlv_data: for tag, length, value in tlv_data:
if tag == 0x83: if tag == 0x83:
self.pace_opp_pub_key = value self.pace_opp_pub_key = value
eac.PACE_STEP3B_compute_shared_secret(self.eac_ctx, self.pace_opp_pub_key) eac.PACE_STEP3B_compute_shared_secret(self.eac_ctx,
self.pace_opp_pub_key)
else: else:
raise SwError(SW["ERR_INCORRECTPARAMETERS"]) raise SwError(SW["ERR_INCORRECTPARAMETERS"])
self.eac_step += 1 self.eac_step += 1
return 0x9000, nPA_SE.__pack_general_authenticate([[0x84, len(eph_pubkey), eph_pubkey]]) return 0x9000, \
nPA_SE.__pack_general_authenticate([[0x84, len(eph_pubkey),
eph_pubkey]])
def __eac_pace_step4(self, data): def __eac_pace_step4(self, data):
tlv_data = nPA_SE.__unpack_general_authenticate(data) tlv_data = nPA_SE.__unpack_general_authenticate(data)
eac.PACE_STEP3C_derive_keys(self.eac_ctx) eac.PACE_STEP3C_derive_keys(self.eac_ctx)
my_token = eac.PACE_STEP3D_compute_authentication_token(self.eac_ctx, self.pace_opp_pub_key) my_token = \
eac.PACE_STEP3D_compute_authentication_token(self.eac_ctx,
self.pace_opp_pub_key)
token = "" token = ""
for tag, length, value in tlv_data: for tag, length, value in tlv_data:
if tag == 0x85: if tag == 0x85:
@@ -360,7 +391,8 @@ class nPA_SE(Security_Environment):
else: else:
raise SwError(SW["ERR_INCORRECTPARAMETERS"]) raise SwError(SW["ERR_INCORRECTPARAMETERS"])
if not my_token or 1 != eac.PACE_STEP3D_verify_authentication_token(self.eac_ctx, token): ver = eac.PACE_STEP3D_verify_authentication_token(self.eac_ctx, token)
if not my_token or ver != 1:
eac.print_ossl_err() eac.print_ossl_err()
raise SwError(SW["WARN_NOINFO63"]) raise SwError(SW["WARN_NOINFO63"])
@@ -394,7 +426,6 @@ class nPA_SE(Security_Environment):
eac.print_ossl_err() eac.print_ossl_err()
raise SwError(SW["WARN_NOINFO63"]) raise SwError(SW["WARN_NOINFO63"])
return 0x9000, nPA_SE.__pack_general_authenticate(result) return 0x9000, nPA_SE.__pack_general_authenticate(result)
def __eac_ca(self, data): def __eac_ca(self, data):
@@ -423,8 +454,9 @@ class nPA_SE(Security_Environment):
# TODO activate SM # TODO activate SM
self.new_encryption_ctx = eac.EAC_ID_CA self.new_encryption_ctx = eac.EAC_ID_CA
return 0x9000, nPA_SE.__pack_general_authenticate([[0x81, return 0x9000, \
len(nonce), nonce], [0x82, len(token), token]]) nPA_SE.__pack_general_authenticate([[0x81, len(nonce), nonce],
[0x82, len(token), token]])
def verify_certificate(self, p1, p2, data): def verify_certificate(self, p1, p2, data):
if (p1, p2) != (0x00, 0xbe): if (p1, p2) != (0x00, 0xbe):
@@ -444,8 +476,9 @@ class nPA_SE(Security_Environment):
Authenticate the terminal to the card. Check whether Terminal correctly Authenticate the terminal to the card. Check whether Terminal correctly
encrypted the given challenge or not encrypted the given challenge or not
""" """
if self.dst.keyref_public_key: # TODO check if this is the correct CAR if self.dst.keyref_public_key: # TODO check if this is the correct CAR
id_picc = eac.EAC_Comp(self.eac_ctx, eac.EAC_ID_PACE, self.my_pace_eph_pubkey) id_picc = eac.EAC_Comp(self.eac_ctx, eac.EAC_ID_PACE,
self.my_pace_eph_pubkey)
# FIXME auxiliary_data might be from an older run of PACE # FIXME auxiliary_data might be from an older run of PACE
if hasattr(self.at, "auxiliary_data"): if hasattr(self.at, "auxiliary_data"):
@@ -454,7 +487,7 @@ class nPA_SE(Security_Environment):
auxiliary_data = None auxiliary_data = None
if 1 != eac.TA_STEP6_verify(self.eac_ctx, self.at.iv, id_picc, if 1 != eac.TA_STEP6_verify(self.eac_ctx, self.at.iv, id_picc,
auxiliary_data, data): auxiliary_data, data):
eac.print_ossl_err() eac.print_ossl_err()
print "Could not verify Terminal's signature" print "Could not verify Terminal's signature"
raise SwError(SW["ERR_CONDITIONNOTSATISFIED"]) raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])
@@ -517,7 +550,7 @@ class nPA_SE(Security_Environment):
tlv_sw = bertlv_pack([(tag, length, sw_str)]) tlv_sw = bertlv_pack([(tag, length, sw_str)])
return_data += tlv_sw return_data += tlv_sw
if self.cct.algorithm == None: if self.cct.algorithm is None:
raise SwError(SW["CONDITIONSNOTSATISFIED"]) raise SwError(SW["CONDITIONSNOTSATISFIED"])
elif self.cct.algorithm == "CC": elif self.cct.algorithm == "CC":
tag = SM_Class["CHECKSUM"] tag = SM_Class["CHECKSUM"]
@@ -535,13 +568,18 @@ class nPA_SE(Security_Environment):
return sw, return_data return sw, return_data
def compute_digital_signature(self, p1, p2, data): def compute_digital_signature(self, p1, p2, data):
# TODO Signing with brainpoolP256r1 or any other key needs some more effort ;-) # TODO Signing with brainpoolP256r1 or any other key needs some more
return '\x0D\xB2\x9B\xB9\x5E\x97\x7D\x42\x73\xCF\xA5\x45\xB7\xED\x5C\x39\x3F\xCE\xCD\x4A\xDE\xDC\x2B\x85\x23\x9F\x66\x52\x10\xC2\x67\xDC\xA6\x35\x94\x2D\x24\xED\xEB\xC8\x34\x6C\x4B\xD1\xA1\x15\xB4\x48\x3A\xA4\x4A\xCE\xFF\xED\x97\x0E\x07\xF3\x72\xF0\xFB\xA3\x62\x8C' # effort ;-)
return '\x0D\xB2\x9B\xB9\x5E\x97\x7D\x42\x73\xCF\xA5\x45\xB7\xED' + \
'\x5C\x39\x3F\xCE\xCD\x4A\xDE\xDC\x2B\x85\x23\x9F\x66\x52' + \
'\x10\xC2\x67\xDC\xA6\x35\x94\x2D\x24\xED\xEB\xC8\x34\x6C' + \
'\x4B\xD1\xA1\x15\xB4\x48\x3A\xA4\x4A\xCE\xFF\xED\x97\x0E' + \
'\x07\xF3\x72\xF0\xFB\xA3\x62\x8C'
class nPA_SAM(SAM): class nPA_SAM(SAM):
def __init__(self, eid_pin, can, mrz, puk, qes_pin, mf, default_se = nPA_SE): def __init__(self, eid_pin, can, mrz, puk, qes_pin, mf, default_se=nPA_SE):
SAM.__init__(self, qes_pin, None, mf) SAM.__init__(self, qes_pin, None, mf)
self.active = True self.active = True
self.current_SE = default_se(self.mf, self) self.current_SE = default_se(self.mf, self)
@@ -559,14 +597,15 @@ class nPA_SAM(SAM):
if self.current_SE.eac_step < 4: if self.current_SE.eac_step < 4:
raise SwError(SW["ERR_SECSTATUS"]) raise SwError(SW["ERR_SECSTATUS"])
# TODO check CAN and PIN for the correct character set # TODO: check CAN and PIN for the correct character set
if p1 == 0x02: if p1 == 0x02:
# change secret # change secret
if p2 == self.current_SE.at.PACE_CAN: if p2 == self.current_SE.at.PACE_CAN:
self.can = data self.can = data
print "Changed CAN to %r" % self.can print "Changed CAN to %r" % self.can
elif p2 == self.current_SE.at.PACE_PIN: elif p2 == self.current_SE.at.PACE_PIN:
# TODO allow terminals to change the PIN with permission "CAN allowed" # TODO: allow terminals to change the PIN with permission
# "CAN allowed"
if not self.current_SE.at.keyref_is_pin(): if not self.current_SE.at.keyref_is_pin():
raise SwError(SW["ERR_CONDITIONNOTSATISFIED"]) raise SwError(SW["ERR_CONDITIONNOTSATISFIED"])
self.eid_pin = data self.eid_pin = data
@@ -583,7 +622,8 @@ class nPA_SAM(SAM):
self.active = True self.active = True
print "Resumed PIN" print "Resumed PIN"
elif self.current_SE.at.keyref_is_pin(): elif self.current_SE.at.keyref_is_pin():
# PACE was successful with PIN, nothing to do resume/unblock # PACE was successful with PIN, nothing to do
# resume/unblock
pass pass
elif self.current_SE.at.keyref_is_puk(): elif self.current_SE.at.keyref_is_puk():
# TODO unblock PIN for signature # TODO unblock PIN for signature
@@ -608,7 +648,8 @@ class nPA_SAM(SAM):
if (p1 != 0x00 or p2 != 0x00): if (p1 != 0x00 or p2 != 0x00):
raise SwError(SW["ERR_INCORRECTP1P2"]) raise SwError(SW["ERR_INCORRECTP1P2"])
self.last_challenge = eac.TA_STEP4_get_nonce(self.current_SE.eac_ctx) self.last_challenge = \
eac.TA_STEP4_get_nonce(self.current_SE.eac_ctx)
if not self.last_challenge: if not self.last_challenge:
eac.print_ossl_err() eac.print_ossl_err()
raise SwError(SW["ERR_NOINFO69"]) raise SwError(SW["ERR_NOINFO69"])
@@ -624,11 +665,14 @@ class nPA_SAM(SAM):
[(tag, _, value)] = structure = unpack(data) [(tag, _, value)] = structure = unpack(data)
if tag == 6: if tag == 6:
mapped_algo = ALGO_MAPPING[value] mapped_algo = ALGO_MAPPING[value]
eid = self.mf.select('dfname', '\xe8\x07\x04\x00\x7f\x00\x07\x03\x02') eid = self.mf.select('dfname', '\xe8\x07\x04\x00\x7f\x00'
'\x07\x03\x02')
if mapped_algo == "DateOfExpiry": if mapped_algo == "DateOfExpiry":
[(_, _, [(_, _, mine)])] = unpack(eid.select('fid', 0x0103).data) [(_, _, [(_, _, mine)])] = \
logging.info("DateOfExpiry: " + str(mine) unpack(eid.select('fid', 0x0103).data)
+ "; reference: " + str(self.current_SE.at.DateOfExpiry)) logging.info("DateOfExpiry: " + str(mine) +
"; reference: " +
str(self.current_SE.at.DateOfExpiry))
if self.current_SE.at.DateOfExpiry < mine: if self.current_SE.at.DateOfExpiry < mine:
print("Date of expiry verified") print("Date of expiry verified")
return SW["NORMAL"], "" return SW["NORMAL"], ""
@@ -636,16 +680,19 @@ class nPA_SAM(SAM):
print("Date of expiry not verified (expired)") print("Date of expiry not verified (expired)")
return SW["WARN_NOINFO63"], "" return SW["WARN_NOINFO63"], ""
elif mapped_algo == "DateOfBirth": elif mapped_algo == "DateOfBirth":
[(_, _, [(_, _, mine)])] = unpack(eid.select('fid', 0x0108).data) [(_, _, [(_, _, mine)])] = \
unpack(eid.select('fid', 0x0108).data)
# case1: YYYYMMDD -> good # case1: YYYYMMDD -> good
# case2: YYYYMM -> mapped to last day of given month, i.e. YYYYMM31 ;-) # case2: YYYYMM -> mapped to last day of given month,
# i.e. YYYYMM31 ;-)
# case3: YYYY -> mapped to YYYY-12-31 # case3: YYYY -> mapped to YYYY-12-31
if len(str(mine)) == 6: if len(str(mine)) == 6:
mine = int(str(mine) + "31") mine = int(str(mine) + "31")
elif len(str(mine)) == 4: elif len(str(mine)) == 4:
mine = int(str(mine) + "1231") mine = int(str(mine) + "1231")
logging.info("DateOfBirth: " + str(mine) logging.info("DateOfBirth: " + str(mine) +
+ "; reference: " + str(self.current_SE.at.DateOfExpiry)) "; reference: " +
str(self.current_SE.at.DateOfExpiry))
if self.current_SE.at.DateOfBirth < mine: if self.current_SE.at.DateOfBirth < mine:
print("Date of birth verified (old enough)") print("Date of birth verified (old enough)")
return SW["NORMAL"], "" return SW["NORMAL"], ""
@@ -653,15 +700,18 @@ class nPA_SAM(SAM):
print("Date of birth not verified (too young)") print("Date of birth not verified (too young)")
return SW["WARN_NOINFO63"], "" return SW["WARN_NOINFO63"], ""
elif mapped_algo == "CommunityID": elif mapped_algo == "CommunityID":
[(_, _, [(_, _, mine)])] = unpack(eid.select('fid', 0x0112).data) [(_, _, [(_, _, mine)])] = \
unpack(eid.select('fid', 0x0112).data)
mine = binascii.hexlify(mine) mine = binascii.hexlify(mine)
logging.info("CommunityID: " + str(mine) logging.info("CommunityID: " + str(mine) +
+ "; reference: " + str(self.current_SE.at.CommunityID)) "; reference: " +
str(self.current_SE.at.CommunityID))
if mine.startswith(self.current_SE.at.CommunityID): if mine.startswith(self.current_SE.at.CommunityID):
print("Community ID verified (living there)") print("Community ID verified (living there)")
return SW["NORMAL"], "" return SW["NORMAL"], ""
else: else:
print("Community ID not verified (not living there)") print("Community ID not verified (not living"
"there)")
return SW["WARN_NOINFO63"], "" return SW["WARN_NOINFO63"], ""
else: else:
return SwError(SW["ERR_DATANOTFOUND"]) return SwError(SW["ERR_DATANOTFOUND"])
@@ -677,10 +727,12 @@ class nPA_SAM(SAM):
protocol = "PACE" protocol = "PACE"
else: else:
protocol = "CA" protocol = "CA"
logging.info("switching to new encryption context established in %s:" % protocol) logging.info("switching to new encryption context established in "
"%s:" % protocol)
logging.info(eac.EAC_CTX_print_private(self.current_SE.eac_ctx, 4)) logging.info(eac.EAC_CTX_print_private(self.current_SE.eac_ctx, 4))
eac.EAC_CTX_set_encryption_ctx(self.current_SE.eac_ctx, self.current_SE.new_encryption_ctx) eac.EAC_CTX_set_encryption_ctx(self.current_SE.eac_ctx,
self.current_SE.new_encryption_ctx)
delattr(self.current_SE, "new_encryption_ctx") delattr(self.current_SE, "new_encryption_ctx")