blob: 0350537fed5161b1e1aadcd2836ca6f15ebd0d48 [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.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001842
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001843 :type cert: :class:`X509`
1844
1845 :param key: Used to sign CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001846
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001847 :type key: :class:`PKey`
1848
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001849 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1850 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001851 :param days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001852
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001853 :type days: :py:data:`int`
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001854
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001855 :param bytes digest: The name of the message digest to use (eg
1856 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001857
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001858 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001859 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001860 if not isinstance(cert, X509):
1861 raise TypeError("cert must be an X509 instance")
1862 if not isinstance(key, PKey):
1863 raise TypeError("key must be a PKey instance")
1864 if not isinstance(type, int):
1865 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001866
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001867 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001868 _warn(
1869 "The default message digest (md5) is deprecated. "
1870 "Pass the name of a message digest explicitly.",
1871 category=DeprecationWarning,
1872 stacklevel=2,
1873 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001874 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001875
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001876 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001877 if digest_obj == _ffi.NULL:
1878 raise ValueError("No such digest method")
1879
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001880 bio = _lib.BIO_new(_lib.BIO_s_mem())
1881 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001882 # TODO: This is untested.
1883 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001884
1885 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001886 sometime = _lib.ASN1_TIME_new()
1887 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001888 # TODO: This is untested.
1889 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001890
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001891 _lib.X509_gmtime_adj(sometime, 0)
1892 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001893
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001894 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1895 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001896
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001897 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001898
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001899 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001900 if not sign_result:
1901 _raise_current_error()
1902
1903 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001904 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001905 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001906 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001907 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001908 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001909 else:
1910 raise ValueError(
1911 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1912
1913 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001914 # TODO: This is untested.
1915 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001916
1917 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001918CRLType = CRL
1919
1920
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001921
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001922class PKCS7(object):
1923 def type_is_signed(self):
1924 """
1925 Check if this NID_pkcs7_signed object
1926
1927 :return: True if the PKCS7 is of type signed
1928 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001929 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001930 return True
1931 return False
1932
1933
1934 def type_is_enveloped(self):
1935 """
1936 Check if this NID_pkcs7_enveloped object
1937
1938 :returns: True if the PKCS7 is of type enveloped
1939 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001940 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001941 return True
1942 return False
1943
1944
1945 def type_is_signedAndEnveloped(self):
1946 """
1947 Check if this NID_pkcs7_signedAndEnveloped object
1948
1949 :returns: True if the PKCS7 is of type signedAndEnveloped
1950 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001951 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001952 return True
1953 return False
1954
1955
1956 def type_is_data(self):
1957 """
1958 Check if this NID_pkcs7_data object
1959
1960 :return: True if the PKCS7 is of type data
1961 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001962 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001963 return True
1964 return False
1965
1966
1967 def get_type_name(self):
1968 """
1969 Returns the type name of the PKCS7 structure
1970
1971 :return: A string with the typename
1972 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001973 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1974 string_type = _lib.OBJ_nid2sn(nid)
1975 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001976
1977PKCS7Type = PKCS7
1978
1979
1980
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001981class PKCS12(object):
1982 def __init__(self):
1983 self._pkey = None
1984 self._cert = None
1985 self._cacerts = None
1986 self._friendlyname = None
1987
1988
1989 def get_certificate(self):
1990 """
1991 Return certificate portion of the PKCS12 structure
1992
1993 :return: X509 object containing the certificate
1994 """
1995 return self._cert
1996
1997
1998 def set_certificate(self, cert):
1999 """
2000 Replace the certificate portion of the PKCS12 structure
2001
2002 :param cert: The new certificate.
2003 :type cert: :py:class:`X509` or :py:data:`None`
2004 :return: None
2005 """
2006 if not isinstance(cert, X509):
2007 raise TypeError("cert must be an X509 instance")
2008 self._cert = cert
2009
2010
2011 def get_privatekey(self):
2012 """
2013 Return private key portion of the PKCS12 structure
2014
2015 :returns: PKey object containing the private key
2016 """
2017 return self._pkey
2018
2019
2020 def set_privatekey(self, pkey):
2021 """
2022 Replace or set the certificate portion of the PKCS12 structure
2023
2024 :param pkey: The new private key.
2025 :type pkey: :py:class:`PKey`
2026 :return: None
2027 """
2028 if not isinstance(pkey, PKey):
2029 raise TypeError("pkey must be a PKey instance")
2030 self._pkey = pkey
2031
2032
2033 def get_ca_certificates(self):
2034 """
2035 Return CA certificates within of the PKCS12 object
2036
2037 :return: A newly created tuple containing the CA certificates in the chain,
2038 if any are present, or None if no CA certificates are present.
2039 """
2040 if self._cacerts is not None:
2041 return tuple(self._cacerts)
2042
2043
2044 def set_ca_certificates(self, cacerts):
2045 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002046 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002047
2048 :param cacerts: The new CA certificates.
2049 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2050 :return: None
2051 """
2052 if cacerts is None:
2053 self._cacerts = None
2054 else:
2055 cacerts = list(cacerts)
2056 for cert in cacerts:
2057 if not isinstance(cert, X509):
2058 raise TypeError("iterable must only contain X509 instances")
2059 self._cacerts = cacerts
2060
2061
2062 def set_friendlyname(self, name):
2063 """
2064 Replace or set the certificate portion of the PKCS12 structure
2065
2066 :param name: The new friendly name.
2067 :type name: :py:class:`bytes`
2068 :return: None
2069 """
2070 if name is None:
2071 self._friendlyname = None
2072 elif not isinstance(name, bytes):
2073 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2074 self._friendlyname = name
2075
2076
2077 def get_friendlyname(self):
2078 """
2079 Return friendly name portion of the PKCS12 structure
2080
2081 :returns: String containing the friendlyname
2082 """
2083 return self._friendlyname
2084
2085
2086 def export(self, passphrase=None, iter=2048, maciter=1):
2087 """
2088 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2089
2090 :param passphrase: used to encrypt the PKCS12
2091 :type passphrase: :py:data:`bytes`
2092
2093 :param iter: How many times to repeat the encryption
2094 :type iter: :py:data:`int`
2095
2096 :param maciter: How many times to repeat the MAC
2097 :type maciter: :py:data:`int`
2098
2099 :return: The string containing the PKCS12
2100 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002101 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002102
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002103 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002104 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002105 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002106 cacerts = _lib.sk_X509_new_null()
2107 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002108 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002109 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002110
2111 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002112 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002113
2114 friendlyname = self._friendlyname
2115 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002116 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002117
2118 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002119 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002120 else:
2121 pkey = self._pkey._pkey
2122
2123 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002124 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002125 else:
2126 cert = self._cert._x509
2127
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002128 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002129 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002130 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2131 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002132 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002133 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002134 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002135 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002136
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002137 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002138 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002139 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002140
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002141PKCS12Type = PKCS12
2142
2143
2144
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002145class NetscapeSPKI(object):
2146 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002147 spki = _lib.NETSCAPE_SPKI_new()
2148 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002149
2150
2151 def sign(self, pkey, digest):
2152 """
2153 Sign the certificate request using the supplied key and digest
2154
2155 :param pkey: The key to sign with
2156 :param digest: The message digest to use
2157 :return: None
2158 """
2159 if pkey._only_public:
2160 raise ValueError("Key has only public part")
2161
2162 if not pkey._initialized:
2163 raise ValueError("Key is uninitialized")
2164
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002165 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002166 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002167 raise ValueError("No such digest method")
2168
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002169 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002170 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002171 # TODO: This is untested.
2172 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002173
2174
2175 def verify(self, key):
2176 """
2177 Verifies a certificate request using the supplied public key
2178
2179 :param key: a public key
2180 :return: True if the signature is correct.
2181 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2182 problem verifying the signature.
2183 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002184 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002185 if answer <= 0:
2186 _raise_current_error()
2187 return True
2188
2189
2190 def b64_encode(self):
2191 """
2192 Generate a base64 encoded string from an SPKI
2193
2194 :return: The base64 encoded string
2195 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002196 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2197 result = _ffi.string(encoded)
2198 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002199 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002200
2201
2202 def get_pubkey(self):
2203 """
2204 Get the public key of the certificate
2205
2206 :return: The public key
2207 """
2208 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002209 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2210 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002211 # TODO: This is untested.
2212 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002213 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002214 pkey._only_public = True
2215 return pkey
2216
2217
2218 def set_pubkey(self, pkey):
2219 """
2220 Set the public key of the certificate
2221
2222 :param pkey: The public key
2223 :return: None
2224 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002225 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002226 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002227 # TODO: This is untested.
2228 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002229NetscapeSPKIType = NetscapeSPKI
2230
2231
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002232class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002233 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002234 if type != FILETYPE_PEM and passphrase is not None:
2235 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002236 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002237 self._more_args = more_args
2238 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002239 self._problems = []
2240
2241
2242 @property
2243 def callback(self):
2244 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002245 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002246 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002247 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002248 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002249 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002250 else:
2251 raise TypeError("Last argument must be string or callable")
2252
2253
2254 @property
2255 def callback_args(self):
2256 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002257 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002258 elif isinstance(self._passphrase, bytes):
2259 return self._passphrase
2260 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002261 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002262 else:
2263 raise TypeError("Last argument must be string or callable")
2264
2265
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002266 def raise_if_problem(self, exceptionType=Error):
2267 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002268 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002269 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002270 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002271 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002272 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002273 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002274
2275
2276 def _read_passphrase(self, buf, size, rwflag, userdata):
2277 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002278 if self._more_args:
2279 result = self._passphrase(size, rwflag, userdata)
2280 else:
2281 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002282 if not isinstance(result, bytes):
2283 raise ValueError("String expected")
2284 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002285 if self._truncate:
2286 result = result[:size]
2287 else:
2288 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002289 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002290 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002291 return len(result)
2292 except Exception as e:
2293 self._problems.append(e)
2294 return 0
2295
2296
2297
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002298def load_privatekey(type, buffer, passphrase=None):
2299 """
2300 Load a private key from a buffer
2301
2302 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2303 :param buffer: The buffer the key is stored in
2304 :param passphrase: (optional) if encrypted PEM format, this can be
2305 either the passphrase to use, or a callback for
2306 providing the passphrase.
2307
2308 :return: The PKey object
2309 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002310 if isinstance(buffer, _text_type):
2311 buffer = buffer.encode("ascii")
2312
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002313 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002314
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002315 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002316 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002317 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2318 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002319 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002320 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002321 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002322 else:
2323 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2324
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002325 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002326 _raise_current_error()
2327
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002328 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002329 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002330 return pkey
2331
2332
2333
2334def dump_certificate_request(type, req):
2335 """
2336 Dump a certificate request to a buffer
2337
2338 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2339 :param req: The certificate request to dump
2340 :return: The buffer with the dumped certificate request in
2341 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002342 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002343
2344 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002345 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002346 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002347 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002348 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002349 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002350 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002351 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002352
2353 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002354 # TODO: This is untested.
2355 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002356
2357 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002358
2359
2360
2361def load_certificate_request(type, buffer):
2362 """
2363 Load a certificate request from a buffer
2364
2365 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2366 :param buffer: The buffer the certificate request is stored in
2367 :return: The X509Req object
2368 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002369 if isinstance(buffer, _text_type):
2370 buffer = buffer.encode("ascii")
2371
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002372 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002373
2374 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002375 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002376 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002377 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002378 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002379 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002380
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002381 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002382 # TODO: This is untested.
2383 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002384
2385 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002386 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002387 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002388
2389
2390
2391def sign(pkey, data, digest):
2392 """
2393 Sign data with a digest
2394
2395 :param pkey: Pkey to sign with
2396 :param data: data to be signed
2397 :param digest: message digest to use
2398 :return: signature
2399 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002400 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002401
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002402 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002403 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002404 raise ValueError("No such digest method")
2405
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002406 md_ctx = _ffi.new("EVP_MD_CTX*")
2407 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002408
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002409 _lib.EVP_SignInit(md_ctx, digest_obj)
2410 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002411
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002412 signature_buffer = _ffi.new("unsigned char[]", 512)
2413 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002414 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002415 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002416 md_ctx, signature_buffer, signature_length, pkey._pkey)
2417
2418 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002419 # TODO: This is untested.
2420 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002421
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002422 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002423
2424
2425
2426def verify(cert, signature, data, digest):
2427 """
2428 Verify a signature
2429
2430 :param cert: signing certificate (X509 object)
2431 :param signature: signature returned by sign function
2432 :param data: data to be verified
2433 :param digest: message digest to use
2434 :return: None if the signature is correct, raise exception otherwise
2435 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002436 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002437
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002438 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002439 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002440 raise ValueError("No such digest method")
2441
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002442 pkey = _lib.X509_get_pubkey(cert._x509)
2443 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002444 # TODO: This is untested.
2445 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002446 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002447
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002448 md_ctx = _ffi.new("EVP_MD_CTX*")
2449 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002450
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002451 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2452 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2453 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002454
2455 if verify_result != 1:
2456 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002457
2458
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002459def load_crl(type, buffer):
2460 """
2461 Load a certificate revocation list from a buffer
2462
2463 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2464 :param buffer: The buffer the CRL is stored in
2465
2466 :return: The PKey object
2467 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002468 if isinstance(buffer, _text_type):
2469 buffer = buffer.encode("ascii")
2470
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002471 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002472
2473 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002474 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002475 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002476 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002477 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002478 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2479
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002480 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002481 _raise_current_error()
2482
2483 result = CRL.__new__(CRL)
2484 result._crl = crl
2485 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002486
2487
2488
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002489def load_pkcs7_data(type, buffer):
2490 """
2491 Load pkcs7 data from a buffer
2492
2493 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2494 :param buffer: The buffer with the pkcs7 data.
2495 :return: The PKCS7 object
2496 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002497 if isinstance(buffer, _text_type):
2498 buffer = buffer.encode("ascii")
2499
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002500 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002501
2502 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002503 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002504 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002505 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002506 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002507 # TODO: This is untested.
2508 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002509 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2510
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002511 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002512 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002513
2514 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002515 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002516 return pypkcs7
2517
2518
2519
Stephen Holsapple38482622014-04-05 20:29:34 -07002520def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002521 """
2522 Load a PKCS12 object from a buffer
2523
2524 :param buffer: The buffer the certificate is stored in
2525 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2526 :returns: The PKCS12 object
2527 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002528 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002529
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002530 if isinstance(buffer, _text_type):
2531 buffer = buffer.encode("ascii")
2532
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002533 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002534
Stephen Holsapple38482622014-04-05 20:29:34 -07002535 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2536 # password based encryption no password and a zero length password are two
2537 # different things, but OpenSSL implementation will try both to figure out
2538 # which one works.
2539 if not passphrase:
2540 passphrase = _ffi.NULL
2541
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002542 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2543 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002544 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002545 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002546
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002547 pkey = _ffi.new("EVP_PKEY**")
2548 cert = _ffi.new("X509**")
2549 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002550
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002551 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002552 if not parse_result:
2553 _raise_current_error()
2554
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002555 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002556
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002557 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2558 # queue for no particular reason. This error isn't interesting to anyone
2559 # outside this function. It's not even interesting to us. Get rid of it.
2560 try:
2561 _raise_current_error()
2562 except Error:
2563 pass
2564
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002565 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002566 pykey = None
2567 else:
2568 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002569 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002570
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002571 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002572 pycert = None
2573 friendlyname = None
2574 else:
2575 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002576 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002577
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002578 friendlyname_length = _ffi.new("int*")
2579 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2580 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2581 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002582 friendlyname = None
2583
2584 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002585 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002586 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002587 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002588 pycacerts.append(pycacert)
2589 if not pycacerts:
2590 pycacerts = None
2591
2592 pkcs12 = PKCS12.__new__(PKCS12)
2593 pkcs12._pkey = pykey
2594 pkcs12._cert = pycert
2595 pkcs12._cacerts = pycacerts
2596 pkcs12._friendlyname = friendlyname
2597 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002598
2599
2600def _initialize_openssl_threads(get_ident, Lock):
2601 import _ssl
2602 return
2603
2604 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2605
2606 def locking_function(mode, index, filename, line):
2607 if mode & _lib.CRYPTO_LOCK:
2608 locks[index].acquire()
2609 else:
2610 locks[index].release()
2611
2612 _lib.CRYPTO_set_id_callback(
2613 _ffi.callback("unsigned long (*)(void)", get_ident))
2614
2615 _lib.CRYPTO_set_locking_callback(
2616 _ffi.callback(
2617 "void (*)(int, int, const char*, int)", locking_function))
2618
2619
2620try:
2621 from thread import get_ident
2622 from threading import Lock
2623except ImportError:
2624 pass
2625else:
2626 _initialize_openssl_threads(get_ident, Lock)
2627 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002628
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002629# There are no direct unit tests for this initialization. It is tested
2630# indirectly since it is necessary for functions like dump_privatekey when
2631# using encryption.
2632#
2633# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2634# and some other similar tests may fail without this (though they may not if
2635# the Python runtime has already done some initialization of the underlying
2636# OpenSSL library (and is linked against the same one that cryptography is
2637# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002638_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002639
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002640# This is similar but exercised mainly by exception_from_error_queue. It calls
2641# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2642_lib.SSL_load_error_strings()