blob: f9e189c8e8ac850886382af848efd6915f766efe [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__
5
6from six import (
7 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -04008 text_type as _text_type,
9 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080010
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050011from OpenSSL._util import (
12 ffi as _ffi,
13 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050014 exception_from_error_queue as _exception_from_error_queue,
15 byte_string as _byte_string,
Jean-Paul Calderone6462b072015-03-29 07:03:11 -040016 native as _native,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040017 text_to_bytes_and_warn as _text_to_bytes_and_warn,
18)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080019
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050020FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
21FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080022
23# TODO This was an API mistake. OpenSSL has no such constant.
24FILETYPE_TEXT = 2 ** 16 - 1
25
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050026TYPE_RSA = _lib.EVP_PKEY_RSA
27TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080028
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080029
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070030
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050031class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050032 """
33 An error occurred in an `OpenSSL.crypto` API.
34 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050035
36
37_raise_current_error = partial(_exception_from_error_queue, Error)
38
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070039
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050040
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050041def _untested_error(where):
42 """
43 An OpenSSL API failed somehow. Additionally, the failure which was
44 encountered isn't one that's exercised by the test suite so future behavior
45 of pyOpenSSL is now somewhat less predictable.
46 """
47 raise RuntimeError("Unknown %s failure" % (where,))
48
49
50
51def _new_mem_buf(buffer=None):
52 """
53 Allocate a new OpenSSL memory BIO.
54
55 Arrange for the garbage collector to clean it up automatically.
56
57 :param buffer: None or some bytes to use to put into the BIO so that they
58 can be read out.
59 """
60 if buffer is None:
61 bio = _lib.BIO_new(_lib.BIO_s_mem())
62 free = _lib.BIO_free
63 else:
64 data = _ffi.new("char[]", buffer)
65 bio = _lib.BIO_new_mem_buf(data, len(buffer))
66 # Keep the memory alive as long as the bio is alive!
67 def free(bio, ref=data):
68 return _lib.BIO_free(bio)
69
70 if bio == _ffi.NULL:
71 # TODO: This is untested.
72 _raise_current_error()
73
74 bio = _ffi.gc(bio, free)
75 return bio
76
77
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050078
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080079def _bio_to_string(bio):
80 """
81 Copy the contents of an OpenSSL BIO object into a Python byte string.
82 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050083 result_buffer = _ffi.new('char**')
84 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
85 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080086
87
88
Jean-Paul Calderone57122982013-02-21 08:47:05 -080089def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050090 """
91 The the time value of an ASN1 time object.
92
93 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
94 castable to that type) which will have its value set.
95 @param when: A string representation of the desired time value.
96
97 @raise TypeError: If C{when} is not a L{bytes} string.
98 @raise ValueError: If C{when} does not represent a time in the required
99 format.
100 @raise RuntimeError: If the time value cannot be set for some other
101 (unspecified) reason.
102 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800103 if not isinstance(when, bytes):
104 raise TypeError("when must be a byte string")
105
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500106 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
107 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800108 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500109 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
110 _lib.ASN1_STRING_set(dummy, when, len(when))
111 check_result = _lib.ASN1_GENERALIZEDTIME_check(
112 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800113 if not check_result:
114 raise ValueError("Invalid string")
115 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500116 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800117
118
119
120def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500121 """
122 Retrieve the time value of an ASN1 time object.
123
124 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
125 that type) from which the time value will be retrieved.
126
127 @return: The time value from C{timestamp} as a L{bytes} string in a certain
128 format. Or C{None} if the object contains no time value.
129 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500130 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
131 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800132 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500133 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
134 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800135 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500136 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
137 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
138 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500139 # This may happen:
140 # - if timestamp was not an ASN1_TIME
141 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
142 # - if a copy of the time data from timestamp cannot be made for
143 # the newly allocated ASN1_GENERALIZEDTIME
144 #
145 # These are difficult to test. cffi enforces the ASN1_TIME type.
146 # Memory allocation failures are a pain to trigger
147 # deterministically.
148 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800149 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500150 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800151 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500152 string_data = _lib.ASN1_STRING_data(string_timestamp)
153 string_result = _ffi.string(string_data)
154 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800155 return string_result
156
157
158
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800159class PKey(object):
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800160 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800161 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800162
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800163 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500164 pkey = _lib.EVP_PKEY_new()
165 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800166 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800167
168
169 def generate_key(self, type, bits):
170 """
171 Generate a key of a given type, with a given number of a bits
172
173 :param type: The key type (TYPE_RSA or TYPE_DSA)
174 :param bits: The number of bits
175
176 :return: None
177 """
178 if not isinstance(type, int):
179 raise TypeError("type must be an integer")
180
181 if not isinstance(bits, int):
182 raise TypeError("bits must be an integer")
183
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800184 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500185 exponent = _lib.BN_new()
186 exponent = _ffi.gc(exponent, _lib.BN_free)
187 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800188
189 if type == TYPE_RSA:
190 if bits <= 0:
191 raise ValueError("Invalid number of bits")
192
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500193 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800194
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500195 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500196 if result == 0:
197 # TODO: The test for this case is commented out. Different
198 # builds of OpenSSL appear to have different failure modes that
199 # make it hard to test. Visual inspection of the OpenSSL
200 # source reveals that a return value of 0 signals an error.
201 # Manual testing on a particular build of OpenSSL suggests that
202 # this is probably the appropriate way to handle those errors.
203 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800204
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500205 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800206 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500207 # TODO: It appears as though this can fail if an engine is in
208 # use which does not support RSA.
209 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800210
211 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500212 dsa = _lib.DSA_generate_parameters(
213 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
214 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500215 # TODO: This is untested.
216 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500217 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500218 # TODO: This is untested.
219 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500220 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500221 # TODO: This is untested.
222 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800223 else:
224 raise Error("No such key type")
225
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800226 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800227
228
229 def check(self):
230 """
231 Check the consistency of an RSA private key.
232
233 :return: True if key is consistent.
234 :raise Error: if the key is inconsistent.
235 :raise TypeError: if the key is of a type which cannot be checked.
236 Only RSA keys can currently be checked.
237 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800238 if self._only_public:
239 raise TypeError("public key only")
240
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500241 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800242 raise TypeError("key type unsupported")
243
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500244 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
245 rsa = _ffi.gc(rsa, _lib.RSA_free)
246 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800247 if result:
248 return True
249 _raise_current_error()
250
251
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800252 def type(self):
253 """
254 Returns the type of the key
255
256 :return: The type of the key.
257 """
258 return self._pkey.type
259
260
261 def bits(self):
262 """
263 Returns the number of bits of the key
264
265 :return: The number of bits of the key.
266 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500267 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800268PKeyType = PKey
269
270
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800271
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400272class _EllipticCurve(object):
273 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400274 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400275
276 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
277 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
278 instances each of which represents one curve supported by the system.
279 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400280 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400281 _curves = None
282
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400283 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400284 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400285 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400286 """
287 Implement cooperation with the right-hand side argument of ``!=``.
288
289 Python 3 seems to have dropped this cooperation in this very narrow
290 circumstance.
291 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400292 if isinstance(other, _EllipticCurve):
293 return super(_EllipticCurve, self).__ne__(other)
294 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400295
296
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400297 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400298 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400299 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400300 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400301
302 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400303
304 :return: A :py:type:`set` of ``cls`` instances giving the names of the
305 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400306 """
307 if lib.Cryptography_HAS_EC:
308 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
309 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
310 # The return value on this call should be num_curves again. We could
311 # check it to make sure but if it *isn't* then.. what could we do?
312 # Abort the whole process, I suppose...? -exarkun
313 lib.EC_get_builtin_curves(builtin_curves, num_curves)
314 return set(
315 cls.from_nid(lib, c.nid)
316 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400317 return set()
318
319
320 @classmethod
321 def _get_elliptic_curves(cls, lib):
322 """
323 Get, cache, and return the curves supported by OpenSSL.
324
325 :param lib: The OpenSSL library binding object.
326
327 :return: A :py:type:`set` of ``cls`` instances giving the names of the
328 elliptic curves the underlying library supports.
329 """
330 if cls._curves is None:
331 cls._curves = cls._load_elliptic_curves(lib)
332 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400333
334
335 @classmethod
336 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400337 """
338 Instantiate a new :py:class:`_EllipticCurve` associated with the given
339 OpenSSL NID.
340
341 :param lib: The OpenSSL library binding object.
342
343 :param nid: The OpenSSL NID the resulting curve object will represent.
344 This must be a curve NID (and not, for example, a hash NID) or
345 subsequent operations will fail in unpredictable ways.
346 :type nid: :py:class:`int`
347
348 :return: The curve object.
349 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400350 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
351
352
353 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400354 """
355 :param _lib: The :py:mod:`cryptography` binding instance used to
356 interface with OpenSSL.
357
358 :param _nid: The OpenSSL NID identifying the curve this object
359 represents.
360 :type _nid: :py:class:`int`
361
362 :param name: The OpenSSL short name identifying the curve this object
363 represents.
364 :type name: :py:class:`unicode`
365 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400366 self._lib = lib
367 self._nid = nid
368 self.name = name
369
370
371 def __repr__(self):
372 return "<Curve %r>" % (self.name,)
373
374
375 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400376 """
377 Create a new OpenSSL EC_KEY structure initialized to use this curve.
378
379 The structure is automatically garbage collected when the Python object
380 is garbage collected.
381 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400382 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
383 return _ffi.gc(key, _lib.EC_KEY_free)
384
385
386
387def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400388 """
389 Return a set of objects representing the elliptic curves supported in the
390 OpenSSL build in use.
391
392 The curve objects have a :py:class:`unicode` ``name`` attribute by which
393 they identify themselves.
394
395 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400396 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
397 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400398 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400399 return _EllipticCurve._get_elliptic_curves(_lib)
400
401
402
403def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400404 """
405 Return a single curve object selected by name.
406
407 See :py:func:`get_elliptic_curves` for information about curve objects.
408
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400409 :param name: The OpenSSL short name identifying the curve object to
410 retrieve.
411 :type name: :py:class:`unicode`
412
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400413 If the named curve is not supported then :py:class:`ValueError` is raised.
414 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400415 for curve in get_elliptic_curves():
416 if curve.name == name:
417 return curve
418 raise ValueError("unknown curve name", name)
419
420
421
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800422class X509Name(object):
423 def __init__(self, name):
424 """
425 Create a new X509Name, copying the given X509Name instance.
426
427 :param name: An X509Name object to copy
428 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500429 name = _lib.X509_NAME_dup(name._name)
430 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800431
432
433 def __setattr__(self, name, value):
434 if name.startswith('_'):
435 return super(X509Name, self).__setattr__(name, value)
436
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800437 # Note: we really do not want str subclasses here, so we do not use
438 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800439 if type(name) is not str:
440 raise TypeError("attribute name must be string, not '%.200s'" % (
441 type(value).__name__,))
442
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500443 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500444 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800445 try:
446 _raise_current_error()
447 except Error:
448 pass
449 raise AttributeError("No such attribute")
450
451 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500452 for i in range(_lib.X509_NAME_entry_count(self._name)):
453 ent = _lib.X509_NAME_get_entry(self._name, i)
454 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
455 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800456 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500457 ent = _lib.X509_NAME_delete_entry(self._name, i)
458 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800459 break
460
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500461 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800462 value = value.encode('utf-8')
463
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500464 add_result = _lib.X509_NAME_add_entry_by_NID(
465 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800466 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500467 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800468
469
470 def __getattr__(self, name):
471 """
472 Find attribute. An X509Name object has the following attributes:
473 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
474 organization (alias O), organizationalUnit (alias OU), commonName (alias
475 CN) and more...
476 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500477 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500478 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800479 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
480 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
481 # push something onto the error queue. If we don't clean that up
482 # now, someone else will bump into it later and be quite confused.
483 # See lp#314814.
484 try:
485 _raise_current_error()
486 except Error:
487 pass
488 return super(X509Name, self).__getattr__(name)
489
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500490 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800491 if entry_index == -1:
492 return None
493
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500494 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
495 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800496
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500497 result_buffer = _ffi.new("unsigned char**")
498 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800499 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500500 # TODO: This is untested.
501 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800502
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700503 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500504 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700505 finally:
506 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500507 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800508 return result
509
510
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500511 def _cmp(op):
512 def f(self, other):
513 if not isinstance(other, X509Name):
514 return NotImplemented
515 result = _lib.X509_NAME_cmp(self._name, other._name)
516 return op(result, 0)
517 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800518
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500519 __eq__ = _cmp(__eq__)
520 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800521
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500522 __lt__ = _cmp(__lt__)
523 __le__ = _cmp(__le__)
524
525 __gt__ = _cmp(__gt__)
526 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800527
528 def __repr__(self):
529 """
530 String representation of an X509Name
531 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500532 result_buffer = _ffi.new("char[]", 512);
533 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800534 self._name, result_buffer, len(result_buffer))
535
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500536 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500537 # TODO: This is untested.
538 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800539
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500540 return "<X509Name object '%s'>" % (
541 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800542
543
544 def hash(self):
545 """
546 Return the hash value of this name
547
548 :return: None
549 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500550 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800551
552
553 def der(self):
554 """
555 Return the DER encoding of this name
556
557 :return: A :py:class:`bytes` instance giving the DER encoded form of
558 this name.
559 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500560 result_buffer = _ffi.new('unsigned char**')
561 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800562 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500563 # TODO: This is untested.
564 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800565
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500566 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
567 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800568 return string_result
569
570
571 def get_components(self):
572 """
573 Returns the split-up components of this name.
574
575 :return: List of tuples (name, value).
576 """
577 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500578 for i in range(_lib.X509_NAME_entry_count(self._name)):
579 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800580
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500581 fname = _lib.X509_NAME_ENTRY_get_object(ent)
582 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800583
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500584 nid = _lib.OBJ_obj2nid(fname)
585 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800586
587 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500588 _ffi.string(name),
589 _ffi.string(
590 _lib.ASN1_STRING_data(fval),
591 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800592
593 return result
594X509NameType = X509Name
595
596
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800597class X509Extension(object):
598 def __init__(self, type_name, critical, value, subject=None, issuer=None):
599 """
600 :param typename: The name of the extension to create.
601 :type typename: :py:data:`str`
602
603 :param critical: A flag indicating whether this is a critical extension.
604
605 :param value: The value of the extension.
606 :type value: :py:data:`str`
607
608 :param subject: Optional X509 cert to use as subject.
609 :type subject: :py:class:`X509`
610
611 :param issuer: Optional X509 cert to use as issuer.
612 :type issuer: :py:class:`X509`
613
614 :return: The X509Extension object
615 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500616 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800617
618 # A context is necessary for any extension which uses the r2i conversion
619 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
620 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500621 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800622
623 # We have no configuration database - but perhaps we should (some
624 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500625 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800626
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800627 # Initialize the subject and issuer, if appropriate. ctx is a local,
628 # and as far as I can tell none of the X509V3_* APIs invoked here steal
629 # any references, so no need to mess with reference counts or duplicates.
630 if issuer is not None:
631 if not isinstance(issuer, X509):
632 raise TypeError("issuer must be an X509 instance")
633 ctx.issuer_cert = issuer._x509
634 if subject is not None:
635 if not isinstance(subject, X509):
636 raise TypeError("subject must be an X509 instance")
637 ctx.subject_cert = subject._x509
638
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800639 if critical:
640 # There are other OpenSSL APIs which would let us pass in critical
641 # separately, but they're harder to use, and since value is already
642 # a pile of crappy junk smuggling a ton of utterly important
643 # structured data, what's the point of trying to avoid nasty stuff
644 # with strings? (However, X509V3_EXT_i2d in particular seems like it
645 # would be a better API to invoke. I do not know where to get the
646 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500647 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800648
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500649 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
650 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800651 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500652 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800653
654
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400655 @property
656 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500657 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400658
659 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500660 _lib.GEN_EMAIL: "email",
661 _lib.GEN_DNS: "DNS",
662 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400663 }
664
665 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500666 method = _lib.X509V3_EXT_get(self._extension)
667 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500668 # TODO: This is untested.
669 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400670 payload = self._extension.value.data
671 length = self._extension.value.length
672
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500673 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400674 payloadptr[0] = payload
675
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500676 if method.it != _ffi.NULL:
677 ptr = _lib.ASN1_ITEM_ptr(method.it)
678 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
679 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400680 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500681 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400682 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500683 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400684
685 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500686 for i in range(_lib.sk_GENERAL_NAME_num(names)):
687 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400688 try:
689 label = self._prefixes[name.type]
690 except KeyError:
691 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500692 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500693 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400694 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500695 value = _native(
696 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
697 parts.append(label + ":" + value)
698 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400699
700
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800701 def __str__(self):
702 """
703 :return: a nice text representation of the extension
704 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500705 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400706 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800707
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400708 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500709 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800710 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500711 # TODO: This is untested.
712 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800713
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500714 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800715
716
717 def get_critical(self):
718 """
719 Returns the critical field of the X509Extension
720
721 :return: The critical field.
722 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500723 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800724
725
726 def get_short_name(self):
727 """
728 Returns the short version of the type name of the X509Extension
729
730 :return: The short type name.
731 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500732 obj = _lib.X509_EXTENSION_get_object(self._extension)
733 nid = _lib.OBJ_obj2nid(obj)
734 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800735
736
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800737 def get_data(self):
738 """
739 Returns the data of the X509Extension
740
741 :return: A :py:data:`str` giving the X509Extension's ASN.1 encoded data.
742 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500743 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
744 string_result = _ffi.cast('ASN1_STRING*', octet_result)
745 char_result = _lib.ASN1_STRING_data(string_result)
746 result_length = _lib.ASN1_STRING_length(string_result)
747 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800748
749X509ExtensionType = X509Extension
750
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800751
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800752class X509Req(object):
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800753 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500754 req = _lib.X509_REQ_new()
755 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800756
757
758 def set_pubkey(self, pkey):
759 """
760 Set the public key of the certificate request
761
762 :param pkey: The public key to use
763 :return: None
764 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500765 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800766 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500767 # TODO: This is untested.
768 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800769
770
771 def get_pubkey(self):
772 """
773 Get the public key from the certificate request
774
775 :return: The public key
776 """
777 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500778 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
779 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500780 # TODO: This is untested.
781 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500782 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800783 pkey._only_public = True
784 return pkey
785
786
787 def set_version(self, version):
788 """
789 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
790 request.
791
792 :param version: The version number
793 :return: None
794 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500795 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800796 if not set_result:
797 _raise_current_error()
798
799
800 def get_version(self):
801 """
802 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
803 request.
804
805 :return: an integer giving the value of the version subfield
806 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500807 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800808
809
810 def get_subject(self):
811 """
812 Create an X509Name object for the subject of the certificate request
813
814 :return: An X509Name object
815 """
816 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500817 name._name = _lib.X509_REQ_get_subject_name(self._req)
818 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500819 # TODO: This is untested.
820 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800821
822 # The name is owned by the X509Req structure. As long as the X509Name
823 # Python object is alive, keep the X509Req Python object alive.
824 name._owner = self
825
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800826 return name
827
828
829 def add_extensions(self, extensions):
830 """
831 Add extensions to the request.
832
833 :param extensions: a sequence of X509Extension objects
834 :return: None
835 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500836 stack = _lib.sk_X509_EXTENSION_new_null()
837 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500838 # TODO: This is untested.
839 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800840
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500841 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800842
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800843 for ext in extensions:
844 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800845 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800846
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800847 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500848 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800849
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500850 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800851 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500852 # TODO: This is untested.
853 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854
855
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800856 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800857 """
858 Get extensions to the request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800859
Jean-Paul Calderoneda3e6c62014-03-02 08:06:11 -0500860 :return: A :py:class:`list` of :py:class:`X509Extension` objects.
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800861 """
862 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500863 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500864 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800865 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500866 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800867 exts.append(ext)
868 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800869
870
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800871 def sign(self, pkey, digest):
872 """
873 Sign the certificate request using the supplied key and digest
874
875 :param pkey: The key to sign with
876 :param digest: The message digest to use
877 :return: None
878 """
879 if pkey._only_public:
880 raise ValueError("Key has only public part")
881
882 if not pkey._initialized:
883 raise ValueError("Key is uninitialized")
884
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500885 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500886 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800887 raise ValueError("No such digest method")
888
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500889 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800890 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500891 # TODO: This is untested.
892 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800893
894
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800895 def verify(self, pkey):
896 """
897 Verifies a certificate request using the supplied public key
898
899 :param key: a public key
900 :return: True if the signature is correct.
901
902 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
903 problem verifying the signature.
904 """
905 if not isinstance(pkey, PKey):
906 raise TypeError("pkey must be a PKey instance")
907
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500908 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800909 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500910 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800911
912 return result
913
914
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800915X509ReqType = X509Req
916
917
918
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800919class X509(object):
920 def __init__(self):
921 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500922 x509 = _lib.X509_new()
923 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800924
925
926 def set_version(self, version):
927 """
928 Set version number of the certificate
929
930 :param version: The version number
931 :type version: :py:class:`int`
932
933 :return: None
934 """
935 if not isinstance(version, int):
936 raise TypeError("version must be an integer")
937
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500938 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800939
940
941 def get_version(self):
942 """
943 Return version number of the certificate
944
945 :return: Version number as a Python integer
946 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500947 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800948
949
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800950 def get_pubkey(self):
951 """
952 Get the public key of the certificate
953
954 :return: The public key
955 """
956 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500957 pkey._pkey = _lib.X509_get_pubkey(self._x509)
958 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800959 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500960 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800961 pkey._only_public = True
962 return pkey
963
964
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800965 def set_pubkey(self, pkey):
966 """
967 Set the public key of the certificate
968
969 :param pkey: The public key
970
971 :return: None
972 """
973 if not isinstance(pkey, PKey):
974 raise TypeError("pkey must be a PKey instance")
975
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500976 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800977 if not set_result:
978 _raise_current_error()
979
980
981 def sign(self, pkey, digest):
982 """
983 Sign the certificate using the supplied key and digest
984
985 :param pkey: The key to sign with
986 :param digest: The message digest to use
987 :return: None
988 """
989 if not isinstance(pkey, PKey):
990 raise TypeError("pkey must be a PKey instance")
991
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800992 if pkey._only_public:
993 raise ValueError("Key only has public part")
994
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800995 if not pkey._initialized:
996 raise ValueError("Key is uninitialized")
997
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500998 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500999 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001000 raise ValueError("No such digest method")
1001
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001002 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001003 if not sign_result:
1004 _raise_current_error()
1005
1006
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001007 def get_signature_algorithm(self):
1008 """
1009 Retrieve the signature algorithm used in the certificate
1010
1011 :return: A byte string giving the name of the signature algorithm used in
1012 the certificate.
1013 :raise ValueError: If the signature algorithm is undefined.
1014 """
1015 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001016 nid = _lib.OBJ_obj2nid(alg)
1017 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001018 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001019 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001020
1021
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001022 def digest(self, digest_name):
1023 """
1024 Return the digest of the X509 object.
1025
1026 :param digest_name: The name of the digest algorithm to use.
1027 :type digest_name: :py:class:`bytes`
1028
1029 :return: The digest of the object
1030 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001031 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001032 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001033 raise ValueError("No such digest method")
1034
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001035 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1036 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001037 result_length[0] = len(result_buffer)
1038
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001039 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001040 self._x509, digest, result_buffer, result_length)
1041
1042 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001043 # TODO: This is untested.
1044 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001045
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001046 return b":".join([
1047 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001048 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001049
1050
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001051 def subject_name_hash(self):
1052 """
1053 Return the hash of the X509 subject.
1054
1055 :return: The hash of the subject.
1056 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001057 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001058
1059
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001060 def set_serial_number(self, serial):
1061 """
1062 Set serial number of the certificate
1063
1064 :param serial: The serial number
1065 :type serial: :py:class:`int`
1066
1067 :return: None
1068 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001069 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001070 raise TypeError("serial must be an integer")
1071
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001072 hex_serial = hex(serial)[2:]
1073 if not isinstance(hex_serial, bytes):
1074 hex_serial = hex_serial.encode('ascii')
1075
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001076 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001077
1078 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1079 # it. If bignum is still NULL after this call, then the return value is
1080 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001081 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001082
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001083 if bignum_serial[0] == _ffi.NULL:
1084 set_result = _lib.ASN1_INTEGER_set(
1085 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001086 if set_result:
1087 # TODO Not tested
1088 _raise_current_error()
1089 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001090 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1091 _lib.BN_free(bignum_serial[0])
1092 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001093 # TODO Not tested
1094 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001095 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1096 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001097 if not set_result:
1098 # TODO Not tested
1099 _raise_current_error()
1100
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001101
1102 def get_serial_number(self):
1103 """
1104 Return serial number of the certificate
1105
1106 :return: Serial number as a Python integer
1107 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001108 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1109 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001110 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001111 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001112 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001113 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001114 serial = int(hexstring_serial, 16)
1115 return serial
1116 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001117 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001118 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001119 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001120
1121
1122 def gmtime_adj_notAfter(self, amount):
1123 """
1124 Adjust the time stamp for when the certificate stops being valid
1125
1126 :param amount: The number of seconds by which to adjust the ending
1127 validity time.
1128 :type amount: :py:class:`int`
1129
1130 :return: None
1131 """
1132 if not isinstance(amount, int):
1133 raise TypeError("amount must be an integer")
1134
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001135 notAfter = _lib.X509_get_notAfter(self._x509)
1136 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001137
1138
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001139 def gmtime_adj_notBefore(self, amount):
1140 """
1141 Change the timestamp for when the certificate starts being valid to the current
1142 time plus an offset.
1143
1144 :param amount: The number of seconds by which to adjust the starting validity
1145 time.
1146 :return: None
1147 """
1148 if not isinstance(amount, int):
1149 raise TypeError("amount must be an integer")
1150
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001151 notBefore = _lib.X509_get_notBefore(self._x509)
1152 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001153
1154
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001155 def has_expired(self):
1156 """
1157 Check whether the certificate has expired.
1158
1159 :return: True if the certificate has expired, false otherwise
1160 """
1161 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001162 notAfter = _lib.X509_get_notAfter(self._x509)
1163 return _lib.ASN1_UTCTIME_cmp_time_t(
1164 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001165
1166
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001167 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001168 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001169
1170
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001171 def get_notBefore(self):
1172 """
1173 Retrieve the time stamp for when the certificate starts being valid
1174
1175 :return: A string giving the timestamp, in the format::
1176
1177 YYYYMMDDhhmmssZ
1178 YYYYMMDDhhmmss+hhmm
1179 YYYYMMDDhhmmss-hhmm
1180
1181 or None if there is no value set.
1182 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001183 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001184
1185
1186 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001187 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001188
1189
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001190 def set_notBefore(self, when):
1191 """
1192 Set the time stamp for when the certificate starts being valid
1193
1194 :param when: A string giving the timestamp, in the format:
1195
1196 YYYYMMDDhhmmssZ
1197 YYYYMMDDhhmmss+hhmm
1198 YYYYMMDDhhmmss-hhmm
1199 :type when: :py:class:`bytes`
1200
1201 :return: None
1202 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001203 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001204
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001205
1206 def get_notAfter(self):
1207 """
1208 Retrieve the time stamp for when the certificate stops being valid
1209
1210 :return: A string giving the timestamp, in the format::
1211
1212 YYYYMMDDhhmmssZ
1213 YYYYMMDDhhmmss+hhmm
1214 YYYYMMDDhhmmss-hhmm
1215
1216 or None if there is no value set.
1217 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001218 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001219
1220
1221 def set_notAfter(self, when):
1222 """
1223 Set the time stamp for when the certificate stops being valid
1224
1225 :param when: A string giving the timestamp, in the format:
1226
1227 YYYYMMDDhhmmssZ
1228 YYYYMMDDhhmmss+hhmm
1229 YYYYMMDDhhmmss-hhmm
1230 :type when: :py:class:`bytes`
1231
1232 :return: None
1233 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001234 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001235
1236
1237 def _get_name(self, which):
1238 name = X509Name.__new__(X509Name)
1239 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001240 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001241 # TODO: This is untested.
1242 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001243
1244 # The name is owned by the X509 structure. As long as the X509Name
1245 # Python object is alive, keep the X509 Python object alive.
1246 name._owner = self
1247
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001248 return name
1249
1250
1251 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001252 if not isinstance(name, X509Name):
1253 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001254 set_result = which(self._x509, name._name)
1255 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001256 # TODO: This is untested.
1257 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001258
1259
1260 def get_issuer(self):
1261 """
1262 Create an X509Name object for the issuer of the certificate
1263
1264 :return: An X509Name object
1265 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001266 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001267
1268
1269 def set_issuer(self, issuer):
1270 """
1271 Set the issuer of the certificate
1272
1273 :param issuer: The issuer name
1274 :type issuer: :py:class:`X509Name`
1275
1276 :return: None
1277 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001278 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001279
1280
1281 def get_subject(self):
1282 """
1283 Create an X509Name object for the subject of the certificate
1284
1285 :return: An X509Name object
1286 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001287 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001288
1289
1290 def set_subject(self, subject):
1291 """
1292 Set the subject of the certificate
1293
1294 :param subject: The subject name
1295 :type subject: :py:class:`X509Name`
1296 :return: None
1297 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001298 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001299
1300
1301 def get_extension_count(self):
1302 """
1303 Get the number of extensions on the certificate.
1304
1305 :return: The number of extensions as an integer.
1306 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001307 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001308
1309
1310 def add_extensions(self, extensions):
1311 """
1312 Add extensions to the certificate.
1313
1314 :param extensions: a sequence of X509Extension objects
1315 :return: None
1316 """
1317 for ext in extensions:
1318 if not isinstance(ext, X509Extension):
1319 raise ValueError("One of the elements is not an X509Extension")
1320
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001321 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001322 if not add_result:
1323 _raise_current_error()
1324
1325
1326 def get_extension(self, index):
1327 """
1328 Get a specific extension of the certificate by index.
1329
1330 :param index: The index of the extension to retrieve.
1331 :return: The X509Extension object at the specified index.
1332 """
1333 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001334 ext._extension = _lib.X509_get_ext(self._x509, index)
1335 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001336 raise IndexError("extension index out of bounds")
1337
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001338 extension = _lib.X509_EXTENSION_dup(ext._extension)
1339 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001340 return ext
1341
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001342X509Type = X509
1343
1344
1345
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001346class X509Store(object):
1347 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001348 store = _lib.X509_STORE_new()
1349 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001350
1351
1352 def add_cert(self, cert):
1353 if not isinstance(cert, X509):
1354 raise TypeError()
1355
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001356 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001357 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001358 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001359
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001360
1361X509StoreType = X509Store
1362
1363
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001364class X509StoreContextError(Exception):
1365 """
1366 An error occurred while verifying a certificate using
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001367 `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001368
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001369 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001370 :type cert: :class:`X509`
1371
1372 """
1373 def __init__(self, message, certificate):
1374 super(X509StoreContextError, self).__init__(message)
1375 self.certificate = certificate
1376
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001377
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001378class X509StoreContext(object):
1379 """
1380 An X.509 store context.
1381
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001382 An :py:class:`X509StoreContext` is used to define some of the criteria for
1383 certificate verification. The information encapsulated in this object
1384 includes, but is not limited to, a set of trusted certificates,
1385 verification parameters, and revoked certificates.
1386
1387 Of these, only the set of trusted certificates is currently exposed.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001388
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001389 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1390 instance. It is dynamically allocated and automatically garbage
1391 collected.
1392
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001393 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001394
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001395 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001396 """
1397
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001398 def __init__(self, store, certificate):
1399 """
1400 :param X509Store store: The certificates which will be trusted for the
1401 purposes of any verifications.
1402
1403 :param X509 certificate: The certificate to be verified.
1404 """
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001405 store_ctx = _lib.X509_STORE_CTX_new()
1406 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1407 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001408 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001409 # Make the store context available for use after instantiating this
1410 # class by initializing it now. Per testing, subsequent calls to
1411 # :py:meth:`_init` have no adverse affect.
1412 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001413
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001414
1415 def _init(self):
1416 """
1417 Set up the store context for a subsequent verification operation.
1418 """
1419 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1420 if ret <= 0:
1421 _raise_current_error()
1422
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001423
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001424 def _cleanup(self):
1425 """
1426 Internally cleans up the store context.
1427
1428 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001429 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001430 """
1431 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1432
1433
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001434 def _exception_from_context(self):
1435 """
1436 Convert an OpenSSL native context error failure into a Python
1437 exception.
1438
1439 When a call to native OpenSSL X509_verify_cert fails, additonal information
1440 about the failure can be obtained from the store context.
1441 """
1442 errors = [
1443 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1444 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1445 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1446 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1447 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001448 # A context error should always be associated with a certificate, so we
1449 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001450 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001451 _cert = _lib.X509_dup(_x509)
1452 pycert = X509.__new__(X509)
1453 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001454 return X509StoreContextError(errors, pycert)
1455
1456
Stephen Holsapple46a09252015-02-12 14:45:43 -08001457 def set_store(self, store):
1458 """
1459 Set the context's trust store.
1460
1461 :param X509Store store: The certificates which will be trusted for the
1462 purposes of any *future* verifications.
1463 """
1464 self._store = store
1465
1466
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001467 def verify_certificate(self):
1468 """
1469 Verify a certificate in a context.
1470
1471 :param store_ctx: The :py:class:`X509StoreContext` to verify.
1472 :raises: Error
1473 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001474 # Always re-initialize the store context in case
1475 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001476 self._init()
1477 ret = _lib.X509_verify_cert(self._store_ctx)
1478 self._cleanup()
1479 if ret <= 0:
1480 raise self._exception_from_context()
1481
1482
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001483
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001484def load_certificate(type, buffer):
1485 """
1486 Load a certificate from a buffer
1487
1488 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001489
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001490 :param buffer: The buffer the certificate is stored in
1491 :type buffer: :py:class:`bytes`
1492
1493 :return: The X509 object
1494 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001495 if isinstance(buffer, _text_type):
1496 buffer = buffer.encode("ascii")
1497
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001498 bio = _new_mem_buf(buffer)
1499
1500 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001501 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001502 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001503 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001504 else:
1505 raise ValueError(
1506 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1507
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001508 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001509 _raise_current_error()
1510
1511 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001512 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001513 return cert
1514
1515
1516def dump_certificate(type, cert):
1517 """
1518 Dump a certificate to a buffer
1519
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001520 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1521 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001522 :param cert: The certificate to dump
1523 :return: The buffer with the dumped certificate in
1524 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001525 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001526
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001527 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001528 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001529 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001530 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001531 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001532 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001533 else:
1534 raise ValueError(
1535 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1536 "FILETYPE_TEXT")
1537
1538 return _bio_to_string(bio)
1539
1540
1541
1542def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1543 """
1544 Dump a private key to a buffer
1545
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001546 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1547 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001548 :param pkey: The PKey to dump
1549 :param cipher: (optional) if encrypted PEM format, the cipher to
1550 use
1551 :param passphrase: (optional) if encrypted PEM format, this can be either
1552 the passphrase to use, or a callback for providing the
1553 passphrase.
1554 :return: The buffer with the dumped key in
1555 :rtype: :py:data:`str`
1556 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001557 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001558
1559 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001560 if passphrase is None:
1561 raise TypeError(
1562 "if a value is given for cipher "
1563 "one must also be given for passphrase")
1564 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001565 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001566 raise ValueError("Invalid cipher name")
1567 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001568 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001569
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001570 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001571 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001572 result_code = _lib.PEM_write_bio_PrivateKey(
1573 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001574 helper.callback, helper.callback_args)
1575 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001576 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001577 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001578 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001579 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1580 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001581 # TODO RSA_free(rsa)?
1582 else:
1583 raise ValueError(
1584 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1585 "FILETYPE_TEXT")
1586
1587 if result_code == 0:
1588 _raise_current_error()
1589
1590 return _bio_to_string(bio)
1591
1592
1593
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001594def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001595 copy = _lib.X509_REVOKED_new()
1596 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001597 # TODO: This is untested.
1598 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001599
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001600 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001601 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001602 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001603
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001604 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001605 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001606 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001607
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001608 if original.extensions != _ffi.NULL:
1609 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1610 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1611 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1612 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1613 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001614 copy.extensions = extension_stack
1615
1616 copy.sequence = original.sequence
1617 return copy
1618
1619
1620
1621class Revoked(object):
1622 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1623 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1624 # OCSP_crl_reason_str. We use the latter, just like the command line
1625 # program.
1626 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001627 b"unspecified",
1628 b"keyCompromise",
1629 b"CACompromise",
1630 b"affiliationChanged",
1631 b"superseded",
1632 b"cessationOfOperation",
1633 b"certificateHold",
1634 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001635 ]
1636
1637 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001638 revoked = _lib.X509_REVOKED_new()
1639 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001640
1641
1642 def set_serial(self, hex_str):
1643 """
1644 Set the serial number of a revoked Revoked structure
1645
1646 :param hex_str: The new serial number.
1647 :type hex_str: :py:data:`str`
1648 :return: None
1649 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001650 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1651 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001652 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001653 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001654 if not bn_result:
1655 raise ValueError("bad hex string")
1656
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001657 asn1_serial = _ffi.gc(
1658 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1659 _lib.ASN1_INTEGER_free)
1660 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001661
1662
1663 def get_serial(self):
1664 """
1665 Return the serial number of a Revoked structure
1666
1667 :return: The serial number as a string
1668 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001669 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001670
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001671 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001672 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001673 # TODO: This is untested.
1674 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001675
1676 return _bio_to_string(bio)
1677
1678
1679 def _delete_reason(self):
1680 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001681 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1682 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1683 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1684 _lib.X509_EXTENSION_free(ext)
1685 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001686 break
1687
1688
1689 def set_reason(self, reason):
1690 """
1691 Set the reason of a Revoked object.
1692
1693 If :py:data:`reason` is :py:data:`None`, delete the reason instead.
1694
1695 :param reason: The reason string.
1696 :type reason: :py:class:`str` or :py:class:`NoneType`
1697 :return: None
1698 """
1699 if reason is None:
1700 self._delete_reason()
1701 elif not isinstance(reason, bytes):
1702 raise TypeError("reason must be None or a byte string")
1703 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001704 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001705 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1706
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001707 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1708 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001709 # TODO: This is untested.
1710 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001711 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001712
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001713 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1714 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001715 # TODO: This is untested.
1716 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001717
1718 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001719 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1720 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001721
1722 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001723 # TODO: This is untested.
1724 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001725
1726
1727 def get_reason(self):
1728 """
1729 Return the reason of a Revoked object.
1730
1731 :return: The reason as a string
1732 """
1733 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001734 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1735 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1736 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001737 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001738
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001739 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001740 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001741 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001742 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001743 # TODO: This is untested.
1744 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001745
1746 return _bio_to_string(bio)
1747
1748
1749 def all_reasons(self):
1750 """
1751 Return a list of all the supported reason strings.
1752
1753 :return: A list of reason strings.
1754 """
1755 return self._crl_reasons[:]
1756
1757
1758 def set_rev_date(self, when):
1759 """
1760 Set the revocation timestamp
1761
1762 :param when: A string giving the timestamp, in the format:
1763
1764 YYYYMMDDhhmmssZ
1765 YYYYMMDDhhmmss+hhmm
1766 YYYYMMDDhhmmss-hhmm
1767
1768 :return: None
1769 """
1770 return _set_asn1_time(self._revoked.revocationDate, when)
1771
1772
1773 def get_rev_date(self):
1774 """
1775 Retrieve the revocation date
1776
1777 :return: A string giving the timestamp, in the format:
1778
1779 YYYYMMDDhhmmssZ
1780 YYYYMMDDhhmmss+hhmm
1781 YYYYMMDDhhmmss-hhmm
1782 """
1783 return _get_asn1_time(self._revoked.revocationDate)
1784
1785
1786
1787class CRL(object):
1788 def __init__(self):
1789 """
1790 Create a new empty CRL object.
1791 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001792 crl = _lib.X509_CRL_new()
1793 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001794
1795
1796 def get_revoked(self):
1797 """
1798 Return revoked portion of the CRL structure (by value not reference).
1799
1800 :return: A tuple of Revoked objects.
1801 """
1802 results = []
1803 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001804 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1805 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001806 revoked_copy = _X509_REVOKED_dup(revoked)
1807 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001808 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001810 if results:
1811 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001812
1813
1814 def add_revoked(self, revoked):
1815 """
1816 Add a revoked (by value not reference) to the CRL structure
1817
1818 :param revoked: The new revoked.
1819 :type revoked: :class:`X509`
1820
1821 :return: None
1822 """
1823 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001824 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001825 # TODO: This is untested.
1826 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001827
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001828 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001829 if add_result == 0:
1830 # TODO: This is untested.
1831 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001832
1833
1834 def export(self, cert, key, type=FILETYPE_PEM, days=100):
1835 """
1836 export a CRL as a string
1837
1838 :param cert: Used to sign CRL.
1839 :type cert: :class:`X509`
1840
1841 :param key: Used to sign CRL.
1842 :type key: :class:`PKey`
1843
1844 :param type: The export format, either :py:data:`FILETYPE_PEM`, :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
1845
1846 :param days: The number of days until the next update of this CRL.
1847 :type days: :py:data:`int`
1848
1849 :return: :py:data:`str`
1850 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001851 if not isinstance(cert, X509):
1852 raise TypeError("cert must be an X509 instance")
1853 if not isinstance(key, PKey):
1854 raise TypeError("key must be a PKey instance")
1855 if not isinstance(type, int):
1856 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001857
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001858 bio = _lib.BIO_new(_lib.BIO_s_mem())
1859 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001860 # TODO: This is untested.
1861 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001862
1863 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001864 sometime = _lib.ASN1_TIME_new()
1865 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001866 # TODO: This is untested.
1867 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001868
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001869 _lib.X509_gmtime_adj(sometime, 0)
1870 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001871
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001872 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1873 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001874
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001875 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001876
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001877 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, _lib.EVP_md5())
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001878 if not sign_result:
1879 _raise_current_error()
1880
1881 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001882 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001883 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001884 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001885 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001886 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001887 else:
1888 raise ValueError(
1889 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1890
1891 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001892 # TODO: This is untested.
1893 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001894
1895 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001896CRLType = CRL
1897
1898
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001899
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001900class PKCS7(object):
1901 def type_is_signed(self):
1902 """
1903 Check if this NID_pkcs7_signed object
1904
1905 :return: True if the PKCS7 is of type signed
1906 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001907 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001908 return True
1909 return False
1910
1911
1912 def type_is_enveloped(self):
1913 """
1914 Check if this NID_pkcs7_enveloped object
1915
1916 :returns: True if the PKCS7 is of type enveloped
1917 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001918 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001919 return True
1920 return False
1921
1922
1923 def type_is_signedAndEnveloped(self):
1924 """
1925 Check if this NID_pkcs7_signedAndEnveloped object
1926
1927 :returns: True if the PKCS7 is of type signedAndEnveloped
1928 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001929 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001930 return True
1931 return False
1932
1933
1934 def type_is_data(self):
1935 """
1936 Check if this NID_pkcs7_data object
1937
1938 :return: True if the PKCS7 is of type data
1939 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001940 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001941 return True
1942 return False
1943
1944
1945 def get_type_name(self):
1946 """
1947 Returns the type name of the PKCS7 structure
1948
1949 :return: A string with the typename
1950 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001951 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1952 string_type = _lib.OBJ_nid2sn(nid)
1953 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001954
1955PKCS7Type = PKCS7
1956
1957
1958
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001959class PKCS12(object):
1960 def __init__(self):
1961 self._pkey = None
1962 self._cert = None
1963 self._cacerts = None
1964 self._friendlyname = None
1965
1966
1967 def get_certificate(self):
1968 """
1969 Return certificate portion of the PKCS12 structure
1970
1971 :return: X509 object containing the certificate
1972 """
1973 return self._cert
1974
1975
1976 def set_certificate(self, cert):
1977 """
1978 Replace the certificate portion of the PKCS12 structure
1979
1980 :param cert: The new certificate.
1981 :type cert: :py:class:`X509` or :py:data:`None`
1982 :return: None
1983 """
1984 if not isinstance(cert, X509):
1985 raise TypeError("cert must be an X509 instance")
1986 self._cert = cert
1987
1988
1989 def get_privatekey(self):
1990 """
1991 Return private key portion of the PKCS12 structure
1992
1993 :returns: PKey object containing the private key
1994 """
1995 return self._pkey
1996
1997
1998 def set_privatekey(self, pkey):
1999 """
2000 Replace or set the certificate portion of the PKCS12 structure
2001
2002 :param pkey: The new private key.
2003 :type pkey: :py:class:`PKey`
2004 :return: None
2005 """
2006 if not isinstance(pkey, PKey):
2007 raise TypeError("pkey must be a PKey instance")
2008 self._pkey = pkey
2009
2010
2011 def get_ca_certificates(self):
2012 """
2013 Return CA certificates within of the PKCS12 object
2014
2015 :return: A newly created tuple containing the CA certificates in the chain,
2016 if any are present, or None if no CA certificates are present.
2017 """
2018 if self._cacerts is not None:
2019 return tuple(self._cacerts)
2020
2021
2022 def set_ca_certificates(self, cacerts):
2023 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002024 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002025
2026 :param cacerts: The new CA certificates.
2027 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2028 :return: None
2029 """
2030 if cacerts is None:
2031 self._cacerts = None
2032 else:
2033 cacerts = list(cacerts)
2034 for cert in cacerts:
2035 if not isinstance(cert, X509):
2036 raise TypeError("iterable must only contain X509 instances")
2037 self._cacerts = cacerts
2038
2039
2040 def set_friendlyname(self, name):
2041 """
2042 Replace or set the certificate portion of the PKCS12 structure
2043
2044 :param name: The new friendly name.
2045 :type name: :py:class:`bytes`
2046 :return: None
2047 """
2048 if name is None:
2049 self._friendlyname = None
2050 elif not isinstance(name, bytes):
2051 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2052 self._friendlyname = name
2053
2054
2055 def get_friendlyname(self):
2056 """
2057 Return friendly name portion of the PKCS12 structure
2058
2059 :returns: String containing the friendlyname
2060 """
2061 return self._friendlyname
2062
2063
2064 def export(self, passphrase=None, iter=2048, maciter=1):
2065 """
2066 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2067
2068 :param passphrase: used to encrypt the PKCS12
2069 :type passphrase: :py:data:`bytes`
2070
2071 :param iter: How many times to repeat the encryption
2072 :type iter: :py:data:`int`
2073
2074 :param maciter: How many times to repeat the MAC
2075 :type maciter: :py:data:`int`
2076
2077 :return: The string containing the PKCS12
2078 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002079 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002080
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002081 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002082 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002083 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002084 cacerts = _lib.sk_X509_new_null()
2085 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002086 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002087 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002088
2089 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002090 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002091
2092 friendlyname = self._friendlyname
2093 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002094 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002095
2096 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002097 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002098 else:
2099 pkey = self._pkey._pkey
2100
2101 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002102 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002103 else:
2104 cert = self._cert._x509
2105
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002106 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002107 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002108 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2109 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002110 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002111 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002112 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002113 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002114
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002115 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002116 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002117 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002118
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002119PKCS12Type = PKCS12
2120
2121
2122
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002123class NetscapeSPKI(object):
2124 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002125 spki = _lib.NETSCAPE_SPKI_new()
2126 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002127
2128
2129 def sign(self, pkey, digest):
2130 """
2131 Sign the certificate request using the supplied key and digest
2132
2133 :param pkey: The key to sign with
2134 :param digest: The message digest to use
2135 :return: None
2136 """
2137 if pkey._only_public:
2138 raise ValueError("Key has only public part")
2139
2140 if not pkey._initialized:
2141 raise ValueError("Key is uninitialized")
2142
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002143 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002144 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002145 raise ValueError("No such digest method")
2146
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002147 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002148 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002149 # TODO: This is untested.
2150 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002151
2152
2153 def verify(self, key):
2154 """
2155 Verifies a certificate request using the supplied public key
2156
2157 :param key: a public key
2158 :return: True if the signature is correct.
2159 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2160 problem verifying the signature.
2161 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002162 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002163 if answer <= 0:
2164 _raise_current_error()
2165 return True
2166
2167
2168 def b64_encode(self):
2169 """
2170 Generate a base64 encoded string from an SPKI
2171
2172 :return: The base64 encoded string
2173 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002174 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2175 result = _ffi.string(encoded)
2176 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002177 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002178
2179
2180 def get_pubkey(self):
2181 """
2182 Get the public key of the certificate
2183
2184 :return: The public key
2185 """
2186 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002187 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2188 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002189 # TODO: This is untested.
2190 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002191 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002192 pkey._only_public = True
2193 return pkey
2194
2195
2196 def set_pubkey(self, pkey):
2197 """
2198 Set the public key of the certificate
2199
2200 :param pkey: The public key
2201 :return: None
2202 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002203 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002204 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002205 # TODO: This is untested.
2206 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002207NetscapeSPKIType = NetscapeSPKI
2208
2209
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002210class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002211 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002212 if type != FILETYPE_PEM and passphrase is not None:
2213 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002214 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002215 self._more_args = more_args
2216 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002217 self._problems = []
2218
2219
2220 @property
2221 def callback(self):
2222 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002223 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002224 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002225 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002226 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002227 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002228 else:
2229 raise TypeError("Last argument must be string or callable")
2230
2231
2232 @property
2233 def callback_args(self):
2234 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002235 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002236 elif isinstance(self._passphrase, bytes):
2237 return self._passphrase
2238 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002239 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002240 else:
2241 raise TypeError("Last argument must be string or callable")
2242
2243
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002244 def raise_if_problem(self, exceptionType=Error):
2245 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002246 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002247 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002248 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002249 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002250 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002251 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002252
2253
2254 def _read_passphrase(self, buf, size, rwflag, userdata):
2255 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002256 if self._more_args:
2257 result = self._passphrase(size, rwflag, userdata)
2258 else:
2259 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002260 if not isinstance(result, bytes):
2261 raise ValueError("String expected")
2262 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002263 if self._truncate:
2264 result = result[:size]
2265 else:
2266 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002267 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002268 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002269 return len(result)
2270 except Exception as e:
2271 self._problems.append(e)
2272 return 0
2273
2274
2275
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002276def load_privatekey(type, buffer, passphrase=None):
2277 """
2278 Load a private key from a buffer
2279
2280 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2281 :param buffer: The buffer the key is stored in
2282 :param passphrase: (optional) if encrypted PEM format, this can be
2283 either the passphrase to use, or a callback for
2284 providing the passphrase.
2285
2286 :return: The PKey object
2287 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002288 if isinstance(buffer, _text_type):
2289 buffer = buffer.encode("ascii")
2290
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002291 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002292
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002293 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002294 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002295 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2296 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002297 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002298 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002299 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002300 else:
2301 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2302
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002303 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002304 _raise_current_error()
2305
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002306 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002307 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002308 return pkey
2309
2310
2311
2312def dump_certificate_request(type, req):
2313 """
2314 Dump a certificate request to a buffer
2315
2316 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2317 :param req: The certificate request to dump
2318 :return: The buffer with the dumped certificate request in
2319 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002320 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002321
2322 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002323 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002324 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002325 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002326 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002327 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002328 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002329 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002330
2331 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002332 # TODO: This is untested.
2333 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002334
2335 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002336
2337
2338
2339def load_certificate_request(type, buffer):
2340 """
2341 Load a certificate request from a buffer
2342
2343 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2344 :param buffer: The buffer the certificate request is stored in
2345 :return: The X509Req object
2346 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002347 if isinstance(buffer, _text_type):
2348 buffer = buffer.encode("ascii")
2349
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002350 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002351
2352 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002353 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002354 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002355 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002356 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002357 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002358
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002359 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002360 # TODO: This is untested.
2361 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002362
2363 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002364 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002365 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002366
2367
2368
2369def sign(pkey, data, digest):
2370 """
2371 Sign data with a digest
2372
2373 :param pkey: Pkey to sign with
2374 :param data: data to be signed
2375 :param digest: message digest to use
2376 :return: signature
2377 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002378 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002379
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002380 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002381 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002382 raise ValueError("No such digest method")
2383
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002384 md_ctx = _ffi.new("EVP_MD_CTX*")
2385 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002386
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002387 _lib.EVP_SignInit(md_ctx, digest_obj)
2388 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002389
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002390 signature_buffer = _ffi.new("unsigned char[]", 512)
2391 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002392 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002393 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002394 md_ctx, signature_buffer, signature_length, pkey._pkey)
2395
2396 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002397 # TODO: This is untested.
2398 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002399
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002400 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002401
2402
2403
2404def verify(cert, signature, data, digest):
2405 """
2406 Verify a signature
2407
2408 :param cert: signing certificate (X509 object)
2409 :param signature: signature returned by sign function
2410 :param data: data to be verified
2411 :param digest: message digest to use
2412 :return: None if the signature is correct, raise exception otherwise
2413 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002414 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002415
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002416 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002417 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002418 raise ValueError("No such digest method")
2419
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002420 pkey = _lib.X509_get_pubkey(cert._x509)
2421 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002422 # TODO: This is untested.
2423 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002424 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002425
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002426 md_ctx = _ffi.new("EVP_MD_CTX*")
2427 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002428
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002429 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2430 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2431 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002432
2433 if verify_result != 1:
2434 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002435
2436
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002437def load_crl(type, buffer):
2438 """
2439 Load a certificate revocation list from a buffer
2440
2441 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2442 :param buffer: The buffer the CRL is stored in
2443
2444 :return: The PKey object
2445 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002446 if isinstance(buffer, _text_type):
2447 buffer = buffer.encode("ascii")
2448
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002449 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002450
2451 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002452 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002453 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002454 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002455 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002456 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2457
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002458 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002459 _raise_current_error()
2460
2461 result = CRL.__new__(CRL)
2462 result._crl = crl
2463 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002464
2465
2466
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002467def load_pkcs7_data(type, buffer):
2468 """
2469 Load pkcs7 data from a buffer
2470
2471 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2472 :param buffer: The buffer with the pkcs7 data.
2473 :return: The PKCS7 object
2474 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002475 if isinstance(buffer, _text_type):
2476 buffer = buffer.encode("ascii")
2477
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002478 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002479
2480 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002481 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002482 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002483 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002484 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002485 # TODO: This is untested.
2486 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002487 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2488
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002489 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002490 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002491
2492 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002493 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002494 return pypkcs7
2495
2496
2497
Stephen Holsapple38482622014-04-05 20:29:34 -07002498def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002499 """
2500 Load a PKCS12 object from a buffer
2501
2502 :param buffer: The buffer the certificate is stored in
2503 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2504 :returns: The PKCS12 object
2505 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002506 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002507
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002508 if isinstance(buffer, _text_type):
2509 buffer = buffer.encode("ascii")
2510
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002511 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002512
Stephen Holsapple38482622014-04-05 20:29:34 -07002513 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2514 # password based encryption no password and a zero length password are two
2515 # different things, but OpenSSL implementation will try both to figure out
2516 # which one works.
2517 if not passphrase:
2518 passphrase = _ffi.NULL
2519
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002520 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2521 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002522 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002523 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002524
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002525 pkey = _ffi.new("EVP_PKEY**")
2526 cert = _ffi.new("X509**")
2527 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002528
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002529 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002530 if not parse_result:
2531 _raise_current_error()
2532
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002533 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002534
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002535 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2536 # queue for no particular reason. This error isn't interesting to anyone
2537 # outside this function. It's not even interesting to us. Get rid of it.
2538 try:
2539 _raise_current_error()
2540 except Error:
2541 pass
2542
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002543 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002544 pykey = None
2545 else:
2546 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002547 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002548
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002549 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002550 pycert = None
2551 friendlyname = None
2552 else:
2553 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002554 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002555
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002556 friendlyname_length = _ffi.new("int*")
2557 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2558 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2559 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002560 friendlyname = None
2561
2562 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002563 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002564 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002565 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002566 pycacerts.append(pycacert)
2567 if not pycacerts:
2568 pycacerts = None
2569
2570 pkcs12 = PKCS12.__new__(PKCS12)
2571 pkcs12._pkey = pykey
2572 pkcs12._cert = pycert
2573 pkcs12._cacerts = pycacerts
2574 pkcs12._friendlyname = friendlyname
2575 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002576
2577
2578def _initialize_openssl_threads(get_ident, Lock):
2579 import _ssl
2580 return
2581
2582 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2583
2584 def locking_function(mode, index, filename, line):
2585 if mode & _lib.CRYPTO_LOCK:
2586 locks[index].acquire()
2587 else:
2588 locks[index].release()
2589
2590 _lib.CRYPTO_set_id_callback(
2591 _ffi.callback("unsigned long (*)(void)", get_ident))
2592
2593 _lib.CRYPTO_set_locking_callback(
2594 _ffi.callback(
2595 "void (*)(int, int, const char*, int)", locking_function))
2596
2597
2598try:
2599 from thread import get_ident
2600 from threading import Lock
2601except ImportError:
2602 pass
2603else:
2604 _initialize_openssl_threads(get_ident, Lock)
2605 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002606
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002607# There are no direct unit tests for this initialization. It is tested
2608# indirectly since it is necessary for functions like dump_privatekey when
2609# using encryption.
2610#
2611# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2612# and some other similar tests may fail without this (though they may not if
2613# the Python runtime has already done some initialization of the underlying
2614# OpenSSL library (and is linked against the same one that cryptography is
2615# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002616_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002617
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002618# This is similar but exercised mainly by exception_from_error_queue. It calls
2619# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2620_lib.SSL_load_error_strings()