diff options
author | Russ Housley <housley@vigilsec.com> | 2019-10-03 11:22:08 -0400 |
---|---|---|
committer | Ilya Etingof <etingof@gmail.com> | 2019-10-03 17:22:08 +0200 |
commit | fe4e942cddbf9b5d788fe2fa34f5a3ac6a0a46ac (patch) | |
tree | 985654322f3f575ccac58b12c163fd3c865266b0 | |
parent | 6b3ecead6ee42ce57986ac00d4e6639337aed7ba (diff) | |
download | pyasn1-modules-fe4e942cddbf9b5d788fe2fa34f5a3ac6a0a46ac.tar.gz |
Add support for RFC 8419 (#70)
-rw-r--r-- | CHANGES.txt | 2 | ||||
-rw-r--r-- | pyasn1_modules/rfc8419.py | 68 | ||||
-rw-r--r-- | tests/__main__.py | 1 | ||||
-rw-r--r-- | tests/test_rfc8419.py | 128 |
4 files changed, 199 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 3d013c4..fb53d21 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -36,6 +36,8 @@ Revision 0.2.7, released XX-09-2019 - Added RFC8494 providing Multicast Email (MULE) over ACP 142 - Added RFC8398 providing Internationalized Email Addresses in X.509 Certificates +- Added RFC8419 providing Edwards-Curve Digital Signature Algorithm + (EdDSA) Signatures in the CMS Revision 0.2.6, released 31-07-2019 ----------------------------------- diff --git a/pyasn1_modules/rfc8419.py b/pyasn1_modules/rfc8419.py new file mode 100644 index 0000000..f10994b --- /dev/null +++ b/pyasn1_modules/rfc8419.py @@ -0,0 +1,68 @@ +# This file is being contributed to pyasn1-modules software. +# +# Created by Russ Housley. +# +# Copyright (c) 2019, Vigil Security, LLC +# License: http://snmplabs.com/pyasn1/license.html +# +# Edwards-Curve Digital Signature Algorithm (EdDSA) Signatures in the CMS +# +# ASN.1 source from: +# https://www.rfc-editor.org/rfc/rfc8419.txt +# https://www.rfc-editor.org/errata/eid5869 + + +from pyasn1.type import univ + +from pyasn1_modules import rfc5280 + + +class ShakeOutputLen(univ.Integer): + pass + + +id_Ed25519 = univ.ObjectIdentifier('1.3.101.112') + +sigAlg_Ed25519 = rfc5280.AlgorithmIdentifier() +sigAlg_Ed25519['algorithm'] = id_Ed25519 +# sigAlg_Ed25519['parameters'] is absent + + +id_Ed448 = univ.ObjectIdentifier('1.3.101.113') + +sigAlg_Ed448 = rfc5280.AlgorithmIdentifier() +sigAlg_Ed448['algorithm'] = id_Ed448 +# sigAlg_Ed448['parameters'] is absent + + +hashAlgs = univ.ObjectIdentifier('2.16.840.1.101.3.4.2') + +id_sha512 = hashAlgs + (3, ) + +hashAlg_SHA_512 = rfc5280.AlgorithmIdentifier() +hashAlg_SHA_512['algorithm'] = id_sha512 +# hashAlg_SHA_512['parameters'] is absent + + +id_shake256 = hashAlgs + (12, ) + +hashAlg_SHAKE256 = rfc5280.AlgorithmIdentifier() +hashAlg_SHAKE256['algorithm'] = id_shake256 +# hashAlg_SHAKE256['parameters']is absent + + +id_shake256_len = hashAlgs + (18, ) + +hashAlg_SHAKE256_LEN = rfc5280.AlgorithmIdentifier() +hashAlg_SHAKE256_LEN['algorithm'] = id_shake256_len +hashAlg_SHAKE256_LEN['parameters'] = ShakeOutputLen() + + +# Map of Algorithm Identifier OIDs to Parameters added to the +# ones in rfc5280.py. Do not add OIDs with absent paramaters. + +_algorithmIdentifierMapUpdate = { + id_shake256_len: ShakeOutputLen(), +} + +rfc5280.algorithmIdentifierMap.update(_algorithmIdentifierMapUpdate) diff --git a/tests/__main__.py b/tests/__main__.py index c90b2e2..251aca6 100644 --- a/tests/__main__.py +++ b/tests/__main__.py @@ -65,6 +65,7 @@ suite = unittest.TestLoader().loadTestsFromNames( 'tests.test_rfc8398.suite', 'tests.test_rfc8410.suite', 'tests.test_rfc8418.suite', + 'tests.test_rfc8419.suite', 'tests.test_rfc8494.suite', 'tests.test_rfc8520.suite', 'tests.test_rfc8619.suite', diff --git a/tests/test_rfc8419.py b/tests/test_rfc8419.py new file mode 100644 index 0000000..ee566c5 --- /dev/null +++ b/tests/test_rfc8419.py @@ -0,0 +1,128 @@ +# +# 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.decoder import decode as der_decode +from pyasn1.codec.der.encoder import encode as der_encode + +from pyasn1_modules import pem +from pyasn1_modules import rfc5280 +from pyasn1_modules import rfc8419 + +try: + import unittest2 as unittest +except ImportError: + import unittest + + +class Ed25519TestCase(unittest.TestCase): + alg_id_1_pem_text = "MAUGAytlcA==" + + def setUp(self): + self.asn1Spec = rfc5280.AlgorithmIdentifier() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.alg_id_1_pem_text) + asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert asn1Object['algorithm'] == rfc8419.id_Ed25519 + assert not asn1Object['parameters'].isValue + assert der_encode(asn1Object) == substrate + + +class Ed448TestCase(unittest.TestCase): + alg_id_2_pem_text = "MAUGAytlcQ==" + + def setUp(self): + self.asn1Spec = rfc5280.AlgorithmIdentifier() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.alg_id_2_pem_text) + asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert asn1Object['algorithm'] == rfc8419.id_Ed448 + assert not asn1Object['parameters'].isValue + assert der_encode(asn1Object) == substrate + + +class SHA512TestCase(unittest.TestCase): + alg_id_3_pem_text = "MAsGCWCGSAFlAwQCAw==" + + def setUp(self): + self.asn1Spec = rfc5280.AlgorithmIdentifier() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.alg_id_3_pem_text) + asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert asn1Object['algorithm'] == rfc8419.id_sha512 + assert not asn1Object['parameters'].isValue + assert der_encode(asn1Object) == substrate + + +class SHAKE256TestCase(unittest.TestCase): + alg_id_4_pem_text = "MAsGCWCGSAFlAwQCDA==" + + def setUp(self): + self.asn1Spec = rfc5280.AlgorithmIdentifier() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.alg_id_4_pem_text) + asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert asn1Object['algorithm'] == rfc8419.id_shake256 + assert not asn1Object['parameters'].isValue + assert der_encode(asn1Object) == substrate + + +class SHAKE256LENTestCase(unittest.TestCase): + alg_id_5_pem_text = "MA8GCWCGSAFlAwQCEgICAgA=" + + def setUp(self): + self.asn1Spec = rfc5280.AlgorithmIdentifier() + + def testDerCodec(self): + substrate = pem.readBase64fromText(self.alg_id_5_pem_text) + asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec) + assert not rest + assert asn1Object.prettyPrint() + assert asn1Object['algorithm'] == rfc8419.id_shake256_len + assert asn1Object['parameters'].isValue + assert der_encode(asn1Object) == substrate + + param, rest = der_decode(asn1Object['parameters'], + asn1Spec=rfc5280.algorithmIdentifierMap[asn1Object['algorithm']]) + assert not rest + assert param.prettyPrint() + assert der_encode(param) == asn1Object['parameters'] + assert param == 512 + + def testOpenTypes(self): + substrate = pem.readBase64fromText(self.alg_id_5_pem_text) + asn1Object, rest = der_decode(substrate, + asn1Spec=self.asn1Spec, + decodeOpenTypes=True) + assert not rest + assert asn1Object.prettyPrint() + assert asn1Object['algorithm'] == rfc8419.id_shake256_len + assert asn1Object['parameters'] == 512 + assert der_encode(asn1Object) == substrate + + +suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + +if __name__ == '__main__': + import sys + + result = unittest.TextTestRunner(verbosity=2).run(suite) + sys.exit(not result.wasSuccessful()) |