blob: c7bdabc0cf11490763ea7f43b6e189a84d15b3c9 [file] [log] [blame]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001from time import time
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05003from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05004from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04005from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05006
7from six import (
8 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -04009 text_type as _text_type,
10 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080011
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050012from OpenSSL._util import (
13 ffi as _ffi,
14 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050015 exception_from_error_queue as _exception_from_error_queue,
16 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040017 native as _native,
18 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040019 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040020)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080021
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050022FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
23FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080024
25# TODO This was an API mistake. OpenSSL has no such constant.
26FILETYPE_TEXT = 2 ** 16 - 1
27
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050028TYPE_RSA = _lib.EVP_PKEY_RSA
29TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080030
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080031
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070032
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050033class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050034 """
35 An error occurred in an `OpenSSL.crypto` API.
36 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050037
38
39_raise_current_error = partial(_exception_from_error_queue, Error)
40
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070041
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050042
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050043def _untested_error(where):
44 """
45 An OpenSSL API failed somehow. Additionally, the failure which was
46 encountered isn't one that's exercised by the test suite so future behavior
47 of pyOpenSSL is now somewhat less predictable.
48 """
49 raise RuntimeError("Unknown %s failure" % (where,))
50
51
52
53def _new_mem_buf(buffer=None):
54 """
55 Allocate a new OpenSSL memory BIO.
56
57 Arrange for the garbage collector to clean it up automatically.
58
59 :param buffer: None or some bytes to use to put into the BIO so that they
60 can be read out.
61 """
62 if buffer is None:
63 bio = _lib.BIO_new(_lib.BIO_s_mem())
64 free = _lib.BIO_free
65 else:
66 data = _ffi.new("char[]", buffer)
67 bio = _lib.BIO_new_mem_buf(data, len(buffer))
68 # Keep the memory alive as long as the bio is alive!
69 def free(bio, ref=data):
70 return _lib.BIO_free(bio)
71
72 if bio == _ffi.NULL:
73 # TODO: This is untested.
74 _raise_current_error()
75
76 bio = _ffi.gc(bio, free)
77 return bio
78
79
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050080
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080081def _bio_to_string(bio):
82 """
83 Copy the contents of an OpenSSL BIO object into a Python byte string.
84 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050085 result_buffer = _ffi.new('char**')
86 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
87 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080088
89
90
Jean-Paul Calderone57122982013-02-21 08:47:05 -080091def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050092 """
93 The the time value of an ASN1 time object.
94
95 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
96 castable to that type) which will have its value set.
97 @param when: A string representation of the desired time value.
98
99 @raise TypeError: If C{when} is not a L{bytes} string.
100 @raise ValueError: If C{when} does not represent a time in the required
101 format.
102 @raise RuntimeError: If the time value cannot be set for some other
103 (unspecified) reason.
104 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800105 if not isinstance(when, bytes):
106 raise TypeError("when must be a byte string")
107
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500108 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
109 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800110 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500111 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
112 _lib.ASN1_STRING_set(dummy, when, len(when))
113 check_result = _lib.ASN1_GENERALIZEDTIME_check(
114 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800115 if not check_result:
116 raise ValueError("Invalid string")
117 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500118 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800119
120
121
122def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500123 """
124 Retrieve the time value of an ASN1 time object.
125
126 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
127 that type) from which the time value will be retrieved.
128
129 @return: The time value from C{timestamp} as a L{bytes} string in a certain
130 format. Or C{None} if the object contains no time value.
131 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500132 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
133 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800134 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500135 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
136 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800137 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500138 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
139 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
140 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500141 # This may happen:
142 # - if timestamp was not an ASN1_TIME
143 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
144 # - if a copy of the time data from timestamp cannot be made for
145 # the newly allocated ASN1_GENERALIZEDTIME
146 #
147 # These are difficult to test. cffi enforces the ASN1_TIME type.
148 # Memory allocation failures are a pain to trigger
149 # deterministically.
150 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800151 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500152 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800153 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500154 string_data = _lib.ASN1_STRING_data(string_timestamp)
155 string_result = _ffi.string(string_data)
156 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800157 return string_result
158
159
160
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800161class PKey(object):
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800162 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800163 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800164
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800165 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500166 pkey = _lib.EVP_PKEY_new()
167 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800168 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800169
170
171 def generate_key(self, type, bits):
172 """
173 Generate a key of a given type, with a given number of a bits
174
175 :param type: The key type (TYPE_RSA or TYPE_DSA)
176 :param bits: The number of bits
177
178 :return: None
179 """
180 if not isinstance(type, int):
181 raise TypeError("type must be an integer")
182
183 if not isinstance(bits, int):
184 raise TypeError("bits must be an integer")
185
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800186 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500187 exponent = _lib.BN_new()
188 exponent = _ffi.gc(exponent, _lib.BN_free)
189 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800190
191 if type == TYPE_RSA:
192 if bits <= 0:
193 raise ValueError("Invalid number of bits")
194
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500195 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800196
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500197 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500198 if result == 0:
199 # TODO: The test for this case is commented out. Different
200 # builds of OpenSSL appear to have different failure modes that
201 # make it hard to test. Visual inspection of the OpenSSL
202 # source reveals that a return value of 0 signals an error.
203 # Manual testing on a particular build of OpenSSL suggests that
204 # this is probably the appropriate way to handle those errors.
205 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800206
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500207 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800208 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500209 # TODO: It appears as though this can fail if an engine is in
210 # use which does not support RSA.
211 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800212
213 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500214 dsa = _lib.DSA_generate_parameters(
215 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
216 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500217 # TODO: This is untested.
218 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500219 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500220 # TODO: This is untested.
221 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500222 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500223 # TODO: This is untested.
224 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800225 else:
226 raise Error("No such key type")
227
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800228 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800229
230
231 def check(self):
232 """
233 Check the consistency of an RSA private key.
234
235 :return: True if key is consistent.
236 :raise Error: if the key is inconsistent.
237 :raise TypeError: if the key is of a type which cannot be checked.
238 Only RSA keys can currently be checked.
239 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800240 if self._only_public:
241 raise TypeError("public key only")
242
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500243 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800244 raise TypeError("key type unsupported")
245
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500246 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
247 rsa = _ffi.gc(rsa, _lib.RSA_free)
248 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800249 if result:
250 return True
251 _raise_current_error()
252
253
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800254 def type(self):
255 """
256 Returns the type of the key
257
258 :return: The type of the key.
259 """
260 return self._pkey.type
261
262
263 def bits(self):
264 """
265 Returns the number of bits of the key
266
267 :return: The number of bits of the key.
268 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500269 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800270PKeyType = PKey
271
272
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800273
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400274class _EllipticCurve(object):
275 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400276 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400277
278 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
279 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
280 instances each of which represents one curve supported by the system.
281 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400282 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400283 _curves = None
284
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400285 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400286 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400287 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400288 """
289 Implement cooperation with the right-hand side argument of ``!=``.
290
291 Python 3 seems to have dropped this cooperation in this very narrow
292 circumstance.
293 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400294 if isinstance(other, _EllipticCurve):
295 return super(_EllipticCurve, self).__ne__(other)
296 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400297
298
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400299 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400300 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400301 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400302 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400303
304 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400305
306 :return: A :py:type:`set` of ``cls`` instances giving the names of the
307 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400308 """
309 if lib.Cryptography_HAS_EC:
310 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
311 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
312 # The return value on this call should be num_curves again. We could
313 # check it to make sure but if it *isn't* then.. what could we do?
314 # Abort the whole process, I suppose...? -exarkun
315 lib.EC_get_builtin_curves(builtin_curves, num_curves)
316 return set(
317 cls.from_nid(lib, c.nid)
318 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400319 return set()
320
321
322 @classmethod
323 def _get_elliptic_curves(cls, lib):
324 """
325 Get, cache, and return the curves supported by OpenSSL.
326
327 :param lib: The OpenSSL library binding object.
328
329 :return: A :py:type:`set` of ``cls`` instances giving the names of the
330 elliptic curves the underlying library supports.
331 """
332 if cls._curves is None:
333 cls._curves = cls._load_elliptic_curves(lib)
334 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400335
336
337 @classmethod
338 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400339 """
340 Instantiate a new :py:class:`_EllipticCurve` associated with the given
341 OpenSSL NID.
342
343 :param lib: The OpenSSL library binding object.
344
345 :param nid: The OpenSSL NID the resulting curve object will represent.
346 This must be a curve NID (and not, for example, a hash NID) or
347 subsequent operations will fail in unpredictable ways.
348 :type nid: :py:class:`int`
349
350 :return: The curve object.
351 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400352 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
353
354
355 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400356 """
357 :param _lib: The :py:mod:`cryptography` binding instance used to
358 interface with OpenSSL.
359
360 :param _nid: The OpenSSL NID identifying the curve this object
361 represents.
362 :type _nid: :py:class:`int`
363
364 :param name: The OpenSSL short name identifying the curve this object
365 represents.
366 :type name: :py:class:`unicode`
367 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400368 self._lib = lib
369 self._nid = nid
370 self.name = name
371
372
373 def __repr__(self):
374 return "<Curve %r>" % (self.name,)
375
376
377 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400378 """
379 Create a new OpenSSL EC_KEY structure initialized to use this curve.
380
381 The structure is automatically garbage collected when the Python object
382 is garbage collected.
383 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400384 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
385 return _ffi.gc(key, _lib.EC_KEY_free)
386
387
388
389def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400390 """
391 Return a set of objects representing the elliptic curves supported in the
392 OpenSSL build in use.
393
394 The curve objects have a :py:class:`unicode` ``name`` attribute by which
395 they identify themselves.
396
397 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400398 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
399 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400400 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400401 return _EllipticCurve._get_elliptic_curves(_lib)
402
403
404
405def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400406 """
407 Return a single curve object selected by name.
408
409 See :py:func:`get_elliptic_curves` for information about curve objects.
410
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400411 :param name: The OpenSSL short name identifying the curve object to
412 retrieve.
413 :type name: :py:class:`unicode`
414
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400415 If the named curve is not supported then :py:class:`ValueError` is raised.
416 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400417 for curve in get_elliptic_curves():
418 if curve.name == name:
419 return curve
420 raise ValueError("unknown curve name", name)
421
422
423
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800424class X509Name(object):
425 def __init__(self, name):
426 """
427 Create a new X509Name, copying the given X509Name instance.
428
429 :param name: An X509Name object to copy
430 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500431 name = _lib.X509_NAME_dup(name._name)
432 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800433
434
435 def __setattr__(self, name, value):
436 if name.startswith('_'):
437 return super(X509Name, self).__setattr__(name, value)
438
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800439 # Note: we really do not want str subclasses here, so we do not use
440 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800441 if type(name) is not str:
442 raise TypeError("attribute name must be string, not '%.200s'" % (
443 type(value).__name__,))
444
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500445 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500446 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800447 try:
448 _raise_current_error()
449 except Error:
450 pass
451 raise AttributeError("No such attribute")
452
453 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500454 for i in range(_lib.X509_NAME_entry_count(self._name)):
455 ent = _lib.X509_NAME_get_entry(self._name, i)
456 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
457 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800458 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500459 ent = _lib.X509_NAME_delete_entry(self._name, i)
460 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800461 break
462
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500463 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800464 value = value.encode('utf-8')
465
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500466 add_result = _lib.X509_NAME_add_entry_by_NID(
467 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800468 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500469 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800470
471
472 def __getattr__(self, name):
473 """
474 Find attribute. An X509Name object has the following attributes:
475 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
476 organization (alias O), organizationalUnit (alias OU), commonName (alias
477 CN) and more...
478 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500479 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500480 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800481 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
482 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
483 # push something onto the error queue. If we don't clean that up
484 # now, someone else will bump into it later and be quite confused.
485 # See lp#314814.
486 try:
487 _raise_current_error()
488 except Error:
489 pass
490 return super(X509Name, self).__getattr__(name)
491
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500492 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800493 if entry_index == -1:
494 return None
495
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500496 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
497 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800498
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500499 result_buffer = _ffi.new("unsigned char**")
500 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800501 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500502 # TODO: This is untested.
503 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800504
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700505 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500506 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700507 finally:
508 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500509 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800510 return result
511
512
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500513 def _cmp(op):
514 def f(self, other):
515 if not isinstance(other, X509Name):
516 return NotImplemented
517 result = _lib.X509_NAME_cmp(self._name, other._name)
518 return op(result, 0)
519 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800520
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500521 __eq__ = _cmp(__eq__)
522 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800523
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500524 __lt__ = _cmp(__lt__)
525 __le__ = _cmp(__le__)
526
527 __gt__ = _cmp(__gt__)
528 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800529
530 def __repr__(self):
531 """
532 String representation of an X509Name
533 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500534 result_buffer = _ffi.new("char[]", 512);
535 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800536 self._name, result_buffer, len(result_buffer))
537
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500538 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500539 # TODO: This is untested.
540 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800541
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500542 return "<X509Name object '%s'>" % (
543 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800544
545
546 def hash(self):
547 """
548 Return the hash value of this name
549
550 :return: None
551 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500552 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800553
554
555 def der(self):
556 """
557 Return the DER encoding of this name
558
559 :return: A :py:class:`bytes` instance giving the DER encoded form of
560 this name.
561 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500562 result_buffer = _ffi.new('unsigned char**')
563 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800564 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500565 # TODO: This is untested.
566 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800567
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500568 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
569 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800570 return string_result
571
572
573 def get_components(self):
574 """
575 Returns the split-up components of this name.
576
577 :return: List of tuples (name, value).
578 """
579 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500580 for i in range(_lib.X509_NAME_entry_count(self._name)):
581 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800582
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500583 fname = _lib.X509_NAME_ENTRY_get_object(ent)
584 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500586 nid = _lib.OBJ_obj2nid(fname)
587 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800588
589 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500590 _ffi.string(name),
591 _ffi.string(
592 _lib.ASN1_STRING_data(fval),
593 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800594
595 return result
596X509NameType = X509Name
597
598
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800599class X509Extension(object):
600 def __init__(self, type_name, critical, value, subject=None, issuer=None):
601 """
602 :param typename: The name of the extension to create.
603 :type typename: :py:data:`str`
604
605 :param critical: A flag indicating whether this is a critical extension.
606
607 :param value: The value of the extension.
608 :type value: :py:data:`str`
609
610 :param subject: Optional X509 cert to use as subject.
611 :type subject: :py:class:`X509`
612
613 :param issuer: Optional X509 cert to use as issuer.
614 :type issuer: :py:class:`X509`
615
616 :return: The X509Extension object
617 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500618 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800619
620 # A context is necessary for any extension which uses the r2i conversion
621 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
622 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500623 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800624
625 # We have no configuration database - but perhaps we should (some
626 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500627 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800628
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800629 # Initialize the subject and issuer, if appropriate. ctx is a local,
630 # and as far as I can tell none of the X509V3_* APIs invoked here steal
631 # any references, so no need to mess with reference counts or duplicates.
632 if issuer is not None:
633 if not isinstance(issuer, X509):
634 raise TypeError("issuer must be an X509 instance")
635 ctx.issuer_cert = issuer._x509
636 if subject is not None:
637 if not isinstance(subject, X509):
638 raise TypeError("subject must be an X509 instance")
639 ctx.subject_cert = subject._x509
640
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800641 if critical:
642 # There are other OpenSSL APIs which would let us pass in critical
643 # separately, but they're harder to use, and since value is already
644 # a pile of crappy junk smuggling a ton of utterly important
645 # structured data, what's the point of trying to avoid nasty stuff
646 # with strings? (However, X509V3_EXT_i2d in particular seems like it
647 # would be a better API to invoke. I do not know where to get the
648 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500649 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800650
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500651 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
652 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800653 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500654 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800655
656
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400657 @property
658 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500659 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400660
661 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500662 _lib.GEN_EMAIL: "email",
663 _lib.GEN_DNS: "DNS",
664 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400665 }
666
667 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500668 method = _lib.X509V3_EXT_get(self._extension)
669 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500670 # TODO: This is untested.
671 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400672 payload = self._extension.value.data
673 length = self._extension.value.length
674
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500675 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400676 payloadptr[0] = payload
677
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500678 if method.it != _ffi.NULL:
679 ptr = _lib.ASN1_ITEM_ptr(method.it)
680 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
681 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400682 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500683 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400684 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500685 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400686
687 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500688 for i in range(_lib.sk_GENERAL_NAME_num(names)):
689 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400690 try:
691 label = self._prefixes[name.type]
692 except KeyError:
693 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500694 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500695 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400696 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500697 value = _native(
698 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
699 parts.append(label + ":" + value)
700 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400701
702
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800703 def __str__(self):
704 """
705 :return: a nice text representation of the extension
706 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500707 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400708 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800709
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400710 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500711 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800712 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500713 # TODO: This is untested.
714 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800715
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500716 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800717
718
719 def get_critical(self):
720 """
721 Returns the critical field of the X509Extension
722
723 :return: The critical field.
724 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500725 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800726
727
728 def get_short_name(self):
729 """
730 Returns the short version of the type name of the X509Extension
731
732 :return: The short type name.
733 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500734 obj = _lib.X509_EXTENSION_get_object(self._extension)
735 nid = _lib.OBJ_obj2nid(obj)
736 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800737
738
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800739 def get_data(self):
740 """
741 Returns the data of the X509Extension
742
743 :return: A :py:data:`str` giving the X509Extension's ASN.1 encoded data.
744 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500745 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
746 string_result = _ffi.cast('ASN1_STRING*', octet_result)
747 char_result = _lib.ASN1_STRING_data(string_result)
748 result_length = _lib.ASN1_STRING_length(string_result)
749 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800750
751X509ExtensionType = X509Extension
752
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800753
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800754class X509Req(object):
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800755 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500756 req = _lib.X509_REQ_new()
757 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800758
759
760 def set_pubkey(self, pkey):
761 """
762 Set the public key of the certificate request
763
764 :param pkey: The public key to use
765 :return: None
766 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500767 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800768 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500769 # TODO: This is untested.
770 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800771
772
773 def get_pubkey(self):
774 """
775 Get the public key from the certificate request
776
777 :return: The public key
778 """
779 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500780 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
781 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500782 # TODO: This is untested.
783 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500784 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800785 pkey._only_public = True
786 return pkey
787
788
789 def set_version(self, version):
790 """
791 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
792 request.
793
794 :param version: The version number
795 :return: None
796 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500797 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800798 if not set_result:
799 _raise_current_error()
800
801
802 def get_version(self):
803 """
804 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
805 request.
806
807 :return: an integer giving the value of the version subfield
808 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500809 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800810
811
812 def get_subject(self):
813 """
814 Create an X509Name object for the subject of the certificate request
815
816 :return: An X509Name object
817 """
818 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500819 name._name = _lib.X509_REQ_get_subject_name(self._req)
820 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500821 # TODO: This is untested.
822 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800823
824 # The name is owned by the X509Req structure. As long as the X509Name
825 # Python object is alive, keep the X509Req Python object alive.
826 name._owner = self
827
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800828 return name
829
830
831 def add_extensions(self, extensions):
832 """
833 Add extensions to the request.
834
835 :param extensions: a sequence of X509Extension objects
836 :return: None
837 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500838 stack = _lib.sk_X509_EXTENSION_new_null()
839 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500840 # TODO: This is untested.
841 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800842
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500843 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800844
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800845 for ext in extensions:
846 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800847 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800848
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800849 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500850 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800851
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500852 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800853 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500854 # TODO: This is untested.
855 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800856
857
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800858 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800859 """
860 Get extensions to the request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800861
Jean-Paul Calderoneda3e6c62014-03-02 08:06:11 -0500862 :return: A :py:class:`list` of :py:class:`X509Extension` objects.
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800863 """
864 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500865 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500866 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800867 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500868 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800869 exts.append(ext)
870 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800871
872
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800873 def sign(self, pkey, digest):
874 """
875 Sign the certificate request using the supplied key and digest
876
877 :param pkey: The key to sign with
878 :param digest: The message digest to use
879 :return: None
880 """
881 if pkey._only_public:
882 raise ValueError("Key has only public part")
883
884 if not pkey._initialized:
885 raise ValueError("Key is uninitialized")
886
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500887 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500888 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889 raise ValueError("No such digest method")
890
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500891 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800892 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500893 # TODO: This is untested.
894 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800895
896
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800897 def verify(self, pkey):
898 """
899 Verifies a certificate request using the supplied public key
900
901 :param key: a public key
902 :return: True if the signature is correct.
903
904 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
905 problem verifying the signature.
906 """
907 if not isinstance(pkey, PKey):
908 raise TypeError("pkey must be a PKey instance")
909
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500910 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800911 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500912 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800913
914 return result
915
916
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800917X509ReqType = X509Req
918
919
920
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800921class X509(object):
922 def __init__(self):
923 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500924 x509 = _lib.X509_new()
925 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800926
927
928 def set_version(self, version):
929 """
930 Set version number of the certificate
931
932 :param version: The version number
933 :type version: :py:class:`int`
934
935 :return: None
936 """
937 if not isinstance(version, int):
938 raise TypeError("version must be an integer")
939
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500940 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800941
942
943 def get_version(self):
944 """
945 Return version number of the certificate
946
947 :return: Version number as a Python integer
948 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500949 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800950
951
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800952 def get_pubkey(self):
953 """
954 Get the public key of the certificate
955
956 :return: The public key
957 """
958 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500959 pkey._pkey = _lib.X509_get_pubkey(self._x509)
960 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800961 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500962 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800963 pkey._only_public = True
964 return pkey
965
966
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800967 def set_pubkey(self, pkey):
968 """
969 Set the public key of the certificate
970
971 :param pkey: The public key
972
973 :return: None
974 """
975 if not isinstance(pkey, PKey):
976 raise TypeError("pkey must be a PKey instance")
977
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500978 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800979 if not set_result:
980 _raise_current_error()
981
982
983 def sign(self, pkey, digest):
984 """
985 Sign the certificate using the supplied key and digest
986
987 :param pkey: The key to sign with
988 :param digest: The message digest to use
989 :return: None
990 """
991 if not isinstance(pkey, PKey):
992 raise TypeError("pkey must be a PKey instance")
993
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800994 if pkey._only_public:
995 raise ValueError("Key only has public part")
996
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800997 if not pkey._initialized:
998 raise ValueError("Key is uninitialized")
999
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001000 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001001 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001002 raise ValueError("No such digest method")
1003
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001004 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001005 if not sign_result:
1006 _raise_current_error()
1007
1008
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001009 def get_signature_algorithm(self):
1010 """
1011 Retrieve the signature algorithm used in the certificate
1012
1013 :return: A byte string giving the name of the signature algorithm used in
1014 the certificate.
1015 :raise ValueError: If the signature algorithm is undefined.
1016 """
1017 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001018 nid = _lib.OBJ_obj2nid(alg)
1019 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001020 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001021 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001022
1023
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001024 def digest(self, digest_name):
1025 """
1026 Return the digest of the X509 object.
1027
1028 :param digest_name: The name of the digest algorithm to use.
1029 :type digest_name: :py:class:`bytes`
1030
1031 :return: The digest of the object
1032 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001033 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001034 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001035 raise ValueError("No such digest method")
1036
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001037 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1038 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001039 result_length[0] = len(result_buffer)
1040
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001041 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001042 self._x509, digest, result_buffer, result_length)
1043
1044 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001045 # TODO: This is untested.
1046 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001047
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001048 return b":".join([
1049 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001050 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001051
1052
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001053 def subject_name_hash(self):
1054 """
1055 Return the hash of the X509 subject.
1056
1057 :return: The hash of the subject.
1058 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001059 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001060
1061
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001062 def set_serial_number(self, serial):
1063 """
1064 Set serial number of the certificate
1065
1066 :param serial: The serial number
1067 :type serial: :py:class:`int`
1068
1069 :return: None
1070 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001071 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001072 raise TypeError("serial must be an integer")
1073
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001074 hex_serial = hex(serial)[2:]
1075 if not isinstance(hex_serial, bytes):
1076 hex_serial = hex_serial.encode('ascii')
1077
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001078 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001079
1080 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1081 # it. If bignum is still NULL after this call, then the return value is
1082 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001083 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001084
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001085 if bignum_serial[0] == _ffi.NULL:
1086 set_result = _lib.ASN1_INTEGER_set(
1087 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001088 if set_result:
1089 # TODO Not tested
1090 _raise_current_error()
1091 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001092 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1093 _lib.BN_free(bignum_serial[0])
1094 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001095 # TODO Not tested
1096 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001097 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1098 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001099 if not set_result:
1100 # TODO Not tested
1101 _raise_current_error()
1102
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001103
1104 def get_serial_number(self):
1105 """
1106 Return serial number of the certificate
1107
1108 :return: Serial number as a Python integer
1109 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001110 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1111 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001112 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001113 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001114 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001115 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001116 serial = int(hexstring_serial, 16)
1117 return serial
1118 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001119 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001120 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001121 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001122
1123
1124 def gmtime_adj_notAfter(self, amount):
1125 """
1126 Adjust the time stamp for when the certificate stops being valid
1127
1128 :param amount: The number of seconds by which to adjust the ending
1129 validity time.
1130 :type amount: :py:class:`int`
1131
1132 :return: None
1133 """
1134 if not isinstance(amount, int):
1135 raise TypeError("amount must be an integer")
1136
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001137 notAfter = _lib.X509_get_notAfter(self._x509)
1138 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001139
1140
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001141 def gmtime_adj_notBefore(self, amount):
1142 """
1143 Change the timestamp for when the certificate starts being valid to the current
1144 time plus an offset.
1145
1146 :param amount: The number of seconds by which to adjust the starting validity
1147 time.
1148 :return: None
1149 """
1150 if not isinstance(amount, int):
1151 raise TypeError("amount must be an integer")
1152
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001153 notBefore = _lib.X509_get_notBefore(self._x509)
1154 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001155
1156
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001157 def has_expired(self):
1158 """
1159 Check whether the certificate has expired.
1160
1161 :return: True if the certificate has expired, false otherwise
1162 """
1163 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001164 notAfter = _lib.X509_get_notAfter(self._x509)
1165 return _lib.ASN1_UTCTIME_cmp_time_t(
1166 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001167
1168
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001169 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001170 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001171
1172
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001173 def get_notBefore(self):
1174 """
1175 Retrieve the time stamp for when the certificate starts being valid
1176
1177 :return: A string giving the timestamp, in the format::
1178
1179 YYYYMMDDhhmmssZ
1180 YYYYMMDDhhmmss+hhmm
1181 YYYYMMDDhhmmss-hhmm
1182
1183 or None if there is no value set.
1184 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001185 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001186
1187
1188 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001189 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001190
1191
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001192 def set_notBefore(self, when):
1193 """
1194 Set the time stamp for when the certificate starts being valid
1195
1196 :param when: A string giving the timestamp, in the format:
1197
1198 YYYYMMDDhhmmssZ
1199 YYYYMMDDhhmmss+hhmm
1200 YYYYMMDDhhmmss-hhmm
1201 :type when: :py:class:`bytes`
1202
1203 :return: None
1204 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001205 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001206
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001207
1208 def get_notAfter(self):
1209 """
1210 Retrieve the time stamp for when the certificate stops being valid
1211
1212 :return: A string giving the timestamp, in the format::
1213
1214 YYYYMMDDhhmmssZ
1215 YYYYMMDDhhmmss+hhmm
1216 YYYYMMDDhhmmss-hhmm
1217
1218 or None if there is no value set.
1219 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001220 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001221
1222
1223 def set_notAfter(self, when):
1224 """
1225 Set the time stamp for when the certificate stops being valid
1226
1227 :param when: A string giving the timestamp, in the format:
1228
1229 YYYYMMDDhhmmssZ
1230 YYYYMMDDhhmmss+hhmm
1231 YYYYMMDDhhmmss-hhmm
1232 :type when: :py:class:`bytes`
1233
1234 :return: None
1235 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001236 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001237
1238
1239 def _get_name(self, which):
1240 name = X509Name.__new__(X509Name)
1241 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001242 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001243 # TODO: This is untested.
1244 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001245
1246 # The name is owned by the X509 structure. As long as the X509Name
1247 # Python object is alive, keep the X509 Python object alive.
1248 name._owner = self
1249
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001250 return name
1251
1252
1253 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001254 if not isinstance(name, X509Name):
1255 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001256 set_result = which(self._x509, name._name)
1257 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001258 # TODO: This is untested.
1259 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001260
1261
1262 def get_issuer(self):
1263 """
1264 Create an X509Name object for the issuer of the certificate
1265
1266 :return: An X509Name object
1267 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001268 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001269
1270
1271 def set_issuer(self, issuer):
1272 """
1273 Set the issuer of the certificate
1274
1275 :param issuer: The issuer name
1276 :type issuer: :py:class:`X509Name`
1277
1278 :return: None
1279 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001280 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001281
1282
1283 def get_subject(self):
1284 """
1285 Create an X509Name object for the subject of the certificate
1286
1287 :return: An X509Name object
1288 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001289 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001290
1291
1292 def set_subject(self, subject):
1293 """
1294 Set the subject of the certificate
1295
1296 :param subject: The subject name
1297 :type subject: :py:class:`X509Name`
1298 :return: None
1299 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001300 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001301
1302
1303 def get_extension_count(self):
1304 """
1305 Get the number of extensions on the certificate.
1306
1307 :return: The number of extensions as an integer.
1308 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001309 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001310
1311
1312 def add_extensions(self, extensions):
1313 """
1314 Add extensions to the certificate.
1315
1316 :param extensions: a sequence of X509Extension objects
1317 :return: None
1318 """
1319 for ext in extensions:
1320 if not isinstance(ext, X509Extension):
1321 raise ValueError("One of the elements is not an X509Extension")
1322
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001323 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001324 if not add_result:
1325 _raise_current_error()
1326
1327
1328 def get_extension(self, index):
1329 """
1330 Get a specific extension of the certificate by index.
1331
1332 :param index: The index of the extension to retrieve.
1333 :return: The X509Extension object at the specified index.
1334 """
1335 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001336 ext._extension = _lib.X509_get_ext(self._x509, index)
1337 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001338 raise IndexError("extension index out of bounds")
1339
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001340 extension = _lib.X509_EXTENSION_dup(ext._extension)
1341 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001342 return ext
1343
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001344X509Type = X509
1345
1346
1347
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001348class X509Store(object):
1349 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001350 store = _lib.X509_STORE_new()
1351 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001352
1353
1354 def add_cert(self, cert):
1355 if not isinstance(cert, X509):
1356 raise TypeError()
1357
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001358 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001359 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001360 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001361
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001362
1363X509StoreType = X509Store
1364
1365
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001366class X509StoreContextError(Exception):
1367 """
1368 An error occurred while verifying a certificate using
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001369 `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001370
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001371 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001372 :type cert: :class:`X509`
1373
1374 """
1375 def __init__(self, message, certificate):
1376 super(X509StoreContextError, self).__init__(message)
1377 self.certificate = certificate
1378
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001379
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001380class X509StoreContext(object):
1381 """
1382 An X.509 store context.
1383
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001384 An :py:class:`X509StoreContext` is used to define some of the criteria for
1385 certificate verification. The information encapsulated in this object
1386 includes, but is not limited to, a set of trusted certificates,
1387 verification parameters, and revoked certificates.
1388
1389 Of these, only the set of trusted certificates is currently exposed.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001390
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001391 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1392 instance. It is dynamically allocated and automatically garbage
1393 collected.
1394
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001395 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001396
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001397 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001398 """
1399
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001400 def __init__(self, store, certificate):
1401 """
1402 :param X509Store store: The certificates which will be trusted for the
1403 purposes of any verifications.
1404
1405 :param X509 certificate: The certificate to be verified.
1406 """
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001407 store_ctx = _lib.X509_STORE_CTX_new()
1408 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1409 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001410 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001411 # Make the store context available for use after instantiating this
1412 # class by initializing it now. Per testing, subsequent calls to
1413 # :py:meth:`_init` have no adverse affect.
1414 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001415
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001416
1417 def _init(self):
1418 """
1419 Set up the store context for a subsequent verification operation.
1420 """
1421 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1422 if ret <= 0:
1423 _raise_current_error()
1424
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001425
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001426 def _cleanup(self):
1427 """
1428 Internally cleans up the store context.
1429
1430 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001431 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001432 """
1433 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1434
1435
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001436 def _exception_from_context(self):
1437 """
1438 Convert an OpenSSL native context error failure into a Python
1439 exception.
1440
1441 When a call to native OpenSSL X509_verify_cert fails, additonal information
1442 about the failure can be obtained from the store context.
1443 """
1444 errors = [
1445 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1446 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1447 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1448 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1449 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001450 # A context error should always be associated with a certificate, so we
1451 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001452 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001453 _cert = _lib.X509_dup(_x509)
1454 pycert = X509.__new__(X509)
1455 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001456 return X509StoreContextError(errors, pycert)
1457
1458
Stephen Holsapple46a09252015-02-12 14:45:43 -08001459 def set_store(self, store):
1460 """
1461 Set the context's trust store.
1462
1463 :param X509Store store: The certificates which will be trusted for the
1464 purposes of any *future* verifications.
1465 """
1466 self._store = store
1467
1468
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001469 def verify_certificate(self):
1470 """
1471 Verify a certificate in a context.
1472
1473 :param store_ctx: The :py:class:`X509StoreContext` to verify.
1474 :raises: Error
1475 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001476 # Always re-initialize the store context in case
1477 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001478 self._init()
1479 ret = _lib.X509_verify_cert(self._store_ctx)
1480 self._cleanup()
1481 if ret <= 0:
1482 raise self._exception_from_context()
1483
1484
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001485
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001486def load_certificate(type, buffer):
1487 """
1488 Load a certificate from a buffer
1489
1490 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001491
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001492 :param buffer: The buffer the certificate is stored in
1493 :type buffer: :py:class:`bytes`
1494
1495 :return: The X509 object
1496 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001497 if isinstance(buffer, _text_type):
1498 buffer = buffer.encode("ascii")
1499
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001500 bio = _new_mem_buf(buffer)
1501
1502 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001503 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001504 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001505 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001506 else:
1507 raise ValueError(
1508 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1509
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001510 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001511 _raise_current_error()
1512
1513 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001514 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001515 return cert
1516
1517
1518def dump_certificate(type, cert):
1519 """
1520 Dump a certificate to a buffer
1521
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001522 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1523 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001524 :param cert: The certificate to dump
1525 :return: The buffer with the dumped certificate in
1526 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001527 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001528
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001529 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001530 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001531 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001532 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001533 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001534 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001535 else:
1536 raise ValueError(
1537 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1538 "FILETYPE_TEXT")
1539
1540 return _bio_to_string(bio)
1541
1542
1543
1544def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1545 """
1546 Dump a private key to a buffer
1547
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001548 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1549 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001550 :param pkey: The PKey to dump
1551 :param cipher: (optional) if encrypted PEM format, the cipher to
1552 use
1553 :param passphrase: (optional) if encrypted PEM format, this can be either
1554 the passphrase to use, or a callback for providing the
1555 passphrase.
1556 :return: The buffer with the dumped key in
1557 :rtype: :py:data:`str`
1558 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001559 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001560
1561 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001562 if passphrase is None:
1563 raise TypeError(
1564 "if a value is given for cipher "
1565 "one must also be given for passphrase")
1566 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001567 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001568 raise ValueError("Invalid cipher name")
1569 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001570 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001571
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001572 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001573 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001574 result_code = _lib.PEM_write_bio_PrivateKey(
1575 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001576 helper.callback, helper.callback_args)
1577 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001578 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001579 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001580 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001581 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1582 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001583 # TODO RSA_free(rsa)?
1584 else:
1585 raise ValueError(
1586 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1587 "FILETYPE_TEXT")
1588
1589 if result_code == 0:
1590 _raise_current_error()
1591
1592 return _bio_to_string(bio)
1593
1594
1595
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001596def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001597 copy = _lib.X509_REVOKED_new()
1598 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001599 # TODO: This is untested.
1600 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001601
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001602 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001603 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001604 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001605
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001606 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001607 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001608 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001609
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001610 if original.extensions != _ffi.NULL:
1611 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1612 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1613 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1614 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1615 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001616 copy.extensions = extension_stack
1617
1618 copy.sequence = original.sequence
1619 return copy
1620
1621
1622
1623class Revoked(object):
1624 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1625 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1626 # OCSP_crl_reason_str. We use the latter, just like the command line
1627 # program.
1628 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001629 b"unspecified",
1630 b"keyCompromise",
1631 b"CACompromise",
1632 b"affiliationChanged",
1633 b"superseded",
1634 b"cessationOfOperation",
1635 b"certificateHold",
1636 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001637 ]
1638
1639 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001640 revoked = _lib.X509_REVOKED_new()
1641 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001642
1643
1644 def set_serial(self, hex_str):
1645 """
1646 Set the serial number of a revoked Revoked structure
1647
1648 :param hex_str: The new serial number.
1649 :type hex_str: :py:data:`str`
1650 :return: None
1651 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001652 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1653 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001654 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001655 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001656 if not bn_result:
1657 raise ValueError("bad hex string")
1658
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001659 asn1_serial = _ffi.gc(
1660 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1661 _lib.ASN1_INTEGER_free)
1662 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001663
1664
1665 def get_serial(self):
1666 """
1667 Return the serial number of a Revoked structure
1668
1669 :return: The serial number as a string
1670 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001671 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001672
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001673 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001674 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001675 # TODO: This is untested.
1676 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001677
1678 return _bio_to_string(bio)
1679
1680
1681 def _delete_reason(self):
1682 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001683 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1684 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1685 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1686 _lib.X509_EXTENSION_free(ext)
1687 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001688 break
1689
1690
1691 def set_reason(self, reason):
1692 """
1693 Set the reason of a Revoked object.
1694
1695 If :py:data:`reason` is :py:data:`None`, delete the reason instead.
1696
1697 :param reason: The reason string.
1698 :type reason: :py:class:`str` or :py:class:`NoneType`
1699 :return: None
1700 """
1701 if reason is None:
1702 self._delete_reason()
1703 elif not isinstance(reason, bytes):
1704 raise TypeError("reason must be None or a byte string")
1705 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001706 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001707 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1708
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001709 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1710 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001711 # TODO: This is untested.
1712 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001713 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001714
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001715 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1716 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001717 # TODO: This is untested.
1718 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001719
1720 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001721 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1722 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001723
1724 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001725 # TODO: This is untested.
1726 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001727
1728
1729 def get_reason(self):
1730 """
1731 Return the reason of a Revoked object.
1732
1733 :return: The reason as a string
1734 """
1735 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001736 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1737 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1738 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001739 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001740
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001741 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001742 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001743 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001744 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001745 # TODO: This is untested.
1746 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001747
1748 return _bio_to_string(bio)
1749
1750
1751 def all_reasons(self):
1752 """
1753 Return a list of all the supported reason strings.
1754
1755 :return: A list of reason strings.
1756 """
1757 return self._crl_reasons[:]
1758
1759
1760 def set_rev_date(self, when):
1761 """
1762 Set the revocation timestamp
1763
1764 :param when: A string giving the timestamp, in the format:
1765
1766 YYYYMMDDhhmmssZ
1767 YYYYMMDDhhmmss+hhmm
1768 YYYYMMDDhhmmss-hhmm
1769
1770 :return: None
1771 """
1772 return _set_asn1_time(self._revoked.revocationDate, when)
1773
1774
1775 def get_rev_date(self):
1776 """
1777 Retrieve the revocation date
1778
1779 :return: A string giving the timestamp, in the format:
1780
1781 YYYYMMDDhhmmssZ
1782 YYYYMMDDhhmmss+hhmm
1783 YYYYMMDDhhmmss-hhmm
1784 """
1785 return _get_asn1_time(self._revoked.revocationDate)
1786
1787
1788
1789class CRL(object):
1790 def __init__(self):
1791 """
1792 Create a new empty CRL object.
1793 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001794 crl = _lib.X509_CRL_new()
1795 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001796
1797
1798 def get_revoked(self):
1799 """
1800 Return revoked portion of the CRL structure (by value not reference).
1801
1802 :return: A tuple of Revoked objects.
1803 """
1804 results = []
1805 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001806 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1807 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001808 revoked_copy = _X509_REVOKED_dup(revoked)
1809 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001810 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001811 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001812 if results:
1813 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001814
1815
1816 def add_revoked(self, revoked):
1817 """
1818 Add a revoked (by value not reference) to the CRL structure
1819
1820 :param revoked: The new revoked.
1821 :type revoked: :class:`X509`
1822
1823 :return: None
1824 """
1825 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001826 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001827 # TODO: This is untested.
1828 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001829
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001830 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001831 if add_result == 0:
1832 # TODO: This is untested.
1833 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001834
1835
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001836 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001837 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001838 """
1839 export a CRL as a string
1840
1841 :param cert: Used to sign CRL.
1842 :type cert: :class:`X509`
1843
1844 :param key: Used to sign CRL.
1845 :type key: :class:`PKey`
1846
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001847 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1848 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001849
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001850 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001851
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001852 :param bytes digest: The name of the message digest to use (eg
1853 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001854
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001855 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001856 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001857 if not isinstance(cert, X509):
1858 raise TypeError("cert must be an X509 instance")
1859 if not isinstance(key, PKey):
1860 raise TypeError("key must be a PKey instance")
1861 if not isinstance(type, int):
1862 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001863
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001864 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001865 _warn(
1866 "The default message digest (md5) is deprecated. "
1867 "Pass the name of a message digest explicitly.",
1868 category=DeprecationWarning,
1869 stacklevel=2,
1870 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001871 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001872
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001873 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001874 if digest_obj == _ffi.NULL:
1875 raise ValueError("No such digest method")
1876
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001877 bio = _lib.BIO_new(_lib.BIO_s_mem())
1878 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001879 # TODO: This is untested.
1880 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001881
1882 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001883 sometime = _lib.ASN1_TIME_new()
1884 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001885 # TODO: This is untested.
1886 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001887
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001888 _lib.X509_gmtime_adj(sometime, 0)
1889 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001890
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001891 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1892 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001893
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001894 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001895
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001896 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001897 if not sign_result:
1898 _raise_current_error()
1899
1900 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001901 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001902 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001903 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001904 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001905 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001906 else:
1907 raise ValueError(
1908 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1909
1910 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001911 # TODO: This is untested.
1912 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001913
1914 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001915CRLType = CRL
1916
1917
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001918
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001919class PKCS7(object):
1920 def type_is_signed(self):
1921 """
1922 Check if this NID_pkcs7_signed object
1923
1924 :return: True if the PKCS7 is of type signed
1925 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001926 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001927 return True
1928 return False
1929
1930
1931 def type_is_enveloped(self):
1932 """
1933 Check if this NID_pkcs7_enveloped object
1934
1935 :returns: True if the PKCS7 is of type enveloped
1936 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001937 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001938 return True
1939 return False
1940
1941
1942 def type_is_signedAndEnveloped(self):
1943 """
1944 Check if this NID_pkcs7_signedAndEnveloped object
1945
1946 :returns: True if the PKCS7 is of type signedAndEnveloped
1947 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001948 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001949 return True
1950 return False
1951
1952
1953 def type_is_data(self):
1954 """
1955 Check if this NID_pkcs7_data object
1956
1957 :return: True if the PKCS7 is of type data
1958 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001959 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001960 return True
1961 return False
1962
1963
1964 def get_type_name(self):
1965 """
1966 Returns the type name of the PKCS7 structure
1967
1968 :return: A string with the typename
1969 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001970 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1971 string_type = _lib.OBJ_nid2sn(nid)
1972 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001973
1974PKCS7Type = PKCS7
1975
1976
1977
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001978class PKCS12(object):
1979 def __init__(self):
1980 self._pkey = None
1981 self._cert = None
1982 self._cacerts = None
1983 self._friendlyname = None
1984
1985
1986 def get_certificate(self):
1987 """
1988 Return certificate portion of the PKCS12 structure
1989
1990 :return: X509 object containing the certificate
1991 """
1992 return self._cert
1993
1994
1995 def set_certificate(self, cert):
1996 """
1997 Replace the certificate portion of the PKCS12 structure
1998
1999 :param cert: The new certificate.
2000 :type cert: :py:class:`X509` or :py:data:`None`
2001 :return: None
2002 """
2003 if not isinstance(cert, X509):
2004 raise TypeError("cert must be an X509 instance")
2005 self._cert = cert
2006
2007
2008 def get_privatekey(self):
2009 """
2010 Return private key portion of the PKCS12 structure
2011
2012 :returns: PKey object containing the private key
2013 """
2014 return self._pkey
2015
2016
2017 def set_privatekey(self, pkey):
2018 """
2019 Replace or set the certificate portion of the PKCS12 structure
2020
2021 :param pkey: The new private key.
2022 :type pkey: :py:class:`PKey`
2023 :return: None
2024 """
2025 if not isinstance(pkey, PKey):
2026 raise TypeError("pkey must be a PKey instance")
2027 self._pkey = pkey
2028
2029
2030 def get_ca_certificates(self):
2031 """
2032 Return CA certificates within of the PKCS12 object
2033
2034 :return: A newly created tuple containing the CA certificates in the chain,
2035 if any are present, or None if no CA certificates are present.
2036 """
2037 if self._cacerts is not None:
2038 return tuple(self._cacerts)
2039
2040
2041 def set_ca_certificates(self, cacerts):
2042 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002043 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002044
2045 :param cacerts: The new CA certificates.
2046 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2047 :return: None
2048 """
2049 if cacerts is None:
2050 self._cacerts = None
2051 else:
2052 cacerts = list(cacerts)
2053 for cert in cacerts:
2054 if not isinstance(cert, X509):
2055 raise TypeError("iterable must only contain X509 instances")
2056 self._cacerts = cacerts
2057
2058
2059 def set_friendlyname(self, name):
2060 """
2061 Replace or set the certificate portion of the PKCS12 structure
2062
2063 :param name: The new friendly name.
2064 :type name: :py:class:`bytes`
2065 :return: None
2066 """
2067 if name is None:
2068 self._friendlyname = None
2069 elif not isinstance(name, bytes):
2070 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2071 self._friendlyname = name
2072
2073
2074 def get_friendlyname(self):
2075 """
2076 Return friendly name portion of the PKCS12 structure
2077
2078 :returns: String containing the friendlyname
2079 """
2080 return self._friendlyname
2081
2082
2083 def export(self, passphrase=None, iter=2048, maciter=1):
2084 """
2085 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2086
2087 :param passphrase: used to encrypt the PKCS12
2088 :type passphrase: :py:data:`bytes`
2089
2090 :param iter: How many times to repeat the encryption
2091 :type iter: :py:data:`int`
2092
2093 :param maciter: How many times to repeat the MAC
2094 :type maciter: :py:data:`int`
2095
2096 :return: The string containing the PKCS12
2097 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002098 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002099
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002100 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002101 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002102 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002103 cacerts = _lib.sk_X509_new_null()
2104 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002105 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002106 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002107
2108 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002109 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002110
2111 friendlyname = self._friendlyname
2112 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002113 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002114
2115 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002116 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002117 else:
2118 pkey = self._pkey._pkey
2119
2120 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002121 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002122 else:
2123 cert = self._cert._x509
2124
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002125 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002126 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002127 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2128 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002129 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002130 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002131 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002132 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002133
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002134 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002135 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002136 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002137
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002138PKCS12Type = PKCS12
2139
2140
2141
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002142class NetscapeSPKI(object):
2143 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002144 spki = _lib.NETSCAPE_SPKI_new()
2145 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002146
2147
2148 def sign(self, pkey, digest):
2149 """
2150 Sign the certificate request using the supplied key and digest
2151
2152 :param pkey: The key to sign with
2153 :param digest: The message digest to use
2154 :return: None
2155 """
2156 if pkey._only_public:
2157 raise ValueError("Key has only public part")
2158
2159 if not pkey._initialized:
2160 raise ValueError("Key is uninitialized")
2161
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002162 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002163 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002164 raise ValueError("No such digest method")
2165
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002166 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002167 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002168 # TODO: This is untested.
2169 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002170
2171
2172 def verify(self, key):
2173 """
2174 Verifies a certificate request using the supplied public key
2175
2176 :param key: a public key
2177 :return: True if the signature is correct.
2178 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2179 problem verifying the signature.
2180 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002181 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002182 if answer <= 0:
2183 _raise_current_error()
2184 return True
2185
2186
2187 def b64_encode(self):
2188 """
2189 Generate a base64 encoded string from an SPKI
2190
2191 :return: The base64 encoded string
2192 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002193 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2194 result = _ffi.string(encoded)
2195 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002196 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002197
2198
2199 def get_pubkey(self):
2200 """
2201 Get the public key of the certificate
2202
2203 :return: The public key
2204 """
2205 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002206 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2207 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002208 # TODO: This is untested.
2209 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002210 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002211 pkey._only_public = True
2212 return pkey
2213
2214
2215 def set_pubkey(self, pkey):
2216 """
2217 Set the public key of the certificate
2218
2219 :param pkey: The public key
2220 :return: None
2221 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002222 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002223 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002224 # TODO: This is untested.
2225 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002226NetscapeSPKIType = NetscapeSPKI
2227
2228
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002229class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002230 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002231 if type != FILETYPE_PEM and passphrase is not None:
2232 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002233 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002234 self._more_args = more_args
2235 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002236 self._problems = []
2237
2238
2239 @property
2240 def callback(self):
2241 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002242 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002243 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002244 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002245 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002246 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002247 else:
2248 raise TypeError("Last argument must be string or callable")
2249
2250
2251 @property
2252 def callback_args(self):
2253 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002254 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002255 elif isinstance(self._passphrase, bytes):
2256 return self._passphrase
2257 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002258 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002259 else:
2260 raise TypeError("Last argument must be string or callable")
2261
2262
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002263 def raise_if_problem(self, exceptionType=Error):
2264 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002265 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002266 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002267 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002268 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002269 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002270 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002271
2272
2273 def _read_passphrase(self, buf, size, rwflag, userdata):
2274 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002275 if self._more_args:
2276 result = self._passphrase(size, rwflag, userdata)
2277 else:
2278 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002279 if not isinstance(result, bytes):
2280 raise ValueError("String expected")
2281 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002282 if self._truncate:
2283 result = result[:size]
2284 else:
2285 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002286 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002287 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002288 return len(result)
2289 except Exception as e:
2290 self._problems.append(e)
2291 return 0
2292
2293
2294
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002295def load_privatekey(type, buffer, passphrase=None):
2296 """
2297 Load a private key from a buffer
2298
2299 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2300 :param buffer: The buffer the key is stored in
2301 :param passphrase: (optional) if encrypted PEM format, this can be
2302 either the passphrase to use, or a callback for
2303 providing the passphrase.
2304
2305 :return: The PKey object
2306 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002307 if isinstance(buffer, _text_type):
2308 buffer = buffer.encode("ascii")
2309
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002310 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002311
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002312 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002313 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002314 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2315 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002316 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002317 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002318 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002319 else:
2320 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2321
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002322 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002323 _raise_current_error()
2324
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002325 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002326 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002327 return pkey
2328
2329
2330
2331def dump_certificate_request(type, req):
2332 """
2333 Dump a certificate request to a buffer
2334
2335 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2336 :param req: The certificate request to dump
2337 :return: The buffer with the dumped certificate request in
2338 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002339 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002340
2341 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002342 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002343 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002344 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002345 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002346 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002347 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002348 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002349
2350 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002351 # TODO: This is untested.
2352 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002353
2354 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002355
2356
2357
2358def load_certificate_request(type, buffer):
2359 """
2360 Load a certificate request from a buffer
2361
2362 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2363 :param buffer: The buffer the certificate request is stored in
2364 :return: The X509Req object
2365 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002366 if isinstance(buffer, _text_type):
2367 buffer = buffer.encode("ascii")
2368
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002369 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002370
2371 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002372 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002373 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002374 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002375 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002376 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002377
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002378 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002379 # TODO: This is untested.
2380 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002381
2382 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002383 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002384 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002385
2386
2387
2388def sign(pkey, data, digest):
2389 """
2390 Sign data with a digest
2391
2392 :param pkey: Pkey to sign with
2393 :param data: data to be signed
2394 :param digest: message digest to use
2395 :return: signature
2396 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002397 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002398
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002399 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002400 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002401 raise ValueError("No such digest method")
2402
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002403 md_ctx = _ffi.new("EVP_MD_CTX*")
2404 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002405
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002406 _lib.EVP_SignInit(md_ctx, digest_obj)
2407 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002408
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002409 signature_buffer = _ffi.new("unsigned char[]", 512)
2410 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002411 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002412 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002413 md_ctx, signature_buffer, signature_length, pkey._pkey)
2414
2415 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002416 # TODO: This is untested.
2417 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002418
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002419 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002420
2421
2422
2423def verify(cert, signature, data, digest):
2424 """
2425 Verify a signature
2426
2427 :param cert: signing certificate (X509 object)
2428 :param signature: signature returned by sign function
2429 :param data: data to be verified
2430 :param digest: message digest to use
2431 :return: None if the signature is correct, raise exception otherwise
2432 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002433 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002434
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002435 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002436 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002437 raise ValueError("No such digest method")
2438
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002439 pkey = _lib.X509_get_pubkey(cert._x509)
2440 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002441 # TODO: This is untested.
2442 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002443 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002444
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002445 md_ctx = _ffi.new("EVP_MD_CTX*")
2446 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002447
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002448 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2449 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2450 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002451
2452 if verify_result != 1:
2453 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002454
2455
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002456def load_crl(type, buffer):
2457 """
2458 Load a certificate revocation list from a buffer
2459
2460 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2461 :param buffer: The buffer the CRL is stored in
2462
2463 :return: The PKey object
2464 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002465 if isinstance(buffer, _text_type):
2466 buffer = buffer.encode("ascii")
2467
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002468 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002469
2470 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002471 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002472 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002473 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002474 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002475 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2476
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002477 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002478 _raise_current_error()
2479
2480 result = CRL.__new__(CRL)
2481 result._crl = crl
2482 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002483
2484
2485
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002486def load_pkcs7_data(type, buffer):
2487 """
2488 Load pkcs7 data from a buffer
2489
2490 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2491 :param buffer: The buffer with the pkcs7 data.
2492 :return: The PKCS7 object
2493 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002494 if isinstance(buffer, _text_type):
2495 buffer = buffer.encode("ascii")
2496
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002497 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002498
2499 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002500 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002501 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002502 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002503 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002504 # TODO: This is untested.
2505 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002506 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2507
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002508 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002509 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002510
2511 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002512 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002513 return pypkcs7
2514
2515
2516
Stephen Holsapple38482622014-04-05 20:29:34 -07002517def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002518 """
2519 Load a PKCS12 object from a buffer
2520
2521 :param buffer: The buffer the certificate is stored in
2522 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2523 :returns: The PKCS12 object
2524 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002525 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002526
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002527 if isinstance(buffer, _text_type):
2528 buffer = buffer.encode("ascii")
2529
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002530 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002531
Stephen Holsapple38482622014-04-05 20:29:34 -07002532 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2533 # password based encryption no password and a zero length password are two
2534 # different things, but OpenSSL implementation will try both to figure out
2535 # which one works.
2536 if not passphrase:
2537 passphrase = _ffi.NULL
2538
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002539 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2540 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002541 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002542 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002543
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002544 pkey = _ffi.new("EVP_PKEY**")
2545 cert = _ffi.new("X509**")
2546 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002547
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002548 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002549 if not parse_result:
2550 _raise_current_error()
2551
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002552 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002553
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002554 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2555 # queue for no particular reason. This error isn't interesting to anyone
2556 # outside this function. It's not even interesting to us. Get rid of it.
2557 try:
2558 _raise_current_error()
2559 except Error:
2560 pass
2561
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002562 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002563 pykey = None
2564 else:
2565 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002566 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002567
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002568 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002569 pycert = None
2570 friendlyname = None
2571 else:
2572 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002573 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002574
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002575 friendlyname_length = _ffi.new("int*")
2576 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2577 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2578 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002579 friendlyname = None
2580
2581 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002582 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002583 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002584 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002585 pycacerts.append(pycacert)
2586 if not pycacerts:
2587 pycacerts = None
2588
2589 pkcs12 = PKCS12.__new__(PKCS12)
2590 pkcs12._pkey = pykey
2591 pkcs12._cert = pycert
2592 pkcs12._cacerts = pycacerts
2593 pkcs12._friendlyname = friendlyname
2594 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002595
2596
2597def _initialize_openssl_threads(get_ident, Lock):
2598 import _ssl
2599 return
2600
2601 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2602
2603 def locking_function(mode, index, filename, line):
2604 if mode & _lib.CRYPTO_LOCK:
2605 locks[index].acquire()
2606 else:
2607 locks[index].release()
2608
2609 _lib.CRYPTO_set_id_callback(
2610 _ffi.callback("unsigned long (*)(void)", get_ident))
2611
2612 _lib.CRYPTO_set_locking_callback(
2613 _ffi.callback(
2614 "void (*)(int, int, const char*, int)", locking_function))
2615
2616
2617try:
2618 from thread import get_ident
2619 from threading import Lock
2620except ImportError:
2621 pass
2622else:
2623 _initialize_openssl_threads(get_ident, Lock)
2624 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002625
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002626# There are no direct unit tests for this initialization. It is tested
2627# indirectly since it is necessary for functions like dump_privatekey when
2628# using encryption.
2629#
2630# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2631# and some other similar tests may fail without this (though they may not if
2632# the Python runtime has already done some initialization of the underlying
2633# OpenSSL library (and is linked against the same one that cryptography is
2634# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002635_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002636
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002637# This is similar but exercised mainly by exception_from_error_queue. It calls
2638# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2639_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002640
2641
2642
2643# Set the default string mask to match OpenSSL upstream (since 2005) and
2644# RFC5280 recommendations.
2645_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')