added PACE support for nPA emulator

git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@671 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
frankmorgner
2011-12-16 19:22:29 +00:00
parent b8e5336e3a
commit bcd0155238
3 changed files with 147 additions and 9 deletions

View File

@@ -148,7 +148,8 @@ class CardGenerator(object):
ALGO_MAPPING["\x04\x00\x7f\x00\x07\x02\x02\x04\x02\x02"] = "PACE" ALGO_MAPPING["\x04\x00\x7f\x00\x07\x02\x02\x04\x02\x02"] = "PACE"
self.mf = MF() self.mf = MF()
self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x011c, shortfid=0x1c, data=card_access)) self.mf.append(TransparentStructureEF(parent=self.mf, fid=0x011c, shortfid=0x1c, data=card_access))
self.sam = nPA_SAM(self.mf) self.sam = nPA_SAM(pin="pin", can="can", mrz="mrz", puk="puk", mf=self.mf)
self.sam.card_access = card_access
def __generate_cryptoflex(self): def __generate_cryptoflex(self):
"""Generate the Filesystem and SAM of a cryptoflex card""" """Generate the Filesystem and SAM of a cryptoflex card"""

View File

@@ -334,7 +334,8 @@ class Iso7816OS(SmartcardOS):
answer = self.formatResult(Iso7816OS.seekable(c.ins), c.effective_Le, result, sw, False) answer = self.formatResult(Iso7816OS.seekable(c.ins), c.effective_Le, result, sw, False)
except SwError as e: except SwError as e:
logging.info(e.message) logging.info(e.message)
#traceback.print_exception(*sys.exc_info()) import traceback
traceback.print_exception(*sys.exc_info())
sw = e.sw sw = e.sw
result = "" result = ""
answer = self.formatResult(False, 0, result, sw, False) answer = self.formatResult(False, 0, result, sw, False)
@@ -495,12 +496,16 @@ class RelayOS(SmartcardOS):
class NPAOS(Iso7816OS): class NPAOS(Iso7816OS):
def __init__(self, mf, sam, ins2handler=None, maxle=MAX_EXTENDED_LE):
Iso7816OS.__init__(self, mf, sam, ins2handler, maxle)
self.ins2handler[0x86] = self.SAM.general_authenticate
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
# effective le, which is either MAX_EXTENDED_LE or MAX_SHORT_LE, # effective le, which is either MAX_EXTENDED_LE or MAX_SHORT_LE,
# depending on the APDU. Note that the following distinguisher has # depending on the APDU. Note that the following distinguisher has
# one false positives # one false positive
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"]
@@ -513,6 +518,7 @@ class NPAOS(Iso7816OS):
# sizeof(int) taken from asizof-package {{{ # sizeof(int) taken from asizof-package {{{
_Csizeof_short = len(struct.pack('h', 0)) _Csizeof_short = len(struct.pack('h', 0))
# }}}
VPCD_CTRL_LEN = 1 VPCD_CTRL_LEN = 1

View File

@@ -21,6 +21,9 @@ from virtualsmartcard.SEutils import ControlReferenceTemplate
from virtualsmartcard.SWutils import SwError, SW from virtualsmartcard.SWutils import SwError, SW
from virtualsmartcard.ConstantDefinitions import CRT_TEMPLATE from virtualsmartcard.ConstantDefinitions import CRT_TEMPLATE
from virtualsmartcard.TLVutils import unpack, bertlv_pack from virtualsmartcard.TLVutils import unpack, bertlv_pack
from virtualsmartcard.SmartcardFilesystem import make_property
from chat import CHAT
import pace
class nPA_AT_CRT(ControlReferenceTemplate): class nPA_AT_CRT(ControlReferenceTemplate):
def __init__(self): def __init__(self):
@@ -50,11 +53,139 @@ class nPA_AT_CRT(ControlReferenceTemplate):
return 0x9000 , "" return 0x9000 , ""
class nPA_SAM(SAM): class nPA_SAM(SAM):
""" # TODO move EAC to the securiity environment
SAM for ICAO ePassport. Implements Basic access control and key derivation # TODO call __eac_abort whenever an error occurred
for Secure Messaging.
""" eac_step = make_property("eac_step", "next step to performed for EAC")
def __init__(self, mf):
def __init__(self, pin, can, mrz, puk, mf):
SAM.__init__(self, None, None, mf) SAM.__init__(self, None, None, mf)
self.current_SE.at = nPA_AT_CRT() self.current_SE.at = nPA_AT_CRT()
self.eac_step = 0
self.eac_ctx = None
self.sec = None
self.step2handler = {
0: self.__eac_pace_step1,
1: self.__eac_pace_step2,
2: self.__eac_pace_step3,
3: self.__eac_pace_step4,
}
self.pin = pin
self.can = can
self.mrz = mrz
self.puk = puk
def general_authenticate(self, p1, p2, data):
def notImplemented(*argz, **args):
raise SwError(SW["WARN_NOINFO63"])
if (p1, p2) != (0x00, 0x00):
raise SwError(SW["ERR_INCORRECTPARAMETERS"])
return self.step2handler.get(self.eac_step, notImplemented)(data)
def __eac_abort(self):
pace.EAC_CTX_clear_free(self.eac_ctx)
pace.PACE_SEC_clear_free(self.sec)
@staticmethod
def __unpack_general_authenticate(data):
data_structure = []
structure = unpack(data)
for tlv in structure:
tag, length, value = tlv
if tag == 0x7c:
data_structure = value
else:
raise SwError(SW["ERR_INCORRECTPARAMETERS"])
return data_structure
@staticmethod
def __pack_general_authenticate(data):
tlv_data = bertlv_pack(data)
return bertlv_pack([[0x7c, len(tlv_data), tlv_data]])
def __eac_pace_step1(self, data):
tlv_data = nPA_SAM.__unpack_general_authenticate(data)
if self.current_SE.at.algorithm != "PACE" or tlv_data != []:
print 'value %r' % tlv_data
raise SwError(SW["WARN_NOINFO63"])
self.__eac_abort()
self.eac_ctx = pace.EAC_CTX_new()
if self.current_SE.at.keyref == '\x01':
self.sec = pace.PACE_SEC_new(self.mrz, pace.PACE_MRZ)
elif self.current_SE.at.keyref == '\x02':
self.sec = pace.PACE_SEC_new(self.can, pace.PACE_CAN)
elif self.current_SE.at.keyref == '\x03':
self.sec = pace.PACE_SEC_new(self.pin, pace.PACE_PIN)
elif self.current_SE.at.keyref == '\x04':
self.sec = pace.PACE_SEC_new(self.puk, pace.PACE_PUK)
else:
raise SwError(SW["ERR_INCORRECTPARAMETERS"])
ef_card_access = self.mf.select('fid', 0x011c)
ef_card_access_data = ef_card_access.getenc('data')
pace.EAC_CTX_init_ef_cardaccess(ef_card_access_data, self.eac_ctx)
nonce = pace.buf2string(pace.PACE_STEP1_enc_nonce(self.eac_ctx, self.sec))
resp = nPA_SAM.__pack_general_authenticate([[0x80, len(nonce), nonce]])
self.eac_step += 1
return 0x9000, resp
def __eac_pace_step2(self, data):
tlv_data = nPA_SAM.__unpack_general_authenticate(data)
if self.current_SE.at.algorithm != "PACE":
raise SwError(SW["WARN_NOINFO63"])
pubkey = pace.buf2string(pace.PACE_STEP3A_generate_mapping_data(self.eac_ctx))
for tag, length, value in tlv_data:
if tag == 0x81:
pace.PACE_STEP3A_map_generator(self.eac_ctx, pace.get_buf(value))
else:
raise SwError(SW["ERR_INCORRECTPARAMETERS"])
self.eac_step += 1
return 0x9000, nPA_SAM.__pack_general_authenticate([[0x82, len(pubkey), pubkey]])
def __eac_pace_step3(self, data):
tlv_data = nPA_SAM.__unpack_general_authenticate(data)
if self.current_SE.at.algorithm != "PACE":
raise SwError(SW["WARN_NOINFO63"])
my_epp_pubkey = pace.buf2string(pace.PACE_STEP3B_generate_ephemeral_key(self.eac_ctx))
for tag, length, value in tlv_data:
if tag == 0x83:
self.pace_opp_pub_key = pace.get_buf(value)
pace.PACE_STEP3B_compute_shared_secret(self.eac_ctx, self.pace_opp_pub_key)
else:
raise SwError(SW["ERR_INCORRECTPARAMETERS"])
self.eac_step += 1
return 0x9000, nPA_SAM.__pack_general_authenticate([[0x84, len(my_epp_pubkey), my_epp_pubkey]])
def __eac_pace_step4(self, data):
tlv_data = nPA_SAM.__unpack_general_authenticate(data)
if self.current_SE.at.algorithm != "PACE":
raise SwError(SW["WARN_NOINFO63"])
pace.PACE_STEP3C_derive_keys(self.eac_ctx)
my_token = pace.buf2string(pace.PACE_STEP3D_compute_authentication_token(self.eac_ctx, self.pace_opp_pub_key))
for tag, length, value in tlv_data:
if tag == 0x85:
pace.PACE_STEP3D_verify_authentication_token(self.eac_ctx, pace.get_buf(value))
else:
raise SwError(SW["ERR_INCORRECTPARAMETERS"])
self.eac_step += 1
return 0x9000, nPA_SAM.__pack_general_authenticate([[0x86, len(my_token), my_token]])