diff options
-rw-r--r-- | pyasn1_modules/rfc5084.py | 23 | ||||
-rw-r--r-- | pyasn1_modules/rfc5280.py | 2 | ||||
-rw-r--r-- | pyasn1_modules/rfc8103.py | 38 | ||||
-rw-r--r-- | pyasn1_modules/rfc8226.py | 123 | ||||
-rw-r--r-- | tests/test_rfc8103.py | 49 | ||||
-rw-r--r-- | tests/test_rfc8226.py | 54 |
6 files changed, 276 insertions, 13 deletions
diff --git a/pyasn1_modules/rfc5084.py b/pyasn1_modules/rfc5084.py index d541df7..99ce60d 100644 --- a/pyasn1_modules/rfc5084.py +++ b/pyasn1_modules/rfc5084.py @@ -1,15 +1,16 @@ -# This file is being contributed to of pyasn1-modules software. +# This file is being contributed to pyasn1-modules software. # -# Created by Russ Housley with assistance from the asn1ate tool, with -# a few comments added afterwards -# Copyright (c) 2018, Vigil Security, LLC +# Created by Russ Housley with assistance from the asn1ate tool, with manual +# changes to AES_CCM_ICVlen.subtypeSpec and added comments +# +# Copyright (c) 2018-2019, Vigil Security, LLC # License: http://snmplabs.com/pyasn1/license.html # # AES-CCM and AES-GCM Algorithms fo use with the Authenticated-Enveloped-Data # protecting content type for the Cryptographic Message Syntax (CMS) # # ASN.1 source from: -# https://www.rfc-editor.org/rfc/rfc5083.txt +# https://www.rfc-editor.org/rfc/rfc5084.txt from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful @@ -34,14 +35,14 @@ class AES_GCM_ICVlen(univ.Integer): pass -class CCMParameters(univ.Sequence): - pass +AES_CCM_ICVlen.subtypeSpec = constraint.SingleValueConstraint(4, 6, 8, 10, 12, 14, 16) -AES_CCM_ICVlen.subtypeSpec = constraint.ValueRangeConstraint(4, 16) +AES_GCM_ICVlen.subtypeSpec = constraint.ValueRangeConstraint(12, 16) -AES_GCM_ICVlen.subtypeSpec = constraint.ValueRangeConstraint(12, 16) +class CCMParameters(univ.Sequence): + pass CCMParameters.componentType = namedtype.NamedTypes( @@ -49,8 +50,6 @@ CCMParameters.componentType = namedtype.NamedTypes( # The aes-nonce parameter contains 15-L octets, where L is the size of the length field. L=8 is RECOMMENDED. # Within the scope of any content-authenticated-encryption key, the nonce value MUST be unique. namedtype.DefaultedNamedType('aes-ICVlen', AES_CCM_ICVlen().subtype(value=12)) - # The programmer must make sure that the AES_CCM_ICVlen is 4, 6, 8, 10, 12, 14, or 16. - # The contraint above will only limit it to 4..16, but will not prohibit the odd numbers. ) @@ -60,7 +59,7 @@ class GCMParameters(univ.Sequence): GCMParameters.componentType = namedtype.NamedTypes( namedtype.NamedType('aes-nonce', univ.OctetString()), - # The aes-nonce may have any number of bits between 8 and 2^64, but it must be a multiple of 8 bits. + # The aes-nonce may have any number of bits between 8 and 2^64, but it MUST be a multiple of 8 bits. # Within the scope of any content-authenticated-encryption key, the nonce value MUST be unique. # A nonce value of 12 octets can be processed more efficiently, so that length is RECOMMENDED. namedtype.DefaultedNamedType('aes-ICVlen', AES_GCM_ICVlen().subtype(value=12)) diff --git a/pyasn1_modules/rfc5280.py b/pyasn1_modules/rfc5280.py index df4b1fc..80bded5 100644 --- a/pyasn1_modules/rfc5280.py +++ b/pyasn1_modules/rfc5280.py @@ -283,7 +283,7 @@ class CertificateSerialNumber(univ.Integer): class AlgorithmIdentifier(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('algorithm', univ.ObjectIdentifier()), - namedtype.OptionalNamedType('parameters', univ.Any()) + namedtype.OptionalNamedType('parameters', univ.Any(), openType=opentype.OpenType) ) diff --git a/pyasn1_modules/rfc8103.py b/pyasn1_modules/rfc8103.py new file mode 100644 index 0000000..5e2d787 --- /dev/null +++ b/pyasn1_modules/rfc8103.py @@ -0,0 +1,38 @@ +# This file is being contributed to pyasn1-modules software. +# +# Created by Russ Housley with assistance from the asn1ate tool. +# Auto-generated by asn1ate v.0.6.0 from rfc8103.asn. +# +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# +# ChaCha20Poly1305 algorithm fo use with the Authenticated-Enveloped-Data +# protecting content type for the Cryptographic Message Syntax (CMS) +# +# ASN.1 source from: +# https://www.rfc-editor.org/rfc/rfc8103.txt + +from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful + + +def _OID(*components): + output = [] + for x in tuple(components): + if isinstance(x, univ.ObjectIdentifier): + output.extend(list(x)) + else: + output.append(int(x)) + + return univ.ObjectIdentifier(output) + + +class AEADChaCha20Poly1305Nonce(univ.OctetString): + pass + + +AEADChaCha20Poly1305Nonce.subtypeSpec = constraint.ValueSizeConstraint(12, 12) + + +id_alg_AEADChaCha20Poly1305 = _OID(1, 2, 840, 113549, 1, 9, 16, 3, 18) + + diff --git a/pyasn1_modules/rfc8226.py b/pyasn1_modules/rfc8226.py new file mode 100644 index 0000000..cd9bfd1 --- /dev/null +++ b/pyasn1_modules/rfc8226.py @@ -0,0 +1,123 @@ +# This file is being contributed to pyasn1-modules software. +# +# Created by Russ Housley with assistance from the asn1ate tool, with manual +# changes to implement appropriate constraints and added comments +# +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# +# JWT Claim Constraints and TN Authorization List for certificate extensions. +# +# ASN.1 source from: +# https://www.rfc-editor.org/rfc/rfc8226.txt (with errata corrected) + +from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful + + +MAX = float('inf') + + +def _OID(*components): + output = [] + for x in tuple(components): + if isinstance(x, univ.ObjectIdentifier): + output.extend(list(x)) + else: + output.append(int(x)) + + return univ.ObjectIdentifier(output) + + +class JWTClaimName(char.IA5String): + pass + + +class JWTClaimNames(univ.SequenceOf): + pass + + +JWTClaimNames.componentType = JWTClaimName() +JWTClaimNames.subtypeSpec=constraint.ValueSizeConstraint(1, MAX) + + +class JWTClaimPermittedValues(univ.Sequence): + pass + + +JWTClaimPermittedValues.componentType = namedtype.NamedTypes( + namedtype.NamedType('claim', JWTClaimName()), + namedtype.NamedType('permitted', univ.SequenceOf(componentType=char.UTF8String()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, MAX))) +) + + +class JWTClaimPermittedValuesList(univ.SequenceOf): + pass + + +JWTClaimPermittedValuesList.componentType = JWTClaimPermittedValues() +JWTClaimPermittedValuesList.subtypeSpec=constraint.ValueSizeConstraint(1, MAX) + + +class JWTClaimConstraints(univ.Sequence): + pass + + +JWTClaimConstraints.componentType = namedtype.NamedTypes( + namedtype.OptionalNamedType('mustInclude', JWTClaimNames().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), + namedtype.OptionalNamedType('permittedValues', JWTClaimPermittedValuesList().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))) +) + + +JWTClaimConstraints.sizeSpec = univ.Sequence.sizeSpec + constraint.ValueSizeConstraint(1, 2) + + +id_pe_JWTClaimConstraints = _OID(1, 3, 6, 1, 5, 5, 7, 1, 27) + + +class ServiceProviderCode(char.IA5String): + pass + + +class TelephoneNumber(char.IA5String): + pass + + +TelephoneNumber.subtypeSpec = constraint.ConstraintsIntersection( + constraint.ValueSizeConstraint(1, 15), + constraint.PermittedAlphabetConstraint('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '*') +) + + +class TelephoneNumberRange(univ.Sequence): + pass + + +TelephoneNumberRange.componentType = namedtype.NamedTypes( + namedtype.NamedType('start', TelephoneNumber()), + namedtype.NamedType('count', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(2, MAX))) +) + + +class TNEntry(univ.Choice): + pass + + +TNEntry.componentType = namedtype.NamedTypes( + namedtype.NamedType('spc', ServiceProviderCode().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0))), + namedtype.NamedType('range', TelephoneNumberRange().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 1))), + namedtype.NamedType('one', TelephoneNumber().subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))) +) + + +class TNAuthorizationList(univ.SequenceOf): + pass + + +TNAuthorizationList.componentType = TNEntry() +TNAuthorizationList.subtypeSpec=constraint.ValueSizeConstraint(1, MAX) + + +id_pe_TNAuthList = _OID(1, 3, 6, 1, 5, 5, 7, 1, 26) + + +id_ad_stirTNList = _OID(1, 3, 6, 1, 5, 5, 7, 48, 14) diff --git a/tests/test_rfc8103.py b/tests/test_rfc8103.py new file mode 100644 index 0000000..56a96fb --- /dev/null +++ b/tests/test_rfc8103.py @@ -0,0 +1,49 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley +# 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 rfc8103 + + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class CAEADChaCha20Poly1305TestCase(unittest.TestCase): + alg_id_pem_text = "MBsGCyqGSIb3DQEJEAMSBAzK/rq++s7brd7K+Ig=" + + def setUp(self): + self.asn1Spec = rfc5280.AlgorithmIdentifier() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.alg_id_pem_text) + asn1Object, rest = der_decoder.decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert asn1Object[0] == rfc8103.id_alg_AEADChaCha20Poly1305 + param, rest = der_decoder.decode(asn1Object[1], rfc8103.AEADChaCha20Poly1305Nonce()) + assert not rest + assert param.prettyPrint() + assert param == rfc8103.AEADChaCha20Poly1305Nonce(value='\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88') + assert der_encoder.encode(asn1Object) == substrate + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) + + diff --git a/tests/test_rfc8226.py b/tests/test_rfc8226.py new file mode 100644 index 0000000..a7dc036 --- /dev/null +++ b/tests/test_rfc8226.py @@ -0,0 +1,54 @@ +# +# This file is part of pyasn1-modules software. +# +# Created by Russ Housley +# 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 rfc8226 + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class JWTClaimConstraintsTestCase(unittest.TestCase): + jwtcc_pem_text = "MD2gBzAFFgNmb2+hMjAwMBkWA2ZvbzASDARmb28xDARmb28yDARmb28zMBMWA2JhcjAMDARiYXIxDARiYXIy" + + def setUp(self): + self.asn1Spec = rfc8226.JWTClaimConstraints() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.jwtcc_pem_text) + asn1Object, rest = der_decoder.decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert der_encoder.encode(asn1Object) == substrate + + +class TNAuthorizationListTestCase(unittest.TestCase): + tnal_pem_text = "MCugBxYFYm9ndXOhEjAQFgo1NzE1NTUxMjEyAgIDFKIMFgo3MDM1NTUxMjEy" + + def setUp(self): + self.asn1Spec = rfc8226.TNAuthorizationList() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.tnal_pem_text) + asn1Object, rest = der_decoder.decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert der_encoder.encode(asn1Object) == substrate + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + unittest.TextTestRunner(verbosity=2).run(suite) |