blob: a52862c5c8c1ea73e53a53fe83e02132daa74cb7 [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 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400570 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500571 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
Paul Kehrerb7d79502015-05-04 07:43:51 -0500736 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400737 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500738 for i in range(_lib.sk_GENERAL_NAME_num(names)):
739 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400740 try:
741 label = self._prefixes[name.type]
742 except KeyError:
743 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500744 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500745 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400746 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500747 value = _native(
748 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
749 parts.append(label + ":" + value)
750 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400751
752
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800753 def __str__(self):
754 """
755 :return: a nice text representation of the extension
756 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500757 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400758 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800759
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400760 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500761 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800762 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500763 # TODO: This is untested.
764 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800765
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500766 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800767
768
769 def get_critical(self):
770 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200771 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800772
773 :return: The critical field.
774 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500775 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800776
777
778 def get_short_name(self):
779 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200780 Returns the short type name of this X.509 extension.
781
782 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800783
784 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200785 :rtype: :py:data:`bytes`
786
787 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800788 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500789 obj = _lib.X509_EXTENSION_get_object(self._extension)
790 nid = _lib.OBJ_obj2nid(obj)
791 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800792
793
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800794 def get_data(self):
795 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200796 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800797
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200798 :return: The ASN.1 encoded data of this X509 extension.
799 :rtype: :py:data:`bytes`
800
801 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800802 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500803 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
804 string_result = _ffi.cast('ASN1_STRING*', octet_result)
805 char_result = _lib.ASN1_STRING_data(string_result)
806 result_length = _lib.ASN1_STRING_length(string_result)
807 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800808
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200809
810
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800811X509ExtensionType = X509Extension
812
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800813
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200814
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800815class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200816 """
817 An X.509 certificate signing requests.
818 """
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800819 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500820 req = _lib.X509_REQ_new()
821 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800822
823
824 def set_pubkey(self, pkey):
825 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200826 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800827
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200828 :param pkey: The public key to use.
829 :type pkey: :py:class:`PKey`
830
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200831 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800832 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500833 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800834 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500835 # TODO: This is untested.
836 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800837
838
839 def get_pubkey(self):
840 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200841 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800842
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200843 :return: The public key.
844 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800845 """
846 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500847 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
848 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500849 # TODO: This is untested.
850 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500851 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800852 pkey._only_public = True
853 return pkey
854
855
856 def set_version(self, version):
857 """
858 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
859 request.
860
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200861 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200862 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800863 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500864 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800865 if not set_result:
866 _raise_current_error()
867
868
869 def get_version(self):
870 """
871 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
872 request.
873
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200874 :return: The value of the version subfield.
875 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800876 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500877 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800878
879
880 def get_subject(self):
881 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200882 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800883
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200884 This creates a new :py:class:`X509Name`: modifying it does not affect
885 this request.
886
887 :return: The subject of this certificate signing request.
888 :rtype: :py:class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889 """
890 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500891 name._name = _lib.X509_REQ_get_subject_name(self._req)
892 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500893 # TODO: This is untested.
894 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800895
896 # The name is owned by the X509Req structure. As long as the X509Name
897 # Python object is alive, keep the X509Req Python object alive.
898 name._owner = self
899
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800900 return name
901
902
903 def add_extensions(self, extensions):
904 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200905 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800906
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200907 :param extensions: The X.509 extensions to add.
908 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200909 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800910 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500911 stack = _lib.sk_X509_EXTENSION_new_null()
912 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500913 # TODO: This is untested.
914 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800915
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500916 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800917
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800918 for ext in extensions:
919 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800920 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800921
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800922 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500923 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800924
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500925 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800926 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500927 # TODO: This is untested.
928 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800929
930
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800931 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800932 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200933 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800934
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200935 :return: The X.509 extensions in this request.
936 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
937
938 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800939 """
940 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500941 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500942 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800943 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500944 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800945 exts.append(ext)
946 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800947
948
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800949 def sign(self, pkey, digest):
950 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700951 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800952
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200953 :param pkey: The key pair to sign with.
954 :type pkey: :py:class:`PKey`
955 :param digest: The name of the message digest to use for the signature,
956 e.g. :py:data:`b"sha1"`.
957 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200958 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800959 """
960 if pkey._only_public:
961 raise ValueError("Key has only public part")
962
963 if not pkey._initialized:
964 raise ValueError("Key is uninitialized")
965
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500966 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500967 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800968 raise ValueError("No such digest method")
969
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500970 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800971 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500972 # TODO: This is untested.
973 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800974
975
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800976 def verify(self, pkey):
977 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200978 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800979
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200980 :param key: A public key.
981 :type key: :py:class:`PKey`
982 :return: :py:data:`True` if the signature is correct.
983 :rtype: :py:class:`bool`
984 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800985 problem verifying the signature.
986 """
987 if not isinstance(pkey, PKey):
988 raise TypeError("pkey must be a PKey instance")
989
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500990 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800991 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500992 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800993
994 return result
995
996
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200997
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800998X509ReqType = X509Req
999
1000
1001
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001002class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001003 """
1004 An X.509 certificate.
1005 """
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001006 def __init__(self):
1007 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001008 x509 = _lib.X509_new()
1009 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001010
1011
1012 def set_version(self, version):
1013 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001014 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001015
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001016 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001017 :type version: :py:class:`int`
1018
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001019 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001020 """
1021 if not isinstance(version, int):
1022 raise TypeError("version must be an integer")
1023
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001024 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001025
1026
1027 def get_version(self):
1028 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001029 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001030
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001031 :return: The version number of the certificate.
1032 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001033 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001034 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001035
1036
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001037 def get_pubkey(self):
1038 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001039 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001040
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001041 :return: The public key.
1042 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001043 """
1044 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001045 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1046 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001047 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001048 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001049 pkey._only_public = True
1050 return pkey
1051
1052
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001053 def set_pubkey(self, pkey):
1054 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001055 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001056
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001057 :param pkey: The public key.
1058 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001059
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001060 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001061 """
1062 if not isinstance(pkey, PKey):
1063 raise TypeError("pkey must be a PKey instance")
1064
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001065 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001066 if not set_result:
1067 _raise_current_error()
1068
1069
1070 def sign(self, pkey, digest):
1071 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001072 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001073
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001074 :param pkey: The key to sign with.
1075 :type pkey: :py:class:`PKey`
1076
1077 :param digest: The name of the message digest to use.
1078 :type digest: :py:class:`bytes`
1079
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001080 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001081 """
1082 if not isinstance(pkey, PKey):
1083 raise TypeError("pkey must be a PKey instance")
1084
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001085 if pkey._only_public:
1086 raise ValueError("Key only has public part")
1087
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001088 if not pkey._initialized:
1089 raise ValueError("Key is uninitialized")
1090
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001091 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001092 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001093 raise ValueError("No such digest method")
1094
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001095 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001096 if not sign_result:
1097 _raise_current_error()
1098
1099
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001100 def get_signature_algorithm(self):
1101 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001102 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001103
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001104 :return: The name of the algorithm.
1105 :rtype: :py:class:`bytes`
1106
1107 :raises ValueError: If the signature algorithm is undefined.
1108
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001109 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001110 """
1111 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001112 nid = _lib.OBJ_obj2nid(alg)
1113 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001114 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001115 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001116
1117
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001118 def digest(self, digest_name):
1119 """
1120 Return the digest of the X509 object.
1121
1122 :param digest_name: The name of the digest algorithm to use.
1123 :type digest_name: :py:class:`bytes`
1124
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001125 :return: The digest of the object, formatted as
1126 :py:const:`b":"`-delimited hex pairs.
1127 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001128 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001129 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001130 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001131 raise ValueError("No such digest method")
1132
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001133 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1134 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001135 result_length[0] = len(result_buffer)
1136
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001137 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001138 self._x509, digest, result_buffer, result_length)
1139
1140 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001141 # TODO: This is untested.
1142 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001143
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001144 return b":".join([
1145 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001146 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001147
1148
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001149 def subject_name_hash(self):
1150 """
1151 Return the hash of the X509 subject.
1152
1153 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001154 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001155 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001156 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001157
1158
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001159 def set_serial_number(self, serial):
1160 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001161 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001162
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001163 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001164 :type serial: :py:class:`int`
1165
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001166 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001167 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001168 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001169 raise TypeError("serial must be an integer")
1170
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001171 hex_serial = hex(serial)[2:]
1172 if not isinstance(hex_serial, bytes):
1173 hex_serial = hex_serial.encode('ascii')
1174
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001175 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001176
1177 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1178 # it. If bignum is still NULL after this call, then the return value is
1179 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001180 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001181
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001182 if bignum_serial[0] == _ffi.NULL:
1183 set_result = _lib.ASN1_INTEGER_set(
1184 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001185 if set_result:
1186 # TODO Not tested
1187 _raise_current_error()
1188 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001189 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1190 _lib.BN_free(bignum_serial[0])
1191 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001192 # TODO Not tested
1193 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001194 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1195 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001196 if not set_result:
1197 # TODO Not tested
1198 _raise_current_error()
1199
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001200
1201 def get_serial_number(self):
1202 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001203 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001204
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001205 :return: The serial number.
1206 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001207 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001208 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1209 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001210 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001211 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001212 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001213 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001214 serial = int(hexstring_serial, 16)
1215 return serial
1216 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001217 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001218 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001219 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001220
1221
1222 def gmtime_adj_notAfter(self, amount):
1223 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001224 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001225
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001226 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001227 :type amount: :py:class:`int`
1228
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001229 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001230 """
1231 if not isinstance(amount, int):
1232 raise TypeError("amount must be an integer")
1233
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001234 notAfter = _lib.X509_get_notAfter(self._x509)
1235 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001236
1237
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001238 def gmtime_adj_notBefore(self, amount):
1239 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001240 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001241
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001242 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001243 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001244 """
1245 if not isinstance(amount, int):
1246 raise TypeError("amount must be an integer")
1247
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001248 notBefore = _lib.X509_get_notBefore(self._x509)
1249 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001250
1251
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001252 def has_expired(self):
1253 """
1254 Check whether the certificate has expired.
1255
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001256 :return: :py:const:`True` if the certificate has expired,
1257 :py:const:`False` otherwise.
1258 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001259 """
1260 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001261 notAfter = _lib.X509_get_notAfter(self._x509)
1262 return _lib.ASN1_UTCTIME_cmp_time_t(
1263 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001264
1265
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001266 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001267 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001268
1269
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001270 def get_notBefore(self):
1271 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001272 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001273
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001274 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001275
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001276 YYYYMMDDhhmmssZ
1277 YYYYMMDDhhmmss+hhmm
1278 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001279
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001280 :return: A timestamp string, or :py:const:`None` if there is none.
1281 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001282 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001283 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001284
1285
1286 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001287 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001288
1289
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001290 def set_notBefore(self, when):
1291 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001292 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001293
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001294 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001295
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001296 YYYYMMDDhhmmssZ
1297 YYYYMMDDhhmmss+hhmm
1298 YYYYMMDDhhmmss-hhmm
1299
1300 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001301 :type when: :py:class:`bytes`
1302
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001303 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001304 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001305 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001306
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001307
1308 def get_notAfter(self):
1309 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001310 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001311
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001312 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001313
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001314 YYYYMMDDhhmmssZ
1315 YYYYMMDDhhmmss+hhmm
1316 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001317
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001318 :return: A timestamp string, or :py:const:`None` if there is none.
1319 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001320 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001321 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001322
1323
1324 def set_notAfter(self, when):
1325 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001326 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001327
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001328 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001329
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001330 YYYYMMDDhhmmssZ
1331 YYYYMMDDhhmmss+hhmm
1332 YYYYMMDDhhmmss-hhmm
1333
1334 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001335 :type when: :py:class:`bytes`
1336
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001337 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001338 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001339 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001340
1341
1342 def _get_name(self, which):
1343 name = X509Name.__new__(X509Name)
1344 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001345 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001346 # TODO: This is untested.
1347 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001348
1349 # The name is owned by the X509 structure. As long as the X509Name
1350 # Python object is alive, keep the X509 Python object alive.
1351 name._owner = self
1352
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001353 return name
1354
1355
1356 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001357 if not isinstance(name, X509Name):
1358 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001359 set_result = which(self._x509, name._name)
1360 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001361 # TODO: This is untested.
1362 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001363
1364
1365 def get_issuer(self):
1366 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001367 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001368
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001369 This creates a new :py:class:`X509Name`: modifying it does not affect
1370 this certificate.
1371
1372 :return: The issuer of this certificate.
1373 :rtype: :py:class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001374 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001375 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001376
1377
1378 def set_issuer(self, issuer):
1379 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001380 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001381
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001382 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001383 :type issuer: :py:class:`X509Name`
1384
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001385 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001386 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001387 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001388
1389
1390 def get_subject(self):
1391 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001392 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001393
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001394 This creates a new :py:class:`X509Name`: modifying it does not affect
1395 this certificate.
1396
1397 :return: The subject of this certificate.
1398 :rtype: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001399 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001400 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001401
1402
1403 def set_subject(self, subject):
1404 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001405 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001406
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001407 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001408 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001409
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001410 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001411 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001412 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001413
1414
1415 def get_extension_count(self):
1416 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001417 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001418
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001419 :return: The number of extensions.
1420 :rtype: :py:class:`int`
1421
1422 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001423 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001424 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001425
1426
1427 def add_extensions(self, extensions):
1428 """
1429 Add extensions to the certificate.
1430
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001431 :param extensions: The extensions to add.
1432 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001433 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001434 """
1435 for ext in extensions:
1436 if not isinstance(ext, X509Extension):
1437 raise ValueError("One of the elements is not an X509Extension")
1438
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001439 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001440 if not add_result:
1441 _raise_current_error()
1442
1443
1444 def get_extension(self, index):
1445 """
1446 Get a specific extension of the certificate by index.
1447
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001448 Extensions on a certificate are kept in order. The index
1449 parameter selects which extension will be returned.
1450
1451 :param int index: The index of the extension to retrieve.
1452 :return: The extension at the specified index.
1453 :rtype: :py:class:`X509Extension`
1454 :raises IndexError: If the extension index was out of bounds.
1455
1456 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001457 """
1458 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001459 ext._extension = _lib.X509_get_ext(self._x509, index)
1460 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001461 raise IndexError("extension index out of bounds")
1462
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001463 extension = _lib.X509_EXTENSION_dup(ext._extension)
1464 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001465 return ext
1466
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001467
1468
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001469X509Type = X509
1470
1471
1472
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001473class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001474 """
1475 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001476 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001477 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001478 store = _lib.X509_STORE_new()
1479 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001480
1481
1482 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001483 """
1484 Adds the certificate :py:data:`cert` to this store.
1485
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001486 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001487
1488 :param X509 cert: The certificate to add to this store.
1489 :raises TypeError: If the certificate is not an :py:class:`X509`.
1490 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001491 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001492 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001493 if not isinstance(cert, X509):
1494 raise TypeError()
1495
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001496 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001497 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001498 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001499
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001500
1501X509StoreType = X509Store
1502
1503
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001504class X509StoreContextError(Exception):
1505 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001506 An exception raised when an error occurred while verifying a certificate
1507 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001508
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001509 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001510 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001511 """
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
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001526 .. note::
1527
1528 Currently, one can only set the trusted certificates on an
1529 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1530 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001531
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001532 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1533 instance. It is dynamically allocated and automatically garbage
1534 collected.
1535
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001536 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001537
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001538 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001539
1540 :param X509Store store: The certificates which will be trusted for the
1541 purposes of any verifications.
1542
1543 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001544 """
1545
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001546 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001547 store_ctx = _lib.X509_STORE_CTX_new()
1548 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1549 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001550 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001551 # Make the store context available for use after instantiating this
1552 # class by initializing it now. Per testing, subsequent calls to
1553 # :py:meth:`_init` have no adverse affect.
1554 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001555
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001556
1557 def _init(self):
1558 """
1559 Set up the store context for a subsequent verification operation.
1560 """
1561 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1562 if ret <= 0:
1563 _raise_current_error()
1564
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001565
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001566 def _cleanup(self):
1567 """
1568 Internally cleans up the store context.
1569
1570 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001571 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001572 """
1573 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1574
1575
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001576 def _exception_from_context(self):
1577 """
1578 Convert an OpenSSL native context error failure into a Python
1579 exception.
1580
1581 When a call to native OpenSSL X509_verify_cert fails, additonal information
1582 about the failure can be obtained from the store context.
1583 """
1584 errors = [
1585 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1586 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1587 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1588 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1589 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001590 # A context error should always be associated with a certificate, so we
1591 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001592 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001593 _cert = _lib.X509_dup(_x509)
1594 pycert = X509.__new__(X509)
1595 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001596 return X509StoreContextError(errors, pycert)
1597
1598
Stephen Holsapple46a09252015-02-12 14:45:43 -08001599 def set_store(self, store):
1600 """
1601 Set the context's trust store.
1602
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001603 .. versionadded:: 0.15
1604
Stephen Holsapple46a09252015-02-12 14:45:43 -08001605 :param X509Store store: The certificates which will be trusted for the
1606 purposes of any *future* verifications.
1607 """
1608 self._store = store
1609
1610
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001611 def verify_certificate(self):
1612 """
1613 Verify a certificate in a context.
1614
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001615 .. versionadded:: 0.15
1616
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001617 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001618
1619 :raises X509StoreContextError: If an error occured when validating a
1620 certificate in the context. Sets ``certificate`` attribute to indicate
1621 which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001622 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001623 # Always re-initialize the store context in case
1624 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001625 self._init()
1626 ret = _lib.X509_verify_cert(self._store_ctx)
1627 self._cleanup()
1628 if ret <= 0:
1629 raise self._exception_from_context()
1630
1631
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001632
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001633def load_certificate(type, buffer):
1634 """
1635 Load a certificate from a buffer
1636
1637 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001638
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001639 :param buffer: The buffer the certificate is stored in
1640 :type buffer: :py:class:`bytes`
1641
1642 :return: The X509 object
1643 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001644 if isinstance(buffer, _text_type):
1645 buffer = buffer.encode("ascii")
1646
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001647 bio = _new_mem_buf(buffer)
1648
1649 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001650 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001651 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001652 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001653 else:
1654 raise ValueError(
1655 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1656
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001657 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001658 _raise_current_error()
1659
1660 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001661 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001662 return cert
1663
1664
1665def dump_certificate(type, cert):
1666 """
1667 Dump a certificate to a buffer
1668
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001669 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1670 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001671 :param cert: The certificate to dump
1672 :return: The buffer with the dumped certificate in
1673 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001674 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001675
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001676 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001677 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001678 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001679 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001680 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001681 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001682 else:
1683 raise ValueError(
1684 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1685 "FILETYPE_TEXT")
1686
1687 return _bio_to_string(bio)
1688
1689
1690
1691def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1692 """
1693 Dump a private key to a buffer
1694
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001695 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1696 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001697 :param pkey: The PKey to dump
1698 :param cipher: (optional) if encrypted PEM format, the cipher to
1699 use
1700 :param passphrase: (optional) if encrypted PEM format, this can be either
1701 the passphrase to use, or a callback for providing the
1702 passphrase.
1703 :return: The buffer with the dumped key in
1704 :rtype: :py:data:`str`
1705 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001706 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001707
1708 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001709 if passphrase is None:
1710 raise TypeError(
1711 "if a value is given for cipher "
1712 "one must also be given for passphrase")
1713 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001714 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001715 raise ValueError("Invalid cipher name")
1716 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001717 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001718
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001719 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001720 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001721 result_code = _lib.PEM_write_bio_PrivateKey(
1722 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001723 helper.callback, helper.callback_args)
1724 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001725 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001726 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001727 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001728 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1729 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001730 # TODO RSA_free(rsa)?
1731 else:
1732 raise ValueError(
1733 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1734 "FILETYPE_TEXT")
1735
1736 if result_code == 0:
1737 _raise_current_error()
1738
1739 return _bio_to_string(bio)
1740
1741
1742
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001743def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001744 copy = _lib.X509_REVOKED_new()
1745 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001746 # TODO: This is untested.
1747 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001748
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001749 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001750 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001751 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001752
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001753 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001754 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001755 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001756
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001757 if original.extensions != _ffi.NULL:
1758 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1759 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1760 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1761 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1762 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001763 copy.extensions = extension_stack
1764
1765 copy.sequence = original.sequence
1766 return copy
1767
1768
1769
1770class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001771 """
1772 A certificate revocation.
1773 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001774 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1775 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1776 # OCSP_crl_reason_str. We use the latter, just like the command line
1777 # program.
1778 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001779 b"unspecified",
1780 b"keyCompromise",
1781 b"CACompromise",
1782 b"affiliationChanged",
1783 b"superseded",
1784 b"cessationOfOperation",
1785 b"certificateHold",
1786 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001787 ]
1788
1789 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001790 revoked = _lib.X509_REVOKED_new()
1791 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001792
1793
1794 def set_serial(self, hex_str):
1795 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001796 Set the serial number.
1797
1798 The serial number is formatted as a hexadecimal number encoded in
1799 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001800
1801 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001802 :type hex_str: :py:class:`bytes`
1803
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001804 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001805 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001806 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1807 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001808 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001809 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001810 if not bn_result:
1811 raise ValueError("bad hex string")
1812
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001813 asn1_serial = _ffi.gc(
1814 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1815 _lib.ASN1_INTEGER_free)
1816 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001817
1818
1819 def get_serial(self):
1820 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001821 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001822
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001823 The serial number is formatted as a hexadecimal number encoded in
1824 ASCII.
1825
1826 :return: The serial number.
1827 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001828 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001829 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001830
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001831 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001832 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001833 # TODO: This is untested.
1834 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001835
1836 return _bio_to_string(bio)
1837
1838
1839 def _delete_reason(self):
1840 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001841 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1842 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1843 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1844 _lib.X509_EXTENSION_free(ext)
1845 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001846 break
1847
1848
1849 def set_reason(self, reason):
1850 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001851 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001852
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001853 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001854
1855 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001856 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1857
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001858 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001859
1860 .. seealso::
1861
1862 :py:meth:`all_reasons`, which gives you a list of all supported
1863 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001864 """
1865 if reason is None:
1866 self._delete_reason()
1867 elif not isinstance(reason, bytes):
1868 raise TypeError("reason must be None or a byte string")
1869 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001870 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001871 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1872
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001873 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1874 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001875 # TODO: This is untested.
1876 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001877 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001878
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001879 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1880 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001881 # TODO: This is untested.
1882 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001883
1884 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001885 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1886 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001887
1888 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001889 # TODO: This is untested.
1890 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001891
1892
1893 def get_reason(self):
1894 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001895 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001896
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001897 :return: The reason, or :py:const:`None` if there is none.
1898 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1899
1900 .. seealso::
1901
1902 :py:meth:`all_reasons`, which gives you a list of all supported
1903 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001904 """
1905 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001906 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1907 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1908 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001909 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001910
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001911 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001912 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001913 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001914 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001915 # TODO: This is untested.
1916 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001917
1918 return _bio_to_string(bio)
1919
1920
1921 def all_reasons(self):
1922 """
1923 Return a list of all the supported reason strings.
1924
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001925 This list is a copy; modifying it does not change the supported reason
1926 strings.
1927
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001928 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001929 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001930 """
1931 return self._crl_reasons[:]
1932
1933
1934 def set_rev_date(self, when):
1935 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001936 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001937
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001938 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1939 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001940 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001941 """
1942 return _set_asn1_time(self._revoked.revocationDate, when)
1943
1944
1945 def get_rev_date(self):
1946 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001947 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001948
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001949 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1950 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001951 """
1952 return _get_asn1_time(self._revoked.revocationDate)
1953
1954
1955
1956class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001957 """
1958 A certificate revocation list.
1959 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001960 def __init__(self):
1961 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001962 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001963 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001964 crl = _lib.X509_CRL_new()
1965 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001966
1967
1968 def get_revoked(self):
1969 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001970 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001971
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001972 These revocations will be provided by value, not by reference.
1973 That means it's okay to mutate them: it won't affect this CRL.
1974
1975 :return: The revocations in this CRL.
1976 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001977 """
1978 results = []
1979 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001980 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1981 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001982 revoked_copy = _X509_REVOKED_dup(revoked)
1983 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001984 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001985 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001986 if results:
1987 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001988
1989
1990 def add_revoked(self, revoked):
1991 """
1992 Add a revoked (by value not reference) to the CRL structure
1993
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001994 This revocation will be added by value, not by reference. That
1995 means it's okay to mutate it after adding: it won't affect
1996 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001997
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001998 :param revoked: The new revocation.
1999 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002000
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002001 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002002 """
2003 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002004 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002005 # TODO: This is untested.
2006 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002007
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002008 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002009 if add_result == 0:
2010 # TODO: This is untested.
2011 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002012
2013
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002014 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002015 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002016 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002017 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002018
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002019 :param cert: The certificate used to sign the CRL.
2020 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002021
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002022 :param key: The key used to sign the CRL.
2023 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002024
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002025 :param type: The export format, either :py:data:`FILETYPE_PEM`,
2026 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002027
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002028 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04002029
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002030 :param bytes digest: The name of the message digest to use (eg
2031 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002032
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002033 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002034 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002035 if not isinstance(cert, X509):
2036 raise TypeError("cert must be an X509 instance")
2037 if not isinstance(key, PKey):
2038 raise TypeError("key must be a PKey instance")
2039 if not isinstance(type, int):
2040 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002041
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002042 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002043 _warn(
2044 "The default message digest (md5) is deprecated. "
2045 "Pass the name of a message digest explicitly.",
2046 category=DeprecationWarning,
2047 stacklevel=2,
2048 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002049 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002050
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002051 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002052 if digest_obj == _ffi.NULL:
2053 raise ValueError("No such digest method")
2054
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002055 bio = _lib.BIO_new(_lib.BIO_s_mem())
2056 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002057 # TODO: This is untested.
2058 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002059
2060 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002061 sometime = _lib.ASN1_TIME_new()
2062 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002063 # TODO: This is untested.
2064 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002065
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002066 _lib.X509_gmtime_adj(sometime, 0)
2067 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002068
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002069 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2070 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002071
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002072 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002073
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002074 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002075 if not sign_result:
2076 _raise_current_error()
2077
2078 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002079 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002080 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002081 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002082 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002083 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002084 else:
2085 raise ValueError(
2086 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
2087
2088 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002089 # TODO: This is untested.
2090 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002091
2092 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002093CRLType = CRL
2094
2095
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002096
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002097class PKCS7(object):
2098 def type_is_signed(self):
2099 """
2100 Check if this NID_pkcs7_signed object
2101
2102 :return: True if the PKCS7 is of type signed
2103 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002104 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002105 return True
2106 return False
2107
2108
2109 def type_is_enveloped(self):
2110 """
2111 Check if this NID_pkcs7_enveloped object
2112
2113 :returns: True if the PKCS7 is of type enveloped
2114 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002115 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002116 return True
2117 return False
2118
2119
2120 def type_is_signedAndEnveloped(self):
2121 """
2122 Check if this NID_pkcs7_signedAndEnveloped object
2123
2124 :returns: True if the PKCS7 is of type signedAndEnveloped
2125 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002126 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002127 return True
2128 return False
2129
2130
2131 def type_is_data(self):
2132 """
2133 Check if this NID_pkcs7_data object
2134
2135 :return: True if the PKCS7 is of type data
2136 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002137 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002138 return True
2139 return False
2140
2141
2142 def get_type_name(self):
2143 """
2144 Returns the type name of the PKCS7 structure
2145
2146 :return: A string with the typename
2147 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002148 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2149 string_type = _lib.OBJ_nid2sn(nid)
2150 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002151
2152PKCS7Type = PKCS7
2153
2154
2155
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002156class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002157 """
2158 A PKCS #12 archive.
2159 """
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002160 def __init__(self):
2161 self._pkey = None
2162 self._cert = None
2163 self._cacerts = None
2164 self._friendlyname = None
2165
2166
2167 def get_certificate(self):
2168 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002169 Get 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 :return: The certificate, or :py:const:`None` if there is none.
2172 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002173 """
2174 return self._cert
2175
2176
2177 def set_certificate(self, cert):
2178 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002179 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002180
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002181 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002182 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002183
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002184 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002185 """
2186 if not isinstance(cert, X509):
2187 raise TypeError("cert must be an X509 instance")
2188 self._cert = cert
2189
2190
2191 def get_privatekey(self):
2192 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002193 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002194
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002195 :return: The private key, or :py:const:`None` if there is none.
2196 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002197 """
2198 return self._pkey
2199
2200
2201 def set_privatekey(self, pkey):
2202 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002203 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002204
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002205 :param pkey: The new private key, or :py:const:`None` to unset it.
2206 :type pkey: :py:class:`PKey` or :py:const:`None`
2207
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002208 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002209 """
2210 if not isinstance(pkey, PKey):
2211 raise TypeError("pkey must be a PKey instance")
2212 self._pkey = pkey
2213
2214
2215 def get_ca_certificates(self):
2216 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002217 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002218
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002219 :return: A tuple with the CA certificates in the chain, or
2220 :py:const:`None` if there are none.
2221 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002222 """
2223 if self._cacerts is not None:
2224 return tuple(self._cacerts)
2225
2226
2227 def set_ca_certificates(self, cacerts):
2228 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002229 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002230
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002231 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2232 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002233 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002234
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002235 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002236 """
2237 if cacerts is None:
2238 self._cacerts = None
2239 else:
2240 cacerts = list(cacerts)
2241 for cert in cacerts:
2242 if not isinstance(cert, X509):
2243 raise TypeError("iterable must only contain X509 instances")
2244 self._cacerts = cacerts
2245
2246
2247 def set_friendlyname(self, name):
2248 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002249 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002250
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002251 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002252 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002253
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002254 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002255 """
2256 if name is None:
2257 self._friendlyname = None
2258 elif not isinstance(name, bytes):
2259 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2260 self._friendlyname = name
2261
2262
2263 def get_friendlyname(self):
2264 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002265 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002266
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002267 :returns: The friendly name, or :py:const:`None` if there is none.
2268 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002269 """
2270 return self._friendlyname
2271
2272
2273 def export(self, passphrase=None, iter=2048, maciter=1):
2274 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002275 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002276
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002277 For more information, see the :c:func:`PKCS12_create` man page.
2278
2279 :param passphrase: The passphrase used to encrypt the structure. Unlike
2280 some other passphrase arguments, this *must* be a string, not a
2281 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002282 :type passphrase: :py:data:`bytes`
2283
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002284 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002285 :type iter: :py:data:`int`
2286
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002287 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002288 :type maciter: :py:data:`int`
2289
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002290 :return: The string representation of the PKCS #12 structure.
2291 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002292 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002293 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002294
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002295 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002296 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002297 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002298 cacerts = _lib.sk_X509_new_null()
2299 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002300 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002301 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002302
2303 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002304 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002305
2306 friendlyname = self._friendlyname
2307 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002308 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002309
2310 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002311 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002312 else:
2313 pkey = self._pkey._pkey
2314
2315 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002316 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002317 else:
2318 cert = self._cert._x509
2319
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002320 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002321 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002322 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2323 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002324 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002325 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002326 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002327 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002328
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002329 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002330 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002331 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002332
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002333
2334
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002335PKCS12Type = PKCS12
2336
2337
2338
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002339class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002340 """
2341 A Netscape SPKI object.
2342 """
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002343 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002344 spki = _lib.NETSCAPE_SPKI_new()
2345 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002346
2347
2348 def sign(self, pkey, digest):
2349 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002350 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002351
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002352 :param pkey: The private key to sign with.
2353 :type pkey: :py:class:`PKey`
2354
2355 :param digest: The message digest to use.
2356 :type digest: :py:class:`bytes`
2357
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002358 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002359 """
2360 if pkey._only_public:
2361 raise ValueError("Key has only public part")
2362
2363 if not pkey._initialized:
2364 raise ValueError("Key is uninitialized")
2365
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002366 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002367 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002368 raise ValueError("No such digest method")
2369
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002370 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002371 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002372 # TODO: This is untested.
2373 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002374
2375
2376 def verify(self, key):
2377 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002378 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002379
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002380 :param key: The public key that signature is supposedly from.
2381 :type pkey: :py:class:`PKey`
2382
2383 :return: :py:const:`True` if the signature is correct.
2384 :rtype: :py:class:`bool`
2385
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002386 :raises Error: If the signature is invalid, or there was a problem
2387 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002388 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002389 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002390 if answer <= 0:
2391 _raise_current_error()
2392 return True
2393
2394
2395 def b64_encode(self):
2396 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002397 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002398
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002399 :return: The base64 encoded string.
2400 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002401 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002402 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2403 result = _ffi.string(encoded)
2404 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002405 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002406
2407
2408 def get_pubkey(self):
2409 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002410 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002411
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002412 :return: The public key.
2413 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002414 """
2415 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002416 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2417 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002418 # TODO: This is untested.
2419 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002420 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002421 pkey._only_public = True
2422 return pkey
2423
2424
2425 def set_pubkey(self, pkey):
2426 """
2427 Set the public key of the certificate
2428
2429 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002430 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002431 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002432 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002433 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002434 # TODO: This is untested.
2435 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002436
2437
2438
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002439NetscapeSPKIType = NetscapeSPKI
2440
2441
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002442
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002443class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002444 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002445 if type != FILETYPE_PEM and passphrase is not None:
2446 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002447 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002448 self._more_args = more_args
2449 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002450 self._problems = []
2451
2452
2453 @property
2454 def callback(self):
2455 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002456 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002457 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002458 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002459 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002460 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002461 else:
2462 raise TypeError("Last argument must be string or callable")
2463
2464
2465 @property
2466 def callback_args(self):
2467 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002468 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002469 elif isinstance(self._passphrase, bytes):
2470 return self._passphrase
2471 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002472 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002473 else:
2474 raise TypeError("Last argument must be string or callable")
2475
2476
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002477 def raise_if_problem(self, exceptionType=Error):
2478 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002479 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002480 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002481 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002482 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002483 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002484 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002485
2486
2487 def _read_passphrase(self, buf, size, rwflag, userdata):
2488 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002489 if self._more_args:
2490 result = self._passphrase(size, rwflag, userdata)
2491 else:
2492 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002493 if not isinstance(result, bytes):
2494 raise ValueError("String expected")
2495 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002496 if self._truncate:
2497 result = result[:size]
2498 else:
2499 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002500 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002501 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002502 return len(result)
2503 except Exception as e:
2504 self._problems.append(e)
2505 return 0
2506
2507
2508
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002509def load_privatekey(type, buffer, passphrase=None):
2510 """
2511 Load a private key from a buffer
2512
2513 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2514 :param buffer: The buffer the key is stored in
2515 :param passphrase: (optional) if encrypted PEM format, this can be
2516 either the passphrase to use, or a callback for
2517 providing the passphrase.
2518
2519 :return: The PKey object
2520 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002521 if isinstance(buffer, _text_type):
2522 buffer = buffer.encode("ascii")
2523
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002524 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002525
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002526 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002527 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002528 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2529 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002530 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002531 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002532 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002533 else:
2534 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2535
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002536 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002537 _raise_current_error()
2538
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002539 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002540 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002541 return pkey
2542
2543
2544
2545def dump_certificate_request(type, req):
2546 """
2547 Dump a certificate request to a buffer
2548
2549 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2550 :param req: The certificate request to dump
2551 :return: The buffer with the dumped certificate request in
2552 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002553 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002554
2555 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002556 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002557 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002558 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002559 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002560 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002561 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002562 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002563
2564 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002565 # TODO: This is untested.
2566 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002567
2568 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002569
2570
2571
2572def load_certificate_request(type, buffer):
2573 """
2574 Load a certificate request from a buffer
2575
2576 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2577 :param buffer: The buffer the certificate request is stored in
2578 :return: The X509Req object
2579 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002580 if isinstance(buffer, _text_type):
2581 buffer = buffer.encode("ascii")
2582
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002583 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002584
2585 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002586 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002587 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002588 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002589 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002590 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002591
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002592 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002593 # TODO: This is untested.
2594 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002595
2596 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002597 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002598 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002599
2600
2601
2602def sign(pkey, data, digest):
2603 """
2604 Sign data with a digest
2605
2606 :param pkey: Pkey to sign with
2607 :param data: data to be signed
2608 :param digest: message digest to use
2609 :return: signature
2610 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002611 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002612
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002613 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002614 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002615 raise ValueError("No such digest method")
2616
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002617 md_ctx = _ffi.new("EVP_MD_CTX*")
2618 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002619
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002620 _lib.EVP_SignInit(md_ctx, digest_obj)
2621 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002622
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002623 signature_buffer = _ffi.new("unsigned char[]", 512)
2624 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002625 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002626 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002627 md_ctx, signature_buffer, signature_length, pkey._pkey)
2628
2629 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002630 # TODO: This is untested.
2631 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002632
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002633 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002634
2635
2636
2637def verify(cert, signature, data, digest):
2638 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002639 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002640
2641 :param cert: signing certificate (X509 object)
2642 :param signature: signature returned by sign function
2643 :param data: data to be verified
2644 :param digest: message digest to use
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002645 :return: :py:const:`None` if the signature is correct, raise exception otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002646 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002647 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002648
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002649 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002650 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002651 raise ValueError("No such digest method")
2652
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002653 pkey = _lib.X509_get_pubkey(cert._x509)
2654 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002655 # TODO: This is untested.
2656 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002657 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002658
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002659 md_ctx = _ffi.new("EVP_MD_CTX*")
2660 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002661
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002662 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2663 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2664 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002665
2666 if verify_result != 1:
2667 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002668
2669
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002670def load_crl(type, buffer):
2671 """
2672 Load a certificate revocation list from a buffer
2673
2674 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2675 :param buffer: The buffer the CRL is stored in
2676
2677 :return: The PKey object
2678 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002679 if isinstance(buffer, _text_type):
2680 buffer = buffer.encode("ascii")
2681
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002682 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002683
2684 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002685 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002686 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002687 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002688 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002689 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2690
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002691 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002692 _raise_current_error()
2693
2694 result = CRL.__new__(CRL)
2695 result._crl = crl
2696 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002697
2698
2699
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002700def load_pkcs7_data(type, buffer):
2701 """
2702 Load pkcs7 data from a buffer
2703
2704 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2705 :param buffer: The buffer with the pkcs7 data.
2706 :return: The PKCS7 object
2707 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002708 if isinstance(buffer, _text_type):
2709 buffer = buffer.encode("ascii")
2710
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002711 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002712
2713 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002714 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002715 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002716 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002717 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002718 # TODO: This is untested.
2719 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002720 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2721
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002722 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002723 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002724
2725 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002726 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002727 return pypkcs7
2728
2729
2730
Stephen Holsapple38482622014-04-05 20:29:34 -07002731def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002732 """
2733 Load a PKCS12 object from a buffer
2734
2735 :param buffer: The buffer the certificate is stored in
2736 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2737 :returns: The PKCS12 object
2738 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002739 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002740
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002741 if isinstance(buffer, _text_type):
2742 buffer = buffer.encode("ascii")
2743
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002744 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002745
Stephen Holsapple38482622014-04-05 20:29:34 -07002746 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2747 # password based encryption no password and a zero length password are two
2748 # different things, but OpenSSL implementation will try both to figure out
2749 # which one works.
2750 if not passphrase:
2751 passphrase = _ffi.NULL
2752
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002753 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2754 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002755 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002756 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002757
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002758 pkey = _ffi.new("EVP_PKEY**")
2759 cert = _ffi.new("X509**")
2760 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002761
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002762 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002763 if not parse_result:
2764 _raise_current_error()
2765
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002766 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002767
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002768 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2769 # queue for no particular reason. This error isn't interesting to anyone
2770 # outside this function. It's not even interesting to us. Get rid of it.
2771 try:
2772 _raise_current_error()
2773 except Error:
2774 pass
2775
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002776 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002777 pykey = None
2778 else:
2779 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002780 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002781
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002782 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002783 pycert = None
2784 friendlyname = None
2785 else:
2786 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002787 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002788
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002789 friendlyname_length = _ffi.new("int*")
2790 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2791 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2792 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002793 friendlyname = None
2794
2795 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002796 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002797 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002798 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002799 pycacerts.append(pycacert)
2800 if not pycacerts:
2801 pycacerts = None
2802
2803 pkcs12 = PKCS12.__new__(PKCS12)
2804 pkcs12._pkey = pykey
2805 pkcs12._cert = pycert
2806 pkcs12._cacerts = pycacerts
2807 pkcs12._friendlyname = friendlyname
2808 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002809
2810
2811def _initialize_openssl_threads(get_ident, Lock):
2812 import _ssl
2813 return
2814
2815 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2816
2817 def locking_function(mode, index, filename, line):
2818 if mode & _lib.CRYPTO_LOCK:
2819 locks[index].acquire()
2820 else:
2821 locks[index].release()
2822
2823 _lib.CRYPTO_set_id_callback(
2824 _ffi.callback("unsigned long (*)(void)", get_ident))
2825
2826 _lib.CRYPTO_set_locking_callback(
2827 _ffi.callback(
2828 "void (*)(int, int, const char*, int)", locking_function))
2829
2830
2831try:
2832 from thread import get_ident
2833 from threading import Lock
2834except ImportError:
2835 pass
2836else:
2837 _initialize_openssl_threads(get_ident, Lock)
2838 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002839
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002840# There are no direct unit tests for this initialization. It is tested
2841# indirectly since it is necessary for functions like dump_privatekey when
2842# using encryption.
2843#
2844# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2845# and some other similar tests may fail without this (though they may not if
2846# the Python runtime has already done some initialization of the underlying
2847# OpenSSL library (and is linked against the same one that cryptography is
2848# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002849_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002850
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002851# This is similar but exercised mainly by exception_from_error_queue. It calls
2852# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2853_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002854
2855
2856
2857# Set the default string mask to match OpenSSL upstream (since 2005) and
2858# RFC5280 recommendations.
2859_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')