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"
|
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"""
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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]])
|
||||||
|
|||||||
Reference in New Issue
Block a user