diff options
author | Ilya Etingof <etingof@gmail.com> | 2019-05-14 22:34:49 +0200 |
---|---|---|
committer | Ilya Etingof <etingof@gmail.com> | 2019-05-14 22:34:49 +0200 |
commit | 9ced271d90e585b291af215f4ddda9cd9b676409 (patch) | |
tree | 19a8ad16d9e081cdba02fa27442758a700f35dc6 | |
parent | 9c6b27562a7cd9ffa6cb2cd0207c603c6d9f6d75 (diff) | |
download | pyasn1-modules-9ced271d90e585b291af215f4ddda9cd9b676409.tar.gz |
Add support for RFC3709
Cherry-picked from [1].
1. https://github.com/etingof/pyasn1-modules/pull/33
-rw-r--r-- | CHANGES.txt | 2 | ||||
-rw-r--r-- | pyasn1_modules/rfc3709.py | 186 | ||||
-rw-r--r-- | tests/__main__.py | 1 | ||||
-rw-r--r-- | tests/test_rfc3709.py | 71 |
4 files changed, 260 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 566776b..6858ba3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -12,6 +12,8 @@ Revision 0.2.6, released XX-04-2019 - Added RFC8520 providing X.509 Extensions for MUD URL and MUD Signer - Added RFC3161 providing Time-Stamp Protocol support +- Added RFC3709 providing X.509 extensions for IP Addresses + and AS Identifiers Revision 0.2.5, released 24-04-2019 ----------------------------------- diff --git a/pyasn1_modules/rfc3709.py b/pyasn1_modules/rfc3709.py new file mode 100644 index 0000000..78ea169 --- /dev/null +++ b/pyasn1_modules/rfc3709.py @@ -0,0 +1,186 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley with assistance from asn1ate v.0.6.0. +# +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# +# X.509 Extensions for IP Addresses and AS Identifiers +# +# ASN.1 source from: +# https://www.rfc-editor.org/rfc/rfc3779.txt +# + +from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful +from pyasn1_modules import rfc5280 + +MAX = float('inf') + + +class HashAlgAndValue(univ.Sequence): + pass + + +HashAlgAndValue.componentType = namedtype.NamedTypes( + namedtype.NamedType('hashAlg', rfc5280.AlgorithmIdentifier()), + namedtype.NamedType('hashValue', univ.OctetString()) +) + + +class LogotypeDetails(univ.Sequence): + pass + + +LogotypeDetails.componentType = namedtype.NamedTypes( + namedtype.NamedType('mediaType', char.IA5String()), + namedtype.NamedType('logotypeHash', univ.SequenceOf( + componentType=HashAlgAndValue()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))), + namedtype.NamedType('logotypeURI', univ.SequenceOf( + componentType=char.IA5String()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))) +) + + +class LogotypeAudioInfo(univ.Sequence): + pass + + +LogotypeAudioInfo.componentType = namedtype.NamedTypes( + namedtype.NamedType('fileSize', univ.Integer()), + namedtype.NamedType('playTime', univ.Integer()), + namedtype.NamedType('channels', univ.Integer()), + namedtype.OptionalNamedType('sampleRate', univ.Integer().subtype( + implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))), + namedtype.OptionalNamedType('language', char.IA5String().subtype( + implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))) +) + + +class LogotypeAudio(univ.Sequence): + pass + + +LogotypeAudio.componentType = namedtype.NamedTypes( + namedtype.NamedType('audioDetails', LogotypeDetails()), + namedtype.OptionalNamedType('audioInfo', LogotypeAudioInfo()) +) + + +class LogotypeImageType(univ.Integer): + pass + + +LogotypeImageType.namedValues = namedval.NamedValues( + ('grayScale', 0), + ('color', 1) +) + + +class LogotypeImageResolution(univ.Choice): + pass + + +LogotypeImageResolution.componentType = namedtype.NamedTypes( + namedtype.NamedType('numBits', + univ.Integer().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))), + namedtype.NamedType('tableSize', + univ.Integer().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))) +) + + +class LogotypeImageInfo(univ.Sequence): + pass + + +LogotypeImageInfo.componentType = namedtype.NamedTypes( + namedtype.DefaultedNamedType('type', LogotypeImageType().subtype( + implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0)).subtype(value='color')), + namedtype.NamedType('fileSize', univ.Integer()), + namedtype.NamedType('xSize', univ.Integer()), + namedtype.NamedType('ySize', univ.Integer()), + namedtype.OptionalNamedType('resolution', LogotypeImageResolution()), + namedtype.OptionalNamedType('language', char.IA5String().subtype( + implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))) +) + + +class LogotypeImage(univ.Sequence): + pass + + +LogotypeImage.componentType = namedtype.NamedTypes( + namedtype.NamedType('imageDetails', LogotypeDetails()), + namedtype.OptionalNamedType('imageInfo', LogotypeImageInfo()) +) + + +class LogotypeData(univ.Sequence): + pass + + +LogotypeData.componentType = namedtype.NamedTypes( + namedtype.OptionalNamedType('image', univ.SequenceOf( + componentType=LogotypeImage())), + namedtype.OptionalNamedType('audio', univ.SequenceOf( + componentType=LogotypeAudio()).subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))) +) + + +class LogotypeReference(univ.Sequence): + pass + + +LogotypeReference.componentType = namedtype.NamedTypes( + namedtype.NamedType('refStructHash', univ.SequenceOf( + componentType=HashAlgAndValue()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))), + namedtype.NamedType('refStructURI', univ.SequenceOf( + componentType=char.IA5String()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))) +) + + +class LogotypeInfo(univ.Choice): + pass + + +LogotypeInfo.componentType = namedtype.NamedTypes( + namedtype.NamedType('direct', + LogotypeData().subtype(implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))), + namedtype.NamedType('indirect', LogotypeReference().subtype( + implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))) +) + +# Other logotype type and associated object identifiers + +id_logo_background = univ.ObjectIdentifier('1.3.6.1.5.5.7.20.2') + +id_logo_loyalty = univ.ObjectIdentifier('1.3.6.1.5.5.7.20.1') + + +class OtherLogotypeInfo(univ.Sequence): + pass + + +OtherLogotypeInfo.componentType = namedtype.NamedTypes( + namedtype.NamedType('logotypeType', univ.ObjectIdentifier()), + namedtype.NamedType('info', LogotypeInfo()) +) + +# Logotype Certificate Extension + +id_pe_logotype = univ.ObjectIdentifier('1.3.6.1.5.5.7.1.12') + + +class LogotypeExtn(univ.Sequence): + pass + + +LogotypeExtn.componentType = namedtype.NamedTypes( + namedtype.OptionalNamedType('communityLogos', univ.SequenceOf( + componentType=LogotypeInfo()).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), + namedtype.OptionalNamedType('issuerLogo', LogotypeInfo().subtype( + explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))), + namedtype.OptionalNamedType('subjectLogo', LogotypeInfo().subtype( + explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 2))), + namedtype.OptionalNamedType('otherLogos', univ.SequenceOf( + componentType=OtherLogotypeInfo()).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))) +) diff --git a/tests/__main__.py b/tests/__main__.py index 85feffa..8b143fe 100644 --- a/tests/__main__.py +++ b/tests/__main__.py @@ -21,6 +21,7 @@ suite = unittest.TestLoader().loadTestsFromNames( 'tests.test_rfc3161.suite', 'tests.test_rfc3560.suite', 'tests.test_rfc3565.suite', + 'tests.test_rfc3709.suite', 'tests.test_rfc3779.suite', 'tests.test_rfc4055.suite', 'tests.test_rfc4108.suite', diff --git a/tests/test_rfc3709.py b/tests/test_rfc3709.py new file mode 100644 index 0000000..dbe1edf --- /dev/null +++ b/tests/test_rfc3709.py @@ -0,0 +1,71 @@ +# +# This file is part of pyasn1-modules software. +# +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# +import sys + +from pyasn1.codec.der import decoder as der_decoder +from pyasn1.codec.der import encoder as der_encoder + +from pyasn1_modules import pem +from pyasn1_modules import rfc5280 +from pyasn1_modules import rfc3709 + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class CertificateExtnTestCase(unittest.TestCase): + pem_text = """\ +MIIC9zCCAn2gAwIBAgIJAKWzVCgbsG46MAoGCCqGSM49BAMDMD8xCzAJBgNVBAYT +AlVTMQswCQYDVQQIDAJWQTEQMA4GA1UEBwwHSGVybmRvbjERMA8GA1UECgwIQm9n +dXMgQ0EwHhcNMTkwNTE0MTAwMjAwWhcNMjAwNTEzMTAwMjAwWjBlMQswCQYDVQQG +EwJVUzELMAkGA1UECBMCVkExEDAOBgNVBAcTB0hlcm5kb24xGzAZBgNVBAoTElZp +Z2lsIFNlY3VyaXR5IExMQzEaMBgGA1UEAxMRbWFpbC52aWdpbHNlYy5jb20wdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATwUXZUseiOaqWdrClDCMbp9YFAM87LTmFirygp +zKDU9cfqSCg7zBDIphXCwMcS9zVWDoStCbcvN0jw5CljHcffzpHYX91P88SZRJ1w +4hawHjOsWxvM3AkYgZ5nfdlL7EajggEdMIIBGTALBgNVHQ8EBAMCB4AwQgYJYIZI +AYb4QgENBDUWM1RoaXMgY2VydGlmaWNhdGUgY2Fubm90IGJlIHRydXN0ZWQgZm9y +IGFueSBwdXJwb3NlLjAdBgNVHQ4EFgQU8jXbNATapVXyvWkDmbBi7OIVCMEwHwYD +VR0jBBgwFoAU8jXbNATapVXyvWkDmbBi7OIVCMEwgYUGCCsGAQUFBwEMBHkwd6J1 +oHMwcTBvMG0WCWltYWdlL3BuZzAzMDEwDQYJYIZIAWUDBAIBBQAEIJtBNrMSSNo+ +6Rwqwctmcy0qf68ilRuKEmlf3GLwGiIkMCsWKWh0dHA6Ly93d3cudmlnaWxzZWMu +Y29tL3ZpZ2lsc2VjX2xvZ28ucG5nMAoGCCqGSM49BAMDA2gAMGUCMGhfLH4kZaCD +H43A8m8mHCUpYt9unT0qYu4TCMaRuOTYEuqj3qtuwyLcfAGuXKp/oAIxAIrPY+3y +Pj22pmfmQi5w21UljqoTj/+lQLkU3wfy5BdVKBwI0GfEA+YL3ctSzPNqAA== +""" + + def setUp(self): + self.asn1Spec = rfc5280.Certificate() + + def testDerCodec(self): + + substrate = pem.readBase64fromText(self.pem_text) + + asn1Object, rest = der_decoder.decode(substrate, asn1Spec=self.asn1Spec) + + assert not rest + assert asn1Object.prettyPrint() + assert der_encoder.encode(asn1Object) == substrate + + for extn in asn1Object['tbsCertificate']['extensions']: + + if extn['extnID'] == rfc3709.id_pe_logotype: + s = extn['extnValue'] + logotype, rest = der_decoder.decode(s, rfc3709.LogotypeExtn()) + assert not rest + assert logotype.prettyPrint() + assert der_encoder.encode(logotype) == s + assert logotype['subjectLogo']['direct']['image'][0]['imageDetails']['mediaType'] == "image/png" + assert logotype['subjectLogo']['direct']['image'][0]['imageDetails']['logotypeURI'][ + 0] == "http://www.vigilsec.com/vigilsec_logo.png" + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) |