Skip to content
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 support for RFC3779 X509 extensions for IPs and AS-IDs #245

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions asn1crypto/x509.py
Original file line number Diff line number Diff line change
Expand Up @@ -1793,6 +1793,74 @@ class AccessDescription(Sequence):
]


class IPAddressRange(Sequence):
_fields = [
("min", BitString),
("max", BitString)
]


class IPAddressOrRange(Choice):
_alternatives = [
("addressPrefix", BitString),
("addressRange", IPAddressRange)
]


class IPAddressOrRanges(SequenceOf):
_child_spec = IPAddressOrRange


class IPAddressChoice(Choice):
_alternatives = [
("inherit", Null),
("addressesOrRanges", IPAddressOrRanges)
]


class IPAddressFamily(Sequence):
_fields = [
('addressFamily', OctetString),
('ipAddressChoice', IPAddressChoice)
]


class IPAddrBlocks(SequenceOf):
_child_spec = IPAddressFamily


class ASRange(Sequence):
_fields = [
("min", Integer),
("max", Integer)
]


class ASIdOrRange(Choice):
_alternatives = [
("id", Integer),
("range", ASRange)
]


class ASIdOrRanges(SequenceOf):
_child_spec = ASIdOrRange


class ASIdentifierChoice(Choice):
_alternatives = [
("inherit", Null),
("asIdsOrRanges", ASIdOrRanges)
]


class ASIdentifiers(Sequence):
_fields = [
('asnum', ASIdentifierChoice, {'optional': True, 'explicit': 0}),
('rdi', ASIdentifierChoice, {'optional': True, 'explicit': 1})
]


class AuthorityInfoAccessSyntax(SequenceOf):
_child_spec = AccessDescription

Expand Down Expand Up @@ -2081,6 +2149,9 @@ class ExtensionId(ObjectIdentifier):
'1.3.6.1.4.1.11129.2.4.2': 'signed_certificate_timestamp_list',
# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/3aec3e50-511a-42f9-a5d5-240af503e470
'1.3.6.1.4.1.311.20.2': 'microsoft_enroll_certtype',
# https://tools.ietf.org/html/rfc3779
'1.3.6.1.5.5.7.1.7': 'ipAddrBlocks',
'1.3.6.1.5.5.7.1.8': 'autonomousSysIds',
}


Expand Down Expand Up @@ -2119,6 +2190,8 @@ class Extension(Sequence):
# Not UTF8String as Microsofts docs claim, see:
# https://www.alvestrand.no/objectid/1.3.6.1.4.1.311.20.2.html
'microsoft_enroll_certtype': BMPString,
'ipAddrBlocks': IPAddrBlocks,
"autonomousSysIds": ASIdentifiers,
}


Expand Down Expand Up @@ -2165,6 +2238,8 @@ class Certificate(Sequence):
_freshest_crl_value = None
_inhibit_any_policy_value = None
_extended_key_usage_value = None
_ip_addr_blocks_value = None
_autonomous_sys_ids_value = None
_authority_information_access_value = None
_subject_information_access_value = None
_private_key_usage_period_value = None
Expand Down Expand Up @@ -2457,6 +2532,32 @@ def authority_information_access_value(self):
self._set_extensions()
return self._authority_information_access_value

@property
def ip_addr_blocks_value(self):
"""
This extension is used to provide information about IP resources

:return:
None or a IPAddrBlocks object
"""

if not self._processed_extensions:
self._set_extensions()
return self._ip_addr_blocks_value

@property
def autonomous_sys_ids_value(self):
"""
This extension is used to provide information about IP resources

:return:
None or a IPAddrBlocks object
"""

if not self._processed_extensions:
self._set_extensions()
return self._autonomous_sys_ids_value

@property
def subject_information_access_value(self):
"""
Expand Down
Binary file added tests/fixtures/cms-as-ip-ext.der
Binary file not shown.
15 changes: 15 additions & 0 deletions tests/test_cms.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,21 @@ def test_parse_content_info_enveloped_data(self):
enveloped_data['unprotected_attrs'].native
)

def test_parse_ip_as_extension(self):
with open(os.path.join(fixtures_dir, 'cms-as-ip-ext.der'), 'rb') as f:
info = cms.ContentInfo.load(f.read())
extensions = info.native["content"]["certificates"][0]["tbs_certificate"]["extensions"]
aut_id = False
ip_add_blocks = False
for ext in extensions:
if ext["extn_id"] == "autonomousSysIds":
aut_id = True
elif ext["extn_id"] == "ipAddrBlocks":
ip_add_blocks = True

self.assertTrue(aut_id, "autonomousSysIds extension was not parsed correctly")
self.assertTrue(ip_add_blocks, "IPAddrBlocks extension was not parsed correctly")

def test_parse_content_info_cms_signed_data(self):
with open(os.path.join(fixtures_dir, 'cms-signed.der'), 'rb') as f:
info = cms.ContentInfo.load(f.read())
Expand Down