aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Housley <housley@vigilsec.com>2019-10-25 16:32:21 -0400
committerIlya Etingof <etingof@gmail.com>2019-10-25 22:32:21 +0200
commita8c0d3aa252e275af4ebd20217a5ee9704fce0e2 (patch)
treeb5f5c7ce47acaca20fec64ca8746c4f13186bb35
parent13343c7a40a06f20bdf59bbc1ff2b83f6a26db97 (diff)
downloadpyasn1-modules-a8c0d3aa252e275af4ebd20217a5ee9704fce0e2.tar.gz
Add support for RFC 6187, RFC 6482, and RFC 6664 (#94)
-rw-r--r--CHANGES.txt3
-rw-r--r--pyasn1_modules/rfc6187.py22
-rw-r--r--pyasn1_modules/rfc6482.py74
-rw-r--r--pyasn1_modules/rfc6664.py147
-rw-r--r--tests/__main__.py3
-rw-r--r--tests/test_rfc6187.py73
-rw-r--r--tests/test_rfc6482.py119
-rw-r--r--tests/test_rfc6664.py109
8 files changed, 550 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 1bc631f..633bfb1 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -14,6 +14,9 @@ Revision 0.2.8, released XX-XX-2019
- Added RFC6487 providing Profile for X.509 PKIX Resource Certificates
- Added RFC6170 providing Certificate Image in the Internet X.509 Public
Key Infrastructure, and import the object identifier into RFC3709.
+- Added RFC6187 providing Certificates for Secure Shell Authentication
+- Added RFC6482 providing RPKI Route Origin Authorizations (ROAs)
+- Added RFC6664 providing S/MIME Capabilities for Public Keys
Revision 0.2.7, released 09-10-2019
-----------------------------------
diff --git a/pyasn1_modules/rfc6187.py b/pyasn1_modules/rfc6187.py
new file mode 100644
index 0000000..4be0054
--- /dev/null
+++ b/pyasn1_modules/rfc6187.py
@@ -0,0 +1,22 @@
+#
+# 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
+#
+# X.509v3 Certificates for Secure Shell Authentication
+#
+# ASN.1 source from:
+# https://www.rfc-editor.org/rfc/rfc6187.txt
+#
+
+from pyasn1.type import univ
+
+id_pkix = univ.ObjectIdentifier('1.3.6.1.5.5.7')
+
+id_kp = id_pkix + (3, )
+
+id_kp_secureShellClient = id_kp + (21, )
+id_kp_secureShellServer = id_kp + (22, )
diff --git a/pyasn1_modules/rfc6482.py b/pyasn1_modules/rfc6482.py
new file mode 100644
index 0000000..d213a46
--- /dev/null
+++ b/pyasn1_modules/rfc6482.py
@@ -0,0 +1,74 @@
+#
+# 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
+#
+# RPKI Route Origin Authorizations (ROAs)
+#
+# ASN.1 source from:
+# https://www.rfc-editor.org/rfc/rfc6482.txt
+# https://www.rfc-editor.org/errata/eid5881
+#
+
+from pyasn1.type import constraint
+from pyasn1.type import namedtype
+from pyasn1.type import tag
+from pyasn1.type import univ
+
+from pyasn1_modules import rfc5652
+
+MAX = float('inf')
+
+
+id_ct_routeOriginAuthz = univ.ObjectIdentifier('1.2.840.113549.1.9.16.1.24')
+
+
+class ASID(univ.Integer):
+ pass
+
+
+class IPAddress(univ.BitString):
+ pass
+
+
+class ROAIPAddress(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('address', IPAddress()),
+ namedtype.OptionalNamedType('maxLength', univ.Integer())
+ )
+
+
+class ROAIPAddressFamily(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('addressFamily',
+ univ.OctetString().subtype(
+ subtypeSpec=constraint.ValueSizeConstraint(2, 3))),
+ namedtype.NamedType('addresses',
+ univ.SequenceOf(componentType=ROAIPAddress()).subtype(
+ subtypeSpec=constraint.ValueSizeConstraint(1, MAX)))
+ )
+
+
+class RouteOriginAttestation(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.DefaultedNamedType('version',
+ univ.Integer().subtype(explicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 0)).subtype(value=0)),
+ namedtype.NamedType('asID', ASID()),
+ namedtype.NamedType('ipAddrBlocks',
+ univ.SequenceOf(componentType=ROAIPAddressFamily()).subtype(
+ subtypeSpec=constraint.ValueSizeConstraint(1, MAX)))
+ )
+
+
+# Map of Content Type OIDs to Content Types added to the
+# ones that are in rfc5652.py
+
+_cmsContentTypesMapUpdate = {
+ id_ct_routeOriginAuthz: RouteOriginAttestation(),
+}
+
+rfc5652.cmsContentTypesMap.update(_cmsContentTypesMapUpdate)
diff --git a/pyasn1_modules/rfc6664.py b/pyasn1_modules/rfc6664.py
new file mode 100644
index 0000000..41629d8
--- /dev/null
+++ b/pyasn1_modules/rfc6664.py
@@ -0,0 +1,147 @@
+#
+# This file is part of pyasn1-modules software.
+#
+# Created by Russ Housley with some assistance from asn1ate v.0.6.0.
+#
+# Copyright (c) 2019, Vigil Security, LLC
+# License: http://snmplabs.com/pyasn1/license.html
+#
+# S/MIME Capabilities for Public Key Definitions
+#
+# ASN.1 source from:
+# https://www.rfc-editor.org/rfc/rfc6664.txt
+#
+
+from pyasn1.type import constraint
+from pyasn1.type import namedtype
+from pyasn1.type import tag
+from pyasn1.type import univ
+
+from pyasn1_modules import rfc5280
+from pyasn1_modules import rfc5751
+from pyasn1_modules import rfc5480
+from pyasn1_modules import rfc4055
+from pyasn1_modules import rfc3279
+
+MAX = float('inf')
+
+
+# Imports from RFC 5280
+
+AlgorithmIdentifier = rfc5280.AlgorithmIdentifier
+
+
+# Imports from RFC 3279
+
+dhpublicnumber = rfc3279.dhpublicnumber
+
+Dss_Parms = rfc3279.Dss_Parms
+
+id_dsa = rfc3279.id_dsa
+
+id_ecPublicKey = rfc3279.id_ecPublicKey
+
+rsaEncryption = rfc3279.rsaEncryption
+
+
+# Imports from RFC 4055
+
+id_mgf1 = rfc4055.id_mgf1
+
+id_RSAES_OAEP = rfc4055.id_RSAES_OAEP
+
+id_RSASSA_PSS = rfc4055.id_RSASSA_PSS
+
+
+# Imports from RFC 5480
+
+ECParameters = rfc5480.ECParameters
+
+id_ecDH = rfc5480.id_ecDH
+
+id_ecMQV = rfc5480.id_ecMQV
+
+
+# RSA
+
+class RSAKeySize(univ.Integer):
+ # suggested values are 1024, 2048, 3072, 4096, 7680, 8192, and 15360;
+ # however, the integer value is not limited to these suggestions
+ pass
+
+
+class RSAKeyCapabilities(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('minKeySize', RSAKeySize()),
+ namedtype.OptionalNamedType('maxKeySize', RSAKeySize())
+ )
+
+
+class RsaSsa_Pss_sig_caps(univ.Sequence):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('hashAlg', AlgorithmIdentifier()),
+ namedtype.OptionalNamedType('maskAlg', AlgorithmIdentifier()),
+ namedtype.DefaultedNamedType('trailerField', univ.Integer().subtype(value=1))
+ )
+
+
+# Diffie-Hellman and DSA
+
+class DSAKeySize(univ.Integer):
+ subtypeSpec = constraint.SingleValueConstraint(1024, 2048, 3072, 7680, 15360)
+
+
+class DSAKeyCapabilities(univ.Choice):
+ componentType = namedtype.NamedTypes(
+ namedtype.NamedType('keySizes', univ.Sequence(componentType=namedtype.NamedTypes(
+ namedtype.NamedType('minKeySize',
+ DSAKeySize()),
+ namedtype.OptionalNamedType('maxKeySize',
+ DSAKeySize()),
+ namedtype.OptionalNamedType('maxSizeP',
+ univ.Integer().subtype(explicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 1))),
+ namedtype.OptionalNamedType('maxSizeQ',
+ univ.Integer().subtype(explicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 2))),
+ namedtype.OptionalNamedType('maxSizeG',
+ univ.Integer().subtype(explicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatSimple, 3)))
+ )).subtype(explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, 0))),
+ namedtype.NamedType('keyParams',
+ Dss_Parms().subtype(explicitTag=tag.Tag(
+ tag.tagClassContext, tag.tagFormatConstructed, 1)))
+ )
+
+
+# Elliptic Curve
+
+class EC_SMimeCaps(univ.SequenceOf):
+ componentType = ECParameters()
+ subtypeSpec=constraint.ValueSizeConstraint(1, MAX)
+
+
+# Update the SMIMECapabilities Attribute Map in rfc5751.py
+#
+# The map can either include an entry for scap-sa-rsaSSA-PSS or
+# scap-pk-rsaSSA-PSS, but not both. One is associated with the
+# public key and the other is associated with the signature
+# algorithm; however, they use the same OID. If you need the
+# other one in your application, copy the map into a local dict,
+# adjust as needed, and pass the local dict to the decoder with
+# openTypes=your_local_map.
+
+_smimeCapabilityMapUpdate = {
+ rsaEncryption: RSAKeyCapabilities(),
+ id_RSASSA_PSS: RSAKeyCapabilities(),
+ # id_RSASSA_PSS: RsaSsa_Pss_sig_caps(),
+ id_RSAES_OAEP: RSAKeyCapabilities(),
+ id_dsa: DSAKeyCapabilities(),
+ dhpublicnumber: DSAKeyCapabilities(),
+ id_ecPublicKey: EC_SMimeCaps(),
+ id_ecDH: EC_SMimeCaps(),
+ id_ecMQV: EC_SMimeCaps(),
+ id_mgf1: AlgorithmIdentifier(),
+}
+
+rfc5751.smimeCapabilityMap.update(_smimeCapabilityMapUpdate)
diff --git a/tests/__main__.py b/tests/__main__.py
index b89faae..d7f9102 100644
--- a/tests/__main__.py
+++ b/tests/__main__.py
@@ -57,10 +57,13 @@ suite = unittest.TestLoader().loadTestsFromNames(
'tests.test_rfc6019.suite',
'tests.test_rfc6031.suite',
'tests.test_rfc6032.suite',
+ 'tests.test_rfc6187.suite',
'tests.test_rfc6210.suite',
'tests.test_rfc6211.suite',
+ 'tests.test_rfc6482.suite',
'tests.test_rfc6486.suite',
'tests.test_rfc6487.suite',
+ 'tests.test_rfc6664.suite',
'tests.test_rfc6955.suite',
'tests.test_rfc6960.suite',
'tests.test_rfc7030.suite',
diff --git a/tests/test_rfc6187.py b/tests/test_rfc6187.py
new file mode 100644
index 0000000..e821d77
--- /dev/null
+++ b/tests/test_rfc6187.py
@@ -0,0 +1,73 @@
+#
+# 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.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 rfc6187
+
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
+
+
+class SSHClientCertificateTestCase(unittest.TestCase):
+ cert_pem_text = """\
+MIICkDCCAhegAwIBAgIJAKWzVCgbsG5BMAoGCCqGSM49BAMDMD8xCzAJBgNVBAYT
+AlVTMQswCQYDVQQIDAJWQTEQMA4GA1UEBwwHSGVybmRvbjERMA8GA1UECgwIQm9n
+dXMgQ0EwHhcNMTkxMDI0MTgyNjA3WhcNMjAxMDIzMTgyNjA3WjB0MQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVkExEDAOBgNVBAcTB0hlcm5kb24xEDAOBgNVBAoTB0V4
+YW1wbGUxEDAOBgNVBAMTB0NoYXJsaWUxIjAgBgkqhkiG9w0BCQEWE2NoYXJsaWVA
+ZXhhbXBsZS5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARfr1XPl5S0A/BwTOm4
+/rO7mGVt2Tmfr3yvYnfN/ggMvyS3RiIXSsdzcAwzeqc907Jp7Dggab0PpaOKDOxD
+WoK0g6B8+kC/VMsU23mfShlb9et8qcR3A8gdU6g8uvSMahWjgakwgaYwCwYDVR0P
+BAQDAgeAMB0GA1UdDgQWBBQfwm5u0GoxiDcjhDt33UJYlvMPFTAfBgNVHSMEGDAW
+gBTyNds0BNqlVfK9aQOZsGLs4hUIwTATBgNVHSUEDDAKBggrBgEFBQcDFTBCBglg
+hkgBhvhCAQ0ENRYzVGhpcyBjZXJ0aWZpY2F0ZSBjYW5ub3QgYmUgdHJ1c3RlZCBm
+b3IgYW55IHB1cnBvc2UuMAoGCCqGSM49BAMDA2cAMGQCMGEme38A3k8q4RGSEs2D
+ThQQOQz3TBJrIW8zr92S8e8BNPkRcQDR+C72TEhL/qoPCQIwGpGaC4ERiUypETkC
+voNP0ODFhhlpFo6lwVHd8Gu+6hShC2PKdAfs4QFDS9ZKgQeZ
+"""
+
+ def setUp(self):
+ self.asn1Spec = rfc5280.Certificate()
+
+ def testDerCodec(self):
+ ssh_eku_oids = [
+ rfc6187.id_kp_secureShellClient,
+ rfc6187.id_kp_secureShellServer,
+ ]
+
+ substrate = pem.readBase64fromText(self.cert_pem_text)
+ asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec)
+ assert not rest
+ assert asn1Object.prettyPrint()
+ assert der_encode(asn1Object) == substrate
+
+ count = 0
+ for extn in asn1Object['tbsCertificate']['extensions']:
+ if extn['extnID'] == rfc5280.id_ce_extKeyUsage:
+ extnValue, rest = der_decode(extn['extnValue'],
+ asn1Spec=rfc5280.ExtKeyUsageSyntax())
+ for oid in extnValue:
+ if oid in ssh_eku_oids:
+ count += 1
+
+ assert count == 1
+
+
+suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
+
+if __name__ == '__main__':
+ import sys
+
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ sys.exit(not result.wasSuccessful())
diff --git a/tests/test_rfc6482.py b/tests/test_rfc6482.py
new file mode 100644
index 0000000..731cbd9
--- /dev/null
+++ b/tests/test_rfc6482.py
@@ -0,0 +1,119 @@
+#
+# 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.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 rfc5652
+from pyasn1_modules import rfc6482
+
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
+
+
+class RPKIROATestCase(unittest.TestCase):
+ roa_pem_text = """\
+MIIGvwYJKoZIhvcNAQcCoIIGsDCCBqwCAQMxDTALBglghkgBZQMEAgEwKgYLKoZIhvcNAQkQ
+ARigGwQZMBcCAwDj+zAQMA4EAgABMAgwBgMEAJMcLaCCBLwwggS4MIIDoKADAgECAgIGGDAN
+BgkqhkiG9w0BAQsFADAzMTEwLwYDVQQDEyg2ZDZmYmZhOTc1M2RiOGQ4NDY0MzNkYjUzNTFk
+OWE5ZWMwN2M5NmJkMB4XDTE5MDgyMDAwNDkyOVoXDTIwMDcwMTAwMDAwMFowMzExMC8GA1UE
+AxMoNUI4M0REODdERTlBQzdDNkUzNEI4NzdERjUwMUEyQjEyMzBBODFCNDCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJcnDgSUtiQeelGQsTx2Ou5cgmfq6KPSEgMz/XyZrRzj
+wcqUQ/DyMYHyRJK8umKZjfMu+rItoPSkE26Wi9PcSnfuY+SyS9chTAtNOGMES6MbtHjNTmBF
+Xar5CFGM8teLIRHlCcScesgSR7q2eKgQ+cLiLTZnol0Mpmuf2NIs+V63Y4Hn/T7QOoudg9nU
+tmsh31hUN4jIENEXFvNDovkray25rl9aqFfW+dtkoNtdJjp367nNXCdp3GdE/3z0SIqT8wnh
+F67tgR22mwzex3umteQBwmM+iR28vuHL4E5jwRKBoiEgGPYqq7gbfkcoFtR3AV6QGKSK2aJU
+mUi+9VheS78CAwEAAaOCAdQwggHQMB0GA1UdDgQWBBRbg92H3prHxuNLh331AaKxIwqBtDAf
+BgNVHSMEGDAWgBRtb7+pdT242EZDPbU1HZqewHyWvTAYBgNVHSABAf8EDjAMMAoGCCsGAQUF
+Bw4CMFAGA1UdHwRJMEcwRaBDoEGGP3JzeW5jOi8vY2EucmcubmV0L3Jwa2kvUkduZXQtT1Uv
+YlctX3FYVTl1TmhHUXoyMU5SMmFuc0I4bHIwLmNybDBkBggrBgEFBQcBAQRYMFYwVAYIKwYB
+BQUHMAKGSHJzeW5jOi8vcnBraS5yaXBlLm5ldC9yZXBvc2l0b3J5L0RFRkFVTFQvYlctX3FY
+VTl1TmhHUXoyMU5SMmFuc0I4bHIwLmNlcjAOBgNVHQ8BAf8EBAMCB4AwgYoGCCsGAQUFBwEL
+BH4wfDBLBggrBgEFBQcwC4Y/cnN5bmM6Ly9jYS5yZy5uZXQvcnBraS9SR25ldC1PVS9XNFBk
+aDk2YXg4YmpTNGQ5OVFHaXNTTUtnYlEucm9hMC0GCCsGAQUFBzANhiFodHRwczovL2NhLnJn
+Lm5ldC9ycmRwL25vdGlmeS54bWwwHwYIKwYBBQUHAQcBAf8EEDAOMAwEAgABMAYDBACTHC0w
+DQYJKoZIhvcNAQELBQADggEBAKhhoJ3XtHejvG6XkFaCTxJci10gOgNvvPFWqz+CfOX2LmB0
+N3QhYjLiAZbfYSOxNReyL4bWDK/tpZgVA2VHuS8GB8fI8+nauQUiP38orVXKAbcUUxo7UkEM
+HxQ5T61FtXrEZx8hgKTlsfof0G2Q+baSJzNV2MIUgHmSszL4Mx/fHUXv8b7l/5mZQbdv3cZ9
+SbODHD0iOVAzK3fmHeuA4roSOk4mBQDWNRY1Ok+xH/HMDQdoOVtbfy57TZI2W7O2uxfElKvx
+fBeEc9TOaWqDz0xvmJ6bdZnmWRuvqW1475mhxi0s/I4eE2ZdaCinvrgrglBp/jpZi1jitY14
+dx+A1PMxggGqMIIBpgIBA4AUW4Pdh96ax8bjS4d99QGisSMKgbQwCwYJYIZIAWUDBAIBoGsw
+GgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEYMBwGCSqGSIb3DQEJBTEPFw0xOTA4MjAwMDQ5
+MjlaMC8GCSqGSIb3DQEJBDEiBCCfuHnOmhF2iBF3JXMOnoZCJzmE+Tcf8b+zObvDUpUddzAN
+BgkqhkiG9w0BAQEFAASCAQBDlJIMKCqWsFV/tQj/XvpSJUxJybG+zwjrUKm4yTKv8QEGOzOD
+aIL6irSOhhXeax6Lw0P2J7x+L3jGW1we1qWslumEDTr9kTE+kN/6rZuptUhwdrXcu3p9G6gJ
+mAUQtzqe2jRN1T3eSBfz1CNU3C7+jSHXOc+4Tea5mKiVddsjotYHXX0PbSCS/ZZ1yzdeES0o
+KWhXhW9ogS0bwtXWVTrciSekaRpp2n/pqcVEDxWg/5NpPiDlPNrRL/9eTEHFp940RAUfhbBh
+pbC2J02N0KgxUJxIJnGnpZ7rXKpG4jMiTVry7XB9bnFxCvZGBdjQW1Hagrfpl2TiVxQFvJWl
+IzU1
+"""
+
+ def testDerCodec(self):
+ substrate = pem.readBase64fromText(self.roa_pem_text)
+
+ layers = { }
+ layers.update(rfc5652.cmsContentTypesMap)
+
+ getNextLayer = {
+ rfc5652.id_ct_contentInfo: lambda x: x['contentType'],
+ rfc5652.id_signedData: lambda x: x['encapContentInfo']['eContentType'],
+ rfc6482.id_ct_routeOriginAuthz: lambda x: None
+ }
+
+ getNextSubstrate = {
+ rfc5652.id_ct_contentInfo: lambda x: x['content'],
+ rfc5652.id_signedData: lambda x: x['encapContentInfo']['eContent'],
+ rfc6482.id_ct_routeOriginAuthz: lambda x: None
+ }
+
+ next_layer = rfc5652.id_ct_contentInfo
+ while next_layer:
+ asn1Object, rest = der_decode(substrate, asn1Spec=layers[next_layer])
+ assert not rest
+ assert asn1Object.prettyPrint()
+ assert der_encode(asn1Object) == substrate
+
+ substrate = getNextSubstrate[next_layer](asn1Object)
+ next_layer = getNextLayer[next_layer](asn1Object)
+
+ assert asn1Object['version'] == 0
+ assert asn1Object['asID'] == 58363
+
+ def testOpenTypes(self):
+ substrate = pem.readBase64fromText(self.roa_pem_text)
+ asn1Object, rest = der_decode(substrate,
+ asn1Spec=rfc5652.ContentInfo(),
+ decodeOpenTypes=True)
+ assert not rest
+ assert asn1Object.prettyPrint()
+ assert der_encode(asn1Object) == substrate
+
+ oid = asn1Object['content']['encapContentInfo']['eContentType']
+ substrate = asn1Object['content']['encapContentInfo']['eContent']
+ assert oid in rfc5652.cmsContentTypesMap.keys()
+ asn1Object, rest = der_decode(substrate,
+ asn1Spec=rfc5652.cmsContentTypesMap[oid],
+ decodeOpenTypes=True)
+ assert not rest
+ assert asn1Object.prettyPrint()
+ assert der_encode(asn1Object) == substrate
+
+ assert asn1Object['version'] == 0
+ assert asn1Object['asID'] == 58363
+
+
+suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
+
+if __name__ == '__main__':
+ import sys
+
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ sys.exit(not result.wasSuccessful())
diff --git a/tests/test_rfc6664.py b/tests/test_rfc6664.py
new file mode 100644
index 0000000..38d0a54
--- /dev/null
+++ b/tests/test_rfc6664.py
@@ -0,0 +1,109 @@
+#
+# 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.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 rfc5480
+from pyasn1_modules import rfc5652
+from pyasn1_modules import rfc5751
+from pyasn1_modules import rfc6664
+
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
+
+
+class SMIMECapabilitiesTestCase(unittest.TestCase):
+ smime_capabilities_pem_text = """\
+MIICOjAJBgUrDgMCGgUAMA0GCWCGSAFlAwQCBAUAMA0GCWCGSAFlAwQCAQUAMA0G
+CWCGSAFlAwQCAgUAMA0GCWCGSAFlAwQCAwUAMBUGCSqGSIb3DQEBATAIAgIEAAIC
+EAAwFQYJKoZIhvcNAQEHMAgCAgQAAgIQADAVBgkqhkiG9w0BAQowCAICBAACAhAA
+MBUGByqGSM44BAGgCjAIAgIEAAICDAAwggEvBgcqhkjOPgIBoYIBIjCCAR4CgYEA
+i6Ued8R33vkopJwCvy/ZZv2TtddPXPYmJK4jyFv+TDJTPqnP7XUZCqRuhCyKX10z
+7SgiZs6qlSMk5gCa8shPF8NCHtps2D1OVC7yppZUJI07FoDxoEAZHImdAFvYIA/V
+cGYpYOKod4kju0/e4VUBZ6Qoer5vKTh+lD/+ZKa/WSUCFQDc3W87QSZSX6ggdbeI
+fzb0rsAhbwKBgCEz/o4WJPUZ4HffJfuXHIGrkPnCxFAYDRtlqueswV0Gy6LunipE
+Iu3nCzYkZhMatyFNyzo+NusEsS+9isOhT8jhL93nSBZCSRBy+GfmSXlXv/3c8mtH
+XTie5JOqjRdonPr4g/+VZvMkcioooNrhx/zICHrC3WZ72871/n/z9M+dMCMGByqG
+SM49AgEwGAYIKoZIzj0DAQcGBSuBBAAiBgUrgQQAIzAhBgUrgQQBDTAYBggqhkjO
+PQMBBwYFK4EEACIGBSuBBAAjMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAA==
+"""
+
+ def setUp(self):
+ self.asn1Spec = rfc5751.SMIMECapabilities()
+
+ def testDerCodec(self):
+ substrate = pem.readBase64fromText(self.smime_capabilities_pem_text)
+ asn1Object, rest = der_decode (substrate, asn1Spec=self.asn1Spec)
+ assert not rest
+ assert asn1Object.prettyPrint()
+ assert der_encode(asn1Object) == substrate
+
+ count = 0
+ for cap in asn1Object:
+ if cap['capabilityID'] in rfc5751.smimeCapabilityMap.keys():
+ substrate = cap['parameters']
+ cap_p, rest = der_decode (substrate,
+ asn1Spec=rfc5751.smimeCapabilityMap[cap['capabilityID']])
+ assert not rest
+ assert cap_p.prettyPrint()
+ assert der_encode(cap_p) == substrate
+ count += 1
+
+ assert count == 8
+
+ def testOpenTypes(self):
+ substrate = pem.readBase64fromText(self.smime_capabilities_pem_text)
+ asn1Object, rest = der_decode(substrate,
+ asn1Spec=self.asn1Spec,
+ decodeOpenTypes=True)
+ assert not rest
+ assert asn1Object.prettyPrint()
+ assert der_encode(asn1Object) == substrate
+
+ parameterValue = {
+ rfc6664.rsaEncryption: lambda x: x['maxKeySize'],
+ rfc6664.id_RSAES_OAEP: lambda x: x['maxKeySize'],
+ rfc6664.id_RSASSA_PSS: lambda x: x['minKeySize'],
+ rfc6664.id_dsa: lambda x: x['keySizes']['maxKeySize'],
+ rfc6664.dhpublicnumber: lambda x: x['keyParams']['q'] % 1023,
+ rfc6664.id_ecPublicKey: lambda x: x[0]['namedCurve'],
+ rfc6664.id_ecMQV: lambda x: x[1]['namedCurve'],
+ }
+
+ expectedValue = {
+ rfc6664.rsaEncryption: 4096,
+ rfc6664.id_RSAES_OAEP: 4096,
+ rfc6664.id_RSASSA_PSS: 1024,
+ rfc6664.id_dsa: 3072,
+ rfc6664.dhpublicnumber: 257,
+ rfc6664.id_ecPublicKey: rfc5480.secp256r1,
+ rfc6664.id_ecMQV: rfc5480.secp384r1,
+ }
+
+ count = 0
+ for cap in asn1Object:
+ if cap['capabilityID'] in parameterValue.keys():
+ pValue = parameterValue[cap['capabilityID']](cap['parameters'])
+ eValue = expectedValue[cap['capabilityID']]
+ assert pValue == eValue
+ count += 1
+
+ assert count == 7
+
+
+suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
+
+if __name__ == '__main__':
+ import sys
+
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ sys.exit(not result.wasSuccessful())