aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Housley <housley@vigilsec.com>2019-10-03 11:22:08 -0400
committerIlya Etingof <etingof@gmail.com>2019-10-03 17:22:08 +0200
commitfe4e942cddbf9b5d788fe2fa34f5a3ac6a0a46ac (patch)
tree985654322f3f575ccac58b12c163fd3c865266b0
parent6b3ecead6ee42ce57986ac00d4e6639337aed7ba (diff)
downloadpyasn1-modules-fe4e942cddbf9b5d788fe2fa34f5a3ac6a0a46ac.tar.gz
Add support for RFC 8419 (#70)
-rw-r--r--CHANGES.txt2
-rw-r--r--pyasn1_modules/rfc8419.py68
-rw-r--r--tests/__main__.py1
-rw-r--r--tests/test_rfc8419.py128
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())