blob: 5743795e8d4294271f857432e7f6f60d697515d5 [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
Paul Kehrerb7d79502015-05-04 07:43:51 -0500687 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400688 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500689 for i in range(_lib.sk_GENERAL_NAME_num(names)):
690 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400691 try:
692 label = self._prefixes[name.type]
693 except KeyError:
694 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500695 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500696 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400697 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500698 value = _native(
699 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
700 parts.append(label + ":" + value)
701 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400702
703
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800704 def __str__(self):
705 """
706 :return: a nice text representation of the extension
707 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500708 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400709 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800710
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400711 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500712 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800713 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500714 # TODO: This is untested.
715 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800716
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500717 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800718
719
720 def get_critical(self):
721 """
722 Returns the critical field of the X509Extension
723
724 :return: The critical field.
725 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500726 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800727
728
729 def get_short_name(self):
730 """
731 Returns the short version of the type name of the X509Extension
732
733 :return: The short type name.
734 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500735 obj = _lib.X509_EXTENSION_get_object(self._extension)
736 nid = _lib.OBJ_obj2nid(obj)
737 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800738
739
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800740 def get_data(self):
741 """
742 Returns the data of the X509Extension
743
744 :return: A :py:data:`str` giving the X509Extension's ASN.1 encoded data.
745 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500746 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
747 string_result = _ffi.cast('ASN1_STRING*', octet_result)
748 char_result = _lib.ASN1_STRING_data(string_result)
749 result_length = _lib.ASN1_STRING_length(string_result)
750 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800751
752X509ExtensionType = X509Extension
753
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800754
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800755class X509Req(object):
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800756 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500757 req = _lib.X509_REQ_new()
758 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800759
760
761 def set_pubkey(self, pkey):
762 """
763 Set the public key of the certificate request
764
765 :param pkey: The public key to use
766 :return: None
767 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500768 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800769 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500770 # TODO: This is untested.
771 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800772
773
774 def get_pubkey(self):
775 """
776 Get the public key from the certificate request
777
778 :return: The public key
779 """
780 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500781 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
782 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500783 # TODO: This is untested.
784 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500785 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800786 pkey._only_public = True
787 return pkey
788
789
790 def set_version(self, version):
791 """
792 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
793 request.
794
795 :param version: The version number
796 :return: None
797 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500798 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800799 if not set_result:
800 _raise_current_error()
801
802
803 def get_version(self):
804 """
805 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
806 request.
807
808 :return: an integer giving the value of the version subfield
809 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500810 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811
812
813 def get_subject(self):
814 """
815 Create an X509Name object for the subject of the certificate request
816
817 :return: An X509Name object
818 """
819 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500820 name._name = _lib.X509_REQ_get_subject_name(self._req)
821 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500822 # TODO: This is untested.
823 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800824
825 # The name is owned by the X509Req structure. As long as the X509Name
826 # Python object is alive, keep the X509Req Python object alive.
827 name._owner = self
828
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800829 return name
830
831
832 def add_extensions(self, extensions):
833 """
834 Add extensions to the request.
835
836 :param extensions: a sequence of X509Extension objects
837 :return: None
838 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500839 stack = _lib.sk_X509_EXTENSION_new_null()
840 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500841 # TODO: This is untested.
842 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800843
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500844 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800845
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800846 for ext in extensions:
847 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800848 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800849
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800850 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500851 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800852
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500853 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500855 # TODO: This is untested.
856 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800857
858
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800859 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800860 """
861 Get extensions to the request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800862
Jean-Paul Calderoneda3e6c62014-03-02 08:06:11 -0500863 :return: A :py:class:`list` of :py:class:`X509Extension` objects.
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800864 """
865 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500866 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500867 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800868 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500869 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800870 exts.append(ext)
871 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800872
873
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800874 def sign(self, pkey, digest):
875 """
876 Sign the certificate request using the supplied key and digest
877
878 :param pkey: The key to sign with
879 :param digest: The message digest to use
880 :return: None
881 """
882 if pkey._only_public:
883 raise ValueError("Key has only public part")
884
885 if not pkey._initialized:
886 raise ValueError("Key is uninitialized")
887
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500888 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500889 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800890 raise ValueError("No such digest method")
891
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500892 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800893 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500894 # TODO: This is untested.
895 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800896
897
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800898 def verify(self, pkey):
899 """
900 Verifies a certificate request using the supplied public key
901
902 :param key: a public key
903 :return: True if the signature is correct.
904
905 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
906 problem verifying the signature.
907 """
908 if not isinstance(pkey, PKey):
909 raise TypeError("pkey must be a PKey instance")
910
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500911 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800912 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500913 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800914
915 return result
916
917
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800918X509ReqType = X509Req
919
920
921
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800922class X509(object):
923 def __init__(self):
924 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500925 x509 = _lib.X509_new()
926 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800927
928
929 def set_version(self, version):
930 """
931 Set version number of the certificate
932
933 :param version: The version number
934 :type version: :py:class:`int`
935
936 :return: None
937 """
938 if not isinstance(version, int):
939 raise TypeError("version must be an integer")
940
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500941 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800942
943
944 def get_version(self):
945 """
946 Return version number of the certificate
947
948 :return: Version number as a Python integer
949 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500950 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800951
952
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800953 def get_pubkey(self):
954 """
955 Get the public key of the certificate
956
957 :return: The public key
958 """
959 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500960 pkey._pkey = _lib.X509_get_pubkey(self._x509)
961 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800962 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500963 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800964 pkey._only_public = True
965 return pkey
966
967
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800968 def set_pubkey(self, pkey):
969 """
970 Set the public key of the certificate
971
972 :param pkey: The public key
973
974 :return: None
975 """
976 if not isinstance(pkey, PKey):
977 raise TypeError("pkey must be a PKey instance")
978
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500979 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800980 if not set_result:
981 _raise_current_error()
982
983
984 def sign(self, pkey, digest):
985 """
986 Sign the certificate using the supplied key and digest
987
988 :param pkey: The key to sign with
989 :param digest: The message digest to use
990 :return: None
991 """
992 if not isinstance(pkey, PKey):
993 raise TypeError("pkey must be a PKey instance")
994
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800995 if pkey._only_public:
996 raise ValueError("Key only has public part")
997
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800998 if not pkey._initialized:
999 raise ValueError("Key is uninitialized")
1000
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001001 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001002 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001003 raise ValueError("No such digest method")
1004
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001005 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001006 if not sign_result:
1007 _raise_current_error()
1008
1009
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001010 def get_signature_algorithm(self):
1011 """
1012 Retrieve the signature algorithm used in the certificate
1013
1014 :return: A byte string giving the name of the signature algorithm used in
1015 the certificate.
1016 :raise ValueError: If the signature algorithm is undefined.
1017 """
1018 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001019 nid = _lib.OBJ_obj2nid(alg)
1020 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001021 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001022 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001023
1024
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001025 def digest(self, digest_name):
1026 """
1027 Return the digest of the X509 object.
1028
1029 :param digest_name: The name of the digest algorithm to use.
1030 :type digest_name: :py:class:`bytes`
1031
1032 :return: The digest of the object
1033 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001034 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001035 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001036 raise ValueError("No such digest method")
1037
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001038 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1039 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001040 result_length[0] = len(result_buffer)
1041
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001042 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001043 self._x509, digest, result_buffer, result_length)
1044
1045 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001046 # TODO: This is untested.
1047 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001048
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001049 return b":".join([
1050 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001051 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001052
1053
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001054 def subject_name_hash(self):
1055 """
1056 Return the hash of the X509 subject.
1057
1058 :return: The hash of the subject.
1059 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001060 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001061
1062
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001063 def set_serial_number(self, serial):
1064 """
1065 Set serial number of the certificate
1066
1067 :param serial: The serial number
1068 :type serial: :py:class:`int`
1069
1070 :return: None
1071 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001072 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001073 raise TypeError("serial must be an integer")
1074
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001075 hex_serial = hex(serial)[2:]
1076 if not isinstance(hex_serial, bytes):
1077 hex_serial = hex_serial.encode('ascii')
1078
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001079 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001080
1081 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1082 # it. If bignum is still NULL after this call, then the return value is
1083 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001084 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001085
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001086 if bignum_serial[0] == _ffi.NULL:
1087 set_result = _lib.ASN1_INTEGER_set(
1088 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001089 if set_result:
1090 # TODO Not tested
1091 _raise_current_error()
1092 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001093 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1094 _lib.BN_free(bignum_serial[0])
1095 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001096 # TODO Not tested
1097 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001098 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1099 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001100 if not set_result:
1101 # TODO Not tested
1102 _raise_current_error()
1103
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001104
1105 def get_serial_number(self):
1106 """
1107 Return serial number of the certificate
1108
1109 :return: Serial number as a Python integer
1110 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001111 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1112 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001113 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001114 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001115 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001116 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001117 serial = int(hexstring_serial, 16)
1118 return serial
1119 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001120 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001121 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001122 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001123
1124
1125 def gmtime_adj_notAfter(self, amount):
1126 """
1127 Adjust the time stamp for when the certificate stops being valid
1128
1129 :param amount: The number of seconds by which to adjust the ending
1130 validity time.
1131 :type amount: :py:class:`int`
1132
1133 :return: None
1134 """
1135 if not isinstance(amount, int):
1136 raise TypeError("amount must be an integer")
1137
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001138 notAfter = _lib.X509_get_notAfter(self._x509)
1139 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001140
1141
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001142 def gmtime_adj_notBefore(self, amount):
1143 """
1144 Change the timestamp for when the certificate starts being valid to the current
1145 time plus an offset.
1146
1147 :param amount: The number of seconds by which to adjust the starting validity
1148 time.
1149 :return: None
1150 """
1151 if not isinstance(amount, int):
1152 raise TypeError("amount must be an integer")
1153
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001154 notBefore = _lib.X509_get_notBefore(self._x509)
1155 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001156
1157
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001158 def has_expired(self):
1159 """
1160 Check whether the certificate has expired.
1161
1162 :return: True if the certificate has expired, false otherwise
1163 """
1164 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001165 notAfter = _lib.X509_get_notAfter(self._x509)
1166 return _lib.ASN1_UTCTIME_cmp_time_t(
1167 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001168
1169
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001170 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001171 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001172
1173
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001174 def get_notBefore(self):
1175 """
1176 Retrieve the time stamp for when the certificate starts being valid
1177
1178 :return: A string giving the timestamp, in the format::
1179
1180 YYYYMMDDhhmmssZ
1181 YYYYMMDDhhmmss+hhmm
1182 YYYYMMDDhhmmss-hhmm
1183
1184 or None if there is no value set.
1185 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001186 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001187
1188
1189 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001190 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001191
1192
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001193 def set_notBefore(self, when):
1194 """
1195 Set the time stamp for when the certificate starts being valid
1196
1197 :param when: A string giving the timestamp, in the format:
1198
1199 YYYYMMDDhhmmssZ
1200 YYYYMMDDhhmmss+hhmm
1201 YYYYMMDDhhmmss-hhmm
1202 :type when: :py:class:`bytes`
1203
1204 :return: None
1205 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001206 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001207
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001208
1209 def get_notAfter(self):
1210 """
1211 Retrieve the time stamp for when the certificate stops being valid
1212
1213 :return: A string giving the timestamp, in the format::
1214
1215 YYYYMMDDhhmmssZ
1216 YYYYMMDDhhmmss+hhmm
1217 YYYYMMDDhhmmss-hhmm
1218
1219 or None if there is no value set.
1220 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001221 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001222
1223
1224 def set_notAfter(self, when):
1225 """
1226 Set the time stamp for when the certificate stops being valid
1227
1228 :param when: A string giving the timestamp, in the format:
1229
1230 YYYYMMDDhhmmssZ
1231 YYYYMMDDhhmmss+hhmm
1232 YYYYMMDDhhmmss-hhmm
1233 :type when: :py:class:`bytes`
1234
1235 :return: None
1236 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001237 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001238
1239
1240 def _get_name(self, which):
1241 name = X509Name.__new__(X509Name)
1242 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001243 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001244 # TODO: This is untested.
1245 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001246
1247 # The name is owned by the X509 structure. As long as the X509Name
1248 # Python object is alive, keep the X509 Python object alive.
1249 name._owner = self
1250
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001251 return name
1252
1253
1254 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001255 if not isinstance(name, X509Name):
1256 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001257 set_result = which(self._x509, name._name)
1258 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001259 # TODO: This is untested.
1260 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001261
1262
1263 def get_issuer(self):
1264 """
1265 Create an X509Name object for the issuer of the certificate
1266
1267 :return: An X509Name object
1268 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001269 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001270
1271
1272 def set_issuer(self, issuer):
1273 """
1274 Set the issuer of the certificate
1275
1276 :param issuer: The issuer name
1277 :type issuer: :py:class:`X509Name`
1278
1279 :return: None
1280 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001281 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001282
1283
1284 def get_subject(self):
1285 """
1286 Create an X509Name object for the subject of the certificate
1287
1288 :return: An X509Name object
1289 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001290 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001291
1292
1293 def set_subject(self, subject):
1294 """
1295 Set the subject of the certificate
1296
1297 :param subject: The subject name
1298 :type subject: :py:class:`X509Name`
1299 :return: None
1300 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001301 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001302
1303
1304 def get_extension_count(self):
1305 """
1306 Get the number of extensions on the certificate.
1307
1308 :return: The number of extensions as an integer.
1309 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001310 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001311
1312
1313 def add_extensions(self, extensions):
1314 """
1315 Add extensions to the certificate.
1316
1317 :param extensions: a sequence of X509Extension objects
1318 :return: None
1319 """
1320 for ext in extensions:
1321 if not isinstance(ext, X509Extension):
1322 raise ValueError("One of the elements is not an X509Extension")
1323
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001324 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001325 if not add_result:
1326 _raise_current_error()
1327
1328
1329 def get_extension(self, index):
1330 """
1331 Get a specific extension of the certificate by index.
1332
1333 :param index: The index of the extension to retrieve.
1334 :return: The X509Extension object at the specified index.
1335 """
1336 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001337 ext._extension = _lib.X509_get_ext(self._x509, index)
1338 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001339 raise IndexError("extension index out of bounds")
1340
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001341 extension = _lib.X509_EXTENSION_dup(ext._extension)
1342 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001343 return ext
1344
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001345X509Type = X509
1346
1347
1348
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001349class X509Store(object):
1350 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001351 store = _lib.X509_STORE_new()
1352 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001353
1354
1355 def add_cert(self, cert):
1356 if not isinstance(cert, X509):
1357 raise TypeError()
1358
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001359 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001360 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001361 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001362
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001363
1364X509StoreType = X509Store
1365
1366
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001367class X509StoreContextError(Exception):
1368 """
1369 An error occurred while verifying a certificate using
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001370 `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001371
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001372 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001373 :type cert: :class:`X509`
1374
1375 """
1376 def __init__(self, message, certificate):
1377 super(X509StoreContextError, self).__init__(message)
1378 self.certificate = certificate
1379
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001380
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001381class X509StoreContext(object):
1382 """
1383 An X.509 store context.
1384
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001385 An :py:class:`X509StoreContext` is used to define some of the criteria for
1386 certificate verification. The information encapsulated in this object
1387 includes, but is not limited to, a set of trusted certificates,
1388 verification parameters, and revoked certificates.
1389
1390 Of these, only the set of trusted certificates is currently exposed.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001391
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001392 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1393 instance. It is dynamically allocated and automatically garbage
1394 collected.
1395
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001396 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001397
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001398 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001399 """
1400
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001401 def __init__(self, store, certificate):
1402 """
1403 :param X509Store store: The certificates which will be trusted for the
1404 purposes of any verifications.
1405
1406 :param X509 certificate: The certificate to be verified.
1407 """
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001408 store_ctx = _lib.X509_STORE_CTX_new()
1409 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1410 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001411 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001412 # Make the store context available for use after instantiating this
1413 # class by initializing it now. Per testing, subsequent calls to
1414 # :py:meth:`_init` have no adverse affect.
1415 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001416
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001417
1418 def _init(self):
1419 """
1420 Set up the store context for a subsequent verification operation.
1421 """
1422 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1423 if ret <= 0:
1424 _raise_current_error()
1425
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001426
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001427 def _cleanup(self):
1428 """
1429 Internally cleans up the store context.
1430
1431 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001432 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001433 """
1434 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1435
1436
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001437 def _exception_from_context(self):
1438 """
1439 Convert an OpenSSL native context error failure into a Python
1440 exception.
1441
1442 When a call to native OpenSSL X509_verify_cert fails, additonal information
1443 about the failure can be obtained from the store context.
1444 """
1445 errors = [
1446 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1447 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1448 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1449 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1450 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001451 # A context error should always be associated with a certificate, so we
1452 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001453 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001454 _cert = _lib.X509_dup(_x509)
1455 pycert = X509.__new__(X509)
1456 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001457 return X509StoreContextError(errors, pycert)
1458
1459
Stephen Holsapple46a09252015-02-12 14:45:43 -08001460 def set_store(self, store):
1461 """
1462 Set the context's trust store.
1463
1464 :param X509Store store: The certificates which will be trusted for the
1465 purposes of any *future* verifications.
1466 """
1467 self._store = store
1468
1469
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001470 def verify_certificate(self):
1471 """
1472 Verify a certificate in a context.
1473
1474 :param store_ctx: The :py:class:`X509StoreContext` to verify.
1475 :raises: Error
1476 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001477 # Always re-initialize the store context in case
1478 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001479 self._init()
1480 ret = _lib.X509_verify_cert(self._store_ctx)
1481 self._cleanup()
1482 if ret <= 0:
1483 raise self._exception_from_context()
1484
1485
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001486
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001487def load_certificate(type, buffer):
1488 """
1489 Load a certificate from a buffer
1490
1491 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001492
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001493 :param buffer: The buffer the certificate is stored in
1494 :type buffer: :py:class:`bytes`
1495
1496 :return: The X509 object
1497 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001498 if isinstance(buffer, _text_type):
1499 buffer = buffer.encode("ascii")
1500
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001501 bio = _new_mem_buf(buffer)
1502
1503 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001504 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001505 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001506 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001507 else:
1508 raise ValueError(
1509 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1510
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001511 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001512 _raise_current_error()
1513
1514 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001515 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001516 return cert
1517
1518
1519def dump_certificate(type, cert):
1520 """
1521 Dump a certificate to a buffer
1522
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001523 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1524 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001525 :param cert: The certificate to dump
1526 :return: The buffer with the dumped certificate in
1527 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001528 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001529
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001530 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001531 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001532 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001533 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001534 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001535 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001536 else:
1537 raise ValueError(
1538 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1539 "FILETYPE_TEXT")
1540
1541 return _bio_to_string(bio)
1542
1543
1544
1545def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1546 """
1547 Dump a private key to a buffer
1548
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001549 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1550 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001551 :param pkey: The PKey to dump
1552 :param cipher: (optional) if encrypted PEM format, the cipher to
1553 use
1554 :param passphrase: (optional) if encrypted PEM format, this can be either
1555 the passphrase to use, or a callback for providing the
1556 passphrase.
1557 :return: The buffer with the dumped key in
1558 :rtype: :py:data:`str`
1559 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001560 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001561
1562 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001563 if passphrase is None:
1564 raise TypeError(
1565 "if a value is given for cipher "
1566 "one must also be given for passphrase")
1567 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001568 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001569 raise ValueError("Invalid cipher name")
1570 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001571 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001572
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001573 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001574 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001575 result_code = _lib.PEM_write_bio_PrivateKey(
1576 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001577 helper.callback, helper.callback_args)
1578 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001579 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001580 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001581 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001582 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1583 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001584 # TODO RSA_free(rsa)?
1585 else:
1586 raise ValueError(
1587 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1588 "FILETYPE_TEXT")
1589
1590 if result_code == 0:
1591 _raise_current_error()
1592
1593 return _bio_to_string(bio)
1594
1595
1596
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001597def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001598 copy = _lib.X509_REVOKED_new()
1599 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001600 # TODO: This is untested.
1601 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001602
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001603 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001604 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001605 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001606
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001607 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001608 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001609 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001610
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001611 if original.extensions != _ffi.NULL:
1612 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1613 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1614 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1615 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1616 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001617 copy.extensions = extension_stack
1618
1619 copy.sequence = original.sequence
1620 return copy
1621
1622
1623
1624class Revoked(object):
1625 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1626 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1627 # OCSP_crl_reason_str. We use the latter, just like the command line
1628 # program.
1629 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001630 b"unspecified",
1631 b"keyCompromise",
1632 b"CACompromise",
1633 b"affiliationChanged",
1634 b"superseded",
1635 b"cessationOfOperation",
1636 b"certificateHold",
1637 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001638 ]
1639
1640 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001641 revoked = _lib.X509_REVOKED_new()
1642 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001643
1644
1645 def set_serial(self, hex_str):
1646 """
1647 Set the serial number of a revoked Revoked structure
1648
1649 :param hex_str: The new serial number.
1650 :type hex_str: :py:data:`str`
1651 :return: None
1652 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001653 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1654 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001655 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001656 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001657 if not bn_result:
1658 raise ValueError("bad hex string")
1659
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001660 asn1_serial = _ffi.gc(
1661 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1662 _lib.ASN1_INTEGER_free)
1663 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001664
1665
1666 def get_serial(self):
1667 """
1668 Return the serial number of a Revoked structure
1669
1670 :return: The serial number as a string
1671 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001672 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001673
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001674 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001675 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001676 # TODO: This is untested.
1677 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001678
1679 return _bio_to_string(bio)
1680
1681
1682 def _delete_reason(self):
1683 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001684 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1685 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1686 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1687 _lib.X509_EXTENSION_free(ext)
1688 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001689 break
1690
1691
1692 def set_reason(self, reason):
1693 """
1694 Set the reason of a Revoked object.
1695
1696 If :py:data:`reason` is :py:data:`None`, delete the reason instead.
1697
1698 :param reason: The reason string.
1699 :type reason: :py:class:`str` or :py:class:`NoneType`
1700 :return: None
1701 """
1702 if reason is None:
1703 self._delete_reason()
1704 elif not isinstance(reason, bytes):
1705 raise TypeError("reason must be None or a byte string")
1706 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001707 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001708 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1709
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001710 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1711 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001712 # TODO: This is untested.
1713 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001714 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001715
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001716 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1717 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001718 # TODO: This is untested.
1719 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001720
1721 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001722 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1723 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001724
1725 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001726 # TODO: This is untested.
1727 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001728
1729
1730 def get_reason(self):
1731 """
1732 Return the reason of a Revoked object.
1733
1734 :return: The reason as a string
1735 """
1736 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001737 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1738 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1739 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001740 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001741
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001742 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001743 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001744 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001745 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001746 # TODO: This is untested.
1747 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001748
1749 return _bio_to_string(bio)
1750
1751
1752 def all_reasons(self):
1753 """
1754 Return a list of all the supported reason strings.
1755
1756 :return: A list of reason strings.
1757 """
1758 return self._crl_reasons[:]
1759
1760
1761 def set_rev_date(self, when):
1762 """
1763 Set the revocation timestamp
1764
1765 :param when: A string giving the timestamp, in the format:
1766
1767 YYYYMMDDhhmmssZ
1768 YYYYMMDDhhmmss+hhmm
1769 YYYYMMDDhhmmss-hhmm
1770
1771 :return: None
1772 """
1773 return _set_asn1_time(self._revoked.revocationDate, when)
1774
1775
1776 def get_rev_date(self):
1777 """
1778 Retrieve the revocation date
1779
1780 :return: A string giving the timestamp, in the format:
1781
1782 YYYYMMDDhhmmssZ
1783 YYYYMMDDhhmmss+hhmm
1784 YYYYMMDDhhmmss-hhmm
1785 """
1786 return _get_asn1_time(self._revoked.revocationDate)
1787
1788
1789
1790class CRL(object):
1791 def __init__(self):
1792 """
1793 Create a new empty CRL object.
1794 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001795 crl = _lib.X509_CRL_new()
1796 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001797
1798
1799 def get_revoked(self):
1800 """
1801 Return revoked portion of the CRL structure (by value not reference).
1802
1803 :return: A tuple of Revoked objects.
1804 """
1805 results = []
1806 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001807 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1808 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809 revoked_copy = _X509_REVOKED_dup(revoked)
1810 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001811 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001812 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001813 if results:
1814 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001815
1816
1817 def add_revoked(self, revoked):
1818 """
1819 Add a revoked (by value not reference) to the CRL structure
1820
1821 :param revoked: The new revoked.
1822 :type revoked: :class:`X509`
1823
1824 :return: None
1825 """
1826 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001827 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001828 # TODO: This is untested.
1829 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001830
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001831 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001832 if add_result == 0:
1833 # TODO: This is untested.
1834 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001835
1836
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001837 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001838 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001839 """
1840 export a CRL as a string
1841
1842 :param cert: Used to sign CRL.
1843 :type cert: :class:`X509`
1844
1845 :param key: Used to sign CRL.
1846 :type key: :class:`PKey`
1847
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001848 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1849 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001850
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001851 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001852
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001853 :param bytes digest: The name of the message digest to use (eg
1854 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001855
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001856 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001857 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001858 if not isinstance(cert, X509):
1859 raise TypeError("cert must be an X509 instance")
1860 if not isinstance(key, PKey):
1861 raise TypeError("key must be a PKey instance")
1862 if not isinstance(type, int):
1863 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001864
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001865 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001866 _warn(
1867 "The default message digest (md5) is deprecated. "
1868 "Pass the name of a message digest explicitly.",
1869 category=DeprecationWarning,
1870 stacklevel=2,
1871 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001872 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001873
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001874 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001875 if digest_obj == _ffi.NULL:
1876 raise ValueError("No such digest method")
1877
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001878 bio = _lib.BIO_new(_lib.BIO_s_mem())
1879 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001880 # TODO: This is untested.
1881 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001882
1883 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001884 sometime = _lib.ASN1_TIME_new()
1885 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001886 # TODO: This is untested.
1887 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001888
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001889 _lib.X509_gmtime_adj(sometime, 0)
1890 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001891
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001892 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1893 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001894
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001895 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001896
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001897 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001898 if not sign_result:
1899 _raise_current_error()
1900
1901 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001902 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001903 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001904 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001905 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001906 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001907 else:
1908 raise ValueError(
1909 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1910
1911 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001912 # TODO: This is untested.
1913 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001914
1915 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001916CRLType = CRL
1917
1918
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001919
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001920class PKCS7(object):
1921 def type_is_signed(self):
1922 """
1923 Check if this NID_pkcs7_signed object
1924
1925 :return: True if the PKCS7 is of type signed
1926 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001927 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001928 return True
1929 return False
1930
1931
1932 def type_is_enveloped(self):
1933 """
1934 Check if this NID_pkcs7_enveloped object
1935
1936 :returns: True if the PKCS7 is of type enveloped
1937 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001938 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001939 return True
1940 return False
1941
1942
1943 def type_is_signedAndEnveloped(self):
1944 """
1945 Check if this NID_pkcs7_signedAndEnveloped object
1946
1947 :returns: True if the PKCS7 is of type signedAndEnveloped
1948 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001949 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001950 return True
1951 return False
1952
1953
1954 def type_is_data(self):
1955 """
1956 Check if this NID_pkcs7_data object
1957
1958 :return: True if the PKCS7 is of type data
1959 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001960 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001961 return True
1962 return False
1963
1964
1965 def get_type_name(self):
1966 """
1967 Returns the type name of the PKCS7 structure
1968
1969 :return: A string with the typename
1970 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001971 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1972 string_type = _lib.OBJ_nid2sn(nid)
1973 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001974
1975PKCS7Type = PKCS7
1976
1977
1978
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001979class PKCS12(object):
1980 def __init__(self):
1981 self._pkey = None
1982 self._cert = None
1983 self._cacerts = None
1984 self._friendlyname = None
1985
1986
1987 def get_certificate(self):
1988 """
1989 Return certificate portion of the PKCS12 structure
1990
1991 :return: X509 object containing the certificate
1992 """
1993 return self._cert
1994
1995
1996 def set_certificate(self, cert):
1997 """
1998 Replace the certificate portion of the PKCS12 structure
1999
2000 :param cert: The new certificate.
2001 :type cert: :py:class:`X509` or :py:data:`None`
2002 :return: None
2003 """
2004 if not isinstance(cert, X509):
2005 raise TypeError("cert must be an X509 instance")
2006 self._cert = cert
2007
2008
2009 def get_privatekey(self):
2010 """
2011 Return private key portion of the PKCS12 structure
2012
2013 :returns: PKey object containing the private key
2014 """
2015 return self._pkey
2016
2017
2018 def set_privatekey(self, pkey):
2019 """
2020 Replace or set the certificate portion of the PKCS12 structure
2021
2022 :param pkey: The new private key.
2023 :type pkey: :py:class:`PKey`
2024 :return: None
2025 """
2026 if not isinstance(pkey, PKey):
2027 raise TypeError("pkey must be a PKey instance")
2028 self._pkey = pkey
2029
2030
2031 def get_ca_certificates(self):
2032 """
2033 Return CA certificates within of the PKCS12 object
2034
2035 :return: A newly created tuple containing the CA certificates in the chain,
2036 if any are present, or None if no CA certificates are present.
2037 """
2038 if self._cacerts is not None:
2039 return tuple(self._cacerts)
2040
2041
2042 def set_ca_certificates(self, cacerts):
2043 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002044 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002045
2046 :param cacerts: The new CA certificates.
2047 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2048 :return: None
2049 """
2050 if cacerts is None:
2051 self._cacerts = None
2052 else:
2053 cacerts = list(cacerts)
2054 for cert in cacerts:
2055 if not isinstance(cert, X509):
2056 raise TypeError("iterable must only contain X509 instances")
2057 self._cacerts = cacerts
2058
2059
2060 def set_friendlyname(self, name):
2061 """
2062 Replace or set the certificate portion of the PKCS12 structure
2063
2064 :param name: The new friendly name.
2065 :type name: :py:class:`bytes`
2066 :return: None
2067 """
2068 if name is None:
2069 self._friendlyname = None
2070 elif not isinstance(name, bytes):
2071 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2072 self._friendlyname = name
2073
2074
2075 def get_friendlyname(self):
2076 """
2077 Return friendly name portion of the PKCS12 structure
2078
2079 :returns: String containing the friendlyname
2080 """
2081 return self._friendlyname
2082
2083
2084 def export(self, passphrase=None, iter=2048, maciter=1):
2085 """
2086 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2087
2088 :param passphrase: used to encrypt the PKCS12
2089 :type passphrase: :py:data:`bytes`
2090
2091 :param iter: How many times to repeat the encryption
2092 :type iter: :py:data:`int`
2093
2094 :param maciter: How many times to repeat the MAC
2095 :type maciter: :py:data:`int`
2096
2097 :return: The string containing the PKCS12
2098 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002099 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002100
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002101 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002102 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002103 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002104 cacerts = _lib.sk_X509_new_null()
2105 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002106 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002107 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002108
2109 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002110 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002111
2112 friendlyname = self._friendlyname
2113 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002114 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002115
2116 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002117 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002118 else:
2119 pkey = self._pkey._pkey
2120
2121 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002122 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002123 else:
2124 cert = self._cert._x509
2125
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002126 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002127 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002128 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2129 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002130 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002131 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002132 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002133 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002134
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002135 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002136 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002137 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002138
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002139PKCS12Type = PKCS12
2140
2141
2142
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002143class NetscapeSPKI(object):
2144 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002145 spki = _lib.NETSCAPE_SPKI_new()
2146 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002147
2148
2149 def sign(self, pkey, digest):
2150 """
2151 Sign the certificate request using the supplied key and digest
2152
2153 :param pkey: The key to sign with
2154 :param digest: The message digest to use
2155 :return: None
2156 """
2157 if pkey._only_public:
2158 raise ValueError("Key has only public part")
2159
2160 if not pkey._initialized:
2161 raise ValueError("Key is uninitialized")
2162
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002163 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002164 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002165 raise ValueError("No such digest method")
2166
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002167 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002168 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002169 # TODO: This is untested.
2170 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002171
2172
2173 def verify(self, key):
2174 """
2175 Verifies a certificate request using the supplied public key
2176
2177 :param key: a public key
2178 :return: True if the signature is correct.
2179 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2180 problem verifying the signature.
2181 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002182 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002183 if answer <= 0:
2184 _raise_current_error()
2185 return True
2186
2187
2188 def b64_encode(self):
2189 """
2190 Generate a base64 encoded string from an SPKI
2191
2192 :return: The base64 encoded string
2193 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002194 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2195 result = _ffi.string(encoded)
2196 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002197 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002198
2199
2200 def get_pubkey(self):
2201 """
2202 Get the public key of the certificate
2203
2204 :return: The public key
2205 """
2206 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002207 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2208 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002209 # TODO: This is untested.
2210 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002211 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002212 pkey._only_public = True
2213 return pkey
2214
2215
2216 def set_pubkey(self, pkey):
2217 """
2218 Set the public key of the certificate
2219
2220 :param pkey: The public key
2221 :return: None
2222 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002223 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002224 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002225 # TODO: This is untested.
2226 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002227NetscapeSPKIType = NetscapeSPKI
2228
2229
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002230class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002231 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002232 if type != FILETYPE_PEM and passphrase is not None:
2233 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002234 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002235 self._more_args = more_args
2236 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002237 self._problems = []
2238
2239
2240 @property
2241 def callback(self):
2242 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002243 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002244 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002245 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002246 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002247 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002248 else:
2249 raise TypeError("Last argument must be string or callable")
2250
2251
2252 @property
2253 def callback_args(self):
2254 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002255 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002256 elif isinstance(self._passphrase, bytes):
2257 return self._passphrase
2258 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002259 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002260 else:
2261 raise TypeError("Last argument must be string or callable")
2262
2263
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002264 def raise_if_problem(self, exceptionType=Error):
2265 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002266 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002267 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002268 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002269 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002270 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002271 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002272
2273
2274 def _read_passphrase(self, buf, size, rwflag, userdata):
2275 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002276 if self._more_args:
2277 result = self._passphrase(size, rwflag, userdata)
2278 else:
2279 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002280 if not isinstance(result, bytes):
2281 raise ValueError("String expected")
2282 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002283 if self._truncate:
2284 result = result[:size]
2285 else:
2286 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002287 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002288 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002289 return len(result)
2290 except Exception as e:
2291 self._problems.append(e)
2292 return 0
2293
2294
2295
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002296def load_privatekey(type, buffer, passphrase=None):
2297 """
2298 Load a private key from a buffer
2299
2300 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2301 :param buffer: The buffer the key is stored in
2302 :param passphrase: (optional) if encrypted PEM format, this can be
2303 either the passphrase to use, or a callback for
2304 providing the passphrase.
2305
2306 :return: The PKey object
2307 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002308 if isinstance(buffer, _text_type):
2309 buffer = buffer.encode("ascii")
2310
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002311 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002312
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002313 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002314 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002315 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2316 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002317 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002318 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002319 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002320 else:
2321 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2322
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002323 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002324 _raise_current_error()
2325
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002326 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002327 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002328 return pkey
2329
2330
2331
2332def dump_certificate_request(type, req):
2333 """
2334 Dump a certificate request to a buffer
2335
2336 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2337 :param req: The certificate request to dump
2338 :return: The buffer with the dumped certificate request in
2339 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002340 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002341
2342 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002343 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002344 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002345 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002346 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002347 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002348 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002349 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002350
2351 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002352 # TODO: This is untested.
2353 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002354
2355 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002356
2357
2358
2359def load_certificate_request(type, buffer):
2360 """
2361 Load a certificate request from a buffer
2362
2363 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2364 :param buffer: The buffer the certificate request is stored in
2365 :return: The X509Req object
2366 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002367 if isinstance(buffer, _text_type):
2368 buffer = buffer.encode("ascii")
2369
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002370 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002371
2372 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002373 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002374 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002375 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002376 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002377 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002378
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002379 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002380 # TODO: This is untested.
2381 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002382
2383 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002384 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002385 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002386
2387
2388
2389def sign(pkey, data, digest):
2390 """
2391 Sign data with a digest
2392
2393 :param pkey: Pkey to sign with
2394 :param data: data to be signed
2395 :param digest: message digest to use
2396 :return: signature
2397 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002398 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002399
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002400 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002401 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002402 raise ValueError("No such digest method")
2403
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002404 md_ctx = _ffi.new("EVP_MD_CTX*")
2405 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002406
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002407 _lib.EVP_SignInit(md_ctx, digest_obj)
2408 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002409
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002410 signature_buffer = _ffi.new("unsigned char[]", 512)
2411 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002412 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002413 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002414 md_ctx, signature_buffer, signature_length, pkey._pkey)
2415
2416 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002417 # TODO: This is untested.
2418 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002419
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002420 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002421
2422
2423
2424def verify(cert, signature, data, digest):
2425 """
2426 Verify a signature
2427
2428 :param cert: signing certificate (X509 object)
2429 :param signature: signature returned by sign function
2430 :param data: data to be verified
2431 :param digest: message digest to use
2432 :return: None if the signature is correct, raise exception otherwise
2433 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002434 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002435
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002436 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002437 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002438 raise ValueError("No such digest method")
2439
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002440 pkey = _lib.X509_get_pubkey(cert._x509)
2441 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002442 # TODO: This is untested.
2443 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002444 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002445
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002446 md_ctx = _ffi.new("EVP_MD_CTX*")
2447 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002448
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002449 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2450 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2451 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002452
2453 if verify_result != 1:
2454 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002455
2456
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002457def load_crl(type, buffer):
2458 """
2459 Load a certificate revocation list from a buffer
2460
2461 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2462 :param buffer: The buffer the CRL is stored in
2463
2464 :return: The PKey object
2465 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002466 if isinstance(buffer, _text_type):
2467 buffer = buffer.encode("ascii")
2468
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002469 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002470
2471 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002472 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002473 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002474 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002475 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002476 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2477
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002478 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002479 _raise_current_error()
2480
2481 result = CRL.__new__(CRL)
2482 result._crl = crl
2483 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002484
2485
2486
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002487def load_pkcs7_data(type, buffer):
2488 """
2489 Load pkcs7 data from a buffer
2490
2491 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2492 :param buffer: The buffer with the pkcs7 data.
2493 :return: The PKCS7 object
2494 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002495 if isinstance(buffer, _text_type):
2496 buffer = buffer.encode("ascii")
2497
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002498 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002499
2500 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002501 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002502 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002503 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002504 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002505 # TODO: This is untested.
2506 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002507 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2508
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002509 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002510 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002511
2512 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002513 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002514 return pypkcs7
2515
2516
2517
Stephen Holsapple38482622014-04-05 20:29:34 -07002518def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002519 """
2520 Load a PKCS12 object from a buffer
2521
2522 :param buffer: The buffer the certificate is stored in
2523 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2524 :returns: The PKCS12 object
2525 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002526 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002527
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002528 if isinstance(buffer, _text_type):
2529 buffer = buffer.encode("ascii")
2530
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002531 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002532
Stephen Holsapple38482622014-04-05 20:29:34 -07002533 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2534 # password based encryption no password and a zero length password are two
2535 # different things, but OpenSSL implementation will try both to figure out
2536 # which one works.
2537 if not passphrase:
2538 passphrase = _ffi.NULL
2539
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002540 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2541 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002542 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002543 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002544
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002545 pkey = _ffi.new("EVP_PKEY**")
2546 cert = _ffi.new("X509**")
2547 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002548
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002549 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002550 if not parse_result:
2551 _raise_current_error()
2552
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002553 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002554
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002555 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2556 # queue for no particular reason. This error isn't interesting to anyone
2557 # outside this function. It's not even interesting to us. Get rid of it.
2558 try:
2559 _raise_current_error()
2560 except Error:
2561 pass
2562
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002563 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002564 pykey = None
2565 else:
2566 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002567 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002568
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002569 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002570 pycert = None
2571 friendlyname = None
2572 else:
2573 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002574 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002575
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002576 friendlyname_length = _ffi.new("int*")
2577 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2578 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2579 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002580 friendlyname = None
2581
2582 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002583 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002584 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002585 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002586 pycacerts.append(pycacert)
2587 if not pycacerts:
2588 pycacerts = None
2589
2590 pkcs12 = PKCS12.__new__(PKCS12)
2591 pkcs12._pkey = pykey
2592 pkcs12._cert = pycert
2593 pkcs12._cacerts = pycacerts
2594 pkcs12._friendlyname = friendlyname
2595 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002596
2597
2598def _initialize_openssl_threads(get_ident, Lock):
2599 import _ssl
2600 return
2601
2602 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2603
2604 def locking_function(mode, index, filename, line):
2605 if mode & _lib.CRYPTO_LOCK:
2606 locks[index].acquire()
2607 else:
2608 locks[index].release()
2609
2610 _lib.CRYPTO_set_id_callback(
2611 _ffi.callback("unsigned long (*)(void)", get_ident))
2612
2613 _lib.CRYPTO_set_locking_callback(
2614 _ffi.callback(
2615 "void (*)(int, int, const char*, int)", locking_function))
2616
2617
2618try:
2619 from thread import get_ident
2620 from threading import Lock
2621except ImportError:
2622 pass
2623else:
2624 _initialize_openssl_threads(get_ident, Lock)
2625 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002626
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002627# There are no direct unit tests for this initialization. It is tested
2628# indirectly since it is necessary for functions like dump_privatekey when
2629# using encryption.
2630#
2631# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2632# and some other similar tests may fail without this (though they may not if
2633# the Python runtime has already done some initialization of the underlying
2634# OpenSSL library (and is linked against the same one that cryptography is
2635# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002636_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002637
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002638# This is similar but exercised mainly by exception_from_error_queue. It calls
2639# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2640_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002641
2642
2643
2644# Set the default string mask to match OpenSSL upstream (since 2005) and
2645# RFC5280 recommendations.
2646_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')