aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Housley <housley@vigilsec.com>2019-06-27 16:32:22 -0400
committerIlya Etingof <etingof@gmail.com>2019-06-27 22:32:22 +0200
commit86f7ad492e0dd2eda1bbc2f98fc00ecc3837114e (patch)
treeb9a0724a2f74b412ea4ef87f44813c2f2e484b3f
parent118dccfd5a18d7b7e48be830fecb0d30ee8b1b7b (diff)
downloadpyasn1-modules-86f7ad492e0dd2eda1bbc2f98fc00ecc3837114e.tar.gz
Add support for RFC 5035 (#48)
-rw-r--r--CHANGES.txt2
-rw-r--r--pyasn1_modules/rfc5035.py189
-rw-r--r--tests/__main__.py1
-rwxr-xr-xtests/test_rfc5035.py151
4 files changed, 343 insertions, 0 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 48f9f92..36948aa 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -24,6 +24,8 @@ Revision 0.2.6, released XX-05-2019
Types
- Added openType support for ORAddress Extension Attributes in
the RFC5280 module
+- Added RFC5035 providing Update to Enhanced Security Services for
+ S/MIME
Revision 0.2.5, released 24-04-2019
-----------------------------------
diff --git a/pyasn1_modules/rfc5035.py b/pyasn1_modules/rfc5035.py
new file mode 100644
index 0000000..5cf0d0d
--- /dev/null
+++ b/pyasn1_modules/rfc5035.py
@@ -0,0 +1,189 @@
+#
+# 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
+#
+# Update to Enhanced Security Services for S/MIME
+#
+# ASN.1 source from:
+# https://www.rfc-editor.org/rfc/rfc5035.txt
+#
+
+from pyasn1.codec.der.encoder import encode as der_encode
+
+from pyasn1.type import namedtype
+from pyasn1.type import univ
+
+from pyasn1_modules import rfc2634
+from pyasn1_modules import rfc4055
+from pyasn1_modules import rfc5652
+from pyasn1_modules import rfc5280
+
+ContentType = rfc5652.ContentType
+
+IssuerAndSerialNumber = rfc5652.IssuerAndSerialNumber
+
+SubjectKeyIdentifier = rfc5652.SubjectKeyIdentifier
+
+AlgorithmIdentifier = rfc5280.AlgorithmIdentifier
+
+PolicyInformation = rfc5280.PolicyInformation
+
+GeneralNames = rfc5280.GeneralNames
+
+CertificateSerialNumber = rfc5280.CertificateSerialNumber
+
+
+# Signing Certificate Attribute V1 and V2
+
+id_aa_signingCertificate = rfc2634.id_aa_signingCertificate
+
+id_aa_signingCertificateV2 = univ.ObjectIdentifier('1.2.840.113549.1.9.16.2.47')
+
+Hash = rfc2634.Hash
+
+IssuerSerial = rfc2634.IssuerSerial
+
+ESSCertID = rfc2634.ESSCertID
+
+SigningCertificate = rfc2634.SigningCertificate
+
+
+sha256AlgId = AlgorithmIdentifier()
+sha256AlgId['algorithm'] = rfc4055.id_sha256
+# A non-schema object for sha256AlgId['parameters'] as absent
+sha256AlgId['parameters'] = der_encode(univ.OctetString(''))
+
+
+class ESSCertIDv2(univ.Sequence):
+ pass
+
+ESSCertIDv2.componentType = namedtype.NamedTypes(
+ namedtype.DefaultedNamedType('hashAlgorithm', sha256AlgId),
+ namedtype.NamedType('certHash', Hash()),
+ namedtype.OptionalNamedType('issuerSerial', IssuerSerial())
+)
+
+
+class SigningCertificateV2(univ.Sequence):
+ pass
+
+SigningCertificateV2.componentType = namedtype.NamedTypes(
+ namedtype.NamedType('certs', univ.SequenceOf(
+ componentType=ESSCertIDv2())),
+ namedtype.OptionalNamedType('policies', univ.SequenceOf(
+ componentType=PolicyInformation()))
+)
+
+
+# Mail List Expansion History Attribute
+
+id_aa_mlExpandHistory = rfc2634.id_aa_mlExpandHistory
+
+ub_ml_expansion_history = rfc2634.ub_ml_expansion_history
+
+EntityIdentifier = rfc2634.EntityIdentifier
+
+MLReceiptPolicy = rfc2634.MLReceiptPolicy
+
+MLData = rfc2634.MLData
+
+MLExpansionHistory = rfc2634.MLExpansionHistory
+
+
+# ESS Security Label Attribute
+
+id_aa_securityLabel = rfc2634.id_aa_securityLabel
+
+ub_privacy_mark_length = rfc2634.ub_privacy_mark_length
+
+ub_security_categories = rfc2634.ub_security_categories
+
+ub_integer_options = rfc2634.ub_integer_options
+
+ESSPrivacyMark = rfc2634.ESSPrivacyMark
+
+SecurityClassification = rfc2634.SecurityClassification
+
+SecurityPolicyIdentifier = rfc2634.SecurityPolicyIdentifier
+
+SecurityCategory = rfc2634.SecurityCategory
+
+SecurityCategories = rfc2634.SecurityCategories
+
+ESSSecurityLabel = rfc2634.ESSSecurityLabel
+
+
+# Equivalent Labels Attribute
+
+id_aa_equivalentLabels = rfc2634.id_aa_equivalentLabels
+
+EquivalentLabels = rfc2634.EquivalentLabels
+
+
+# Content Identifier Attribute
+
+id_aa_contentIdentifier = rfc2634.id_aa_contentIdentifier
+
+ContentIdentifier = rfc2634.ContentIdentifier
+
+
+# Content Reference Attribute
+
+id_aa_contentReference = rfc2634.id_aa_contentReference
+
+ContentReference = rfc2634.ContentReference
+
+
+# Message Signature Digest Attribute
+
+id_aa_msgSigDigest = rfc2634.id_aa_msgSigDigest
+
+MsgSigDigest = rfc2634.MsgSigDigest
+
+
+# Content Hints Attribute
+
+id_aa_contentHint = rfc2634.id_aa_contentHint
+
+ContentHints = rfc2634.ContentHints
+
+
+# Receipt Request Attribute
+
+AllOrFirstTier = rfc2634.AllOrFirstTier
+
+ReceiptsFrom = rfc2634.ReceiptsFrom
+
+id_aa_receiptRequest = rfc2634.id_aa_receiptRequest
+
+ub_receiptsTo = rfc2634.ub_receiptsTo
+
+ReceiptRequest = rfc2634.ReceiptRequest
+
+
+# Receipt Content Type
+
+ESSVersion = rfc2634.ESSVersion
+
+id_ct_receipt = rfc2634.id_ct_receipt
+
+Receipt = rfc2634.Receipt
+
+ub_receiptsTo = rfc2634.ub_receiptsTo
+
+ReceiptRequest = rfc2634.ReceiptRequest
+
+
+# Map of Attribute Type to the Attribute structure
+
+ESSAttributeMap = rfc2634.ESSAttributeMap
+
+_ESSAttributeMapAddition = {
+ id_aa_signingCertificateV2: SigningCertificateV2(),
+}
+
+ESSAttributeMap.update(_ESSAttributeMapAddition)
diff --git a/tests/__main__.py b/tests/__main__.py
index 879981e..08b0424 100644
--- a/tests/__main__.py
+++ b/tests/__main__.py
@@ -29,6 +29,7 @@ suite = unittest.TestLoader().loadTestsFromNames(
'tests.test_rfc4073.suite',
'tests.test_rfc4108.suite',
'tests.test_rfc4210.suite',
+ 'tests.test_rfc5035.suite',
'tests.test_rfc5083.suite',
'tests.test_rfc5084.suite',
'tests.test_rfc5208.suite',
diff --git a/tests/test_rfc5035.py b/tests/test_rfc5035.py
new file mode 100755
index 0000000..022d149
--- /dev/null
+++ b/tests/test_rfc5035.py
@@ -0,0 +1,151 @@
+#
+# 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 rfc5652
+from pyasn1_modules import rfc5035
+
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
+
+
+class SignedMessageTestCase(unittest.TestCase):
+ signed_message_pem_text = """\
+MIIFzAYJKoZIhvcNAQcCoIIFvTCCBbkCAQExDTALBglghkgBZQMEAgIwUQYJKoZI
+hvcNAQcBoEQEQkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbg0KDQpXYXRzb24sIGNv
+bWUgaGVyZSAtIEkgd2FudCB0byBzZWUgeW91LqCCAnwwggJ4MIIB/qADAgECAgkA
+pbNUKBuwbjswCgYIKoZIzj0EAwMwPzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlZB
+MRAwDgYDVQQHDAdIZXJuZG9uMREwDwYDVQQKDAhCb2d1cyBDQTAeFw0xOTA1Mjkx
+NDQ1NDFaFw0yMDA1MjgxNDQ1NDFaMHAxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJW
+QTEQMA4GA1UEBxMHSGVybmRvbjEQMA4GA1UEChMHRXhhbXBsZTEOMAwGA1UEAxMF
+QWxpY2UxIDAeBgkqhkiG9w0BCQEWEWFsaWNlQGV4YW1wbGUuY29tMHYwEAYHKoZI
+zj0CAQYFK4EEACIDYgAE+M2fBy/sRA6V1pKFqecRTE8+LuAHtZxes1wmJZrBBg+b
+z7uYZfYQxI3dVB0YCSD6Mt3yXFlnmfBRwoqyArbjIBYrDbHBv2k8Csg2DhQ7qs/w
+to8hMKoFgkcscqIbiV7Zo4GUMIGRMAsGA1UdDwQEAwIHgDBCBglghkgBhvhCAQ0E
+NRYzVGhpcyBjZXJ0aWZpY2F0ZSBjYW5ub3QgYmUgdHJ1c3RlZCBmb3IgYW55IHB1
+cnBvc2UuMB0GA1UdDgQWBBTEuloOPnrjPIGw9AKqaLsW4JYONTAfBgNVHSMEGDAW
+gBTyNds0BNqlVfK9aQOZsGLs4hUIwTAKBggqhkjOPQQDAwNoADBlAjBjuR/RNbgL
+3kRhmn+PJTeKaL9sh/oQgHOYTgLmSnv3+NDCkhfKuMNoo/tHrkmihYgCMQC94Mae
+rDIrQpi0IDh+v0QSAv9rMife8tClafXWtDwwL8MS7oAh0ymT446Uizxx3PUxggLQ
+MIICzAIBATBMMD8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UEBwwH
+SGVybmRvbjERMA8GA1UECgwIQm9ndXMgQ0ECCQCls1QoG7BuOzALBglghkgBZQME
+AgKgggH1MBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X
+DTE5MDUyOTE4MjMxOVowJQYLKoZIhvcNAQkQAgcxFgQUAbWZQYhLO5wtUgsOCGtT
+4V3aNhUwLwYLKoZIhvcNAQkQAgQxIDAeDBFXYXRzb24sIGNvbWUgaGVyZQYJKoZI
+hvcNAQcBMDUGCyqGSIb3DQEJEAICMSYxJAIBAQYKKwYBBAGBrGABARMTQm9hZ3Vz
+IFByaXZhY3kgTWFyazA/BgkqhkiG9w0BCQQxMgQwtuQipP2CZx7U96rGbUT06LC5
+jVFYccZW5/CaNvpcrOPiChDm2vI3m4k300z5mSZsME0GCyqGSIb3DQEJEAIBMT4w
+PAQgx08hD2QnVwj1DoeRELNtdZ0PffW4BQIvcwwVc/goU6OAAQEwFTATgRFhbGlj
+ZUBleGFtcGxlLmNvbTCBmwYLKoZIhvcNAQkQAi8xgYswgYgwdjB0BCACcp04gyM2
+dTDg+0ydCwlucr6Mg8Wd3J3c9V+iLHsnZzBQMEOkQTA/MQswCQYDVQQGEwJVUzEL
+MAkGA1UECAwCVkExEDAOBgNVBAcMB0hlcm5kb24xETAPBgNVBAoMCEJvZ3VzIENB
+AgkApbNUKBuwbjswDjAMBgorBgEEAYGsYAEBMAoGCCqGSM49BAMDBGcwZQIxAO3K
+D9YjFTKE3p383VVw/ol79WTVoMea4H1+7xn+3E1XO4oyb7qwQz0KmsGfdqWptgIw
+T9yMtRLN5ZDU14y+Phzq9NKpSw/x5KyXoUKjCMc3Ru6dIW+CgcRQees+dhnvuD5U
+"""
+
+ def setUp(self):
+ self.asn1Spec = rfc5652.ContentInfo()
+
+ def testDerCodec(self):
+ substrate = pem.readBase64fromText(self.signed_message_pem_text)
+ asn1Object, rest = der_decode (substrate, asn1Spec=self.asn1Spec)
+ assert not rest
+ assert asn1Object.prettyPrint()
+ assert der_encode(asn1Object) == substrate
+
+ assert asn1Object['contentType'] == rfc5652.id_signedData
+ sd, rest = der_decode(asn1Object['content'], asn1Spec=rfc5652.SignedData())
+ assert not rest
+ assert sd.prettyPrint()
+ assert der_encode(sd) == asn1Object['content']
+
+ for sa in sd['signerInfos'][0]['signedAttrs']:
+ sat = sa['attrType']
+ sav0 = sa['attrValues'][0]
+
+ if sat in rfc5035.ESSAttributeMap.keys():
+ sav, rest = der_decode(sav0, asn1Spec=rfc5035.ESSAttributeMap[sat])
+ assert not rest
+ assert sav.prettyPrint()
+ assert der_encode(sav) == sav0
+
+
+class SignedReceiptTestCase(unittest.TestCase):
+ signed_receipt_pem_text = """\
+MIIE3gYJKoZIhvcNAQcCoIIEzzCCBMsCAQMxDTALBglghkgBZQMEAgEwga4GCyqGSIb3DQEJ
+EAEBoIGeBIGbMIGYAgEBBgkqhkiG9w0BBwEEIMdPIQ9kJ1cI9Q6HkRCzbXWdD331uAUCL3MM
+FXP4KFOjBGYwZAIwOLV5WCbYjy5HLHE69IqXQQHVDJQzmo18WwkFrEYH3EMsvpXEIGqsFTFN
+6NV4VBe9AjA5fGOCP5IhI32YqmGfs+zDlqZyb2xSX6Gr/IfCIm0angfOI39g7lAZDyivjh5H
+/oSgggJ3MIICczCCAfqgAwIBAgIJAKWzVCgbsG48MAoGCCqGSM49BAMDMD8xCzAJBgNVBAYT
+AlVTMQswCQYDVQQIDAJWQTEQMA4GA1UEBwwHSGVybmRvbjERMA8GA1UECgwIQm9ndXMgQ0Ew
+HhcNMTkwNTI5MTkyMDEzWhcNMjAwNTI4MTkyMDEzWjBsMQswCQYDVQQGEwJVUzELMAkGA1UE
+CBMCVkExEDAOBgNVBAcTB0hlcm5kb24xEDAOBgNVBAoTB0V4YW1wbGUxDDAKBgNVBAMTA0Jv
+YjEeMBwGCSqGSIb3DQEJARYPYm9iQGV4YW1wbGUuY29tMHYwEAYHKoZIzj0CAQYFK4EEACID
+YgAEMaRiVS8WvN8Ycmpfq75jBbOMUukNfXAg6AL0JJBXtIFAuIJcZVlkLn/xbywkcMLHK/O+
+w9RWUQa2Cjw+h8b/1Cl+gIpqLtE558bD5PfM2aYpJ/YE6yZ9nBfTQs7z1TH5o4GUMIGRMAsG
+A1UdDwQEAwIHgDBCBglghkgBhvhCAQ0ENRYzVGhpcyBjZXJ0aWZpY2F0ZSBjYW5ub3QgYmUg
+dHJ1c3RlZCBmb3IgYW55IHB1cnBvc2UuMB0GA1UdDgQWBBTKa2Zy3iybV3+YjuLDKtNmjsIa
+pTAfBgNVHSMEGDAWgBTyNds0BNqlVfK9aQOZsGLs4hUIwTAKBggqhkjOPQQDAwNnADBkAjAV
+boS6OfEYQomLDi2RUkd71hzwwiQZztbxNbosahIzjR8ZQaHhjdjJlrP/T6aXBwsCMDfRweYz
+3Ce4E4wPfoqQnvqpM7ZlfhstjQQGOsWAtIIfqW/l+TgCO8ux3XLV6fj36zGCAYkwggGFAgEB
+MEwwPzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlZBMRAwDgYDVQQHDAdIZXJuZG9uMREwDwYD
+VQQKDAhCb2d1cyBDQQIJAKWzVCgbsG48MAsGCWCGSAFlAwQCAaCBrjAaBgkqhkiG9w0BCQMx
+DQYLKoZIhvcNAQkQAQEwHAYJKoZIhvcNAQkFMQ8XDTE5MDUyOTE5MzU1NVowLwYJKoZIhvcN
+AQkEMSIEIGb9Hm2kCnM0CYNpZU4Uj7dN0AzOieIn9sDqZMcIcZrEMEEGCyqGSIb3DQEJEAIF
+MTIEMBZzeHVja7fQ62ywyh8rtKzBP1WJooMdZ+8c6pRqfIESYIU5bQnH99OPA51QCwdOdjAK
+BggqhkjOPQQDAgRoMGYCMQDZiT22xgab6RFMAPvN4fhWwzx017EzttD4VaYrpbolropBdPJ6
+jIXiZQgCwxbGTCwCMQClaQ9K+L5LTeuW50ZKSIbmBZQ5dxjtnK3OlS7hYRi6U0JKZmWbbuS8
+vFIgX7eIkd8=
+"""
+
+ def setUp(self):
+ self.asn1Spec = rfc5652.ContentInfo()
+
+ def testDerCodec(self):
+ substrate = pem.readBase64fromText(self.signed_receipt_pem_text)
+ asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec)
+ assert not rest
+ assert asn1Object.prettyPrint()
+ assert der_encode(asn1Object) == substrate
+
+ assert asn1Object['contentType'] == rfc5652.id_signedData
+ sd, rest = der_decode (asn1Object['content'], asn1Spec=rfc5652.SignedData())
+ assert not rest
+ assert sd.prettyPrint()
+ assert der_encode(sd) == asn1Object['content']
+
+ assert sd['encapContentInfo']['eContentType'] == rfc5035.id_ct_receipt
+ receipt, rest = der_decode(sd['encapContentInfo']['eContent'],
+ asn1Spec=rfc5035.Receipt())
+ assert not rest
+ assert receipt.prettyPrint()
+ assert der_encode(receipt) == sd['encapContentInfo']['eContent']
+
+ for sa in sd['signerInfos'][0]['signedAttrs']:
+ sat = sa['attrType']
+ sav0 = sa['attrValues'][0]
+
+ if sat in rfc5035.ESSAttributeMap.keys():
+ sav, rest = der_decode(sav0, asn1Spec=rfc5035.ESSAttributeMap[sat])
+ assert not rest
+ assert sav.prettyPrint()
+ assert der_encode(sav) == sav0
+
+
+suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
+
+if __name__ == '__main__':
+ unittest.TextTestRunner(verbosity=2).run(suite)