blob: 4f0e7f226ea61a7479c2048a4daff35bbbe4fc24 [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,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040017 native as _native,
18 UNSPECIFIED as _UNSPECIFIED,
19)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080020
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050021FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
22FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080023
24# TODO This was an API mistake. OpenSSL has no such constant.
25FILETYPE_TEXT = 2 ** 16 - 1
26
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050027TYPE_RSA = _lib.EVP_PKEY_RSA
28TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080029
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080030
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070031
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050032class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050033 """
34 An error occurred in an `OpenSSL.crypto` API.
35 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050036
37
38_raise_current_error = partial(_exception_from_error_queue, Error)
39
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070040
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050041
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050042def _untested_error(where):
43 """
44 An OpenSSL API failed somehow. Additionally, the failure which was
45 encountered isn't one that's exercised by the test suite so future behavior
46 of pyOpenSSL is now somewhat less predictable.
47 """
48 raise RuntimeError("Unknown %s failure" % (where,))
49
50
51
52def _new_mem_buf(buffer=None):
53 """
54 Allocate a new OpenSSL memory BIO.
55
56 Arrange for the garbage collector to clean it up automatically.
57
58 :param buffer: None or some bytes to use to put into the BIO so that they
59 can be read out.
60 """
61 if buffer is None:
62 bio = _lib.BIO_new(_lib.BIO_s_mem())
63 free = _lib.BIO_free
64 else:
65 data = _ffi.new("char[]", buffer)
66 bio = _lib.BIO_new_mem_buf(data, len(buffer))
67 # Keep the memory alive as long as the bio is alive!
68 def free(bio, ref=data):
69 return _lib.BIO_free(bio)
70
71 if bio == _ffi.NULL:
72 # TODO: This is untested.
73 _raise_current_error()
74
75 bio = _ffi.gc(bio, free)
76 return bio
77
78
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050079
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080080def _bio_to_string(bio):
81 """
82 Copy the contents of an OpenSSL BIO object into a Python byte string.
83 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050084 result_buffer = _ffi.new('char**')
85 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
86 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080087
88
89
Jean-Paul Calderone57122982013-02-21 08:47:05 -080090def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050091 """
92 The the time value of an ASN1 time object.
93
94 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
95 castable to that type) which will have its value set.
96 @param when: A string representation of the desired time value.
97
98 @raise TypeError: If C{when} is not a L{bytes} string.
99 @raise ValueError: If C{when} does not represent a time in the required
100 format.
101 @raise RuntimeError: If the time value cannot be set for some other
102 (unspecified) reason.
103 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800104 if not isinstance(when, bytes):
105 raise TypeError("when must be a byte string")
106
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500107 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
108 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800109 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500110 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
111 _lib.ASN1_STRING_set(dummy, when, len(when))
112 check_result = _lib.ASN1_GENERALIZEDTIME_check(
113 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800114 if not check_result:
115 raise ValueError("Invalid string")
116 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500117 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800118
119
120
121def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500122 """
123 Retrieve the time value of an ASN1 time object.
124
125 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
126 that type) from which the time value will be retrieved.
127
128 @return: The time value from C{timestamp} as a L{bytes} string in a certain
129 format. Or C{None} if the object contains no time value.
130 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500131 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
132 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800133 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500134 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
135 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800136 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500137 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
138 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
139 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500140 # This may happen:
141 # - if timestamp was not an ASN1_TIME
142 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
143 # - if a copy of the time data from timestamp cannot be made for
144 # the newly allocated ASN1_GENERALIZEDTIME
145 #
146 # These are difficult to test. cffi enforces the ASN1_TIME type.
147 # Memory allocation failures are a pain to trigger
148 # deterministically.
149 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800150 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500151 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800152 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500153 string_data = _lib.ASN1_STRING_data(string_timestamp)
154 string_result = _ffi.string(string_data)
155 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800156 return string_result
157
158
159
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800160class PKey(object):
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800161 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800162 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800163
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800164 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500165 pkey = _lib.EVP_PKEY_new()
166 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800167 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800168
169
170 def generate_key(self, type, bits):
171 """
172 Generate a key of a given type, with a given number of a bits
173
174 :param type: The key type (TYPE_RSA or TYPE_DSA)
175 :param bits: The number of bits
176
177 :return: None
178 """
179 if not isinstance(type, int):
180 raise TypeError("type must be an integer")
181
182 if not isinstance(bits, int):
183 raise TypeError("bits must be an integer")
184
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800185 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500186 exponent = _lib.BN_new()
187 exponent = _ffi.gc(exponent, _lib.BN_free)
188 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800189
190 if type == TYPE_RSA:
191 if bits <= 0:
192 raise ValueError("Invalid number of bits")
193
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500194 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800195
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500196 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500197 if result == 0:
198 # TODO: The test for this case is commented out. Different
199 # builds of OpenSSL appear to have different failure modes that
200 # make it hard to test. Visual inspection of the OpenSSL
201 # source reveals that a return value of 0 signals an error.
202 # Manual testing on a particular build of OpenSSL suggests that
203 # this is probably the appropriate way to handle those errors.
204 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800205
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500206 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800207 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500208 # TODO: It appears as though this can fail if an engine is in
209 # use which does not support RSA.
210 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800211
212 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500213 dsa = _lib.DSA_generate_parameters(
214 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
215 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500216 # TODO: This is untested.
217 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500218 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500219 # TODO: This is untested.
220 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500221 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500222 # TODO: This is untested.
223 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800224 else:
225 raise Error("No such key type")
226
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800227 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800228
229
230 def check(self):
231 """
232 Check the consistency of an RSA private key.
233
234 :return: True if key is consistent.
235 :raise Error: if the key is inconsistent.
236 :raise TypeError: if the key is of a type which cannot be checked.
237 Only RSA keys can currently be checked.
238 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800239 if self._only_public:
240 raise TypeError("public key only")
241
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500242 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800243 raise TypeError("key type unsupported")
244
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500245 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
246 rsa = _ffi.gc(rsa, _lib.RSA_free)
247 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800248 if result:
249 return True
250 _raise_current_error()
251
252
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800253 def type(self):
254 """
255 Returns the type of the key
256
257 :return: The type of the key.
258 """
259 return self._pkey.type
260
261
262 def bits(self):
263 """
264 Returns the number of bits of the key
265
266 :return: The number of bits of the key.
267 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500268 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800269PKeyType = PKey
270
271
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800272
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400273class _EllipticCurve(object):
274 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400275 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400276
277 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
278 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
279 instances each of which represents one curve supported by the system.
280 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400281 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400282 _curves = None
283
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400284 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400285 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400286 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400287 """
288 Implement cooperation with the right-hand side argument of ``!=``.
289
290 Python 3 seems to have dropped this cooperation in this very narrow
291 circumstance.
292 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400293 if isinstance(other, _EllipticCurve):
294 return super(_EllipticCurve, self).__ne__(other)
295 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400296
297
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400298 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400299 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400300 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400301 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400302
303 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400304
305 :return: A :py:type:`set` of ``cls`` instances giving the names of the
306 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400307 """
308 if lib.Cryptography_HAS_EC:
309 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
310 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
311 # The return value on this call should be num_curves again. We could
312 # check it to make sure but if it *isn't* then.. what could we do?
313 # Abort the whole process, I suppose...? -exarkun
314 lib.EC_get_builtin_curves(builtin_curves, num_curves)
315 return set(
316 cls.from_nid(lib, c.nid)
317 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400318 return set()
319
320
321 @classmethod
322 def _get_elliptic_curves(cls, lib):
323 """
324 Get, cache, and return the curves supported by OpenSSL.
325
326 :param lib: The OpenSSL library binding object.
327
328 :return: A :py:type:`set` of ``cls`` instances giving the names of the
329 elliptic curves the underlying library supports.
330 """
331 if cls._curves is None:
332 cls._curves = cls._load_elliptic_curves(lib)
333 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400334
335
336 @classmethod
337 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400338 """
339 Instantiate a new :py:class:`_EllipticCurve` associated with the given
340 OpenSSL NID.
341
342 :param lib: The OpenSSL library binding object.
343
344 :param nid: The OpenSSL NID the resulting curve object will represent.
345 This must be a curve NID (and not, for example, a hash NID) or
346 subsequent operations will fail in unpredictable ways.
347 :type nid: :py:class:`int`
348
349 :return: The curve object.
350 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400351 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
352
353
354 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400355 """
356 :param _lib: The :py:mod:`cryptography` binding instance used to
357 interface with OpenSSL.
358
359 :param _nid: The OpenSSL NID identifying the curve this object
360 represents.
361 :type _nid: :py:class:`int`
362
363 :param name: The OpenSSL short name identifying the curve this object
364 represents.
365 :type name: :py:class:`unicode`
366 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400367 self._lib = lib
368 self._nid = nid
369 self.name = name
370
371
372 def __repr__(self):
373 return "<Curve %r>" % (self.name,)
374
375
376 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400377 """
378 Create a new OpenSSL EC_KEY structure initialized to use this curve.
379
380 The structure is automatically garbage collected when the Python object
381 is garbage collected.
382 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400383 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
384 return _ffi.gc(key, _lib.EC_KEY_free)
385
386
387
388def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400389 """
390 Return a set of objects representing the elliptic curves supported in the
391 OpenSSL build in use.
392
393 The curve objects have a :py:class:`unicode` ``name`` attribute by which
394 they identify themselves.
395
396 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400397 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
398 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400399 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400400 return _EllipticCurve._get_elliptic_curves(_lib)
401
402
403
404def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400405 """
406 Return a single curve object selected by name.
407
408 See :py:func:`get_elliptic_curves` for information about curve objects.
409
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400410 :param name: The OpenSSL short name identifying the curve object to
411 retrieve.
412 :type name: :py:class:`unicode`
413
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400414 If the named curve is not supported then :py:class:`ValueError` is raised.
415 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400416 for curve in get_elliptic_curves():
417 if curve.name == name:
418 return curve
419 raise ValueError("unknown curve name", name)
420
421
422
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800423class X509Name(object):
424 def __init__(self, name):
425 """
426 Create a new X509Name, copying the given X509Name instance.
427
428 :param name: An X509Name object to copy
429 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500430 name = _lib.X509_NAME_dup(name._name)
431 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800432
433
434 def __setattr__(self, name, value):
435 if name.startswith('_'):
436 return super(X509Name, self).__setattr__(name, value)
437
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800438 # Note: we really do not want str subclasses here, so we do not use
439 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800440 if type(name) is not str:
441 raise TypeError("attribute name must be string, not '%.200s'" % (
442 type(value).__name__,))
443
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500444 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500445 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800446 try:
447 _raise_current_error()
448 except Error:
449 pass
450 raise AttributeError("No such attribute")
451
452 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500453 for i in range(_lib.X509_NAME_entry_count(self._name)):
454 ent = _lib.X509_NAME_get_entry(self._name, i)
455 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
456 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800457 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500458 ent = _lib.X509_NAME_delete_entry(self._name, i)
459 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800460 break
461
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500462 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800463 value = value.encode('utf-8')
464
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500465 add_result = _lib.X509_NAME_add_entry_by_NID(
466 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800467 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500468 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800469
470
471 def __getattr__(self, name):
472 """
473 Find attribute. An X509Name object has the following attributes:
474 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
475 organization (alias O), organizationalUnit (alias OU), commonName (alias
476 CN) and more...
477 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500478 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500479 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800480 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
481 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
482 # push something onto the error queue. If we don't clean that up
483 # now, someone else will bump into it later and be quite confused.
484 # See lp#314814.
485 try:
486 _raise_current_error()
487 except Error:
488 pass
489 return super(X509Name, self).__getattr__(name)
490
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500491 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800492 if entry_index == -1:
493 return None
494
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500495 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
496 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800497
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500498 result_buffer = _ffi.new("unsigned char**")
499 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800500 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500501 # TODO: This is untested.
502 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800503
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700504 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500505 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700506 finally:
507 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500508 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800509 return result
510
511
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500512 def _cmp(op):
513 def f(self, other):
514 if not isinstance(other, X509Name):
515 return NotImplemented
516 result = _lib.X509_NAME_cmp(self._name, other._name)
517 return op(result, 0)
518 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800519
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500520 __eq__ = _cmp(__eq__)
521 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800522
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500523 __lt__ = _cmp(__lt__)
524 __le__ = _cmp(__le__)
525
526 __gt__ = _cmp(__gt__)
527 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800528
529 def __repr__(self):
530 """
531 String representation of an X509Name
532 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500533 result_buffer = _ffi.new("char[]", 512);
534 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800535 self._name, result_buffer, len(result_buffer))
536
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500537 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500538 # TODO: This is untested.
539 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800540
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500541 return "<X509Name object '%s'>" % (
542 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800543
544
545 def hash(self):
546 """
547 Return the hash value of this name
548
549 :return: None
550 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500551 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800552
553
554 def der(self):
555 """
556 Return the DER encoding of this name
557
558 :return: A :py:class:`bytes` instance giving the DER encoded form of
559 this name.
560 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500561 result_buffer = _ffi.new('unsigned char**')
562 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800563 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500564 # TODO: This is untested.
565 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800566
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500567 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
568 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800569 return string_result
570
571
572 def get_components(self):
573 """
574 Returns the split-up components of this name.
575
576 :return: List of tuples (name, value).
577 """
578 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500579 for i in range(_lib.X509_NAME_entry_count(self._name)):
580 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800581
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500582 fname = _lib.X509_NAME_ENTRY_get_object(ent)
583 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800584
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500585 nid = _lib.OBJ_obj2nid(fname)
586 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800587
588 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500589 _ffi.string(name),
590 _ffi.string(
591 _lib.ASN1_STRING_data(fval),
592 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800593
594 return result
595X509NameType = X509Name
596
597
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800598class X509Extension(object):
599 def __init__(self, type_name, critical, value, subject=None, issuer=None):
600 """
601 :param typename: The name of the extension to create.
602 :type typename: :py:data:`str`
603
604 :param critical: A flag indicating whether this is a critical extension.
605
606 :param value: The value of the extension.
607 :type value: :py:data:`str`
608
609 :param subject: Optional X509 cert to use as subject.
610 :type subject: :py:class:`X509`
611
612 :param issuer: Optional X509 cert to use as issuer.
613 :type issuer: :py:class:`X509`
614
615 :return: The X509Extension object
616 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500617 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800618
619 # A context is necessary for any extension which uses the r2i conversion
620 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
621 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500622 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800623
624 # We have no configuration database - but perhaps we should (some
625 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500626 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800627
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800628 # Initialize the subject and issuer, if appropriate. ctx is a local,
629 # and as far as I can tell none of the X509V3_* APIs invoked here steal
630 # any references, so no need to mess with reference counts or duplicates.
631 if issuer is not None:
632 if not isinstance(issuer, X509):
633 raise TypeError("issuer must be an X509 instance")
634 ctx.issuer_cert = issuer._x509
635 if subject is not None:
636 if not isinstance(subject, X509):
637 raise TypeError("subject must be an X509 instance")
638 ctx.subject_cert = subject._x509
639
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800640 if critical:
641 # There are other OpenSSL APIs which would let us pass in critical
642 # separately, but they're harder to use, and since value is already
643 # a pile of crappy junk smuggling a ton of utterly important
644 # structured data, what's the point of trying to avoid nasty stuff
645 # with strings? (However, X509V3_EXT_i2d in particular seems like it
646 # would be a better API to invoke. I do not know where to get the
647 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500648 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800649
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500650 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
651 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800652 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500653 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800654
655
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400656 @property
657 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500658 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400659
660 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500661 _lib.GEN_EMAIL: "email",
662 _lib.GEN_DNS: "DNS",
663 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400664 }
665
666 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500667 method = _lib.X509V3_EXT_get(self._extension)
668 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500669 # TODO: This is untested.
670 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400671 payload = self._extension.value.data
672 length = self._extension.value.length
673
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500674 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400675 payloadptr[0] = payload
676
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500677 if method.it != _ffi.NULL:
678 ptr = _lib.ASN1_ITEM_ptr(method.it)
679 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
680 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400681 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500682 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400683 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500684 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400685
686 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500687 for i in range(_lib.sk_GENERAL_NAME_num(names)):
688 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400689 try:
690 label = self._prefixes[name.type]
691 except KeyError:
692 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500693 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500694 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400695 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500696 value = _native(
697 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
698 parts.append(label + ":" + value)
699 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400700
701
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800702 def __str__(self):
703 """
704 :return: a nice text representation of the extension
705 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500706 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400707 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800708
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400709 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500710 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800711 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500712 # TODO: This is untested.
713 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800714
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500715 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800716
717
718 def get_critical(self):
719 """
720 Returns the critical field of the X509Extension
721
722 :return: The critical field.
723 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500724 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800725
726
727 def get_short_name(self):
728 """
729 Returns the short version of the type name of the X509Extension
730
731 :return: The short type name.
732 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500733 obj = _lib.X509_EXTENSION_get_object(self._extension)
734 nid = _lib.OBJ_obj2nid(obj)
735 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800736
737
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800738 def get_data(self):
739 """
740 Returns the data of the X509Extension
741
742 :return: A :py:data:`str` giving the X509Extension's ASN.1 encoded data.
743 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500744 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
745 string_result = _ffi.cast('ASN1_STRING*', octet_result)
746 char_result = _lib.ASN1_STRING_data(string_result)
747 result_length = _lib.ASN1_STRING_length(string_result)
748 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800749
750X509ExtensionType = X509Extension
751
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800752
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800753class X509Req(object):
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800754 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500755 req = _lib.X509_REQ_new()
756 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800757
758
759 def set_pubkey(self, pkey):
760 """
761 Set the public key of the certificate request
762
763 :param pkey: The public key to use
764 :return: None
765 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500766 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800767 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500768 # TODO: This is untested.
769 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800770
771
772 def get_pubkey(self):
773 """
774 Get the public key from the certificate request
775
776 :return: The public key
777 """
778 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500779 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
780 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500781 # TODO: This is untested.
782 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500783 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800784 pkey._only_public = True
785 return pkey
786
787
788 def set_version(self, version):
789 """
790 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
791 request.
792
793 :param version: The version number
794 :return: None
795 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500796 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800797 if not set_result:
798 _raise_current_error()
799
800
801 def get_version(self):
802 """
803 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
804 request.
805
806 :return: an integer giving the value of the version subfield
807 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500808 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800809
810
811 def get_subject(self):
812 """
813 Create an X509Name object for the subject of the certificate request
814
815 :return: An X509Name object
816 """
817 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500818 name._name = _lib.X509_REQ_get_subject_name(self._req)
819 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500820 # TODO: This is untested.
821 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800822
823 # The name is owned by the X509Req structure. As long as the X509Name
824 # Python object is alive, keep the X509Req Python object alive.
825 name._owner = self
826
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800827 return name
828
829
830 def add_extensions(self, extensions):
831 """
832 Add extensions to the request.
833
834 :param extensions: a sequence of X509Extension objects
835 :return: None
836 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500837 stack = _lib.sk_X509_EXTENSION_new_null()
838 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500839 # TODO: This is untested.
840 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800841
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500842 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800843
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800844 for ext in extensions:
845 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800846 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800847
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800848 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500849 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500851 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800852 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500853 # TODO: This is untested.
854 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800855
856
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800857 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800858 """
859 Get extensions to the request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800860
Jean-Paul Calderoneda3e6c62014-03-02 08:06:11 -0500861 :return: A :py:class:`list` of :py:class:`X509Extension` objects.
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800862 """
863 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500864 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500865 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800866 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500867 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800868 exts.append(ext)
869 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800870
871
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800872 def sign(self, pkey, digest):
873 """
874 Sign the certificate request using the supplied key and digest
875
876 :param pkey: The key to sign with
877 :param digest: The message digest to use
878 :return: None
879 """
880 if pkey._only_public:
881 raise ValueError("Key has only public part")
882
883 if not pkey._initialized:
884 raise ValueError("Key is uninitialized")
885
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500886 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500887 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800888 raise ValueError("No such digest method")
889
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500890 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800891 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500892 # TODO: This is untested.
893 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800894
895
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800896 def verify(self, pkey):
897 """
898 Verifies a certificate request using the supplied public key
899
900 :param key: a public key
901 :return: True if the signature is correct.
902
903 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
904 problem verifying the signature.
905 """
906 if not isinstance(pkey, PKey):
907 raise TypeError("pkey must be a PKey instance")
908
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500909 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800910 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500911 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800912
913 return result
914
915
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800916X509ReqType = X509Req
917
918
919
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800920class X509(object):
921 def __init__(self):
922 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500923 x509 = _lib.X509_new()
924 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800925
926
927 def set_version(self, version):
928 """
929 Set version number of the certificate
930
931 :param version: The version number
932 :type version: :py:class:`int`
933
934 :return: None
935 """
936 if not isinstance(version, int):
937 raise TypeError("version must be an integer")
938
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500939 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800940
941
942 def get_version(self):
943 """
944 Return version number of the certificate
945
946 :return: Version number as a Python integer
947 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500948 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800949
950
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800951 def get_pubkey(self):
952 """
953 Get the public key of the certificate
954
955 :return: The public key
956 """
957 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500958 pkey._pkey = _lib.X509_get_pubkey(self._x509)
959 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800960 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500961 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800962 pkey._only_public = True
963 return pkey
964
965
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800966 def set_pubkey(self, pkey):
967 """
968 Set the public key of the certificate
969
970 :param pkey: The public key
971
972 :return: None
973 """
974 if not isinstance(pkey, PKey):
975 raise TypeError("pkey must be a PKey instance")
976
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500977 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800978 if not set_result:
979 _raise_current_error()
980
981
982 def sign(self, pkey, digest):
983 """
984 Sign the certificate using the supplied key and digest
985
986 :param pkey: The key to sign with
987 :param digest: The message digest to use
988 :return: None
989 """
990 if not isinstance(pkey, PKey):
991 raise TypeError("pkey must be a PKey instance")
992
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800993 if pkey._only_public:
994 raise ValueError("Key only has public part")
995
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800996 if not pkey._initialized:
997 raise ValueError("Key is uninitialized")
998
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500999 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001000 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001001 raise ValueError("No such digest method")
1002
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001003 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001004 if not sign_result:
1005 _raise_current_error()
1006
1007
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001008 def get_signature_algorithm(self):
1009 """
1010 Retrieve the signature algorithm used in the certificate
1011
1012 :return: A byte string giving the name of the signature algorithm used in
1013 the certificate.
1014 :raise ValueError: If the signature algorithm is undefined.
1015 """
1016 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001017 nid = _lib.OBJ_obj2nid(alg)
1018 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001019 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001020 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001021
1022
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001023 def digest(self, digest_name):
1024 """
1025 Return the digest of the X509 object.
1026
1027 :param digest_name: The name of the digest algorithm to use.
1028 :type digest_name: :py:class:`bytes`
1029
1030 :return: The digest of the object
1031 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001032 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001033 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001034 raise ValueError("No such digest method")
1035
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001036 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1037 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001038 result_length[0] = len(result_buffer)
1039
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001040 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001041 self._x509, digest, result_buffer, result_length)
1042
1043 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001044 # TODO: This is untested.
1045 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001046
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001047 return b":".join([
1048 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001049 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001050
1051
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001052 def subject_name_hash(self):
1053 """
1054 Return the hash of the X509 subject.
1055
1056 :return: The hash of the subject.
1057 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001058 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001059
1060
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001061 def set_serial_number(self, serial):
1062 """
1063 Set serial number of the certificate
1064
1065 :param serial: The serial number
1066 :type serial: :py:class:`int`
1067
1068 :return: None
1069 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001070 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001071 raise TypeError("serial must be an integer")
1072
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001073 hex_serial = hex(serial)[2:]
1074 if not isinstance(hex_serial, bytes):
1075 hex_serial = hex_serial.encode('ascii')
1076
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001077 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001078
1079 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1080 # it. If bignum is still NULL after this call, then the return value is
1081 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001082 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001083
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001084 if bignum_serial[0] == _ffi.NULL:
1085 set_result = _lib.ASN1_INTEGER_set(
1086 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001087 if set_result:
1088 # TODO Not tested
1089 _raise_current_error()
1090 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001091 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1092 _lib.BN_free(bignum_serial[0])
1093 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001094 # TODO Not tested
1095 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001096 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1097 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001098 if not set_result:
1099 # TODO Not tested
1100 _raise_current_error()
1101
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001102
1103 def get_serial_number(self):
1104 """
1105 Return serial number of the certificate
1106
1107 :return: Serial number as a Python integer
1108 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001109 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1110 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001111 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001112 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001113 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001114 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001115 serial = int(hexstring_serial, 16)
1116 return serial
1117 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001118 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001119 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001120 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001121
1122
1123 def gmtime_adj_notAfter(self, amount):
1124 """
1125 Adjust the time stamp for when the certificate stops being valid
1126
1127 :param amount: The number of seconds by which to adjust the ending
1128 validity time.
1129 :type amount: :py:class:`int`
1130
1131 :return: None
1132 """
1133 if not isinstance(amount, int):
1134 raise TypeError("amount must be an integer")
1135
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001136 notAfter = _lib.X509_get_notAfter(self._x509)
1137 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001138
1139
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001140 def gmtime_adj_notBefore(self, amount):
1141 """
1142 Change the timestamp for when the certificate starts being valid to the current
1143 time plus an offset.
1144
1145 :param amount: The number of seconds by which to adjust the starting validity
1146 time.
1147 :return: None
1148 """
1149 if not isinstance(amount, int):
1150 raise TypeError("amount must be an integer")
1151
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001152 notBefore = _lib.X509_get_notBefore(self._x509)
1153 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001154
1155
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001156 def has_expired(self):
1157 """
1158 Check whether the certificate has expired.
1159
1160 :return: True if the certificate has expired, false otherwise
1161 """
1162 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001163 notAfter = _lib.X509_get_notAfter(self._x509)
1164 return _lib.ASN1_UTCTIME_cmp_time_t(
1165 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001166
1167
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001168 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001169 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001170
1171
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001172 def get_notBefore(self):
1173 """
1174 Retrieve the time stamp for when the certificate starts being valid
1175
1176 :return: A string giving the timestamp, in the format::
1177
1178 YYYYMMDDhhmmssZ
1179 YYYYMMDDhhmmss+hhmm
1180 YYYYMMDDhhmmss-hhmm
1181
1182 or None if there is no value set.
1183 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001184 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001185
1186
1187 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001188 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001189
1190
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001191 def set_notBefore(self, when):
1192 """
1193 Set the time stamp for when the certificate starts being valid
1194
1195 :param when: A string giving the timestamp, in the format:
1196
1197 YYYYMMDDhhmmssZ
1198 YYYYMMDDhhmmss+hhmm
1199 YYYYMMDDhhmmss-hhmm
1200 :type when: :py:class:`bytes`
1201
1202 :return: None
1203 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001204 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001205
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001206
1207 def get_notAfter(self):
1208 """
1209 Retrieve the time stamp for when the certificate stops being valid
1210
1211 :return: A string giving the timestamp, in the format::
1212
1213 YYYYMMDDhhmmssZ
1214 YYYYMMDDhhmmss+hhmm
1215 YYYYMMDDhhmmss-hhmm
1216
1217 or None if there is no value set.
1218 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001219 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001220
1221
1222 def set_notAfter(self, when):
1223 """
1224 Set the time stamp for when the certificate stops being valid
1225
1226 :param when: A string giving the timestamp, in the format:
1227
1228 YYYYMMDDhhmmssZ
1229 YYYYMMDDhhmmss+hhmm
1230 YYYYMMDDhhmmss-hhmm
1231 :type when: :py:class:`bytes`
1232
1233 :return: None
1234 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001235 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001236
1237
1238 def _get_name(self, which):
1239 name = X509Name.__new__(X509Name)
1240 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001241 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001242 # TODO: This is untested.
1243 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001244
1245 # The name is owned by the X509 structure. As long as the X509Name
1246 # Python object is alive, keep the X509 Python object alive.
1247 name._owner = self
1248
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001249 return name
1250
1251
1252 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001253 if not isinstance(name, X509Name):
1254 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001255 set_result = which(self._x509, name._name)
1256 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001257 # TODO: This is untested.
1258 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001259
1260
1261 def get_issuer(self):
1262 """
1263 Create an X509Name object for the issuer of the certificate
1264
1265 :return: An X509Name object
1266 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001267 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001268
1269
1270 def set_issuer(self, issuer):
1271 """
1272 Set the issuer of the certificate
1273
1274 :param issuer: The issuer name
1275 :type issuer: :py:class:`X509Name`
1276
1277 :return: None
1278 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001279 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001280
1281
1282 def get_subject(self):
1283 """
1284 Create an X509Name object for the subject of the certificate
1285
1286 :return: An X509Name object
1287 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001288 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001289
1290
1291 def set_subject(self, subject):
1292 """
1293 Set the subject of the certificate
1294
1295 :param subject: The subject name
1296 :type subject: :py:class:`X509Name`
1297 :return: None
1298 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001299 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001300
1301
1302 def get_extension_count(self):
1303 """
1304 Get the number of extensions on the certificate.
1305
1306 :return: The number of extensions as an integer.
1307 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001308 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001309
1310
1311 def add_extensions(self, extensions):
1312 """
1313 Add extensions to the certificate.
1314
1315 :param extensions: a sequence of X509Extension objects
1316 :return: None
1317 """
1318 for ext in extensions:
1319 if not isinstance(ext, X509Extension):
1320 raise ValueError("One of the elements is not an X509Extension")
1321
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001322 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001323 if not add_result:
1324 _raise_current_error()
1325
1326
1327 def get_extension(self, index):
1328 """
1329 Get a specific extension of the certificate by index.
1330
1331 :param index: The index of the extension to retrieve.
1332 :return: The X509Extension object at the specified index.
1333 """
1334 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001335 ext._extension = _lib.X509_get_ext(self._x509, index)
1336 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001337 raise IndexError("extension index out of bounds")
1338
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001339 extension = _lib.X509_EXTENSION_dup(ext._extension)
1340 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001341 return ext
1342
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001343X509Type = X509
1344
1345
1346
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001347class X509Store(object):
1348 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001349 store = _lib.X509_STORE_new()
1350 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001351
1352
1353 def add_cert(self, cert):
1354 if not isinstance(cert, X509):
1355 raise TypeError()
1356
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001357 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001358 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001359 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001360
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001361
1362X509StoreType = X509Store
1363
1364
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001365class X509StoreContextError(Exception):
1366 """
1367 An error occurred while verifying a certificate using
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001368 `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001369
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001370 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001371 :type cert: :class:`X509`
1372
1373 """
1374 def __init__(self, message, certificate):
1375 super(X509StoreContextError, self).__init__(message)
1376 self.certificate = certificate
1377
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001378
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001379class X509StoreContext(object):
1380 """
1381 An X.509 store context.
1382
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001383 An :py:class:`X509StoreContext` is used to define some of the criteria for
1384 certificate verification. The information encapsulated in this object
1385 includes, but is not limited to, a set of trusted certificates,
1386 verification parameters, and revoked certificates.
1387
1388 Of these, only the set of trusted certificates is currently exposed.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001389
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001390 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1391 instance. It is dynamically allocated and automatically garbage
1392 collected.
1393
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001394 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001395
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001396 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001397 """
1398
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001399 def __init__(self, store, certificate):
1400 """
1401 :param X509Store store: The certificates which will be trusted for the
1402 purposes of any verifications.
1403
1404 :param X509 certificate: The certificate to be verified.
1405 """
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001406 store_ctx = _lib.X509_STORE_CTX_new()
1407 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1408 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001409 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001410 # Make the store context available for use after instantiating this
1411 # class by initializing it now. Per testing, subsequent calls to
1412 # :py:meth:`_init` have no adverse affect.
1413 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001414
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001415
1416 def _init(self):
1417 """
1418 Set up the store context for a subsequent verification operation.
1419 """
1420 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1421 if ret <= 0:
1422 _raise_current_error()
1423
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001424
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001425 def _cleanup(self):
1426 """
1427 Internally cleans up the store context.
1428
1429 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001430 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001431 """
1432 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1433
1434
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001435 def _exception_from_context(self):
1436 """
1437 Convert an OpenSSL native context error failure into a Python
1438 exception.
1439
1440 When a call to native OpenSSL X509_verify_cert fails, additonal information
1441 about the failure can be obtained from the store context.
1442 """
1443 errors = [
1444 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1445 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1446 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1447 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1448 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001449 # A context error should always be associated with a certificate, so we
1450 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001451 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001452 _cert = _lib.X509_dup(_x509)
1453 pycert = X509.__new__(X509)
1454 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001455 return X509StoreContextError(errors, pycert)
1456
1457
Stephen Holsapple46a09252015-02-12 14:45:43 -08001458 def set_store(self, store):
1459 """
1460 Set the context's trust store.
1461
1462 :param X509Store store: The certificates which will be trusted for the
1463 purposes of any *future* verifications.
1464 """
1465 self._store = store
1466
1467
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001468 def verify_certificate(self):
1469 """
1470 Verify a certificate in a context.
1471
1472 :param store_ctx: The :py:class:`X509StoreContext` to verify.
1473 :raises: Error
1474 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001475 # Always re-initialize the store context in case
1476 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001477 self._init()
1478 ret = _lib.X509_verify_cert(self._store_ctx)
1479 self._cleanup()
1480 if ret <= 0:
1481 raise self._exception_from_context()
1482
1483
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001484
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001485def load_certificate(type, buffer):
1486 """
1487 Load a certificate from a buffer
1488
1489 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001490
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001491 :param buffer: The buffer the certificate is stored in
1492 :type buffer: :py:class:`bytes`
1493
1494 :return: The X509 object
1495 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001496 if isinstance(buffer, _text_type):
1497 buffer = buffer.encode("ascii")
1498
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001499 bio = _new_mem_buf(buffer)
1500
1501 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001502 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001503 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001504 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001505 else:
1506 raise ValueError(
1507 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1508
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001509 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001510 _raise_current_error()
1511
1512 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001513 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001514 return cert
1515
1516
1517def dump_certificate(type, cert):
1518 """
1519 Dump a certificate to a buffer
1520
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001521 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1522 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001523 :param cert: The certificate to dump
1524 :return: The buffer with the dumped certificate in
1525 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001526 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001527
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001528 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001529 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001530 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001531 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001532 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001533 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001534 else:
1535 raise ValueError(
1536 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1537 "FILETYPE_TEXT")
1538
1539 return _bio_to_string(bio)
1540
1541
1542
1543def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1544 """
1545 Dump a private key to a buffer
1546
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001547 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1548 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001549 :param pkey: The PKey to dump
1550 :param cipher: (optional) if encrypted PEM format, the cipher to
1551 use
1552 :param passphrase: (optional) if encrypted PEM format, this can be either
1553 the passphrase to use, or a callback for providing the
1554 passphrase.
1555 :return: The buffer with the dumped key in
1556 :rtype: :py:data:`str`
1557 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001558 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001559
1560 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001561 if passphrase is None:
1562 raise TypeError(
1563 "if a value is given for cipher "
1564 "one must also be given for passphrase")
1565 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001566 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001567 raise ValueError("Invalid cipher name")
1568 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001569 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001570
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001571 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001572 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001573 result_code = _lib.PEM_write_bio_PrivateKey(
1574 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001575 helper.callback, helper.callback_args)
1576 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001577 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001578 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001579 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001580 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1581 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001582 # TODO RSA_free(rsa)?
1583 else:
1584 raise ValueError(
1585 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1586 "FILETYPE_TEXT")
1587
1588 if result_code == 0:
1589 _raise_current_error()
1590
1591 return _bio_to_string(bio)
1592
1593
1594
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001595def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001596 copy = _lib.X509_REVOKED_new()
1597 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001598 # TODO: This is untested.
1599 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001600
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001601 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001602 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001603 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001604
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001605 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001606 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001607 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001608
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001609 if original.extensions != _ffi.NULL:
1610 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1611 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1612 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1613 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1614 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001615 copy.extensions = extension_stack
1616
1617 copy.sequence = original.sequence
1618 return copy
1619
1620
1621
1622class Revoked(object):
1623 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1624 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1625 # OCSP_crl_reason_str. We use the latter, just like the command line
1626 # program.
1627 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001628 b"unspecified",
1629 b"keyCompromise",
1630 b"CACompromise",
1631 b"affiliationChanged",
1632 b"superseded",
1633 b"cessationOfOperation",
1634 b"certificateHold",
1635 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001636 ]
1637
1638 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001639 revoked = _lib.X509_REVOKED_new()
1640 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001641
1642
1643 def set_serial(self, hex_str):
1644 """
1645 Set the serial number of a revoked Revoked structure
1646
1647 :param hex_str: The new serial number.
1648 :type hex_str: :py:data:`str`
1649 :return: None
1650 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001651 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1652 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001653 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001654 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001655 if not bn_result:
1656 raise ValueError("bad hex string")
1657
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001658 asn1_serial = _ffi.gc(
1659 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1660 _lib.ASN1_INTEGER_free)
1661 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001662
1663
1664 def get_serial(self):
1665 """
1666 Return the serial number of a Revoked structure
1667
1668 :return: The serial number as a string
1669 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001670 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001671
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001672 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001673 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001674 # TODO: This is untested.
1675 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001676
1677 return _bio_to_string(bio)
1678
1679
1680 def _delete_reason(self):
1681 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001682 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1683 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1684 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1685 _lib.X509_EXTENSION_free(ext)
1686 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001687 break
1688
1689
1690 def set_reason(self, reason):
1691 """
1692 Set the reason of a Revoked object.
1693
1694 If :py:data:`reason` is :py:data:`None`, delete the reason instead.
1695
1696 :param reason: The reason string.
1697 :type reason: :py:class:`str` or :py:class:`NoneType`
1698 :return: None
1699 """
1700 if reason is None:
1701 self._delete_reason()
1702 elif not isinstance(reason, bytes):
1703 raise TypeError("reason must be None or a byte string")
1704 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001705 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001706 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1707
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001708 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1709 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001710 # TODO: This is untested.
1711 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001712 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001713
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001714 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1715 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001716 # TODO: This is untested.
1717 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001718
1719 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001720 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1721 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001722
1723 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001724 # TODO: This is untested.
1725 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001726
1727
1728 def get_reason(self):
1729 """
1730 Return the reason of a Revoked object.
1731
1732 :return: The reason as a string
1733 """
1734 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001735 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1736 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1737 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001738 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001739
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001740 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001741 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001742 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001743 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001744 # TODO: This is untested.
1745 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001746
1747 return _bio_to_string(bio)
1748
1749
1750 def all_reasons(self):
1751 """
1752 Return a list of all the supported reason strings.
1753
1754 :return: A list of reason strings.
1755 """
1756 return self._crl_reasons[:]
1757
1758
1759 def set_rev_date(self, when):
1760 """
1761 Set the revocation timestamp
1762
1763 :param when: A string giving the timestamp, in the format:
1764
1765 YYYYMMDDhhmmssZ
1766 YYYYMMDDhhmmss+hhmm
1767 YYYYMMDDhhmmss-hhmm
1768
1769 :return: None
1770 """
1771 return _set_asn1_time(self._revoked.revocationDate, when)
1772
1773
1774 def get_rev_date(self):
1775 """
1776 Retrieve the revocation date
1777
1778 :return: A string giving the timestamp, in the format:
1779
1780 YYYYMMDDhhmmssZ
1781 YYYYMMDDhhmmss+hhmm
1782 YYYYMMDDhhmmss-hhmm
1783 """
1784 return _get_asn1_time(self._revoked.revocationDate)
1785
1786
1787
1788class CRL(object):
1789 def __init__(self):
1790 """
1791 Create a new empty CRL object.
1792 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001793 crl = _lib.X509_CRL_new()
1794 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001795
1796
1797 def get_revoked(self):
1798 """
1799 Return revoked portion of the CRL structure (by value not reference).
1800
1801 :return: A tuple of Revoked objects.
1802 """
1803 results = []
1804 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001805 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1806 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807 revoked_copy = _X509_REVOKED_dup(revoked)
1808 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001809 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001810 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001811 if results:
1812 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001813
1814
1815 def add_revoked(self, revoked):
1816 """
1817 Add a revoked (by value not reference) to the CRL structure
1818
1819 :param revoked: The new revoked.
1820 :type revoked: :class:`X509`
1821
1822 :return: None
1823 """
1824 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001825 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001826 # TODO: This is untested.
1827 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001828
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001829 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001830 if add_result == 0:
1831 # TODO: This is untested.
1832 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001833
1834
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001835 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001836 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001837 """
1838 export a CRL as a string
1839
1840 :param cert: Used to sign CRL.
1841 :type cert: :class:`X509`
1842
1843 :param key: Used to sign CRL.
1844 :type key: :class:`PKey`
1845
1846 :param type: The export format, either :py:data:`FILETYPE_PEM`, :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
1847
1848 :param days: The number of days until the next update of this CRL.
1849 :type days: :py:data:`int`
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001850
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001851 :param digest: The message digest to use (eg ``"sha1"``).
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001852 :type digest: :py:data:`str`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001853
1854 :return: :py:data:`str`
1855 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001856 if not isinstance(cert, X509):
1857 raise TypeError("cert must be an X509 instance")
1858 if not isinstance(key, PKey):
1859 raise TypeError("key must be a PKey instance")
1860 if not isinstance(type, int):
1861 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001862
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001863 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001864 _warn(
1865 "The default message digest (md5) is deprecated. "
1866 "Pass the name of a message digest explicitly.",
1867 category=DeprecationWarning,
1868 stacklevel=2,
1869 )
1870 digest = "md5"
1871
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001872 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
1873 if digest_obj == _ffi.NULL:
1874 raise ValueError("No such digest method")
1875
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001876 bio = _lib.BIO_new(_lib.BIO_s_mem())
1877 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001878 # TODO: This is untested.
1879 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001880
1881 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001882 sometime = _lib.ASN1_TIME_new()
1883 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001884 # TODO: This is untested.
1885 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001886
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001887 _lib.X509_gmtime_adj(sometime, 0)
1888 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001889
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001890 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1891 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001892
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001893 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001894
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001895 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001896 if not sign_result:
1897 _raise_current_error()
1898
1899 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001900 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001901 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001902 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001903 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001904 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001905 else:
1906 raise ValueError(
1907 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1908
1909 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001910 # TODO: This is untested.
1911 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001912
1913 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001914CRLType = CRL
1915
1916
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001917
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001918class PKCS7(object):
1919 def type_is_signed(self):
1920 """
1921 Check if this NID_pkcs7_signed object
1922
1923 :return: True if the PKCS7 is of type signed
1924 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001925 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001926 return True
1927 return False
1928
1929
1930 def type_is_enveloped(self):
1931 """
1932 Check if this NID_pkcs7_enveloped object
1933
1934 :returns: True if the PKCS7 is of type enveloped
1935 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001936 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001937 return True
1938 return False
1939
1940
1941 def type_is_signedAndEnveloped(self):
1942 """
1943 Check if this NID_pkcs7_signedAndEnveloped object
1944
1945 :returns: True if the PKCS7 is of type signedAndEnveloped
1946 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001947 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001948 return True
1949 return False
1950
1951
1952 def type_is_data(self):
1953 """
1954 Check if this NID_pkcs7_data object
1955
1956 :return: True if the PKCS7 is of type data
1957 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001958 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001959 return True
1960 return False
1961
1962
1963 def get_type_name(self):
1964 """
1965 Returns the type name of the PKCS7 structure
1966
1967 :return: A string with the typename
1968 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001969 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1970 string_type = _lib.OBJ_nid2sn(nid)
1971 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001972
1973PKCS7Type = PKCS7
1974
1975
1976
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001977class PKCS12(object):
1978 def __init__(self):
1979 self._pkey = None
1980 self._cert = None
1981 self._cacerts = None
1982 self._friendlyname = None
1983
1984
1985 def get_certificate(self):
1986 """
1987 Return certificate portion of the PKCS12 structure
1988
1989 :return: X509 object containing the certificate
1990 """
1991 return self._cert
1992
1993
1994 def set_certificate(self, cert):
1995 """
1996 Replace the certificate portion of the PKCS12 structure
1997
1998 :param cert: The new certificate.
1999 :type cert: :py:class:`X509` or :py:data:`None`
2000 :return: None
2001 """
2002 if not isinstance(cert, X509):
2003 raise TypeError("cert must be an X509 instance")
2004 self._cert = cert
2005
2006
2007 def get_privatekey(self):
2008 """
2009 Return private key portion of the PKCS12 structure
2010
2011 :returns: PKey object containing the private key
2012 """
2013 return self._pkey
2014
2015
2016 def set_privatekey(self, pkey):
2017 """
2018 Replace or set the certificate portion of the PKCS12 structure
2019
2020 :param pkey: The new private key.
2021 :type pkey: :py:class:`PKey`
2022 :return: None
2023 """
2024 if not isinstance(pkey, PKey):
2025 raise TypeError("pkey must be a PKey instance")
2026 self._pkey = pkey
2027
2028
2029 def get_ca_certificates(self):
2030 """
2031 Return CA certificates within of the PKCS12 object
2032
2033 :return: A newly created tuple containing the CA certificates in the chain,
2034 if any are present, or None if no CA certificates are present.
2035 """
2036 if self._cacerts is not None:
2037 return tuple(self._cacerts)
2038
2039
2040 def set_ca_certificates(self, cacerts):
2041 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002042 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002043
2044 :param cacerts: The new CA certificates.
2045 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2046 :return: None
2047 """
2048 if cacerts is None:
2049 self._cacerts = None
2050 else:
2051 cacerts = list(cacerts)
2052 for cert in cacerts:
2053 if not isinstance(cert, X509):
2054 raise TypeError("iterable must only contain X509 instances")
2055 self._cacerts = cacerts
2056
2057
2058 def set_friendlyname(self, name):
2059 """
2060 Replace or set the certificate portion of the PKCS12 structure
2061
2062 :param name: The new friendly name.
2063 :type name: :py:class:`bytes`
2064 :return: None
2065 """
2066 if name is None:
2067 self._friendlyname = None
2068 elif not isinstance(name, bytes):
2069 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2070 self._friendlyname = name
2071
2072
2073 def get_friendlyname(self):
2074 """
2075 Return friendly name portion of the PKCS12 structure
2076
2077 :returns: String containing the friendlyname
2078 """
2079 return self._friendlyname
2080
2081
2082 def export(self, passphrase=None, iter=2048, maciter=1):
2083 """
2084 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2085
2086 :param passphrase: used to encrypt the PKCS12
2087 :type passphrase: :py:data:`bytes`
2088
2089 :param iter: How many times to repeat the encryption
2090 :type iter: :py:data:`int`
2091
2092 :param maciter: How many times to repeat the MAC
2093 :type maciter: :py:data:`int`
2094
2095 :return: The string containing the PKCS12
2096 """
2097 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002098 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002099 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002100 cacerts = _lib.sk_X509_new_null()
2101 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002102 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002103 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002104
2105 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002106 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002107
2108 friendlyname = self._friendlyname
2109 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002110 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002111
2112 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002113 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002114 else:
2115 pkey = self._pkey._pkey
2116
2117 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002118 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002119 else:
2120 cert = self._cert._x509
2121
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002122 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002123 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002124 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2125 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002126 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002127 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002128 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002129 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002130
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002131 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002132 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002133 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002134
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002135PKCS12Type = PKCS12
2136
2137
2138
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002139class NetscapeSPKI(object):
2140 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002141 spki = _lib.NETSCAPE_SPKI_new()
2142 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002143
2144
2145 def sign(self, pkey, digest):
2146 """
2147 Sign the certificate request using the supplied key and digest
2148
2149 :param pkey: The key to sign with
2150 :param digest: The message digest to use
2151 :return: None
2152 """
2153 if pkey._only_public:
2154 raise ValueError("Key has only public part")
2155
2156 if not pkey._initialized:
2157 raise ValueError("Key is uninitialized")
2158
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002159 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002160 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002161 raise ValueError("No such digest method")
2162
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002163 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002164 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002165 # TODO: This is untested.
2166 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002167
2168
2169 def verify(self, key):
2170 """
2171 Verifies a certificate request using the supplied public key
2172
2173 :param key: a public key
2174 :return: True if the signature is correct.
2175 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2176 problem verifying the signature.
2177 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002178 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002179 if answer <= 0:
2180 _raise_current_error()
2181 return True
2182
2183
2184 def b64_encode(self):
2185 """
2186 Generate a base64 encoded string from an SPKI
2187
2188 :return: The base64 encoded string
2189 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002190 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2191 result = _ffi.string(encoded)
2192 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002193 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002194
2195
2196 def get_pubkey(self):
2197 """
2198 Get the public key of the certificate
2199
2200 :return: The public key
2201 """
2202 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002203 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2204 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002205 # TODO: This is untested.
2206 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002207 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002208 pkey._only_public = True
2209 return pkey
2210
2211
2212 def set_pubkey(self, pkey):
2213 """
2214 Set the public key of the certificate
2215
2216 :param pkey: The public key
2217 :return: None
2218 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002219 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002220 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002221 # TODO: This is untested.
2222 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002223NetscapeSPKIType = NetscapeSPKI
2224
2225
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002226class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002227 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002228 if type != FILETYPE_PEM and passphrase is not None:
2229 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002230 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002231 self._more_args = more_args
2232 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002233 self._problems = []
2234
2235
2236 @property
2237 def callback(self):
2238 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002239 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002240 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002241 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002242 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002243 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002244 else:
2245 raise TypeError("Last argument must be string or callable")
2246
2247
2248 @property
2249 def callback_args(self):
2250 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002251 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002252 elif isinstance(self._passphrase, bytes):
2253 return self._passphrase
2254 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002255 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002256 else:
2257 raise TypeError("Last argument must be string or callable")
2258
2259
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002260 def raise_if_problem(self, exceptionType=Error):
2261 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002262 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002263 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002264 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002265 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002266 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002267 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002268
2269
2270 def _read_passphrase(self, buf, size, rwflag, userdata):
2271 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002272 if self._more_args:
2273 result = self._passphrase(size, rwflag, userdata)
2274 else:
2275 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002276 if not isinstance(result, bytes):
2277 raise ValueError("String expected")
2278 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002279 if self._truncate:
2280 result = result[:size]
2281 else:
2282 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002283 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002284 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002285 return len(result)
2286 except Exception as e:
2287 self._problems.append(e)
2288 return 0
2289
2290
2291
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002292def load_privatekey(type, buffer, passphrase=None):
2293 """
2294 Load a private key from a buffer
2295
2296 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2297 :param buffer: The buffer the key is stored in
2298 :param passphrase: (optional) if encrypted PEM format, this can be
2299 either the passphrase to use, or a callback for
2300 providing the passphrase.
2301
2302 :return: The PKey object
2303 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002304 if isinstance(buffer, _text_type):
2305 buffer = buffer.encode("ascii")
2306
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002307 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002308
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002309 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002310 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002311 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2312 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002313 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002314 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002315 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002316 else:
2317 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2318
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002319 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002320 _raise_current_error()
2321
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002322 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002323 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002324 return pkey
2325
2326
2327
2328def dump_certificate_request(type, req):
2329 """
2330 Dump a certificate request to a buffer
2331
2332 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2333 :param req: The certificate request to dump
2334 :return: The buffer with the dumped certificate request in
2335 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002336 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002337
2338 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002339 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002340 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002341 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002342 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002343 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002344 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002345 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002346
2347 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002348 # TODO: This is untested.
2349 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002350
2351 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002352
2353
2354
2355def load_certificate_request(type, buffer):
2356 """
2357 Load a certificate request from a buffer
2358
2359 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2360 :param buffer: The buffer the certificate request is stored in
2361 :return: The X509Req object
2362 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002363 if isinstance(buffer, _text_type):
2364 buffer = buffer.encode("ascii")
2365
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002366 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002367
2368 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002369 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002370 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002371 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002372 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002373 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002374
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002375 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002376 # TODO: This is untested.
2377 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002378
2379 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002380 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002381 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002382
2383
2384
2385def sign(pkey, data, digest):
2386 """
2387 Sign data with a digest
2388
2389 :param pkey: Pkey to sign with
2390 :param data: data to be signed
2391 :param digest: message digest to use
2392 :return: signature
2393 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002394 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002395 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002396 raise ValueError("No such digest method")
2397
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002398 md_ctx = _ffi.new("EVP_MD_CTX*")
2399 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002400
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002401 _lib.EVP_SignInit(md_ctx, digest_obj)
2402 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002403
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002404 signature_buffer = _ffi.new("unsigned char[]", 512)
2405 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002406 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002407 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002408 md_ctx, signature_buffer, signature_length, pkey._pkey)
2409
2410 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002411 # TODO: This is untested.
2412 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002413
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002414 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002415
2416
2417
2418def verify(cert, signature, data, digest):
2419 """
2420 Verify a signature
2421
2422 :param cert: signing certificate (X509 object)
2423 :param signature: signature returned by sign function
2424 :param data: data to be verified
2425 :param digest: message digest to use
2426 :return: None if the signature is correct, raise exception otherwise
2427 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002428 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002429 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002430 raise ValueError("No such digest method")
2431
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002432 pkey = _lib.X509_get_pubkey(cert._x509)
2433 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002434 # TODO: This is untested.
2435 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002436 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002437
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002438 md_ctx = _ffi.new("EVP_MD_CTX*")
2439 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002440
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002441 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2442 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2443 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002444
2445 if verify_result != 1:
2446 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002447
2448
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002449def load_crl(type, buffer):
2450 """
2451 Load a certificate revocation list from a buffer
2452
2453 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2454 :param buffer: The buffer the CRL is stored in
2455
2456 :return: The PKey object
2457 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002458 if isinstance(buffer, _text_type):
2459 buffer = buffer.encode("ascii")
2460
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002461 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002462
2463 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002464 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002465 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002466 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002467 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002468 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2469
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002470 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002471 _raise_current_error()
2472
2473 result = CRL.__new__(CRL)
2474 result._crl = crl
2475 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002476
2477
2478
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002479def load_pkcs7_data(type, buffer):
2480 """
2481 Load pkcs7 data from a buffer
2482
2483 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2484 :param buffer: The buffer with the pkcs7 data.
2485 :return: The PKCS7 object
2486 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002487 if isinstance(buffer, _text_type):
2488 buffer = buffer.encode("ascii")
2489
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002490 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002491
2492 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002493 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002494 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002495 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002496 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002497 # TODO: This is untested.
2498 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002499 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2500
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002501 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002502 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002503
2504 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002505 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002506 return pypkcs7
2507
2508
2509
Stephen Holsapple38482622014-04-05 20:29:34 -07002510def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002511 """
2512 Load a PKCS12 object from a buffer
2513
2514 :param buffer: The buffer the certificate is stored in
2515 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2516 :returns: The PKCS12 object
2517 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002518 if isinstance(buffer, _text_type):
2519 buffer = buffer.encode("ascii")
2520
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002521 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002522
Stephen Holsapple38482622014-04-05 20:29:34 -07002523 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2524 # password based encryption no password and a zero length password are two
2525 # different things, but OpenSSL implementation will try both to figure out
2526 # which one works.
2527 if not passphrase:
2528 passphrase = _ffi.NULL
2529
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002530 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2531 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002532 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002533 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002534
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002535 pkey = _ffi.new("EVP_PKEY**")
2536 cert = _ffi.new("X509**")
2537 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002538
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002539 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002540 if not parse_result:
2541 _raise_current_error()
2542
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002543 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002544
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002545 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2546 # queue for no particular reason. This error isn't interesting to anyone
2547 # outside this function. It's not even interesting to us. Get rid of it.
2548 try:
2549 _raise_current_error()
2550 except Error:
2551 pass
2552
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002553 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002554 pykey = None
2555 else:
2556 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002557 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002558
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002559 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002560 pycert = None
2561 friendlyname = None
2562 else:
2563 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002564 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002565
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002566 friendlyname_length = _ffi.new("int*")
2567 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2568 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2569 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002570 friendlyname = None
2571
2572 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002573 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002574 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002575 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002576 pycacerts.append(pycacert)
2577 if not pycacerts:
2578 pycacerts = None
2579
2580 pkcs12 = PKCS12.__new__(PKCS12)
2581 pkcs12._pkey = pykey
2582 pkcs12._cert = pycert
2583 pkcs12._cacerts = pycacerts
2584 pkcs12._friendlyname = friendlyname
2585 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002586
2587
2588def _initialize_openssl_threads(get_ident, Lock):
2589 import _ssl
2590 return
2591
2592 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2593
2594 def locking_function(mode, index, filename, line):
2595 if mode & _lib.CRYPTO_LOCK:
2596 locks[index].acquire()
2597 else:
2598 locks[index].release()
2599
2600 _lib.CRYPTO_set_id_callback(
2601 _ffi.callback("unsigned long (*)(void)", get_ident))
2602
2603 _lib.CRYPTO_set_locking_callback(
2604 _ffi.callback(
2605 "void (*)(int, int, const char*, int)", locking_function))
2606
2607
2608try:
2609 from thread import get_ident
2610 from threading import Lock
2611except ImportError:
2612 pass
2613else:
2614 _initialize_openssl_threads(get_ident, Lock)
2615 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002616
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002617# There are no direct unit tests for this initialization. It is tested
2618# indirectly since it is necessary for functions like dump_privatekey when
2619# using encryption.
2620#
2621# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2622# and some other similar tests may fail without this (though they may not if
2623# the Python runtime has already done some initialization of the underlying
2624# OpenSSL library (and is linked against the same one that cryptography is
2625# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002626_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002627
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002628# This is similar but exercised mainly by exception_from_error_queue. It calls
2629# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2630_lib.SSL_load_error_strings()