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#
8import sys
9
10from pyasn1.codec.der.decoder import decode as der_decode
11from pyasn1.codec.der.encoder import encode as der_encode
12
13from pyasn1.type import univ
14
15from pyasn1_modules import pem
16from pyasn1_modules import rfc2985
17from pyasn1_modules import rfc5280
18from pyasn1_modules import rfc5652
19from pyasn1_modules import rfc7292
20
21
22try:
23    import unittest2 as unittest
24
25except ImportError:
26    import unittest
27
28
29class PKCS9AttrsTestCase(unittest.TestCase):
30    pem_text = """\
31MYIQjzAOBgNVBEExBwwFQWxpY2UwDwYIKwYBBQUHCQMxAxMBTTAQBgNVBAUxCRMH
32QjQ4LTAwNzAQBggrBgEFBQcJBDEEEwJVUzAQBggrBgEFBQcJBTEEEwJVUzARBgoq
33hkiG9w0BCRkEMQMCATAwFAYJKoZIhvcNAQkCMQcWBUFsaWNlMBgGCiqGSIb3DQEJ
34GQMxCgQIUTeqnHYky4AwHAYJKoZIhvcNAQkPMQ8wDTALBglghkgBZQMEAS0wHQYI
35KwYBBQUHCQExERgPMjAxOTA4MDMxMjAwMDBaMB0GCCsGAQUFBwkCMREMD0hlcm5k
36b24sIFZBLCBVUzApBgkqhkiG9w0BCRQxHB4aAEYAcgBpAGUAbgBkAGwAeQAgAE4A
37YQBtAGUwLwYJKoZIhvcNAQkIMSITIDEyMyBVbmtub3duIFdheSwgTm93aGVyZSwg
38VkEsIFVTMIGZBgoqhkiG9w0BCRkCMYGKMIGHMAsGCWCGSAFlAwQBLQR4VsJb7t4l
39IqjJCT54rqkbCJsBPE17YQJeEYvyA4M1aDIUU5GnCgEhctgMiDPWGMvaSziixdIg
40aU/0zvWvYCm8UwPvBBwMtm9X5NDvk9p4nXbGAT8E/OsV1SYWVvwRJwYak0yWWexM
41HSixw1Ljh2nb0fIbqwLOeMmIMIIEsQYKKoZIhvcNAQkZBTGCBKEwggSdBgkqhkiG
429w0BBwKgggSOMIIEigIBATENMAsGCWCGSAFlAwQCAjBRBgkqhkiG9w0BBwGgRARC
43Q29udGVudC1UeXBlOiB0ZXh0L3BsYWluDQoNCldhdHNvbiwgY29tZSBoZXJlIC0g
44SSB3YW50IHRvIHNlZSB5b3UuoIICfDCCAngwggH+oAMCAQICCQCls1QoG7BuOzAK
45BggqhkjOPQQDAzA/MQswCQYDVQQGEwJVUzELMAkGA1UECAwCVkExEDAOBgNVBAcM
46B0hlcm5kb24xETAPBgNVBAoMCEJvZ3VzIENBMB4XDTE5MDUyOTE0NDU0MVoXDTIw
47MDUyODE0NDU0MVowcDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlZBMRAwDgYDVQQH
48EwdIZXJuZG9uMRAwDgYDVQQKEwdFeGFtcGxlMQ4wDAYDVQQDEwVBbGljZTEgMB4G
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
850L0c2bbkom3WkPq/po/dPDuoaX61nKmztUHaL5r5QZzBBwKVyhdw9J0btnWAFPNK
86vzgy5U9iV4+6jXH5TCmlIreszwRPoqqEaYRIfmUpp2+zy91PpzjTs98tx/HIAbOM
87fT3WmuTahEnEHehABhwq+S4xwzoVIskLbrcOP6l7UYYR7GTUCjKxh7ru0rSwHrqG
889t33YdzJaFbz+8jb88xtf454Rvur66Cew/4GYX9u1Zef0DF9So1ay3IicpOf5emo
89VWIwg4bh7bELi78i/MbdWtNZQcXimykfeTsYH8Q4u+1uxHS5pwEWWwKiUnLQVpZP
902ut255TdgSIhEILwsaLVelRrx/lp14EpY355FOusXiju6g14aWfBnt5udvuTXxDQ
91ZHPPNNk+gwzgvvTey98T941hYUctjg0NApJiB66bfrlYB9mkc5ftg5zqhEasYH5C
924ajKKRNMM7zGlwSZvy8PPhnAeE3Q9LTnos0l4ygjQD/kMlvd7XSLW3GUzjyxtkG4
93gQh6LGvnafAbgu7GpcapKEppN86sXEePHiQjj92n103+TxMYWwtaO4iAwkjqdEdt
94avEHcXRcpdqC0st6nUwPAPAC4LKJbZgLQnNG+wlWIiCMMD56IdfQ7r/zGIr13MxC
95kjNNUdISoWWE5GnQMYHbMBMGCSqGSIb3DQEJFTEGBAQBAAAAMFcGCSqGSIb3DQEJ
96FDFKHkgAMwBmADcAMQBhAGYANgA1AC0AMQA2ADgANwAtADQANAA0AGEALQA5AGYA
97NAA2AC0AYwA4AGIAZQAxADkANABjADMAZQA4AGUwawYJKwYBBAGCNxEBMV4eXABN
98AGkAYwByAG8AcwBvAGYAdAAgAEUAbgBoAGEAbgBjAGUAZAAgAEMAcgB5AHAAdABv
99AGcAcgBhAHAAaABpAGMAIABQAHIAbwB2AGkAZABlAHIAIAB2ADEALgAwMIIDaAYJ
100KoZIhvcNAQcBoIIDWQSCA1UwggNRMIIDTQYLKoZIhvcNAQwKAQOgggMlMIIDIQYK
101KoZIhvcNAQkWAaCCAxEEggMNMIIDCTCCAfGgAwIBAgIQNu32hzqhCKdHATXzboyI
102ETANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDEwlhbm9ueW1vdXMwIBcNMTYwNzE5
103MjIwMDAxWhgPMjExNjA2MjUyMjAwMDFaMBQxEjAQBgNVBAMTCWFub255bW91czCC
104ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALy2sEJMGNdcDg6BI7mdFM5T
105lPzo5sKBzvUnagK5SKBJ11xMPN5toPTBzICB/XTWEB3AwpD0O+srSca+bsUAyedS
1065V4BNp8qCyEu5RNRR8qPHheJ/guhLT96/gGI4jlrUyUhFntPkLKODxu+7KanMy6K
107dD+PVE8shXRUZTYe4PG64/c7z3wapnf4XoCXkJRzCY5f3MKz3Ul039kVnTlJcikd
108C7I9I9RflXLwXVl4nxUbeeRt6Z8WVWS4pCq+14v2aVPvP3mtVmAYHedRkvS04Hrx
1094xx98D3NSSw6Z5OLkzqOcFw15fYmH2NLdhh34gSWJmaaCBAbuQ+1rx/42p7MvvsC
110AwEAAaNVMFMwFQYDVR0lBA4wDAYKKwYBBAGCNwoDBDAvBgNVHREEKDAmoCQGCisG
111AQQBgjcUAgOgFgwUYW5vbnltb3VzQHdpbmRvd3MteAAwCQYDVR0TBAIwADANBgkq
112hkiG9w0BAQUFAAOCAQEAuH7iqY0/MLozwFb39ILYAJDHE+HToZBQbHQP4YtienrU
113Stk60rIp0WH65lam7m/JhgAcItc/tV1L8mEnLrvvKcA+NeIL8sDOtM28azvgcOi0
114P3roeLLLRCuiykUaKmUcZEDm9cDYKIpJf7QetWQ3uuGTk9iRzpH79x2ix35BnyWQ
115Rr3INZzmX/+9YRvPBXKYl/89F/w1ORYArpI9XtjfuPWaGQmM4f1WRHE2t3qRyKFF
116ri7QiZdpcSx5zvsRHSyjfUMoKs+b6upk+P01lIhg/ewwYngGab+fZhF15pTNN2hx
1178PdNGcrGzrkNKCmJKrWCa2xczuMA+z8SCuC1tYTKmDEVMBMGCSqGSIb3DQEJFTEG
118BAQBAAAAMDswHzAHBgUrDgMCGgQUpWCP/fZR0TK5BwGuqvTd0+duiKcEFJTubF2k
119HktMK+isIjxOTk4yJTOOAgIH0A==
120"""
121
122    def setUp(self):
123        self.asn1Spec = rfc2985.AttributeSet()
124
125    def testDerCodec(self):
126        substrate = pem.readBase64fromText(self.pem_text)
127        asn1Object, rest = der_decode(substrate, asn1Spec=self.asn1Spec)
128        assert not rest
129        assert asn1Object.prettyPrint()
130        assert der_encode(asn1Object) == substrate
131
132        openTypesMap = {
133            rfc2985.pkcs_9_at_smimeCapabilities: rfc2985.SMIMECapabilities(),
134        }
135        openTypesMap.update(rfc5280.certificateAttributesMap)
136        openTypesMap.update(rfc5652.cmsAttributesMap)
137
138        for attr in asn1Object:
139            assert attr['type'] in openTypesMap.keys()
140            av, rest = der_decode(attr['values'][0],
141                asn1Spec=openTypesMap[attr['type']])
142            assert not rest
143            assert av.prettyPrint()
144            assert der_encode(av) == attr['values'][0]
145
146            if attr['type'] == rfc2985.pkcs_9_at_userPKCS12:
147                assert av['version'] == univ.Integer(3)
148                assert av['authSafe']['contentType'] == rfc5652.id_data
149                outdata, rest = der_decode(av['authSafe']['content'],
150                    asn1Spec=univ.OctetString())
151                assert not rest
152                authsafe, rest = der_decode(outdata,
153                    asn1Spec=rfc7292.AuthenticatedSafe())
154                assert not rest
155
156                for ci in authsafe:
157                    assert ci['contentType'] == rfc5652.id_data
158                    indata, rest = der_decode(ci['content'],
159                        asn1Spec=univ.OctetString())
160                    assert not rest
161                    sc, rest = der_decode(indata,
162                        asn1Spec=rfc7292.SafeContents())
163                    assert not rest
164
165                    for sb in sc:
166                        if sb['bagId'] in rfc7292.pkcs12BagTypeMap:
167                            bv, rest = der_decode(sb['bagValue'],
168                                asn1Spec=rfc7292.pkcs12BagTypeMap[sb['bagId']])
169                            assert not rest
170
171                            for bagattr in sb['bagAttributes']:
172                                if bagattr['attrType'] in openTypesMap:
173                                    inav, rest = der_decode(bagattr['attrValues'][0],
174                                        asn1Spec=openTypesMap[bagattr['attrType']])
175                                    assert not rest
176
177                                    if bagattr['attrType'] == rfc2985.pkcs_9_at_friendlyName:
178                                        assert inav == "3f71af65-1687-444a-9f46-c8be194c3e8e"
179
180                                    if bagattr['attrType'] == rfc2985.pkcs_9_at_localKeyId:
181                                        assert inav == univ.OctetString(hexValue='01000000')
182
183            if attr['type'] == rfc2985.pkcs_9_at_pkcs7PDU:
184                ci, rest = der_decode(attr['values'][0],
185                    asn1Spec=rfc5652.ContentInfo())
186                assert not rest
187                assert ci['contentType'] == rfc5652.id_signedData
188
189                sd, rest = der_decode(ci['content'],
190                    asn1Spec=rfc5652.SignedData())
191                assert not rest
192                assert sd['version'] == 1
193
194                for si in sd['signerInfos']:
195                    assert si['version'] == 1
196
197                    for siattr in si['signedAttrs']:
198                        if siattr['attrType'] in openTypesMap:
199                            siav, rest = der_decode(siattr['attrValues'][0],
200                                asn1Spec=openTypesMap[siattr['attrType']])
201                            assert not rest
202
203                            if siattr['attrType'] == rfc2985.pkcs_9_at_contentType:
204                                assert siav == rfc5652.id_data
205
206                            if siattr['attrType'] == rfc2985.pkcs_9_at_messageDigest:
207                                assert siav.prettyPrint()[2:10] == 'b6e422a4'
208
209                            if siattr['attrType'] == rfc2985.pkcs_9_at_signingTime:
210                                assert siav['utcTime'] == '190529182319Z'
211
212                for choices in sd['certificates']:
213                    for rdn in choices[0]['tbsCertificate']['subject']['rdnSequence']:
214                        if rdn[0]['type'] in openTypesMap:
215                            nv, rest = der_decode(rdn[0]['value'],
216                                 asn1Spec=openTypesMap[rdn[0]['type']])
217                            assert not rest
218
219                            if rdn[0]['type'] == rfc2985.pkcs_9_at_emailAddress:
220                                assert nv == '[email protected]'
221
222    def testOpenTypes(self):
223        openTypesMap = {
224            rfc2985.pkcs_9_at_smimeCapabilities: rfc2985.SMIMECapabilities(),
225        }
226        openTypesMap.update(rfc5280.certificateAttributesMap)
227        openTypesMap.update(rfc5652.cmsAttributesMap)
228
229        substrate = pem.readBase64fromText(self.pem_text)
230        asn1Object, rest = der_decode(substrate,
231            asn1Spec=self.asn1Spec,
232            openTypes=openTypesMap,
233            decodeOpenTypes=True)
234        assert not rest
235        assert asn1Object.prettyPrint()
236        assert der_encode(asn1Object) == substrate
237
238        for attr in asn1Object:
239            assert attr['type'] in openTypesMap.keys()
240
241            if attr['type'] == rfc2985.pkcs_9_at_userPKCS12:
242                assert attr['values'][0]['version'] == univ.Integer(3)
243                assert attr['values'][0]['authSafe']['contentType'] == rfc5652.id_data
244                authsafe, rest = der_decode(attr['values'][0]['authSafe']['content'],
245                    asn1Spec=rfc7292.AuthenticatedSafe())
246                assert not rest
247
248                for ci in authsafe:
249                    assert ci['contentType'] == rfc5652.id_data
250                    indata, rest = der_decode(ci['content'],
251                       asn1Spec=univ.OctetString())
252                    assert not rest
253
254                    sc, rest = der_decode(indata,
255                        asn1Spec=rfc7292.SafeContents(),
256                        decodeOpenTypes=True)
257                    assert not rest
258
259                    for sb in sc:
260                        if sb['bagId'] in rfc7292.pkcs12BagTypeMap:
261                            for bagattr in sb['bagAttributes']:
262                                if bagattr['attrType'] in openTypesMap:
263
264                                    if bagattr['attrType'] == rfc2985.pkcs_9_at_friendlyName:
265                                        assert bagattr['attrValues'][0] == "3f71af65-1687-444a-9f46-c8be194c3e8e"
266
267                                    if bagattr['attrType'] == rfc2985.pkcs_9_at_localKeyId:
268                                        assert bagattr['attrValues'][0] == univ.OctetString(hexValue='01000000')
269
270            if attr['type'] == rfc2985.pkcs_9_at_pkcs7PDU:
271                assert attr['values'][0]['contentType'] == rfc5652.id_signedData
272                assert attr['values'][0]['content']['version'] == 1
273
274                for si in attr['values'][0]['content']['signerInfos']:
275                    assert si['version'] == 1
276
277                    for siattr in si['signedAttrs']:
278                        if siattr['attrType'] in openTypesMap:
279
280                            if siattr['attrType'] == rfc2985.pkcs_9_at_contentType:
281                                assert siattr['attrValues'][0] == rfc5652.id_data
282
283                            if siattr['attrType'] == rfc2985.pkcs_9_at_messageDigest:
284                                assert siattr['attrValues'][0].prettyPrint()[2:10] == 'b6e422a4'
285
286                            if siattr['attrType'] == rfc2985.pkcs_9_at_signingTime:
287                                assert siattr['attrValues'][0]['utcTime'] == '190529182319Z'
288
289                for choices in attr['values'][0]['content']['certificates']:
290                    for rdn in choices[0]['tbsCertificate']['subject']['rdnSequence']:
291                        if rdn[0]['type'] in openTypesMap:
292                            if rdn[0]['type'] == rfc2985.pkcs_9_at_emailAddress:
293                                assert rdn[0]['value'] == '[email protected]'
294
295
296suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
297
298if __name__ == '__main__':
299    unittest.TextTestRunner(verbosity=2).run(suite)
300