blob: 1b1058eda126199fd03ddab8b848d54a2f595ffc [file] [log] [blame]
Jeff Tangfc18f7b2015-04-15 17:42:33 -04001from time import time, strptime
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002from base64 import b16encode
Jeff Tangfc18f7b2015-04-15 17:42:33 -04003from calendar import timegm
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05004from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05005from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04006from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05007
8from six import (
9 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -040010 text_type as _text_type,
11 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080012
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050013from OpenSSL._util import (
14 ffi as _ffi,
15 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050016 exception_from_error_queue as _exception_from_error_queue,
17 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040018 native as _native,
19 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040020 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040021)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080022
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050023FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
24FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080025
26# TODO This was an API mistake. OpenSSL has no such constant.
27FILETYPE_TEXT = 2 ** 16 - 1
28
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050029TYPE_RSA = _lib.EVP_PKEY_RSA
30TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080031
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080032
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070033
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050034class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050035 """
36 An error occurred in an `OpenSSL.crypto` API.
37 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050038
39
40_raise_current_error = partial(_exception_from_error_queue, Error)
41
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070042
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050043
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050044def _untested_error(where):
45 """
46 An OpenSSL API failed somehow. Additionally, the failure which was
47 encountered isn't one that's exercised by the test suite so future behavior
48 of pyOpenSSL is now somewhat less predictable.
49 """
50 raise RuntimeError("Unknown %s failure" % (where,))
51
52
53
54def _new_mem_buf(buffer=None):
55 """
56 Allocate a new OpenSSL memory BIO.
57
58 Arrange for the garbage collector to clean it up automatically.
59
60 :param buffer: None or some bytes to use to put into the BIO so that they
61 can be read out.
62 """
63 if buffer is None:
64 bio = _lib.BIO_new(_lib.BIO_s_mem())
65 free = _lib.BIO_free
66 else:
67 data = _ffi.new("char[]", buffer)
68 bio = _lib.BIO_new_mem_buf(data, len(buffer))
69 # Keep the memory alive as long as the bio is alive!
70 def free(bio, ref=data):
71 return _lib.BIO_free(bio)
72
73 if bio == _ffi.NULL:
74 # TODO: This is untested.
75 _raise_current_error()
76
77 bio = _ffi.gc(bio, free)
78 return bio
79
80
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050081
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080082def _bio_to_string(bio):
83 """
84 Copy the contents of an OpenSSL BIO object into a Python byte string.
85 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050086 result_buffer = _ffi.new('char**')
87 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
88 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080089
90
91
Jean-Paul Calderone57122982013-02-21 08:47:05 -080092def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050093 """
94 The the time value of an ASN1 time object.
95
96 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
97 castable to that type) which will have its value set.
98 @param when: A string representation of the desired time value.
99
100 @raise TypeError: If C{when} is not a L{bytes} string.
101 @raise ValueError: If C{when} does not represent a time in the required
102 format.
103 @raise RuntimeError: If the time value cannot be set for some other
104 (unspecified) reason.
105 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800106 if not isinstance(when, bytes):
107 raise TypeError("when must be a byte string")
108
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500109 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
110 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800111 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500112 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
113 _lib.ASN1_STRING_set(dummy, when, len(when))
114 check_result = _lib.ASN1_GENERALIZEDTIME_check(
115 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800116 if not check_result:
117 raise ValueError("Invalid string")
118 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500119 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800120
121
122
123def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500124 """
125 Retrieve the time value of an ASN1 time object.
126
127 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
128 that type) from which the time value will be retrieved.
129
130 @return: The time value from C{timestamp} as a L{bytes} string in a certain
131 format. Or C{None} if the object contains no time value.
132 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500133 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
134 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800135 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500136 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
137 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800138 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500139 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
140 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
141 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500142 # This may happen:
143 # - if timestamp was not an ASN1_TIME
144 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
145 # - if a copy of the time data from timestamp cannot be made for
146 # the newly allocated ASN1_GENERALIZEDTIME
147 #
148 # These are difficult to test. cffi enforces the ASN1_TIME type.
149 # Memory allocation failures are a pain to trigger
150 # deterministically.
151 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800152 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500153 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800154 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500155 string_data = _lib.ASN1_STRING_data(string_timestamp)
156 string_result = _ffi.string(string_data)
157 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800158 return string_result
159
160
161
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800162class PKey(object):
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800163 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800164 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800165
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800166 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500167 pkey = _lib.EVP_PKEY_new()
168 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800169 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800170
171
172 def generate_key(self, type, bits):
173 """
174 Generate a key of a given type, with a given number of a bits
175
176 :param type: The key type (TYPE_RSA or TYPE_DSA)
177 :param bits: The number of bits
178
179 :return: None
180 """
181 if not isinstance(type, int):
182 raise TypeError("type must be an integer")
183
184 if not isinstance(bits, int):
185 raise TypeError("bits must be an integer")
186
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800187 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500188 exponent = _lib.BN_new()
189 exponent = _ffi.gc(exponent, _lib.BN_free)
190 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800191
192 if type == TYPE_RSA:
193 if bits <= 0:
194 raise ValueError("Invalid number of bits")
195
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500196 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800197
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500198 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500199 if result == 0:
200 # TODO: The test for this case is commented out. Different
201 # builds of OpenSSL appear to have different failure modes that
202 # make it hard to test. Visual inspection of the OpenSSL
203 # source reveals that a return value of 0 signals an error.
204 # Manual testing on a particular build of OpenSSL suggests that
205 # this is probably the appropriate way to handle those errors.
206 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800207
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500208 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800209 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500210 # TODO: It appears as though this can fail if an engine is in
211 # use which does not support RSA.
212 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800213
214 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500215 dsa = _lib.DSA_generate_parameters(
216 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
217 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500218 # TODO: This is untested.
219 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500220 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500221 # TODO: This is untested.
222 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500223 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500224 # TODO: This is untested.
225 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800226 else:
227 raise Error("No such key type")
228
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800229 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800230
231
232 def check(self):
233 """
234 Check the consistency of an RSA private key.
235
236 :return: True if key is consistent.
237 :raise Error: if the key is inconsistent.
238 :raise TypeError: if the key is of a type which cannot be checked.
239 Only RSA keys can currently be checked.
240 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800241 if self._only_public:
242 raise TypeError("public key only")
243
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500244 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800245 raise TypeError("key type unsupported")
246
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500247 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
248 rsa = _ffi.gc(rsa, _lib.RSA_free)
249 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800250 if result:
251 return True
252 _raise_current_error()
253
254
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800255 def type(self):
256 """
257 Returns the type of the key
258
259 :return: The type of the key.
260 """
261 return self._pkey.type
262
263
264 def bits(self):
265 """
266 Returns the number of bits of the key
267
268 :return: The number of bits of the key.
269 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500270 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800271PKeyType = PKey
272
273
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800274
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400275class _EllipticCurve(object):
276 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400277 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400278
279 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
280 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
281 instances each of which represents one curve supported by the system.
282 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400283 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400284 _curves = None
285
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400286 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400287 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400288 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400289 """
290 Implement cooperation with the right-hand side argument of ``!=``.
291
292 Python 3 seems to have dropped this cooperation in this very narrow
293 circumstance.
294 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400295 if isinstance(other, _EllipticCurve):
296 return super(_EllipticCurve, self).__ne__(other)
297 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400298
299
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400300 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400301 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400302 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400303 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400304
305 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400306
307 :return: A :py:type:`set` of ``cls`` instances giving the names of the
308 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400309 """
310 if lib.Cryptography_HAS_EC:
311 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
312 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
313 # The return value on this call should be num_curves again. We could
314 # check it to make sure but if it *isn't* then.. what could we do?
315 # Abort the whole process, I suppose...? -exarkun
316 lib.EC_get_builtin_curves(builtin_curves, num_curves)
317 return set(
318 cls.from_nid(lib, c.nid)
319 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400320 return set()
321
322
323 @classmethod
324 def _get_elliptic_curves(cls, lib):
325 """
326 Get, cache, and return the curves supported by OpenSSL.
327
328 :param lib: The OpenSSL library binding object.
329
330 :return: A :py:type:`set` of ``cls`` instances giving the names of the
331 elliptic curves the underlying library supports.
332 """
333 if cls._curves is None:
334 cls._curves = cls._load_elliptic_curves(lib)
335 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400336
337
338 @classmethod
339 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400340 """
341 Instantiate a new :py:class:`_EllipticCurve` associated with the given
342 OpenSSL NID.
343
344 :param lib: The OpenSSL library binding object.
345
346 :param nid: The OpenSSL NID the resulting curve object will represent.
347 This must be a curve NID (and not, for example, a hash NID) or
348 subsequent operations will fail in unpredictable ways.
349 :type nid: :py:class:`int`
350
351 :return: The curve object.
352 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400353 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
354
355
356 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400357 """
358 :param _lib: The :py:mod:`cryptography` binding instance used to
359 interface with OpenSSL.
360
361 :param _nid: The OpenSSL NID identifying the curve this object
362 represents.
363 :type _nid: :py:class:`int`
364
365 :param name: The OpenSSL short name identifying the curve this object
366 represents.
367 :type name: :py:class:`unicode`
368 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400369 self._lib = lib
370 self._nid = nid
371 self.name = name
372
373
374 def __repr__(self):
375 return "<Curve %r>" % (self.name,)
376
377
378 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400379 """
380 Create a new OpenSSL EC_KEY structure initialized to use this curve.
381
382 The structure is automatically garbage collected when the Python object
383 is garbage collected.
384 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400385 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
386 return _ffi.gc(key, _lib.EC_KEY_free)
387
388
389
390def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400391 """
392 Return a set of objects representing the elliptic curves supported in the
393 OpenSSL build in use.
394
395 The curve objects have a :py:class:`unicode` ``name`` attribute by which
396 they identify themselves.
397
398 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400399 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
400 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400401 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400402 return _EllipticCurve._get_elliptic_curves(_lib)
403
404
405
406def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400407 """
408 Return a single curve object selected by name.
409
410 See :py:func:`get_elliptic_curves` for information about curve objects.
411
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400412 :param name: The OpenSSL short name identifying the curve object to
413 retrieve.
414 :type name: :py:class:`unicode`
415
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400416 If the named curve is not supported then :py:class:`ValueError` is raised.
417 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400418 for curve in get_elliptic_curves():
419 if curve.name == name:
420 return curve
421 raise ValueError("unknown curve name", name)
422
423
424
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800425class X509Name(object):
426 def __init__(self, name):
427 """
428 Create a new X509Name, copying the given X509Name instance.
429
430 :param name: An X509Name object to copy
431 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500432 name = _lib.X509_NAME_dup(name._name)
433 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800434
435
436 def __setattr__(self, name, value):
437 if name.startswith('_'):
438 return super(X509Name, self).__setattr__(name, value)
439
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800440 # Note: we really do not want str subclasses here, so we do not use
441 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800442 if type(name) is not str:
443 raise TypeError("attribute name must be string, not '%.200s'" % (
444 type(value).__name__,))
445
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500446 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500447 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800448 try:
449 _raise_current_error()
450 except Error:
451 pass
452 raise AttributeError("No such attribute")
453
454 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500455 for i in range(_lib.X509_NAME_entry_count(self._name)):
456 ent = _lib.X509_NAME_get_entry(self._name, i)
457 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
458 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800459 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500460 ent = _lib.X509_NAME_delete_entry(self._name, i)
461 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800462 break
463
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500464 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800465 value = value.encode('utf-8')
466
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500467 add_result = _lib.X509_NAME_add_entry_by_NID(
468 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800469 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500470 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800471
472
473 def __getattr__(self, name):
474 """
475 Find attribute. An X509Name object has the following attributes:
476 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
477 organization (alias O), organizationalUnit (alias OU), commonName (alias
478 CN) and more...
479 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500480 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500481 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800482 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
483 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
484 # push something onto the error queue. If we don't clean that up
485 # now, someone else will bump into it later and be quite confused.
486 # See lp#314814.
487 try:
488 _raise_current_error()
489 except Error:
490 pass
491 return super(X509Name, self).__getattr__(name)
492
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500493 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800494 if entry_index == -1:
495 return None
496
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500497 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
498 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800499
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500500 result_buffer = _ffi.new("unsigned char**")
501 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800502 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500503 # TODO: This is untested.
504 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800505
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700506 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500507 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700508 finally:
509 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500510 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800511 return result
512
513
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500514 def _cmp(op):
515 def f(self, other):
516 if not isinstance(other, X509Name):
517 return NotImplemented
518 result = _lib.X509_NAME_cmp(self._name, other._name)
519 return op(result, 0)
520 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800521
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500522 __eq__ = _cmp(__eq__)
523 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800524
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500525 __lt__ = _cmp(__lt__)
526 __le__ = _cmp(__le__)
527
528 __gt__ = _cmp(__gt__)
529 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800530
531 def __repr__(self):
532 """
533 String representation of an X509Name
534 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500535 result_buffer = _ffi.new("char[]", 512);
536 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800537 self._name, result_buffer, len(result_buffer))
538
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500539 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500540 # TODO: This is untested.
541 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800542
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500543 return "<X509Name object '%s'>" % (
544 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800545
546
547 def hash(self):
548 """
549 Return the hash value of this name
550
551 :return: None
552 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500553 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800554
555
556 def der(self):
557 """
558 Return the DER encoding of this name
559
560 :return: A :py:class:`bytes` instance giving the DER encoded form of
561 this name.
562 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500563 result_buffer = _ffi.new('unsigned char**')
564 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800565 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500566 # TODO: This is untested.
567 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800568
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500569 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
570 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800571 return string_result
572
573
574 def get_components(self):
575 """
576 Returns the split-up components of this name.
577
578 :return: List of tuples (name, value).
579 """
580 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500581 for i in range(_lib.X509_NAME_entry_count(self._name)):
582 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800583
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500584 fname = _lib.X509_NAME_ENTRY_get_object(ent)
585 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800586
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500587 nid = _lib.OBJ_obj2nid(fname)
588 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800589
590 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500591 _ffi.string(name),
592 _ffi.string(
593 _lib.ASN1_STRING_data(fval),
594 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800595
596 return result
597X509NameType = X509Name
598
599
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800600class X509Extension(object):
601 def __init__(self, type_name, critical, value, subject=None, issuer=None):
602 """
603 :param typename: The name of the extension to create.
604 :type typename: :py:data:`str`
605
606 :param critical: A flag indicating whether this is a critical extension.
607
608 :param value: The value of the extension.
609 :type value: :py:data:`str`
610
611 :param subject: Optional X509 cert to use as subject.
612 :type subject: :py:class:`X509`
613
614 :param issuer: Optional X509 cert to use as issuer.
615 :type issuer: :py:class:`X509`
616
617 :return: The X509Extension object
618 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500619 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800620
621 # A context is necessary for any extension which uses the r2i conversion
622 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
623 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500624 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800625
626 # We have no configuration database - but perhaps we should (some
627 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500628 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800629
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800630 # Initialize the subject and issuer, if appropriate. ctx is a local,
631 # and as far as I can tell none of the X509V3_* APIs invoked here steal
632 # any references, so no need to mess with reference counts or duplicates.
633 if issuer is not None:
634 if not isinstance(issuer, X509):
635 raise TypeError("issuer must be an X509 instance")
636 ctx.issuer_cert = issuer._x509
637 if subject is not None:
638 if not isinstance(subject, X509):
639 raise TypeError("subject must be an X509 instance")
640 ctx.subject_cert = subject._x509
641
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800642 if critical:
643 # There are other OpenSSL APIs which would let us pass in critical
644 # separately, but they're harder to use, and since value is already
645 # a pile of crappy junk smuggling a ton of utterly important
646 # structured data, what's the point of trying to avoid nasty stuff
647 # with strings? (However, X509V3_EXT_i2d in particular seems like it
648 # would be a better API to invoke. I do not know where to get the
649 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500650 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800651
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500652 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
653 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800654 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500655 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800656
657
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400658 @property
659 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500660 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400661
662 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500663 _lib.GEN_EMAIL: "email",
664 _lib.GEN_DNS: "DNS",
665 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400666 }
667
668 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500669 method = _lib.X509V3_EXT_get(self._extension)
670 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500671 # TODO: This is untested.
672 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400673 payload = self._extension.value.data
674 length = self._extension.value.length
675
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500676 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400677 payloadptr[0] = payload
678
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500679 if method.it != _ffi.NULL:
680 ptr = _lib.ASN1_ITEM_ptr(method.it)
681 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
682 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400683 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500684 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400685 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500686 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400687
688 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500689 for i in range(_lib.sk_GENERAL_NAME_num(names)):
690 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400691 try:
692 label = self._prefixes[name.type]
693 except KeyError:
694 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500695 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500696 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400697 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500698 value = _native(
699 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
700 parts.append(label + ":" + value)
701 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400702
703
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800704 def __str__(self):
705 """
706 :return: a nice text representation of the extension
707 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500708 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400709 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800710
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400711 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500712 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800713 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500714 # TODO: This is untested.
715 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800716
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500717 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800718
719
720 def get_critical(self):
721 """
722 Returns the critical field of the X509Extension
723
724 :return: The critical field.
725 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500726 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800727
728
729 def get_short_name(self):
730 """
731 Returns the short version of the type name of the X509Extension
732
733 :return: The short type name.
734 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500735 obj = _lib.X509_EXTENSION_get_object(self._extension)
736 nid = _lib.OBJ_obj2nid(obj)
737 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800738
739
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800740 def get_data(self):
741 """
742 Returns the data of the X509Extension
743
744 :return: A :py:data:`str` giving the X509Extension's ASN.1 encoded data.
745 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500746 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
747 string_result = _ffi.cast('ASN1_STRING*', octet_result)
748 char_result = _lib.ASN1_STRING_data(string_result)
749 result_length = _lib.ASN1_STRING_length(string_result)
750 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800751
752X509ExtensionType = X509Extension
753
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800754
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800755class X509Req(object):
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800756 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500757 req = _lib.X509_REQ_new()
758 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800759
760
761 def set_pubkey(self, pkey):
762 """
763 Set the public key of the certificate request
764
765 :param pkey: The public key to use
766 :return: None
767 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500768 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800769 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500770 # TODO: This is untested.
771 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800772
773
774 def get_pubkey(self):
775 """
776 Get the public key from the certificate request
777
778 :return: The public key
779 """
780 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500781 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
782 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500783 # TODO: This is untested.
784 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500785 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800786 pkey._only_public = True
787 return pkey
788
789
790 def set_version(self, version):
791 """
792 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
793 request.
794
795 :param version: The version number
796 :return: None
797 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500798 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800799 if not set_result:
800 _raise_current_error()
801
802
803 def get_version(self):
804 """
805 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
806 request.
807
808 :return: an integer giving the value of the version subfield
809 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500810 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811
812
813 def get_subject(self):
814 """
815 Create an X509Name object for the subject of the certificate request
816
817 :return: An X509Name object
818 """
819 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500820 name._name = _lib.X509_REQ_get_subject_name(self._req)
821 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500822 # TODO: This is untested.
823 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800824
825 # The name is owned by the X509Req structure. As long as the X509Name
826 # Python object is alive, keep the X509Req Python object alive.
827 name._owner = self
828
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800829 return name
830
831
832 def add_extensions(self, extensions):
833 """
834 Add extensions to the request.
835
836 :param extensions: a sequence of X509Extension objects
837 :return: None
838 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500839 stack = _lib.sk_X509_EXTENSION_new_null()
840 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500841 # TODO: This is untested.
842 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800843
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500844 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800845
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800846 for ext in extensions:
847 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800848 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800849
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800850 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500851 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800852
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500853 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500855 # TODO: This is untested.
856 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800857
858
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800859 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800860 """
861 Get extensions to the request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800862
Jean-Paul Calderoneda3e6c62014-03-02 08:06:11 -0500863 :return: A :py:class:`list` of :py:class:`X509Extension` objects.
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800864 """
865 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500866 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500867 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800868 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500869 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800870 exts.append(ext)
871 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800872
873
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800874 def sign(self, pkey, digest):
875 """
876 Sign the certificate request using the supplied key and digest
877
878 :param pkey: The key to sign with
879 :param digest: The message digest to use
880 :return: None
881 """
882 if pkey._only_public:
883 raise ValueError("Key has only public part")
884
885 if not pkey._initialized:
886 raise ValueError("Key is uninitialized")
887
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500888 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500889 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800890 raise ValueError("No such digest method")
891
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500892 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800893 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500894 # TODO: This is untested.
895 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800896
897
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800898 def verify(self, pkey):
899 """
900 Verifies a certificate request using the supplied public key
901
902 :param key: a public key
903 :return: True if the signature is correct.
904
905 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
906 problem verifying the signature.
907 """
908 if not isinstance(pkey, PKey):
909 raise TypeError("pkey must be a PKey instance")
910
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500911 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800912 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500913 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800914
915 return result
916
917
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800918X509ReqType = X509Req
919
920
921
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800922class X509(object):
923 def __init__(self):
924 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500925 x509 = _lib.X509_new()
926 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800927
928
929 def set_version(self, version):
930 """
931 Set version number of the certificate
932
933 :param version: The version number
934 :type version: :py:class:`int`
935
936 :return: None
937 """
938 if not isinstance(version, int):
939 raise TypeError("version must be an integer")
940
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500941 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800942
943
944 def get_version(self):
945 """
946 Return version number of the certificate
947
948 :return: Version number as a Python integer
949 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500950 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800951
952
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800953 def get_pubkey(self):
954 """
955 Get the public key of the certificate
956
957 :return: The public key
958 """
959 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500960 pkey._pkey = _lib.X509_get_pubkey(self._x509)
961 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800962 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500963 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800964 pkey._only_public = True
965 return pkey
966
967
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800968 def set_pubkey(self, pkey):
969 """
970 Set the public key of the certificate
971
972 :param pkey: The public key
973
974 :return: None
975 """
976 if not isinstance(pkey, PKey):
977 raise TypeError("pkey must be a PKey instance")
978
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500979 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800980 if not set_result:
981 _raise_current_error()
982
983
984 def sign(self, pkey, digest):
985 """
986 Sign the certificate using the supplied key and digest
987
988 :param pkey: The key to sign with
989 :param digest: The message digest to use
990 :return: None
991 """
992 if not isinstance(pkey, PKey):
993 raise TypeError("pkey must be a PKey instance")
994
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800995 if pkey._only_public:
996 raise ValueError("Key only has public part")
997
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800998 if not pkey._initialized:
999 raise ValueError("Key is uninitialized")
1000
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001001 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001002 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001003 raise ValueError("No such digest method")
1004
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001005 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001006 if not sign_result:
1007 _raise_current_error()
1008
1009
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001010 def get_signature_algorithm(self):
1011 """
1012 Retrieve the signature algorithm used in the certificate
1013
1014 :return: A byte string giving the name of the signature algorithm used in
1015 the certificate.
1016 :raise ValueError: If the signature algorithm is undefined.
1017 """
1018 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001019 nid = _lib.OBJ_obj2nid(alg)
1020 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001021 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001022 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001023
1024
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001025 def digest(self, digest_name):
1026 """
1027 Return the digest of the X509 object.
1028
1029 :param digest_name: The name of the digest algorithm to use.
1030 :type digest_name: :py:class:`bytes`
1031
1032 :return: The digest of the object
1033 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001034 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001035 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001036 raise ValueError("No such digest method")
1037
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001038 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1039 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001040 result_length[0] = len(result_buffer)
1041
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001042 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001043 self._x509, digest, result_buffer, result_length)
1044
1045 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001046 # TODO: This is untested.
1047 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001048
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001049 return b":".join([
1050 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001051 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001052
1053
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001054 def subject_name_hash(self):
1055 """
1056 Return the hash of the X509 subject.
1057
1058 :return: The hash of the subject.
1059 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001060 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001061
1062
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001063 def set_serial_number(self, serial):
1064 """
1065 Set serial number of the certificate
1066
1067 :param serial: The serial number
1068 :type serial: :py:class:`int`
1069
1070 :return: None
1071 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001072 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001073 raise TypeError("serial must be an integer")
1074
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001075 hex_serial = hex(serial)[2:]
1076 if not isinstance(hex_serial, bytes):
1077 hex_serial = hex_serial.encode('ascii')
1078
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001079 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001080
1081 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1082 # it. If bignum is still NULL after this call, then the return value is
1083 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001084 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001085
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001086 if bignum_serial[0] == _ffi.NULL:
1087 set_result = _lib.ASN1_INTEGER_set(
1088 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001089 if set_result:
1090 # TODO Not tested
1091 _raise_current_error()
1092 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001093 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1094 _lib.BN_free(bignum_serial[0])
1095 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001096 # TODO Not tested
1097 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001098 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1099 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001100 if not set_result:
1101 # TODO Not tested
1102 _raise_current_error()
1103
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001104
1105 def get_serial_number(self):
1106 """
1107 Return serial number of the certificate
1108
1109 :return: Serial number as a Python integer
1110 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001111 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1112 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001113 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001114 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001115 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001116 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001117 serial = int(hexstring_serial, 16)
1118 return serial
1119 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001120 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001121 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001122 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001123
1124
1125 def gmtime_adj_notAfter(self, amount):
1126 """
1127 Adjust the time stamp for when the certificate stops being valid
1128
1129 :param amount: The number of seconds by which to adjust the ending
1130 validity time.
1131 :type amount: :py:class:`int`
1132
1133 :return: None
1134 """
1135 if not isinstance(amount, int):
1136 raise TypeError("amount must be an integer")
1137
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001138 notAfter = _lib.X509_get_notAfter(self._x509)
1139 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001140
1141
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001142 def gmtime_adj_notBefore(self, amount):
1143 """
1144 Change the timestamp for when the certificate starts being valid to the current
1145 time plus an offset.
1146
1147 :param amount: The number of seconds by which to adjust the starting validity
1148 time.
1149 :return: None
1150 """
1151 if not isinstance(amount, int):
1152 raise TypeError("amount must be an integer")
1153
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001154 notBefore = _lib.X509_get_notBefore(self._x509)
1155 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001156
1157
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001158 def has_expired(self):
1159 """
1160 Check whether the certificate has expired.
1161
1162 :return: True if the certificate has expired, false otherwise
1163 """
1164 now = int(time())
Jeff Tangfc18f7b2015-04-15 17:42:33 -04001165 notAfter = self.get_notAfter().decode('utf-8')
1166 notAfterSecs = timegm(strptime(notAfter, '%Y%m%d%H%M%SZ'))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001167
Jeff Tangfc18f7b2015-04-15 17:42:33 -04001168 return now > notAfterSecs
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001169
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001170 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001171 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001172
1173
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001174 def get_notBefore(self):
1175 """
1176 Retrieve the time stamp for when the certificate starts being valid
1177
1178 :return: A string giving the timestamp, in the format::
1179
1180 YYYYMMDDhhmmssZ
1181 YYYYMMDDhhmmss+hhmm
1182 YYYYMMDDhhmmss-hhmm
1183
1184 or None if there is no value set.
1185 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001186 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001187
1188
1189 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001190 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001191
1192
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001193 def set_notBefore(self, when):
1194 """
1195 Set the time stamp for when the certificate starts being valid
1196
1197 :param when: A string giving the timestamp, in the format:
1198
1199 YYYYMMDDhhmmssZ
1200 YYYYMMDDhhmmss+hhmm
1201 YYYYMMDDhhmmss-hhmm
1202 :type when: :py:class:`bytes`
1203
1204 :return: None
1205 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001206 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001207
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001208
1209 def get_notAfter(self):
1210 """
1211 Retrieve the time stamp for when the certificate stops being valid
1212
1213 :return: A string giving the timestamp, in the format::
1214
1215 YYYYMMDDhhmmssZ
1216 YYYYMMDDhhmmss+hhmm
1217 YYYYMMDDhhmmss-hhmm
1218
1219 or None if there is no value set.
1220 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001221 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001222
1223
1224 def set_notAfter(self, when):
1225 """
1226 Set the time stamp for when the certificate stops being valid
1227
1228 :param when: A string giving the timestamp, in the format:
1229
1230 YYYYMMDDhhmmssZ
1231 YYYYMMDDhhmmss+hhmm
1232 YYYYMMDDhhmmss-hhmm
1233 :type when: :py:class:`bytes`
1234
1235 :return: None
1236 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001237 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001238
1239
1240 def _get_name(self, which):
1241 name = X509Name.__new__(X509Name)
1242 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001243 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001244 # TODO: This is untested.
1245 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001246
1247 # The name is owned by the X509 structure. As long as the X509Name
1248 # Python object is alive, keep the X509 Python object alive.
1249 name._owner = self
1250
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001251 return name
1252
1253
1254 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001255 if not isinstance(name, X509Name):
1256 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001257 set_result = which(self._x509, name._name)
1258 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001259 # TODO: This is untested.
1260 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001261
1262
1263 def get_issuer(self):
1264 """
1265 Create an X509Name object for the issuer of the certificate
1266
1267 :return: An X509Name object
1268 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001269 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001270
1271
1272 def set_issuer(self, issuer):
1273 """
1274 Set the issuer of the certificate
1275
1276 :param issuer: The issuer name
1277 :type issuer: :py:class:`X509Name`
1278
1279 :return: None
1280 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001281 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001282
1283
1284 def get_subject(self):
1285 """
1286 Create an X509Name object for the subject of the certificate
1287
1288 :return: An X509Name object
1289 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001290 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001291
1292
1293 def set_subject(self, subject):
1294 """
1295 Set the subject of the certificate
1296
1297 :param subject: The subject name
1298 :type subject: :py:class:`X509Name`
1299 :return: None
1300 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001301 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001302
1303
1304 def get_extension_count(self):
1305 """
1306 Get the number of extensions on the certificate.
1307
1308 :return: The number of extensions as an integer.
1309 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001310 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001311
1312
1313 def add_extensions(self, extensions):
1314 """
1315 Add extensions to the certificate.
1316
1317 :param extensions: a sequence of X509Extension objects
1318 :return: None
1319 """
1320 for ext in extensions:
1321 if not isinstance(ext, X509Extension):
1322 raise ValueError("One of the elements is not an X509Extension")
1323
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001324 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001325 if not add_result:
1326 _raise_current_error()
1327
1328
1329 def get_extension(self, index):
1330 """
1331 Get a specific extension of the certificate by index.
1332
1333 :param index: The index of the extension to retrieve.
1334 :return: The X509Extension object at the specified index.
1335 """
1336 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001337 ext._extension = _lib.X509_get_ext(self._x509, index)
1338 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001339 raise IndexError("extension index out of bounds")
1340
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001341 extension = _lib.X509_EXTENSION_dup(ext._extension)
1342 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001343 return ext
1344
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001345X509Type = X509
1346
1347
1348
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001349class X509Store(object):
1350 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001351 store = _lib.X509_STORE_new()
1352 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001353
1354
1355 def add_cert(self, cert):
1356 if not isinstance(cert, X509):
1357 raise TypeError()
1358
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001359 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001360 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001361 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001362
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001363
1364X509StoreType = X509Store
1365
1366
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001367class X509StoreContextError(Exception):
1368 """
1369 An error occurred while verifying a certificate using
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001370 `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001371
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001372 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001373 :type cert: :class:`X509`
1374
1375 """
1376 def __init__(self, message, certificate):
1377 super(X509StoreContextError, self).__init__(message)
1378 self.certificate = certificate
1379
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001380
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001381class X509StoreContext(object):
1382 """
1383 An X.509 store context.
1384
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001385 An :py:class:`X509StoreContext` is used to define some of the criteria for
1386 certificate verification. The information encapsulated in this object
1387 includes, but is not limited to, a set of trusted certificates,
1388 verification parameters, and revoked certificates.
1389
1390 Of these, only the set of trusted certificates is currently exposed.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001391
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001392 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1393 instance. It is dynamically allocated and automatically garbage
1394 collected.
1395
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001396 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001397
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001398 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001399 """
1400
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001401 def __init__(self, store, certificate):
1402 """
1403 :param X509Store store: The certificates which will be trusted for the
1404 purposes of any verifications.
1405
1406 :param X509 certificate: The certificate to be verified.
1407 """
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001408 store_ctx = _lib.X509_STORE_CTX_new()
1409 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1410 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001411 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001412 # Make the store context available for use after instantiating this
1413 # class by initializing it now. Per testing, subsequent calls to
1414 # :py:meth:`_init` have no adverse affect.
1415 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001416
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001417
1418 def _init(self):
1419 """
1420 Set up the store context for a subsequent verification operation.
1421 """
1422 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1423 if ret <= 0:
1424 _raise_current_error()
1425
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001426
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001427 def _cleanup(self):
1428 """
1429 Internally cleans up the store context.
1430
1431 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001432 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001433 """
1434 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1435
1436
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001437 def _exception_from_context(self):
1438 """
1439 Convert an OpenSSL native context error failure into a Python
1440 exception.
1441
1442 When a call to native OpenSSL X509_verify_cert fails, additonal information
1443 about the failure can be obtained from the store context.
1444 """
1445 errors = [
1446 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1447 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1448 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1449 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1450 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001451 # A context error should always be associated with a certificate, so we
1452 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001453 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001454 _cert = _lib.X509_dup(_x509)
1455 pycert = X509.__new__(X509)
1456 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001457 return X509StoreContextError(errors, pycert)
1458
1459
Stephen Holsapple46a09252015-02-12 14:45:43 -08001460 def set_store(self, store):
1461 """
1462 Set the context's trust store.
1463
1464 :param X509Store store: The certificates which will be trusted for the
1465 purposes of any *future* verifications.
1466 """
1467 self._store = store
1468
1469
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001470 def verify_certificate(self):
1471 """
1472 Verify a certificate in a context.
1473
1474 :param store_ctx: The :py:class:`X509StoreContext` to verify.
1475 :raises: Error
1476 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001477 # Always re-initialize the store context in case
1478 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001479 self._init()
1480 ret = _lib.X509_verify_cert(self._store_ctx)
1481 self._cleanup()
1482 if ret <= 0:
1483 raise self._exception_from_context()
1484
1485
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001486
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001487def load_certificate(type, buffer):
1488 """
1489 Load a certificate from a buffer
1490
1491 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001492
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001493 :param buffer: The buffer the certificate is stored in
1494 :type buffer: :py:class:`bytes`
1495
1496 :return: The X509 object
1497 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001498 if isinstance(buffer, _text_type):
1499 buffer = buffer.encode("ascii")
1500
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001501 bio = _new_mem_buf(buffer)
1502
1503 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001504 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001505 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001506 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001507 else:
1508 raise ValueError(
1509 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1510
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001511 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001512 _raise_current_error()
1513
1514 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001515 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001516 return cert
1517
1518
1519def dump_certificate(type, cert):
1520 """
1521 Dump a certificate to a buffer
1522
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001523 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1524 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001525 :param cert: The certificate to dump
1526 :return: The buffer with the dumped certificate in
1527 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001528 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001529
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001530 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001531 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001532 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001533 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001534 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001535 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001536 else:
1537 raise ValueError(
1538 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1539 "FILETYPE_TEXT")
1540
1541 return _bio_to_string(bio)
1542
1543
1544
1545def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1546 """
1547 Dump a private key to a buffer
1548
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001549 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1550 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001551 :param pkey: The PKey to dump
1552 :param cipher: (optional) if encrypted PEM format, the cipher to
1553 use
1554 :param passphrase: (optional) if encrypted PEM format, this can be either
1555 the passphrase to use, or a callback for providing the
1556 passphrase.
1557 :return: The buffer with the dumped key in
1558 :rtype: :py:data:`str`
1559 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001560 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001561
1562 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001563 if passphrase is None:
1564 raise TypeError(
1565 "if a value is given for cipher "
1566 "one must also be given for passphrase")
1567 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001568 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001569 raise ValueError("Invalid cipher name")
1570 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001571 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001572
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001573 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001574 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001575 result_code = _lib.PEM_write_bio_PrivateKey(
1576 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001577 helper.callback, helper.callback_args)
1578 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001579 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001580 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001581 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001582 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1583 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001584 # TODO RSA_free(rsa)?
1585 else:
1586 raise ValueError(
1587 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1588 "FILETYPE_TEXT")
1589
1590 if result_code == 0:
1591 _raise_current_error()
1592
1593 return _bio_to_string(bio)
1594
1595
1596
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001597def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001598 copy = _lib.X509_REVOKED_new()
1599 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001600 # TODO: This is untested.
1601 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001602
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001603 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001604 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001605 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001606
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001607 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001608 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001609 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001610
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001611 if original.extensions != _ffi.NULL:
1612 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1613 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1614 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1615 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1616 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001617 copy.extensions = extension_stack
1618
1619 copy.sequence = original.sequence
1620 return copy
1621
1622
1623
1624class Revoked(object):
1625 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1626 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1627 # OCSP_crl_reason_str. We use the latter, just like the command line
1628 # program.
1629 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001630 b"unspecified",
1631 b"keyCompromise",
1632 b"CACompromise",
1633 b"affiliationChanged",
1634 b"superseded",
1635 b"cessationOfOperation",
1636 b"certificateHold",
1637 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001638 ]
1639
1640 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001641 revoked = _lib.X509_REVOKED_new()
1642 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001643
1644
1645 def set_serial(self, hex_str):
1646 """
1647 Set the serial number of a revoked Revoked structure
1648
1649 :param hex_str: The new serial number.
1650 :type hex_str: :py:data:`str`
1651 :return: None
1652 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001653 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1654 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001655 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001656 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001657 if not bn_result:
1658 raise ValueError("bad hex string")
1659
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001660 asn1_serial = _ffi.gc(
1661 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1662 _lib.ASN1_INTEGER_free)
1663 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001664
1665
1666 def get_serial(self):
1667 """
1668 Return the serial number of a Revoked structure
1669
1670 :return: The serial number as a string
1671 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001672 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001673
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001674 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001675 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001676 # TODO: This is untested.
1677 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001678
1679 return _bio_to_string(bio)
1680
1681
1682 def _delete_reason(self):
1683 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001684 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1685 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1686 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1687 _lib.X509_EXTENSION_free(ext)
1688 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001689 break
1690
1691
1692 def set_reason(self, reason):
1693 """
1694 Set the reason of a Revoked object.
1695
1696 If :py:data:`reason` is :py:data:`None`, delete the reason instead.
1697
1698 :param reason: The reason string.
1699 :type reason: :py:class:`str` or :py:class:`NoneType`
1700 :return: None
1701 """
1702 if reason is None:
1703 self._delete_reason()
1704 elif not isinstance(reason, bytes):
1705 raise TypeError("reason must be None or a byte string")
1706 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001707 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001708 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1709
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001710 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1711 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001712 # TODO: This is untested.
1713 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001714 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001715
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001716 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1717 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001718 # TODO: This is untested.
1719 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001720
1721 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001722 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1723 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001724
1725 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001726 # TODO: This is untested.
1727 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001728
1729
1730 def get_reason(self):
1731 """
1732 Return the reason of a Revoked object.
1733
1734 :return: The reason as a string
1735 """
1736 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001737 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1738 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1739 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001740 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001741
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001742 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001743 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001744 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001745 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001746 # TODO: This is untested.
1747 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001748
1749 return _bio_to_string(bio)
1750
1751
1752 def all_reasons(self):
1753 """
1754 Return a list of all the supported reason strings.
1755
1756 :return: A list of reason strings.
1757 """
1758 return self._crl_reasons[:]
1759
1760
1761 def set_rev_date(self, when):
1762 """
1763 Set the revocation timestamp
1764
1765 :param when: A string giving the timestamp, in the format:
1766
1767 YYYYMMDDhhmmssZ
1768 YYYYMMDDhhmmss+hhmm
1769 YYYYMMDDhhmmss-hhmm
1770
1771 :return: None
1772 """
1773 return _set_asn1_time(self._revoked.revocationDate, when)
1774
1775
1776 def get_rev_date(self):
1777 """
1778 Retrieve the revocation date
1779
1780 :return: A string giving the timestamp, in the format:
1781
1782 YYYYMMDDhhmmssZ
1783 YYYYMMDDhhmmss+hhmm
1784 YYYYMMDDhhmmss-hhmm
1785 """
1786 return _get_asn1_time(self._revoked.revocationDate)
1787
1788
1789
1790class CRL(object):
1791 def __init__(self):
1792 """
1793 Create a new empty CRL object.
1794 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001795 crl = _lib.X509_CRL_new()
1796 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001797
1798
1799 def get_revoked(self):
1800 """
1801 Return revoked portion of the CRL structure (by value not reference).
1802
1803 :return: A tuple of Revoked objects.
1804 """
1805 results = []
1806 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001807 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1808 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809 revoked_copy = _X509_REVOKED_dup(revoked)
1810 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001811 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001812 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001813 if results:
1814 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001815
1816
1817 def add_revoked(self, revoked):
1818 """
1819 Add a revoked (by value not reference) to the CRL structure
1820
1821 :param revoked: The new revoked.
1822 :type revoked: :class:`X509`
1823
1824 :return: None
1825 """
1826 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001827 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001828 # TODO: This is untested.
1829 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001830
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001831 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001832 if add_result == 0:
1833 # TODO: This is untested.
1834 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001835
1836
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001837 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001838 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001839 """
1840 export a CRL as a string
1841
1842 :param cert: Used to sign CRL.
1843 :type cert: :class:`X509`
1844
1845 :param key: Used to sign CRL.
1846 :type key: :class:`PKey`
1847
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001848 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1849 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001850
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001851 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001852
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001853 :param bytes digest: The name of the message digest to use (eg
1854 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001855
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001856 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001857 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001858 if not isinstance(cert, X509):
1859 raise TypeError("cert must be an X509 instance")
1860 if not isinstance(key, PKey):
1861 raise TypeError("key must be a PKey instance")
1862 if not isinstance(type, int):
1863 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001864
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001865 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001866 _warn(
1867 "The default message digest (md5) is deprecated. "
1868 "Pass the name of a message digest explicitly.",
1869 category=DeprecationWarning,
1870 stacklevel=2,
1871 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001872 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001873
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001874 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001875 if digest_obj == _ffi.NULL:
1876 raise ValueError("No such digest method")
1877
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001878 bio = _lib.BIO_new(_lib.BIO_s_mem())
1879 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001880 # TODO: This is untested.
1881 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001882
1883 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001884 sometime = _lib.ASN1_TIME_new()
1885 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001886 # TODO: This is untested.
1887 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001888
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001889 _lib.X509_gmtime_adj(sometime, 0)
1890 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001891
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001892 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1893 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001894
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001895 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001896
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001897 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001898 if not sign_result:
1899 _raise_current_error()
1900
1901 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001902 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001903 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001904 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001905 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001906 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001907 else:
1908 raise ValueError(
1909 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1910
1911 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001912 # TODO: This is untested.
1913 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001914
1915 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001916CRLType = CRL
1917
1918
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001919
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001920class PKCS7(object):
1921 def type_is_signed(self):
1922 """
1923 Check if this NID_pkcs7_signed object
1924
1925 :return: True if the PKCS7 is of type signed
1926 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001927 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001928 return True
1929 return False
1930
1931
1932 def type_is_enveloped(self):
1933 """
1934 Check if this NID_pkcs7_enveloped object
1935
1936 :returns: True if the PKCS7 is of type enveloped
1937 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001938 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001939 return True
1940 return False
1941
1942
1943 def type_is_signedAndEnveloped(self):
1944 """
1945 Check if this NID_pkcs7_signedAndEnveloped object
1946
1947 :returns: True if the PKCS7 is of type signedAndEnveloped
1948 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001949 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001950 return True
1951 return False
1952
1953
1954 def type_is_data(self):
1955 """
1956 Check if this NID_pkcs7_data object
1957
1958 :return: True if the PKCS7 is of type data
1959 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001960 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001961 return True
1962 return False
1963
1964
1965 def get_type_name(self):
1966 """
1967 Returns the type name of the PKCS7 structure
1968
1969 :return: A string with the typename
1970 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001971 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1972 string_type = _lib.OBJ_nid2sn(nid)
1973 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001974
1975PKCS7Type = PKCS7
1976
1977
1978
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001979class PKCS12(object):
1980 def __init__(self):
1981 self._pkey = None
1982 self._cert = None
1983 self._cacerts = None
1984 self._friendlyname = None
1985
1986
1987 def get_certificate(self):
1988 """
1989 Return certificate portion of the PKCS12 structure
1990
1991 :return: X509 object containing the certificate
1992 """
1993 return self._cert
1994
1995
1996 def set_certificate(self, cert):
1997 """
1998 Replace the certificate portion of the PKCS12 structure
1999
2000 :param cert: The new certificate.
2001 :type cert: :py:class:`X509` or :py:data:`None`
2002 :return: None
2003 """
2004 if not isinstance(cert, X509):
2005 raise TypeError("cert must be an X509 instance")
2006 self._cert = cert
2007
2008
2009 def get_privatekey(self):
2010 """
2011 Return private key portion of the PKCS12 structure
2012
2013 :returns: PKey object containing the private key
2014 """
2015 return self._pkey
2016
2017
2018 def set_privatekey(self, pkey):
2019 """
2020 Replace or set the certificate portion of the PKCS12 structure
2021
2022 :param pkey: The new private key.
2023 :type pkey: :py:class:`PKey`
2024 :return: None
2025 """
2026 if not isinstance(pkey, PKey):
2027 raise TypeError("pkey must be a PKey instance")
2028 self._pkey = pkey
2029
2030
2031 def get_ca_certificates(self):
2032 """
2033 Return CA certificates within of the PKCS12 object
2034
2035 :return: A newly created tuple containing the CA certificates in the chain,
2036 if any are present, or None if no CA certificates are present.
2037 """
2038 if self._cacerts is not None:
2039 return tuple(self._cacerts)
2040
2041
2042 def set_ca_certificates(self, cacerts):
2043 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002044 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002045
2046 :param cacerts: The new CA certificates.
2047 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2048 :return: None
2049 """
2050 if cacerts is None:
2051 self._cacerts = None
2052 else:
2053 cacerts = list(cacerts)
2054 for cert in cacerts:
2055 if not isinstance(cert, X509):
2056 raise TypeError("iterable must only contain X509 instances")
2057 self._cacerts = cacerts
2058
2059
2060 def set_friendlyname(self, name):
2061 """
2062 Replace or set the certificate portion of the PKCS12 structure
2063
2064 :param name: The new friendly name.
2065 :type name: :py:class:`bytes`
2066 :return: None
2067 """
2068 if name is None:
2069 self._friendlyname = None
2070 elif not isinstance(name, bytes):
2071 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2072 self._friendlyname = name
2073
2074
2075 def get_friendlyname(self):
2076 """
2077 Return friendly name portion of the PKCS12 structure
2078
2079 :returns: String containing the friendlyname
2080 """
2081 return self._friendlyname
2082
2083
2084 def export(self, passphrase=None, iter=2048, maciter=1):
2085 """
2086 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2087
2088 :param passphrase: used to encrypt the PKCS12
2089 :type passphrase: :py:data:`bytes`
2090
2091 :param iter: How many times to repeat the encryption
2092 :type iter: :py:data:`int`
2093
2094 :param maciter: How many times to repeat the MAC
2095 :type maciter: :py:data:`int`
2096
2097 :return: The string containing the PKCS12
2098 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002099 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002100
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002101 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002102 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002103 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002104 cacerts = _lib.sk_X509_new_null()
2105 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002106 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002107 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002108
2109 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002110 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002111
2112 friendlyname = self._friendlyname
2113 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002114 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002115
2116 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002117 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002118 else:
2119 pkey = self._pkey._pkey
2120
2121 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002122 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002123 else:
2124 cert = self._cert._x509
2125
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002126 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002127 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002128 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2129 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002130 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002131 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002132 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002133 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002134
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002135 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002136 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002137 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002138
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002139PKCS12Type = PKCS12
2140
2141
2142
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002143class NetscapeSPKI(object):
2144 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002145 spki = _lib.NETSCAPE_SPKI_new()
2146 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002147
2148
2149 def sign(self, pkey, digest):
2150 """
2151 Sign the certificate request using the supplied key and digest
2152
2153 :param pkey: The key to sign with
2154 :param digest: The message digest to use
2155 :return: None
2156 """
2157 if pkey._only_public:
2158 raise ValueError("Key has only public part")
2159
2160 if not pkey._initialized:
2161 raise ValueError("Key is uninitialized")
2162
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002163 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002164 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002165 raise ValueError("No such digest method")
2166
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002167 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002168 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002169 # TODO: This is untested.
2170 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002171
2172
2173 def verify(self, key):
2174 """
2175 Verifies a certificate request using the supplied public key
2176
2177 :param key: a public key
2178 :return: True if the signature is correct.
2179 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2180 problem verifying the signature.
2181 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002182 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002183 if answer <= 0:
2184 _raise_current_error()
2185 return True
2186
2187
2188 def b64_encode(self):
2189 """
2190 Generate a base64 encoded string from an SPKI
2191
2192 :return: The base64 encoded string
2193 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002194 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2195 result = _ffi.string(encoded)
2196 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002197 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002198
2199
2200 def get_pubkey(self):
2201 """
2202 Get the public key of the certificate
2203
2204 :return: The public key
2205 """
2206 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002207 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2208 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002209 # TODO: This is untested.
2210 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002211 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002212 pkey._only_public = True
2213 return pkey
2214
2215
2216 def set_pubkey(self, pkey):
2217 """
2218 Set the public key of the certificate
2219
2220 :param pkey: The public key
2221 :return: None
2222 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002223 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002224 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002225 # TODO: This is untested.
2226 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002227NetscapeSPKIType = NetscapeSPKI
2228
2229
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002230class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002231 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002232 if type != FILETYPE_PEM and passphrase is not None:
2233 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002234 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002235 self._more_args = more_args
2236 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002237 self._problems = []
2238
2239
2240 @property
2241 def callback(self):
2242 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002243 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002244 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002245 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002246 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002247 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002248 else:
2249 raise TypeError("Last argument must be string or callable")
2250
2251
2252 @property
2253 def callback_args(self):
2254 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002255 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002256 elif isinstance(self._passphrase, bytes):
2257 return self._passphrase
2258 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002259 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002260 else:
2261 raise TypeError("Last argument must be string or callable")
2262
2263
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002264 def raise_if_problem(self, exceptionType=Error):
2265 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002266 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002267 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002268 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002269 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002270 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002271 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002272
2273
2274 def _read_passphrase(self, buf, size, rwflag, userdata):
2275 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002276 if self._more_args:
2277 result = self._passphrase(size, rwflag, userdata)
2278 else:
2279 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002280 if not isinstance(result, bytes):
2281 raise ValueError("String expected")
2282 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002283 if self._truncate:
2284 result = result[:size]
2285 else:
2286 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002287 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002288 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002289 return len(result)
2290 except Exception as e:
2291 self._problems.append(e)
2292 return 0
2293
2294
2295
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002296def load_privatekey(type, buffer, passphrase=None):
2297 """
2298 Load a private key from a buffer
2299
2300 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2301 :param buffer: The buffer the key is stored in
2302 :param passphrase: (optional) if encrypted PEM format, this can be
2303 either the passphrase to use, or a callback for
2304 providing the passphrase.
2305
2306 :return: The PKey object
2307 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002308 if isinstance(buffer, _text_type):
2309 buffer = buffer.encode("ascii")
2310
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002311 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002312
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002313 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002314 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002315 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2316 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002317 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002318 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002319 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002320 else:
2321 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2322
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002323 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002324 _raise_current_error()
2325
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002326 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002327 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002328 return pkey
2329
2330
2331
2332def dump_certificate_request(type, req):
2333 """
2334 Dump a certificate request to a buffer
2335
2336 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2337 :param req: The certificate request to dump
2338 :return: The buffer with the dumped certificate request in
2339 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002340 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002341
2342 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002343 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002344 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002345 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002346 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002347 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002348 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002349 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002350
2351 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002352 # TODO: This is untested.
2353 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002354
2355 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002356
2357
2358
2359def load_certificate_request(type, buffer):
2360 """
2361 Load a certificate request from a buffer
2362
2363 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2364 :param buffer: The buffer the certificate request is stored in
2365 :return: The X509Req 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 Calderone066f0572013-02-20 13:43:44 -08002371
2372 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002373 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002374 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002375 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002376 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002377 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002378
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002379 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002380 # TODO: This is untested.
2381 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002382
2383 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002384 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002385 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002386
2387
2388
2389def sign(pkey, data, digest):
2390 """
2391 Sign data with a digest
2392
2393 :param pkey: Pkey to sign with
2394 :param data: data to be signed
2395 :param digest: message digest to use
2396 :return: signature
2397 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002398 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002399
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002400 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002401 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002402 raise ValueError("No such digest method")
2403
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002404 md_ctx = _ffi.new("EVP_MD_CTX*")
2405 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002406
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002407 _lib.EVP_SignInit(md_ctx, digest_obj)
2408 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002409
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002410 signature_buffer = _ffi.new("unsigned char[]", 512)
2411 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002412 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002413 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002414 md_ctx, signature_buffer, signature_length, pkey._pkey)
2415
2416 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002417 # TODO: This is untested.
2418 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002419
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002420 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002421
2422
2423
2424def verify(cert, signature, data, digest):
2425 """
2426 Verify a signature
2427
2428 :param cert: signing certificate (X509 object)
2429 :param signature: signature returned by sign function
2430 :param data: data to be verified
2431 :param digest: message digest to use
2432 :return: None if the signature is correct, raise exception otherwise
2433 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002434 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002435
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002436 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002437 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002438 raise ValueError("No such digest method")
2439
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002440 pkey = _lib.X509_get_pubkey(cert._x509)
2441 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002442 # TODO: This is untested.
2443 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002444 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002445
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002446 md_ctx = _ffi.new("EVP_MD_CTX*")
2447 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002448
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002449 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2450 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2451 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002452
2453 if verify_result != 1:
2454 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002455
2456
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002457def load_crl(type, buffer):
2458 """
2459 Load a certificate revocation list from a buffer
2460
2461 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2462 :param buffer: The buffer the CRL is stored in
2463
2464 :return: The PKey object
2465 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002466 if isinstance(buffer, _text_type):
2467 buffer = buffer.encode("ascii")
2468
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002469 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002470
2471 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002472 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002473 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002474 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002475 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002476 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2477
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002478 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002479 _raise_current_error()
2480
2481 result = CRL.__new__(CRL)
2482 result._crl = crl
2483 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002484
2485
2486
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002487def load_pkcs7_data(type, buffer):
2488 """
2489 Load pkcs7 data from a buffer
2490
2491 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2492 :param buffer: The buffer with the pkcs7 data.
2493 :return: The PKCS7 object
2494 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002495 if isinstance(buffer, _text_type):
2496 buffer = buffer.encode("ascii")
2497
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002498 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002499
2500 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002501 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002502 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002503 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002504 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002505 # TODO: This is untested.
2506 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002507 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2508
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002509 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002510 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002511
2512 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002513 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002514 return pypkcs7
2515
2516
2517
Stephen Holsapple38482622014-04-05 20:29:34 -07002518def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002519 """
2520 Load a PKCS12 object from a buffer
2521
2522 :param buffer: The buffer the certificate is stored in
2523 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2524 :returns: The PKCS12 object
2525 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002526 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002527
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002528 if isinstance(buffer, _text_type):
2529 buffer = buffer.encode("ascii")
2530
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002531 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002532
Stephen Holsapple38482622014-04-05 20:29:34 -07002533 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2534 # password based encryption no password and a zero length password are two
2535 # different things, but OpenSSL implementation will try both to figure out
2536 # which one works.
2537 if not passphrase:
2538 passphrase = _ffi.NULL
2539
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002540 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2541 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002542 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002543 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002544
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002545 pkey = _ffi.new("EVP_PKEY**")
2546 cert = _ffi.new("X509**")
2547 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002548
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002549 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002550 if not parse_result:
2551 _raise_current_error()
2552
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002553 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002554
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002555 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2556 # queue for no particular reason. This error isn't interesting to anyone
2557 # outside this function. It's not even interesting to us. Get rid of it.
2558 try:
2559 _raise_current_error()
2560 except Error:
2561 pass
2562
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002563 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002564 pykey = None
2565 else:
2566 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002567 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002568
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002569 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002570 pycert = None
2571 friendlyname = None
2572 else:
2573 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002574 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002575
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002576 friendlyname_length = _ffi.new("int*")
2577 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2578 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2579 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002580 friendlyname = None
2581
2582 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002583 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002584 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002585 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002586 pycacerts.append(pycacert)
2587 if not pycacerts:
2588 pycacerts = None
2589
2590 pkcs12 = PKCS12.__new__(PKCS12)
2591 pkcs12._pkey = pykey
2592 pkcs12._cert = pycert
2593 pkcs12._cacerts = pycacerts
2594 pkcs12._friendlyname = friendlyname
2595 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002596
2597
2598def _initialize_openssl_threads(get_ident, Lock):
2599 import _ssl
2600 return
2601
2602 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2603
2604 def locking_function(mode, index, filename, line):
2605 if mode & _lib.CRYPTO_LOCK:
2606 locks[index].acquire()
2607 else:
2608 locks[index].release()
2609
2610 _lib.CRYPTO_set_id_callback(
2611 _ffi.callback("unsigned long (*)(void)", get_ident))
2612
2613 _lib.CRYPTO_set_locking_callback(
2614 _ffi.callback(
2615 "void (*)(int, int, const char*, int)", locking_function))
2616
2617
2618try:
2619 from thread import get_ident
2620 from threading import Lock
2621except ImportError:
2622 pass
2623else:
2624 _initialize_openssl_threads(get_ident, Lock)
2625 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002626
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002627# There are no direct unit tests for this initialization. It is tested
2628# indirectly since it is necessary for functions like dump_privatekey when
2629# using encryption.
2630#
2631# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2632# and some other similar tests may fail without this (though they may not if
2633# the Python runtime has already done some initialization of the underlying
2634# OpenSSL library (and is linked against the same one that cryptography is
2635# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002636_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002637
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002638# This is similar but exercised mainly by exception_from_error_queue. It calls
2639# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2640_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002641
2642
2643
2644# Set the default string mask to match OpenSSL upstream (since 2005) and
2645# RFC5280 recommendations.
2646_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')