blob: 678c048856f59e1d9671c52ff8f73446fcab22f6 [file] [log] [blame]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001from time import time
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05003from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05004from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
5
6from six import (
7 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -04008 text_type as _text_type,
9 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080010
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050011from OpenSSL._util import (
12 ffi as _ffi,
13 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050014 exception_from_error_queue as _exception_from_error_queue,
15 byte_string as _byte_string,
16 native as _native)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080017
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050018FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
19FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080020
21# TODO This was an API mistake. OpenSSL has no such constant.
22FILETYPE_TEXT = 2 ** 16 - 1
23
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050024TYPE_RSA = _lib.EVP_PKEY_RSA
25TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080026
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080027
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050028class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050029 """
30 An error occurred in an `OpenSSL.crypto` API.
31 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050032
33
34_raise_current_error = partial(_exception_from_error_queue, Error)
35
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050036def _untested_error(where):
37 """
38 An OpenSSL API failed somehow. Additionally, the failure which was
39 encountered isn't one that's exercised by the test suite so future behavior
40 of pyOpenSSL is now somewhat less predictable.
41 """
42 raise RuntimeError("Unknown %s failure" % (where,))
43
44
45
46def _new_mem_buf(buffer=None):
47 """
48 Allocate a new OpenSSL memory BIO.
49
50 Arrange for the garbage collector to clean it up automatically.
51
52 :param buffer: None or some bytes to use to put into the BIO so that they
53 can be read out.
54 """
55 if buffer is None:
56 bio = _lib.BIO_new(_lib.BIO_s_mem())
57 free = _lib.BIO_free
58 else:
59 data = _ffi.new("char[]", buffer)
60 bio = _lib.BIO_new_mem_buf(data, len(buffer))
61 # Keep the memory alive as long as the bio is alive!
62 def free(bio, ref=data):
63 return _lib.BIO_free(bio)
64
65 if bio == _ffi.NULL:
66 # TODO: This is untested.
67 _raise_current_error()
68
69 bio = _ffi.gc(bio, free)
70 return bio
71
72
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050073
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080074def _bio_to_string(bio):
75 """
76 Copy the contents of an OpenSSL BIO object into a Python byte string.
77 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050078 result_buffer = _ffi.new('char**')
79 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
80 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080081
82
83
Jean-Paul Calderone57122982013-02-21 08:47:05 -080084def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050085 """
86 The the time value of an ASN1 time object.
87
88 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
89 castable to that type) which will have its value set.
90 @param when: A string representation of the desired time value.
91
92 @raise TypeError: If C{when} is not a L{bytes} string.
93 @raise ValueError: If C{when} does not represent a time in the required
94 format.
95 @raise RuntimeError: If the time value cannot be set for some other
96 (unspecified) reason.
97 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -080098 if not isinstance(when, bytes):
99 raise TypeError("when must be a byte string")
100
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500101 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
102 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800103 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500104 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
105 _lib.ASN1_STRING_set(dummy, when, len(when))
106 check_result = _lib.ASN1_GENERALIZEDTIME_check(
107 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800108 if not check_result:
109 raise ValueError("Invalid string")
110 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500111 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800112
113
114
115def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500116 """
117 Retrieve the time value of an ASN1 time object.
118
119 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
120 that type) from which the time value will be retrieved.
121
122 @return: The time value from C{timestamp} as a L{bytes} string in a certain
123 format. Or C{None} if the object contains no time value.
124 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500125 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
126 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800127 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500128 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
129 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800130 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500131 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
132 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
133 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500134 # This may happen:
135 # - if timestamp was not an ASN1_TIME
136 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
137 # - if a copy of the time data from timestamp cannot be made for
138 # the newly allocated ASN1_GENERALIZEDTIME
139 #
140 # These are difficult to test. cffi enforces the ASN1_TIME type.
141 # Memory allocation failures are a pain to trigger
142 # deterministically.
143 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800144 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500145 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800146 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500147 string_data = _lib.ASN1_STRING_data(string_timestamp)
148 string_result = _ffi.string(string_data)
149 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800150 return string_result
151
152
153
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800154class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200155 """
156 A class representing an DSA or RSA public key or key pair.
157 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800158 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800159 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800160
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800161 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500162 pkey = _lib.EVP_PKEY_new()
163 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800164 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800165
166
167 def generate_key(self, type, bits):
168 """
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200169 Generate a key pair of the given type, with the given number of a bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800170
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200171 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800172
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200173 :param type: The key type.
174 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
175 :param bits: The number of bits.
176 :type bits: :py:data:`int` ``>= 0``
177 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
178 of the appropriate type.
179 :raises ValueError: If the number of bits isn't an integer of
180 the appropriate size.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200181 :return: :py:const:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800182 """
183 if not isinstance(type, int):
184 raise TypeError("type must be an integer")
185
186 if not isinstance(bits, int):
187 raise TypeError("bits must be an integer")
188
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800189 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500190 exponent = _lib.BN_new()
191 exponent = _ffi.gc(exponent, _lib.BN_free)
192 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800193
194 if type == TYPE_RSA:
195 if bits <= 0:
196 raise ValueError("Invalid number of bits")
197
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500198 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800199
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500200 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500201 if result == 0:
202 # TODO: The test for this case is commented out. Different
203 # builds of OpenSSL appear to have different failure modes that
204 # make it hard to test. Visual inspection of the OpenSSL
205 # source reveals that a return value of 0 signals an error.
206 # Manual testing on a particular build of OpenSSL suggests that
207 # this is probably the appropriate way to handle those errors.
208 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800209
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500210 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800211 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500212 # TODO: It appears as though this can fail if an engine is in
213 # use which does not support RSA.
214 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800215
216 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500217 dsa = _lib.DSA_generate_parameters(
218 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
219 if dsa == _ffi.NULL:
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.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500223 # TODO: This is untested.
224 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500225 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500226 # TODO: This is untested.
227 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800228 else:
229 raise Error("No such key type")
230
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800231 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800232
233
234 def check(self):
235 """
236 Check the consistency of an RSA private key.
237
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200238 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
239
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800240 :return: True if key is consistent.
241 :raise Error: if the key is inconsistent.
242 :raise TypeError: if the key is of a type which cannot be checked.
243 Only RSA keys can currently be checked.
244 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800245 if self._only_public:
246 raise TypeError("public key only")
247
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500248 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800249 raise TypeError("key type unsupported")
250
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500251 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
252 rsa = _ffi.gc(rsa, _lib.RSA_free)
253 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800254 if result:
255 return True
256 _raise_current_error()
257
258
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800259 def type(self):
260 """
261 Returns the type of the key
262
263 :return: The type of the key.
264 """
265 return self._pkey.type
266
267
268 def bits(self):
269 """
270 Returns the number of bits of the key
271
272 :return: The number of bits of the key.
273 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500274 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800275PKeyType = PKey
276
277
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800278
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400279class _EllipticCurve(object):
280 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400281 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400282
283 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
284 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
285 instances each of which represents one curve supported by the system.
286 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400287 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400288 _curves = None
289
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400290 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400291 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400292 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400293 """
294 Implement cooperation with the right-hand side argument of ``!=``.
295
296 Python 3 seems to have dropped this cooperation in this very narrow
297 circumstance.
298 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400299 if isinstance(other, _EllipticCurve):
300 return super(_EllipticCurve, self).__ne__(other)
301 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400302
303
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400304 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400305 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400306 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400307 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400308
309 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400310
311 :return: A :py:type:`set` of ``cls`` instances giving the names of the
312 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400313 """
314 if lib.Cryptography_HAS_EC:
315 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
316 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
317 # The return value on this call should be num_curves again. We could
318 # check it to make sure but if it *isn't* then.. what could we do?
319 # Abort the whole process, I suppose...? -exarkun
320 lib.EC_get_builtin_curves(builtin_curves, num_curves)
321 return set(
322 cls.from_nid(lib, c.nid)
323 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400324 return set()
325
326
327 @classmethod
328 def _get_elliptic_curves(cls, lib):
329 """
330 Get, cache, and return the curves supported by OpenSSL.
331
332 :param lib: The OpenSSL library binding object.
333
334 :return: A :py:type:`set` of ``cls`` instances giving the names of the
335 elliptic curves the underlying library supports.
336 """
337 if cls._curves is None:
338 cls._curves = cls._load_elliptic_curves(lib)
339 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400340
341
342 @classmethod
343 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400344 """
345 Instantiate a new :py:class:`_EllipticCurve` associated with the given
346 OpenSSL NID.
347
348 :param lib: The OpenSSL library binding object.
349
350 :param nid: The OpenSSL NID the resulting curve object will represent.
351 This must be a curve NID (and not, for example, a hash NID) or
352 subsequent operations will fail in unpredictable ways.
353 :type nid: :py:class:`int`
354
355 :return: The curve object.
356 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400357 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
358
359
360 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400361 """
362 :param _lib: The :py:mod:`cryptography` binding instance used to
363 interface with OpenSSL.
364
365 :param _nid: The OpenSSL NID identifying the curve this object
366 represents.
367 :type _nid: :py:class:`int`
368
369 :param name: The OpenSSL short name identifying the curve this object
370 represents.
371 :type name: :py:class:`unicode`
372 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400373 self._lib = lib
374 self._nid = nid
375 self.name = name
376
377
378 def __repr__(self):
379 return "<Curve %r>" % (self.name,)
380
381
382 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400383 """
384 Create a new OpenSSL EC_KEY structure initialized to use this curve.
385
386 The structure is automatically garbage collected when the Python object
387 is garbage collected.
388 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400389 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
390 return _ffi.gc(key, _lib.EC_KEY_free)
391
392
393
394def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400395 """
396 Return a set of objects representing the elliptic curves supported in the
397 OpenSSL build in use.
398
399 The curve objects have a :py:class:`unicode` ``name`` attribute by which
400 they identify themselves.
401
402 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400403 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
404 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400405 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400406 return _EllipticCurve._get_elliptic_curves(_lib)
407
408
409
410def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400411 """
412 Return a single curve object selected by name.
413
414 See :py:func:`get_elliptic_curves` for information about curve objects.
415
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400416 :param name: The OpenSSL short name identifying the curve object to
417 retrieve.
418 :type name: :py:class:`unicode`
419
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400420 If the named curve is not supported then :py:class:`ValueError` is raised.
421 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400422 for curve in get_elliptic_curves():
423 if curve.name == name:
424 return curve
425 raise ValueError("unknown curve name", name)
426
427
428
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800429class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200430 """
431 An X.509 Distinguished Name.
432
433 :ivar countryName: The country of the entity.
434 :ivar C: Alias for :py:attr:`countryName`.
435
436 :ivar stateOrProvinceName: The state or province of the entity.
437 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
438
439 :ivar localityName: The locality of the entity.
440 :ivar L: Alias for :py:attr:`localityName`.
441
442 :ivar organizationName: The organization name of the entity.
443 :ivar O: Alias for :py:attr:`organizationName`.
444
445 :ivar organizationalUnitName: The organizational unit of the entity.
446 :ivar OU: Alias for :py:attr:`organizationalUnitName`
447
448 :ivar commonName: The common name of the entity.
449 :ivar CN: Alias for :py:attr:`commonName`.
450
451 :ivar emailAddress: The e-mail address of the entity.
452 """
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800453 def __init__(self, name):
454 """
455 Create a new X509Name, copying the given X509Name instance.
456
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200457 :param name: The name to copy.
458 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800459 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500460 name = _lib.X509_NAME_dup(name._name)
461 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800462
463
464 def __setattr__(self, name, value):
465 if name.startswith('_'):
466 return super(X509Name, self).__setattr__(name, value)
467
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800468 # Note: we really do not want str subclasses here, so we do not use
469 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800470 if type(name) is not str:
471 raise TypeError("attribute name must be string, not '%.200s'" % (
472 type(value).__name__,))
473
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500474 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500475 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800476 try:
477 _raise_current_error()
478 except Error:
479 pass
480 raise AttributeError("No such attribute")
481
482 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500483 for i in range(_lib.X509_NAME_entry_count(self._name)):
484 ent = _lib.X509_NAME_get_entry(self._name, i)
485 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
486 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800487 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500488 ent = _lib.X509_NAME_delete_entry(self._name, i)
489 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800490 break
491
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500492 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800493 value = value.encode('utf-8')
494
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500495 add_result = _lib.X509_NAME_add_entry_by_NID(
496 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800497 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500498 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800499
500
501 def __getattr__(self, name):
502 """
503 Find attribute. An X509Name object has the following attributes:
504 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
505 organization (alias O), organizationalUnit (alias OU), commonName (alias
506 CN) and more...
507 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500508 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500509 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800510 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
511 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
512 # push something onto the error queue. If we don't clean that up
513 # now, someone else will bump into it later and be quite confused.
514 # See lp#314814.
515 try:
516 _raise_current_error()
517 except Error:
518 pass
519 return super(X509Name, self).__getattr__(name)
520
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500521 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800522 if entry_index == -1:
523 return None
524
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500525 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
526 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800527
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500528 result_buffer = _ffi.new("unsigned char**")
529 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800530 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500531 # TODO: This is untested.
532 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800533
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700534 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500535 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700536 finally:
537 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500538 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800539 return result
540
541
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500542 def _cmp(op):
543 def f(self, other):
544 if not isinstance(other, X509Name):
545 return NotImplemented
546 result = _lib.X509_NAME_cmp(self._name, other._name)
547 return op(result, 0)
548 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800549
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500550 __eq__ = _cmp(__eq__)
551 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800552
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500553 __lt__ = _cmp(__lt__)
554 __le__ = _cmp(__le__)
555
556 __gt__ = _cmp(__gt__)
557 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800558
559 def __repr__(self):
560 """
561 String representation of an X509Name
562 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500563 result_buffer = _ffi.new("char[]", 512);
564 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800565 self._name, result_buffer, len(result_buffer))
566
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500567 if format_result == _ffi.NULL:
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 Calderone4f0467a2014-01-11 11:58:41 -0500571 return "<X509Name object '%s'>" % (
572 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800573
574
575 def hash(self):
576 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200577 Return an integer representation of the first four bytes of the
578 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800579
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200580 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
581
582 :return: The (integer) hash of this name.
583 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800584 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500585 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800586
587
588 def der(self):
589 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200590 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800591
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200592 :return: The DER encoded form of this name.
593 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800594 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500595 result_buffer = _ffi.new('unsigned char**')
596 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800597 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500598 # TODO: This is untested.
599 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800600
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500601 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
602 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800603 return string_result
604
605
606 def get_components(self):
607 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200608 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800609
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200610 :return: The components of this name.
611 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800612 """
613 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500614 for i in range(_lib.X509_NAME_entry_count(self._name)):
615 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800616
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500617 fname = _lib.X509_NAME_ENTRY_get_object(ent)
618 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800619
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500620 nid = _lib.OBJ_obj2nid(fname)
621 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800622
623 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500624 _ffi.string(name),
625 _ffi.string(
626 _lib.ASN1_STRING_data(fval),
627 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800628
629 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200630
631
632
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800633X509NameType = X509Name
634
635
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200636
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800637class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200638 """
639 An X.509 v3 certificate extension.
640 """
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800641 def __init__(self, type_name, critical, value, subject=None, issuer=None):
642 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200643 Initializes an X509 extension.
644
645 :param typename: The name of the type of extension to create. See
646 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800647 :type typename: :py:data:`str`
648
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200649 :param bool critical: A flag indicating whether this is a critical extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800650
651 :param value: The value of the extension.
652 :type value: :py:data:`str`
653
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200654 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800655 :type subject: :py:class:`X509`
656
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200657 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800658 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800659 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500660 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800661
662 # A context is necessary for any extension which uses the r2i conversion
663 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
664 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500665 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800666
667 # We have no configuration database - but perhaps we should (some
668 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500669 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800670
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800671 # Initialize the subject and issuer, if appropriate. ctx is a local,
672 # and as far as I can tell none of the X509V3_* APIs invoked here steal
673 # any references, so no need to mess with reference counts or duplicates.
674 if issuer is not None:
675 if not isinstance(issuer, X509):
676 raise TypeError("issuer must be an X509 instance")
677 ctx.issuer_cert = issuer._x509
678 if subject is not None:
679 if not isinstance(subject, X509):
680 raise TypeError("subject must be an X509 instance")
681 ctx.subject_cert = subject._x509
682
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800683 if critical:
684 # There are other OpenSSL APIs which would let us pass in critical
685 # separately, but they're harder to use, and since value is already
686 # a pile of crappy junk smuggling a ton of utterly important
687 # structured data, what's the point of trying to avoid nasty stuff
688 # with strings? (However, X509V3_EXT_i2d in particular seems like it
689 # would be a better API to invoke. I do not know where to get the
690 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500691 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800692
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500693 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
694 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800695 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500696 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800697
698
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400699 @property
700 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500701 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400702
703 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500704 _lib.GEN_EMAIL: "email",
705 _lib.GEN_DNS: "DNS",
706 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400707 }
708
709 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500710 method = _lib.X509V3_EXT_get(self._extension)
711 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500712 # TODO: This is untested.
713 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400714 payload = self._extension.value.data
715 length = self._extension.value.length
716
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500717 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400718 payloadptr[0] = payload
719
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500720 if method.it != _ffi.NULL:
721 ptr = _lib.ASN1_ITEM_ptr(method.it)
722 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
723 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400724 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500725 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400726 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500727 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400728
729 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500730 for i in range(_lib.sk_GENERAL_NAME_num(names)):
731 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400732 try:
733 label = self._prefixes[name.type]
734 except KeyError:
735 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500736 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500737 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400738 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500739 value = _native(
740 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
741 parts.append(label + ":" + value)
742 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400743
744
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800745 def __str__(self):
746 """
747 :return: a nice text representation of the extension
748 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500749 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400750 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800751
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400752 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500753 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800754 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500755 # TODO: This is untested.
756 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800757
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500758 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800759
760
761 def get_critical(self):
762 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200763 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800764
765 :return: The critical field.
766 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500767 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800768
769
770 def get_short_name(self):
771 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200772 Returns the short type name of this X.509 extension.
773
774 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800775
776 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200777 :rtype: :py:data:`bytes`
778
779 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800780 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500781 obj = _lib.X509_EXTENSION_get_object(self._extension)
782 nid = _lib.OBJ_obj2nid(obj)
783 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800784
785
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800786 def get_data(self):
787 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200788 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800789
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200790 :return: The ASN.1 encoded data of this X509 extension.
791 :rtype: :py:data:`bytes`
792
793 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800794 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500795 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
796 string_result = _ffi.cast('ASN1_STRING*', octet_result)
797 char_result = _lib.ASN1_STRING_data(string_result)
798 result_length = _lib.ASN1_STRING_length(string_result)
799 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800800
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200801
802
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800803X509ExtensionType = X509Extension
804
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800805
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200806
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800807class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200808 """
809 An X.509 certificate signing requests.
810 """
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500812 req = _lib.X509_REQ_new()
813 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800814
815
816 def set_pubkey(self, pkey):
817 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200818 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800819
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200820 :param pkey: The public key to use.
821 :type pkey: :py:class:`PKey`
822
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200823 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800824 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500825 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800826 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500827 # TODO: This is untested.
828 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800829
830
831 def get_pubkey(self):
832 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200833 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800834
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200835 :return: The public key.
836 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800837 """
838 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500839 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
840 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500841 # TODO: This is untested.
842 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500843 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800844 pkey._only_public = True
845 return pkey
846
847
848 def set_version(self, version):
849 """
850 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
851 request.
852
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200853 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200854 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800855 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500856 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800857 if not set_result:
858 _raise_current_error()
859
860
861 def get_version(self):
862 """
863 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
864 request.
865
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200866 :return: The value of the version subfield.
867 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800868 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500869 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800870
871
872 def get_subject(self):
873 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200874 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800875
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200876 This creates a new :py:class:`X509Name`: modifying it does not affect
877 this request.
878
879 :return: The subject of this certificate signing request.
880 :rtype: :py:class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800881 """
882 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500883 name._name = _lib.X509_REQ_get_subject_name(self._req)
884 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500885 # TODO: This is untested.
886 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800887
888 # The name is owned by the X509Req structure. As long as the X509Name
889 # Python object is alive, keep the X509Req Python object alive.
890 name._owner = self
891
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800892 return name
893
894
895 def add_extensions(self, extensions):
896 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200897 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800898
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200899 :param extensions: The X.509 extensions to add.
900 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200901 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800902 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500903 stack = _lib.sk_X509_EXTENSION_new_null()
904 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500905 # TODO: This is untested.
906 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800907
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500908 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800909
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800910 for ext in extensions:
911 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800912 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800913
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800914 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500915 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800916
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500917 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800918 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500919 # TODO: This is untested.
920 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800921
922
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800923 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800924 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200925 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800926
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200927 :return: The X.509 extensions in this request.
928 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
929
930 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800931 """
932 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500933 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500934 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800935 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500936 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800937 exts.append(ext)
938 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800939
940
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800941 def sign(self, pkey, digest):
942 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200943 Sign the certificate signing request using the supplied key and digest.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800944
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200945 :param pkey: The key pair to sign with.
946 :type pkey: :py:class:`PKey`
947 :param digest: The name of the message digest to use for the signature,
948 e.g. :py:data:`b"sha1"`.
949 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200950 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800951 """
952 if pkey._only_public:
953 raise ValueError("Key has only public part")
954
955 if not pkey._initialized:
956 raise ValueError("Key is uninitialized")
957
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500958 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500959 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800960 raise ValueError("No such digest method")
961
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500962 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800963 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500964 # TODO: This is untested.
965 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800966
967
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800968 def verify(self, pkey):
969 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200970 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800971
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200972 :param key: A public key.
973 :type key: :py:class:`PKey`
974 :return: :py:data:`True` if the signature is correct.
975 :rtype: :py:class:`bool`
976 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800977 problem verifying the signature.
978 """
979 if not isinstance(pkey, PKey):
980 raise TypeError("pkey must be a PKey instance")
981
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500982 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800983 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500984 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800985
986 return result
987
988
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200989
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800990X509ReqType = X509Req
991
992
993
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800994class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200995 """
996 An X.509 certificate.
997 """
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800998 def __init__(self):
999 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001000 x509 = _lib.X509_new()
1001 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001002
1003
1004 def set_version(self, version):
1005 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001006 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001007
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001008 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001009 :type version: :py:class:`int`
1010
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001011 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001012 """
1013 if not isinstance(version, int):
1014 raise TypeError("version must be an integer")
1015
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001016 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001017
1018
1019 def get_version(self):
1020 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001021 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001022
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001023 :return: The version number of the certificate.
1024 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001025 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001026 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001027
1028
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001029 def get_pubkey(self):
1030 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001031 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001032
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001033 :return: The public key.
1034 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001035 """
1036 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001037 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1038 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001039 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001040 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001041 pkey._only_public = True
1042 return pkey
1043
1044
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001045 def set_pubkey(self, pkey):
1046 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001047 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001048
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001049 :param pkey: The public key.
1050 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001051
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001052 :return: :py:data`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001053 """
1054 if not isinstance(pkey, PKey):
1055 raise TypeError("pkey must be a PKey instance")
1056
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001057 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001058 if not set_result:
1059 _raise_current_error()
1060
1061
1062 def sign(self, pkey, digest):
1063 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001064 Sign the certificate using the supplied key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001065
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001066 :param pkey: The key to sign with.
1067 :type pkey: :py:class:`PKey`
1068
1069 :param digest: The name of the message digest to use.
1070 :type digest: :py:class:`bytes`
1071
1072 :return: :py:data`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001073 """
1074 if not isinstance(pkey, PKey):
1075 raise TypeError("pkey must be a PKey instance")
1076
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001077 if pkey._only_public:
1078 raise ValueError("Key only has public part")
1079
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001080 if not pkey._initialized:
1081 raise ValueError("Key is uninitialized")
1082
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001083 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001084 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001085 raise ValueError("No such digest method")
1086
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001087 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001088 if not sign_result:
1089 _raise_current_error()
1090
1091
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001092 def get_signature_algorithm(self):
1093 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001094 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001095
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001096 :return: The name of the algorithm.
1097 :rtype: :py:class:`bytes`
1098
1099 :raises ValueError: If the signature algorithm is undefined.
1100
1101 ..versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001102 """
1103 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001104 nid = _lib.OBJ_obj2nid(alg)
1105 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001106 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001107 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001108
1109
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001110 def digest(self, digest_name):
1111 """
1112 Return the digest of the X509 object.
1113
1114 :param digest_name: The name of the digest algorithm to use.
1115 :type digest_name: :py:class:`bytes`
1116
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001117 :return: The digest of the object, formatted as
1118 :py:const:`b":"`-delimited hex pairs.
1119 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001120 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001121 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001122 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001123 raise ValueError("No such digest method")
1124
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001125 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1126 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001127 result_length[0] = len(result_buffer)
1128
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001129 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001130 self._x509, digest, result_buffer, result_length)
1131
1132 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001133 # TODO: This is untested.
1134 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001135
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001136 return b":".join([
1137 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001138 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001139
1140
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001141 def subject_name_hash(self):
1142 """
1143 Return the hash of the X509 subject.
1144
1145 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001146 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001147 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001148 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001149
1150
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001151 def set_serial_number(self, serial):
1152 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001153 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001154
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001155 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001156 :type serial: :py:class:`int`
1157
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001158 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001159 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001160 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001161 raise TypeError("serial must be an integer")
1162
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001163 hex_serial = hex(serial)[2:]
1164 if not isinstance(hex_serial, bytes):
1165 hex_serial = hex_serial.encode('ascii')
1166
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001167 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001168
1169 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1170 # it. If bignum is still NULL after this call, then the return value is
1171 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001172 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001173
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001174 if bignum_serial[0] == _ffi.NULL:
1175 set_result = _lib.ASN1_INTEGER_set(
1176 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001177 if set_result:
1178 # TODO Not tested
1179 _raise_current_error()
1180 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001181 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1182 _lib.BN_free(bignum_serial[0])
1183 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001184 # TODO Not tested
1185 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001186 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1187 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001188 if not set_result:
1189 # TODO Not tested
1190 _raise_current_error()
1191
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001192
1193 def get_serial_number(self):
1194 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001195 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001196
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001197 :return: The serial number.
1198 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001199 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001200 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1201 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001202 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001203 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001204 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001205 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001206 serial = int(hexstring_serial, 16)
1207 return serial
1208 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001209 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001210 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001211 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001212
1213
1214 def gmtime_adj_notAfter(self, amount):
1215 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001216 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001217
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001218 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001219 :type amount: :py:class:`int`
1220
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001221 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001222 """
1223 if not isinstance(amount, int):
1224 raise TypeError("amount must be an integer")
1225
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001226 notAfter = _lib.X509_get_notAfter(self._x509)
1227 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001228
1229
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001230 def gmtime_adj_notBefore(self, amount):
1231 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001232 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001233
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001234 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001235 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001236 """
1237 if not isinstance(amount, int):
1238 raise TypeError("amount must be an integer")
1239
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001240 notBefore = _lib.X509_get_notBefore(self._x509)
1241 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001242
1243
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001244 def has_expired(self):
1245 """
1246 Check whether the certificate has expired.
1247
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001248 :return: :py:const:`True` if the certificate has expired,
1249 :py:const:`False` otherwise.
1250 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001251 """
1252 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001253 notAfter = _lib.X509_get_notAfter(self._x509)
1254 return _lib.ASN1_UTCTIME_cmp_time_t(
1255 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001256
1257
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001258 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001259 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001260
1261
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001262 def get_notBefore(self):
1263 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001264 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001265
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001266 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001267
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001268 YYYYMMDDhhmmssZ
1269 YYYYMMDDhhmmss+hhmm
1270 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001271
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001272 :return: A timestamp string, or :py:const:`None` if there is none.
1273 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001274 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001275 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001276
1277
1278 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001279 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001280
1281
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001282 def set_notBefore(self, when):
1283 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001284 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001285
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001286 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001287
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001288 YYYYMMDDhhmmssZ
1289 YYYYMMDDhhmmss+hhmm
1290 YYYYMMDDhhmmss-hhmm
1291
1292 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001293 :type when: :py:class:`bytes`
1294
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001295 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001296 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001297 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001298
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001299
1300 def get_notAfter(self):
1301 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001302 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001303
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001304 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001305
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001306 YYYYMMDDhhmmssZ
1307 YYYYMMDDhhmmss+hhmm
1308 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001309
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001310 :return: A timestamp string, or :py:const:`None` if there is none.
1311 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001312 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001313 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001314
1315
1316 def set_notAfter(self, when):
1317 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001318 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001319
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001320 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001321
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001322 YYYYMMDDhhmmssZ
1323 YYYYMMDDhhmmss+hhmm
1324 YYYYMMDDhhmmss-hhmm
1325
1326 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001327 :type when: :py:class:`bytes`
1328
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001329 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001330 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001331 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001332
1333
1334 def _get_name(self, which):
1335 name = X509Name.__new__(X509Name)
1336 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001337 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001338 # TODO: This is untested.
1339 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001340
1341 # The name is owned by the X509 structure. As long as the X509Name
1342 # Python object is alive, keep the X509 Python object alive.
1343 name._owner = self
1344
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001345 return name
1346
1347
1348 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001349 if not isinstance(name, X509Name):
1350 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001351 set_result = which(self._x509, name._name)
1352 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001353 # TODO: This is untested.
1354 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001355
1356
1357 def get_issuer(self):
1358 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001359 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001360
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001361 This creates a new :py:class:`X509Name`: modifying it does not affect
1362 this certificate.
1363
1364 :return: The issuer of this certificate.
1365 :rtype: :py:class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001366 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001367 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001368
1369
1370 def set_issuer(self, issuer):
1371 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001372 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001373
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001374 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001375 :type issuer: :py:class:`X509Name`
1376
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001377 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001378 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001379 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001380
1381
1382 def get_subject(self):
1383 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001384 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001385
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001386 This creates a new :py:class:`X509Name`: modifying it does not affect
1387 this certificate.
1388
1389 :return: The subject of this certificate.
1390 :rtype: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001391 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001392 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001393
1394
1395 def set_subject(self, subject):
1396 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001397 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001398
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001399 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001400 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001401
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001402 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001403 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001404 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001405
1406
1407 def get_extension_count(self):
1408 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001409 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001410
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001411 :return: The number of extensions.
1412 :rtype: :py:class:`int`
1413
1414 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001415 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001416 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001417
1418
1419 def add_extensions(self, extensions):
1420 """
1421 Add extensions to the certificate.
1422
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001423 :param extensions: The extensions to add.
1424 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001425 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001426 """
1427 for ext in extensions:
1428 if not isinstance(ext, X509Extension):
1429 raise ValueError("One of the elements is not an X509Extension")
1430
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001431 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001432 if not add_result:
1433 _raise_current_error()
1434
1435
1436 def get_extension(self, index):
1437 """
1438 Get a specific extension of the certificate by index.
1439
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001440 Extensions on a certificate are kept in order. The index
1441 parameter selects which extension will be returned.
1442
1443 :param int index: The index of the extension to retrieve.
1444 :return: The extension at the specified index.
1445 :rtype: :py:class:`X509Extension`
1446 :raises IndexError: If the extension index was out of bounds.
1447
1448 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001449 """
1450 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001451 ext._extension = _lib.X509_get_ext(self._x509, index)
1452 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001453 raise IndexError("extension index out of bounds")
1454
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001455 extension = _lib.X509_EXTENSION_dup(ext._extension)
1456 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001457 return ext
1458
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001459
1460
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001461X509Type = X509
1462
1463
1464
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001465class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001466 """
1467 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001468 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001469 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001470 store = _lib.X509_STORE_new()
1471 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001472
1473
1474 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001475 """
1476 Adds the certificate :py:data:`cert` to this store.
1477
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001478 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001479
1480 :param X509 cert: The certificate to add to this store.
1481 :raises TypeError: If the certificate is not an :py:class:`X509`.
1482 :raises Error: If OpenSSL was unhappy with your certificate.
1483 :return: py:data:`None` if the certificate was added successfully.
1484 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001485 if not isinstance(cert, X509):
1486 raise TypeError()
1487
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001488 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001489 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001490 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001491
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001492
1493X509StoreType = X509Store
1494
1495
1496
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001497def load_certificate(type, buffer):
1498 """
1499 Load a certificate from a buffer
1500
1501 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1502
1503 :param buffer: The buffer the certificate is stored in
1504 :type buffer: :py:class:`bytes`
1505
1506 :return: The X509 object
1507 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001508 if isinstance(buffer, _text_type):
1509 buffer = buffer.encode("ascii")
1510
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001511 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001512
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001513 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001514 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001515 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001516 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001517 else:
1518 raise ValueError(
1519 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001520
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001521 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001522 _raise_current_error()
1523
1524 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001525 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001526 return cert
1527
1528
1529def dump_certificate(type, cert):
1530 """
1531 Dump a certificate to a buffer
1532
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001533 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1534 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001535 :param cert: The certificate to dump
1536 :return: The buffer with the dumped certificate in
1537 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001538 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001539
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001540 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001541 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001542 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001543 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001544 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001545 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001546 else:
1547 raise ValueError(
1548 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1549 "FILETYPE_TEXT")
1550
1551 return _bio_to_string(bio)
1552
1553
1554
1555def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1556 """
1557 Dump a private key to a buffer
1558
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001559 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1560 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001561 :param pkey: The PKey to dump
1562 :param cipher: (optional) if encrypted PEM format, the cipher to
1563 use
1564 :param passphrase: (optional) if encrypted PEM format, this can be either
1565 the passphrase to use, or a callback for providing the
1566 passphrase.
1567 :return: The buffer with the dumped key in
1568 :rtype: :py:data:`str`
1569 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001570 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001571
1572 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001573 if passphrase is None:
1574 raise TypeError(
1575 "if a value is given for cipher "
1576 "one must also be given for passphrase")
1577 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001578 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001579 raise ValueError("Invalid cipher name")
1580 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001581 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001582
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001583 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001584 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001585 result_code = _lib.PEM_write_bio_PrivateKey(
1586 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001587 helper.callback, helper.callback_args)
1588 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001589 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001590 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001591 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001592 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1593 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001594 # TODO RSA_free(rsa)?
1595 else:
1596 raise ValueError(
1597 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1598 "FILETYPE_TEXT")
1599
1600 if result_code == 0:
1601 _raise_current_error()
1602
1603 return _bio_to_string(bio)
1604
1605
1606
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001607def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001608 copy = _lib.X509_REVOKED_new()
1609 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001610 # TODO: This is untested.
1611 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001612
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001613 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001614 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001615 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001616
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001617 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001618 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001619 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001620
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001621 if original.extensions != _ffi.NULL:
1622 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1623 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1624 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1625 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1626 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001627 copy.extensions = extension_stack
1628
1629 copy.sequence = original.sequence
1630 return copy
1631
1632
1633
1634class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001635 """
1636 A certificate revocation.
1637 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001638 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1639 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1640 # OCSP_crl_reason_str. We use the latter, just like the command line
1641 # program.
1642 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001643 b"unspecified",
1644 b"keyCompromise",
1645 b"CACompromise",
1646 b"affiliationChanged",
1647 b"superseded",
1648 b"cessationOfOperation",
1649 b"certificateHold",
1650 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001651 ]
1652
1653 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001654 revoked = _lib.X509_REVOKED_new()
1655 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001656
1657
1658 def set_serial(self, hex_str):
1659 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001660 Set the serial number.
1661
1662 The serial number is formatted as a hexadecimal number encoded in
1663 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001664
1665 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001666 :type hex_str: :py:class:`bytes`
1667
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001668 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001669 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001670 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1671 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001672 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001673 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001674 if not bn_result:
1675 raise ValueError("bad hex string")
1676
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001677 asn1_serial = _ffi.gc(
1678 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1679 _lib.ASN1_INTEGER_free)
1680 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001681
1682
1683 def get_serial(self):
1684 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001685 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001686
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001687 The serial number is formatted as a hexadecimal number encoded in
1688 ASCII.
1689
1690 :return: The serial number.
1691 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001692 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001693 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001694
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001695 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001696 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001697 # TODO: This is untested.
1698 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001699
1700 return _bio_to_string(bio)
1701
1702
1703 def _delete_reason(self):
1704 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001705 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1706 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1707 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1708 _lib.X509_EXTENSION_free(ext)
1709 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001710 break
1711
1712
1713 def set_reason(self, reason):
1714 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001715 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001716
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001717 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001718
1719 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001720 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1721
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001722 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001723
1724 .. seealso::
1725
1726 :py:meth:`all_reasons`, which gives you a list of all supported
1727 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001728 """
1729 if reason is None:
1730 self._delete_reason()
1731 elif not isinstance(reason, bytes):
1732 raise TypeError("reason must be None or a byte string")
1733 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001734 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001735 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1736
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001737 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1738 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001739 # TODO: This is untested.
1740 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001741 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001742
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001743 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1744 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001745 # TODO: This is untested.
1746 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001747
1748 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001749 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1750 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001751
1752 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001753 # TODO: This is untested.
1754 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001755
1756
1757 def get_reason(self):
1758 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001759 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001760
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001761 :return: The reason, or :py:const:`None` if there is none.
1762 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1763
1764 .. seealso::
1765
1766 :py:meth:`all_reasons`, which gives you a list of all supported
1767 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001768 """
1769 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001770 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1771 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1772 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001773 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001774
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001775 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001776 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001777 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001778 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001779 # TODO: This is untested.
1780 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001781
1782 return _bio_to_string(bio)
1783
1784
1785 def all_reasons(self):
1786 """
1787 Return a list of all the supported reason strings.
1788
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001789 This list is a copy; modifying it does not change the supported reason
1790 strings.
1791
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001792 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001793 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001794 """
1795 return self._crl_reasons[:]
1796
1797
1798 def set_rev_date(self, when):
1799 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001800 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001801
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001802 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1803 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001804 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001805 """
1806 return _set_asn1_time(self._revoked.revocationDate, when)
1807
1808
1809 def get_rev_date(self):
1810 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001811 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001812
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001813 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1814 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001815 """
1816 return _get_asn1_time(self._revoked.revocationDate)
1817
1818
1819
1820class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001821 """
1822 A certificate revocation list.
1823 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001824 def __init__(self):
1825 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001826 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001827 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001828 crl = _lib.X509_CRL_new()
1829 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001830
1831
1832 def get_revoked(self):
1833 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001834 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001835
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001836 These revocations will be provided by value, not by reference.
1837 That means it's okay to mutate them: it won't affect this CRL.
1838
1839 :return: The revocations in this CRL.
1840 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001841 """
1842 results = []
1843 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001844 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1845 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001846 revoked_copy = _X509_REVOKED_dup(revoked)
1847 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001848 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001849 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001850 if results:
1851 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001852
1853
1854 def add_revoked(self, revoked):
1855 """
1856 Add a revoked (by value not reference) to the CRL structure
1857
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001858 This revocation will be added by value, not by reference. That
1859 means it's okay to mutate it after adding: it won't affect
1860 this CRL.
1861
1862 :param revoked: The new revocation.
1863 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001864
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001865 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001866 """
1867 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001868 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001869 # TODO: This is untested.
1870 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001871
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001872 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001873 if add_result == 0:
1874 # TODO: This is untested.
1875 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001876
1877
1878 def export(self, cert, key, type=FILETYPE_PEM, days=100):
1879 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001880 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001881
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001882 :param cert: The certificate used to sign the CRL.
1883 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001884
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001885 :param key: The key used to sign the CRL.
1886 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001887
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001888 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1889 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001890
1891 :param days: The number of days until the next update of this CRL.
1892 :type days: :py:data:`int`
1893
1894 :return: :py:data:`str`
1895 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001896 if not isinstance(cert, X509):
1897 raise TypeError("cert must be an X509 instance")
1898 if not isinstance(key, PKey):
1899 raise TypeError("key must be a PKey instance")
1900 if not isinstance(type, int):
1901 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001902
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001903 bio = _lib.BIO_new(_lib.BIO_s_mem())
1904 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001905 # TODO: This is untested.
1906 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001907
1908 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001909 sometime = _lib.ASN1_TIME_new()
1910 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001911 # TODO: This is untested.
1912 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001913
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001914 _lib.X509_gmtime_adj(sometime, 0)
1915 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001916
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001917 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1918 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001919
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001920 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001921
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001922 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, _lib.EVP_md5())
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001923 if not sign_result:
1924 _raise_current_error()
1925
1926 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001927 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001928 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001929 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001930 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001931 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001932 else:
1933 raise ValueError(
1934 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1935
1936 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001937 # TODO: This is untested.
1938 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001939
1940 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001941CRLType = CRL
1942
1943
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001944
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001945class PKCS7(object):
1946 def type_is_signed(self):
1947 """
1948 Check if this NID_pkcs7_signed object
1949
1950 :return: True if the PKCS7 is of type signed
1951 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001952 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001953 return True
1954 return False
1955
1956
1957 def type_is_enveloped(self):
1958 """
1959 Check if this NID_pkcs7_enveloped object
1960
1961 :returns: True if the PKCS7 is of type enveloped
1962 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001963 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001964 return True
1965 return False
1966
1967
1968 def type_is_signedAndEnveloped(self):
1969 """
1970 Check if this NID_pkcs7_signedAndEnveloped object
1971
1972 :returns: True if the PKCS7 is of type signedAndEnveloped
1973 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001974 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001975 return True
1976 return False
1977
1978
1979 def type_is_data(self):
1980 """
1981 Check if this NID_pkcs7_data object
1982
1983 :return: True if the PKCS7 is of type data
1984 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001985 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001986 return True
1987 return False
1988
1989
1990 def get_type_name(self):
1991 """
1992 Returns the type name of the PKCS7 structure
1993
1994 :return: A string with the typename
1995 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001996 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1997 string_type = _lib.OBJ_nid2sn(nid)
1998 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001999
2000PKCS7Type = PKCS7
2001
2002
2003
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002004class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002005 """
2006 A PKCS #12 archive.
2007 """
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002008 def __init__(self):
2009 self._pkey = None
2010 self._cert = None
2011 self._cacerts = None
2012 self._friendlyname = None
2013
2014
2015 def get_certificate(self):
2016 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002017 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002018
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002019 :return: The certificate, or :py:const:`None` if there is none.
2020 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002021 """
2022 return self._cert
2023
2024
2025 def set_certificate(self, cert):
2026 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002027 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002028
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002029 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002030 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002031
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002032 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002033 """
2034 if not isinstance(cert, X509):
2035 raise TypeError("cert must be an X509 instance")
2036 self._cert = cert
2037
2038
2039 def get_privatekey(self):
2040 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002041 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002042
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002043 :return: The private key, or :py:const:`None` if there is none.
2044 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002045 """
2046 return self._pkey
2047
2048
2049 def set_privatekey(self, pkey):
2050 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002051 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002052
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002053 :param pkey: The new private key, or :py:const:`None` to unset it.
2054 :type pkey: :py:class:`PKey` or :py:const:`None`
2055
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002056 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002057 """
2058 if not isinstance(pkey, PKey):
2059 raise TypeError("pkey must be a PKey instance")
2060 self._pkey = pkey
2061
2062
2063 def get_ca_certificates(self):
2064 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002065 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002066
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002067 :return: A tuple with the CA certificates in the chain, or
2068 :py:const:`None` if there are none.
2069 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002070 """
2071 if self._cacerts is not None:
2072 return tuple(self._cacerts)
2073
2074
2075 def set_ca_certificates(self, cacerts):
2076 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002077 Set the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002078
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002079 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2080 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002081 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002082
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002083 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002084 """
2085 if cacerts is None:
2086 self._cacerts = None
2087 else:
2088 cacerts = list(cacerts)
2089 for cert in cacerts:
2090 if not isinstance(cert, X509):
2091 raise TypeError("iterable must only contain X509 instances")
2092 self._cacerts = cacerts
2093
2094
2095 def set_friendlyname(self, name):
2096 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002097 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002098
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002099 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002100 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002101
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002102 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002103 """
2104 if name is None:
2105 self._friendlyname = None
2106 elif not isinstance(name, bytes):
2107 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2108 self._friendlyname = name
2109
2110
2111 def get_friendlyname(self):
2112 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002113 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002114
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002115 :returns: The friendly name, or :py:const:`None` if there is none.
2116 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002117 """
2118 return self._friendlyname
2119
2120
2121 def export(self, passphrase=None, iter=2048, maciter=1):
2122 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002123 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002124
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002125 For more information, see the :c:func:`PKCS12_create` man page.
2126
2127 :param passphrase: The passphrase used to encrypt the structure. Unlike
2128 some other passphrase arguments, this *must* be a string, not a
2129 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002130 :type passphrase: :py:data:`bytes`
2131
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002132 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002133 :type iter: :py:data:`int`
2134
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002135 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002136 :type maciter: :py:data:`int`
2137
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002138 :return: The string representation of the PKCS #12 structure.
2139 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002140 """
2141 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002142 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002143 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002144 cacerts = _lib.sk_X509_new_null()
2145 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002146 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002147 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002148
2149 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002150 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002151
2152 friendlyname = self._friendlyname
2153 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002154 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002155
2156 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002157 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002158 else:
2159 pkey = self._pkey._pkey
2160
2161 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002162 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002163 else:
2164 cert = self._cert._x509
2165
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002166 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002167 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002168 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2169 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002170 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002171 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002172 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002173 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002174
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002175 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002176 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002177 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002178
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002179
2180
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002181PKCS12Type = PKCS12
2182
2183
2184
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002185class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002186 """
2187 A Netscape SPKI object.
2188 """
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002189 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002190 spki = _lib.NETSCAPE_SPKI_new()
2191 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002192
2193
2194 def sign(self, pkey, digest):
2195 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002196 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002197
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002198 :param pkey: The private key to sign with.
2199 :type pkey: :py:class:`PKey`
2200
2201 :param digest: The message digest to use.
2202 :type digest: :py:class:`bytes`
2203
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002204 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002205 """
2206 if pkey._only_public:
2207 raise ValueError("Key has only public part")
2208
2209 if not pkey._initialized:
2210 raise ValueError("Key is uninitialized")
2211
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002212 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002213 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002214 raise ValueError("No such digest method")
2215
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002216 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002217 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002218 # TODO: This is untested.
2219 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002220
2221
2222 def verify(self, key):
2223 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002224 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002225
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002226 :param key: The public key that signature is supposedly from.
2227 :type pkey: :py:class:`PKey`
2228
2229 :return: :py:const:`True` if the signature is correct.
2230 :rtype: :py:class:`bool`
2231
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002232 :raises Error: If the signature is invalid, or there was a problem
2233 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002234 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002235 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002236 if answer <= 0:
2237 _raise_current_error()
2238 return True
2239
2240
2241 def b64_encode(self):
2242 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002243 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002244
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002245 :return: The base64 encoded string.
2246 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002247 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002248 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2249 result = _ffi.string(encoded)
2250 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002251 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002252
2253
2254 def get_pubkey(self):
2255 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002256 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002257
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002258 :return: The public key.
2259 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002260 """
2261 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002262 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2263 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002264 # TODO: This is untested.
2265 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002266 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002267 pkey._only_public = True
2268 return pkey
2269
2270
2271 def set_pubkey(self, pkey):
2272 """
2273 Set the public key of the certificate
2274
2275 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002276 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002277 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002278 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002279 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002280 # TODO: This is untested.
2281 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002282
2283
2284
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002285NetscapeSPKIType = NetscapeSPKI
2286
2287
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002288
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002289class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002290 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002291 if type != FILETYPE_PEM and passphrase is not None:
2292 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002293 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002294 self._more_args = more_args
2295 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002296 self._problems = []
2297
2298
2299 @property
2300 def callback(self):
2301 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002302 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002303 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002304 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002305 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002306 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002307 else:
2308 raise TypeError("Last argument must be string or callable")
2309
2310
2311 @property
2312 def callback_args(self):
2313 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002314 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002315 elif isinstance(self._passphrase, bytes):
2316 return self._passphrase
2317 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002318 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002319 else:
2320 raise TypeError("Last argument must be string or callable")
2321
2322
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002323 def raise_if_problem(self, exceptionType=Error):
2324 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002325 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002326 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002327 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002328 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002329 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002330 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002331
2332
2333 def _read_passphrase(self, buf, size, rwflag, userdata):
2334 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002335 if self._more_args:
2336 result = self._passphrase(size, rwflag, userdata)
2337 else:
2338 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002339 if not isinstance(result, bytes):
2340 raise ValueError("String expected")
2341 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002342 if self._truncate:
2343 result = result[:size]
2344 else:
2345 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002346 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002347 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002348 return len(result)
2349 except Exception as e:
2350 self._problems.append(e)
2351 return 0
2352
2353
2354
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002355def load_privatekey(type, buffer, passphrase=None):
2356 """
2357 Load a private key from a buffer
2358
2359 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2360 :param buffer: The buffer the key is stored in
2361 :param passphrase: (optional) if encrypted PEM format, this can be
2362 either the passphrase to use, or a callback for
2363 providing the passphrase.
2364
2365 :return: The PKey object
2366 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002367 if isinstance(buffer, _text_type):
2368 buffer = buffer.encode("ascii")
2369
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002370 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002371
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002372 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002373 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002374 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2375 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002376 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002377 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002378 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002379 else:
2380 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2381
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002382 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002383 _raise_current_error()
2384
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002385 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002386 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002387 return pkey
2388
2389
2390
2391def dump_certificate_request(type, req):
2392 """
2393 Dump a certificate request to a buffer
2394
2395 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2396 :param req: The certificate request to dump
2397 :return: The buffer with the dumped certificate request in
2398 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002399 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002400
2401 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002402 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002403 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002404 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002405 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002406 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002407 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002408 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002409
2410 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002411 # TODO: This is untested.
2412 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002413
2414 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002415
2416
2417
2418def load_certificate_request(type, buffer):
2419 """
2420 Load a certificate request from a buffer
2421
2422 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2423 :param buffer: The buffer the certificate request is stored in
2424 :return: The X509Req object
2425 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002426 if isinstance(buffer, _text_type):
2427 buffer = buffer.encode("ascii")
2428
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002429 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002430
2431 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002432 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002433 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002434 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002435 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002436 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002437
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002438 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002439 # TODO: This is untested.
2440 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002441
2442 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002443 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002444 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002445
2446
2447
2448def sign(pkey, data, digest):
2449 """
2450 Sign data with a digest
2451
2452 :param pkey: Pkey to sign with
2453 :param data: data to be signed
2454 :param digest: message digest to use
2455 :return: signature
2456 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002457 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002458 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002459 raise ValueError("No such digest method")
2460
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002461 md_ctx = _ffi.new("EVP_MD_CTX*")
2462 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002463
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002464 _lib.EVP_SignInit(md_ctx, digest_obj)
2465 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002466
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002467 signature_buffer = _ffi.new("unsigned char[]", 512)
2468 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002469 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002470 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002471 md_ctx, signature_buffer, signature_length, pkey._pkey)
2472
2473 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002474 # TODO: This is untested.
2475 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002476
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002477 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002478
2479
2480
2481def verify(cert, signature, data, digest):
2482 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002483 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002484
2485 :param cert: signing certificate (X509 object)
2486 :param signature: signature returned by sign function
2487 :param data: data to be verified
2488 :param digest: message digest to use
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002489 :return: :py:const:`None` if the signature is correct, raise exception otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002490 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002491 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002492 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002493 raise ValueError("No such digest method")
2494
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002495 pkey = _lib.X509_get_pubkey(cert._x509)
2496 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002497 # TODO: This is untested.
2498 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002499 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002500
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002501 md_ctx = _ffi.new("EVP_MD_CTX*")
2502 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002503
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002504 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2505 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2506 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002507
2508 if verify_result != 1:
2509 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002510
2511
2512
2513def load_crl(type, buffer):
2514 """
2515 Load a certificate revocation list from a buffer
2516
2517 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2518 :param buffer: The buffer the CRL is stored in
2519
2520 :return: The PKey object
2521 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002522 if isinstance(buffer, _text_type):
2523 buffer = buffer.encode("ascii")
2524
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002525 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002526
2527 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002528 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002529 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002530 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002531 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002532 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2533
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002534 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002535 _raise_current_error()
2536
2537 result = CRL.__new__(CRL)
2538 result._crl = crl
2539 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002540
2541
2542
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002543def load_pkcs7_data(type, buffer):
2544 """
2545 Load pkcs7 data from a buffer
2546
2547 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2548 :param buffer: The buffer with the pkcs7 data.
2549 :return: The PKCS7 object
2550 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002551 if isinstance(buffer, _text_type):
2552 buffer = buffer.encode("ascii")
2553
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002554 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002555
2556 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002557 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002558 elif type == FILETYPE_ASN1:
2559 pass
2560 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002561 # TODO: This is untested.
2562 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002563 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2564
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002565 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002566 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002567
2568 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002569 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002570 return pypkcs7
2571
2572
2573
Stephen Holsapple38482622014-04-05 20:29:34 -07002574def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002575 """
2576 Load a PKCS12 object from a buffer
2577
2578 :param buffer: The buffer the certificate is stored in
2579 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2580 :returns: The PKCS12 object
2581 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002582 if isinstance(buffer, _text_type):
2583 buffer = buffer.encode("ascii")
2584
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002585 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002586
Stephen Holsapple38482622014-04-05 20:29:34 -07002587 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2588 # password based encryption no password and a zero length password are two
2589 # different things, but OpenSSL implementation will try both to figure out
2590 # which one works.
2591 if not passphrase:
2592 passphrase = _ffi.NULL
2593
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002594 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2595 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002596 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002597 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002598
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002599 pkey = _ffi.new("EVP_PKEY**")
2600 cert = _ffi.new("X509**")
2601 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002602
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002603 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002604 if not parse_result:
2605 _raise_current_error()
2606
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002607 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002608
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002609 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2610 # queue for no particular reason. This error isn't interesting to anyone
2611 # outside this function. It's not even interesting to us. Get rid of it.
2612 try:
2613 _raise_current_error()
2614 except Error:
2615 pass
2616
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002617 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002618 pykey = None
2619 else:
2620 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002621 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002622
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002623 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002624 pycert = None
2625 friendlyname = None
2626 else:
2627 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002628 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002629
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002630 friendlyname_length = _ffi.new("int*")
2631 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2632 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2633 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002634 friendlyname = None
2635
2636 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002637 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002638 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002639 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002640 pycacerts.append(pycacert)
2641 if not pycacerts:
2642 pycacerts = None
2643
2644 pkcs12 = PKCS12.__new__(PKCS12)
2645 pkcs12._pkey = pykey
2646 pkcs12._cert = pycert
2647 pkcs12._cacerts = pycacerts
2648 pkcs12._friendlyname = friendlyname
2649 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002650
2651
2652def _initialize_openssl_threads(get_ident, Lock):
2653 import _ssl
2654 return
2655
2656 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2657
2658 def locking_function(mode, index, filename, line):
2659 if mode & _lib.CRYPTO_LOCK:
2660 locks[index].acquire()
2661 else:
2662 locks[index].release()
2663
2664 _lib.CRYPTO_set_id_callback(
2665 _ffi.callback("unsigned long (*)(void)", get_ident))
2666
2667 _lib.CRYPTO_set_locking_callback(
2668 _ffi.callback(
2669 "void (*)(int, int, const char*, int)", locking_function))
2670
2671
2672try:
2673 from thread import get_ident
2674 from threading import Lock
2675except ImportError:
2676 pass
2677else:
2678 _initialize_openssl_threads(get_ident, Lock)
2679 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002680
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002681# There are no direct unit tests for this initialization. It is tested
2682# indirectly since it is necessary for functions like dump_privatekey when
2683# using encryption.
2684#
2685# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2686# and some other similar tests may fail without this (though they may not if
2687# the Python runtime has already done some initialization of the underlying
2688# OpenSSL library (and is linked against the same one that cryptography is
2689# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002690_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002691
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002692# This is similar but exercised mainly by exception_from_error_queue. It calls
2693# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2694_lib.SSL_load_error_strings()