-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add dg2, dg7 and dg11 #3
base: master
Are you sure you want to change the base?
Changes from 5 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,28 @@ | ||
from .base import ( | ||
ElementaryFile, | ||
ElementaryFileError, | ||
LDSVersionInfo | ||
) | ||
from .base import ElementaryFile, ElementaryFileError, LDSVersionInfo | ||
|
||
from .dg import ( | ||
DataGroup, | ||
DataGroupNumber, | ||
DG1, | ||
DG14, | ||
DG15 | ||
) | ||
from .dg import DataGroup, DataGroupNumber, DG1, DG2, DG14, DG15 | ||
|
||
from .mrz import ( | ||
MachineReadableZone | ||
) | ||
from .mrz import MachineReadableZone | ||
|
||
from .sod import ( | ||
SOD, | ||
SODError | ||
) | ||
from .dg2 import DataGroup2 | ||
|
||
from .sod import SOD, SODError | ||
|
||
from .errors import NFCPassportReaderError | ||
|
||
__all__ = [ | ||
"DataGroup", | ||
"DataGroupNumber", | ||
"DG1", | ||
"DG2", | ||
"DG14", | ||
"DG15", | ||
"ElementaryFile", | ||
"ElementaryFileError", | ||
"LDSVersionInfo", | ||
"MachineReadableZone", | ||
"DataGroup2", | ||
"SOD", | ||
"SODError" | ||
] | ||
"SODError", | ||
"NFCPassportReaderError", | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,96 +2,98 @@ | |
from asn1crypto.util import int_from_bytes | ||
from asn1crypto.keys import PublicKeyInfo | ||
from pymrtd.pki import keys, oids | ||
from typing import Union #pylint: disable=wrong-import-order | ||
from typing import Union # pylint: disable=wrong-import-order | ||
|
||
from .base import ElementaryFile | ||
from .mrz import MachineReadableZone | ||
from .dg2 import DataGroup2 | ||
|
||
|
||
class ActiveAuthenticationInfoId(asn1.ObjectIdentifier): | ||
_map = { | ||
oids.id_icao_mrtd_security_aaProtocolObject: 'aa_info', | ||
oids.id_icao_mrtd_security_aaProtocolObject: "aa_info", | ||
} | ||
|
||
|
||
class ActiveAuthenticationInfo(asn1.Sequence): | ||
_fields = [ | ||
('protocol', ActiveAuthenticationInfoId), | ||
('version', asn1.Integer), | ||
('signature_algorithm', keys.SignatureAlgorithmId) | ||
("protocol", ActiveAuthenticationInfoId), | ||
("version", asn1.Integer), | ||
("signature_algorithm", keys.SignatureAlgorithmId), | ||
] | ||
|
||
|
||
class ChipAuthenticationInfoId(asn1.ObjectIdentifier): | ||
_map = { | ||
oids.id_CA_DH_3DES_CBC_CBC : 'ca_dh_3des_cbc_cbc', | ||
oids.id_CA_DH_AES_CBC_CMAC_128 : 'ca_dh_aes_cbc_cmac_128', | ||
oids.id_CA_DH_AES_CBC_CMAC_192 : 'ca_dh_aes_cbc_cmac_192', | ||
oids.id_CA_DH_AES_CBC_CMAC_256 : 'ca_dh_aes_cbc_cmac_256', | ||
oids.id_CA_ECDH_3DES_CBC_CBC : 'ca_ecdh_3des_cbc_cbc', | ||
oids.id_CA_ECDH_AES_CBC_CMAC_128 : 'ca_ecdh_aes_cbc_cmac_128', | ||
oids.id_CA_ECDH_AES_CBC_CMAC_192 : 'ca_ecdh_aes_cbc_cmac_192', | ||
oids.id_CA_ECDH_AES_CBC_CMAC_256 : 'ca_ecdh_aes_cbc_cmac_256' | ||
oids.id_CA_DH_3DES_CBC_CBC: "ca_dh_3des_cbc_cbc", | ||
oids.id_CA_DH_AES_CBC_CMAC_128: "ca_dh_aes_cbc_cmac_128", | ||
oids.id_CA_DH_AES_CBC_CMAC_192: "ca_dh_aes_cbc_cmac_192", | ||
oids.id_CA_DH_AES_CBC_CMAC_256: "ca_dh_aes_cbc_cmac_256", | ||
oids.id_CA_ECDH_3DES_CBC_CBC: "ca_ecdh_3des_cbc_cbc", | ||
oids.id_CA_ECDH_AES_CBC_CMAC_128: "ca_ecdh_aes_cbc_cmac_128", | ||
oids.id_CA_ECDH_AES_CBC_CMAC_192: "ca_ecdh_aes_cbc_cmac_192", | ||
oids.id_CA_ECDH_AES_CBC_CMAC_256: "ca_ecdh_aes_cbc_cmac_256", | ||
} | ||
|
||
|
||
class ChipAuthenticationInfo(asn1.Sequence): | ||
_fields = [ | ||
('protocol', ChipAuthenticationInfoId), | ||
('version', asn1.Integer), | ||
('key_id', asn1.Integer, {'optional': True}) | ||
("protocol", ChipAuthenticationInfoId), | ||
("version", asn1.Integer), | ||
("key_id", asn1.Integer, {"optional": True}), | ||
] | ||
|
||
|
||
class ChipAuthenticationPublicKeyInfoId(asn1.ObjectIdentifier): | ||
_map = { | ||
oids.id_PK_DH : 'pk_dh', | ||
oids.id_PK_ECDH : 'pk_ecdh' | ||
} | ||
_map = {oids.id_PK_DH: "pk_dh", oids.id_PK_ECDH: "pk_ecdh"} | ||
|
||
|
||
class ChipAuthenticationPublicKeyInfo(asn1.Sequence): | ||
_fields = [ | ||
('protocol', ChipAuthenticationPublicKeyInfoId), | ||
('chip_auth_public_key', PublicKeyInfo), | ||
('key_id', asn1.Integer, {'optional': True}) | ||
("protocol", ChipAuthenticationPublicKeyInfoId), | ||
("chip_auth_public_key", PublicKeyInfo), | ||
("key_id", asn1.Integer, {"optional": True}), | ||
] | ||
|
||
|
||
class DefaultSecurityInfo(asn1.Sequence): | ||
_fields = [ | ||
('protocol', asn1.ObjectIdentifier), | ||
('required_data', asn1.Any), | ||
('optional', asn1.Any, {'optional': True}) | ||
("protocol", asn1.ObjectIdentifier), | ||
("required_data", asn1.Any), | ||
("optional", asn1.Any, {"optional": True}), | ||
] | ||
|
||
|
||
class SecurityInfo(asn1.Choice): | ||
_alternatives = [ | ||
('security_info', DefaultSecurityInfo), | ||
('aa_info', ActiveAuthenticationInfo), | ||
('chip_auth_info', ChipAuthenticationInfo), | ||
('chip_auth_pub_key_info', ChipAuthenticationPublicKeyInfo) | ||
#Note: Missing PACEDomainParameterInfo and PACEInfo | ||
("security_info", DefaultSecurityInfo), | ||
("aa_info", ActiveAuthenticationInfo), | ||
("chip_auth_info", ChipAuthenticationInfo), | ||
("chip_auth_pub_key_info", ChipAuthenticationPublicKeyInfo), | ||
# Note: Missing PACEDomainParameterInfo and PACEInfo | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use single quote mark. |
||
] | ||
|
||
def validate(self, class_, tag, contents): | ||
""" this function select proper SecurityInfo choice index based on OID """ | ||
"""this function select proper SecurityInfo choice index based on OID""" | ||
oid = asn1.ObjectIdentifier.load(contents).dotted | ||
|
||
self._choice = 0 | ||
for index, info in enumerate(self._alternatives): | ||
toidm = info[1]._fields[0][1]._map #pylint: disable=protected-access | ||
toidm = info[1]._fields[0][1]._map # pylint: disable=protected-access | ||
if toidm is not None and oid in toidm: | ||
self._choice = index | ||
return | ||
|
||
def parse(self): | ||
if self._parsed is None: | ||
super().parse() | ||
if self.name == 'aa_info' or self.name == 'chip_auth_info': | ||
if self._parsed['version'].native != 1: | ||
from asn1crypto._types import type_name #pylint: disable=import-outside-toplevel | ||
raise ValueError(f'{type_name(self._parsed)} version != 1') | ||
if self.name == "aa_info" or self.name == "chip_auth_info": | ||
if self._parsed["version"].native != 1: | ||
from asn1crypto._types import ( | ||
type_name, | ||
) # pylint: disable=import-outside-toplevel | ||
|
||
raise ValueError(f"{type_name(self._parsed)} version != 1") | ||
return self._parsed | ||
|
||
|
||
|
@@ -100,26 +102,26 @@ class SecurityInfos(asn1.SetOf): | |
|
||
|
||
class DataGroupNumber(asn1.Integer): | ||
min = 1 # DG min value | ||
max = 16 # DG max value | ||
min = 1 # DG min value | ||
max = 16 # DG max value | ||
|
||
_map = { | ||
1: 'EF.DG1', | ||
2: 'EF.DG2', | ||
3: 'EF.DG3', | ||
4: 'EF.DG4', | ||
5: 'EF.DG5', | ||
6: 'EF.DG6', | ||
7: 'EF.DG7', | ||
8: 'EF.DG8', | ||
9: 'EF.DG9', | ||
10: 'EF.DG10', | ||
11: 'EF.DG11', | ||
12: 'EF.DG12', | ||
13: 'EF.DG13', | ||
14: 'EF.DG14', | ||
15: 'EF.DG15', | ||
16: 'EF.DG16' | ||
1: "EF.DG1", | ||
2: "EF.DG2", | ||
3: "EF.DG3", | ||
4: "EF.DG4", | ||
5: "EF.DG5", | ||
6: "EF.DG6", | ||
7: "EF.DG7", | ||
8: "EF.DG8", | ||
9: "EF.DG9", | ||
10: "EF.DG10", | ||
11: "EF.DG11", | ||
12: "EF.DG12", | ||
13: "EF.DG13", | ||
14: "EF.DG14", | ||
15: "EF.DG15", | ||
16: "EF.DG16", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use single quote mark. |
||
} | ||
|
||
@property | ||
|
@@ -138,12 +140,12 @@ def __ne__(self, other) -> bool: | |
|
||
def set(self, value): | ||
if isinstance(value, int): | ||
if value == 21: # DG2 tag | ||
if value == 21: # DG2 tag | ||
value = 2 | ||
elif value == 22: # DG4 tag | ||
elif value == 22: # DG4 tag | ||
value = 4 | ||
elif value not in DataGroupNumber._map: | ||
raise ValueError('Invalid data group number') | ||
raise ValueError("Invalid data group number") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use single quote mark. |
||
super().set(value) | ||
|
||
def __hash__(self) -> int: | ||
|
@@ -159,8 +161,9 @@ def __str__(self): | |
Returns string representation of self i.e. EF.DG<No>(fp=XXXXXXXXXXXXXXXX) | ||
""" | ||
if self._str_rep is None: | ||
self._str_rep = super().__str__()\ | ||
.replace("EF(", f'{self.number.native}(', 1) | ||
self._str_rep = ( | ||
super().__str__().replace("EF(", f"{self.number.native}(", 1) | ||
) | ||
return self._str_rep | ||
|
||
@property | ||
|
@@ -178,7 +181,20 @@ def mrz(self) -> MachineReadableZone: | |
|
||
@property | ||
def native(self): | ||
return { 'mrz': self.mrz.native } | ||
return {"mrz": self.mrz.native} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use single quote mark. |
||
|
||
|
||
class DG2(DataGroup): | ||
tag = 21 | ||
_content_spec = DataGroup2 | ||
|
||
@property | ||
def portrait(self) -> DataGroup2: | ||
return self.content | ||
|
||
@property | ||
def native(self): | ||
return {"portrait": self.portrait} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit, use single quote mark. |
||
|
||
|
||
class DG14(DataGroup): | ||
|
@@ -187,7 +203,7 @@ class DG14(DataGroup): | |
|
||
@property | ||
def aaInfo(self) -> Union[ActiveAuthenticationInfo, None]: | ||
''' Returns ActiveAuthenticationInfo if in list otherwise None. ''' | ||
"""Returns ActiveAuthenticationInfo if in list otherwise None.""" | ||
|
||
# Loop over list of SecurityInfo objects and try to find ActiveAuthentication object | ||
# Should contain only one ActiveAuthenticationInfo | ||
|
@@ -198,14 +214,14 @@ def aaInfo(self) -> Union[ActiveAuthenticationInfo, None]: | |
|
||
@property | ||
def aaSignatureAlgo(self) -> keys.SignatureAlgorithm: | ||
''' Returns SignatureAlgorithm object or None if DG doesn't contain one. ''' | ||
"""Returns SignatureAlgorithm object or None if DG doesn't contain one.""" | ||
|
||
aai = self.aaInfo | ||
if aai is None: | ||
return None | ||
|
||
# Get signature algorithm | ||
return keys.SignatureAlgorithm({ 'algorithm' : aai.native['signature_algorithm'] }) | ||
return keys.SignatureAlgorithm({"algorithm": aai.native["signature_algorithm"]}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use single quote mark. |
||
|
||
|
||
class DG15(DataGroup): | ||
|
@@ -215,12 +231,12 @@ class DG15(DataGroup): | |
|
||
@property | ||
def aaPublicKeyInfo(self) -> PublicKeyInfo: | ||
''' Returns active authentication public key info ''' | ||
"""Returns active authentication public key info""" | ||
return self.content | ||
|
||
@property | ||
def aaPublicKey(self) -> keys.AAPublicKey: | ||
''' Returns active authentication public key ''' | ||
if not hasattr(self, '_aakey'): | ||
"""Returns active authentication public key""" | ||
if not hasattr(self, "_aakey"): | ||
self._aakey = keys.AAPublicKey.load(self.aaPublicKeyInfo.dump()) | ||
return self._aakey |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you revert include style back to original.