blob: cab145d918ad1d16b8b2988b2ae7a211efbea215 [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):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200162 """
163 A class representing an DSA or RSA public key or key pair.
164 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800165 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800166 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800167
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800168 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500169 pkey = _lib.EVP_PKEY_new()
170 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800171 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800172
173
174 def generate_key(self, type, bits):
175 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700176 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800177
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200178 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800179
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200180 :param type: The key type.
181 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
182 :param bits: The number of bits.
183 :type bits: :py:data:`int` ``>= 0``
184 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
185 of the appropriate type.
186 :raises ValueError: If the number of bits isn't an integer of
187 the appropriate size.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200188 :return: :py:const:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800189 """
190 if not isinstance(type, int):
191 raise TypeError("type must be an integer")
192
193 if not isinstance(bits, int):
194 raise TypeError("bits must be an integer")
195
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800196 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500197 exponent = _lib.BN_new()
198 exponent = _ffi.gc(exponent, _lib.BN_free)
199 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800200
201 if type == TYPE_RSA:
202 if bits <= 0:
203 raise ValueError("Invalid number of bits")
204
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500205 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800206
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500207 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500208 if result == 0:
209 # TODO: The test for this case is commented out. Different
210 # builds of OpenSSL appear to have different failure modes that
211 # make it hard to test. Visual inspection of the OpenSSL
212 # source reveals that a return value of 0 signals an error.
213 # Manual testing on a particular build of OpenSSL suggests that
214 # this is probably the appropriate way to handle those errors.
215 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800216
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500217 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800218 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500219 # TODO: It appears as though this can fail if an engine is in
220 # use which does not support RSA.
221 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800222
223 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500224 dsa = _lib.DSA_generate_parameters(
225 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
226 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500227 # TODO: This is untested.
228 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500229 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500230 # TODO: This is untested.
231 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500232 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500233 # TODO: This is untested.
234 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800235 else:
236 raise Error("No such key type")
237
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800238 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800239
240
241 def check(self):
242 """
243 Check the consistency of an RSA private key.
244
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200245 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
246
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800247 :return: True if key is consistent.
248 :raise Error: if the key is inconsistent.
249 :raise TypeError: if the key is of a type which cannot be checked.
250 Only RSA keys can currently be checked.
251 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800252 if self._only_public:
253 raise TypeError("public key only")
254
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500255 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800256 raise TypeError("key type unsupported")
257
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500258 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
259 rsa = _ffi.gc(rsa, _lib.RSA_free)
260 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800261 if result:
262 return True
263 _raise_current_error()
264
265
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800266 def type(self):
267 """
268 Returns the type of the key
269
270 :return: The type of the key.
271 """
272 return self._pkey.type
273
274
275 def bits(self):
276 """
277 Returns the number of bits of the key
278
279 :return: The number of bits of the key.
280 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500281 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800282PKeyType = PKey
283
284
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800285
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400286class _EllipticCurve(object):
287 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400288 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400289
290 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
291 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
292 instances each of which represents one curve supported by the system.
293 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400294 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400295 _curves = None
296
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400297 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400298 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400299 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400300 """
301 Implement cooperation with the right-hand side argument of ``!=``.
302
303 Python 3 seems to have dropped this cooperation in this very narrow
304 circumstance.
305 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400306 if isinstance(other, _EllipticCurve):
307 return super(_EllipticCurve, self).__ne__(other)
308 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400309
310
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400311 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400312 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400313 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400314 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400315
316 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400317
318 :return: A :py:type:`set` of ``cls`` instances giving the names of the
319 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400320 """
321 if lib.Cryptography_HAS_EC:
322 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
323 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
324 # The return value on this call should be num_curves again. We could
325 # check it to make sure but if it *isn't* then.. what could we do?
326 # Abort the whole process, I suppose...? -exarkun
327 lib.EC_get_builtin_curves(builtin_curves, num_curves)
328 return set(
329 cls.from_nid(lib, c.nid)
330 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400331 return set()
332
333
334 @classmethod
335 def _get_elliptic_curves(cls, lib):
336 """
337 Get, cache, and return the curves supported by OpenSSL.
338
339 :param lib: The OpenSSL library binding object.
340
341 :return: A :py:type:`set` of ``cls`` instances giving the names of the
342 elliptic curves the underlying library supports.
343 """
344 if cls._curves is None:
345 cls._curves = cls._load_elliptic_curves(lib)
346 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400347
348
349 @classmethod
350 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400351 """
352 Instantiate a new :py:class:`_EllipticCurve` associated with the given
353 OpenSSL NID.
354
355 :param lib: The OpenSSL library binding object.
356
357 :param nid: The OpenSSL NID the resulting curve object will represent.
358 This must be a curve NID (and not, for example, a hash NID) or
359 subsequent operations will fail in unpredictable ways.
360 :type nid: :py:class:`int`
361
362 :return: The curve object.
363 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400364 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
365
366
367 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400368 """
369 :param _lib: The :py:mod:`cryptography` binding instance used to
370 interface with OpenSSL.
371
372 :param _nid: The OpenSSL NID identifying the curve this object
373 represents.
374 :type _nid: :py:class:`int`
375
376 :param name: The OpenSSL short name identifying the curve this object
377 represents.
378 :type name: :py:class:`unicode`
379 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400380 self._lib = lib
381 self._nid = nid
382 self.name = name
383
384
385 def __repr__(self):
386 return "<Curve %r>" % (self.name,)
387
388
389 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400390 """
391 Create a new OpenSSL EC_KEY structure initialized to use this curve.
392
393 The structure is automatically garbage collected when the Python object
394 is garbage collected.
395 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400396 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
397 return _ffi.gc(key, _lib.EC_KEY_free)
398
399
400
401def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400402 """
403 Return a set of objects representing the elliptic curves supported in the
404 OpenSSL build in use.
405
406 The curve objects have a :py:class:`unicode` ``name`` attribute by which
407 they identify themselves.
408
409 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400410 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
411 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400412 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400413 return _EllipticCurve._get_elliptic_curves(_lib)
414
415
416
417def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400418 """
419 Return a single curve object selected by name.
420
421 See :py:func:`get_elliptic_curves` for information about curve objects.
422
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400423 :param name: The OpenSSL short name identifying the curve object to
424 retrieve.
425 :type name: :py:class:`unicode`
426
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400427 If the named curve is not supported then :py:class:`ValueError` is raised.
428 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400429 for curve in get_elliptic_curves():
430 if curve.name == name:
431 return curve
432 raise ValueError("unknown curve name", name)
433
434
435
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800436class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200437 """
438 An X.509 Distinguished Name.
439
440 :ivar countryName: The country of the entity.
441 :ivar C: Alias for :py:attr:`countryName`.
442
443 :ivar stateOrProvinceName: The state or province of the entity.
444 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
445
446 :ivar localityName: The locality of the entity.
447 :ivar L: Alias for :py:attr:`localityName`.
448
449 :ivar organizationName: The organization name of the entity.
450 :ivar O: Alias for :py:attr:`organizationName`.
451
452 :ivar organizationalUnitName: The organizational unit of the entity.
453 :ivar OU: Alias for :py:attr:`organizationalUnitName`
454
455 :ivar commonName: The common name of the entity.
456 :ivar CN: Alias for :py:attr:`commonName`.
457
458 :ivar emailAddress: The e-mail address of the entity.
459 """
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800460 def __init__(self, name):
461 """
462 Create a new X509Name, copying the given X509Name instance.
463
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200464 :param name: The name to copy.
465 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800466 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500467 name = _lib.X509_NAME_dup(name._name)
468 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800469
470
471 def __setattr__(self, name, value):
472 if name.startswith('_'):
473 return super(X509Name, self).__setattr__(name, value)
474
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800475 # Note: we really do not want str subclasses here, so we do not use
476 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800477 if type(name) is not str:
478 raise TypeError("attribute name must be string, not '%.200s'" % (
479 type(value).__name__,))
480
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500481 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500482 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800483 try:
484 _raise_current_error()
485 except Error:
486 pass
487 raise AttributeError("No such attribute")
488
489 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500490 for i in range(_lib.X509_NAME_entry_count(self._name)):
491 ent = _lib.X509_NAME_get_entry(self._name, i)
492 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
493 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800494 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500495 ent = _lib.X509_NAME_delete_entry(self._name, i)
496 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800497 break
498
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500499 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800500 value = value.encode('utf-8')
501
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500502 add_result = _lib.X509_NAME_add_entry_by_NID(
503 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800504 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500505 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800506
507
508 def __getattr__(self, name):
509 """
510 Find attribute. An X509Name object has the following attributes:
511 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
512 organization (alias O), organizationalUnit (alias OU), commonName (alias
513 CN) and more...
514 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500515 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500516 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800517 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
518 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
519 # push something onto the error queue. If we don't clean that up
520 # now, someone else will bump into it later and be quite confused.
521 # See lp#314814.
522 try:
523 _raise_current_error()
524 except Error:
525 pass
526 return super(X509Name, self).__getattr__(name)
527
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500528 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800529 if entry_index == -1:
530 return None
531
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500532 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
533 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800534
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500535 result_buffer = _ffi.new("unsigned char**")
536 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800537 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500538 # TODO: This is untested.
539 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800540
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700541 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500542 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700543 finally:
544 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500545 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800546 return result
547
548
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500549 def _cmp(op):
550 def f(self, other):
551 if not isinstance(other, X509Name):
552 return NotImplemented
553 result = _lib.X509_NAME_cmp(self._name, other._name)
554 return op(result, 0)
555 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800556
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500557 __eq__ = _cmp(__eq__)
558 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800559
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500560 __lt__ = _cmp(__lt__)
561 __le__ = _cmp(__le__)
562
563 __gt__ = _cmp(__gt__)
564 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800565
566 def __repr__(self):
567 """
568 String representation of an X509Name
569 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500570 result_buffer = _ffi.new("char[]", 512);
571 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800572 self._name, result_buffer, len(result_buffer))
573
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500574 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500575 # TODO: This is untested.
576 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800577
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500578 return "<X509Name object '%s'>" % (
579 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800580
581
582 def hash(self):
583 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200584 Return an integer representation of the first four bytes of the
585 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800586
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200587 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
588
589 :return: The (integer) hash of this name.
590 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800591 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500592 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800593
594
595 def der(self):
596 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200597 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800598
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200599 :return: The DER encoded form of this name.
600 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800601 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500602 result_buffer = _ffi.new('unsigned char**')
603 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800604 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500605 # TODO: This is untested.
606 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800607
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500608 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
609 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800610 return string_result
611
612
613 def get_components(self):
614 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200615 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800616
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200617 :return: The components of this name.
618 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800619 """
620 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500621 for i in range(_lib.X509_NAME_entry_count(self._name)):
622 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800623
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500624 fname = _lib.X509_NAME_ENTRY_get_object(ent)
625 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800626
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500627 nid = _lib.OBJ_obj2nid(fname)
628 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800629
630 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500631 _ffi.string(name),
632 _ffi.string(
633 _lib.ASN1_STRING_data(fval),
634 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800635
636 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200637
638
639
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800640X509NameType = X509Name
641
642
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200643
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800644class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200645 """
646 An X.509 v3 certificate extension.
647 """
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800648 def __init__(self, type_name, critical, value, subject=None, issuer=None):
649 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200650 Initializes an X509 extension.
651
652 :param typename: The name of the type of extension to create. See
653 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800654 :type typename: :py:data:`str`
655
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200656 :param bool critical: A flag indicating whether this is a critical extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800657
658 :param value: The value of the extension.
659 :type value: :py:data:`str`
660
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200661 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800662 :type subject: :py:class:`X509`
663
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200664 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800665 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800666 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500667 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800668
669 # A context is necessary for any extension which uses the r2i conversion
670 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
671 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500672 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800673
674 # We have no configuration database - but perhaps we should (some
675 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500676 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800677
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800678 # Initialize the subject and issuer, if appropriate. ctx is a local,
679 # and as far as I can tell none of the X509V3_* APIs invoked here steal
680 # any references, so no need to mess with reference counts or duplicates.
681 if issuer is not None:
682 if not isinstance(issuer, X509):
683 raise TypeError("issuer must be an X509 instance")
684 ctx.issuer_cert = issuer._x509
685 if subject is not None:
686 if not isinstance(subject, X509):
687 raise TypeError("subject must be an X509 instance")
688 ctx.subject_cert = subject._x509
689
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800690 if critical:
691 # There are other OpenSSL APIs which would let us pass in critical
692 # separately, but they're harder to use, and since value is already
693 # a pile of crappy junk smuggling a ton of utterly important
694 # structured data, what's the point of trying to avoid nasty stuff
695 # with strings? (However, X509V3_EXT_i2d in particular seems like it
696 # would be a better API to invoke. I do not know where to get the
697 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500698 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800699
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500700 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
701 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800702 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500703 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800704
705
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400706 @property
707 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500708 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400709
710 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500711 _lib.GEN_EMAIL: "email",
712 _lib.GEN_DNS: "DNS",
713 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400714 }
715
716 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500717 method = _lib.X509V3_EXT_get(self._extension)
718 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500719 # TODO: This is untested.
720 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400721 payload = self._extension.value.data
722 length = self._extension.value.length
723
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500724 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400725 payloadptr[0] = payload
726
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500727 if method.it != _ffi.NULL:
728 ptr = _lib.ASN1_ITEM_ptr(method.it)
729 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
730 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400731 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500732 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400733 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500734 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400735
736 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500737 for i in range(_lib.sk_GENERAL_NAME_num(names)):
738 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400739 try:
740 label = self._prefixes[name.type]
741 except KeyError:
742 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500743 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500744 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400745 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500746 value = _native(
747 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
748 parts.append(label + ":" + value)
749 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400750
751
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800752 def __str__(self):
753 """
754 :return: a nice text representation of the extension
755 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500756 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400757 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800758
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400759 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500760 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800761 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500762 # TODO: This is untested.
763 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800764
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500765 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800766
767
768 def get_critical(self):
769 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200770 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800771
772 :return: The critical field.
773 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500774 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800775
776
777 def get_short_name(self):
778 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200779 Returns the short type name of this X.509 extension.
780
781 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800782
783 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200784 :rtype: :py:data:`bytes`
785
786 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800787 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500788 obj = _lib.X509_EXTENSION_get_object(self._extension)
789 nid = _lib.OBJ_obj2nid(obj)
790 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800791
792
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800793 def get_data(self):
794 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200795 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800796
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200797 :return: The ASN.1 encoded data of this X509 extension.
798 :rtype: :py:data:`bytes`
799
800 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800801 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500802 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
803 string_result = _ffi.cast('ASN1_STRING*', octet_result)
804 char_result = _lib.ASN1_STRING_data(string_result)
805 result_length = _lib.ASN1_STRING_length(string_result)
806 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800807
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200808
809
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800810X509ExtensionType = X509Extension
811
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800812
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200813
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800814class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200815 """
816 An X.509 certificate signing requests.
817 """
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800818 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500819 req = _lib.X509_REQ_new()
820 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800821
822
823 def set_pubkey(self, pkey):
824 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200825 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800826
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200827 :param pkey: The public key to use.
828 :type pkey: :py:class:`PKey`
829
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200830 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800831 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500832 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800833 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500834 # TODO: This is untested.
835 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800836
837
838 def get_pubkey(self):
839 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200840 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800841
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200842 :return: The public key.
843 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800844 """
845 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500846 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
847 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500848 # TODO: This is untested.
849 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500850 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800851 pkey._only_public = True
852 return pkey
853
854
855 def set_version(self, version):
856 """
857 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
858 request.
859
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200860 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200861 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800862 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500863 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800864 if not set_result:
865 _raise_current_error()
866
867
868 def get_version(self):
869 """
870 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
871 request.
872
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200873 :return: The value of the version subfield.
874 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800875 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500876 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800877
878
879 def get_subject(self):
880 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200881 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800882
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200883 This creates a new :py:class:`X509Name`: modifying it does not affect
884 this request.
885
886 :return: The subject of this certificate signing request.
887 :rtype: :py:class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800888 """
889 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500890 name._name = _lib.X509_REQ_get_subject_name(self._req)
891 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500892 # TODO: This is untested.
893 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800894
895 # The name is owned by the X509Req structure. As long as the X509Name
896 # Python object is alive, keep the X509Req Python object alive.
897 name._owner = self
898
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800899 return name
900
901
902 def add_extensions(self, extensions):
903 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200904 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800905
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200906 :param extensions: The X.509 extensions to add.
907 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200908 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800909 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500910 stack = _lib.sk_X509_EXTENSION_new_null()
911 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500912 # TODO: This is untested.
913 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800914
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500915 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800916
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800917 for ext in extensions:
918 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800919 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800920
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800921 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500922 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800923
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500924 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800925 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500926 # TODO: This is untested.
927 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800928
929
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800930 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800931 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200932 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800933
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200934 :return: The X.509 extensions in this request.
935 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
936
937 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800938 """
939 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500940 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500941 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800942 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500943 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800944 exts.append(ext)
945 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800946
947
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800948 def sign(self, pkey, digest):
949 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700950 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800951
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200952 :param pkey: The key pair to sign with.
953 :type pkey: :py:class:`PKey`
954 :param digest: The name of the message digest to use for the signature,
955 e.g. :py:data:`b"sha1"`.
956 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200957 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800958 """
959 if pkey._only_public:
960 raise ValueError("Key has only public part")
961
962 if not pkey._initialized:
963 raise ValueError("Key is uninitialized")
964
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500965 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500966 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800967 raise ValueError("No such digest method")
968
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500969 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800970 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500971 # TODO: This is untested.
972 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800973
974
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800975 def verify(self, pkey):
976 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200977 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800978
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200979 :param key: A public key.
980 :type key: :py:class:`PKey`
981 :return: :py:data:`True` if the signature is correct.
982 :rtype: :py:class:`bool`
983 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800984 problem verifying the signature.
985 """
986 if not isinstance(pkey, PKey):
987 raise TypeError("pkey must be a PKey instance")
988
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500989 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800990 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500991 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800992
993 return result
994
995
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200996
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800997X509ReqType = X509Req
998
999
1000
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001001class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001002 """
1003 An X.509 certificate.
1004 """
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001005 def __init__(self):
1006 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001007 x509 = _lib.X509_new()
1008 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001009
1010
1011 def set_version(self, version):
1012 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001013 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001014
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001015 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001016 :type version: :py:class:`int`
1017
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001018 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001019 """
1020 if not isinstance(version, int):
1021 raise TypeError("version must be an integer")
1022
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001023 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001024
1025
1026 def get_version(self):
1027 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001028 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001029
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001030 :return: The version number of the certificate.
1031 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001032 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001033 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001034
1035
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001036 def get_pubkey(self):
1037 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001038 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001039
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001040 :return: The public key.
1041 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001042 """
1043 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001044 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1045 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001046 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001047 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001048 pkey._only_public = True
1049 return pkey
1050
1051
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001052 def set_pubkey(self, pkey):
1053 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001054 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001055
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001056 :param pkey: The public key.
1057 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001058
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001059 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001060 """
1061 if not isinstance(pkey, PKey):
1062 raise TypeError("pkey must be a PKey instance")
1063
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001064 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001065 if not set_result:
1066 _raise_current_error()
1067
1068
1069 def sign(self, pkey, digest):
1070 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001071 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001072
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001073 :param pkey: The key to sign with.
1074 :type pkey: :py:class:`PKey`
1075
1076 :param digest: The name of the message digest to use.
1077 :type digest: :py:class:`bytes`
1078
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001079 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001080 """
1081 if not isinstance(pkey, PKey):
1082 raise TypeError("pkey must be a PKey instance")
1083
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001084 if pkey._only_public:
1085 raise ValueError("Key only has public part")
1086
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001087 if not pkey._initialized:
1088 raise ValueError("Key is uninitialized")
1089
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001090 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001091 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001092 raise ValueError("No such digest method")
1093
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001094 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001095 if not sign_result:
1096 _raise_current_error()
1097
1098
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001099 def get_signature_algorithm(self):
1100 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001101 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001102
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001103 :return: The name of the algorithm.
1104 :rtype: :py:class:`bytes`
1105
1106 :raises ValueError: If the signature algorithm is undefined.
1107
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001108 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001109 """
1110 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001111 nid = _lib.OBJ_obj2nid(alg)
1112 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001113 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001114 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001115
1116
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001117 def digest(self, digest_name):
1118 """
1119 Return the digest of the X509 object.
1120
1121 :param digest_name: The name of the digest algorithm to use.
1122 :type digest_name: :py:class:`bytes`
1123
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001124 :return: The digest of the object, formatted as
1125 :py:const:`b":"`-delimited hex pairs.
1126 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001127 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001128 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001129 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001130 raise ValueError("No such digest method")
1131
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001132 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1133 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001134 result_length[0] = len(result_buffer)
1135
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001136 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001137 self._x509, digest, result_buffer, result_length)
1138
1139 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001140 # TODO: This is untested.
1141 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001142
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001143 return b":".join([
1144 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001145 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001146
1147
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001148 def subject_name_hash(self):
1149 """
1150 Return the hash of the X509 subject.
1151
1152 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001153 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001154 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001155 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001156
1157
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001158 def set_serial_number(self, serial):
1159 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001160 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001161
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001162 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001163 :type serial: :py:class:`int`
1164
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001165 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001166 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001167 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001168 raise TypeError("serial must be an integer")
1169
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001170 hex_serial = hex(serial)[2:]
1171 if not isinstance(hex_serial, bytes):
1172 hex_serial = hex_serial.encode('ascii')
1173
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001174 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001175
1176 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1177 # it. If bignum is still NULL after this call, then the return value is
1178 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001179 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001180
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001181 if bignum_serial[0] == _ffi.NULL:
1182 set_result = _lib.ASN1_INTEGER_set(
1183 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001184 if set_result:
1185 # TODO Not tested
1186 _raise_current_error()
1187 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001188 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1189 _lib.BN_free(bignum_serial[0])
1190 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001191 # TODO Not tested
1192 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001193 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1194 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001195 if not set_result:
1196 # TODO Not tested
1197 _raise_current_error()
1198
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001199
1200 def get_serial_number(self):
1201 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001202 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001203
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001204 :return: The serial number.
1205 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001206 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001207 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1208 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001209 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001210 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001211 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001212 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001213 serial = int(hexstring_serial, 16)
1214 return serial
1215 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001216 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001217 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001218 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001219
1220
1221 def gmtime_adj_notAfter(self, amount):
1222 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001223 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001224
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001225 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001226 :type amount: :py:class:`int`
1227
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001228 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001229 """
1230 if not isinstance(amount, int):
1231 raise TypeError("amount must be an integer")
1232
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001233 notAfter = _lib.X509_get_notAfter(self._x509)
1234 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001235
1236
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001237 def gmtime_adj_notBefore(self, amount):
1238 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001239 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001240
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001241 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001242 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001243 """
1244 if not isinstance(amount, int):
1245 raise TypeError("amount must be an integer")
1246
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001247 notBefore = _lib.X509_get_notBefore(self._x509)
1248 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001249
1250
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001251 def has_expired(self):
1252 """
1253 Check whether the certificate has expired.
1254
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001255 :return: :py:const:`True` if the certificate has expired,
1256 :py:const:`False` otherwise.
1257 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001258 """
1259 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001260 notAfter = _lib.X509_get_notAfter(self._x509)
1261 return _lib.ASN1_UTCTIME_cmp_time_t(
1262 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001263
1264
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001265 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001266 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001267
1268
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001269 def get_notBefore(self):
1270 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001271 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001272
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001273 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001274
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001275 YYYYMMDDhhmmssZ
1276 YYYYMMDDhhmmss+hhmm
1277 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001278
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001279 :return: A timestamp string, or :py:const:`None` if there is none.
1280 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001281 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001282 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001283
1284
1285 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001286 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001287
1288
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001289 def set_notBefore(self, when):
1290 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001291 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001292
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001293 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001294
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001295 YYYYMMDDhhmmssZ
1296 YYYYMMDDhhmmss+hhmm
1297 YYYYMMDDhhmmss-hhmm
1298
1299 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001300 :type when: :py:class:`bytes`
1301
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001302 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001303 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001304 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001305
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001306
1307 def get_notAfter(self):
1308 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001309 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001310
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001311 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001312
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001313 YYYYMMDDhhmmssZ
1314 YYYYMMDDhhmmss+hhmm
1315 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001316
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001317 :return: A timestamp string, or :py:const:`None` if there is none.
1318 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001319 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001320 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001321
1322
1323 def set_notAfter(self, when):
1324 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001325 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001326
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001327 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001328
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001329 YYYYMMDDhhmmssZ
1330 YYYYMMDDhhmmss+hhmm
1331 YYYYMMDDhhmmss-hhmm
1332
1333 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001334 :type when: :py:class:`bytes`
1335
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001336 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001337 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001338 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001339
1340
1341 def _get_name(self, which):
1342 name = X509Name.__new__(X509Name)
1343 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001344 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001345 # TODO: This is untested.
1346 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001347
1348 # The name is owned by the X509 structure. As long as the X509Name
1349 # Python object is alive, keep the X509 Python object alive.
1350 name._owner = self
1351
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001352 return name
1353
1354
1355 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001356 if not isinstance(name, X509Name):
1357 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001358 set_result = which(self._x509, name._name)
1359 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001360 # TODO: This is untested.
1361 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001362
1363
1364 def get_issuer(self):
1365 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001366 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001367
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001368 This creates a new :py:class:`X509Name`: modifying it does not affect
1369 this certificate.
1370
1371 :return: The issuer of this certificate.
1372 :rtype: :py:class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001373 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001374 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001375
1376
1377 def set_issuer(self, issuer):
1378 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001379 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001380
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001381 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001382 :type issuer: :py:class:`X509Name`
1383
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001384 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001385 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001386 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001387
1388
1389 def get_subject(self):
1390 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001391 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001392
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001393 This creates a new :py:class:`X509Name`: modifying it does not affect
1394 this certificate.
1395
1396 :return: The subject of this certificate.
1397 :rtype: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001398 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001399 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001400
1401
1402 def set_subject(self, subject):
1403 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001404 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001405
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001406 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001407 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001408
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001409 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001410 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001411 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001412
1413
1414 def get_extension_count(self):
1415 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001416 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001417
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001418 :return: The number of extensions.
1419 :rtype: :py:class:`int`
1420
1421 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001422 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001423 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001424
1425
1426 def add_extensions(self, extensions):
1427 """
1428 Add extensions to the certificate.
1429
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001430 :param extensions: The extensions to add.
1431 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001432 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001433 """
1434 for ext in extensions:
1435 if not isinstance(ext, X509Extension):
1436 raise ValueError("One of the elements is not an X509Extension")
1437
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001438 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001439 if not add_result:
1440 _raise_current_error()
1441
1442
1443 def get_extension(self, index):
1444 """
1445 Get a specific extension of the certificate by index.
1446
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001447 Extensions on a certificate are kept in order. The index
1448 parameter selects which extension will be returned.
1449
1450 :param int index: The index of the extension to retrieve.
1451 :return: The extension at the specified index.
1452 :rtype: :py:class:`X509Extension`
1453 :raises IndexError: If the extension index was out of bounds.
1454
1455 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001456 """
1457 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001458 ext._extension = _lib.X509_get_ext(self._x509, index)
1459 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001460 raise IndexError("extension index out of bounds")
1461
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001462 extension = _lib.X509_EXTENSION_dup(ext._extension)
1463 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001464 return ext
1465
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001466
1467
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001468X509Type = X509
1469
1470
1471
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001472class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001473 """
1474 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001475 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001476 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001477 store = _lib.X509_STORE_new()
1478 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001479
1480
1481 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001482 """
1483 Adds the certificate :py:data:`cert` to this store.
1484
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001485 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001486
1487 :param X509 cert: The certificate to add to this store.
1488 :raises TypeError: If the certificate is not an :py:class:`X509`.
1489 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001490 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001491 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001492 if not isinstance(cert, X509):
1493 raise TypeError()
1494
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001495 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001496 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001497 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001498
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001499
1500X509StoreType = X509Store
1501
1502
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001503class X509StoreContextError(Exception):
1504 """
1505 An error occurred while verifying a certificate using
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001506 `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001507
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001508 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001509 :type cert: :class:`X509`
1510
1511 """
1512 def __init__(self, message, certificate):
1513 super(X509StoreContextError, self).__init__(message)
1514 self.certificate = certificate
1515
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001516
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001517class X509StoreContext(object):
1518 """
1519 An X.509 store context.
1520
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001521 An :py:class:`X509StoreContext` is used to define some of the criteria for
1522 certificate verification. The information encapsulated in this object
1523 includes, but is not limited to, a set of trusted certificates,
1524 verification parameters, and revoked certificates.
1525
1526 Of these, only the set of trusted certificates is currently exposed.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001527
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001528 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1529 instance. It is dynamically allocated and automatically garbage
1530 collected.
1531
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001532 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001533
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001534 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001535 """
1536
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001537 def __init__(self, store, certificate):
1538 """
1539 :param X509Store store: The certificates which will be trusted for the
1540 purposes of any verifications.
1541
1542 :param X509 certificate: The certificate to be verified.
1543 """
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001544 store_ctx = _lib.X509_STORE_CTX_new()
1545 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1546 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001547 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001548 # Make the store context available for use after instantiating this
1549 # class by initializing it now. Per testing, subsequent calls to
1550 # :py:meth:`_init` have no adverse affect.
1551 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001552
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001553
1554 def _init(self):
1555 """
1556 Set up the store context for a subsequent verification operation.
1557 """
1558 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1559 if ret <= 0:
1560 _raise_current_error()
1561
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001562
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001563 def _cleanup(self):
1564 """
1565 Internally cleans up the store context.
1566
1567 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001568 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001569 """
1570 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1571
1572
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001573 def _exception_from_context(self):
1574 """
1575 Convert an OpenSSL native context error failure into a Python
1576 exception.
1577
1578 When a call to native OpenSSL X509_verify_cert fails, additonal information
1579 about the failure can be obtained from the store context.
1580 """
1581 errors = [
1582 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1583 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1584 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1585 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1586 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001587 # A context error should always be associated with a certificate, so we
1588 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001589 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001590 _cert = _lib.X509_dup(_x509)
1591 pycert = X509.__new__(X509)
1592 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001593 return X509StoreContextError(errors, pycert)
1594
1595
Stephen Holsapple46a09252015-02-12 14:45:43 -08001596 def set_store(self, store):
1597 """
1598 Set the context's trust store.
1599
1600 :param X509Store store: The certificates which will be trusted for the
1601 purposes of any *future* verifications.
1602 """
1603 self._store = store
1604
1605
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001606 def verify_certificate(self):
1607 """
1608 Verify a certificate in a context.
1609
1610 :param store_ctx: The :py:class:`X509StoreContext` to verify.
1611 :raises: Error
1612 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001613 # Always re-initialize the store context in case
1614 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001615 self._init()
1616 ret = _lib.X509_verify_cert(self._store_ctx)
1617 self._cleanup()
1618 if ret <= 0:
1619 raise self._exception_from_context()
1620
1621
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001622
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001623def load_certificate(type, buffer):
1624 """
1625 Load a certificate from a buffer
1626
1627 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001628
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001629 :param buffer: The buffer the certificate is stored in
1630 :type buffer: :py:class:`bytes`
1631
1632 :return: The X509 object
1633 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001634 if isinstance(buffer, _text_type):
1635 buffer = buffer.encode("ascii")
1636
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001637 bio = _new_mem_buf(buffer)
1638
1639 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001640 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001641 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001642 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001643 else:
1644 raise ValueError(
1645 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1646
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001647 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001648 _raise_current_error()
1649
1650 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001651 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001652 return cert
1653
1654
1655def dump_certificate(type, cert):
1656 """
1657 Dump a certificate to a buffer
1658
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001659 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1660 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001661 :param cert: The certificate to dump
1662 :return: The buffer with the dumped certificate in
1663 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001664 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001665
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001666 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001667 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001668 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001669 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001670 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001671 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001672 else:
1673 raise ValueError(
1674 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1675 "FILETYPE_TEXT")
1676
1677 return _bio_to_string(bio)
1678
1679
1680
1681def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1682 """
1683 Dump a private key to a buffer
1684
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001685 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1686 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001687 :param pkey: The PKey to dump
1688 :param cipher: (optional) if encrypted PEM format, the cipher to
1689 use
1690 :param passphrase: (optional) if encrypted PEM format, this can be either
1691 the passphrase to use, or a callback for providing the
1692 passphrase.
1693 :return: The buffer with the dumped key in
1694 :rtype: :py:data:`str`
1695 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001696 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001697
1698 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001699 if passphrase is None:
1700 raise TypeError(
1701 "if a value is given for cipher "
1702 "one must also be given for passphrase")
1703 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001704 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001705 raise ValueError("Invalid cipher name")
1706 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001707 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001708
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001709 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001710 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001711 result_code = _lib.PEM_write_bio_PrivateKey(
1712 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001713 helper.callback, helper.callback_args)
1714 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001715 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001716 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001717 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001718 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1719 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001720 # TODO RSA_free(rsa)?
1721 else:
1722 raise ValueError(
1723 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1724 "FILETYPE_TEXT")
1725
1726 if result_code == 0:
1727 _raise_current_error()
1728
1729 return _bio_to_string(bio)
1730
1731
1732
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001733def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001734 copy = _lib.X509_REVOKED_new()
1735 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001736 # TODO: This is untested.
1737 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001738
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001739 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001740 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001741 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001742
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001743 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001744 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001745 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001746
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001747 if original.extensions != _ffi.NULL:
1748 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1749 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1750 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1751 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1752 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001753 copy.extensions = extension_stack
1754
1755 copy.sequence = original.sequence
1756 return copy
1757
1758
1759
1760class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001761 """
1762 A certificate revocation.
1763 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001764 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1765 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1766 # OCSP_crl_reason_str. We use the latter, just like the command line
1767 # program.
1768 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001769 b"unspecified",
1770 b"keyCompromise",
1771 b"CACompromise",
1772 b"affiliationChanged",
1773 b"superseded",
1774 b"cessationOfOperation",
1775 b"certificateHold",
1776 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001777 ]
1778
1779 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001780 revoked = _lib.X509_REVOKED_new()
1781 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001782
1783
1784 def set_serial(self, hex_str):
1785 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001786 Set the serial number.
1787
1788 The serial number is formatted as a hexadecimal number encoded in
1789 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001790
1791 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001792 :type hex_str: :py:class:`bytes`
1793
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001794 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001795 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001796 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1797 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001798 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001799 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001800 if not bn_result:
1801 raise ValueError("bad hex string")
1802
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001803 asn1_serial = _ffi.gc(
1804 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1805 _lib.ASN1_INTEGER_free)
1806 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807
1808
1809 def get_serial(self):
1810 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001811 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001812
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001813 The serial number is formatted as a hexadecimal number encoded in
1814 ASCII.
1815
1816 :return: The serial number.
1817 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001818 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001819 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001820
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001821 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001822 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001823 # TODO: This is untested.
1824 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001825
1826 return _bio_to_string(bio)
1827
1828
1829 def _delete_reason(self):
1830 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001831 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1832 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1833 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1834 _lib.X509_EXTENSION_free(ext)
1835 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001836 break
1837
1838
1839 def set_reason(self, reason):
1840 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001841 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001842
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001843 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001844
1845 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001846 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1847
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001848 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001849
1850 .. seealso::
1851
1852 :py:meth:`all_reasons`, which gives you a list of all supported
1853 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001854 """
1855 if reason is None:
1856 self._delete_reason()
1857 elif not isinstance(reason, bytes):
1858 raise TypeError("reason must be None or a byte string")
1859 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001860 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001861 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1862
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001863 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1864 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001865 # TODO: This is untested.
1866 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001867 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001868
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001869 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1870 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001871 # TODO: This is untested.
1872 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001873
1874 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001875 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1876 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001877
1878 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001879 # TODO: This is untested.
1880 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001881
1882
1883 def get_reason(self):
1884 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001885 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001886
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001887 :return: The reason, or :py:const:`None` if there is none.
1888 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1889
1890 .. seealso::
1891
1892 :py:meth:`all_reasons`, which gives you a list of all supported
1893 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001894 """
1895 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001896 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1897 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1898 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001899 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001900
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001901 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001902 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001903 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001904 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001905 # TODO: This is untested.
1906 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001907
1908 return _bio_to_string(bio)
1909
1910
1911 def all_reasons(self):
1912 """
1913 Return a list of all the supported reason strings.
1914
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001915 This list is a copy; modifying it does not change the supported reason
1916 strings.
1917
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001918 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001919 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001920 """
1921 return self._crl_reasons[:]
1922
1923
1924 def set_rev_date(self, when):
1925 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001926 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001927
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001928 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1929 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001930 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001931 """
1932 return _set_asn1_time(self._revoked.revocationDate, when)
1933
1934
1935 def get_rev_date(self):
1936 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001937 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001938
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001939 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1940 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001941 """
1942 return _get_asn1_time(self._revoked.revocationDate)
1943
1944
1945
1946class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001947 """
1948 A certificate revocation list.
1949 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001950 def __init__(self):
1951 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001952 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001953 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001954 crl = _lib.X509_CRL_new()
1955 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001956
1957
1958 def get_revoked(self):
1959 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001960 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001961
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001962 These revocations will be provided by value, not by reference.
1963 That means it's okay to mutate them: it won't affect this CRL.
1964
1965 :return: The revocations in this CRL.
1966 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001967 """
1968 results = []
1969 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001970 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1971 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001972 revoked_copy = _X509_REVOKED_dup(revoked)
1973 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001974 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001975 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001976 if results:
1977 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001978
1979
1980 def add_revoked(self, revoked):
1981 """
1982 Add a revoked (by value not reference) to the CRL structure
1983
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001984 This revocation will be added by value, not by reference. That
1985 means it's okay to mutate it after adding: it won't affect
1986 this CRL.
1987
1988 :param revoked: The new revocation.
1989 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001990
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001991 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001992 """
1993 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001994 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001995 # TODO: This is untested.
1996 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001997
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001998 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001999 if add_result == 0:
2000 # TODO: This is untested.
2001 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002002
2003
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002004 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002005 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002006 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002007 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002008
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002009 :param cert: The certificate used to sign the CRL.
2010 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002011
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002012 :param key: The key used to sign the CRL.
2013 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002014
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002015 :param type: The export format, either :py:data:`FILETYPE_PEM`,
2016 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002017
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002018 :param int days: The number of days until the next update of this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002019
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002020 :param bytes digest: The name of the message digest to use (eg
2021 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002022
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002023 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002024 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002025 if not isinstance(cert, X509):
2026 raise TypeError("cert must be an X509 instance")
2027 if not isinstance(key, PKey):
2028 raise TypeError("key must be a PKey instance")
2029 if not isinstance(type, int):
2030 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002031
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002032 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002033 _warn(
2034 "The default message digest (md5) is deprecated. "
2035 "Pass the name of a message digest explicitly.",
2036 category=DeprecationWarning,
2037 stacklevel=2,
2038 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002039 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002040
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002041 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002042 if digest_obj == _ffi.NULL:
2043 raise ValueError("No such digest method")
2044
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002045 bio = _lib.BIO_new(_lib.BIO_s_mem())
2046 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002047 # TODO: This is untested.
2048 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002049
2050 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002051 sometime = _lib.ASN1_TIME_new()
2052 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002053 # TODO: This is untested.
2054 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002055
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002056 _lib.X509_gmtime_adj(sometime, 0)
2057 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002058
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002059 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2060 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002061
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002062 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002063
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002064 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002065 if not sign_result:
2066 _raise_current_error()
2067
2068 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002069 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002070 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002071 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002072 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002073 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002074 else:
2075 raise ValueError(
2076 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
2077
2078 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002079 # TODO: This is untested.
2080 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002081
2082 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002083CRLType = CRL
2084
2085
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002086
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002087class PKCS7(object):
2088 def type_is_signed(self):
2089 """
2090 Check if this NID_pkcs7_signed object
2091
2092 :return: True if the PKCS7 is of type signed
2093 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002094 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002095 return True
2096 return False
2097
2098
2099 def type_is_enveloped(self):
2100 """
2101 Check if this NID_pkcs7_enveloped object
2102
2103 :returns: True if the PKCS7 is of type enveloped
2104 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002105 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002106 return True
2107 return False
2108
2109
2110 def type_is_signedAndEnveloped(self):
2111 """
2112 Check if this NID_pkcs7_signedAndEnveloped object
2113
2114 :returns: True if the PKCS7 is of type signedAndEnveloped
2115 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002116 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002117 return True
2118 return False
2119
2120
2121 def type_is_data(self):
2122 """
2123 Check if this NID_pkcs7_data object
2124
2125 :return: True if the PKCS7 is of type data
2126 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002127 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002128 return True
2129 return False
2130
2131
2132 def get_type_name(self):
2133 """
2134 Returns the type name of the PKCS7 structure
2135
2136 :return: A string with the typename
2137 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002138 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2139 string_type = _lib.OBJ_nid2sn(nid)
2140 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002141
2142PKCS7Type = PKCS7
2143
2144
2145
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002146class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002147 """
2148 A PKCS #12 archive.
2149 """
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002150 def __init__(self):
2151 self._pkey = None
2152 self._cert = None
2153 self._cacerts = None
2154 self._friendlyname = None
2155
2156
2157 def get_certificate(self):
2158 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002159 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002160
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002161 :return: The certificate, or :py:const:`None` if there is none.
2162 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002163 """
2164 return self._cert
2165
2166
2167 def set_certificate(self, cert):
2168 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002169 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002170
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002171 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002172 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002173
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002174 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002175 """
2176 if not isinstance(cert, X509):
2177 raise TypeError("cert must be an X509 instance")
2178 self._cert = cert
2179
2180
2181 def get_privatekey(self):
2182 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002183 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002184
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002185 :return: The private key, or :py:const:`None` if there is none.
2186 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002187 """
2188 return self._pkey
2189
2190
2191 def set_privatekey(self, pkey):
2192 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002193 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002194
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002195 :param pkey: The new private key, or :py:const:`None` to unset it.
2196 :type pkey: :py:class:`PKey` or :py:const:`None`
2197
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002198 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002199 """
2200 if not isinstance(pkey, PKey):
2201 raise TypeError("pkey must be a PKey instance")
2202 self._pkey = pkey
2203
2204
2205 def get_ca_certificates(self):
2206 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002207 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002208
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002209 :return: A tuple with the CA certificates in the chain, or
2210 :py:const:`None` if there are none.
2211 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002212 """
2213 if self._cacerts is not None:
2214 return tuple(self._cacerts)
2215
2216
2217 def set_ca_certificates(self, cacerts):
2218 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002219 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002220
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002221 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2222 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002223 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002224
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002225 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002226 """
2227 if cacerts is None:
2228 self._cacerts = None
2229 else:
2230 cacerts = list(cacerts)
2231 for cert in cacerts:
2232 if not isinstance(cert, X509):
2233 raise TypeError("iterable must only contain X509 instances")
2234 self._cacerts = cacerts
2235
2236
2237 def set_friendlyname(self, name):
2238 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002239 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002240
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002241 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002242 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002243
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002244 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002245 """
2246 if name is None:
2247 self._friendlyname = None
2248 elif not isinstance(name, bytes):
2249 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2250 self._friendlyname = name
2251
2252
2253 def get_friendlyname(self):
2254 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002255 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002256
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002257 :returns: The friendly name, or :py:const:`None` if there is none.
2258 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002259 """
2260 return self._friendlyname
2261
2262
2263 def export(self, passphrase=None, iter=2048, maciter=1):
2264 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002265 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002266
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002267 For more information, see the :c:func:`PKCS12_create` man page.
2268
2269 :param passphrase: The passphrase used to encrypt the structure. Unlike
2270 some other passphrase arguments, this *must* be a string, not a
2271 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002272 :type passphrase: :py:data:`bytes`
2273
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002274 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002275 :type iter: :py:data:`int`
2276
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002277 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002278 :type maciter: :py:data:`int`
2279
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002280 :return: The string representation of the PKCS #12 structure.
2281 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002282 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002283 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002284
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002285 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002286 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002287 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002288 cacerts = _lib.sk_X509_new_null()
2289 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002290 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002291 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002292
2293 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002294 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002295
2296 friendlyname = self._friendlyname
2297 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002298 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002299
2300 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002301 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002302 else:
2303 pkey = self._pkey._pkey
2304
2305 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002306 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002307 else:
2308 cert = self._cert._x509
2309
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002310 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002311 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002312 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2313 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002314 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002315 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002316 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002317 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002318
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002319 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002320 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002321 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002322
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002323
2324
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002325PKCS12Type = PKCS12
2326
2327
2328
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002329class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002330 """
2331 A Netscape SPKI object.
2332 """
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002333 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002334 spki = _lib.NETSCAPE_SPKI_new()
2335 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002336
2337
2338 def sign(self, pkey, digest):
2339 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002340 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002341
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002342 :param pkey: The private key to sign with.
2343 :type pkey: :py:class:`PKey`
2344
2345 :param digest: The message digest to use.
2346 :type digest: :py:class:`bytes`
2347
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002348 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002349 """
2350 if pkey._only_public:
2351 raise ValueError("Key has only public part")
2352
2353 if not pkey._initialized:
2354 raise ValueError("Key is uninitialized")
2355
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002356 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002357 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002358 raise ValueError("No such digest method")
2359
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002360 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002361 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002362 # TODO: This is untested.
2363 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002364
2365
2366 def verify(self, key):
2367 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002368 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002369
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002370 :param key: The public key that signature is supposedly from.
2371 :type pkey: :py:class:`PKey`
2372
2373 :return: :py:const:`True` if the signature is correct.
2374 :rtype: :py:class:`bool`
2375
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002376 :raises Error: If the signature is invalid, or there was a problem
2377 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002378 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002379 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002380 if answer <= 0:
2381 _raise_current_error()
2382 return True
2383
2384
2385 def b64_encode(self):
2386 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002387 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002388
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002389 :return: The base64 encoded string.
2390 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002391 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002392 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2393 result = _ffi.string(encoded)
2394 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002395 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002396
2397
2398 def get_pubkey(self):
2399 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002400 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002401
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002402 :return: The public key.
2403 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002404 """
2405 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002406 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2407 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002408 # TODO: This is untested.
2409 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002410 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002411 pkey._only_public = True
2412 return pkey
2413
2414
2415 def set_pubkey(self, pkey):
2416 """
2417 Set the public key of the certificate
2418
2419 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002420 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002421 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002422 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002423 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002424 # TODO: This is untested.
2425 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002426
2427
2428
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002429NetscapeSPKIType = NetscapeSPKI
2430
2431
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002432
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002433class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002434 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002435 if type != FILETYPE_PEM and passphrase is not None:
2436 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002437 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002438 self._more_args = more_args
2439 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002440 self._problems = []
2441
2442
2443 @property
2444 def callback(self):
2445 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002446 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002447 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002448 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002449 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002450 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002451 else:
2452 raise TypeError("Last argument must be string or callable")
2453
2454
2455 @property
2456 def callback_args(self):
2457 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002458 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002459 elif isinstance(self._passphrase, bytes):
2460 return self._passphrase
2461 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002462 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002463 else:
2464 raise TypeError("Last argument must be string or callable")
2465
2466
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002467 def raise_if_problem(self, exceptionType=Error):
2468 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002469 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002470 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002471 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002472 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002473 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002474 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002475
2476
2477 def _read_passphrase(self, buf, size, rwflag, userdata):
2478 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002479 if self._more_args:
2480 result = self._passphrase(size, rwflag, userdata)
2481 else:
2482 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002483 if not isinstance(result, bytes):
2484 raise ValueError("String expected")
2485 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002486 if self._truncate:
2487 result = result[:size]
2488 else:
2489 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002490 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002491 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002492 return len(result)
2493 except Exception as e:
2494 self._problems.append(e)
2495 return 0
2496
2497
2498
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002499def load_privatekey(type, buffer, passphrase=None):
2500 """
2501 Load a private key from a buffer
2502
2503 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2504 :param buffer: The buffer the key is stored in
2505 :param passphrase: (optional) if encrypted PEM format, this can be
2506 either the passphrase to use, or a callback for
2507 providing the passphrase.
2508
2509 :return: The PKey object
2510 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002511 if isinstance(buffer, _text_type):
2512 buffer = buffer.encode("ascii")
2513
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002514 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002515
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002516 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002517 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002518 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2519 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002520 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002521 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002522 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002523 else:
2524 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2525
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002526 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002527 _raise_current_error()
2528
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002529 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002530 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002531 return pkey
2532
2533
2534
2535def dump_certificate_request(type, req):
2536 """
2537 Dump a certificate request to a buffer
2538
2539 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2540 :param req: The certificate request to dump
2541 :return: The buffer with the dumped certificate request in
2542 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002543 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002544
2545 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002546 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002547 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002548 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002549 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002550 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002551 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002552 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002553
2554 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002555 # TODO: This is untested.
2556 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002557
2558 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002559
2560
2561
2562def load_certificate_request(type, buffer):
2563 """
2564 Load a certificate request from a buffer
2565
2566 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2567 :param buffer: The buffer the certificate request is stored in
2568 :return: The X509Req object
2569 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002570 if isinstance(buffer, _text_type):
2571 buffer = buffer.encode("ascii")
2572
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002573 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002574
2575 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002576 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002577 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002578 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002579 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002580 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002581
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002582 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002583 # TODO: This is untested.
2584 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002585
2586 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002587 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002588 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002589
2590
2591
2592def sign(pkey, data, digest):
2593 """
2594 Sign data with a digest
2595
2596 :param pkey: Pkey to sign with
2597 :param data: data to be signed
2598 :param digest: message digest to use
2599 :return: signature
2600 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002601 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002602
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002603 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002604 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002605 raise ValueError("No such digest method")
2606
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002607 md_ctx = _ffi.new("EVP_MD_CTX*")
2608 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002609
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002610 _lib.EVP_SignInit(md_ctx, digest_obj)
2611 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002612
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002613 signature_buffer = _ffi.new("unsigned char[]", 512)
2614 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002615 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002616 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002617 md_ctx, signature_buffer, signature_length, pkey._pkey)
2618
2619 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002620 # TODO: This is untested.
2621 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002622
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002623 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002624
2625
2626
2627def verify(cert, signature, data, digest):
2628 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002629 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002630
2631 :param cert: signing certificate (X509 object)
2632 :param signature: signature returned by sign function
2633 :param data: data to be verified
2634 :param digest: message digest to use
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002635 :return: :py:const:`None` if the signature is correct, raise exception otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002636 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002637 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002638
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002639 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002640 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002641 raise ValueError("No such digest method")
2642
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002643 pkey = _lib.X509_get_pubkey(cert._x509)
2644 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002645 # TODO: This is untested.
2646 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002647 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002648
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002649 md_ctx = _ffi.new("EVP_MD_CTX*")
2650 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002651
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002652 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2653 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2654 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002655
2656 if verify_result != 1:
2657 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002658
2659
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002660def load_crl(type, buffer):
2661 """
2662 Load a certificate revocation list from a buffer
2663
2664 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2665 :param buffer: The buffer the CRL is stored in
2666
2667 :return: The PKey object
2668 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002669 if isinstance(buffer, _text_type):
2670 buffer = buffer.encode("ascii")
2671
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002672 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002673
2674 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002675 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002676 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002677 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002678 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002679 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2680
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002681 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002682 _raise_current_error()
2683
2684 result = CRL.__new__(CRL)
2685 result._crl = crl
2686 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002687
2688
2689
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002690def load_pkcs7_data(type, buffer):
2691 """
2692 Load pkcs7 data from a buffer
2693
2694 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2695 :param buffer: The buffer with the pkcs7 data.
2696 :return: The PKCS7 object
2697 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002698 if isinstance(buffer, _text_type):
2699 buffer = buffer.encode("ascii")
2700
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002701 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002702
2703 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002704 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002705 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002706 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002707 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002708 # TODO: This is untested.
2709 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002710 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2711
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002712 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002713 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002714
2715 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002716 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002717 return pypkcs7
2718
2719
2720
Stephen Holsapple38482622014-04-05 20:29:34 -07002721def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002722 """
2723 Load a PKCS12 object from a buffer
2724
2725 :param buffer: The buffer the certificate is stored in
2726 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2727 :returns: The PKCS12 object
2728 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002729 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002730
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002731 if isinstance(buffer, _text_type):
2732 buffer = buffer.encode("ascii")
2733
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002734 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002735
Stephen Holsapple38482622014-04-05 20:29:34 -07002736 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2737 # password based encryption no password and a zero length password are two
2738 # different things, but OpenSSL implementation will try both to figure out
2739 # which one works.
2740 if not passphrase:
2741 passphrase = _ffi.NULL
2742
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002743 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2744 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002745 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002746 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002747
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002748 pkey = _ffi.new("EVP_PKEY**")
2749 cert = _ffi.new("X509**")
2750 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002751
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002752 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002753 if not parse_result:
2754 _raise_current_error()
2755
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002756 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002757
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002758 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2759 # queue for no particular reason. This error isn't interesting to anyone
2760 # outside this function. It's not even interesting to us. Get rid of it.
2761 try:
2762 _raise_current_error()
2763 except Error:
2764 pass
2765
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002766 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002767 pykey = None
2768 else:
2769 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002770 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002771
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002772 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002773 pycert = None
2774 friendlyname = None
2775 else:
2776 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002777 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002778
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002779 friendlyname_length = _ffi.new("int*")
2780 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2781 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2782 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002783 friendlyname = None
2784
2785 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002786 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002787 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002788 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002789 pycacerts.append(pycacert)
2790 if not pycacerts:
2791 pycacerts = None
2792
2793 pkcs12 = PKCS12.__new__(PKCS12)
2794 pkcs12._pkey = pykey
2795 pkcs12._cert = pycert
2796 pkcs12._cacerts = pycacerts
2797 pkcs12._friendlyname = friendlyname
2798 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002799
2800
2801def _initialize_openssl_threads(get_ident, Lock):
2802 import _ssl
2803 return
2804
2805 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2806
2807 def locking_function(mode, index, filename, line):
2808 if mode & _lib.CRYPTO_LOCK:
2809 locks[index].acquire()
2810 else:
2811 locks[index].release()
2812
2813 _lib.CRYPTO_set_id_callback(
2814 _ffi.callback("unsigned long (*)(void)", get_ident))
2815
2816 _lib.CRYPTO_set_locking_callback(
2817 _ffi.callback(
2818 "void (*)(int, int, const char*, int)", locking_function))
2819
2820
2821try:
2822 from thread import get_ident
2823 from threading import Lock
2824except ImportError:
2825 pass
2826else:
2827 _initialize_openssl_threads(get_ident, Lock)
2828 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002829
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002830# There are no direct unit tests for this initialization. It is tested
2831# indirectly since it is necessary for functions like dump_privatekey when
2832# using encryption.
2833#
2834# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2835# and some other similar tests may fail without this (though they may not if
2836# the Python runtime has already done some initialization of the underlying
2837# OpenSSL library (and is linked against the same one that cryptography is
2838# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002839_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002840
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002841# This is similar but exercised mainly by exception_from_error_queue. It calls
2842# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2843_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002844
2845
2846
2847# Set the default string mask to match OpenSSL upstream (since 2005) and
2848# RFC5280 recommendations.
2849_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')