blob: 7649f44ebec3c6e7d3949005434b566b66c965a7 [file] [log] [blame]
Jean-Paul Calderone8b63d452008-03-21 18:31:12 -04001# Copyright (C) Jean-Paul Calderone 2008, All rights reserved
2
Jean-Paul Calderoned8782ad2008-03-04 23:39:59 -05003"""
4Unit tests for L{OpenSSL.crypto}.
5"""
6
7from unittest import TestCase
8
9from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType
Jean-Paul Calderone78381d22008-03-06 23:35:22 -050010from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType
Jean-Paul Calderone2aa2b332008-03-06 21:43:14 -050011from OpenSSL.crypto import X509Req, X509ReqType
Jean-Paul Calderone38a646d2008-03-25 15:16:18 -040012from OpenSSL.crypto import FILETYPE_PEM, load_certificate
Jean-Paul Calderoned8782ad2008-03-04 23:39:59 -050013
Jean-Paul Calderoneac930e12008-03-06 18:50:51 -050014class _Python23TestCaseHelper:
Jean-Paul Calderone7da26a72008-03-06 00:35:20 -050015 # Python 2.3 compatibility.
16 def assertTrue(self, *a, **kw):
17 return self.failUnless(*a, **kw)
18
19
Jean-Paul Calderone7535dab2008-03-06 18:53:11 -050020 def assertFalse(self, *a, **kw):
21 return self.failIf(*a, **kw)
22
23
24
Jean-Paul Calderoneac930e12008-03-06 18:50:51 -050025class PKeyTests(TestCase, _Python23TestCaseHelper):
26 """
27 Unit tests for L{OpenSSL.crypto.PKey}.
28 """
Jean-Paul Calderoned8782ad2008-03-04 23:39:59 -050029 def test_construction(self):
30 """
31 L{PKey} takes no arguments and returns a new L{PKeyType} instance.
32 """
33 self.assertRaises(TypeError, PKey, None)
34 key = PKey()
35 self.assertTrue(
36 isinstance(key, PKeyType),
37 "%r is of type %r, should be %r" % (key, type(key), PKeyType))
38
39
40 def test_pregeneration(self):
41 """
42 L{PKeyType.bits} and L{PKeyType.type} return C{0} before the key is
43 generated.
44 """
45 key = PKey()
46 self.assertEqual(key.type(), 0)
47 self.assertEqual(key.bits(), 0)
48
49
50 def test_failedGeneration(self):
51 """
Jean-Paul Calderoneab82db72008-03-06 00:09:31 -050052 L{PKeyType.generate_key} takes two arguments, the first giving the key
53 type as one of L{TYPE_RSA} or L{TYPE_DSA} and the second giving the
54 number of bits to generate. If an invalid type is specified or
55 generation fails, L{Error} is raised. If an invalid number of bits is
56 specified, L{ValueError} or L{Error} is raised.
Jean-Paul Calderoned8782ad2008-03-04 23:39:59 -050057 """
58 key = PKey()
59 self.assertRaises(TypeError, key.generate_key)
60 self.assertRaises(TypeError, key.generate_key, 1, 2, 3)
61 self.assertRaises(TypeError, key.generate_key, "foo", "bar")
62 self.assertRaises(Error, key.generate_key, -1, 0)
Jean-Paul Calderoneab82db72008-03-06 00:09:31 -050063
Jean-Paul Calderoneab82db72008-03-06 00:09:31 -050064 self.assertRaises(ValueError, key.generate_key, TYPE_RSA, -1)
65 self.assertRaises(ValueError, key.generate_key, TYPE_RSA, 0)
Jean-Paul Calderoned71fe982008-03-06 00:31:50 -050066
67 # XXX RSA generation for small values of bits is fairly buggy in a wide
68 # range of OpenSSL versions. I need to figure out what the safe lower
69 # bound for a reasonable number of OpenSSL versions is and explicitly
70 # check for that in the wrapper. The failure behavior is typically an
71 # infinite loop inside OpenSSL.
72
73 # self.assertRaises(Error, key.generate_key, TYPE_RSA, 2)
Jean-Paul Calderoned8782ad2008-03-04 23:39:59 -050074
75 # XXX DSA generation seems happy with any number of bits. The DSS
76 # says bits must be between 512 and 1024 inclusive. OpenSSL's DSA
77 # generator doesn't seem to care about the upper limit at all. For
Jean-Paul Calderoneeff3cd92008-03-05 22:35:26 -050078 # the lower limit, it uses 512 if anything smaller is specified.
Jean-Paul Calderoned8782ad2008-03-04 23:39:59 -050079 # So, it doesn't seem possible to make generate_key fail for
80 # TYPE_DSA with a bits argument which is at least an int.
81
82 # self.assertRaises(Error, key.generate_key, TYPE_DSA, -7)
83
84
85 def test_rsaGeneration(self):
86 """
87 L{PKeyType.generate_key} generates an RSA key when passed
88 L{TYPE_RSA} as a type and a reasonable number of bits.
89 """
90 bits = 128
91 key = PKey()
92 key.generate_key(TYPE_RSA, bits)
93 self.assertEqual(key.type(), TYPE_RSA)
94 self.assertEqual(key.bits(), bits)
95
96
97 def test_dsaGeneration(self):
98 """
99 L{PKeyType.generate_key} generates a DSA key when passed
100 L{TYPE_DSA} as a type and a reasonable number of bits.
101 """
102 # 512 is a magic number. The DSS (Digital Signature Standard)
103 # allows a minimum of 512 bits for DSA. DSA_generate_parameters
104 # will silently promote any value below 512 to 512.
105 bits = 512
106 key = PKey()
107 key.generate_key(TYPE_DSA, bits)
108 self.assertEqual(key.type(), TYPE_DSA)
109 self.assertEqual(key.bits(), bits)
110
111
112 def test_regeneration(self):
113 """
114 L{PKeyType.generate_key} can be called multiple times on the same
115 key to generate new keys.
116 """
117 key = PKey()
118 for type, bits in [(TYPE_RSA, 512), (TYPE_DSA, 576)]:
119 key.generate_key(type, bits)
120 self.assertEqual(key.type(), type)
121 self.assertEqual(key.bits(), bits)
Jean-Paul Calderoneeff3cd92008-03-05 22:35:26 -0500122
123
124
Jean-Paul Calderoneac930e12008-03-06 18:50:51 -0500125class X509NameTests(TestCase, _Python23TestCaseHelper):
Jean-Paul Calderoneeff3cd92008-03-05 22:35:26 -0500126 """
127 Unit tests for L{OpenSSL.crypto.X509Name}.
128 """
Jean-Paul Calderonee098dc72008-03-06 18:36:19 -0500129 def _x509name(self, **attrs):
130 # XXX There's no other way to get a new X509Name yet.
131 name = X509().get_subject()
132 attrs = attrs.items()
133 # Make the order stable - order matters!
134 attrs.sort(lambda (k1, v1), (k2, v2): cmp(v1, v2))
135 for k, v in attrs:
136 setattr(name, k, v)
137 return name
138
139
Jean-Paul Calderoneeff3cd92008-03-05 22:35:26 -0500140 def test_attributes(self):
141 """
142 L{X509NameType} instances have attributes for each standard (?)
143 X509Name field.
144 """
Jean-Paul Calderonee098dc72008-03-06 18:36:19 -0500145 name = self._x509name()
Jean-Paul Calderoneeff3cd92008-03-05 22:35:26 -0500146 name.commonName = "foo"
147 self.assertEqual(name.commonName, "foo")
148 self.assertEqual(name.CN, "foo")
149 name.CN = "baz"
150 self.assertEqual(name.commonName, "baz")
151 self.assertEqual(name.CN, "baz")
152 name.commonName = "bar"
153 self.assertEqual(name.commonName, "bar")
154 self.assertEqual(name.CN, "bar")
155 name.CN = "quux"
156 self.assertEqual(name.commonName, "quux")
157 self.assertEqual(name.CN, "quux")
158
159
Jean-Paul Calderoneeff3cd92008-03-05 22:35:26 -0500160 def test_copy(self):
161 """
162 L{X509Name} creates a new L{X509NameType} instance with all the same
163 attributes as an existing L{X509NameType} instance when called with
164 one.
165 """
Jean-Paul Calderonee098dc72008-03-06 18:36:19 -0500166 name = self._x509name(commonName="foo", emailAddress="bar@example.com")
Jean-Paul Calderoneeff3cd92008-03-05 22:35:26 -0500167
168 copy = X509Name(name)
169 self.assertEqual(copy.commonName, "foo")
170 self.assertEqual(copy.emailAddress, "bar@example.com")
Jean-Paul Calderonee098dc72008-03-06 18:36:19 -0500171
172 # Mutate the copy and ensure the original is unmodified.
Jean-Paul Calderoneeff3cd92008-03-05 22:35:26 -0500173 copy.commonName = "baz"
174 self.assertEqual(name.commonName, "foo")
Jean-Paul Calderonee098dc72008-03-06 18:36:19 -0500175
176 # Mutate the original and ensure the copy is unmodified.
Jean-Paul Calderoneeff3cd92008-03-05 22:35:26 -0500177 name.emailAddress = "quux@example.com"
178 self.assertEqual(copy.emailAddress, "bar@example.com")
179
Jean-Paul Calderonee098dc72008-03-06 18:36:19 -0500180
181 def test_repr(self):
182 """
183 L{repr} passed an L{X509NameType} instance should return a string
184 containing a description of the type and the NIDs which have been set
185 on it.
186 """
187 name = self._x509name(commonName="foo", emailAddress="bar")
188 self.assertEqual(
189 repr(name),
190 "<X509Name object '/emailAddress=bar/CN=foo'>")
191
192
193 def test_comparison(self):
194 """
195 L{X509NameType} instances should compare based on their NIDs.
196 """
197 def _equality(a, b, assertTrue, assertFalse):
198 assertTrue(a == b, "(%r == %r) --> False" % (a, b))
199 assertFalse(a != b)
200 assertTrue(b == a)
201 assertFalse(b != a)
202
203 def assertEqual(a, b):
204 _equality(a, b, self.assertTrue, self.assertFalse)
205
206 # Instances compare equal to themselves.
207 name = self._x509name()
208 assertEqual(name, name)
209
210 # Empty instances should compare equal to each other.
211 assertEqual(self._x509name(), self._x509name())
212
213 # Instances with equal NIDs should compare equal to each other.
214 assertEqual(self._x509name(commonName="foo"),
215 self._x509name(commonName="foo"))
216
217 # Instance with equal NIDs set using different aliases should compare
218 # equal to each other.
219 assertEqual(self._x509name(commonName="foo"),
220 self._x509name(CN="foo"))
221
222 # Instances with more than one NID with the same values should compare
223 # equal to each other.
224 assertEqual(self._x509name(CN="foo", organizationalUnitName="bar"),
225 self._x509name(commonName="foo", OU="bar"))
226
227 def assertNotEqual(a, b):
228 _equality(a, b, self.assertFalse, self.assertTrue)
229
230 # Instances with different values for the same NID should not compare
231 # equal to each other.
232 assertNotEqual(self._x509name(CN="foo"),
233 self._x509name(CN="bar"))
234
235 # Instances with different NIDs should not compare equal to each other.
236 assertNotEqual(self._x509name(CN="foo"),
237 self._x509name(OU="foo"))
238
239 def _inequality(a, b, assertTrue, assertFalse):
240 assertTrue(a < b)
241 assertTrue(a <= b)
242 assertTrue(b > a)
243 assertTrue(b >= a)
244 assertFalse(a > b)
245 assertFalse(a >= b)
246 assertFalse(b < a)
247 assertFalse(b <= a)
248
249 def assertLessThan(a, b):
250 _inequality(a, b, self.assertTrue, self.assertFalse)
251
252 # An X509Name with a NID with a value which sorts less than the value
253 # of the same NID on another X509Name compares less than the other
254 # X509Name.
255 assertLessThan(self._x509name(CN="abc"),
256 self._x509name(CN="def"))
257
258 def assertGreaterThan(a, b):
259 _inequality(a, b, self.assertFalse, self.assertTrue)
260
261 # An X509Name with a NID with a value which sorts greater than the
262 # value of the same NID on another X509Name compares greater than the
263 # other X509Name.
264 assertGreaterThan(self._x509name(CN="def"),
265 self._x509name(CN="abc"))
Jean-Paul Calderone2aa2b332008-03-06 21:43:14 -0500266
267
Jean-Paul Calderone110cd092008-03-24 17:27:42 -0400268 def test_hash(self):
269 """
270 L{X509Name.hash} returns an integer hash based on the value of the
271 name.
272 """
273 a = self._x509name(CN="foo")
274 b = self._x509name(CN="foo")
275 self.assertEqual(a.hash(), b.hash())
276 a.CN = "bar"
277 self.assertNotEqual(a.hash(), b.hash())
278
279
Jean-Paul Calderonee957a002008-03-25 15:16:51 -0400280 def test_der(self):
281 """
282 L{X509Name.der} returns the DER encoded form of the name.
283 """
284 a = self._x509name(CN="foo", C="US")
285 self.assertEqual(
286 a.der(),
287 '0\x1b1\x0b0\t\x06\x03U\x04\x06\x13\x02US'
288 '1\x0c0\n\x06\x03U\x04\x03\x13\x03foo')
289
290
Jean-Paul Calderone110cd092008-03-24 17:27:42 -0400291
Jean-Paul Calderoneac0d95f2008-03-10 00:00:42 -0400292class _PKeyInteractionTestsMixin:
293 """
294 Tests which involve another thing and a PKey.
295 """
296 def signable(self):
297 """
298 Return something with a C{set_pubkey}, C{set_pubkey}, and C{sign} method.
299 """
300 raise NotImplementedError()
301
302
303 def test_signWithUngenerated(self):
304 """
305 L{X509Req.sign} raises L{ValueError} when pass a L{PKey} with no parts.
306 """
307 request = self.signable()
308 key = PKey()
309 self.assertRaises(ValueError, request.sign, key, 'MD5')
310
311
312 def test_signWithPublicKey(self):
313 """
314 L{X509Req.sign} raises L{ValueError} when pass a L{PKey} with no
315 private part as the signing key.
316 """
317 request = self.signable()
318 key = PKey()
319 key.generate_key(TYPE_RSA, 512)
320 request.set_pubkey(key)
321 pub = request.get_pubkey()
322 self.assertRaises(ValueError, request.sign, pub, 'MD5')
323
324
325
326class X509ReqTests(TestCase, _PKeyInteractionTestsMixin, _Python23TestCaseHelper):
Jean-Paul Calderone2aa2b332008-03-06 21:43:14 -0500327 """
328 Tests for L{OpenSSL.crypto.X509Req}.
329 """
Jean-Paul Calderoneac0d95f2008-03-10 00:00:42 -0400330 def signable(self):
331 """
332 Create and return a new L{X509Req}.
333 """
334 return X509Req()
335
336
Jean-Paul Calderone2aa2b332008-03-06 21:43:14 -0500337 def test_construction(self):
338 """
339 L{X509Req} takes no arguments and returns an L{X509ReqType} instance.
340 """
341 request = X509Req()
342 self.assertTrue(
343 isinstance(request, X509ReqType),
344 "%r is of type %r, should be %r" % (request, type(request), X509ReqType))
345
346
347 def test_get_subject(self):
348 """
349 L{X509ReqType.get_subject} returns an L{X509Name} for the subject of
350 the request and which is valid even after the request object is
351 otherwise dead.
352 """
353 request = X509Req()
354 subject = request.get_subject()
355 self.assertTrue(
356 isinstance(subject, X509NameType),
357 "%r is of type %r, should be %r" % (subject, type(subject), X509NameType))
358 subject.commonName = "foo"
359 self.assertEqual(request.get_subject().commonName, "foo")
360 del request
361 subject.commonName = "bar"
362 self.assertEqual(subject.commonName, "bar")
Jean-Paul Calderone78381d22008-03-06 23:35:22 -0500363
364
365
Jean-Paul Calderoneac0d95f2008-03-10 00:00:42 -0400366class X509Tests(TestCase, _PKeyInteractionTestsMixin, _Python23TestCaseHelper):
Jean-Paul Calderone78381d22008-03-06 23:35:22 -0500367 """
368 Tests for L{OpenSSL.crypto.X509}.
369 """
Jean-Paul Calderone8114b452008-03-25 15:27:59 -0400370 pemData = """
371-----BEGIN CERTIFICATE-----
372MIICfTCCAeYCAQEwDQYJKoZIhvcNAQEEBQAwgYYxCzAJBgNVBAYTAlVTMRkwFwYD
373VQQDExBweW9wZW5zc2wuc2YubmV0MREwDwYDVQQHEwhOZXcgWW9yazESMBAGA1UE
374ChMJUHlPcGVuU1NMMREwDwYDVQQIEwhOZXcgWW9yazEQMA4GCSqGSIb3DQEJARYB
375IDEQMA4GA1UECxMHVGVzdGluZzAeFw0wODAzMjUxOTA0MTNaFw0wOTAzMjUxOTA0
376MTNaMIGGMQswCQYDVQQGEwJVUzEZMBcGA1UEAxMQcHlvcGVuc3NsLnNmLm5ldDER
377MA8GA1UEBxMITmV3IFlvcmsxEjAQBgNVBAoTCVB5T3BlblNTTDERMA8GA1UECBMI
378TmV3IFlvcmsxEDAOBgkqhkiG9w0BCQEWASAxEDAOBgNVBAsTB1Rlc3RpbmcwgZ8w
379DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANp6Y17WzKSwBsUWkXdqg6tnXy8H8hA1
380msCMWpc+/2KJ4mbv5NyD6UD+/SqagQqulPbF/DFea9nAE0zhmHJELcM8gUTIlXv/
381cgDWnmK4xj8YkjVUiCdqKRAKeuzLG1pGmwwF5lGeJpXNxQn5ecR0UYSOWj6TTGXB
3829VyUMQzCClcBAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAmm0Vzvv1O91WLl2LnF2P
383q55LJdOnJbCCXIgxLdoVmvYAz1ZJq1eGKgKWI5QLgxiSzJLEU7KK//aVfiZzoCd5
384RipBiEEMEV4eAY317bHPwPP+4Bj9t0l8AsDLseC5vLRHgxrLEu3bn08DYx6imB5Q
385UBj849/xpszEM7BhwKE0GiQ=
386-----END CERTIFICATE-----
387-----BEGIN RSA PRIVATE KEY-----
388MIICXAIBAAKBgQDaemNe1syksAbFFpF3aoOrZ18vB/IQNZrAjFqXPv9iieJm7+Tc
389g+lA/v0qmoEKrpT2xfwxXmvZwBNM4ZhyRC3DPIFEyJV7/3IA1p5iuMY/GJI1VIgn
390aikQCnrsyxtaRpsMBeZRniaVzcUJ+XnEdFGEjlo+k0xlwfVclDEMwgpXAQIDAQAB
391AoGBALi0a7pMQqqgnriVAdpBVJveQtxSDVWi2/gZMKVZfzNheuSnv4amhtaKPKJ+
392CMZtHkcazsE2IFvxRN/kgato9H3gJqq8nq2CkdpdLNVKBoxiCtkLfutdY4SQLtoY
393USN7exk131pchsAJXYlR6mCW+ZP+E523cNwpPgsyKxVbmXSBAkEA9470fy2W0jFM
394taZFslpntKSzbvn6JmdtjtvWrM1bBaeeqFiGBuQFYg46VaCUaeRWYw02jmYAsDYh
395ZQavmXThaQJBAOHtlAQ0IJJEiMZr6vtVPH32fmbthSv1AUSYPzKqdlQrUnOXPQXu
396z70cFoLG1TvPF5rBxbOkbQ/s8/ka5ZjPfdkCQCeC7YsO36+UpsWnUCBzRXITh4AC
3977eYLQ/U1KUJTVF/GrQ/5cQrQgftwgecAxi9Qfmk4xqhbp2h4e0QAmS5I9WECQH02
3980QwrX8nxFeTytr8pFGezj4a4KVCdb2B3CL+p3f70K7RIo9d/7b6frJI6ZL/LHQf2
399UP4pKRDkgKsVDx7MELECQGm072/Z7vmb03h/uE95IYJOgY4nfmYs0QKA9Is18wUz
400DpjfE33p0Ha6GO1VZRIQoqE24F8o5oimy3BEjryFuw4=
401-----END RSA PRIVATE KEY-----
402"""
403
Jean-Paul Calderoneac0d95f2008-03-10 00:00:42 -0400404 def signable(self):
405 """
406 Create and return a new L{X509}.
407 """
408 return X509()
409
410
Jean-Paul Calderone78381d22008-03-06 23:35:22 -0500411 def test_construction(self):
412 """
413 L{X509} takes no arguments and returns an instance of L{X509Type}.
414 """
415 certificate = X509()
416 self.assertTrue(
417 isinstance(certificate, X509Type),
418 "%r is of type %r, should be %r" % (certificate,
419 type(certificate),
420 X509Type))
421
422
423 def test_serial_number(self):
424 """
425 The serial number of an L{X509Type} can be retrieved and modified with
426 L{X509Type.get_serial_number} and L{X509Type.set_serial_number}.
427 """
428 certificate = X509()
429 self.assertRaises(TypeError, certificate.set_serial_number)
430 self.assertRaises(TypeError, certificate.set_serial_number, 1, 2)
431 self.assertRaises(TypeError, certificate.set_serial_number, "1")
432 self.assertRaises(TypeError, certificate.set_serial_number, 5.5)
433 self.assertEqual(certificate.get_serial_number(), 0)
434 certificate.set_serial_number(1)
435 self.assertEqual(certificate.get_serial_number(), 1)
436 certificate.set_serial_number(2 ** 32 + 1)
437 self.assertEqual(certificate.get_serial_number(), 2 ** 32 + 1)
438 certificate.set_serial_number(2 ** 64 + 1)
439 self.assertEqual(certificate.get_serial_number(), 2 ** 64 + 1)
Jean-Paul Calderone525ef802008-03-09 20:39:42 -0400440 certificate.set_serial_number(2 ** 128 + 1)
441 self.assertEqual(certificate.get_serial_number(), 2 ** 128 + 1)
442
443
444 def _setBoundTest(self, which):
445 """
446 L{X509Type.set_notBefore} takes a string in the format of an ASN1
447 GENERALIZEDTIME and sets the beginning of the certificate's validity
448 period to it.
449 """
450 certificate = X509()
451 set = getattr(certificate, 'set_not' + which)
452 get = getattr(certificate, 'get_not' + which)
453
Jean-Paul Calderonee0615b52008-03-09 21:44:46 -0400454 # Starts with no value.
455 self.assertEqual(get(), None)
456
Jean-Paul Calderone525ef802008-03-09 20:39:42 -0400457 # GMT (Or is it UTC?) -exarkun
458 when = "20040203040506Z"
459 set(when)
460 self.assertEqual(get(), when)
461
462 # A plus two hours and thirty minutes offset
463 when = "20040203040506+0530"
464 set(when)
465 self.assertEqual(get(), when)
466
467 # A minus one hour fifteen minutes offset
468 when = "20040203040506-0115"
469 set(when)
470 self.assertEqual(get(), when)
471
472 # An invalid string results in a ValueError
473 self.assertRaises(ValueError, set, "foo bar")
474
475
476 def test_set_notBefore(self):
477 """
478 L{X509Type.set_notBefore} takes a string in the format of an ASN1
479 GENERALIZEDTIME and sets the beginning of the certificate's validity
480 period to it.
481 """
482 self._setBoundTest("Before")
483
484
485 def test_set_notAfter(self):
486 """
487 L{X509Type.set_notAfter} takes a string in the format of an ASN1
488 GENERALIZEDTIME and sets the end of the certificate's validity period
489 to it.
490 """
491 self._setBoundTest("After")
Jean-Paul Calderone76576d52008-03-24 16:04:46 -0400492
493
Jean-Paul Calderone38a646d2008-03-25 15:16:18 -0400494 def test_get_notBefore(self):
495 """
496 L{X509Type.get_notBefore} returns a string in the format of an ASN1
497 GENERALIZEDTIME even for certificates which store it as UTCTIME
498 internally.
499 """
Jean-Paul Calderone8114b452008-03-25 15:27:59 -0400500 cert = load_certificate(FILETYPE_PEM, self.pemData)
Jean-Paul Calderone38a646d2008-03-25 15:16:18 -0400501 self.assertEqual(cert.get_notBefore(), "20080325190413Z")
502
503
504 def test_get_notAfter(self):
505 """
506 L{X509Type.get_notAfter} returns a string in the format of an ASN1
507 GENERALIZEDTIME even for certificates which store it as UTCTIME
508 internally.
509 """
Jean-Paul Calderone8114b452008-03-25 15:27:59 -0400510 cert = load_certificate(FILETYPE_PEM, self.pemData)
Jean-Paul Calderone38a646d2008-03-25 15:16:18 -0400511 self.assertEqual(cert.get_notAfter(), "20090325190413Z")
512
513
Jean-Paul Calderone76576d52008-03-24 16:04:46 -0400514 def test_digest(self):
515 """
516 L{X509.digest} returns a string giving ":"-separated hex-encoded words
517 of the digest of the certificate.
518 """
519 cert = X509()
520 self.assertEqual(
521 cert.digest("md5"),
522 "A8:EB:07:F8:53:25:0A:F2:56:05:C5:A5:C4:C4:C7:15")