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:
@@ -148,7 +148,8 @@ class CardGenerator(object):
|
||||
ALGO_MAPPING["\x04\x00\x7f\x00\x07\x02\x02\x04\x02\x02"] = "PACE"
|
||||
self.mf = MF()
|
||||
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):
|
||||
"""Generate the Filesystem and SAM of a cryptoflex card"""
|
||||
|
||||
@@ -334,7 +334,8 @@ class Iso7816OS(SmartcardOS):
|
||||
answer = self.formatResult(Iso7816OS.seekable(c.ins), c.effective_Le, result, sw, False)
|
||||
except SwError as e:
|
||||
logging.info(e.message)
|
||||
#traceback.print_exception(*sys.exc_info())
|
||||
import traceback
|
||||
traceback.print_exception(*sys.exc_info())
|
||||
sw = e.sw
|
||||
result = ""
|
||||
answer = self.formatResult(False, 0, result, sw, False)
|
||||
@@ -495,12 +496,16 @@ class RelayOS(SmartcardOS):
|
||||
|
||||
|
||||
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):
|
||||
if seekable:
|
||||
# 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,
|
||||
# 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:
|
||||
sw = SW["WARN_EOFBEFORENEREAD"]
|
||||
|
||||
@@ -513,6 +518,7 @@ class NPAOS(Iso7816OS):
|
||||
|
||||
# sizeof(int) taken from asizof-package {{{
|
||||
_Csizeof_short = len(struct.pack('h', 0))
|
||||
# }}}
|
||||
|
||||
|
||||
VPCD_CTRL_LEN = 1
|
||||
|
||||
@@ -21,6 +21,9 @@ from virtualsmartcard.SEutils import ControlReferenceTemplate
|
||||
from virtualsmartcard.SWutils import SwError, SW
|
||||
from virtualsmartcard.ConstantDefinitions import CRT_TEMPLATE
|
||||
from virtualsmartcard.TLVutils import unpack, bertlv_pack
|
||||
from virtualsmartcard.SmartcardFilesystem import make_property
|
||||
from chat import CHAT
|
||||
import pace
|
||||
|
||||
class nPA_AT_CRT(ControlReferenceTemplate):
|
||||
def __init__(self):
|
||||
@@ -50,11 +53,139 @@ class nPA_AT_CRT(ControlReferenceTemplate):
|
||||
|
||||
return 0x9000 , ""
|
||||
|
||||
class nPA_SAM(SAM):
|
||||
"""
|
||||
SAM for ICAO ePassport. Implements Basic access control and key derivation
|
||||
for Secure Messaging.
|
||||
"""
|
||||
def __init__(self, mf):
|
||||
class nPA_SAM(SAM):
|
||||
# TODO move EAC to the securiity environment
|
||||
# TODO call __eac_abort whenever an error occurred
|
||||
|
||||
eac_step = make_property("eac_step", "next step to performed for EAC")
|
||||
|
||||
def __init__(self, pin, can, mrz, puk, mf):
|
||||
SAM.__init__(self, None, None, mf)
|
||||
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]])
|
||||
|
||||
Reference in New Issue
Block a user