blob: 4999194d815cf8f8ac863fb63455841716f7b9e4 [file] [log] [blame]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001from time import time
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05003from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05004from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04005from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05006
7from six import (
8 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -04009 text_type as _text_type,
10 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080011
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050012from OpenSSL._util import (
13 ffi as _ffi,
14 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050015 exception_from_error_queue as _exception_from_error_queue,
16 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040017 native as _native,
18 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040019 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040020)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080021
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050022FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
23FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080024
25# TODO This was an API mistake. OpenSSL has no such constant.
26FILETYPE_TEXT = 2 ** 16 - 1
27
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050028TYPE_RSA = _lib.EVP_PKEY_RSA
29TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080030
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080031
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070032
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050033class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050034 """
35 An error occurred in an `OpenSSL.crypto` API.
36 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050037
38
39_raise_current_error = partial(_exception_from_error_queue, Error)
40
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070041
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050042
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050043def _untested_error(where):
44 """
45 An OpenSSL API failed somehow. Additionally, the failure which was
46 encountered isn't one that's exercised by the test suite so future behavior
47 of pyOpenSSL is now somewhat less predictable.
48 """
49 raise RuntimeError("Unknown %s failure" % (where,))
50
51
52
53def _new_mem_buf(buffer=None):
54 """
55 Allocate a new OpenSSL memory BIO.
56
57 Arrange for the garbage collector to clean it up automatically.
58
59 :param buffer: None or some bytes to use to put into the BIO so that they
60 can be read out.
61 """
62 if buffer is None:
63 bio = _lib.BIO_new(_lib.BIO_s_mem())
64 free = _lib.BIO_free
65 else:
66 data = _ffi.new("char[]", buffer)
67 bio = _lib.BIO_new_mem_buf(data, len(buffer))
68 # Keep the memory alive as long as the bio is alive!
69 def free(bio, ref=data):
70 return _lib.BIO_free(bio)
71
72 if bio == _ffi.NULL:
73 # TODO: This is untested.
74 _raise_current_error()
75
76 bio = _ffi.gc(bio, free)
77 return bio
78
79
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050080
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080081def _bio_to_string(bio):
82 """
83 Copy the contents of an OpenSSL BIO object into a Python byte string.
84 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050085 result_buffer = _ffi.new('char**')
86 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
87 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080088
89
90
Jean-Paul Calderone57122982013-02-21 08:47:05 -080091def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050092 """
93 The the time value of an ASN1 time object.
94
95 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
96 castable to that type) which will have its value set.
97 @param when: A string representation of the desired time value.
98
99 @raise TypeError: If C{when} is not a L{bytes} string.
100 @raise ValueError: If C{when} does not represent a time in the required
101 format.
102 @raise RuntimeError: If the time value cannot be set for some other
103 (unspecified) reason.
104 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800105 if not isinstance(when, bytes):
106 raise TypeError("when must be a byte string")
107
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500108 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
109 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800110 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500111 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
112 _lib.ASN1_STRING_set(dummy, when, len(when))
113 check_result = _lib.ASN1_GENERALIZEDTIME_check(
114 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800115 if not check_result:
116 raise ValueError("Invalid string")
117 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500118 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800119
120
121
122def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500123 """
124 Retrieve the time value of an ASN1 time object.
125
126 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
127 that type) from which the time value will be retrieved.
128
129 @return: The time value from C{timestamp} as a L{bytes} string in a certain
130 format. Or C{None} if the object contains no time value.
131 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500132 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
133 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800134 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500135 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
136 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800137 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500138 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
139 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
140 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500141 # This may happen:
142 # - if timestamp was not an ASN1_TIME
143 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
144 # - if a copy of the time data from timestamp cannot be made for
145 # the newly allocated ASN1_GENERALIZEDTIME
146 #
147 # These are difficult to test. cffi enforces the ASN1_TIME type.
148 # Memory allocation failures are a pain to trigger
149 # deterministically.
150 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800151 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500152 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800153 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500154 string_data = _lib.ASN1_STRING_data(string_timestamp)
155 string_result = _ffi.string(string_data)
156 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800157 return string_result
158
159
160
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800161class PKey(object):
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800162 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800163 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800164
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800165 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500166 pkey = _lib.EVP_PKEY_new()
167 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800168 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800169
170
171 def generate_key(self, type, bits):
172 """
173 Generate a key of a given type, with a given number of a bits
174
175 :param type: The key type (TYPE_RSA or TYPE_DSA)
176 :param bits: The number of bits
177
178 :return: None
179 """
180 if not isinstance(type, int):
181 raise TypeError("type must be an integer")
182
183 if not isinstance(bits, int):
184 raise TypeError("bits must be an integer")
185
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800186 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500187 exponent = _lib.BN_new()
188 exponent = _ffi.gc(exponent, _lib.BN_free)
189 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800190
191 if type == TYPE_RSA:
192 if bits <= 0:
193 raise ValueError("Invalid number of bits")
194
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500195 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800196
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500197 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500198 if result == 0:
199 # TODO: The test for this case is commented out. Different
200 # builds of OpenSSL appear to have different failure modes that
201 # make it hard to test. Visual inspection of the OpenSSL
202 # source reveals that a return value of 0 signals an error.
203 # Manual testing on a particular build of OpenSSL suggests that
204 # this is probably the appropriate way to handle those errors.
205 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800206
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500207 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800208 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500209 # TODO: It appears as though this can fail if an engine is in
210 # use which does not support RSA.
211 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800212
213 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500214 dsa = _lib.DSA_generate_parameters(
215 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
216 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500217 # TODO: This is untested.
218 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500219 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500220 # TODO: This is untested.
221 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500222 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500223 # TODO: This is untested.
224 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800225 else:
226 raise Error("No such key type")
227
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800228 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800229
230
231 def check(self):
232 """
233 Check the consistency of an RSA private key.
234
235 :return: True if key is consistent.
236 :raise Error: if the key is inconsistent.
237 :raise TypeError: if the key is of a type which cannot be checked.
238 Only RSA keys can currently be checked.
239 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800240 if self._only_public:
241 raise TypeError("public key only")
242
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500243 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800244 raise TypeError("key type unsupported")
245
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500246 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
247 rsa = _ffi.gc(rsa, _lib.RSA_free)
248 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800249 if result:
250 return True
251 _raise_current_error()
252
253
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800254 def type(self):
255 """
256 Returns the type of the key
257
258 :return: The type of the key.
259 """
260 return self._pkey.type
261
262
263 def bits(self):
264 """
265 Returns the number of bits of the key
266
267 :return: The number of bits of the key.
268 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500269 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800270PKeyType = PKey
271
272
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800273
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400274class _EllipticCurve(object):
275 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400276 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400277
278 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
279 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
280 instances each of which represents one curve supported by the system.
281 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400282 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400283 _curves = None
284
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400285 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400286 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400287 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400288 """
289 Implement cooperation with the right-hand side argument of ``!=``.
290
291 Python 3 seems to have dropped this cooperation in this very narrow
292 circumstance.
293 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400294 if isinstance(other, _EllipticCurve):
295 return super(_EllipticCurve, self).__ne__(other)
296 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400297
298
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400299 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400300 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400301 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400302 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400303
304 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400305
306 :return: A :py:type:`set` of ``cls`` instances giving the names of the
307 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400308 """
309 if lib.Cryptography_HAS_EC:
310 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
311 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
312 # The return value on this call should be num_curves again. We could
313 # check it to make sure but if it *isn't* then.. what could we do?
314 # Abort the whole process, I suppose...? -exarkun
315 lib.EC_get_builtin_curves(builtin_curves, num_curves)
316 return set(
317 cls.from_nid(lib, c.nid)
318 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400319 return set()
320
321
322 @classmethod
323 def _get_elliptic_curves(cls, lib):
324 """
325 Get, cache, and return the curves supported by OpenSSL.
326
327 :param lib: The OpenSSL library binding object.
328
329 :return: A :py:type:`set` of ``cls`` instances giving the names of the
330 elliptic curves the underlying library supports.
331 """
332 if cls._curves is None:
333 cls._curves = cls._load_elliptic_curves(lib)
334 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400335
336
337 @classmethod
338 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400339 """
340 Instantiate a new :py:class:`_EllipticCurve` associated with the given
341 OpenSSL NID.
342
343 :param lib: The OpenSSL library binding object.
344
345 :param nid: The OpenSSL NID the resulting curve object will represent.
346 This must be a curve NID (and not, for example, a hash NID) or
347 subsequent operations will fail in unpredictable ways.
348 :type nid: :py:class:`int`
349
350 :return: The curve object.
351 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400352 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
353
354
355 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400356 """
357 :param _lib: The :py:mod:`cryptography` binding instance used to
358 interface with OpenSSL.
359
360 :param _nid: The OpenSSL NID identifying the curve this object
361 represents.
362 :type _nid: :py:class:`int`
363
364 :param name: The OpenSSL short name identifying the curve this object
365 represents.
366 :type name: :py:class:`unicode`
367 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400368 self._lib = lib
369 self._nid = nid
370 self.name = name
371
372
373 def __repr__(self):
374 return "<Curve %r>" % (self.name,)
375
376
377 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400378 """
379 Create a new OpenSSL EC_KEY structure initialized to use this curve.
380
381 The structure is automatically garbage collected when the Python object
382 is garbage collected.
383 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400384 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
385 return _ffi.gc(key, _lib.EC_KEY_free)
386
387
388
389def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400390 """
391 Return a set of objects representing the elliptic curves supported in the
392 OpenSSL build in use.
393
394 The curve objects have a :py:class:`unicode` ``name`` attribute by which
395 they identify themselves.
396
397 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400398 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
399 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400400 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400401 return _EllipticCurve._get_elliptic_curves(_lib)
402
403
404
405def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400406 """
407 Return a single curve object selected by name.
408
409 See :py:func:`get_elliptic_curves` for information about curve objects.
410
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400411 :param name: The OpenSSL short name identifying the curve object to
412 retrieve.
413 :type name: :py:class:`unicode`
414
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400415 If the named curve is not supported then :py:class:`ValueError` is raised.
416 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400417 for curve in get_elliptic_curves():
418 if curve.name == name:
419 return curve
420 raise ValueError("unknown curve name", name)
421
422
423
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800424class X509Name(object):
425 def __init__(self, name):
426 """
427 Create a new X509Name, copying the given X509Name instance.
428
429 :param name: An X509Name object to copy
430 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500431 name = _lib.X509_NAME_dup(name._name)
432 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800433
434
435 def __setattr__(self, name, value):
436 if name.startswith('_'):
437 return super(X509Name, self).__setattr__(name, value)
438
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800439 # Note: we really do not want str subclasses here, so we do not use
440 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800441 if type(name) is not str:
442 raise TypeError("attribute name must be string, not '%.200s'" % (
443 type(value).__name__,))
444
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500445 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500446 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800447 try:
448 _raise_current_error()
449 except Error:
450 pass
451 raise AttributeError("No such attribute")
452
453 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500454 for i in range(_lib.X509_NAME_entry_count(self._name)):
455 ent = _lib.X509_NAME_get_entry(self._name, i)
456 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
457 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800458 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500459 ent = _lib.X509_NAME_delete_entry(self._name, i)
460 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800461 break
462
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500463 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800464 value = value.encode('utf-8')
465
D.S. Ljungmark5533e252014-05-31 13:18:41 +0200466 # Make it so OpenSSL generates utf-8 strings.
467 _lib.ASN1_STRING_set_default_mask_asc(b'utf8only')
468
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500469 add_result = _lib.X509_NAME_add_entry_by_NID(
470 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800471 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500472 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800473
474
475 def __getattr__(self, name):
476 """
477 Find attribute. An X509Name object has the following attributes:
478 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
479 organization (alias O), organizationalUnit (alias OU), commonName (alias
480 CN) and more...
481 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500482 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500483 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800484 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
485 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
486 # push something onto the error queue. If we don't clean that up
487 # now, someone else will bump into it later and be quite confused.
488 # See lp#314814.
489 try:
490 _raise_current_error()
491 except Error:
492 pass
493 return super(X509Name, self).__getattr__(name)
494
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500495 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800496 if entry_index == -1:
497 return None
498
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500499 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
500 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800501
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500502 result_buffer = _ffi.new("unsigned char**")
503 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800504 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500505 # TODO: This is untested.
506 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800507
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700508 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500509 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700510 finally:
511 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500512 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800513 return result
514
515
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500516 def _cmp(op):
517 def f(self, other):
518 if not isinstance(other, X509Name):
519 return NotImplemented
520 result = _lib.X509_NAME_cmp(self._name, other._name)
521 return op(result, 0)
522 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800523
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500524 __eq__ = _cmp(__eq__)
525 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800526
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500527 __lt__ = _cmp(__lt__)
528 __le__ = _cmp(__le__)
529
530 __gt__ = _cmp(__gt__)
531 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800532
533 def __repr__(self):
534 """
535 String representation of an X509Name
536 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500537 result_buffer = _ffi.new("char[]", 512);
538 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800539 self._name, result_buffer, len(result_buffer))
540
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500541 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500542 # TODO: This is untested.
543 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800544
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500545 return "<X509Name object '%s'>" % (
546 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800547
548
549 def hash(self):
550 """
551 Return the hash value of this name
552
553 :return: None
554 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500555 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800556
557
558 def der(self):
559 """
560 Return the DER encoding of this name
561
562 :return: A :py:class:`bytes` instance giving the DER encoded form of
563 this name.
564 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500565 result_buffer = _ffi.new('unsigned char**')
566 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800567 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500568 # TODO: This is untested.
569 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800570
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500571 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
572 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800573 return string_result
574
575
576 def get_components(self):
577 """
578 Returns the split-up components of this name.
579
580 :return: List of tuples (name, value).
581 """
582 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500583 for i in range(_lib.X509_NAME_entry_count(self._name)):
584 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500586 fname = _lib.X509_NAME_ENTRY_get_object(ent)
587 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800588
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500589 nid = _lib.OBJ_obj2nid(fname)
590 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800591
592 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500593 _ffi.string(name),
594 _ffi.string(
595 _lib.ASN1_STRING_data(fval),
596 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800597
598 return result
599X509NameType = X509Name
600
601
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800602class X509Extension(object):
603 def __init__(self, type_name, critical, value, subject=None, issuer=None):
604 """
605 :param typename: The name of the extension to create.
606 :type typename: :py:data:`str`
607
608 :param critical: A flag indicating whether this is a critical extension.
609
610 :param value: The value of the extension.
611 :type value: :py:data:`str`
612
613 :param subject: Optional X509 cert to use as subject.
614 :type subject: :py:class:`X509`
615
616 :param issuer: Optional X509 cert to use as issuer.
617 :type issuer: :py:class:`X509`
618
619 :return: The X509Extension object
620 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500621 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800622
623 # A context is necessary for any extension which uses the r2i conversion
624 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
625 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500626 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800627
628 # We have no configuration database - but perhaps we should (some
629 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500630 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800631
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800632 # Initialize the subject and issuer, if appropriate. ctx is a local,
633 # and as far as I can tell none of the X509V3_* APIs invoked here steal
634 # any references, so no need to mess with reference counts or duplicates.
635 if issuer is not None:
636 if not isinstance(issuer, X509):
637 raise TypeError("issuer must be an X509 instance")
638 ctx.issuer_cert = issuer._x509
639 if subject is not None:
640 if not isinstance(subject, X509):
641 raise TypeError("subject must be an X509 instance")
642 ctx.subject_cert = subject._x509
643
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800644 if critical:
645 # There are other OpenSSL APIs which would let us pass in critical
646 # separately, but they're harder to use, and since value is already
647 # a pile of crappy junk smuggling a ton of utterly important
648 # structured data, what's the point of trying to avoid nasty stuff
649 # with strings? (However, X509V3_EXT_i2d in particular seems like it
650 # would be a better API to invoke. I do not know where to get the
651 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500652 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800653
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500654 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
655 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800656 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500657 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800658
659
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400660 @property
661 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500662 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400663
664 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500665 _lib.GEN_EMAIL: "email",
666 _lib.GEN_DNS: "DNS",
667 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400668 }
669
670 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500671 method = _lib.X509V3_EXT_get(self._extension)
672 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500673 # TODO: This is untested.
674 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400675 payload = self._extension.value.data
676 length = self._extension.value.length
677
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500678 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400679 payloadptr[0] = payload
680
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500681 if method.it != _ffi.NULL:
682 ptr = _lib.ASN1_ITEM_ptr(method.it)
683 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
684 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400685 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500686 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400687 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500688 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400689
690 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500691 for i in range(_lib.sk_GENERAL_NAME_num(names)):
692 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400693 try:
694 label = self._prefixes[name.type]
695 except KeyError:
696 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500697 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500698 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400699 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500700 value = _native(
701 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
702 parts.append(label + ":" + value)
703 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400704
705
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800706 def __str__(self):
707 """
708 :return: a nice text representation of the extension
709 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500710 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400711 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800712
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400713 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500714 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800715 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500716 # TODO: This is untested.
717 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800718
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500719 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800720
721
722 def get_critical(self):
723 """
724 Returns the critical field of the X509Extension
725
726 :return: The critical field.
727 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500728 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800729
730
731 def get_short_name(self):
732 """
733 Returns the short version of the type name of the X509Extension
734
735 :return: The short type name.
736 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500737 obj = _lib.X509_EXTENSION_get_object(self._extension)
738 nid = _lib.OBJ_obj2nid(obj)
739 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800740
741
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800742 def get_data(self):
743 """
744 Returns the data of the X509Extension
745
746 :return: A :py:data:`str` giving the X509Extension's ASN.1 encoded data.
747 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500748 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
749 string_result = _ffi.cast('ASN1_STRING*', octet_result)
750 char_result = _lib.ASN1_STRING_data(string_result)
751 result_length = _lib.ASN1_STRING_length(string_result)
752 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800753
754X509ExtensionType = X509Extension
755
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800756
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800757class X509Req(object):
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800758 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500759 req = _lib.X509_REQ_new()
760 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800761
762
763 def set_pubkey(self, pkey):
764 """
765 Set the public key of the certificate request
766
767 :param pkey: The public key to use
768 :return: None
769 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500770 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800771 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500772 # TODO: This is untested.
773 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800774
775
776 def get_pubkey(self):
777 """
778 Get the public key from the certificate request
779
780 :return: The public key
781 """
782 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500783 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
784 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500785 # TODO: This is untested.
786 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500787 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800788 pkey._only_public = True
789 return pkey
790
791
792 def set_version(self, version):
793 """
794 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
795 request.
796
797 :param version: The version number
798 :return: None
799 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500800 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800801 if not set_result:
802 _raise_current_error()
803
804
805 def get_version(self):
806 """
807 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
808 request.
809
810 :return: an integer giving the value of the version subfield
811 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500812 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800813
814
815 def get_subject(self):
816 """
817 Create an X509Name object for the subject of the certificate request
818
819 :return: An X509Name object
820 """
821 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500822 name._name = _lib.X509_REQ_get_subject_name(self._req)
823 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500824 # TODO: This is untested.
825 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800826
827 # The name is owned by the X509Req structure. As long as the X509Name
828 # Python object is alive, keep the X509Req Python object alive.
829 name._owner = self
830
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800831 return name
832
833
834 def add_extensions(self, extensions):
835 """
836 Add extensions to the request.
837
838 :param extensions: a sequence of X509Extension objects
839 :return: None
840 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500841 stack = _lib.sk_X509_EXTENSION_new_null()
842 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500843 # TODO: This is untested.
844 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800845
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500846 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800847
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800848 for ext in extensions:
849 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800850 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800851
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800852 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500853 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500855 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800856 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500857 # TODO: This is untested.
858 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800859
860
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800861 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800862 """
863 Get extensions to the request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800864
Jean-Paul Calderoneda3e6c62014-03-02 08:06:11 -0500865 :return: A :py:class:`list` of :py:class:`X509Extension` objects.
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800866 """
867 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500868 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500869 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800870 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500871 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800872 exts.append(ext)
873 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800874
875
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800876 def sign(self, pkey, digest):
877 """
878 Sign the certificate request using the supplied key and digest
879
880 :param pkey: The key to sign with
881 :param digest: The message digest to use
882 :return: None
883 """
884 if pkey._only_public:
885 raise ValueError("Key has only public part")
886
887 if not pkey._initialized:
888 raise ValueError("Key is uninitialized")
889
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500890 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500891 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800892 raise ValueError("No such digest method")
893
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500894 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800895 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500896 # TODO: This is untested.
897 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800898
899
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800900 def verify(self, pkey):
901 """
902 Verifies a certificate request using the supplied public key
903
904 :param key: a public key
905 :return: True if the signature is correct.
906
907 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
908 problem verifying the signature.
909 """
910 if not isinstance(pkey, PKey):
911 raise TypeError("pkey must be a PKey instance")
912
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500913 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800914 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500915 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800916
917 return result
918
919
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800920X509ReqType = X509Req
921
922
923
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800924class X509(object):
925 def __init__(self):
926 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500927 x509 = _lib.X509_new()
928 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800929
930
931 def set_version(self, version):
932 """
933 Set version number of the certificate
934
935 :param version: The version number
936 :type version: :py:class:`int`
937
938 :return: None
939 """
940 if not isinstance(version, int):
941 raise TypeError("version must be an integer")
942
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500943 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800944
945
946 def get_version(self):
947 """
948 Return version number of the certificate
949
950 :return: Version number as a Python integer
951 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500952 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800953
954
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800955 def get_pubkey(self):
956 """
957 Get the public key of the certificate
958
959 :return: The public key
960 """
961 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500962 pkey._pkey = _lib.X509_get_pubkey(self._x509)
963 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800964 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500965 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800966 pkey._only_public = True
967 return pkey
968
969
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800970 def set_pubkey(self, pkey):
971 """
972 Set the public key of the certificate
973
974 :param pkey: The public key
975
976 :return: None
977 """
978 if not isinstance(pkey, PKey):
979 raise TypeError("pkey must be a PKey instance")
980
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500981 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800982 if not set_result:
983 _raise_current_error()
984
985
986 def sign(self, pkey, digest):
987 """
988 Sign the certificate using the supplied key and digest
989
990 :param pkey: The key to sign with
991 :param digest: The message digest to use
992 :return: None
993 """
994 if not isinstance(pkey, PKey):
995 raise TypeError("pkey must be a PKey instance")
996
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800997 if pkey._only_public:
998 raise ValueError("Key only has public part")
999
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001000 if not pkey._initialized:
1001 raise ValueError("Key is uninitialized")
1002
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001003 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001004 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001005 raise ValueError("No such digest method")
1006
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001007 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001008 if not sign_result:
1009 _raise_current_error()
1010
1011
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001012 def get_signature_algorithm(self):
1013 """
1014 Retrieve the signature algorithm used in the certificate
1015
1016 :return: A byte string giving the name of the signature algorithm used in
1017 the certificate.
1018 :raise ValueError: If the signature algorithm is undefined.
1019 """
1020 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001021 nid = _lib.OBJ_obj2nid(alg)
1022 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001023 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001024 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001025
1026
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001027 def digest(self, digest_name):
1028 """
1029 Return the digest of the X509 object.
1030
1031 :param digest_name: The name of the digest algorithm to use.
1032 :type digest_name: :py:class:`bytes`
1033
1034 :return: The digest of the object
1035 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001036 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001037 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001038 raise ValueError("No such digest method")
1039
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001040 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1041 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001042 result_length[0] = len(result_buffer)
1043
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001044 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001045 self._x509, digest, result_buffer, result_length)
1046
1047 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001048 # TODO: This is untested.
1049 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001050
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001051 return b":".join([
1052 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001053 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001054
1055
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001056 def subject_name_hash(self):
1057 """
1058 Return the hash of the X509 subject.
1059
1060 :return: The hash of the subject.
1061 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001062 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001063
1064
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001065 def set_serial_number(self, serial):
1066 """
1067 Set serial number of the certificate
1068
1069 :param serial: The serial number
1070 :type serial: :py:class:`int`
1071
1072 :return: None
1073 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001074 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001075 raise TypeError("serial must be an integer")
1076
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001077 hex_serial = hex(serial)[2:]
1078 if not isinstance(hex_serial, bytes):
1079 hex_serial = hex_serial.encode('ascii')
1080
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001081 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001082
1083 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1084 # it. If bignum is still NULL after this call, then the return value is
1085 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001086 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001087
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001088 if bignum_serial[0] == _ffi.NULL:
1089 set_result = _lib.ASN1_INTEGER_set(
1090 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001091 if set_result:
1092 # TODO Not tested
1093 _raise_current_error()
1094 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001095 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1096 _lib.BN_free(bignum_serial[0])
1097 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001098 # TODO Not tested
1099 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001100 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1101 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001102 if not set_result:
1103 # TODO Not tested
1104 _raise_current_error()
1105
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001106
1107 def get_serial_number(self):
1108 """
1109 Return serial number of the certificate
1110
1111 :return: Serial number as a Python integer
1112 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001113 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1114 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001115 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001116 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001117 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001118 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001119 serial = int(hexstring_serial, 16)
1120 return serial
1121 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001122 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001123 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001124 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001125
1126
1127 def gmtime_adj_notAfter(self, amount):
1128 """
1129 Adjust the time stamp for when the certificate stops being valid
1130
1131 :param amount: The number of seconds by which to adjust the ending
1132 validity time.
1133 :type amount: :py:class:`int`
1134
1135 :return: None
1136 """
1137 if not isinstance(amount, int):
1138 raise TypeError("amount must be an integer")
1139
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001140 notAfter = _lib.X509_get_notAfter(self._x509)
1141 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001142
1143
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001144 def gmtime_adj_notBefore(self, amount):
1145 """
1146 Change the timestamp for when the certificate starts being valid to the current
1147 time plus an offset.
1148
1149 :param amount: The number of seconds by which to adjust the starting validity
1150 time.
1151 :return: None
1152 """
1153 if not isinstance(amount, int):
1154 raise TypeError("amount must be an integer")
1155
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001156 notBefore = _lib.X509_get_notBefore(self._x509)
1157 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001158
1159
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001160 def has_expired(self):
1161 """
1162 Check whether the certificate has expired.
1163
1164 :return: True if the certificate has expired, false otherwise
1165 """
1166 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001167 notAfter = _lib.X509_get_notAfter(self._x509)
1168 return _lib.ASN1_UTCTIME_cmp_time_t(
1169 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001170
1171
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001172 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001173 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001174
1175
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001176 def get_notBefore(self):
1177 """
1178 Retrieve the time stamp for when the certificate starts being valid
1179
1180 :return: A string giving the timestamp, in the format::
1181
1182 YYYYMMDDhhmmssZ
1183 YYYYMMDDhhmmss+hhmm
1184 YYYYMMDDhhmmss-hhmm
1185
1186 or None if there is no value set.
1187 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001188 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001189
1190
1191 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001192 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001193
1194
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001195 def set_notBefore(self, when):
1196 """
1197 Set the time stamp for when the certificate starts being valid
1198
1199 :param when: A string giving the timestamp, in the format:
1200
1201 YYYYMMDDhhmmssZ
1202 YYYYMMDDhhmmss+hhmm
1203 YYYYMMDDhhmmss-hhmm
1204 :type when: :py:class:`bytes`
1205
1206 :return: None
1207 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001208 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001209
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001210
1211 def get_notAfter(self):
1212 """
1213 Retrieve the time stamp for when the certificate stops being valid
1214
1215 :return: A string giving the timestamp, in the format::
1216
1217 YYYYMMDDhhmmssZ
1218 YYYYMMDDhhmmss+hhmm
1219 YYYYMMDDhhmmss-hhmm
1220
1221 or None if there is no value set.
1222 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001223 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001224
1225
1226 def set_notAfter(self, when):
1227 """
1228 Set the time stamp for when the certificate stops being valid
1229
1230 :param when: A string giving the timestamp, in the format:
1231
1232 YYYYMMDDhhmmssZ
1233 YYYYMMDDhhmmss+hhmm
1234 YYYYMMDDhhmmss-hhmm
1235 :type when: :py:class:`bytes`
1236
1237 :return: None
1238 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001239 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001240
1241
1242 def _get_name(self, which):
1243 name = X509Name.__new__(X509Name)
1244 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001245 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001246 # TODO: This is untested.
1247 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001248
1249 # The name is owned by the X509 structure. As long as the X509Name
1250 # Python object is alive, keep the X509 Python object alive.
1251 name._owner = self
1252
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001253 return name
1254
1255
1256 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001257 if not isinstance(name, X509Name):
1258 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001259 set_result = which(self._x509, name._name)
1260 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001261 # TODO: This is untested.
1262 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001263
1264
1265 def get_issuer(self):
1266 """
1267 Create an X509Name object for the issuer of the certificate
1268
1269 :return: An X509Name object
1270 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001271 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001272
1273
1274 def set_issuer(self, issuer):
1275 """
1276 Set the issuer of the certificate
1277
1278 :param issuer: The issuer name
1279 :type issuer: :py:class:`X509Name`
1280
1281 :return: None
1282 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001283 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001284
1285
1286 def get_subject(self):
1287 """
1288 Create an X509Name object for the subject of the certificate
1289
1290 :return: An X509Name object
1291 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001292 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001293
1294
1295 def set_subject(self, subject):
1296 """
1297 Set the subject of the certificate
1298
1299 :param subject: The subject name
1300 :type subject: :py:class:`X509Name`
1301 :return: None
1302 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001303 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001304
1305
1306 def get_extension_count(self):
1307 """
1308 Get the number of extensions on the certificate.
1309
1310 :return: The number of extensions as an integer.
1311 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001312 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001313
1314
1315 def add_extensions(self, extensions):
1316 """
1317 Add extensions to the certificate.
1318
1319 :param extensions: a sequence of X509Extension objects
1320 :return: None
1321 """
1322 for ext in extensions:
1323 if not isinstance(ext, X509Extension):
1324 raise ValueError("One of the elements is not an X509Extension")
1325
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001326 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001327 if not add_result:
1328 _raise_current_error()
1329
1330
1331 def get_extension(self, index):
1332 """
1333 Get a specific extension of the certificate by index.
1334
1335 :param index: The index of the extension to retrieve.
1336 :return: The X509Extension object at the specified index.
1337 """
1338 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001339 ext._extension = _lib.X509_get_ext(self._x509, index)
1340 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001341 raise IndexError("extension index out of bounds")
1342
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001343 extension = _lib.X509_EXTENSION_dup(ext._extension)
1344 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001345 return ext
1346
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001347X509Type = X509
1348
1349
1350
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001351class X509Store(object):
1352 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001353 store = _lib.X509_STORE_new()
1354 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001355
1356
1357 def add_cert(self, cert):
1358 if not isinstance(cert, X509):
1359 raise TypeError()
1360
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001361 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001362 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001363 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001364
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001365
1366X509StoreType = X509Store
1367
1368
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001369class X509StoreContextError(Exception):
1370 """
1371 An error occurred while verifying a certificate using
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001372 `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001373
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001374 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001375 :type cert: :class:`X509`
1376
1377 """
1378 def __init__(self, message, certificate):
1379 super(X509StoreContextError, self).__init__(message)
1380 self.certificate = certificate
1381
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001382
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001383class X509StoreContext(object):
1384 """
1385 An X.509 store context.
1386
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001387 An :py:class:`X509StoreContext` is used to define some of the criteria for
1388 certificate verification. The information encapsulated in this object
1389 includes, but is not limited to, a set of trusted certificates,
1390 verification parameters, and revoked certificates.
1391
1392 Of these, only the set of trusted certificates is currently exposed.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001393
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001394 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1395 instance. It is dynamically allocated and automatically garbage
1396 collected.
1397
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001398 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001399
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001400 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001401 """
1402
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001403 def __init__(self, store, certificate):
1404 """
1405 :param X509Store store: The certificates which will be trusted for the
1406 purposes of any verifications.
1407
1408 :param X509 certificate: The certificate to be verified.
1409 """
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001410 store_ctx = _lib.X509_STORE_CTX_new()
1411 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1412 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001413 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001414 # Make the store context available for use after instantiating this
1415 # class by initializing it now. Per testing, subsequent calls to
1416 # :py:meth:`_init` have no adverse affect.
1417 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001418
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001419
1420 def _init(self):
1421 """
1422 Set up the store context for a subsequent verification operation.
1423 """
1424 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1425 if ret <= 0:
1426 _raise_current_error()
1427
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001428
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001429 def _cleanup(self):
1430 """
1431 Internally cleans up the store context.
1432
1433 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001434 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001435 """
1436 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1437
1438
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001439 def _exception_from_context(self):
1440 """
1441 Convert an OpenSSL native context error failure into a Python
1442 exception.
1443
1444 When a call to native OpenSSL X509_verify_cert fails, additonal information
1445 about the failure can be obtained from the store context.
1446 """
1447 errors = [
1448 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1449 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1450 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1451 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1452 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001453 # A context error should always be associated with a certificate, so we
1454 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001455 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001456 _cert = _lib.X509_dup(_x509)
1457 pycert = X509.__new__(X509)
1458 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001459 return X509StoreContextError(errors, pycert)
1460
1461
Stephen Holsapple46a09252015-02-12 14:45:43 -08001462 def set_store(self, store):
1463 """
1464 Set the context's trust store.
1465
1466 :param X509Store store: The certificates which will be trusted for the
1467 purposes of any *future* verifications.
1468 """
1469 self._store = store
1470
1471
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001472 def verify_certificate(self):
1473 """
1474 Verify a certificate in a context.
1475
1476 :param store_ctx: The :py:class:`X509StoreContext` to verify.
1477 :raises: Error
1478 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001479 # Always re-initialize the store context in case
1480 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001481 self._init()
1482 ret = _lib.X509_verify_cert(self._store_ctx)
1483 self._cleanup()
1484 if ret <= 0:
1485 raise self._exception_from_context()
1486
1487
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001488
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001489def load_certificate(type, buffer):
1490 """
1491 Load a certificate from a buffer
1492
1493 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001494
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001495 :param buffer: The buffer the certificate is stored in
1496 :type buffer: :py:class:`bytes`
1497
1498 :return: The X509 object
1499 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001500 if isinstance(buffer, _text_type):
1501 buffer = buffer.encode("ascii")
1502
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001503 bio = _new_mem_buf(buffer)
1504
1505 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001506 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001507 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001508 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001509 else:
1510 raise ValueError(
1511 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1512
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001513 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001514 _raise_current_error()
1515
1516 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001517 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001518 return cert
1519
1520
1521def dump_certificate(type, cert):
1522 """
1523 Dump a certificate to a buffer
1524
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001525 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1526 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001527 :param cert: The certificate to dump
1528 :return: The buffer with the dumped certificate in
1529 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001530 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001531
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001532 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001533 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001534 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001535 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001536 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001537 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001538 else:
1539 raise ValueError(
1540 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1541 "FILETYPE_TEXT")
1542
1543 return _bio_to_string(bio)
1544
1545
1546
1547def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1548 """
1549 Dump a private key to a buffer
1550
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001551 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1552 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001553 :param pkey: The PKey to dump
1554 :param cipher: (optional) if encrypted PEM format, the cipher to
1555 use
1556 :param passphrase: (optional) if encrypted PEM format, this can be either
1557 the passphrase to use, or a callback for providing the
1558 passphrase.
1559 :return: The buffer with the dumped key in
1560 :rtype: :py:data:`str`
1561 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001562 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001563
1564 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001565 if passphrase is None:
1566 raise TypeError(
1567 "if a value is given for cipher "
1568 "one must also be given for passphrase")
1569 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001570 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001571 raise ValueError("Invalid cipher name")
1572 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001573 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001574
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001575 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001576 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001577 result_code = _lib.PEM_write_bio_PrivateKey(
1578 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001579 helper.callback, helper.callback_args)
1580 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001581 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001582 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001583 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001584 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1585 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001586 # TODO RSA_free(rsa)?
1587 else:
1588 raise ValueError(
1589 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1590 "FILETYPE_TEXT")
1591
1592 if result_code == 0:
1593 _raise_current_error()
1594
1595 return _bio_to_string(bio)
1596
1597
1598
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001599def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001600 copy = _lib.X509_REVOKED_new()
1601 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001602 # TODO: This is untested.
1603 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001604
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001605 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001606 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001607 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001608
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001609 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001610 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001611 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001612
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001613 if original.extensions != _ffi.NULL:
1614 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1615 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1616 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1617 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1618 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001619 copy.extensions = extension_stack
1620
1621 copy.sequence = original.sequence
1622 return copy
1623
1624
1625
1626class Revoked(object):
1627 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1628 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1629 # OCSP_crl_reason_str. We use the latter, just like the command line
1630 # program.
1631 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001632 b"unspecified",
1633 b"keyCompromise",
1634 b"CACompromise",
1635 b"affiliationChanged",
1636 b"superseded",
1637 b"cessationOfOperation",
1638 b"certificateHold",
1639 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001640 ]
1641
1642 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001643 revoked = _lib.X509_REVOKED_new()
1644 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001645
1646
1647 def set_serial(self, hex_str):
1648 """
1649 Set the serial number of a revoked Revoked structure
1650
1651 :param hex_str: The new serial number.
1652 :type hex_str: :py:data:`str`
1653 :return: None
1654 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001655 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1656 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001657 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001658 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001659 if not bn_result:
1660 raise ValueError("bad hex string")
1661
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001662 asn1_serial = _ffi.gc(
1663 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1664 _lib.ASN1_INTEGER_free)
1665 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001666
1667
1668 def get_serial(self):
1669 """
1670 Return the serial number of a Revoked structure
1671
1672 :return: The serial number as a string
1673 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001674 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001675
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001676 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001677 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001678 # TODO: This is untested.
1679 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001680
1681 return _bio_to_string(bio)
1682
1683
1684 def _delete_reason(self):
1685 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001686 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1687 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1688 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1689 _lib.X509_EXTENSION_free(ext)
1690 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001691 break
1692
1693
1694 def set_reason(self, reason):
1695 """
1696 Set the reason of a Revoked object.
1697
1698 If :py:data:`reason` is :py:data:`None`, delete the reason instead.
1699
1700 :param reason: The reason string.
1701 :type reason: :py:class:`str` or :py:class:`NoneType`
1702 :return: None
1703 """
1704 if reason is None:
1705 self._delete_reason()
1706 elif not isinstance(reason, bytes):
1707 raise TypeError("reason must be None or a byte string")
1708 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001709 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001710 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1711
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001712 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1713 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001714 # TODO: This is untested.
1715 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001716 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001717
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001718 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1719 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001720 # TODO: This is untested.
1721 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001722
1723 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001724 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1725 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001726
1727 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001728 # TODO: This is untested.
1729 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001730
1731
1732 def get_reason(self):
1733 """
1734 Return the reason of a Revoked object.
1735
1736 :return: The reason as a string
1737 """
1738 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001739 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1740 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1741 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001742 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001743
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001744 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001745 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001746 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001747 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001748 # TODO: This is untested.
1749 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001750
1751 return _bio_to_string(bio)
1752
1753
1754 def all_reasons(self):
1755 """
1756 Return a list of all the supported reason strings.
1757
1758 :return: A list of reason strings.
1759 """
1760 return self._crl_reasons[:]
1761
1762
1763 def set_rev_date(self, when):
1764 """
1765 Set the revocation timestamp
1766
1767 :param when: A string giving the timestamp, in the format:
1768
1769 YYYYMMDDhhmmssZ
1770 YYYYMMDDhhmmss+hhmm
1771 YYYYMMDDhhmmss-hhmm
1772
1773 :return: None
1774 """
1775 return _set_asn1_time(self._revoked.revocationDate, when)
1776
1777
1778 def get_rev_date(self):
1779 """
1780 Retrieve the revocation date
1781
1782 :return: A string giving the timestamp, in the format:
1783
1784 YYYYMMDDhhmmssZ
1785 YYYYMMDDhhmmss+hhmm
1786 YYYYMMDDhhmmss-hhmm
1787 """
1788 return _get_asn1_time(self._revoked.revocationDate)
1789
1790
1791
1792class CRL(object):
1793 def __init__(self):
1794 """
1795 Create a new empty CRL object.
1796 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001797 crl = _lib.X509_CRL_new()
1798 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001799
1800
1801 def get_revoked(self):
1802 """
1803 Return revoked portion of the CRL structure (by value not reference).
1804
1805 :return: A tuple of Revoked objects.
1806 """
1807 results = []
1808 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001809 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1810 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001811 revoked_copy = _X509_REVOKED_dup(revoked)
1812 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001813 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001814 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001815 if results:
1816 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001817
1818
1819 def add_revoked(self, revoked):
1820 """
1821 Add a revoked (by value not reference) to the CRL structure
1822
1823 :param revoked: The new revoked.
1824 :type revoked: :class:`X509`
1825
1826 :return: None
1827 """
1828 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001829 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001830 # TODO: This is untested.
1831 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001832
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001833 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001834 if add_result == 0:
1835 # TODO: This is untested.
1836 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001837
1838
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001839 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001840 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001841 """
1842 export a CRL as a string
1843
1844 :param cert: Used to sign CRL.
1845 :type cert: :class:`X509`
1846
1847 :param key: Used to sign CRL.
1848 :type key: :class:`PKey`
1849
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001850 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1851 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001852
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001853 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001854
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001855 :param bytes digest: The name of the message digest to use (eg
1856 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001857
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001858 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001859 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001860 if not isinstance(cert, X509):
1861 raise TypeError("cert must be an X509 instance")
1862 if not isinstance(key, PKey):
1863 raise TypeError("key must be a PKey instance")
1864 if not isinstance(type, int):
1865 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001866
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001867 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001868 _warn(
1869 "The default message digest (md5) is deprecated. "
1870 "Pass the name of a message digest explicitly.",
1871 category=DeprecationWarning,
1872 stacklevel=2,
1873 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001874 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001875
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001876 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001877 if digest_obj == _ffi.NULL:
1878 raise ValueError("No such digest method")
1879
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001880 bio = _lib.BIO_new(_lib.BIO_s_mem())
1881 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001882 # TODO: This is untested.
1883 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001884
1885 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001886 sometime = _lib.ASN1_TIME_new()
1887 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001888 # TODO: This is untested.
1889 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001890
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001891 _lib.X509_gmtime_adj(sometime, 0)
1892 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001893
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001894 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1895 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001896
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001897 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001898
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001899 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001900 if not sign_result:
1901 _raise_current_error()
1902
1903 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001904 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001905 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001906 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001907 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001908 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001909 else:
1910 raise ValueError(
1911 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1912
1913 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001914 # TODO: This is untested.
1915 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001916
1917 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001918CRLType = CRL
1919
1920
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001921
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001922class PKCS7(object):
1923 def type_is_signed(self):
1924 """
1925 Check if this NID_pkcs7_signed object
1926
1927 :return: True if the PKCS7 is of type signed
1928 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001929 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001930 return True
1931 return False
1932
1933
1934 def type_is_enveloped(self):
1935 """
1936 Check if this NID_pkcs7_enveloped object
1937
1938 :returns: True if the PKCS7 is of type enveloped
1939 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001940 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001941 return True
1942 return False
1943
1944
1945 def type_is_signedAndEnveloped(self):
1946 """
1947 Check if this NID_pkcs7_signedAndEnveloped object
1948
1949 :returns: True if the PKCS7 is of type signedAndEnveloped
1950 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001951 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001952 return True
1953 return False
1954
1955
1956 def type_is_data(self):
1957 """
1958 Check if this NID_pkcs7_data object
1959
1960 :return: True if the PKCS7 is of type data
1961 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001962 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001963 return True
1964 return False
1965
1966
1967 def get_type_name(self):
1968 """
1969 Returns the type name of the PKCS7 structure
1970
1971 :return: A string with the typename
1972 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001973 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1974 string_type = _lib.OBJ_nid2sn(nid)
1975 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001976
1977PKCS7Type = PKCS7
1978
1979
1980
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001981class PKCS12(object):
1982 def __init__(self):
1983 self._pkey = None
1984 self._cert = None
1985 self._cacerts = None
1986 self._friendlyname = None
1987
1988
1989 def get_certificate(self):
1990 """
1991 Return certificate portion of the PKCS12 structure
1992
1993 :return: X509 object containing the certificate
1994 """
1995 return self._cert
1996
1997
1998 def set_certificate(self, cert):
1999 """
2000 Replace the certificate portion of the PKCS12 structure
2001
2002 :param cert: The new certificate.
2003 :type cert: :py:class:`X509` or :py:data:`None`
2004 :return: None
2005 """
2006 if not isinstance(cert, X509):
2007 raise TypeError("cert must be an X509 instance")
2008 self._cert = cert
2009
2010
2011 def get_privatekey(self):
2012 """
2013 Return private key portion of the PKCS12 structure
2014
2015 :returns: PKey object containing the private key
2016 """
2017 return self._pkey
2018
2019
2020 def set_privatekey(self, pkey):
2021 """
2022 Replace or set the certificate portion of the PKCS12 structure
2023
2024 :param pkey: The new private key.
2025 :type pkey: :py:class:`PKey`
2026 :return: None
2027 """
2028 if not isinstance(pkey, PKey):
2029 raise TypeError("pkey must be a PKey instance")
2030 self._pkey = pkey
2031
2032
2033 def get_ca_certificates(self):
2034 """
2035 Return CA certificates within of the PKCS12 object
2036
2037 :return: A newly created tuple containing the CA certificates in the chain,
2038 if any are present, or None if no CA certificates are present.
2039 """
2040 if self._cacerts is not None:
2041 return tuple(self._cacerts)
2042
2043
2044 def set_ca_certificates(self, cacerts):
2045 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002046 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002047
2048 :param cacerts: The new CA certificates.
2049 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2050 :return: None
2051 """
2052 if cacerts is None:
2053 self._cacerts = None
2054 else:
2055 cacerts = list(cacerts)
2056 for cert in cacerts:
2057 if not isinstance(cert, X509):
2058 raise TypeError("iterable must only contain X509 instances")
2059 self._cacerts = cacerts
2060
2061
2062 def set_friendlyname(self, name):
2063 """
2064 Replace or set the certificate portion of the PKCS12 structure
2065
2066 :param name: The new friendly name.
2067 :type name: :py:class:`bytes`
2068 :return: None
2069 """
2070 if name is None:
2071 self._friendlyname = None
2072 elif not isinstance(name, bytes):
2073 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2074 self._friendlyname = name
2075
2076
2077 def get_friendlyname(self):
2078 """
2079 Return friendly name portion of the PKCS12 structure
2080
2081 :returns: String containing the friendlyname
2082 """
2083 return self._friendlyname
2084
2085
2086 def export(self, passphrase=None, iter=2048, maciter=1):
2087 """
2088 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2089
2090 :param passphrase: used to encrypt the PKCS12
2091 :type passphrase: :py:data:`bytes`
2092
2093 :param iter: How many times to repeat the encryption
2094 :type iter: :py:data:`int`
2095
2096 :param maciter: How many times to repeat the MAC
2097 :type maciter: :py:data:`int`
2098
2099 :return: The string containing the PKCS12
2100 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002101 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002102
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002103 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002104 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002105 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002106 cacerts = _lib.sk_X509_new_null()
2107 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002108 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002109 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002110
2111 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002112 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002113
2114 friendlyname = self._friendlyname
2115 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002116 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002117
2118 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002119 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002120 else:
2121 pkey = self._pkey._pkey
2122
2123 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002124 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002125 else:
2126 cert = self._cert._x509
2127
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002128 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002129 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002130 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2131 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002132 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002133 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002134 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002135 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002136
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002137 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002138 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002139 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002140
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002141PKCS12Type = PKCS12
2142
2143
2144
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002145class NetscapeSPKI(object):
2146 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002147 spki = _lib.NETSCAPE_SPKI_new()
2148 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002149
2150
2151 def sign(self, pkey, digest):
2152 """
2153 Sign the certificate request using the supplied key and digest
2154
2155 :param pkey: The key to sign with
2156 :param digest: The message digest to use
2157 :return: None
2158 """
2159 if pkey._only_public:
2160 raise ValueError("Key has only public part")
2161
2162 if not pkey._initialized:
2163 raise ValueError("Key is uninitialized")
2164
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002165 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002166 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002167 raise ValueError("No such digest method")
2168
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002169 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002170 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002171 # TODO: This is untested.
2172 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002173
2174
2175 def verify(self, key):
2176 """
2177 Verifies a certificate request using the supplied public key
2178
2179 :param key: a public key
2180 :return: True if the signature is correct.
2181 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2182 problem verifying the signature.
2183 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002184 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002185 if answer <= 0:
2186 _raise_current_error()
2187 return True
2188
2189
2190 def b64_encode(self):
2191 """
2192 Generate a base64 encoded string from an SPKI
2193
2194 :return: The base64 encoded string
2195 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002196 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2197 result = _ffi.string(encoded)
2198 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002199 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002200
2201
2202 def get_pubkey(self):
2203 """
2204 Get the public key of the certificate
2205
2206 :return: The public key
2207 """
2208 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002209 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2210 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002211 # TODO: This is untested.
2212 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002213 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002214 pkey._only_public = True
2215 return pkey
2216
2217
2218 def set_pubkey(self, pkey):
2219 """
2220 Set the public key of the certificate
2221
2222 :param pkey: The public key
2223 :return: None
2224 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002225 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002226 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002227 # TODO: This is untested.
2228 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002229NetscapeSPKIType = NetscapeSPKI
2230
2231
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002232class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002233 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002234 if type != FILETYPE_PEM and passphrase is not None:
2235 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002236 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002237 self._more_args = more_args
2238 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002239 self._problems = []
2240
2241
2242 @property
2243 def callback(self):
2244 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002245 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002246 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002247 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002248 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002249 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002250 else:
2251 raise TypeError("Last argument must be string or callable")
2252
2253
2254 @property
2255 def callback_args(self):
2256 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002257 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002258 elif isinstance(self._passphrase, bytes):
2259 return self._passphrase
2260 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002261 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002262 else:
2263 raise TypeError("Last argument must be string or callable")
2264
2265
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002266 def raise_if_problem(self, exceptionType=Error):
2267 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002268 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002269 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002270 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002271 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002272 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002273 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002274
2275
2276 def _read_passphrase(self, buf, size, rwflag, userdata):
2277 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002278 if self._more_args:
2279 result = self._passphrase(size, rwflag, userdata)
2280 else:
2281 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002282 if not isinstance(result, bytes):
2283 raise ValueError("String expected")
2284 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002285 if self._truncate:
2286 result = result[:size]
2287 else:
2288 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002289 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002290 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002291 return len(result)
2292 except Exception as e:
2293 self._problems.append(e)
2294 return 0
2295
2296
2297
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002298def load_privatekey(type, buffer, passphrase=None):
2299 """
2300 Load a private key from a buffer
2301
2302 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2303 :param buffer: The buffer the key is stored in
2304 :param passphrase: (optional) if encrypted PEM format, this can be
2305 either the passphrase to use, or a callback for
2306 providing the passphrase.
2307
2308 :return: The PKey object
2309 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002310 if isinstance(buffer, _text_type):
2311 buffer = buffer.encode("ascii")
2312
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002313 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002314
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002315 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002316 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002317 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2318 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002319 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002320 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002321 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002322 else:
2323 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2324
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002325 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002326 _raise_current_error()
2327
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002328 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002329 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002330 return pkey
2331
2332
2333
2334def dump_certificate_request(type, req):
2335 """
2336 Dump a certificate request to a buffer
2337
2338 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2339 :param req: The certificate request to dump
2340 :return: The buffer with the dumped certificate request in
2341 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002342 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002343
2344 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002345 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002346 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002347 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002348 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002349 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002350 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002351 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002352
2353 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002354 # TODO: This is untested.
2355 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002356
2357 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002358
2359
2360
2361def load_certificate_request(type, buffer):
2362 """
2363 Load a certificate request from a buffer
2364
2365 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2366 :param buffer: The buffer the certificate request is stored in
2367 :return: The X509Req object
2368 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002369 if isinstance(buffer, _text_type):
2370 buffer = buffer.encode("ascii")
2371
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002372 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002373
2374 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002375 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002376 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002377 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002378 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002379 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002380
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002381 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002382 # TODO: This is untested.
2383 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002384
2385 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002386 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002387 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002388
2389
2390
2391def sign(pkey, data, digest):
2392 """
2393 Sign data with a digest
2394
2395 :param pkey: Pkey to sign with
2396 :param data: data to be signed
2397 :param digest: message digest to use
2398 :return: signature
2399 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002400 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002401
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002402 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002403 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002404 raise ValueError("No such digest method")
2405
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002406 md_ctx = _ffi.new("EVP_MD_CTX*")
2407 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002408
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002409 _lib.EVP_SignInit(md_ctx, digest_obj)
2410 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002411
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002412 signature_buffer = _ffi.new("unsigned char[]", 512)
2413 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002414 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002415 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002416 md_ctx, signature_buffer, signature_length, pkey._pkey)
2417
2418 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002419 # TODO: This is untested.
2420 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002421
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002422 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002423
2424
2425
2426def verify(cert, signature, data, digest):
2427 """
2428 Verify a signature
2429
2430 :param cert: signing certificate (X509 object)
2431 :param signature: signature returned by sign function
2432 :param data: data to be verified
2433 :param digest: message digest to use
2434 :return: None if the signature is correct, raise exception otherwise
2435 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002436 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002437
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002438 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002439 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002440 raise ValueError("No such digest method")
2441
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002442 pkey = _lib.X509_get_pubkey(cert._x509)
2443 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002444 # TODO: This is untested.
2445 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002446 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002447
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002448 md_ctx = _ffi.new("EVP_MD_CTX*")
2449 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002450
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002451 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2452 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2453 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002454
2455 if verify_result != 1:
2456 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002457
2458
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002459def load_crl(type, buffer):
2460 """
2461 Load a certificate revocation list from a buffer
2462
2463 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2464 :param buffer: The buffer the CRL is stored in
2465
2466 :return: The PKey object
2467 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002468 if isinstance(buffer, _text_type):
2469 buffer = buffer.encode("ascii")
2470
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002471 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002472
2473 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002474 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002475 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002476 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002477 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002478 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2479
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002480 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002481 _raise_current_error()
2482
2483 result = CRL.__new__(CRL)
2484 result._crl = crl
2485 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002486
2487
2488
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002489def load_pkcs7_data(type, buffer):
2490 """
2491 Load pkcs7 data from a buffer
2492
2493 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2494 :param buffer: The buffer with the pkcs7 data.
2495 :return: The PKCS7 object
2496 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002497 if isinstance(buffer, _text_type):
2498 buffer = buffer.encode("ascii")
2499
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002500 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002501
2502 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002503 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002504 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002505 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002506 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002507 # TODO: This is untested.
2508 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002509 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2510
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002511 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002512 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002513
2514 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002515 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002516 return pypkcs7
2517
2518
2519
Stephen Holsapple38482622014-04-05 20:29:34 -07002520def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002521 """
2522 Load a PKCS12 object from a buffer
2523
2524 :param buffer: The buffer the certificate is stored in
2525 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2526 :returns: The PKCS12 object
2527 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002528 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002529
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002530 if isinstance(buffer, _text_type):
2531 buffer = buffer.encode("ascii")
2532
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002533 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002534
Stephen Holsapple38482622014-04-05 20:29:34 -07002535 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2536 # password based encryption no password and a zero length password are two
2537 # different things, but OpenSSL implementation will try both to figure out
2538 # which one works.
2539 if not passphrase:
2540 passphrase = _ffi.NULL
2541
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002542 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2543 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002544 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002545 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002546
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002547 pkey = _ffi.new("EVP_PKEY**")
2548 cert = _ffi.new("X509**")
2549 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002550
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002551 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002552 if not parse_result:
2553 _raise_current_error()
2554
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002555 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002556
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002557 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2558 # queue for no particular reason. This error isn't interesting to anyone
2559 # outside this function. It's not even interesting to us. Get rid of it.
2560 try:
2561 _raise_current_error()
2562 except Error:
2563 pass
2564
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002565 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002566 pykey = None
2567 else:
2568 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002569 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002570
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002571 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002572 pycert = None
2573 friendlyname = None
2574 else:
2575 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002576 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002577
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002578 friendlyname_length = _ffi.new("int*")
2579 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2580 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2581 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002582 friendlyname = None
2583
2584 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002585 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002586 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002587 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002588 pycacerts.append(pycacert)
2589 if not pycacerts:
2590 pycacerts = None
2591
2592 pkcs12 = PKCS12.__new__(PKCS12)
2593 pkcs12._pkey = pykey
2594 pkcs12._cert = pycert
2595 pkcs12._cacerts = pycacerts
2596 pkcs12._friendlyname = friendlyname
2597 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002598
2599
2600def _initialize_openssl_threads(get_ident, Lock):
2601 import _ssl
2602 return
2603
2604 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2605
2606 def locking_function(mode, index, filename, line):
2607 if mode & _lib.CRYPTO_LOCK:
2608 locks[index].acquire()
2609 else:
2610 locks[index].release()
2611
2612 _lib.CRYPTO_set_id_callback(
2613 _ffi.callback("unsigned long (*)(void)", get_ident))
2614
2615 _lib.CRYPTO_set_locking_callback(
2616 _ffi.callback(
2617 "void (*)(int, int, const char*, int)", locking_function))
2618
2619
2620try:
2621 from thread import get_ident
2622 from threading import Lock
2623except ImportError:
2624 pass
2625else:
2626 _initialize_openssl_threads(get_ident, Lock)
2627 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002628
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002629# There are no direct unit tests for this initialization. It is tested
2630# indirectly since it is necessary for functions like dump_privatekey when
2631# using encryption.
2632#
2633# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2634# and some other similar tests may fail without this (though they may not if
2635# the Python runtime has already done some initialization of the underlying
2636# OpenSSL library (and is linked against the same one that cryptography is
2637# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002638_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002639
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002640# This is similar but exercised mainly by exception_from_error_queue. It calls
2641# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2642_lib.SSL_load_error_strings()