]> www.wagner.pp.ru Git - oss/ctypescrypto.git/blob - tests/testx509.py
Add X509 to __all__. Add pem() method to X509
[oss/ctypescrypto.git] / tests / testx509.py
1 #!/usr/bin/env python
2 # -*- encoding: utf-8 -*-
3
4 from ctypescrypto.x509 import X509,X509Store,utc,StackOfX509
5 from ctypescrypto.oid import Oid
6 from tempfile import NamedTemporaryFile
7 import datetime
8 import unittest
9
10
11
12 class TestCertInfo(unittest.TestCase):
13         ca_cert="""-----BEGIN CERTIFICATE-----
14 MIIEDzCCAvegAwIBAgIJAN9Ejmna3JJ7MA0GCSqGSIb3DQEBBQUAMIGdMQswCQYD
15 VQQGEwJSVTEVMBMGA1UECAwM0JzQvtGB0LrQstCwMTAwLgYDVQQKDCfQo9C00L7R
16 gdGC0L7QstC10YDRj9GO0YnQuNC5INGG0LXQvdGC0YAxIjAgBgNVBAMMGdCS0LjQ
17 utGC0L7RgCDQktCw0LPQvdC10YAxITAfBgkqhkiG9w0BCQEWEnZpdHVzQHdhZ25l
18 ci5wcC5ydTAeFw0xNDEwMjYxNDQ2MzJaFw0xNzEwMjUxNDQ2MzJaMIGdMQswCQYD
19 VQQGEwJSVTEVMBMGA1UECAwM0JzQvtGB0LrQstCwMTAwLgYDVQQKDCfQo9C00L7R
20 gdGC0L7QstC10YDRj9GO0YnQuNC5INGG0LXQvdGC0YAxIjAgBgNVBAMMGdCS0LjQ
21 utGC0L7RgCDQktCw0LPQvdC10YAxITAfBgkqhkiG9w0BCQEWEnZpdHVzQHdhZ25l
22 ci5wcC5ydTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJn+nL8CDaM0
23 KNafGYdEDuFuCKHFxCcbaT7ecGbwjPKtnqZLOnYpa2iLFY+n7zAYw1MRkFkaR8b+
24 +AeFPWS9T60ygeWysT9XTS77Fdl69Tmr8HChRk0BuLB3vFCy34vBHSG6Frdm8PtS
25 PLEleldiwUCHLS+EckrnJylQK13X3HofSbIGzKK53MsuQOtp2dJw3b7MILM/+XBm
26 RgZlEbTEPYMOH8CE3mu9/LqXfIRQM7+nmzcNZI3RAwxEVHOSHEbgFZaksTj8rMIa
27 SrJwknmxHntI3P5PSNNbs0SO3TW8ePDIIpbVcjNsMX4qGX8b+8quZuzciKOto8S0
28 0A6eOBd8Vi0CAwEAAaNQME4wHQYDVR0OBBYEFKzcbd6+N1TKfBjvmyTvw8+DnzAZ
29 MB8GA1UdIwQYMBaAFKzcbd6+N1TKfBjvmyTvw8+DnzAZMAwGA1UdEwQFMAMBAf8w
30 DQYJKoZIhvcNAQEFBQADggEBAAa1PpkpL842hh8jLXIpA/nK8aVDDcu5p3pA72/b
31 noFnZuKcuaSUOz1rrLqxDK2JB3lmChQaVx3pZwqJgA0h0XBScar+8wM2TfeyW+oU
32 Gr5tOAxoHVRpgn6oCoJkKo0HS2/NA12T/gYsXhXJXn4tuvDjaUzY+K+hhAWh64oL
33 /c61eKfCZKp50t9Eoua0xHII2Mveb27Ps46j/CZ1r0ts7sGieOqjQo3GZOOikG6F
34 vFY/2KV16/FdBovTFWMyKrzlYHm0Wgt28IWqhocq/golLfvkz3VAkLQvOF2i6hNc
35 4feBv69SRTsTCFN9PtJCtxPX/K9LZKeccBKgGjrHQpAF+JU=
36 -----END CERTIFICATE-----
37 """
38         cert1="""-----BEGIN CERTIFICATE-----
39 MIIEDzCCAvegAwIBAgIJAN9Ejmna3JJ8MA0GCSqGSIb3DQEBBQUAMIGdMQswCQYD
40 VQQGEwJSVTEVMBMGA1UECAwM0JzQvtGB0LrQstCwMTAwLgYDVQQKDCfQo9C00L7R
41 gdGC0L7QstC10YDRj9GO0YnQuNC5INGG0LXQvdGC0YAxIjAgBgNVBAMMGdCS0LjQ
42 utGC0L7RgCDQktCw0LPQvdC10YAxITAfBgkqhkiG9w0BCQEWEnZpdHVzQHdhZ25l
43 ci5wcC5ydTAeFw0xNDEwMjYxOTA3MTdaFw0yNDEwMjMxOTA3MTdaMIGBMQswCQYD
44 VQQGEwJSVTEVMBMGA1UECAwM0JzQvtGB0LrQstCwMRUwEwYDVQQHDAzQnNC+0YHQ
45 utCy0LAxIDAeBgNVBAoMF9Cn0LDRgdGC0L3QvtC1INC70LjRhtC+MSIwIAYDVQQD
46 DBnQktC40LrRgtC+0YAg0JLQsNCz0L3QtdGAMIIBIjANBgkqhkiG9w0BAQEFAAOC
47 AQ8AMIIBCgKCAQEArQSfrrxNROyzNEz60G2EHBP+E4BL0b1QytGAZZiQp2XIhhQe
48 b7mx+c4mpwgvD7/IdAcK+YVGx78nfY723T3wG48U7HzFNbLvNDycxyXecXbvCmRs
49 xPy8TxkwPf6TIT3UcixtwMMqZFqlAtSTDmOOWSaUuftL/+yFk729xDoYkOZhFwUS
50 UM5SbEZ0JpufWFjDi3Qwj3ZOTXliHC3e4C7187Me0Nne59dttyKpq1YAThn4Srar
51 vZYU6Ykk/LUae0FCvfeiKLShWY05XnPVmvPiiFTXJP8/Au8kfezlA4b+eS81zWq2
52 BFvNlBQsgf04S88oew0CuBBgtjUIIw7XZkS03QIDAQABo2wwajAJBgNVHRMEAjAA
53 MB0GA1UdDgQWBBRflZBerCFYheRQne/sWL3zY7GiAzAfBgNVHSMEGDAWgBSs3G3e
54 vjdUynwY75sk78PPg58wGTAdBgNVHREEFjAUgRJ2aXR1c0B3YWduZXIucHAucnUw
55 DQYJKoZIhvcNAQEFBQADggEBAGx1z0ylq90hP3x/2DmfVUYBA46CiGnV4NSiaOWE
56 Y18jCuG3W8FcI7JP4uEEjKyz3XbuhTFW2GsZ2L3FGgpA5eXBikgCn5kRpOHgb45r
57 SxE8u3TwVlYlaF+7RHPYLqmgb25d/O/28McemMmTGecPC9edbtDqLv03aJ0t4gXn
58 BD+xTJOP74Yhu5IPIV92J6pSBpIoy+qiyOA1iRpOWzrVHVR504vAaFxlfZs3VJhP
59 uo291iEXyooazJdbWwZwcwk7WrNNKhqktPTg0X1ZHNnGwOAGPzwNJFGPeFj71r0t
60 aFWU5EMRKaZK75keXq/RdaOAenl+nKF6xA2XHDhGgdndFfY=
61 -----END CERTIFICATE-----
62 """
63         pubkey1="""-----BEGIN PUBLIC KEY-----
64 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArQSfrrxNROyzNEz60G2E
65 HBP+E4BL0b1QytGAZZiQp2XIhhQeb7mx+c4mpwgvD7/IdAcK+YVGx78nfY723T3w
66 G48U7HzFNbLvNDycxyXecXbvCmRsxPy8TxkwPf6TIT3UcixtwMMqZFqlAtSTDmOO
67 WSaUuftL/+yFk729xDoYkOZhFwUSUM5SbEZ0JpufWFjDi3Qwj3ZOTXliHC3e4C71
68 87Me0Nne59dttyKpq1YAThn4SrarvZYU6Ykk/LUae0FCvfeiKLShWY05XnPVmvPi
69 iFTXJP8/Au8kfezlA4b+eS81zWq2BFvNlBQsgf04S88oew0CuBBgtjUIIw7XZkS0
70 3QIDAQAB
71 -----END PUBLIC KEY-----
72 """
73         digicert_cert="""digicert.crt
74 -----BEGIN CERTIFICATE-----
75 MIIG5jCCBc6gAwIBAgIQAze5KDR8YKauxa2xIX84YDANBgkqhkiG9w0BAQUFADBs
76 MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
77 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
78 ZSBFViBSb290IENBMB4XDTA3MTEwOTEyMDAwMFoXDTIxMTExMDAwMDAwMFowaTEL
79 MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
80 LmRpZ2ljZXJ0LmNvbTEoMCYGA1UEAxMfRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
81 RVYgQ0EtMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPOWYth1bhn/
82 PzR8SU8xfg0ETpmB4rOFVZEwscCvcLssqOcYqj9495BoUoYBiJfiOwZlkKq9ZXbC
83 7L4QWzd4g2B1Rca9dKq2n6Q6AVAXxDlpufFP74LByvNK28yeUE9NQKM6kOeGZrzw
84 PnYoTNF1gJ5qNRQ1A57bDIzCKK1Qss72kaPDpQpYSfZ1RGy6+c7pqzoC4E3zrOJ6
85 4GAiBTyC01Li85xH+DvYskuTVkq/cKs+6WjIHY9YHSpNXic9rQpZL1oRIEDZaARo
86 LfTAhAsKG3jf7RpY3PtBWm1r8u0c7lwytlzs16YDMqbo3rcoJ1mIgP97rYlY1R4U
87 pPKwcNSgPqcCAwEAAaOCA4UwggOBMA4GA1UdDwEB/wQEAwIBhjA7BgNVHSUENDAy
88 BggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUH
89 AwgwggHEBgNVHSAEggG7MIIBtzCCAbMGCWCGSAGG/WwCATCCAaQwOgYIKwYBBQUH
90 AgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5o
91 dG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0
92 AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1
93 AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABp
94 AGcAaQBDAGUAcgB0ACAARQBWACAAQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBl
95 AGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBo
96 AGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAg
97 AGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAg
98 AGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wEgYDVR0TAQH/BAgwBgEB/wIBADCB
99 gwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
100 dC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NBQ2Vy
101 dHMvRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3J0MIGPBgNVHR8EgYcw
102 gYQwQKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hB
103 c3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0
104 LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwHQYDVR0OBBYE
105 FExYyyXwQU9S9CjIgUObpqig5pLlMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoI
106 Au9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQBMeheHKF0XvLIyc7/NLvVYMR3wsXFU
107 nNabZ5PbLwM+Fm8eA8lThKNWYB54lBuiqG+jpItSkdfdXJW777UWSemlQk808kf/
108 roF/E1S3IMRwFcuBCoHLdFfcnN8kpCkMGPAc5K4HM+zxST5Vz25PDVR708noFUjU
109 xbvcNRx3RQdIRYW9135TuMAW2ZXNi419yWBP0aKb49Aw1rRzNubS+QOy46T15bg+
110 BEkAui6mSnKDcp33C4ypieez12Qf1uNgywPE3IjpnSUBAHHLA7QpYCWP+UbRe3Gu
111 zVMSW4SOwg/H7ZMZ2cn6j1g0djIvruFQFGHUqFijyDATI+/GJYw2jxyA
112 -----END CERTIFICATE-----
113 """
114         def test_readpubkey(self):
115                 c=X509(self.cert1)
116                 p=c.pubkey
117                 self.assertEqual(p.exportpub(),self.pubkey1)
118         def test_pem(self):
119                 c=X509(self.cert1)
120                 self.assertEqual(c.pem(),self.cert1)
121         def test_subject(self):
122                 c=X509(self.cert1)
123                 self.assertEqual(unicode(c.subject),u'C=RU,ST=Москва,L=Москва,O=Частное лицо,CN=Виктор Вагнер')
124         def test_subject_str(self):
125                 c=X509(self.cert1)
126                 self.assertEqual(str(c.subject),b'C=RU,ST=\\D0\\9C\\D0\\BE\\D1\\81\\D0\\BA\\D0\\B2\\D0\\B0,L=\\D0\\9C\\D0\\BE\\D1\\81\\D0\\BA\\D0\\B2\\D0\\B0,O=\\D0\\A7\\D0\\B0\\D1\\81\\D1\\82\\D0\\BD\\D0\\BE\\D0\\B5 \\D0\\BB\\D0\\B8\\D1\\86\\D0\\BE,CN=\\D0\\92\\D0\\B8\\D0\\BA\\D1\\82\\D0\\BE\\D1\\80 \\D0\\92\\D0\\B0\\D0\\B3\\D0\\BD\\D0\\B5\\D1\\80')
127         def test_subject_len(self):
128                 c=X509(self.cert1)
129                 self.assertEqual(len(c.subject),5)
130         def test_issuer(self):
131                 c=X509(self.cert1)
132                 self.assertEqual(unicode(c.issuer),u'C=RU,ST=Москва,O=Удостоверяющий центр,CN=Виктор Вагнер,emailAddress=vitus@wagner.pp.ru')
133         def test_subjectfields(self):
134                 c=X509(self.cert1)
135                 self.assertEqual(c.subject[Oid("C")],"RU")
136                 with self.assertRaises(TypeError):
137                         x=c.subject["CN"]
138                 self.assertEqual(c.subject[Oid("L")],u'\u041c\u043e\u0441\u043a\u0432\u0430')
139         def test_subjectmodify(self):
140                 c=X509(self.cert1)
141                 with self.assertRaises(ValueError):
142                         c.subject[Oid("CN")]=u'Foo'
143                 with self.assertRaises(ValueError):
144                         del c.subject[Oid('CN')]
145         def test_subjectbadsubfield(self):
146                 c=X509(self.cert1)
147                 with self.assertRaises(KeyError):
148                         x=c.subject[Oid("streetAddress")]
149         def test_subjectfieldindex(self):
150                 c=X509(self.cert1)
151                 self.assertEqual(repr(c.subject[0]),repr((Oid('C'),u'RU')))
152         def test_subjectbadindex(self):
153                 c=X509(self.cert1)
154                 with self.assertRaises(IndexError):
155                         x=c.subject[11]
156                 with self.assertRaises(IndexError):
157                         x=c.subject[-1]
158         def test_notBefore(self):
159                 c=X509(self.cert1)
160                 self.assertEqual(c.startDate,datetime.datetime(2014,10,26,19,07,17,0,utc))
161         def test_notAfter(self):
162                 c=X509(self.cert1)
163                 self.assertEqual(c.endDate,datetime.datetime(2024,10,23,19,7,17,0,utc))
164         def test_subjectHash(self):
165                 c=X509(self.cert1)
166                 self.assertEqual(hash(c.subject),0x1f3ed722)
167         def test_issuerHash(self):
168                 c=X509(self.cert1)
169                 self.assertEqual(hash(c.issuer),0x7d3ea8c3)
170         def test_namecomp(self):
171                 c=X509(self.cert1)
172                 ca=X509(self.ca_cert)
173                 self.assertEqual(c.issuer,ca.subject)
174                 self.assertNotEqual(c.subject,c.issuer)
175                 self.assertEqual(ca.issuer,ca.subject)
176         def test_serial(self):
177                 c=X509(self.cert1)
178                 self.assertEqual(c.serial,0xDF448E69DADC927CL)
179         def test_version(self):
180                 c=X509(self.cert1)
181                 self.assertEqual(c.version,3)
182         def test_ca_cert(self):
183                 ca=X509(self.ca_cert)
184                 self.assertTrue(ca.check_ca())
185                 notca=X509(self.cert1)
186                 self.assertFalse(notca.check_ca())
187         def test_extension_count(self):
188                 cert=X509(self.cert1)
189                 self.assertTrue(len(cert.extensions),4)
190                 ca_cert=X509(self.ca_cert)
191                 self.assertEqual(len(ca_cert.extensions),3)
192         def test_extension_outofrange(self):
193                 cert=X509(self.cert1)
194                 with self.assertRaises(IndexError):
195                         cert.extensions[4]
196                 with self.assertRaises(IndexError):
197                         cert.extensions[-1]
198         def test_extension_oid(self):
199                 cert=X509(self.cert1)
200                 ext=cert.extensions[0]
201                 ext_id=ext.oid
202                 self.assertTrue(isinstance(ext_id,Oid))
203                 self.assertEqual(ext_id,Oid('basicConstraints'))
204         def test_extension_text(self):
205                 cert=X509(self.cert1)
206                 ext=cert.extensions[0]
207                 self.assertEqual(str(ext),'CA:FALSE')
208                 self.assertEqual(unicode(ext),u'CA:FALSE')
209         def test_extenson_find(self):
210                 cert=X509(self.cert1)
211                 exts=cert.extensions.find(Oid('subjectAltName'))
212                 self.assertEqual(len(exts),1)
213                 self.assertEqual(exts[0].oid,Oid('subjectAltName'))
214         def test_extension_bad_find(self):
215                 cert=X509(self.cert1)
216                 with self.assertRaises(TypeError):
217                         exts=cert.extensions.find('subjectAltName')
218         def test_extenson_critical(self):
219                 cert=X509(self.digicert_cert)
220                 crit_exts=cert.extensions.find_critical()
221                 self.assertEqual(len(crit_exts),2)
222                 other_exts=cert.extensions.find_critical(False)
223                 self.assertEqual(len(crit_exts)+len(other_exts),len(cert.extensions))
224                 self.assertEqual(crit_exts[0].critical,True)
225                 self.assertEqual(other_exts[0].critical,False)
226         def test_verify_by_key(self):
227                 ca=X509(self.ca_cert)
228                 pubkey=ca.pubkey
229                 self.assertTrue(ca.verify(key=pubkey))
230                 c=X509(self.cert1)
231                 pk2=c.pubkey
232                 self.assertFalse(c.verify(key=pk2))
233                 self.assertTrue(c.verify(key=pubkey))
234         def test_verify_self_singed(self):
235                 ca=X509(self.ca_cert)
236                 self.assertTrue(ca.verify())
237         def test_default_filestore(self):
238                 store=X509Store(default=True)
239                 c1=X509(self.cert1)
240                 # Cert signed by our CA shouldn't be successfully verified
241                 # by default CA store
242                 self.assertFalse(c1.verify(store))
243                 # but cert, downloaded from some commercial CA - should.
244                 c2=X509(self.digicert_cert)
245                 self.assertTrue(c2.verify(store))
246         def test_verify_by_filestore(self):
247                 trusted=NamedTemporaryFile()
248                 trusted.write(self.ca_cert)
249                 trusted.flush()
250                 goodcert=X509(self.cert1)
251                 badcert=X509(self.cert1[0:-30]+"GG"+self.cert1[-28:])
252                 gitcert=X509(self.digicert_cert)
253                 store=X509Store(file=trusted.name)
254                 # We should successfuly verify certificate signed by our CA cert
255                 self.assertTrue(goodcert.verify(store))
256                 # We should reject corrupted certificate
257                 self.assertFalse(badcert.verify(store))
258                 # And if we specify explicitely certificate file, certificate,
259                 # signed by some commercial CA should be rejected too
260                 self.assertFalse(gitcert.verify(store))
261                 trusted.close()
262         def test_verify_by_dirstore(self):
263                 pass
264         def test_certstack1(self):
265                 l=[]
266                 l.append(X509(self.cert1))
267                 self.assertEqual(unicode(l[0].subject[Oid('CN')]),u'Виктор Вагнер')
268                 l.append(X509(self.ca_cert))
269                 l.append(X509(self.digicert_cert))
270                 stack=StackOfX509(certs=l)
271                 self.assertEqual(len(stack),3)
272                 self.assertTrue(isinstance(stack[1],X509))
273                 self.assertEqual(unicode(stack[0].subject[Oid('CN')]),u'Виктор Вагнер')
274                 with self.assertRaises(IndexError):
275                         c=stack[-1]
276                 with self.assertRaises(IndexError):
277                         c=stack[3]
278                 del stack[1]
279                 self.assertEqual(len(stack),2)
280                 self.assertEqual(unicode(stack[0].subject[Oid('CN')]),u'Виктор Вагнер')
281                 self.assertEqual(unicode(stack[1].subject[Oid('CN')]),u'DigiCert High Assurance EV CA-1')
282         def test_certstack2(self):
283                 stack=StackOfX509()
284                 stack.append(X509(self.cert1))
285                 stack.append(X509(self.ca_cert))
286                 c=stack[1]
287                 stack[1]=X509(self.digicert_cert)
288                 self.assertEqual(len(stack),2)
289                 self.assertEqual(unicode(stack[1].subject[Oid('CN')]),u'DigiCert High Assurance EV CA-1')
290                 with self.assertRaises(IndexError):
291                         stack[-1]=c
292                 with self.assertRaises(IndexError):
293                         stack[3]=c
294                 with self.assertRaises(TypeError):
295                         stack[0]=self.cert1
296                 with self.assertRaises(TypeError):
297                         stack.append(self.cert1)
298         def test_certstack3(self):
299                 l=[]
300                 l.append(X509(self.cert1))
301                 self.assertEqual(unicode(l[0].subject[Oid('CN')]),u'Виктор Вагнер')
302                 l.append(X509(self.ca_cert))
303                 l.append(X509(self.digicert_cert))
304                 stack=StackOfX509(certs=l)
305                 stack2=StackOfX509(ptr=stack.ptr,disposable=False)
306                 with self.assertRaises(ValueError):
307                         stack3=StackOfX509(ptr=stack.ptr,certs=l)
308                 with self.assertRaises(ValueError):
309                         stack2[1]=l[0]
310                 with self.assertRaises(ValueError):
311                         stack2.append(l[0])
312 if __name__ == '__main__':
313         unittest.main()