Verify implemented for Age, DocumentValidity and PlaceVerification checks
In case of AgeVerification , DocumentValidity and PlaceVerification checks, the return code is not longer hard coded. Based on given reference values a check is does against given DG3, DG8 and DG18 values Still ToDo is incomplete DG8 BirthDate in Format YYYY-XX where the day is missing
This commit is contained in:
@@ -20,12 +20,13 @@ from virtualsmartcard.SmartcardSAM import SAM
|
||||
from virtualsmartcard.SEutils import ControlReferenceTemplate, Security_Environment
|
||||
from virtualsmartcard.SWutils import SwError, SW
|
||||
from virtualsmartcard.ConstantDefinitions import CRT_TEMPLATE, SM_Class, ALGO_MAPPING
|
||||
from virtualsmartcard.TLVutils import unpack, bertlv_pack
|
||||
from virtualsmartcard.TLVutils import unpack, bertlv_pack, decodeDiscretionaryDataObjects, tlv_find_tag
|
||||
from virtualsmartcard.SmartcardFilesystem import make_property
|
||||
from virtualsmartcard.utils import inttostring
|
||||
import virtualsmartcard.CryptoUtils as vsCrypto
|
||||
from chat import CHAT, CVC, PACE_SEC, EAC_CTX
|
||||
import eac
|
||||
import logging, binascii
|
||||
|
||||
class nPA_AT_CRT(ControlReferenceTemplate):
|
||||
|
||||
@@ -33,6 +34,9 @@ class nPA_AT_CRT(ControlReferenceTemplate):
|
||||
PACE_CAN = 0x02
|
||||
PACE_PIN = 0x03
|
||||
PACE_PUK = 0x04
|
||||
DateOfBirth = None
|
||||
DateOfExpiry = None
|
||||
CommunityID = None
|
||||
|
||||
def __init__(self):
|
||||
ControlReferenceTemplate.__init__(self, CRT_TEMPLATE["AT"])
|
||||
@@ -71,6 +75,29 @@ class nPA_AT_CRT(ControlReferenceTemplate):
|
||||
print(self.chat)
|
||||
elif tag == 0x67:
|
||||
self.auxiliary_data = bertlv_pack([[tag, length, value]])
|
||||
# extract reference values for DocumentValiditaCheck, AgeVerificatiobCheck and PlaceVerificationCheck
|
||||
# first we have up to three objects, one for each reference value
|
||||
for subtlv in value:
|
||||
subtag, sublength, subvalue = subtlv
|
||||
# extract oid value which is given within TagID = 6
|
||||
oidtlv = tlv_find_tag(subvalue, 6)
|
||||
for oiddetails in oidtlv:
|
||||
oidtag, oidlength, oidvalue = oiddetails
|
||||
# extract finally the reference value which is given within TagID = 83
|
||||
valtlv = tlv_find_tag(subvalue, 83)
|
||||
val = decodeDiscretionaryDataObjects(valtlv)
|
||||
if ALGO_MAPPING[oidvalue] == "DateOfBirth":
|
||||
logging.info("ALGO_MAPPING[oid] == DateOfBirth matched")
|
||||
nPA_AT_CRT.DateOfBirth = int(val[0])
|
||||
logging.info("extracted value for reference DateOfBirth: " + str(nPA_AT_CRT.DateOfBirth))
|
||||
elif ALGO_MAPPING[oidvalue] == "DateOfExpiry":
|
||||
logging.info("ALGO_MAPPING[oid] == DateOfExpiry matched")
|
||||
nPA_AT_CRT.DateOfExpiry = int(val[0])
|
||||
logging.info("extracted value for reference DateOfExpiry: " + str(nPA_AT_CRT.DateOfExpiry))
|
||||
elif ALGO_MAPPING[oidvalue] == "CommunityID":
|
||||
logging.info("ALGO_MAPPING[oid] == CommunityID matched")
|
||||
nPA_AT_CRT.CommunityID = binascii.hexlify(val[0])
|
||||
logging.info("extracted value for reference CommunityID: " + str(nPA_AT_CRT.CommunityID))
|
||||
elif tag == 0x80 or tag == 0x84 or tag == 0x83 or tag == 0x91:
|
||||
# handled by ControlReferenceTemplate.parse_SE_config
|
||||
pass
|
||||
@@ -133,7 +160,7 @@ class nPA_SE(Security_Environment):
|
||||
elif self.eac_step == 5 and self.at.algorithm == "CA":
|
||||
return self.__eac_ca(data)
|
||||
elif self.eac_step == 6:
|
||||
# TODO implement RI
|
||||
# TODO implement RI "\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"])
|
||||
@@ -539,17 +566,88 @@ class nPA_SAM(SAM):
|
||||
structure = unpack(data)
|
||||
for tag, length, value in structure:
|
||||
if tag == 6 and ALGO_MAPPING[value] == "DateOfExpiry":
|
||||
# hell yes, this is a valid nPA
|
||||
# TODO actually check it...
|
||||
return SW["NORMAL"], ""
|
||||
logging.info("Doing verify command for DocumentValidityCheck with reference value: " + str(nPA_AT_CRT.DateOfExpiry))
|
||||
# extract DateOfExpiry DG3 value
|
||||
dg3 = self.mf.select('filedescriptor' , 0x38).select('fid', 0x0103).data
|
||||
dg_structure = unpack(dg3)
|
||||
# dg_structure is a TLV object with a sub TLV in value part
|
||||
for data in dg_structure:
|
||||
datatag, datalength, datavalue = data
|
||||
# datavalue contains now the datagroup value
|
||||
dg_entry = tlv_find_tag(datavalue, 18)
|
||||
for detail in dg_entry:
|
||||
dgtag, dglength, dgvalue = detail
|
||||
logging.info("dg3 DateOfExpiry value: " + str(dgvalue))
|
||||
dg3_DateOfExpiry = int(dgvalue)
|
||||
# Verification result OK ==SW["NORMAL"] / Failed = SW["WARN_NOINFO63"]
|
||||
logging.info("is reference DateOfExpiry < dg3_DateOfExpiry ?")
|
||||
logging.info("is " + str(nPA_AT_CRT.DateOfExpiry) + " < " + str(dg3_DateOfExpiry) + " ?")
|
||||
if nPA_AT_CRT.DateOfExpiry < dg3_DateOfExpiry:
|
||||
logging.info("Verify result: OK")
|
||||
return SW["NORMAL"], ""
|
||||
else:
|
||||
logging.info("Verify result: Failed")
|
||||
return SW["WARN_NOINFO63"], ""
|
||||
|
||||
if tag == 6 and ALGO_MAPPING[value] == "DateOfBirth":
|
||||
# hell yes, we are old enough
|
||||
# TODO actually check it...
|
||||
return SW["NORMAL"], ""
|
||||
logging.info("Doing verify command for AgeVerificationCheck with reference value: " + str(nPA_AT_CRT.DateOfBirth))
|
||||
# extract DateOfBirth DG8 value
|
||||
dg8 = self.mf.select('filedescriptor' , 0x38).select('fid', 0x0108).data
|
||||
dg_structure = unpack(dg8)
|
||||
# dg_structure is a TLV object with a sub TLV in value part
|
||||
for data in dg_structure:
|
||||
datatag, datalength, datavalue = data
|
||||
# datavalue contains now the datagroup value
|
||||
dg_entry = tlv_find_tag(datavalue, 18)
|
||||
for detail in dg_entry:
|
||||
dgtag, dglength, dgvalue = detail
|
||||
logging.info("dg8 DateOfBirth value: " + str(dgvalue))
|
||||
dg8_DateOfBirth = int(dgvalue)
|
||||
# !!! TODO FixMe validation against incomplete birth date in dg8_DateOfBirth where "XX" is a missing part !!!
|
||||
# case1: YYYY-MM-DD (normal)
|
||||
# case2: YYYY-MM-XX --> will be mapped to last day of the given month
|
||||
# case3: YYYY-XX-XX --> will be mapped to YYYY-12-31
|
||||
# Verification result OK ==SW["NORMAL"] / Failed = SW["WARN_NOINFO63"]
|
||||
if len(str(dg8_DateOfBirth))==6:
|
||||
logging.info("Verify result: Failed because of missing implementation for validation against incomplete birth date")
|
||||
return SW["WARN_NOINFO63"], ""
|
||||
elif len(str(dg8_DateOfBirth))==4:
|
||||
logging.info("Incomplete birth date with 'year' found only. Will map it to 'YYYY-12-31'")
|
||||
dg8_DateOfBirth = int(str(dg8_DateOfBirth) + "1231")
|
||||
|
||||
logging.info("is reference DateOfBirth > dg8_DateOfBirth ?")
|
||||
logging.info("is " + str(nPA_AT_CRT.DateOfBirth) + " > " + str(dg8_DateOfBirth) + " ?")
|
||||
if nPA_AT_CRT.DateOfBirth > dg8_DateOfBirth:
|
||||
logging.info("Verify result: OK")
|
||||
return SW["NORMAL"], ""
|
||||
else:
|
||||
logging.info("Verify result: Failed")
|
||||
return SW["WARN_NOINFO63"], ""
|
||||
|
||||
if tag == 6 and ALGO_MAPPING[value] == "CommunityID":
|
||||
# well OK, we are living there
|
||||
# TODO actually check it...
|
||||
return SW["NORMAL"], ""
|
||||
logging.info("Doing verify command for PlaceVerificationCheck with reference value: " + str(nPA_AT_CRT.CommunityID))
|
||||
# extract CommunityID DG18 value
|
||||
dg18 = self.mf.select('filedescriptor' , 0x38).select('fid', 0x0112).data
|
||||
dg_structure = unpack(dg18)
|
||||
# dg_structure is a TLV object with a sub TLV in value part
|
||||
for data in dg_structure:
|
||||
datatag, datalength, datavalue = data
|
||||
# datavalue contains now the datagroup value
|
||||
dg_entry = tlv_find_tag(datavalue, 4)
|
||||
for detail in dg_entry:
|
||||
dgtag, dglength, dgvalue = detail
|
||||
dg18_CommunityID = binascii.hexlify(dgvalue)
|
||||
logging.info("dg18 CommunityID value: " + str(dg18_CommunityID))
|
||||
# Verification result OK ==SW["NORMAL"] / Failed = SW["WARN_NOINFO63"]
|
||||
logging.info("does dg18_CommunityID starts with reference CommunityID ?")
|
||||
logging.info("does '" + str(dg18_CommunityID) + "' starts with '" + str(nPA_AT_CRT.CommunityID) + "' ?")
|
||||
if dg18_CommunityID.startswith(nPA_AT_CRT.CommunityID):
|
||||
logging.info("Verify result: OK")
|
||||
return SW["NORMAL"], ""
|
||||
else:
|
||||
logging.info("Verify result: Failed")
|
||||
return SW["WARN_NOINFO63"], ""
|
||||
|
||||
else:
|
||||
return SAM.verify(self, p1, p2, data)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user