blob: ba83efe729a70ec6ca646a96875251ca1df0bc80 [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.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001841
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001842 :type cert: :class:`X509`
1843
1844 :param key: Used to sign CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001845
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001846 :type key: :class:`PKey`
1847
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001848 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1849 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001850 :param days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001851
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001852 :type days: :py:data:`int`
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001853
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001854 :param bytes digest: The name of the message digest to use (eg
1855 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001856
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001857 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001858 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001859 if not isinstance(cert, X509):
1860 raise TypeError("cert must be an X509 instance")
1861 if not isinstance(key, PKey):
1862 raise TypeError("key must be a PKey instance")
1863 if not isinstance(type, int):
1864 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001865
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001866 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001867 _warn(
1868 "The default message digest (md5) is deprecated. "
1869 "Pass the name of a message digest explicitly.",
1870 category=DeprecationWarning,
1871 stacklevel=2,
1872 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001873 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001874
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001875 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001876 if digest_obj == _ffi.NULL:
1877 raise ValueError("No such digest method")
1878
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001879 bio = _lib.BIO_new(_lib.BIO_s_mem())
1880 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001881 # TODO: This is untested.
1882 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001883
1884 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001885 sometime = _lib.ASN1_TIME_new()
1886 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001887 # TODO: This is untested.
1888 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001889
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001890 _lib.X509_gmtime_adj(sometime, 0)
1891 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001892
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001893 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1894 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001895
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001896 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001897
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001898 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001899 if not sign_result:
1900 _raise_current_error()
1901
1902 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001903 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001904 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001905 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001906 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001907 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001908 else:
1909 raise ValueError(
1910 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1911
1912 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001913 # TODO: This is untested.
1914 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001915
1916 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001917CRLType = CRL
1918
1919
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001920
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001921class PKCS7(object):
1922 def type_is_signed(self):
1923 """
1924 Check if this NID_pkcs7_signed object
1925
1926 :return: True if the PKCS7 is of type signed
1927 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001928 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001929 return True
1930 return False
1931
1932
1933 def type_is_enveloped(self):
1934 """
1935 Check if this NID_pkcs7_enveloped object
1936
1937 :returns: True if the PKCS7 is of type enveloped
1938 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001939 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001940 return True
1941 return False
1942
1943
1944 def type_is_signedAndEnveloped(self):
1945 """
1946 Check if this NID_pkcs7_signedAndEnveloped object
1947
1948 :returns: True if the PKCS7 is of type signedAndEnveloped
1949 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001950 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001951 return True
1952 return False
1953
1954
1955 def type_is_data(self):
1956 """
1957 Check if this NID_pkcs7_data object
1958
1959 :return: True if the PKCS7 is of type data
1960 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001961 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001962 return True
1963 return False
1964
1965
1966 def get_type_name(self):
1967 """
1968 Returns the type name of the PKCS7 structure
1969
1970 :return: A string with the typename
1971 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001972 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1973 string_type = _lib.OBJ_nid2sn(nid)
1974 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001975
1976PKCS7Type = PKCS7
1977
1978
1979
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001980class PKCS12(object):
1981 def __init__(self):
1982 self._pkey = None
1983 self._cert = None
1984 self._cacerts = None
1985 self._friendlyname = None
1986
1987
1988 def get_certificate(self):
1989 """
1990 Return certificate portion of the PKCS12 structure
1991
1992 :return: X509 object containing the certificate
1993 """
1994 return self._cert
1995
1996
1997 def set_certificate(self, cert):
1998 """
1999 Replace the certificate portion of the PKCS12 structure
2000
2001 :param cert: The new certificate.
2002 :type cert: :py:class:`X509` or :py:data:`None`
2003 :return: None
2004 """
2005 if not isinstance(cert, X509):
2006 raise TypeError("cert must be an X509 instance")
2007 self._cert = cert
2008
2009
2010 def get_privatekey(self):
2011 """
2012 Return private key portion of the PKCS12 structure
2013
2014 :returns: PKey object containing the private key
2015 """
2016 return self._pkey
2017
2018
2019 def set_privatekey(self, pkey):
2020 """
2021 Replace or set the certificate portion of the PKCS12 structure
2022
2023 :param pkey: The new private key.
2024 :type pkey: :py:class:`PKey`
2025 :return: None
2026 """
2027 if not isinstance(pkey, PKey):
2028 raise TypeError("pkey must be a PKey instance")
2029 self._pkey = pkey
2030
2031
2032 def get_ca_certificates(self):
2033 """
2034 Return CA certificates within of the PKCS12 object
2035
2036 :return: A newly created tuple containing the CA certificates in the chain,
2037 if any are present, or None if no CA certificates are present.
2038 """
2039 if self._cacerts is not None:
2040 return tuple(self._cacerts)
2041
2042
2043 def set_ca_certificates(self, cacerts):
2044 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002045 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002046
2047 :param cacerts: The new CA certificates.
2048 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2049 :return: None
2050 """
2051 if cacerts is None:
2052 self._cacerts = None
2053 else:
2054 cacerts = list(cacerts)
2055 for cert in cacerts:
2056 if not isinstance(cert, X509):
2057 raise TypeError("iterable must only contain X509 instances")
2058 self._cacerts = cacerts
2059
2060
2061 def set_friendlyname(self, name):
2062 """
2063 Replace or set the certificate portion of the PKCS12 structure
2064
2065 :param name: The new friendly name.
2066 :type name: :py:class:`bytes`
2067 :return: None
2068 """
2069 if name is None:
2070 self._friendlyname = None
2071 elif not isinstance(name, bytes):
2072 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2073 self._friendlyname = name
2074
2075
2076 def get_friendlyname(self):
2077 """
2078 Return friendly name portion of the PKCS12 structure
2079
2080 :returns: String containing the friendlyname
2081 """
2082 return self._friendlyname
2083
2084
2085 def export(self, passphrase=None, iter=2048, maciter=1):
2086 """
2087 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2088
2089 :param passphrase: used to encrypt the PKCS12
2090 :type passphrase: :py:data:`bytes`
2091
2092 :param iter: How many times to repeat the encryption
2093 :type iter: :py:data:`int`
2094
2095 :param maciter: How many times to repeat the MAC
2096 :type maciter: :py:data:`int`
2097
2098 :return: The string containing the PKCS12
2099 """
2100 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002101 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002102 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002103 cacerts = _lib.sk_X509_new_null()
2104 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002105 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002106 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002107
2108 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002109 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002110
2111 friendlyname = self._friendlyname
2112 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002113 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002114
2115 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002116 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002117 else:
2118 pkey = self._pkey._pkey
2119
2120 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002121 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002122 else:
2123 cert = self._cert._x509
2124
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002125 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002126 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002127 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2128 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002129 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002130 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002131 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002132 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002133
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002134 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002135 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002136 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002137
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002138PKCS12Type = PKCS12
2139
2140
2141
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002142class NetscapeSPKI(object):
2143 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002144 spki = _lib.NETSCAPE_SPKI_new()
2145 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002146
2147
2148 def sign(self, pkey, digest):
2149 """
2150 Sign the certificate request using the supplied key and digest
2151
2152 :param pkey: The key to sign with
2153 :param digest: The message digest to use
2154 :return: None
2155 """
2156 if pkey._only_public:
2157 raise ValueError("Key has only public part")
2158
2159 if not pkey._initialized:
2160 raise ValueError("Key is uninitialized")
2161
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002162 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002163 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002164 raise ValueError("No such digest method")
2165
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002166 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002167 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002168 # TODO: This is untested.
2169 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002170
2171
2172 def verify(self, key):
2173 """
2174 Verifies a certificate request using the supplied public key
2175
2176 :param key: a public key
2177 :return: True if the signature is correct.
2178 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2179 problem verifying the signature.
2180 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002181 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002182 if answer <= 0:
2183 _raise_current_error()
2184 return True
2185
2186
2187 def b64_encode(self):
2188 """
2189 Generate a base64 encoded string from an SPKI
2190
2191 :return: The base64 encoded string
2192 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002193 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2194 result = _ffi.string(encoded)
2195 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002196 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002197
2198
2199 def get_pubkey(self):
2200 """
2201 Get the public key of the certificate
2202
2203 :return: The public key
2204 """
2205 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002206 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2207 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002208 # TODO: This is untested.
2209 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002210 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002211 pkey._only_public = True
2212 return pkey
2213
2214
2215 def set_pubkey(self, pkey):
2216 """
2217 Set the public key of the certificate
2218
2219 :param pkey: The public key
2220 :return: None
2221 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002222 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002223 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002224 # TODO: This is untested.
2225 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002226NetscapeSPKIType = NetscapeSPKI
2227
2228
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002229class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002230 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002231 if type != FILETYPE_PEM and passphrase is not None:
2232 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002233 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002234 self._more_args = more_args
2235 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002236 self._problems = []
2237
2238
2239 @property
2240 def callback(self):
2241 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002242 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002243 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002244 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002245 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002246 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002247 else:
2248 raise TypeError("Last argument must be string or callable")
2249
2250
2251 @property
2252 def callback_args(self):
2253 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002254 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002255 elif isinstance(self._passphrase, bytes):
2256 return self._passphrase
2257 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002258 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002259 else:
2260 raise TypeError("Last argument must be string or callable")
2261
2262
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002263 def raise_if_problem(self, exceptionType=Error):
2264 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002265 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002266 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002267 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002268 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002269 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002270 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002271
2272
2273 def _read_passphrase(self, buf, size, rwflag, userdata):
2274 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002275 if self._more_args:
2276 result = self._passphrase(size, rwflag, userdata)
2277 else:
2278 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002279 if not isinstance(result, bytes):
2280 raise ValueError("String expected")
2281 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002282 if self._truncate:
2283 result = result[:size]
2284 else:
2285 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002286 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002287 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002288 return len(result)
2289 except Exception as e:
2290 self._problems.append(e)
2291 return 0
2292
2293
2294
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002295def load_privatekey(type, buffer, passphrase=None):
2296 """
2297 Load a private key from a buffer
2298
2299 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2300 :param buffer: The buffer the key is stored in
2301 :param passphrase: (optional) if encrypted PEM format, this can be
2302 either the passphrase to use, or a callback for
2303 providing the passphrase.
2304
2305 :return: The PKey object
2306 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002307 if isinstance(buffer, _text_type):
2308 buffer = buffer.encode("ascii")
2309
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002310 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002311
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002312 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002313 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002314 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2315 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002316 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002317 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002318 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002319 else:
2320 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2321
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002322 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002323 _raise_current_error()
2324
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002325 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002326 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002327 return pkey
2328
2329
2330
2331def dump_certificate_request(type, req):
2332 """
2333 Dump a certificate request to a buffer
2334
2335 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2336 :param req: The certificate request to dump
2337 :return: The buffer with the dumped certificate request in
2338 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002339 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002340
2341 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002342 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002343 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002344 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002345 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002346 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002347 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002348 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002349
2350 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002351 # TODO: This is untested.
2352 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002353
2354 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002355
2356
2357
2358def load_certificate_request(type, buffer):
2359 """
2360 Load a certificate request from a buffer
2361
2362 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2363 :param buffer: The buffer the certificate request is stored in
2364 :return: The X509Req object
2365 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002366 if isinstance(buffer, _text_type):
2367 buffer = buffer.encode("ascii")
2368
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002369 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002370
2371 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002372 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002373 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002374 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002375 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002376 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002377
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002378 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002379 # TODO: This is untested.
2380 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002381
2382 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002383 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002384 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002385
2386
2387
2388def sign(pkey, data, digest):
2389 """
2390 Sign data with a digest
2391
2392 :param pkey: Pkey to sign with
2393 :param data: data to be signed
2394 :param digest: message digest to use
2395 :return: signature
2396 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002397 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002398 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002399 raise ValueError("No such digest method")
2400
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002401 md_ctx = _ffi.new("EVP_MD_CTX*")
2402 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002403
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002404 _lib.EVP_SignInit(md_ctx, digest_obj)
2405 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002406
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002407 signature_buffer = _ffi.new("unsigned char[]", 512)
2408 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002409 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002410 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002411 md_ctx, signature_buffer, signature_length, pkey._pkey)
2412
2413 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002414 # TODO: This is untested.
2415 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002416
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002417 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002418
2419
2420
2421def verify(cert, signature, data, digest):
2422 """
2423 Verify a signature
2424
2425 :param cert: signing certificate (X509 object)
2426 :param signature: signature returned by sign function
2427 :param data: data to be verified
2428 :param digest: message digest to use
2429 :return: None if the signature is correct, raise exception otherwise
2430 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002431 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002432 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002433 raise ValueError("No such digest method")
2434
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002435 pkey = _lib.X509_get_pubkey(cert._x509)
2436 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002437 # TODO: This is untested.
2438 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002439 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002440
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002441 md_ctx = _ffi.new("EVP_MD_CTX*")
2442 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002443
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002444 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2445 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2446 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002447
2448 if verify_result != 1:
2449 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002450
2451
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002452def load_crl(type, buffer):
2453 """
2454 Load a certificate revocation list from a buffer
2455
2456 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2457 :param buffer: The buffer the CRL is stored in
2458
2459 :return: The PKey object
2460 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002461 if isinstance(buffer, _text_type):
2462 buffer = buffer.encode("ascii")
2463
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002464 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002465
2466 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002467 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002468 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002469 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002470 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002471 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2472
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002473 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002474 _raise_current_error()
2475
2476 result = CRL.__new__(CRL)
2477 result._crl = crl
2478 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002479
2480
2481
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002482def load_pkcs7_data(type, buffer):
2483 """
2484 Load pkcs7 data from a buffer
2485
2486 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2487 :param buffer: The buffer with the pkcs7 data.
2488 :return: The PKCS7 object
2489 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002490 if isinstance(buffer, _text_type):
2491 buffer = buffer.encode("ascii")
2492
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002493 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002494
2495 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002496 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002497 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002498 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002499 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002500 # TODO: This is untested.
2501 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002502 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2503
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002504 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002505 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002506
2507 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002508 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002509 return pypkcs7
2510
2511
2512
Stephen Holsapple38482622014-04-05 20:29:34 -07002513def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002514 """
2515 Load a PKCS12 object from a buffer
2516
2517 :param buffer: The buffer the certificate is stored in
2518 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2519 :returns: The PKCS12 object
2520 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002521 if isinstance(buffer, _text_type):
2522 buffer = buffer.encode("ascii")
2523
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002524 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002525
Stephen Holsapple38482622014-04-05 20:29:34 -07002526 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2527 # password based encryption no password and a zero length password are two
2528 # different things, but OpenSSL implementation will try both to figure out
2529 # which one works.
2530 if not passphrase:
2531 passphrase = _ffi.NULL
2532
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002533 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2534 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002535 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002536 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002537
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002538 pkey = _ffi.new("EVP_PKEY**")
2539 cert = _ffi.new("X509**")
2540 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002541
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002542 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002543 if not parse_result:
2544 _raise_current_error()
2545
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002546 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002547
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002548 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2549 # queue for no particular reason. This error isn't interesting to anyone
2550 # outside this function. It's not even interesting to us. Get rid of it.
2551 try:
2552 _raise_current_error()
2553 except Error:
2554 pass
2555
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002556 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002557 pykey = None
2558 else:
2559 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002560 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002561
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002562 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002563 pycert = None
2564 friendlyname = None
2565 else:
2566 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002567 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002568
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002569 friendlyname_length = _ffi.new("int*")
2570 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2571 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2572 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002573 friendlyname = None
2574
2575 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002576 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002577 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002578 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002579 pycacerts.append(pycacert)
2580 if not pycacerts:
2581 pycacerts = None
2582
2583 pkcs12 = PKCS12.__new__(PKCS12)
2584 pkcs12._pkey = pykey
2585 pkcs12._cert = pycert
2586 pkcs12._cacerts = pycacerts
2587 pkcs12._friendlyname = friendlyname
2588 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002589
2590
2591def _initialize_openssl_threads(get_ident, Lock):
2592 import _ssl
2593 return
2594
2595 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2596
2597 def locking_function(mode, index, filename, line):
2598 if mode & _lib.CRYPTO_LOCK:
2599 locks[index].acquire()
2600 else:
2601 locks[index].release()
2602
2603 _lib.CRYPTO_set_id_callback(
2604 _ffi.callback("unsigned long (*)(void)", get_ident))
2605
2606 _lib.CRYPTO_set_locking_callback(
2607 _ffi.callback(
2608 "void (*)(int, int, const char*, int)", locking_function))
2609
2610
2611try:
2612 from thread import get_ident
2613 from threading import Lock
2614except ImportError:
2615 pass
2616else:
2617 _initialize_openssl_threads(get_ident, Lock)
2618 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002619
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002620# There are no direct unit tests for this initialization. It is tested
2621# indirectly since it is necessary for functions like dump_privatekey when
2622# using encryption.
2623#
2624# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2625# and some other similar tests may fail without this (though they may not if
2626# the Python runtime has already done some initialization of the underlying
2627# OpenSSL library (and is linked against the same one that cryptography is
2628# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002629_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002630
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002631# This is similar but exercised mainly by exception_from_error_queue. It calls
2632# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2633_lib.SSL_load_error_strings()