blob: 53a8dfc7214f8aeed124148da7c0eaa3e13520e5 [file] [log] [blame]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001from time import time
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05003from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05004from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04005from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05006
7from six import (
8 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -04009 text_type as _text_type,
10 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080011
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050012from OpenSSL._util import (
13 ffi as _ffi,
14 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050015 exception_from_error_queue as _exception_from_error_queue,
16 byte_string as _byte_string,
17 native as _native)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080018
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050019FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
20FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080021
22# TODO This was an API mistake. OpenSSL has no such constant.
23FILETYPE_TEXT = 2 ** 16 - 1
24
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050025TYPE_RSA = _lib.EVP_PKEY_RSA
26TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080027
Jean-Paul Calderone60432792015-04-13 12:26:07 -040028# A marker object to observe whether some optional arguments are passed any
29# value or not.
30_undefined = object()
31
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080032
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070033
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050034class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050035 """
36 An error occurred in an `OpenSSL.crypto` API.
37 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050038
39
40_raise_current_error = partial(_exception_from_error_queue, Error)
41
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070042
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050043
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050044def _untested_error(where):
45 """
46 An OpenSSL API failed somehow. Additionally, the failure which was
47 encountered isn't one that's exercised by the test suite so future behavior
48 of pyOpenSSL is now somewhat less predictable.
49 """
50 raise RuntimeError("Unknown %s failure" % (where,))
51
52
53
54def _new_mem_buf(buffer=None):
55 """
56 Allocate a new OpenSSL memory BIO.
57
58 Arrange for the garbage collector to clean it up automatically.
59
60 :param buffer: None or some bytes to use to put into the BIO so that they
61 can be read out.
62 """
63 if buffer is None:
64 bio = _lib.BIO_new(_lib.BIO_s_mem())
65 free = _lib.BIO_free
66 else:
67 data = _ffi.new("char[]", buffer)
68 bio = _lib.BIO_new_mem_buf(data, len(buffer))
69 # Keep the memory alive as long as the bio is alive!
70 def free(bio, ref=data):
71 return _lib.BIO_free(bio)
72
73 if bio == _ffi.NULL:
74 # TODO: This is untested.
75 _raise_current_error()
76
77 bio = _ffi.gc(bio, free)
78 return bio
79
80
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050081
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080082def _bio_to_string(bio):
83 """
84 Copy the contents of an OpenSSL BIO object into a Python byte string.
85 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050086 result_buffer = _ffi.new('char**')
87 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
88 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080089
90
91
Jean-Paul Calderone57122982013-02-21 08:47:05 -080092def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050093 """
94 The the time value of an ASN1 time object.
95
96 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
97 castable to that type) which will have its value set.
98 @param when: A string representation of the desired time value.
99
100 @raise TypeError: If C{when} is not a L{bytes} string.
101 @raise ValueError: If C{when} does not represent a time in the required
102 format.
103 @raise RuntimeError: If the time value cannot be set for some other
104 (unspecified) reason.
105 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800106 if not isinstance(when, bytes):
107 raise TypeError("when must be a byte string")
108
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500109 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
110 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800111 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500112 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
113 _lib.ASN1_STRING_set(dummy, when, len(when))
114 check_result = _lib.ASN1_GENERALIZEDTIME_check(
115 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800116 if not check_result:
117 raise ValueError("Invalid string")
118 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500119 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800120
121
122
123def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500124 """
125 Retrieve the time value of an ASN1 time object.
126
127 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
128 that type) from which the time value will be retrieved.
129
130 @return: The time value from C{timestamp} as a L{bytes} string in a certain
131 format. Or C{None} if the object contains no time value.
132 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500133 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
134 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800135 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500136 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
137 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800138 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500139 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
140 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
141 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500142 # This may happen:
143 # - if timestamp was not an ASN1_TIME
144 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
145 # - if a copy of the time data from timestamp cannot be made for
146 # the newly allocated ASN1_GENERALIZEDTIME
147 #
148 # These are difficult to test. cffi enforces the ASN1_TIME type.
149 # Memory allocation failures are a pain to trigger
150 # deterministically.
151 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800152 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500153 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800154 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500155 string_data = _lib.ASN1_STRING_data(string_timestamp)
156 string_result = _ffi.string(string_data)
157 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800158 return string_result
159
160
161
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800162class PKey(object):
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800163 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800164 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800165
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800166 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500167 pkey = _lib.EVP_PKEY_new()
168 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800169 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800170
171
172 def generate_key(self, type, bits):
173 """
174 Generate a key of a given type, with a given number of a bits
175
176 :param type: The key type (TYPE_RSA or TYPE_DSA)
177 :param bits: The number of bits
178
179 :return: None
180 """
181 if not isinstance(type, int):
182 raise TypeError("type must be an integer")
183
184 if not isinstance(bits, int):
185 raise TypeError("bits must be an integer")
186
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800187 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500188 exponent = _lib.BN_new()
189 exponent = _ffi.gc(exponent, _lib.BN_free)
190 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800191
192 if type == TYPE_RSA:
193 if bits <= 0:
194 raise ValueError("Invalid number of bits")
195
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500196 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800197
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500198 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500199 if result == 0:
200 # TODO: The test for this case is commented out. Different
201 # builds of OpenSSL appear to have different failure modes that
202 # make it hard to test. Visual inspection of the OpenSSL
203 # source reveals that a return value of 0 signals an error.
204 # Manual testing on a particular build of OpenSSL suggests that
205 # this is probably the appropriate way to handle those errors.
206 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800207
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500208 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800209 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500210 # TODO: It appears as though this can fail if an engine is in
211 # use which does not support RSA.
212 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800213
214 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500215 dsa = _lib.DSA_generate_parameters(
216 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
217 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500218 # TODO: This is untested.
219 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500220 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500221 # TODO: This is untested.
222 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500223 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500224 # TODO: This is untested.
225 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800226 else:
227 raise Error("No such key type")
228
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800229 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800230
231
232 def check(self):
233 """
234 Check the consistency of an RSA private key.
235
236 :return: True if key is consistent.
237 :raise Error: if the key is inconsistent.
238 :raise TypeError: if the key is of a type which cannot be checked.
239 Only RSA keys can currently be checked.
240 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800241 if self._only_public:
242 raise TypeError("public key only")
243
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500244 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800245 raise TypeError("key type unsupported")
246
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500247 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
248 rsa = _ffi.gc(rsa, _lib.RSA_free)
249 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800250 if result:
251 return True
252 _raise_current_error()
253
254
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800255 def type(self):
256 """
257 Returns the type of the key
258
259 :return: The type of the key.
260 """
261 return self._pkey.type
262
263
264 def bits(self):
265 """
266 Returns the number of bits of the key
267
268 :return: The number of bits of the key.
269 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500270 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800271PKeyType = PKey
272
273
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800274
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400275class _EllipticCurve(object):
276 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400277 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400278
279 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
280 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
281 instances each of which represents one curve supported by the system.
282 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400283 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400284 _curves = None
285
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400286 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400287 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400288 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400289 """
290 Implement cooperation with the right-hand side argument of ``!=``.
291
292 Python 3 seems to have dropped this cooperation in this very narrow
293 circumstance.
294 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400295 if isinstance(other, _EllipticCurve):
296 return super(_EllipticCurve, self).__ne__(other)
297 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400298
299
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400300 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400301 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400302 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400303 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400304
305 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400306
307 :return: A :py:type:`set` of ``cls`` instances giving the names of the
308 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400309 """
310 if lib.Cryptography_HAS_EC:
311 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
312 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
313 # The return value on this call should be num_curves again. We could
314 # check it to make sure but if it *isn't* then.. what could we do?
315 # Abort the whole process, I suppose...? -exarkun
316 lib.EC_get_builtin_curves(builtin_curves, num_curves)
317 return set(
318 cls.from_nid(lib, c.nid)
319 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400320 return set()
321
322
323 @classmethod
324 def _get_elliptic_curves(cls, lib):
325 """
326 Get, cache, and return the curves supported by OpenSSL.
327
328 :param lib: The OpenSSL library binding object.
329
330 :return: A :py:type:`set` of ``cls`` instances giving the names of the
331 elliptic curves the underlying library supports.
332 """
333 if cls._curves is None:
334 cls._curves = cls._load_elliptic_curves(lib)
335 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400336
337
338 @classmethod
339 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400340 """
341 Instantiate a new :py:class:`_EllipticCurve` associated with the given
342 OpenSSL NID.
343
344 :param lib: The OpenSSL library binding object.
345
346 :param nid: The OpenSSL NID the resulting curve object will represent.
347 This must be a curve NID (and not, for example, a hash NID) or
348 subsequent operations will fail in unpredictable ways.
349 :type nid: :py:class:`int`
350
351 :return: The curve object.
352 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400353 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
354
355
356 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400357 """
358 :param _lib: The :py:mod:`cryptography` binding instance used to
359 interface with OpenSSL.
360
361 :param _nid: The OpenSSL NID identifying the curve this object
362 represents.
363 :type _nid: :py:class:`int`
364
365 :param name: The OpenSSL short name identifying the curve this object
366 represents.
367 :type name: :py:class:`unicode`
368 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400369 self._lib = lib
370 self._nid = nid
371 self.name = name
372
373
374 def __repr__(self):
375 return "<Curve %r>" % (self.name,)
376
377
378 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400379 """
380 Create a new OpenSSL EC_KEY structure initialized to use this curve.
381
382 The structure is automatically garbage collected when the Python object
383 is garbage collected.
384 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400385 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
386 return _ffi.gc(key, _lib.EC_KEY_free)
387
388
389
390def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400391 """
392 Return a set of objects representing the elliptic curves supported in the
393 OpenSSL build in use.
394
395 The curve objects have a :py:class:`unicode` ``name`` attribute by which
396 they identify themselves.
397
398 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400399 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
400 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400401 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400402 return _EllipticCurve._get_elliptic_curves(_lib)
403
404
405
406def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400407 """
408 Return a single curve object selected by name.
409
410 See :py:func:`get_elliptic_curves` for information about curve objects.
411
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400412 :param name: The OpenSSL short name identifying the curve object to
413 retrieve.
414 :type name: :py:class:`unicode`
415
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400416 If the named curve is not supported then :py:class:`ValueError` is raised.
417 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400418 for curve in get_elliptic_curves():
419 if curve.name == name:
420 return curve
421 raise ValueError("unknown curve name", name)
422
423
424
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800425class X509Name(object):
426 def __init__(self, name):
427 """
428 Create a new X509Name, copying the given X509Name instance.
429
430 :param name: An X509Name object to copy
431 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500432 name = _lib.X509_NAME_dup(name._name)
433 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800434
435
436 def __setattr__(self, name, value):
437 if name.startswith('_'):
438 return super(X509Name, self).__setattr__(name, value)
439
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800440 # Note: we really do not want str subclasses here, so we do not use
441 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800442 if type(name) is not str:
443 raise TypeError("attribute name must be string, not '%.200s'" % (
444 type(value).__name__,))
445
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500446 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500447 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800448 try:
449 _raise_current_error()
450 except Error:
451 pass
452 raise AttributeError("No such attribute")
453
454 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500455 for i in range(_lib.X509_NAME_entry_count(self._name)):
456 ent = _lib.X509_NAME_get_entry(self._name, i)
457 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
458 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800459 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500460 ent = _lib.X509_NAME_delete_entry(self._name, i)
461 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800462 break
463
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500464 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800465 value = value.encode('utf-8')
466
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500467 add_result = _lib.X509_NAME_add_entry_by_NID(
468 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800469 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500470 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800471
472
473 def __getattr__(self, name):
474 """
475 Find attribute. An X509Name object has the following attributes:
476 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
477 organization (alias O), organizationalUnit (alias OU), commonName (alias
478 CN) and more...
479 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500480 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500481 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800482 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
483 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
484 # push something onto the error queue. If we don't clean that up
485 # now, someone else will bump into it later and be quite confused.
486 # See lp#314814.
487 try:
488 _raise_current_error()
489 except Error:
490 pass
491 return super(X509Name, self).__getattr__(name)
492
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500493 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800494 if entry_index == -1:
495 return None
496
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500497 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
498 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800499
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500500 result_buffer = _ffi.new("unsigned char**")
501 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800502 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500503 # TODO: This is untested.
504 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800505
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700506 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500507 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700508 finally:
509 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500510 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800511 return result
512
513
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500514 def _cmp(op):
515 def f(self, other):
516 if not isinstance(other, X509Name):
517 return NotImplemented
518 result = _lib.X509_NAME_cmp(self._name, other._name)
519 return op(result, 0)
520 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800521
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500522 __eq__ = _cmp(__eq__)
523 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800524
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500525 __lt__ = _cmp(__lt__)
526 __le__ = _cmp(__le__)
527
528 __gt__ = _cmp(__gt__)
529 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800530
531 def __repr__(self):
532 """
533 String representation of an X509Name
534 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500535 result_buffer = _ffi.new("char[]", 512);
536 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800537 self._name, result_buffer, len(result_buffer))
538
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500539 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500540 # TODO: This is untested.
541 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800542
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500543 return "<X509Name object '%s'>" % (
544 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800545
546
547 def hash(self):
548 """
549 Return the hash value of this name
550
551 :return: None
552 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500553 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800554
555
556 def der(self):
557 """
558 Return the DER encoding of this name
559
560 :return: A :py:class:`bytes` instance giving the DER encoded form of
561 this name.
562 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500563 result_buffer = _ffi.new('unsigned char**')
564 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800565 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500566 # TODO: This is untested.
567 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800568
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500569 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
570 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800571 return string_result
572
573
574 def get_components(self):
575 """
576 Returns the split-up components of this name.
577
578 :return: List of tuples (name, value).
579 """
580 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500581 for i in range(_lib.X509_NAME_entry_count(self._name)):
582 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800583
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500584 fname = _lib.X509_NAME_ENTRY_get_object(ent)
585 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800586
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500587 nid = _lib.OBJ_obj2nid(fname)
588 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800589
590 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500591 _ffi.string(name),
592 _ffi.string(
593 _lib.ASN1_STRING_data(fval),
594 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800595
596 return result
597X509NameType = X509Name
598
599
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800600class X509Extension(object):
601 def __init__(self, type_name, critical, value, subject=None, issuer=None):
602 """
603 :param typename: The name of the extension to create.
604 :type typename: :py:data:`str`
605
606 :param critical: A flag indicating whether this is a critical extension.
607
608 :param value: The value of the extension.
609 :type value: :py:data:`str`
610
611 :param subject: Optional X509 cert to use as subject.
612 :type subject: :py:class:`X509`
613
614 :param issuer: Optional X509 cert to use as issuer.
615 :type issuer: :py:class:`X509`
616
617 :return: The X509Extension object
618 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500619 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800620
621 # A context is necessary for any extension which uses the r2i conversion
622 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
623 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500624 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800625
626 # We have no configuration database - but perhaps we should (some
627 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500628 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800629
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800630 # Initialize the subject and issuer, if appropriate. ctx is a local,
631 # and as far as I can tell none of the X509V3_* APIs invoked here steal
632 # any references, so no need to mess with reference counts or duplicates.
633 if issuer is not None:
634 if not isinstance(issuer, X509):
635 raise TypeError("issuer must be an X509 instance")
636 ctx.issuer_cert = issuer._x509
637 if subject is not None:
638 if not isinstance(subject, X509):
639 raise TypeError("subject must be an X509 instance")
640 ctx.subject_cert = subject._x509
641
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800642 if critical:
643 # There are other OpenSSL APIs which would let us pass in critical
644 # separately, but they're harder to use, and since value is already
645 # a pile of crappy junk smuggling a ton of utterly important
646 # structured data, what's the point of trying to avoid nasty stuff
647 # with strings? (However, X509V3_EXT_i2d in particular seems like it
648 # would be a better API to invoke. I do not know where to get the
649 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500650 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800651
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500652 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
653 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800654 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500655 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800656
657
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400658 @property
659 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500660 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400661
662 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500663 _lib.GEN_EMAIL: "email",
664 _lib.GEN_DNS: "DNS",
665 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400666 }
667
668 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500669 method = _lib.X509V3_EXT_get(self._extension)
670 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500671 # TODO: This is untested.
672 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400673 payload = self._extension.value.data
674 length = self._extension.value.length
675
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500676 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400677 payloadptr[0] = payload
678
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500679 if method.it != _ffi.NULL:
680 ptr = _lib.ASN1_ITEM_ptr(method.it)
681 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
682 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400683 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500684 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400685 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500686 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400687
688 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500689 for i in range(_lib.sk_GENERAL_NAME_num(names)):
690 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400691 try:
692 label = self._prefixes[name.type]
693 except KeyError:
694 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500695 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500696 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400697 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500698 value = _native(
699 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
700 parts.append(label + ":" + value)
701 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400702
703
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800704 def __str__(self):
705 """
706 :return: a nice text representation of the extension
707 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500708 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400709 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800710
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400711 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500712 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800713 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500714 # TODO: This is untested.
715 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800716
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500717 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800718
719
720 def get_critical(self):
721 """
722 Returns the critical field of the X509Extension
723
724 :return: The critical field.
725 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500726 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800727
728
729 def get_short_name(self):
730 """
731 Returns the short version of the type name of the X509Extension
732
733 :return: The short type name.
734 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500735 obj = _lib.X509_EXTENSION_get_object(self._extension)
736 nid = _lib.OBJ_obj2nid(obj)
737 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800738
739
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800740 def get_data(self):
741 """
742 Returns the data of the X509Extension
743
744 :return: A :py:data:`str` giving the X509Extension's ASN.1 encoded data.
745 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500746 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
747 string_result = _ffi.cast('ASN1_STRING*', octet_result)
748 char_result = _lib.ASN1_STRING_data(string_result)
749 result_length = _lib.ASN1_STRING_length(string_result)
750 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800751
752X509ExtensionType = X509Extension
753
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800754
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800755class X509Req(object):
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800756 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500757 req = _lib.X509_REQ_new()
758 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800759
760
761 def set_pubkey(self, pkey):
762 """
763 Set the public key of the certificate request
764
765 :param pkey: The public key to use
766 :return: None
767 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500768 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800769 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500770 # TODO: This is untested.
771 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800772
773
774 def get_pubkey(self):
775 """
776 Get the public key from the certificate request
777
778 :return: The public key
779 """
780 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500781 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
782 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500783 # TODO: This is untested.
784 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500785 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800786 pkey._only_public = True
787 return pkey
788
789
790 def set_version(self, version):
791 """
792 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
793 request.
794
795 :param version: The version number
796 :return: None
797 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500798 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800799 if not set_result:
800 _raise_current_error()
801
802
803 def get_version(self):
804 """
805 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
806 request.
807
808 :return: an integer giving the value of the version subfield
809 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500810 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811
812
813 def get_subject(self):
814 """
815 Create an X509Name object for the subject of the certificate request
816
817 :return: An X509Name object
818 """
819 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500820 name._name = _lib.X509_REQ_get_subject_name(self._req)
821 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500822 # TODO: This is untested.
823 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800824
825 # The name is owned by the X509Req structure. As long as the X509Name
826 # Python object is alive, keep the X509Req Python object alive.
827 name._owner = self
828
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800829 return name
830
831
832 def add_extensions(self, extensions):
833 """
834 Add extensions to the request.
835
836 :param extensions: a sequence of X509Extension objects
837 :return: None
838 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500839 stack = _lib.sk_X509_EXTENSION_new_null()
840 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500841 # TODO: This is untested.
842 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800843
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500844 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800845
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800846 for ext in extensions:
847 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800848 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800849
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800850 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500851 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800852
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500853 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500855 # TODO: This is untested.
856 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800857
858
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800859 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800860 """
861 Get extensions to the request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800862
Jean-Paul Calderoneda3e6c62014-03-02 08:06:11 -0500863 :return: A :py:class:`list` of :py:class:`X509Extension` objects.
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800864 """
865 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500866 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500867 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800868 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500869 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800870 exts.append(ext)
871 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800872
873
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800874 def sign(self, pkey, digest):
875 """
876 Sign the certificate request using the supplied key and digest
877
878 :param pkey: The key to sign with
879 :param digest: The message digest to use
880 :return: None
881 """
882 if pkey._only_public:
883 raise ValueError("Key has only public part")
884
885 if not pkey._initialized:
886 raise ValueError("Key is uninitialized")
887
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500888 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500889 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800890 raise ValueError("No such digest method")
891
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500892 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800893 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500894 # TODO: This is untested.
895 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800896
897
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800898 def verify(self, pkey):
899 """
900 Verifies a certificate request using the supplied public key
901
902 :param key: a public key
903 :return: True if the signature is correct.
904
905 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
906 problem verifying the signature.
907 """
908 if not isinstance(pkey, PKey):
909 raise TypeError("pkey must be a PKey instance")
910
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500911 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800912 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500913 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800914
915 return result
916
917
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800918X509ReqType = X509Req
919
920
921
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800922class X509(object):
923 def __init__(self):
924 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500925 x509 = _lib.X509_new()
926 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800927
928
929 def set_version(self, version):
930 """
931 Set version number of the certificate
932
933 :param version: The version number
934 :type version: :py:class:`int`
935
936 :return: None
937 """
938 if not isinstance(version, int):
939 raise TypeError("version must be an integer")
940
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500941 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800942
943
944 def get_version(self):
945 """
946 Return version number of the certificate
947
948 :return: Version number as a Python integer
949 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500950 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800951
952
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800953 def get_pubkey(self):
954 """
955 Get the public key of the certificate
956
957 :return: The public key
958 """
959 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500960 pkey._pkey = _lib.X509_get_pubkey(self._x509)
961 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800962 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500963 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800964 pkey._only_public = True
965 return pkey
966
967
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800968 def set_pubkey(self, pkey):
969 """
970 Set the public key of the certificate
971
972 :param pkey: The public key
973
974 :return: None
975 """
976 if not isinstance(pkey, PKey):
977 raise TypeError("pkey must be a PKey instance")
978
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500979 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800980 if not set_result:
981 _raise_current_error()
982
983
984 def sign(self, pkey, digest):
985 """
986 Sign the certificate using the supplied key and digest
987
988 :param pkey: The key to sign with
989 :param digest: The message digest to use
990 :return: None
991 """
992 if not isinstance(pkey, PKey):
993 raise TypeError("pkey must be a PKey instance")
994
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800995 if pkey._only_public:
996 raise ValueError("Key only has public part")
997
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800998 if not pkey._initialized:
999 raise ValueError("Key is uninitialized")
1000
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001001 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001002 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001003 raise ValueError("No such digest method")
1004
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001005 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001006 if not sign_result:
1007 _raise_current_error()
1008
1009
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001010 def get_signature_algorithm(self):
1011 """
1012 Retrieve the signature algorithm used in the certificate
1013
1014 :return: A byte string giving the name of the signature algorithm used in
1015 the certificate.
1016 :raise ValueError: If the signature algorithm is undefined.
1017 """
1018 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001019 nid = _lib.OBJ_obj2nid(alg)
1020 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001021 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001022 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001023
1024
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001025 def digest(self, digest_name):
1026 """
1027 Return the digest of the X509 object.
1028
1029 :param digest_name: The name of the digest algorithm to use.
1030 :type digest_name: :py:class:`bytes`
1031
1032 :return: The digest of the object
1033 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001034 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001035 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001036 raise ValueError("No such digest method")
1037
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001038 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1039 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001040 result_length[0] = len(result_buffer)
1041
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001042 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001043 self._x509, digest, result_buffer, result_length)
1044
1045 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001046 # TODO: This is untested.
1047 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001048
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001049 return b":".join([
1050 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001051 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001052
1053
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001054 def subject_name_hash(self):
1055 """
1056 Return the hash of the X509 subject.
1057
1058 :return: The hash of the subject.
1059 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001060 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001061
1062
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001063 def set_serial_number(self, serial):
1064 """
1065 Set serial number of the certificate
1066
1067 :param serial: The serial number
1068 :type serial: :py:class:`int`
1069
1070 :return: None
1071 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001072 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001073 raise TypeError("serial must be an integer")
1074
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001075 hex_serial = hex(serial)[2:]
1076 if not isinstance(hex_serial, bytes):
1077 hex_serial = hex_serial.encode('ascii')
1078
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001079 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001080
1081 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1082 # it. If bignum is still NULL after this call, then the return value is
1083 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001084 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001085
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001086 if bignum_serial[0] == _ffi.NULL:
1087 set_result = _lib.ASN1_INTEGER_set(
1088 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001089 if set_result:
1090 # TODO Not tested
1091 _raise_current_error()
1092 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001093 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1094 _lib.BN_free(bignum_serial[0])
1095 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001096 # TODO Not tested
1097 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001098 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1099 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001100 if not set_result:
1101 # TODO Not tested
1102 _raise_current_error()
1103
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001104
1105 def get_serial_number(self):
1106 """
1107 Return serial number of the certificate
1108
1109 :return: Serial number as a Python integer
1110 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001111 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1112 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001113 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001114 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001115 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001116 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001117 serial = int(hexstring_serial, 16)
1118 return serial
1119 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001120 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001121 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001122 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001123
1124
1125 def gmtime_adj_notAfter(self, amount):
1126 """
1127 Adjust the time stamp for when the certificate stops being valid
1128
1129 :param amount: The number of seconds by which to adjust the ending
1130 validity time.
1131 :type amount: :py:class:`int`
1132
1133 :return: None
1134 """
1135 if not isinstance(amount, int):
1136 raise TypeError("amount must be an integer")
1137
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001138 notAfter = _lib.X509_get_notAfter(self._x509)
1139 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001140
1141
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001142 def gmtime_adj_notBefore(self, amount):
1143 """
1144 Change the timestamp for when the certificate starts being valid to the current
1145 time plus an offset.
1146
1147 :param amount: The number of seconds by which to adjust the starting validity
1148 time.
1149 :return: None
1150 """
1151 if not isinstance(amount, int):
1152 raise TypeError("amount must be an integer")
1153
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001154 notBefore = _lib.X509_get_notBefore(self._x509)
1155 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001156
1157
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001158 def has_expired(self):
1159 """
1160 Check whether the certificate has expired.
1161
1162 :return: True if the certificate has expired, false otherwise
1163 """
1164 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001165 notAfter = _lib.X509_get_notAfter(self._x509)
1166 return _lib.ASN1_UTCTIME_cmp_time_t(
1167 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001168
1169
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001170 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001171 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001172
1173
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001174 def get_notBefore(self):
1175 """
1176 Retrieve the time stamp for when the certificate starts being valid
1177
1178 :return: A string giving the timestamp, in the format::
1179
1180 YYYYMMDDhhmmssZ
1181 YYYYMMDDhhmmss+hhmm
1182 YYYYMMDDhhmmss-hhmm
1183
1184 or None if there is no value set.
1185 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001186 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001187
1188
1189 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001190 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001191
1192
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001193 def set_notBefore(self, when):
1194 """
1195 Set the time stamp for when the certificate starts being valid
1196
1197 :param when: A string giving the timestamp, in the format:
1198
1199 YYYYMMDDhhmmssZ
1200 YYYYMMDDhhmmss+hhmm
1201 YYYYMMDDhhmmss-hhmm
1202 :type when: :py:class:`bytes`
1203
1204 :return: None
1205 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001206 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001207
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001208
1209 def get_notAfter(self):
1210 """
1211 Retrieve the time stamp for when the certificate stops being valid
1212
1213 :return: A string giving the timestamp, in the format::
1214
1215 YYYYMMDDhhmmssZ
1216 YYYYMMDDhhmmss+hhmm
1217 YYYYMMDDhhmmss-hhmm
1218
1219 or None if there is no value set.
1220 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001221 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001222
1223
1224 def set_notAfter(self, when):
1225 """
1226 Set the time stamp for when the certificate stops being valid
1227
1228 :param when: A string giving the timestamp, in the format:
1229
1230 YYYYMMDDhhmmssZ
1231 YYYYMMDDhhmmss+hhmm
1232 YYYYMMDDhhmmss-hhmm
1233 :type when: :py:class:`bytes`
1234
1235 :return: None
1236 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001237 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001238
1239
1240 def _get_name(self, which):
1241 name = X509Name.__new__(X509Name)
1242 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001243 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001244 # TODO: This is untested.
1245 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001246
1247 # The name is owned by the X509 structure. As long as the X509Name
1248 # Python object is alive, keep the X509 Python object alive.
1249 name._owner = self
1250
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001251 return name
1252
1253
1254 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001255 if not isinstance(name, X509Name):
1256 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001257 set_result = which(self._x509, name._name)
1258 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001259 # TODO: This is untested.
1260 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001261
1262
1263 def get_issuer(self):
1264 """
1265 Create an X509Name object for the issuer of the certificate
1266
1267 :return: An X509Name object
1268 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001269 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001270
1271
1272 def set_issuer(self, issuer):
1273 """
1274 Set the issuer of the certificate
1275
1276 :param issuer: The issuer name
1277 :type issuer: :py:class:`X509Name`
1278
1279 :return: None
1280 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001281 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001282
1283
1284 def get_subject(self):
1285 """
1286 Create an X509Name object for the subject of the certificate
1287
1288 :return: An X509Name object
1289 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001290 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001291
1292
1293 def set_subject(self, subject):
1294 """
1295 Set the subject of the certificate
1296
1297 :param subject: The subject name
1298 :type subject: :py:class:`X509Name`
1299 :return: None
1300 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001301 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001302
1303
1304 def get_extension_count(self):
1305 """
1306 Get the number of extensions on the certificate.
1307
1308 :return: The number of extensions as an integer.
1309 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001310 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001311
1312
1313 def add_extensions(self, extensions):
1314 """
1315 Add extensions to the certificate.
1316
1317 :param extensions: a sequence of X509Extension objects
1318 :return: None
1319 """
1320 for ext in extensions:
1321 if not isinstance(ext, X509Extension):
1322 raise ValueError("One of the elements is not an X509Extension")
1323
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001324 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001325 if not add_result:
1326 _raise_current_error()
1327
1328
1329 def get_extension(self, index):
1330 """
1331 Get a specific extension of the certificate by index.
1332
1333 :param index: The index of the extension to retrieve.
1334 :return: The X509Extension object at the specified index.
1335 """
1336 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001337 ext._extension = _lib.X509_get_ext(self._x509, index)
1338 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001339 raise IndexError("extension index out of bounds")
1340
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001341 extension = _lib.X509_EXTENSION_dup(ext._extension)
1342 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001343 return ext
1344
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001345X509Type = X509
1346
1347
1348
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001349class X509Store(object):
1350 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001351 store = _lib.X509_STORE_new()
1352 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001353
1354
1355 def add_cert(self, cert):
1356 if not isinstance(cert, X509):
1357 raise TypeError()
1358
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001359 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001360 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001361 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001362
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001363
1364X509StoreType = X509Store
1365
1366
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001367class X509StoreContextError(Exception):
1368 """
1369 An error occurred while verifying a certificate using
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001370 `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001371
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001372 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001373 :type cert: :class:`X509`
1374
1375 """
1376 def __init__(self, message, certificate):
1377 super(X509StoreContextError, self).__init__(message)
1378 self.certificate = certificate
1379
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001380
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001381class X509StoreContext(object):
1382 """
1383 An X.509 store context.
1384
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001385 An :py:class:`X509StoreContext` is used to define some of the criteria for
1386 certificate verification. The information encapsulated in this object
1387 includes, but is not limited to, a set of trusted certificates,
1388 verification parameters, and revoked certificates.
1389
1390 Of these, only the set of trusted certificates is currently exposed.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001391
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001392 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1393 instance. It is dynamically allocated and automatically garbage
1394 collected.
1395
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001396 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001397
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001398 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001399 """
1400
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001401 def __init__(self, store, certificate):
1402 """
1403 :param X509Store store: The certificates which will be trusted for the
1404 purposes of any verifications.
1405
1406 :param X509 certificate: The certificate to be verified.
1407 """
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001408 store_ctx = _lib.X509_STORE_CTX_new()
1409 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1410 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001411 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001412 # Make the store context available for use after instantiating this
1413 # class by initializing it now. Per testing, subsequent calls to
1414 # :py:meth:`_init` have no adverse affect.
1415 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001416
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001417
1418 def _init(self):
1419 """
1420 Set up the store context for a subsequent verification operation.
1421 """
1422 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1423 if ret <= 0:
1424 _raise_current_error()
1425
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001426
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001427 def _cleanup(self):
1428 """
1429 Internally cleans up the store context.
1430
1431 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001432 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001433 """
1434 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1435
1436
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001437 def _exception_from_context(self):
1438 """
1439 Convert an OpenSSL native context error failure into a Python
1440 exception.
1441
1442 When a call to native OpenSSL X509_verify_cert fails, additonal information
1443 about the failure can be obtained from the store context.
1444 """
1445 errors = [
1446 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1447 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1448 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1449 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1450 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001451 # A context error should always be associated with a certificate, so we
1452 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001453 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001454 _cert = _lib.X509_dup(_x509)
1455 pycert = X509.__new__(X509)
1456 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001457 return X509StoreContextError(errors, pycert)
1458
1459
Stephen Holsapple46a09252015-02-12 14:45:43 -08001460 def set_store(self, store):
1461 """
1462 Set the context's trust store.
1463
1464 :param X509Store store: The certificates which will be trusted for the
1465 purposes of any *future* verifications.
1466 """
1467 self._store = store
1468
1469
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001470 def verify_certificate(self):
1471 """
1472 Verify a certificate in a context.
1473
1474 :param store_ctx: The :py:class:`X509StoreContext` to verify.
1475 :raises: Error
1476 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001477 # Always re-initialize the store context in case
1478 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001479 self._init()
1480 ret = _lib.X509_verify_cert(self._store_ctx)
1481 self._cleanup()
1482 if ret <= 0:
1483 raise self._exception_from_context()
1484
1485
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001486
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001487def load_certificate(type, buffer):
1488 """
1489 Load a certificate from a buffer
1490
1491 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001492
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001493 :param buffer: The buffer the certificate is stored in
1494 :type buffer: :py:class:`bytes`
1495
1496 :return: The X509 object
1497 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001498 if isinstance(buffer, _text_type):
1499 buffer = buffer.encode("ascii")
1500
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001501 bio = _new_mem_buf(buffer)
1502
1503 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001504 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001505 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001506 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001507 else:
1508 raise ValueError(
1509 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1510
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001511 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001512 _raise_current_error()
1513
1514 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001515 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001516 return cert
1517
1518
1519def dump_certificate(type, cert):
1520 """
1521 Dump a certificate to a buffer
1522
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001523 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1524 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001525 :param cert: The certificate to dump
1526 :return: The buffer with the dumped certificate in
1527 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001528 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001529
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001530 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001531 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001532 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001533 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001534 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001535 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001536 else:
1537 raise ValueError(
1538 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1539 "FILETYPE_TEXT")
1540
1541 return _bio_to_string(bio)
1542
1543
1544
1545def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1546 """
1547 Dump a private key to a buffer
1548
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001549 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1550 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001551 :param pkey: The PKey to dump
1552 :param cipher: (optional) if encrypted PEM format, the cipher to
1553 use
1554 :param passphrase: (optional) if encrypted PEM format, this can be either
1555 the passphrase to use, or a callback for providing the
1556 passphrase.
1557 :return: The buffer with the dumped key in
1558 :rtype: :py:data:`str`
1559 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001560 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001561
1562 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001563 if passphrase is None:
1564 raise TypeError(
1565 "if a value is given for cipher "
1566 "one must also be given for passphrase")
1567 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001568 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001569 raise ValueError("Invalid cipher name")
1570 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001571 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001572
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001573 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001574 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001575 result_code = _lib.PEM_write_bio_PrivateKey(
1576 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001577 helper.callback, helper.callback_args)
1578 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001579 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001580 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001581 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001582 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1583 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001584 # TODO RSA_free(rsa)?
1585 else:
1586 raise ValueError(
1587 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1588 "FILETYPE_TEXT")
1589
1590 if result_code == 0:
1591 _raise_current_error()
1592
1593 return _bio_to_string(bio)
1594
1595
1596
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001597def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001598 copy = _lib.X509_REVOKED_new()
1599 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001600 # TODO: This is untested.
1601 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001602
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001603 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001604 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001605 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001606
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001607 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001608 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001609 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001610
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001611 if original.extensions != _ffi.NULL:
1612 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1613 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1614 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1615 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1616 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001617 copy.extensions = extension_stack
1618
1619 copy.sequence = original.sequence
1620 return copy
1621
1622
1623
1624class Revoked(object):
1625 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1626 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1627 # OCSP_crl_reason_str. We use the latter, just like the command line
1628 # program.
1629 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001630 b"unspecified",
1631 b"keyCompromise",
1632 b"CACompromise",
1633 b"affiliationChanged",
1634 b"superseded",
1635 b"cessationOfOperation",
1636 b"certificateHold",
1637 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001638 ]
1639
1640 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001641 revoked = _lib.X509_REVOKED_new()
1642 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001643
1644
1645 def set_serial(self, hex_str):
1646 """
1647 Set the serial number of a revoked Revoked structure
1648
1649 :param hex_str: The new serial number.
1650 :type hex_str: :py:data:`str`
1651 :return: None
1652 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001653 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1654 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001655 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001656 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001657 if not bn_result:
1658 raise ValueError("bad hex string")
1659
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001660 asn1_serial = _ffi.gc(
1661 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1662 _lib.ASN1_INTEGER_free)
1663 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001664
1665
1666 def get_serial(self):
1667 """
1668 Return the serial number of a Revoked structure
1669
1670 :return: The serial number as a string
1671 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001672 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001673
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001674 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001675 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001676 # TODO: This is untested.
1677 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001678
1679 return _bio_to_string(bio)
1680
1681
1682 def _delete_reason(self):
1683 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001684 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1685 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1686 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1687 _lib.X509_EXTENSION_free(ext)
1688 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001689 break
1690
1691
1692 def set_reason(self, reason):
1693 """
1694 Set the reason of a Revoked object.
1695
1696 If :py:data:`reason` is :py:data:`None`, delete the reason instead.
1697
1698 :param reason: The reason string.
1699 :type reason: :py:class:`str` or :py:class:`NoneType`
1700 :return: None
1701 """
1702 if reason is None:
1703 self._delete_reason()
1704 elif not isinstance(reason, bytes):
1705 raise TypeError("reason must be None or a byte string")
1706 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001707 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001708 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1709
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001710 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1711 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001712 # TODO: This is untested.
1713 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001714 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001715
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001716 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1717 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001718 # TODO: This is untested.
1719 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001720
1721 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001722 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1723 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001724
1725 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001726 # TODO: This is untested.
1727 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001728
1729
1730 def get_reason(self):
1731 """
1732 Return the reason of a Revoked object.
1733
1734 :return: The reason as a string
1735 """
1736 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001737 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1738 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1739 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001740 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001741
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001742 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001743 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001744 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001745 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001746 # TODO: This is untested.
1747 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001748
1749 return _bio_to_string(bio)
1750
1751
1752 def all_reasons(self):
1753 """
1754 Return a list of all the supported reason strings.
1755
1756 :return: A list of reason strings.
1757 """
1758 return self._crl_reasons[:]
1759
1760
1761 def set_rev_date(self, when):
1762 """
1763 Set the revocation timestamp
1764
1765 :param when: A string giving the timestamp, in the format:
1766
1767 YYYYMMDDhhmmssZ
1768 YYYYMMDDhhmmss+hhmm
1769 YYYYMMDDhhmmss-hhmm
1770
1771 :return: None
1772 """
1773 return _set_asn1_time(self._revoked.revocationDate, when)
1774
1775
1776 def get_rev_date(self):
1777 """
1778 Retrieve the revocation date
1779
1780 :return: A string giving the timestamp, in the format:
1781
1782 YYYYMMDDhhmmssZ
1783 YYYYMMDDhhmmss+hhmm
1784 YYYYMMDDhhmmss-hhmm
1785 """
1786 return _get_asn1_time(self._revoked.revocationDate)
1787
1788
1789
1790class CRL(object):
1791 def __init__(self):
1792 """
1793 Create a new empty CRL object.
1794 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001795 crl = _lib.X509_CRL_new()
1796 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001797
1798
1799 def get_revoked(self):
1800 """
1801 Return revoked portion of the CRL structure (by value not reference).
1802
1803 :return: A tuple of Revoked objects.
1804 """
1805 results = []
1806 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001807 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1808 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809 revoked_copy = _X509_REVOKED_dup(revoked)
1810 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001811 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001812 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001813 if results:
1814 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001815
1816
1817 def add_revoked(self, revoked):
1818 """
1819 Add a revoked (by value not reference) to the CRL structure
1820
1821 :param revoked: The new revoked.
1822 :type revoked: :class:`X509`
1823
1824 :return: None
1825 """
1826 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001827 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001828 # TODO: This is untested.
1829 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001830
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001831 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001832 if add_result == 0:
1833 # TODO: This is untested.
1834 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001835
1836
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001837 def export(self, cert, key, type=FILETYPE_PEM, days=100,
1838 digest=_undefined):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001839 """
1840 export a CRL as a string
1841
1842 :param cert: Used to sign CRL.
1843 :type cert: :class:`X509`
1844
1845 :param key: Used to sign CRL.
1846 :type key: :class:`PKey`
1847
1848 :param type: The export format, either :py:data:`FILETYPE_PEM`, :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
1849
1850 :param days: The number of days until the next update of this CRL.
1851 :type days: :py:data:`int`
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001852
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001853 :param digest: The message digest to use (eg ``"sha1"``).
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001854 :type digest: :py:data:`str`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001855
1856 :return: :py:data:`str`
1857 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001858 if not isinstance(cert, X509):
1859 raise TypeError("cert must be an X509 instance")
1860 if not isinstance(key, PKey):
1861 raise TypeError("key must be a PKey instance")
1862 if not isinstance(type, int):
1863 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001864
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001865 if digest is _undefined:
1866 _warn(
1867 "The default message digest (md5) is deprecated. "
1868 "Pass the name of a message digest explicitly.",
1869 category=DeprecationWarning,
1870 stacklevel=2,
1871 )
1872 digest = "md5"
1873
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001874 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
1875 if digest_obj == _ffi.NULL:
1876 raise ValueError("No such digest method")
1877
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001878 bio = _lib.BIO_new(_lib.BIO_s_mem())
1879 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001880 # TODO: This is untested.
1881 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001882
1883 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001884 sometime = _lib.ASN1_TIME_new()
1885 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001886 # TODO: This is untested.
1887 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001888
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001889 _lib.X509_gmtime_adj(sometime, 0)
1890 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001891
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001892 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1893 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001894
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001895 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001896
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001897 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001898 if not sign_result:
1899 _raise_current_error()
1900
1901 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001902 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001903 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001904 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001905 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001906 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001907 else:
1908 raise ValueError(
1909 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1910
1911 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001912 # TODO: This is untested.
1913 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001914
1915 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001916CRLType = CRL
1917
1918
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001919
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001920class PKCS7(object):
1921 def type_is_signed(self):
1922 """
1923 Check if this NID_pkcs7_signed object
1924
1925 :return: True if the PKCS7 is of type signed
1926 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001927 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001928 return True
1929 return False
1930
1931
1932 def type_is_enveloped(self):
1933 """
1934 Check if this NID_pkcs7_enveloped object
1935
1936 :returns: True if the PKCS7 is of type enveloped
1937 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001938 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001939 return True
1940 return False
1941
1942
1943 def type_is_signedAndEnveloped(self):
1944 """
1945 Check if this NID_pkcs7_signedAndEnveloped object
1946
1947 :returns: True if the PKCS7 is of type signedAndEnveloped
1948 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001949 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001950 return True
1951 return False
1952
1953
1954 def type_is_data(self):
1955 """
1956 Check if this NID_pkcs7_data object
1957
1958 :return: True if the PKCS7 is of type data
1959 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001960 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001961 return True
1962 return False
1963
1964
1965 def get_type_name(self):
1966 """
1967 Returns the type name of the PKCS7 structure
1968
1969 :return: A string with the typename
1970 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001971 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1972 string_type = _lib.OBJ_nid2sn(nid)
1973 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001974
1975PKCS7Type = PKCS7
1976
1977
1978
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001979class PKCS12(object):
1980 def __init__(self):
1981 self._pkey = None
1982 self._cert = None
1983 self._cacerts = None
1984 self._friendlyname = None
1985
1986
1987 def get_certificate(self):
1988 """
1989 Return certificate portion of the PKCS12 structure
1990
1991 :return: X509 object containing the certificate
1992 """
1993 return self._cert
1994
1995
1996 def set_certificate(self, cert):
1997 """
1998 Replace the certificate portion of the PKCS12 structure
1999
2000 :param cert: The new certificate.
2001 :type cert: :py:class:`X509` or :py:data:`None`
2002 :return: None
2003 """
2004 if not isinstance(cert, X509):
2005 raise TypeError("cert must be an X509 instance")
2006 self._cert = cert
2007
2008
2009 def get_privatekey(self):
2010 """
2011 Return private key portion of the PKCS12 structure
2012
2013 :returns: PKey object containing the private key
2014 """
2015 return self._pkey
2016
2017
2018 def set_privatekey(self, pkey):
2019 """
2020 Replace or set the certificate portion of the PKCS12 structure
2021
2022 :param pkey: The new private key.
2023 :type pkey: :py:class:`PKey`
2024 :return: None
2025 """
2026 if not isinstance(pkey, PKey):
2027 raise TypeError("pkey must be a PKey instance")
2028 self._pkey = pkey
2029
2030
2031 def get_ca_certificates(self):
2032 """
2033 Return CA certificates within of the PKCS12 object
2034
2035 :return: A newly created tuple containing the CA certificates in the chain,
2036 if any are present, or None if no CA certificates are present.
2037 """
2038 if self._cacerts is not None:
2039 return tuple(self._cacerts)
2040
2041
2042 def set_ca_certificates(self, cacerts):
2043 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002044 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002045
2046 :param cacerts: The new CA certificates.
2047 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2048 :return: None
2049 """
2050 if cacerts is None:
2051 self._cacerts = None
2052 else:
2053 cacerts = list(cacerts)
2054 for cert in cacerts:
2055 if not isinstance(cert, X509):
2056 raise TypeError("iterable must only contain X509 instances")
2057 self._cacerts = cacerts
2058
2059
2060 def set_friendlyname(self, name):
2061 """
2062 Replace or set the certificate portion of the PKCS12 structure
2063
2064 :param name: The new friendly name.
2065 :type name: :py:class:`bytes`
2066 :return: None
2067 """
2068 if name is None:
2069 self._friendlyname = None
2070 elif not isinstance(name, bytes):
2071 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2072 self._friendlyname = name
2073
2074
2075 def get_friendlyname(self):
2076 """
2077 Return friendly name portion of the PKCS12 structure
2078
2079 :returns: String containing the friendlyname
2080 """
2081 return self._friendlyname
2082
2083
2084 def export(self, passphrase=None, iter=2048, maciter=1):
2085 """
2086 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2087
2088 :param passphrase: used to encrypt the PKCS12
2089 :type passphrase: :py:data:`bytes`
2090
2091 :param iter: How many times to repeat the encryption
2092 :type iter: :py:data:`int`
2093
2094 :param maciter: How many times to repeat the MAC
2095 :type maciter: :py:data:`int`
2096
2097 :return: The string containing the PKCS12
2098 """
2099 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002100 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002101 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002102 cacerts = _lib.sk_X509_new_null()
2103 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002104 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002105 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002106
2107 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002108 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002109
2110 friendlyname = self._friendlyname
2111 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002112 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002113
2114 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002115 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002116 else:
2117 pkey = self._pkey._pkey
2118
2119 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002120 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002121 else:
2122 cert = self._cert._x509
2123
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002124 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002125 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002126 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2127 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002128 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002129 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002130 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002131 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002132
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002133 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002134 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002135 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002136
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002137PKCS12Type = PKCS12
2138
2139
2140
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002141class NetscapeSPKI(object):
2142 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002143 spki = _lib.NETSCAPE_SPKI_new()
2144 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002145
2146
2147 def sign(self, pkey, digest):
2148 """
2149 Sign the certificate request using the supplied key and digest
2150
2151 :param pkey: The key to sign with
2152 :param digest: The message digest to use
2153 :return: None
2154 """
2155 if pkey._only_public:
2156 raise ValueError("Key has only public part")
2157
2158 if not pkey._initialized:
2159 raise ValueError("Key is uninitialized")
2160
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002161 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002162 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002163 raise ValueError("No such digest method")
2164
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002165 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002166 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002167 # TODO: This is untested.
2168 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002169
2170
2171 def verify(self, key):
2172 """
2173 Verifies a certificate request using the supplied public key
2174
2175 :param key: a public key
2176 :return: True if the signature is correct.
2177 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2178 problem verifying the signature.
2179 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002180 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002181 if answer <= 0:
2182 _raise_current_error()
2183 return True
2184
2185
2186 def b64_encode(self):
2187 """
2188 Generate a base64 encoded string from an SPKI
2189
2190 :return: The base64 encoded string
2191 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002192 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2193 result = _ffi.string(encoded)
2194 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002195 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002196
2197
2198 def get_pubkey(self):
2199 """
2200 Get the public key of the certificate
2201
2202 :return: The public key
2203 """
2204 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002205 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2206 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002207 # TODO: This is untested.
2208 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002209 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002210 pkey._only_public = True
2211 return pkey
2212
2213
2214 def set_pubkey(self, pkey):
2215 """
2216 Set the public key of the certificate
2217
2218 :param pkey: The public key
2219 :return: None
2220 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002221 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002222 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002223 # TODO: This is untested.
2224 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002225NetscapeSPKIType = NetscapeSPKI
2226
2227
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002228class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002229 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002230 if type != FILETYPE_PEM and passphrase is not None:
2231 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002232 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002233 self._more_args = more_args
2234 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002235 self._problems = []
2236
2237
2238 @property
2239 def callback(self):
2240 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002241 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002242 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002243 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002244 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002245 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002246 else:
2247 raise TypeError("Last argument must be string or callable")
2248
2249
2250 @property
2251 def callback_args(self):
2252 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002253 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002254 elif isinstance(self._passphrase, bytes):
2255 return self._passphrase
2256 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002257 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002258 else:
2259 raise TypeError("Last argument must be string or callable")
2260
2261
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002262 def raise_if_problem(self, exceptionType=Error):
2263 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002264 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002265 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002266 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002267 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002268 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002269 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002270
2271
2272 def _read_passphrase(self, buf, size, rwflag, userdata):
2273 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002274 if self._more_args:
2275 result = self._passphrase(size, rwflag, userdata)
2276 else:
2277 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002278 if not isinstance(result, bytes):
2279 raise ValueError("String expected")
2280 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002281 if self._truncate:
2282 result = result[:size]
2283 else:
2284 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002285 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002286 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002287 return len(result)
2288 except Exception as e:
2289 self._problems.append(e)
2290 return 0
2291
2292
2293
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002294def load_privatekey(type, buffer, passphrase=None):
2295 """
2296 Load a private key from a buffer
2297
2298 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2299 :param buffer: The buffer the key is stored in
2300 :param passphrase: (optional) if encrypted PEM format, this can be
2301 either the passphrase to use, or a callback for
2302 providing the passphrase.
2303
2304 :return: The PKey object
2305 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002306 if isinstance(buffer, _text_type):
2307 buffer = buffer.encode("ascii")
2308
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002309 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002310
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002311 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002312 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002313 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2314 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002315 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002316 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002317 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002318 else:
2319 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2320
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002321 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002322 _raise_current_error()
2323
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002324 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002325 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002326 return pkey
2327
2328
2329
2330def dump_certificate_request(type, req):
2331 """
2332 Dump a certificate request to a buffer
2333
2334 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2335 :param req: The certificate request to dump
2336 :return: The buffer with the dumped certificate request in
2337 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002338 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002339
2340 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002341 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002342 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002343 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002344 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002345 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002346 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002347 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002348
2349 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002350 # TODO: This is untested.
2351 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002352
2353 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002354
2355
2356
2357def load_certificate_request(type, buffer):
2358 """
2359 Load a certificate request from a buffer
2360
2361 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2362 :param buffer: The buffer the certificate request is stored in
2363 :return: The X509Req object
2364 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002365 if isinstance(buffer, _text_type):
2366 buffer = buffer.encode("ascii")
2367
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002368 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002369
2370 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002371 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002372 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002373 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002374 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002375 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002376
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002377 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002378 # TODO: This is untested.
2379 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002380
2381 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002382 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002383 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002384
2385
2386
2387def sign(pkey, data, digest):
2388 """
2389 Sign data with a digest
2390
2391 :param pkey: Pkey to sign with
2392 :param data: data to be signed
2393 :param digest: message digest to use
2394 :return: signature
2395 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002396 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002397 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002398 raise ValueError("No such digest method")
2399
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002400 md_ctx = _ffi.new("EVP_MD_CTX*")
2401 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002402
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002403 _lib.EVP_SignInit(md_ctx, digest_obj)
2404 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002405
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002406 signature_buffer = _ffi.new("unsigned char[]", 512)
2407 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002408 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002409 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002410 md_ctx, signature_buffer, signature_length, pkey._pkey)
2411
2412 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002413 # TODO: This is untested.
2414 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002415
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002416 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002417
2418
2419
2420def verify(cert, signature, data, digest):
2421 """
2422 Verify a signature
2423
2424 :param cert: signing certificate (X509 object)
2425 :param signature: signature returned by sign function
2426 :param data: data to be verified
2427 :param digest: message digest to use
2428 :return: None if the signature is correct, raise exception otherwise
2429 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002430 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002431 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002432 raise ValueError("No such digest method")
2433
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002434 pkey = _lib.X509_get_pubkey(cert._x509)
2435 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002436 # TODO: This is untested.
2437 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002438 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002439
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002440 md_ctx = _ffi.new("EVP_MD_CTX*")
2441 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002442
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002443 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2444 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2445 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002446
2447 if verify_result != 1:
2448 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002449
2450
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002451def load_crl(type, buffer):
2452 """
2453 Load a certificate revocation list from a buffer
2454
2455 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2456 :param buffer: The buffer the CRL is stored in
2457
2458 :return: The PKey object
2459 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002460 if isinstance(buffer, _text_type):
2461 buffer = buffer.encode("ascii")
2462
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002463 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002464
2465 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002466 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002467 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002468 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002469 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002470 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2471
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002472 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002473 _raise_current_error()
2474
2475 result = CRL.__new__(CRL)
2476 result._crl = crl
2477 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002478
2479
2480
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002481def load_pkcs7_data(type, buffer):
2482 """
2483 Load pkcs7 data from a buffer
2484
2485 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2486 :param buffer: The buffer with the pkcs7 data.
2487 :return: The PKCS7 object
2488 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002489 if isinstance(buffer, _text_type):
2490 buffer = buffer.encode("ascii")
2491
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002492 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002493
2494 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002495 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002496 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002497 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002498 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002499 # TODO: This is untested.
2500 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002501 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2502
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002503 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002504 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002505
2506 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002507 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002508 return pypkcs7
2509
2510
2511
Stephen Holsapple38482622014-04-05 20:29:34 -07002512def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002513 """
2514 Load a PKCS12 object from a buffer
2515
2516 :param buffer: The buffer the certificate is stored in
2517 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2518 :returns: The PKCS12 object
2519 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002520 if isinstance(buffer, _text_type):
2521 buffer = buffer.encode("ascii")
2522
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002523 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002524
Stephen Holsapple38482622014-04-05 20:29:34 -07002525 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2526 # password based encryption no password and a zero length password are two
2527 # different things, but OpenSSL implementation will try both to figure out
2528 # which one works.
2529 if not passphrase:
2530 passphrase = _ffi.NULL
2531
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002532 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2533 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002534 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002535 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002536
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002537 pkey = _ffi.new("EVP_PKEY**")
2538 cert = _ffi.new("X509**")
2539 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002540
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002541 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002542 if not parse_result:
2543 _raise_current_error()
2544
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002545 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002546
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002547 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2548 # queue for no particular reason. This error isn't interesting to anyone
2549 # outside this function. It's not even interesting to us. Get rid of it.
2550 try:
2551 _raise_current_error()
2552 except Error:
2553 pass
2554
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002555 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002556 pykey = None
2557 else:
2558 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002559 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002560
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002561 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002562 pycert = None
2563 friendlyname = None
2564 else:
2565 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002566 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002567
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002568 friendlyname_length = _ffi.new("int*")
2569 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2570 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2571 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002572 friendlyname = None
2573
2574 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002575 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002576 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002577 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002578 pycacerts.append(pycacert)
2579 if not pycacerts:
2580 pycacerts = None
2581
2582 pkcs12 = PKCS12.__new__(PKCS12)
2583 pkcs12._pkey = pykey
2584 pkcs12._cert = pycert
2585 pkcs12._cacerts = pycacerts
2586 pkcs12._friendlyname = friendlyname
2587 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002588
2589
2590def _initialize_openssl_threads(get_ident, Lock):
2591 import _ssl
2592 return
2593
2594 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2595
2596 def locking_function(mode, index, filename, line):
2597 if mode & _lib.CRYPTO_LOCK:
2598 locks[index].acquire()
2599 else:
2600 locks[index].release()
2601
2602 _lib.CRYPTO_set_id_callback(
2603 _ffi.callback("unsigned long (*)(void)", get_ident))
2604
2605 _lib.CRYPTO_set_locking_callback(
2606 _ffi.callback(
2607 "void (*)(int, int, const char*, int)", locking_function))
2608
2609
2610try:
2611 from thread import get_ident
2612 from threading import Lock
2613except ImportError:
2614 pass
2615else:
2616 _initialize_openssl_threads(get_ident, Lock)
2617 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002618
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002619# There are no direct unit tests for this initialization. It is tested
2620# indirectly since it is necessary for functions like dump_privatekey when
2621# using encryption.
2622#
2623# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2624# and some other similar tests may fail without this (though they may not if
2625# the Python runtime has already done some initialization of the underlying
2626# OpenSSL library (and is linked against the same one that cryptography is
2627# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002628_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002629
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002630# This is similar but exercised mainly by exception_from_error_queue. It calls
2631# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2632_lib.SSL_load_error_strings()