1#
2# This file is part of pyasn1-modules software.
3#
4# Created by Russ Housley
5# Copyright (c) 2019, Vigil Security, LLC
6# License: http://snmplabs.com/pyasn1/license.html
7#
8
9import sys
10
11from pyasn1.codec.der.decoder import decode as der_decode
12from pyasn1.codec.der.encoder import encode as der_encode
13
14from pyasn1.compat.octets import str2octs
15
16from pyasn1_modules import pem
17from pyasn1_modules import rfc2634
18from pyasn1_modules import rfc4073
19from pyasn1_modules import rfc5652
20
21try:
22    import unittest2 as unittest
23except ImportError:
24    import unittest
25
26
27class ContentCollectionTestCase(unittest.TestCase):
28    pem_text = """\
29MIIG/QYLKoZIhvcNAQkQAROgggbsMIIG6DCCAWcGCyqGSIb3DQEJEAEUoIIBVjCC
30AVIwgfEGCSqGSIb3DQEHAaCB4wSB4ENvbnRlbnQtVHlwZTogdGV4dC9wbGFpbgoK
31UkZDIDQwNzMsIHB1Ymxpc2hlZCBpbiBNYXkgMjAwNSwgZGVzY3JpYmVzIGEgY29u
32dmVudGlvbiBmb3IgdXNpbmcgdGhlCkNyeXB0b2dyYXBoaWMgTWVzc2FnZSBTeW50
33YXggKENNUykgdG8gcHJvdGVjdCBhIGNvbnRlbnQgY29sbGVjdGlvbi4gIElmCmRl
34c2lyZWQsIGF0dHJpYnV0ZXMgY2FuIGJlIGFzc29jaWF0ZWQgd2l0aCB0aGUgY29u
35dGVudC4KMFwwMwYLKoZIhvcNAQkQAgQxJDAiDBVBYnN0cmFjdCBmb3IgUkZDIDQw
36NzMGCSqGSIb3DQEHATAlBgsqhkiG9w0BCRACBzEWBBSkLSXBiRWvbwnJKb4EGb1X
37FwCa3zCCBXkGCyqGSIb3DQEJEAEUoIIFaDCCBWQwggT9BgkqhkiG9w0BBwGgggTu
38BIIE6kNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbgoKVGhlIGZvbGxvd2luZyBBU04u
39MSBtb2R1bGUgZGVmaW5lcyB0aGUgc3RydWN0dXJlcyB0aGF0IGFyZSBuZWVkZWQg
40dG8KaW1wbGVtZW50IHRoZSBzcGVjaWZpY2F0aW9uIGluIFJGQyA0MDczLiAgSXQg
41aXMgZXhwZWN0ZWQgdG8gYmUgdXNlZCBpbgpjb25qdW5jdGlvbiB3aXRoIHRoZSBB
42U04uMSBtb2R1bGVzIGluIFJGQyA1NjUyIGFuZCBSRkMgMzI3NC4KCiAgIENvbnRl
43bnRDb2xsZWN0aW9uTW9kdWxlCiAgICAgeyBpc28oMSkgbWVtYmVyLWJvZHkoMikg
44dXMoODQwKSByc2Fkc2koMTEzNTQ5KSBwa2NzKDEpCiAgICAgICBwa2NzLTkoOSkg
45c21pbWUoMTYpIG1vZHVsZXMoMCkgMjYgfQoKICAgREVGSU5JVElPTlMgSU1QTElD
46SVQgVEFHUyA6Oj0KICAgQkVHSU4KCiAgIElNUE9SVFMKICAgICBBdHRyaWJ1dGUs
47IENvbnRlbnRJbmZvCiAgICAgICBGUk9NIENyeXB0b2dyYXBoaWNNZXNzYWdlU3lu
48dGF4MjAwNCAtLSBbQ01TXQogICAgICAgICB7IGlzbygxKSBtZW1iZXItYm9keSgy
49KSB1cyg4NDApIHJzYWRzaSgxMTM1NDkpCiAgICAgICAgICAgcGtjcygxKSBwa2Nz
50LTkoOSkgc21pbWUoMTYpIG1vZHVsZXMoMCkgY21zLTIwMDEoMTQpIH07CgoKICAg
51LS0gQ29udGVudCBDb2xsZWN0aW9uIENvbnRlbnQgVHlwZSBhbmQgT2JqZWN0IElk
52ZW50aWZpZXIKCiAgIGlkLWN0LWNvbnRlbnRDb2xsZWN0aW9uIE9CSkVDVCBJREVO
53VElGSUVSIDo6PSB7CiAgICAgICAgICAgaXNvKDEpIG1lbWJlci1ib2R5KDIpIHVz
54KDg0MCkgcnNhZHNpKDExMzU0OSkgcGtjcygxKQogICAgICAgICAgIHBrY3M5KDkp
55IHNtaW1lKDE2KSBjdCgxKSAxOSB9CgogICBDb250ZW50Q29sbGVjdGlvbiA6Oj0g
56U0VRVUVOQ0UgU0laRSAoMS4uTUFYKSBPRiBDb250ZW50SW5mbwoKICAgLS0gQ29u
57dGVudCBXaXRoIEF0dHJpYnV0ZXMgQ29udGVudCBUeXBlIGFuZCBPYmplY3QgSWRl
58bnRpZmllcgoKICAgaWQtY3QtY29udGVudFdpdGhBdHRycyBPQkpFQ1QgSURFTlRJ
59RklFUiA6Oj0gewogICAgICAgICAgIGlzbygxKSBtZW1iZXItYm9keSgyKSB1cyg4
60NDApIHJzYWRzaSgxMTM1NDkpIHBrY3MoMSkKICAgICAgICAgICBwa2NzOSg5KSBz
61bWltZSgxNikgY3QoMSkgMjAgfQoKICAgQ29udGVudFdpdGhBdHRyaWJ1dGVzIDo6
62PSBTRVFVRU5DRSB7CiAgICAgICBjb250ZW50ICAgICBDb250ZW50SW5mbywKICAg
63ICAgIGF0dHJzICAgICAgIFNFUVVFTkNFIFNJWkUgKDEuLk1BWCkgT0YgQXR0cmli
64dXRlIH0KCiAgIEVORAowYTA4BgsqhkiG9w0BCRACBDEpMCcMGkFTTi4xIE1vZHVs
65ZSBmcm9tIFJGQyA0MDczBgkqhkiG9w0BBwEwJQYLKoZIhvcNAQkQAgcxFgQUMbeK
66buWO3egPDL8Kf7tBhzjIKLw=
67"""
68
69    def setUp(self):
70        self.asn1Spec = rfc5652.ContentInfo()
71
72    def testDerCodec(self):
73
74        def test_layer(substrate, content_type):
75            asn1Object, rest = der_decode(substrate, asn1Spec=layers[content_type])
76            assert not rest
77            assert asn1Object.prettyPrint()
78            assert der_encode(asn1Object) == substrate
79
80            if content_type == rfc4073.id_ct_contentWithAttrs:
81                for attr in asn1Object['attrs']:
82                    assert attr['attrType'] in rfc5652.cmsAttributesMap.keys()
83
84            return asn1Object
85
86        layers = rfc5652.cmsContentTypesMap
87
88        getNextLayer = {
89            rfc5652.id_ct_contentInfo: lambda x: x['contentType'],
90            rfc4073.id_ct_contentCollection: lambda x: x[0]['contentType'],
91            rfc4073.id_ct_contentWithAttrs: lambda x: x['content']['contentType'],
92            rfc5652.id_data: lambda x: None,
93        }
94
95        getNextSubstrate = {
96            rfc5652.id_ct_contentInfo: lambda x: x['content'],
97            rfc4073.id_ct_contentCollection: lambda x: x[0]['content'],
98            rfc4073.id_ct_contentWithAttrs: lambda x: x['content']['content'],
99            rfc5652.id_data: lambda x: None,
100        }
101
102        substrate = pem.readBase64fromText(self.pem_text)
103
104        this_layer = rfc5652.id_ct_contentInfo
105        while this_layer != rfc5652.id_data:
106            if this_layer == rfc4073.id_ct_contentCollection:
107                asn1Object = test_layer(substrate, this_layer)
108                for ci in asn1Object:
109                    substrate = ci['content']
110                    this_layer = ci['contentType']
111                    while this_layer != rfc5652.id_data:
112                        asn1Object = test_layer(substrate, this_layer)
113                        substrate = getNextSubstrate[this_layer](asn1Object)
114                        this_layer = getNextLayer[this_layer](asn1Object)
115            else:
116                asn1Object = test_layer(substrate, this_layer)
117                substrate = getNextSubstrate[this_layer](asn1Object)
118                this_layer = getNextLayer[this_layer](asn1Object)
119
120    def testOpenTypes(self):
121        substrate = pem.readBase64fromText(self.pem_text)
122        asn1Object, rest = der_decode(substrate,
123            asn1Spec=rfc5652.ContentInfo(),
124            decodeOpenTypes=True)
125        assert not rest
126        assert asn1Object.prettyPrint()
127        assert der_encode(asn1Object) == substrate
128
129        assert asn1Object['contentType'] == rfc4073.id_ct_contentCollection
130        for ci in asn1Object['content']:
131            assert ci['contentType'] in rfc5652.cmsContentTypesMap.keys()
132            assert ci['contentType'] == rfc4073.id_ct_contentWithAttrs
133            next_ci = ci['content']['content']
134            assert next_ci['contentType'] in rfc5652.cmsContentTypesMap.keys()
135            assert next_ci['contentType'] == rfc5652.id_data
136            assert str2octs('Content-Type: text') in next_ci['content']
137
138            for attr in ci['content']['attrs']:
139                assert attr['attrType'] in rfc5652.cmsAttributesMap.keys()
140                if attr['attrType'] == rfc2634.id_aa_contentHint:
141                    assert 'RFC 4073' in attr['attrValues'][0]['contentDescription']
142
143
144suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
145
146if __name__ == '__main__':
147    import sys
148
149    result = unittest.TextTestRunner(verbosity=2).run(suite)
150    sys.exit(not result.wasSuccessful())