blob: d3aa8aa118d32aa1c3eae372764be04c050e86b9 [file] [log] [blame]
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001import datetime
Paul Kehrer8d887e12015-10-24 09:09:55 -05002
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05003from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05004from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05005from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04006from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05007
8from six import (
9 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -040010 text_type as _text_type,
11 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080012
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050013from OpenSSL._util import (
14 ffi as _ffi,
15 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050016 exception_from_error_queue as _exception_from_error_queue,
17 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040018 native as _native,
19 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040020 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Alex Gaynor67903a62016-06-02 10:37:13 -070021 make_assert as _make_assert,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040022)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080023
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050024FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
25FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080026
27# TODO This was an API mistake. OpenSSL has no such constant.
28FILETYPE_TEXT = 2 ** 16 - 1
29
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050030TYPE_RSA = _lib.EVP_PKEY_RSA
31TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080032
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080033
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050034class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050035 """
36 An error occurred in an `OpenSSL.crypto` API.
37 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050038
39
40_raise_current_error = partial(_exception_from_error_queue, Error)
Alex Gaynor67903a62016-06-02 10:37:13 -070041_openssl_assert = _make_assert(Error)
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050042
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070043
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050044def _untested_error(where):
45 """
46 An OpenSSL API failed somehow. Additionally, the failure which was
47 encountered isn't one that's exercised by the test suite so future behavior
48 of pyOpenSSL is now somewhat less predictable.
49 """
50 raise RuntimeError("Unknown %s failure" % (where,))
51
52
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050053def _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))
Alex Gaynor5945ea82015-09-05 14:59:06 -040068
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050069 # Keep the memory alive as long as the bio is alive!
70 def free(bio, ref=data):
71 return _lib.BIO_free(bio)
72
Alex Gaynorfb8a2a12016-06-04 18:26:26 -070073 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050074
75 bio = _ffi.gc(bio, free)
76 return bio
77
78
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080079def _bio_to_string(bio):
80 """
81 Copy the contents of an OpenSSL BIO object into a Python byte string.
82 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050083 result_buffer = _ffi.new('char**')
84 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
85 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080086
87
Jean-Paul Calderone57122982013-02-21 08:47:05 -080088def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050089 """
90 The the time value of an ASN1 time object.
91
92 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
93 castable to that type) which will have its value set.
94 @param when: A string representation of the desired time value.
95
96 @raise TypeError: If C{when} is not a L{bytes} string.
97 @raise ValueError: If C{when} does not represent a time in the required
98 format.
99 @raise RuntimeError: If the time value cannot be set for some other
100 (unspecified) reason.
101 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800102 if not isinstance(when, bytes):
103 raise TypeError("when must be a byte string")
104
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500105 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
106 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800107 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500108 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
109 _lib.ASN1_STRING_set(dummy, when, len(when))
110 check_result = _lib.ASN1_GENERALIZEDTIME_check(
111 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800112 if not check_result:
113 raise ValueError("Invalid string")
114 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500115 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800116
Alex Gaynor510293e2016-06-02 12:07:59 -0700117
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800118def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500119 """
120 Retrieve the time value of an ASN1 time object.
121
122 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
123 that type) from which the time value will be retrieved.
124
125 @return: The time value from C{timestamp} as a L{bytes} string in a certain
126 format. Or C{None} if the object contains no time value.
127 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500128 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
129 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800130 return None
Alex Gaynor5945ea82015-09-05 14:59:06 -0400131 elif (
132 _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
133 ):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500134 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800135 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500136 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
137 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
138 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500139 # This may happen:
140 # - if timestamp was not an ASN1_TIME
141 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
142 # - if a copy of the time data from timestamp cannot be made for
143 # the newly allocated ASN1_GENERALIZEDTIME
144 #
145 # These are difficult to test. cffi enforces the ASN1_TIME type.
146 # Memory allocation failures are a pain to trigger
147 # deterministically.
148 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800149 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500150 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800151 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500152 string_data = _lib.ASN1_STRING_data(string_timestamp)
153 string_result = _ffi.string(string_data)
154 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800155 return string_result
156
157
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800158class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200159 """
160 A class representing an DSA or RSA public key or key pair.
161 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800162 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800163 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800164
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800165 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500166 pkey = _lib.EVP_PKEY_new()
167 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800168 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800169
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800170 def generate_key(self, type, bits):
171 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700172 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800173
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200174 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800175
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200176 :param type: The key type.
177 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
178 :param bits: The number of bits.
179 :type bits: :py:data:`int` ``>= 0``
180 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
181 of the appropriate type.
182 :raises ValueError: If the number of bits isn't an integer of
183 the appropriate size.
Dan Sully44e767a2016-06-04 18:05:27 -0700184 :return: ``None``
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800185 """
186 if not isinstance(type, int):
187 raise TypeError("type must be an integer")
188
189 if not isinstance(bits, int):
190 raise TypeError("bits must be an integer")
191
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800192 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500193 exponent = _lib.BN_new()
194 exponent = _ffi.gc(exponent, _lib.BN_free)
195 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800196
197 if type == TYPE_RSA:
198 if bits <= 0:
199 raise ValueError("Invalid number of bits")
200
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500201 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800202
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500203 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500204 if result == 0:
205 # TODO: The test for this case is commented out. Different
206 # builds of OpenSSL appear to have different failure modes that
207 # make it hard to test. Visual inspection of the OpenSSL
208 # source reveals that a return value of 0 signals an error.
209 # Manual testing on a particular build of OpenSSL suggests that
210 # this is probably the appropriate way to handle those errors.
211 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800212
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500213 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800214 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500215 # TODO: It appears as though this can fail if an engine is in
216 # use which does not support RSA.
217 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800218
219 elif type == TYPE_DSA:
Paul Kehrera0860b92016-03-09 21:39:27 -0400220 dsa = _lib.DSA_new()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700221 _openssl_assert(dsa != _ffi.NULL)
Paul Kehrerafa5a662016-03-10 10:29:28 -0400222
223 dsa = _ffi.gc(dsa, _lib.DSA_free)
Paul Kehrera0860b92016-03-09 21:39:27 -0400224 res = _lib.DSA_generate_parameters_ex(
225 dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL
226 )
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700227 _openssl_assert(res == 1)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500228 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500229 # TODO: This is untested.
230 _raise_current_error()
Paul Kehrerafa5a662016-03-10 10:29:28 -0400231 if not _lib.EVP_PKEY_set1_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500232 # TODO: This is untested.
233 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800234 else:
235 raise Error("No such key type")
236
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800237 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800238
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800239 def check(self):
240 """
241 Check the consistency of an RSA private key.
242
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200243 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
244
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800245 :return: True if key is consistent.
246 :raise Error: if the key is inconsistent.
247 :raise TypeError: if the key is of a type which cannot be checked.
248 Only RSA keys can currently be checked.
249 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800250 if self._only_public:
251 raise TypeError("public key only")
252
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100253 if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800254 raise TypeError("key type unsupported")
255
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500256 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
257 rsa = _ffi.gc(rsa, _lib.RSA_free)
258 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800259 if result:
260 return True
261 _raise_current_error()
262
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800263 def type(self):
264 """
265 Returns the type of the key
266
267 :return: The type of the key.
268 """
Alex Gaynorc84567b2016-03-16 07:45:09 -0400269 return _lib.Cryptography_EVP_PKEY_id(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800270
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800271 def bits(self):
272 """
273 Returns the number of bits of the key
274
275 :return: The number of bits of the key.
276 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500277 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800278PKeyType = PKey
279
280
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400281class _EllipticCurve(object):
282 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400283 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400284
285 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
286 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
287 instances each of which represents one curve supported by the system.
288 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400289 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400290 _curves = None
291
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400292 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400293 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400294 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400295 """
296 Implement cooperation with the right-hand side argument of ``!=``.
297
298 Python 3 seems to have dropped this cooperation in this very narrow
299 circumstance.
300 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400301 if isinstance(other, _EllipticCurve):
302 return super(_EllipticCurve, self).__ne__(other)
303 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400304
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400305 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400306 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400307 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400308 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400309
310 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400311
312 :return: A :py:type:`set` of ``cls`` instances giving the names of the
313 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400314 """
315 if lib.Cryptography_HAS_EC:
316 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
317 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400318 # The return value on this call should be num_curves again. We
319 # could check it to make sure but if it *isn't* then.. what could
320 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400321 lib.EC_get_builtin_curves(builtin_curves, num_curves)
322 return set(
323 cls.from_nid(lib, c.nid)
324 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400325 return set()
326
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400327 @classmethod
328 def _get_elliptic_curves(cls, lib):
329 """
330 Get, cache, and return the curves supported by OpenSSL.
331
332 :param lib: The OpenSSL library binding object.
333
334 :return: A :py:type:`set` of ``cls`` instances giving the names of the
335 elliptic curves the underlying library supports.
336 """
337 if cls._curves is None:
338 cls._curves = cls._load_elliptic_curves(lib)
339 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400340
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400341 @classmethod
342 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400343 """
344 Instantiate a new :py:class:`_EllipticCurve` associated with the given
345 OpenSSL NID.
346
347 :param lib: The OpenSSL library binding object.
348
349 :param nid: The OpenSSL NID the resulting curve object will represent.
350 This must be a curve NID (and not, for example, a hash NID) or
351 subsequent operations will fail in unpredictable ways.
352 :type nid: :py:class:`int`
353
354 :return: The curve object.
355 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400356 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
357
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400358 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400359 """
360 :param _lib: The :py:mod:`cryptography` binding instance used to
361 interface with OpenSSL.
362
363 :param _nid: The OpenSSL NID identifying the curve this object
364 represents.
365 :type _nid: :py:class:`int`
366
367 :param name: The OpenSSL short name identifying the curve this object
368 represents.
369 :type name: :py:class:`unicode`
370 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400371 self._lib = lib
372 self._nid = nid
373 self.name = name
374
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400375 def __repr__(self):
376 return "<Curve %r>" % (self.name,)
377
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400378 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400379 """
380 Create a new OpenSSL EC_KEY structure initialized to use this curve.
381
382 The structure is automatically garbage collected when the Python object
383 is garbage collected.
384 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400385 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
386 return _ffi.gc(key, _lib.EC_KEY_free)
387
388
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400389def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400390 """
391 Return a set of objects representing the elliptic curves supported in the
392 OpenSSL build in use.
393
394 The curve objects have a :py:class:`unicode` ``name`` attribute by which
395 they identify themselves.
396
397 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400398 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
399 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400400 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400401 return _EllipticCurve._get_elliptic_curves(_lib)
402
403
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400404def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400405 """
406 Return a single curve object selected by name.
407
408 See :py:func:`get_elliptic_curves` for information about curve objects.
409
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400410 :param name: The OpenSSL short name identifying the curve object to
411 retrieve.
412 :type name: :py:class:`unicode`
413
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400414 If the named curve is not supported then :py:class:`ValueError` is raised.
415 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400416 for curve in get_elliptic_curves():
417 if curve.name == name:
418 return curve
419 raise ValueError("unknown curve name", name)
420
421
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800422class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200423 """
424 An X.509 Distinguished Name.
425
426 :ivar countryName: The country of the entity.
427 :ivar C: Alias for :py:attr:`countryName`.
428
429 :ivar stateOrProvinceName: The state or province of the entity.
430 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
431
432 :ivar localityName: The locality of the entity.
433 :ivar L: Alias for :py:attr:`localityName`.
434
435 :ivar organizationName: The organization name of the entity.
436 :ivar O: Alias for :py:attr:`organizationName`.
437
438 :ivar organizationalUnitName: The organizational unit of the entity.
439 :ivar OU: Alias for :py:attr:`organizationalUnitName`
440
441 :ivar commonName: The common name of the entity.
442 :ivar CN: Alias for :py:attr:`commonName`.
443
444 :ivar emailAddress: The e-mail address of the entity.
445 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400446
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800447 def __init__(self, name):
448 """
449 Create a new X509Name, copying the given X509Name instance.
450
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200451 :param name: The name to copy.
452 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800453 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500454 name = _lib.X509_NAME_dup(name._name)
455 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800456
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800457 def __setattr__(self, name, value):
458 if name.startswith('_'):
459 return super(X509Name, self).__setattr__(name, value)
460
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800461 # Note: we really do not want str subclasses here, so we do not use
462 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800463 if type(name) is not str:
464 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400465 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800466
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500467 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500468 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800469 try:
470 _raise_current_error()
471 except Error:
472 pass
473 raise AttributeError("No such attribute")
474
475 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500476 for i in range(_lib.X509_NAME_entry_count(self._name)):
477 ent = _lib.X509_NAME_get_entry(self._name, i)
478 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
479 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800480 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500481 ent = _lib.X509_NAME_delete_entry(self._name, i)
482 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800483 break
484
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500485 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800486 value = value.encode('utf-8')
487
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500488 add_result = _lib.X509_NAME_add_entry_by_NID(
489 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800490 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500491 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800492
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800493 def __getattr__(self, name):
494 """
495 Find attribute. An X509Name object has the following attributes:
496 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400497 organization (alias O), organizationalUnit (alias OU), commonName
498 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800499 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500500 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500501 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800502 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
503 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
504 # push something onto the error queue. If we don't clean that up
505 # now, someone else will bump into it later and be quite confused.
506 # See lp#314814.
507 try:
508 _raise_current_error()
509 except Error:
510 pass
511 return super(X509Name, self).__getattr__(name)
512
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500513 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800514 if entry_index == -1:
515 return None
516
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500517 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
518 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800519
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500520 result_buffer = _ffi.new("unsigned char**")
521 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800522 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500523 # TODO: This is untested.
524 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800525
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700526 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400527 result = _ffi.buffer(
528 result_buffer[0], data_length
529 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700530 finally:
531 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500532 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800533 return result
534
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500535 def _cmp(op):
536 def f(self, other):
537 if not isinstance(other, X509Name):
538 return NotImplemented
539 result = _lib.X509_NAME_cmp(self._name, other._name)
540 return op(result, 0)
541 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800542
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500543 __eq__ = _cmp(__eq__)
544 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800545
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500546 __lt__ = _cmp(__lt__)
547 __le__ = _cmp(__le__)
548
549 __gt__ = _cmp(__gt__)
550 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800551
552 def __repr__(self):
553 """
554 String representation of an X509Name
555 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400556 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500557 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800558 self._name, result_buffer, len(result_buffer))
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700559 _openssl_assert(format_result != _ffi.NULL)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800560
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500561 return "<X509Name object '%s'>" % (
562 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800563
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800564 def hash(self):
565 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200566 Return an integer representation of the first four bytes of the
567 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800568
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200569 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
570
571 :return: The (integer) hash of this name.
572 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800573 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500574 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800575
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800576 def der(self):
577 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200578 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800579
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200580 :return: The DER encoded form of this name.
581 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800582 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500583 result_buffer = _ffi.new('unsigned char**')
584 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500586 # TODO: This is untested.
587 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800588
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500589 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
590 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800591 return string_result
592
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800593 def get_components(self):
594 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200595 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800596
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200597 :return: The components of this name.
598 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800599 """
600 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500601 for i in range(_lib.X509_NAME_entry_count(self._name)):
602 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800603
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500604 fname = _lib.X509_NAME_ENTRY_get_object(ent)
605 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800606
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500607 nid = _lib.OBJ_obj2nid(fname)
608 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800609
610 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400611 _ffi.string(name),
612 _ffi.string(
613 _lib.ASN1_STRING_data(fval),
614 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800615
616 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200617
618
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800619X509NameType = X509Name
620
621
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800622class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200623 """
624 An X.509 v3 certificate extension.
625 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400626
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800627 def __init__(self, type_name, critical, value, subject=None, issuer=None):
628 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200629 Initializes an X509 extension.
630
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100631 :param type_name: The name of the type of extension_ to create.
Alex Gaynor6f719912015-09-20 09:21:29 -0400632 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800633
Alex Gaynor5945ea82015-09-05 14:59:06 -0400634 :param bool critical: A flag indicating whether this is a critical
635 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800636
637 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200638 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800639
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200640 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800641 :type subject: :py:class:`X509`
642
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200643 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800644 :type issuer: :py:class:`X509`
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100645
646 .. _extension: https://openssl.org/docs/manmaster/apps/
647 x509v3_config.html#STANDARD-EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800648 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500649 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800650
Alex Gaynor5945ea82015-09-05 14:59:06 -0400651 # A context is necessary for any extension which uses the r2i
652 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
653 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500654 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800655
656 # We have no configuration database - but perhaps we should (some
657 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500658 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800659
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800660 # Initialize the subject and issuer, if appropriate. ctx is a local,
661 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400662 # any references, so no need to mess with reference counts or
663 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800664 if issuer is not None:
665 if not isinstance(issuer, X509):
666 raise TypeError("issuer must be an X509 instance")
667 ctx.issuer_cert = issuer._x509
668 if subject is not None:
669 if not isinstance(subject, X509):
670 raise TypeError("subject must be an X509 instance")
671 ctx.subject_cert = subject._x509
672
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800673 if critical:
674 # There are other OpenSSL APIs which would let us pass in critical
675 # separately, but they're harder to use, and since value is already
676 # a pile of crappy junk smuggling a ton of utterly important
677 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400678 # with strings? (However, X509V3_EXT_i2d in particular seems like
679 # it would be a better API to invoke. I do not know where to get
680 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500681 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800682
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500683 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
684 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800685 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500686 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800687
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400688 @property
689 def _nid(self):
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400690 return _lib.OBJ_obj2nid(
691 _lib.X509_EXTENSION_get_object(self._extension)
692 )
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400693
694 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500695 _lib.GEN_EMAIL: "email",
696 _lib.GEN_DNS: "DNS",
697 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400698 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400699
700 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500701 method = _lib.X509V3_EXT_get(self._extension)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700702 _openssl_assert(method != _ffi.NULL)
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400703 ext_data = _lib.X509_EXTENSION_get_data(self._extension)
704 payload = ext_data.data
705 length = ext_data.length
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400706
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500707 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400708 payloadptr[0] = payload
709
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500710 if method.it != _ffi.NULL:
711 ptr = _lib.ASN1_ITEM_ptr(method.it)
712 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
713 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400714 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500715 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400716 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500717 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400718
Paul Kehrerb7d79502015-05-04 07:43:51 -0500719 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400720 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500721 for i in range(_lib.sk_GENERAL_NAME_num(names)):
722 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400723 try:
724 label = self._prefixes[name.type]
725 except KeyError:
726 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500727 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500728 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400729 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500730 value = _native(
731 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
732 parts.append(label + ":" + value)
733 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400734
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800735 def __str__(self):
736 """
737 :return: a nice text representation of the extension
738 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500739 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400740 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800741
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400742 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500743 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800744 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500745 # TODO: This is untested.
746 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800747
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500748 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800749
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800750 def get_critical(self):
751 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200752 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800753
754 :return: The critical field.
755 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500756 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800757
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800758 def get_short_name(self):
759 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200760 Returns the short type name of this X.509 extension.
761
762 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800763
764 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200765 :rtype: :py:data:`bytes`
766
767 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800768 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500769 obj = _lib.X509_EXTENSION_get_object(self._extension)
770 nid = _lib.OBJ_obj2nid(obj)
771 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800772
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800773 def get_data(self):
774 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200775 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800776
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200777 :return: The ASN.1 encoded data of this X509 extension.
778 :rtype: :py:data:`bytes`
779
780 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800781 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500782 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
783 string_result = _ffi.cast('ASN1_STRING*', octet_result)
784 char_result = _lib.ASN1_STRING_data(string_result)
785 result_length = _lib.ASN1_STRING_length(string_result)
786 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800787
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200788
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800789X509ExtensionType = X509Extension
790
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800791
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800792class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200793 """
794 An X.509 certificate signing requests.
795 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400796
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800797 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500798 req = _lib.X509_REQ_new()
799 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800800
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800801 def set_pubkey(self, pkey):
802 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200803 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800804
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200805 :param pkey: The public key to use.
806 :type pkey: :py:class:`PKey`
807
Dan Sully44e767a2016-06-04 18:05:27 -0700808 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800809 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500810 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500812 # TODO: This is untested.
813 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800814
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800815 def get_pubkey(self):
816 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200817 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800818
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200819 :return: The public key.
820 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800821 """
822 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500823 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700824 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500825 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800826 pkey._only_public = True
827 return pkey
828
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800829 def set_version(self, version):
830 """
831 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
832 request.
833
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200834 :param int version: The version number.
Dan Sully44e767a2016-06-04 18:05:27 -0700835 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800836 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500837 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800838 if not set_result:
839 _raise_current_error()
840
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800841 def get_version(self):
842 """
843 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
844 request.
845
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200846 :return: The value of the version subfield.
847 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800848 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500849 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800851 def get_subject(self):
852 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200853 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854
Cory Benfield881dc8d2015-12-09 08:25:14 +0000855 This creates a new :class:`X509Name` that wraps the underlying subject
856 name field on the certificate signing request. Modifying it will modify
857 the underlying signing request, and will have the effect of modifying
858 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200859
860 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000861 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800862 """
863 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500864 name._name = _lib.X509_REQ_get_subject_name(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700865 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800866
867 # The name is owned by the X509Req structure. As long as the X509Name
868 # Python object is alive, keep the X509Req Python object alive.
869 name._owner = self
870
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800871 return name
872
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800873 def add_extensions(self, extensions):
874 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200875 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800876
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200877 :param extensions: The X.509 extensions to add.
878 :type extensions: iterable of :py:class:`X509Extension`
Dan Sully44e767a2016-06-04 18:05:27 -0700879 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800880 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500881 stack = _lib.sk_X509_EXTENSION_new_null()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700882 _openssl_assert(stack != _ffi.NULL)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800883
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500884 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800885
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800886 for ext in extensions:
887 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800888 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800890 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500891 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800892
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500893 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800894 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500895 # TODO: This is untested.
896 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800897
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800898 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800899 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200900 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800901
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200902 :return: The X.509 extensions in this request.
903 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
904
905 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800906 """
907 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500908 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500909 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800910 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500911 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800912 exts.append(ext)
913 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800914
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800915 def sign(self, pkey, digest):
916 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700917 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800918
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200919 :param pkey: The key pair to sign with.
920 :type pkey: :py:class:`PKey`
921 :param digest: The name of the message digest to use for the signature,
922 e.g. :py:data:`b"sha1"`.
923 :type digest: :py:class:`bytes`
Dan Sully44e767a2016-06-04 18:05:27 -0700924 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800925 """
926 if pkey._only_public:
927 raise ValueError("Key has only public part")
928
929 if not pkey._initialized:
930 raise ValueError("Key is uninitialized")
931
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500932 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500933 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800934 raise ValueError("No such digest method")
935
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500936 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800937 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500938 # TODO: This is untested.
939 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800940
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800941 def verify(self, pkey):
942 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200943 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800944
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200945 :param key: A public key.
946 :type key: :py:class:`PKey`
947 :return: :py:data:`True` if the signature is correct.
948 :rtype: :py:class:`bool`
949 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800950 problem verifying the signature.
951 """
952 if not isinstance(pkey, PKey):
953 raise TypeError("pkey must be a PKey instance")
954
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500955 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800956 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500957 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800958
959 return result
960
961
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800962X509ReqType = X509Req
963
964
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800965class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200966 """
967 An X.509 certificate.
968 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400969
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800970 def __init__(self):
971 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500972 x509 = _lib.X509_new()
973 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800974
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800975 def set_version(self, version):
976 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200977 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800978
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200979 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800980 :type version: :py:class:`int`
981
Dan Sully44e767a2016-06-04 18:05:27 -0700982 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800983 """
984 if not isinstance(version, int):
985 raise TypeError("version must be an integer")
986
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500987 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800988
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800989 def get_version(self):
990 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200991 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800992
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200993 :return: The version number of the certificate.
994 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800995 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500996 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800997
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800998 def get_pubkey(self):
999 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001000 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001001
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001002 :return: The public key.
1003 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001004 """
1005 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001006 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1007 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001008 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001009 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001010 pkey._only_public = True
1011 return pkey
1012
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001013 def set_pubkey(self, pkey):
1014 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001015 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001016
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001017 :param pkey: The public key.
1018 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001019
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001020 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001021 """
1022 if not isinstance(pkey, PKey):
1023 raise TypeError("pkey must be a PKey instance")
1024
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001025 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001026 if not set_result:
1027 _raise_current_error()
1028
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001029 def sign(self, pkey, digest):
1030 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001031 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001032
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001033 :param pkey: The key to sign with.
1034 :type pkey: :py:class:`PKey`
1035
1036 :param digest: The name of the message digest to use.
1037 :type digest: :py:class:`bytes`
1038
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001039 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001040 """
1041 if not isinstance(pkey, PKey):
1042 raise TypeError("pkey must be a PKey instance")
1043
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001044 if pkey._only_public:
1045 raise ValueError("Key only has public part")
1046
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001047 if not pkey._initialized:
1048 raise ValueError("Key is uninitialized")
1049
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001050 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001051 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001052 raise ValueError("No such digest method")
1053
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001054 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001055 if not sign_result:
1056 _raise_current_error()
1057
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001058 def get_signature_algorithm(self):
1059 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001060 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001061
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001062 :return: The name of the algorithm.
1063 :rtype: :py:class:`bytes`
1064
1065 :raises ValueError: If the signature algorithm is undefined.
1066
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001067 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001068 """
Alex Gaynor39ea5312016-06-02 09:12:10 -07001069 algor = _lib.X509_get0_tbs_sigalg(self._x509)
1070 nid = _lib.OBJ_obj2nid(algor.algorithm)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001071 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001072 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001073 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001074
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001075 def digest(self, digest_name):
1076 """
1077 Return the digest of the X509 object.
1078
1079 :param digest_name: The name of the digest algorithm to use.
1080 :type digest_name: :py:class:`bytes`
1081
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001082 :return: The digest of the object, formatted as
1083 :py:const:`b":"`-delimited hex pairs.
1084 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001085 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001086 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001087 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001088 raise ValueError("No such digest method")
1089
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001090 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1091 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001092 result_length[0] = len(result_buffer)
1093
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001094 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001095 self._x509, digest, result_buffer, result_length)
1096
1097 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001098 # TODO: This is untested.
1099 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001100
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001101 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001102 b16encode(ch).upper() for ch
1103 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001104
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001105 def subject_name_hash(self):
1106 """
1107 Return the hash of the X509 subject.
1108
1109 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001110 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001111 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001112 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001113
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001114 def set_serial_number(self, serial):
1115 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001116 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001117
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001118 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001119 :type serial: :py:class:`int`
1120
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001121 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001122 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001123 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001124 raise TypeError("serial must be an integer")
1125
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001126 hex_serial = hex(serial)[2:]
1127 if not isinstance(hex_serial, bytes):
1128 hex_serial = hex_serial.encode('ascii')
1129
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001130 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001131
1132 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001133 # it. If bignum is still NULL after this call, then the return value
1134 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001135 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001136
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001137 if bignum_serial[0] == _ffi.NULL:
1138 set_result = _lib.ASN1_INTEGER_set(
1139 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001140 if set_result:
1141 # TODO Not tested
1142 _raise_current_error()
1143 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001144 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1145 _lib.BN_free(bignum_serial[0])
1146 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001147 # TODO Not tested
1148 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001149 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1150 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001151 if not set_result:
1152 # TODO Not tested
1153 _raise_current_error()
1154
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001155 def get_serial_number(self):
1156 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001157 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001158
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001159 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001160 :rtype: int
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001161 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001162 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1163 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001164 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001165 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001166 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001167 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001168 serial = int(hexstring_serial, 16)
1169 return serial
1170 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001171 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001172 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001173 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001174
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001175 def gmtime_adj_notAfter(self, amount):
1176 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001177 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001178
Dan Sully44e767a2016-06-04 18:05:27 -07001179 :param int amount: The number of seconds by which to adjust the
1180 timestamp.
1181 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001182 """
1183 if not isinstance(amount, int):
1184 raise TypeError("amount must be an integer")
1185
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001186 notAfter = _lib.X509_get_notAfter(self._x509)
1187 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001188
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001189 def gmtime_adj_notBefore(self, amount):
1190 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001191 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001192
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001193 :param amount: The number of seconds by which to adjust the timestamp.
Dan Sully44e767a2016-06-04 18:05:27 -07001194 :return: ``None``
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001195 """
1196 if not isinstance(amount, int):
1197 raise TypeError("amount must be an integer")
1198
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001199 notBefore = _lib.X509_get_notBefore(self._x509)
1200 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001201
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001202 def has_expired(self):
1203 """
1204 Check whether the certificate has expired.
1205
Dan Sully44e767a2016-06-04 18:05:27 -07001206 :return: ``True`` if the certificate has expired, ``False`` otherwise.
1207 :rtype: bool
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001208 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001209 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001210 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001211
Paul Kehrerfde45c92016-01-21 12:57:37 -06001212 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001213
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001214 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001215 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001216
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001217 def get_notBefore(self):
1218 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001219 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001220
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001221 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001222
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001223 YYYYMMDDhhmmssZ
1224 YYYYMMDDhhmmss+hhmm
1225 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001226
Dan Sully44e767a2016-06-04 18:05:27 -07001227 :return: A timestamp string, or ``None`` if there is none.
1228 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001229 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001230 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001231
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001232 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001233 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001234
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001235 def set_notBefore(self, when):
1236 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001237 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001238
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001239 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001240
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001241 YYYYMMDDhhmmssZ
1242 YYYYMMDDhhmmss+hhmm
1243 YYYYMMDDhhmmss-hhmm
1244
Dan Sully44e767a2016-06-04 18:05:27 -07001245 :param bytes when: A timestamp string.
1246 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001247 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001248 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001249
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001250 def get_notAfter(self):
1251 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001252 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001253
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001254 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001255
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001256 YYYYMMDDhhmmssZ
1257 YYYYMMDDhhmmss+hhmm
1258 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001259
Dan Sully44e767a2016-06-04 18:05:27 -07001260 :return: A timestamp string, or ``None`` if there is none.
1261 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001262 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001263 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001264
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001265 def set_notAfter(self, when):
1266 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001267 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001268
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001269 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001270
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001271 YYYYMMDDhhmmssZ
1272 YYYYMMDDhhmmss+hhmm
1273 YYYYMMDDhhmmss-hhmm
1274
Dan Sully44e767a2016-06-04 18:05:27 -07001275 :param bytes when: A timestamp string.
1276 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001277 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001278 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001279
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001280 def _get_name(self, which):
1281 name = X509Name.__new__(X509Name)
1282 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001283 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001284 # TODO: This is untested.
1285 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001286
1287 # The name is owned by the X509 structure. As long as the X509Name
1288 # Python object is alive, keep the X509 Python object alive.
1289 name._owner = self
1290
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001291 return name
1292
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001293 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001294 if not isinstance(name, X509Name):
1295 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001296 set_result = which(self._x509, name._name)
1297 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001298 # TODO: This is untested.
1299 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001300
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001301 def get_issuer(self):
1302 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001303 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001304
Cory Benfielde6bcce82015-12-09 08:40:03 +00001305 This creates a new :class:`X509Name` that wraps the underlying issuer
1306 name field on the certificate. Modifying it will modify the underlying
1307 certificate, and will have the effect of modifying any other
1308 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001309
1310 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001311 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001312 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001313 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001314
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001315 def set_issuer(self, issuer):
1316 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001317 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001318
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001319 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001320 :type issuer: :py:class:`X509Name`
1321
Dan Sully44e767a2016-06-04 18:05:27 -07001322 :return: ``None``
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001323 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001324 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001325
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001326 def get_subject(self):
1327 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001328 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001329
Cory Benfielde6bcce82015-12-09 08:40:03 +00001330 This creates a new :class:`X509Name` that wraps the underlying subject
1331 name field on the certificate. Modifying it will modify the underlying
1332 certificate, and will have the effect of modifying any other
1333 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001334
1335 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001336 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001337 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001338 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001339
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001340 def set_subject(self, subject):
1341 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001342 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001343
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001344 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001345 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001346
Dan Sully44e767a2016-06-04 18:05:27 -07001347 :return: ``None``
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001348 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001349 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001350
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001351 def get_extension_count(self):
1352 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001353 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001354
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001355 :return: The number of extensions.
1356 :rtype: :py:class:`int`
1357
1358 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001359 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001360 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001361
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001362 def add_extensions(self, extensions):
1363 """
1364 Add extensions to the certificate.
1365
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001366 :param extensions: The extensions to add.
1367 :type extensions: An iterable of :py:class:`X509Extension` objects.
Dan Sully44e767a2016-06-04 18:05:27 -07001368 :return: ``None``
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001369 """
1370 for ext in extensions:
1371 if not isinstance(ext, X509Extension):
1372 raise ValueError("One of the elements is not an X509Extension")
1373
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001374 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001375 if not add_result:
1376 _raise_current_error()
1377
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001378 def get_extension(self, index):
1379 """
1380 Get a specific extension of the certificate by index.
1381
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001382 Extensions on a certificate are kept in order. The index
1383 parameter selects which extension will be returned.
1384
1385 :param int index: The index of the extension to retrieve.
1386 :return: The extension at the specified index.
1387 :rtype: :py:class:`X509Extension`
1388 :raises IndexError: If the extension index was out of bounds.
1389
1390 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001391 """
1392 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001393 ext._extension = _lib.X509_get_ext(self._x509, index)
1394 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001395 raise IndexError("extension index out of bounds")
1396
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001397 extension = _lib.X509_EXTENSION_dup(ext._extension)
1398 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001399 return ext
1400
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001401
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001402X509Type = X509
1403
1404
Dan Sully44e767a2016-06-04 18:05:27 -07001405class X509StoreFlags(object):
1406 """
1407 Flags for X509 verification, used to change the behavior of
1408 :class:`X509Store`.
1409
1410 See `OpenSSL Verification Flags`_ for details.
1411
1412 .. _OpenSSL Verification Flags:
1413 https://www.openssl.org/docs/manmaster/crypto/X509_VERIFY_PARAM_set_flags.html
1414 """
1415 CRL_CHECK = _lib.X509_V_FLAG_CRL_CHECK
1416 CRL_CHECK_ALL = _lib.X509_V_FLAG_CRL_CHECK_ALL
1417 IGNORE_CRITICAL = _lib.X509_V_FLAG_IGNORE_CRITICAL
1418 X509_STRICT = _lib.X509_V_FLAG_X509_STRICT
1419 ALLOW_PROXY_CERTS = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS
1420 POLICY_CHECK = _lib.X509_V_FLAG_POLICY_CHECK
1421 EXPLICIT_POLICY = _lib.X509_V_FLAG_EXPLICIT_POLICY
1422 INHIBIT_MAP = _lib.X509_V_FLAG_INHIBIT_MAP
1423 NOTIFY_POLICY = _lib.X509_V_FLAG_NOTIFY_POLICY
1424 CHECK_SS_SIGNATURE = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE
1425 CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK
1426
1427
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001428class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001429 """
Dan Sully44e767a2016-06-04 18:05:27 -07001430 An X.509 store.
1431
1432 An X.509 store is used to describe a context in which to verify a
1433 certificate. A description of a context may include a set of certificates
1434 to trust, a set of certificate revocation lists, verification flags and
1435 more.
1436
1437 An X.509 store, being only a description, cannot be used by itself to
1438 verify a certificate. To carry out the actual verification process, see
1439 :class:`X509StoreContext`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001440 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001441
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001442 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001443 store = _lib.X509_STORE_new()
1444 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001445
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001446 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001447 """
Dan Sully44e767a2016-06-04 18:05:27 -07001448 Adds a trusted certificate to this store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001449
Dan Sully44e767a2016-06-04 18:05:27 -07001450 Adding a certificate with this method adds this certificate as a
1451 *trusted* certificate.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001452
1453 :param X509 cert: The certificate to add to this store.
Dan Sully44e767a2016-06-04 18:05:27 -07001454 :raises TypeError: If the certificate is not an :class:`X509`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001455 :raises Error: If OpenSSL was unhappy with your certificate.
Dan Sully44e767a2016-06-04 18:05:27 -07001456 :return: ``None`` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001457 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001458 if not isinstance(cert, X509):
1459 raise TypeError()
1460
Dan Sully44e767a2016-06-04 18:05:27 -07001461 _openssl_assert(_lib.X509_STORE_add_cert(self._store, cert._x509) != 0)
1462
1463 def add_crl(self, crl):
1464 """
1465 Add a certificate revocation list to this store.
1466
1467 The certificate revocation lists added to a store will only be used if
1468 the associated flags are configured to check certificate revocation
1469 lists.
1470
1471 .. versionadded:: 16.1.0
1472
1473 :param CRL crl: The certificate revocation list to add to this store.
1474 :return: ``None`` if the certificate revocation list was added
1475 successfully.
1476 """
1477 _openssl_assert(_lib.X509_STORE_add_crl(self._store, crl._crl) != 0)
1478
1479 def set_flags(self, flags):
1480 """
1481 Set verification flags to this store.
1482
1483 Verification flags can be combined by oring them together.
1484
1485 .. note::
1486
1487 Setting a verification flag sometimes requires clients to add
1488 additional information to the store, otherwise a suitable error will
1489 be raised.
1490
1491 For example, in setting flags to enable CRL checking a
1492 suitable CRL must be added to the store otherwise an error will be
1493 raised.
1494
1495 .. versionadded:: 16.1.0
1496
1497 :param int flags: The verification flags to set on this store.
1498 See :class:`X509StoreFlags` for available constants.
1499 :return: ``None`` if the verification flags were successfully set.
1500 """
1501 _openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0)
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001502
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001503
1504X509StoreType = X509Store
1505
1506
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001507class X509StoreContextError(Exception):
1508 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001509 An exception raised when an error occurred while verifying a certificate
1510 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001511
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001512 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001513 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001514 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001515
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001516 def __init__(self, message, certificate):
1517 super(X509StoreContextError, self).__init__(message)
1518 self.certificate = certificate
1519
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001520
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001521class X509StoreContext(object):
1522 """
1523 An X.509 store context.
1524
Dan Sully44e767a2016-06-04 18:05:27 -07001525 An X.509 store context is used to carry out the actual verification process
1526 of a certificate in a described context. For describing such a context, see
1527 :class:`X509Store`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001528
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001529 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1530 instance. It is dynamically allocated and automatically garbage
1531 collected.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001532 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001533 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001534 :param X509Store store: The certificates which will be trusted for the
1535 purposes of any verifications.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001536 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001537 """
1538
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001539 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001540 store_ctx = _lib.X509_STORE_CTX_new()
1541 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1542 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001543 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001544 # Make the store context available for use after instantiating this
1545 # class by initializing it now. Per testing, subsequent calls to
Dan Sully44e767a2016-06-04 18:05:27 -07001546 # :meth:`_init` have no adverse affect.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001547 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001548
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001549 def _init(self):
1550 """
1551 Set up the store context for a subsequent verification operation.
1552 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001553 ret = _lib.X509_STORE_CTX_init(
1554 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1555 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001556 if ret <= 0:
1557 _raise_current_error()
1558
1559 def _cleanup(self):
1560 """
1561 Internally cleans up the store context.
1562
Dan Sully44e767a2016-06-04 18:05:27 -07001563 The store context can then be reused with a new call to :meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001564 """
1565 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1566
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001567 def _exception_from_context(self):
1568 """
1569 Convert an OpenSSL native context error failure into a Python
1570 exception.
1571
Alex Gaynor5945ea82015-09-05 14:59:06 -04001572 When a call to native OpenSSL X509_verify_cert fails, additional
1573 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001574 """
1575 errors = [
1576 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1577 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1578 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001579 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001580 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001581 # A context error should always be associated with a certificate, so we
1582 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001583 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001584 _cert = _lib.X509_dup(_x509)
1585 pycert = X509.__new__(X509)
1586 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001587 return X509StoreContextError(errors, pycert)
1588
Stephen Holsapple46a09252015-02-12 14:45:43 -08001589 def set_store(self, store):
1590 """
Dan Sully44e767a2016-06-04 18:05:27 -07001591 Set the context's X.509 store.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001592
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001593 .. versionadded:: 0.15
1594
Dan Sully44e767a2016-06-04 18:05:27 -07001595 :param X509Store store: The store description which will be used for
1596 the purposes of any *future* verifications.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001597 """
1598 self._store = store
1599
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001600 def verify_certificate(self):
1601 """
1602 Verify a certificate in a context.
1603
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001604 .. versionadded:: 0.15
1605
Alex Gaynorca87ff62015-09-04 23:31:03 -04001606 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001607 certificate in the context. Sets ``certificate`` attribute to
1608 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001609 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001610 # Always re-initialize the store context in case
Dan Sully44e767a2016-06-04 18:05:27 -07001611 # :meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001612 self._init()
1613 ret = _lib.X509_verify_cert(self._store_ctx)
1614 self._cleanup()
1615 if ret <= 0:
1616 raise self._exception_from_context()
1617
1618
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001619def load_certificate(type, buffer):
1620 """
1621 Load a certificate from a buffer
1622
1623 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1624
Dan Sully44e767a2016-06-04 18:05:27 -07001625 :param bytes buffer: The buffer the certificate is stored in
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001626
1627 :return: The X509 object
1628 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001629 if isinstance(buffer, _text_type):
1630 buffer = buffer.encode("ascii")
1631
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001632 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001633
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001634 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001635 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001636 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001637 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001638 else:
1639 raise ValueError(
1640 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001641
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001642 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001643 _raise_current_error()
1644
1645 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001646 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001647 return cert
1648
1649
1650def dump_certificate(type, cert):
1651 """
1652 Dump a certificate to a buffer
1653
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001654 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1655 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001656 :param cert: The certificate to dump
1657 :return: The buffer with the dumped certificate in
1658 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001659 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001660
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001661 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001662 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001663 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001664 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001665 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001666 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001667 else:
1668 raise ValueError(
1669 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1670 "FILETYPE_TEXT")
1671
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001672 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001673 return _bio_to_string(bio)
1674
1675
Cory Benfield6492f7c2015-10-27 16:57:58 +09001676def dump_publickey(type, pkey):
1677 """
Cory Benfield11c10192015-10-27 17:23:03 +09001678 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001679
Cory Benfield9c590b92015-10-28 14:55:05 +09001680 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001681 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001682 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001683 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001684 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001685 """
1686 bio = _new_mem_buf()
1687 if type == FILETYPE_PEM:
1688 write_bio = _lib.PEM_write_bio_PUBKEY
1689 elif type == FILETYPE_ASN1:
1690 write_bio = _lib.i2d_PUBKEY_bio
1691 else:
1692 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1693
1694 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001695 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001696 _raise_current_error()
1697
1698 return _bio_to_string(bio)
1699
1700
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001701def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1702 """
1703 Dump a private key to a buffer
1704
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001705 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1706 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001707 :param pkey: The PKey to dump
1708 :param cipher: (optional) if encrypted PEM format, the cipher to
1709 use
1710 :param passphrase: (optional) if encrypted PEM format, this can be either
1711 the passphrase to use, or a callback for providing the
1712 passphrase.
1713 :return: The buffer with the dumped key in
Dan Sully44e767a2016-06-04 18:05:27 -07001714 :rtype: bytes
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001715 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001716 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001717
1718 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001719 if passphrase is None:
1720 raise TypeError(
1721 "if a value is given for cipher "
1722 "one must also be given for passphrase")
1723 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001724 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001725 raise ValueError("Invalid cipher name")
1726 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001727 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001728
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001729 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001730 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001731 result_code = _lib.PEM_write_bio_PrivateKey(
1732 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001733 helper.callback, helper.callback_args)
1734 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001735 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001736 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001737 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001738 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1739 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001740 # TODO RSA_free(rsa)?
1741 else:
1742 raise ValueError(
1743 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1744 "FILETYPE_TEXT")
1745
1746 if result_code == 0:
1747 _raise_current_error()
1748
1749 return _bio_to_string(bio)
1750
1751
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001752class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001753 """
1754 A certificate revocation.
1755 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001756 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1757 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1758 # OCSP_crl_reason_str. We use the latter, just like the command line
1759 # program.
1760 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001761 b"unspecified",
1762 b"keyCompromise",
1763 b"CACompromise",
1764 b"affiliationChanged",
1765 b"superseded",
1766 b"cessationOfOperation",
1767 b"certificateHold",
1768 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001769 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001770
1771 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001772 revoked = _lib.X509_REVOKED_new()
1773 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001774
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001775 def set_serial(self, hex_str):
1776 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001777 Set the serial number.
1778
1779 The serial number is formatted as a hexadecimal number encoded in
1780 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001781
Dan Sully44e767a2016-06-04 18:05:27 -07001782 :param bytes hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001783
Dan Sully44e767a2016-06-04 18:05:27 -07001784 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001785 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001786 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1787 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001788 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001789 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001790 if not bn_result:
1791 raise ValueError("bad hex string")
1792
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001793 asn1_serial = _ffi.gc(
1794 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1795 _lib.ASN1_INTEGER_free)
1796 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001797
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001798 def get_serial(self):
1799 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001800 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001801
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001802 The serial number is formatted as a hexadecimal number encoded in
1803 ASCII.
1804
1805 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001806 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001808 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809
Alex Gaynor67903a62016-06-02 10:37:13 -07001810 asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked)
1811 _openssl_assert(asn1_int != _ffi.NULL)
1812 result = _lib.i2a_ASN1_INTEGER(bio, asn1_int)
1813 _openssl_assert(result >= 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001814 return _bio_to_string(bio)
1815
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001816 def _delete_reason(self):
Alex Gaynor67903a62016-06-02 10:37:13 -07001817 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1818 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001819 obj = _lib.X509_EXTENSION_get_object(ext)
1820 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001821 _lib.X509_EXTENSION_free(ext)
Alex Gaynor67903a62016-06-02 10:37:13 -07001822 _lib.X509_REVOKED_delete_ext(self._revoked, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001823 break
1824
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001825 def set_reason(self, reason):
1826 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001827 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001828
Dan Sully44e767a2016-06-04 18:05:27 -07001829 If :data:`reason` is ``None``, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001830
1831 :param reason: The reason string.
Dan Sully44e767a2016-06-04 18:05:27 -07001832 :type reason: :class:`bytes` or :class:`NoneType`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001833
Dan Sully44e767a2016-06-04 18:05:27 -07001834 :return: ``None``
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001835
1836 .. seealso::
1837
Dan Sully44e767a2016-06-04 18:05:27 -07001838 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001839 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001840 """
1841 if reason is None:
1842 self._delete_reason()
1843 elif not isinstance(reason, bytes):
1844 raise TypeError("reason must be None or a byte string")
1845 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001846 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001847 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1848
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001849 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1850 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001851 # TODO: This is untested.
1852 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001853 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001854
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001855 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1856 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001857 # TODO: This is untested.
1858 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001859
1860 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001861 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1862 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001863
1864 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001865 # TODO: This is untested.
1866 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001867
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001868 def get_reason(self):
1869 """
Alex Gaynor80262fb2016-04-22 07:53:42 -04001870 Get the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001871
Dan Sully44e767a2016-06-04 18:05:27 -07001872 :return: The reason, or ``None`` if there is none.
1873 :rtype: bytes or NoneType
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001874
1875 .. seealso::
1876
Dan Sully44e767a2016-06-04 18:05:27 -07001877 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001878 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001879 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001880 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1881 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001882 obj = _lib.X509_EXTENSION_get_object(ext)
1883 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001884 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001885
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001886 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001887 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001888 print_result = _lib.M_ASN1_OCTET_STRING_print(
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001889 bio, _lib.X509_EXTENSION_get_data(ext)
Alex Gaynor5945ea82015-09-05 14:59:06 -04001890 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001891 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001892 # TODO: This is untested.
1893 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001894
1895 return _bio_to_string(bio)
1896
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001897 def all_reasons(self):
1898 """
1899 Return a list of all the supported reason strings.
1900
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001901 This list is a copy; modifying it does not change the supported reason
1902 strings.
1903
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001904 :return: A list of reason strings.
Dan Sully44e767a2016-06-04 18:05:27 -07001905 :rtype: :class:`list` of :class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001906 """
1907 return self._crl_reasons[:]
1908
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001909 def set_rev_date(self, when):
1910 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001911 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001912
Dan Sully44e767a2016-06-04 18:05:27 -07001913 :param bytes when: The timestamp of the revocation,
1914 as ASN.1 GENERALIZEDTIME.
1915 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001916 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001917 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1918 return _set_asn1_time(dt, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001919
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001920 def get_rev_date(self):
1921 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001922 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001923
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001924 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
Dan Sully44e767a2016-06-04 18:05:27 -07001925 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001926 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001927 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1928 return _get_asn1_time(dt)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001929
1930
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001931class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001932 """
1933 A certificate revocation list.
1934 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001935
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001936 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001937 crl = _lib.X509_CRL_new()
1938 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001939
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001940 def get_revoked(self):
1941 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001942 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001943
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001944 These revocations will be provided by value, not by reference.
1945 That means it's okay to mutate them: it won't affect this CRL.
1946
1947 :return: The revocations in this CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07001948 :rtype: :class:`tuple` of :class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001949 """
1950 results = []
Alex Gaynor67903a62016-06-02 10:37:13 -07001951 revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001952 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1953 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Paul Kehrer2fe23b02016-03-09 22:02:15 -04001954 revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001955 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001956 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001957 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001958 if results:
1959 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001960
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001961 def add_revoked(self, revoked):
1962 """
1963 Add a revoked (by value not reference) to the CRL structure
1964
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001965 This revocation will be added by value, not by reference. That
1966 means it's okay to mutate it after adding: it won't affect
1967 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001968
Dan Sully44e767a2016-06-04 18:05:27 -07001969 :param Revoked revoked: The new revocation.
1970 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001971 """
Paul Kehrer8dddb1a2016-03-09 21:48:04 -04001972 copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001973 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001974 # TODO: This is untested.
1975 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001976
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001977 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001978 if add_result == 0:
1979 # TODO: This is untested.
1980 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001981
Dan Sully44e767a2016-06-04 18:05:27 -07001982 def get_issuer(self):
1983 """
1984 Get the CRL's issuer.
1985
1986 .. versionadded:: 16.1.0
1987
1988 :rtype: X509Name
1989 """
1990 _issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl))
1991 _openssl_assert(_issuer != _ffi.NULL)
1992 _issuer = _ffi.gc(_issuer, _lib.X509_NAME_free)
1993 issuer = X509Name.__new__(X509Name)
1994 issuer._name = _issuer
1995 return issuer
1996
1997 def set_version(self, version):
1998 """
1999 Set the CRL version.
2000
2001 .. versionadded:: 16.1.0
2002
2003 :param int version: The version of the CRL.
2004 :return: ``None``
2005 """
2006 _openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0)
2007
2008 def _set_boundary_time(self, which, when):
2009 return _set_asn1_time(which(self._crl), when)
2010
2011 def set_lastUpdate(self, when):
2012 """
2013 Set when the CRL was last updated.
2014
2015 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2016
2017 YYYYMMDDhhmmssZ
2018 YYYYMMDDhhmmss+hhmm
2019 YYYYMMDDhhmmss-hhmm
2020
2021 .. versionadded:: 16.1.0
2022
2023 :param bytes when: A timestamp string.
2024 :return: ``None``
2025 """
2026 return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when)
2027
2028 def set_nextUpdate(self, when):
2029 """
2030 Set when the CRL will next be udpated.
2031
2032 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2033
2034 YYYYMMDDhhmmssZ
2035 YYYYMMDDhhmmss+hhmm
2036 YYYYMMDDhhmmss-hhmm
2037
2038 .. versionadded:: 16.1.0
2039
2040 :param bytes when: A timestamp string.
2041 :return: ``None``
2042 """
2043 return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when)
2044
2045 def sign(self, issuer_cert, issuer_key, digest):
2046 """
2047 Sign the CRL.
2048
2049 Signing a CRL enables clients to associate the CRL itself with an
2050 issuer. Before a CRL is meaningful to other OpenSSL functions, it must
2051 be signed by an issuer.
2052
2053 This method implicitly sets the issuer's name based on the issuer
2054 certificate and private key used to sign the CRL.
2055
2056 .. versionadded:: 16.1.0
2057
2058 :param X509 issuer_cert: The issuer's certificate.
2059 :param PKey issuer_key: The issuer's private key.
2060 :param bytes digest: The digest method to sign the CRL with.
2061 """
2062 digest_obj = _lib.EVP_get_digestbyname(digest)
2063 _openssl_assert(digest_obj != _ffi.NULL)
2064 _lib.X509_CRL_set_issuer_name(
2065 self._crl, _lib.X509_get_subject_name(issuer_cert._x509))
2066 _lib.X509_CRL_sort(self._crl)
2067 result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj)
2068 _openssl_assert(result != 0)
2069
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002070 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002071 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002072 """
Dan Sully44e767a2016-06-04 18:05:27 -07002073 Export the CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002074
Dan Sully44e767a2016-06-04 18:05:27 -07002075 :param X509 cert: The certificate used to sign the CRL.
2076 :param PKey key: The key used to sign the CRL.
2077 :param int type: The export format, either :data:`FILETYPE_PEM`,
2078 :data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`.
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002079 :param int days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002080 :param bytes digest: The name of the message digest to use (eg
2081 ``b"sha1"``).
Dan Sully44e767a2016-06-04 18:05:27 -07002082 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002083 """
Dan Sully44e767a2016-06-04 18:05:27 -07002084
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002085 if not isinstance(cert, X509):
2086 raise TypeError("cert must be an X509 instance")
2087 if not isinstance(key, PKey):
2088 raise TypeError("key must be a PKey instance")
2089 if not isinstance(type, int):
2090 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002091
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002092 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002093 _warn(
2094 "The default message digest (md5) is deprecated. "
2095 "Pass the name of a message digest explicitly.",
2096 category=DeprecationWarning,
2097 stacklevel=2,
2098 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002099 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002100
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002101 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002102 if digest_obj == _ffi.NULL:
2103 raise ValueError("No such digest method")
2104
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002105 bio = _lib.BIO_new(_lib.BIO_s_mem())
2106 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002107 # TODO: This is untested.
2108 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002109
Alex Gaynora738ed52015-09-05 11:17:10 -04002110 # A scratch time object to give different values to different CRL
2111 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002112 sometime = _lib.ASN1_TIME_new()
2113 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002114 # TODO: This is untested.
2115 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002116
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002117 _lib.X509_gmtime_adj(sometime, 0)
2118 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002119
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002120 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2121 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002122
Alex Gaynor5945ea82015-09-05 14:59:06 -04002123 _lib.X509_CRL_set_issuer_name(
2124 self._crl, _lib.X509_get_subject_name(cert._x509)
2125 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002126
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002127 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002128 if not sign_result:
2129 _raise_current_error()
2130
Dominic Chenf05b2122015-10-13 16:32:35 +00002131 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002132
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002133
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002134CRLType = CRL
2135
2136
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002137class PKCS7(object):
2138 def type_is_signed(self):
2139 """
2140 Check if this NID_pkcs7_signed object
2141
2142 :return: True if the PKCS7 is of type signed
2143 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002144 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002145 return True
2146 return False
2147
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002148 def type_is_enveloped(self):
2149 """
2150 Check if this NID_pkcs7_enveloped object
2151
2152 :returns: True if the PKCS7 is of type enveloped
2153 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002154 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002155 return True
2156 return False
2157
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002158 def type_is_signedAndEnveloped(self):
2159 """
2160 Check if this NID_pkcs7_signedAndEnveloped object
2161
2162 :returns: True if the PKCS7 is of type signedAndEnveloped
2163 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002164 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002165 return True
2166 return False
2167
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002168 def type_is_data(self):
2169 """
2170 Check if this NID_pkcs7_data object
2171
2172 :return: True if the PKCS7 is of type data
2173 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002174 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002175 return True
2176 return False
2177
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002178 def get_type_name(self):
2179 """
2180 Returns the type name of the PKCS7 structure
2181
2182 :return: A string with the typename
2183 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002184 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2185 string_type = _lib.OBJ_nid2sn(nid)
2186 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002187
2188PKCS7Type = PKCS7
2189
2190
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002191class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002192 """
2193 A PKCS #12 archive.
2194 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002195
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002196 def __init__(self):
2197 self._pkey = None
2198 self._cert = None
2199 self._cacerts = None
2200 self._friendlyname = None
2201
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002202 def get_certificate(self):
2203 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002204 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002205
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002206 :return: The certificate, or :py:const:`None` if there is none.
2207 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002208 """
2209 return self._cert
2210
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002211 def set_certificate(self, cert):
2212 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002213 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002214
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002215 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002216 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002217
Dan Sully44e767a2016-06-04 18:05:27 -07002218 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002219 """
2220 if not isinstance(cert, X509):
2221 raise TypeError("cert must be an X509 instance")
2222 self._cert = cert
2223
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002224 def get_privatekey(self):
2225 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002226 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002227
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002228 :return: The private key, or :py:const:`None` if there is none.
2229 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002230 """
2231 return self._pkey
2232
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002233 def set_privatekey(self, pkey):
2234 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002235 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002236
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002237 :param pkey: The new private key, or :py:const:`None` to unset it.
2238 :type pkey: :py:class:`PKey` or :py:const:`None`
2239
Dan Sully44e767a2016-06-04 18:05:27 -07002240 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002241 """
2242 if not isinstance(pkey, PKey):
2243 raise TypeError("pkey must be a PKey instance")
2244 self._pkey = pkey
2245
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002246 def get_ca_certificates(self):
2247 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002248 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002249
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002250 :return: A tuple with the CA certificates in the chain, or
2251 :py:const:`None` if there are none.
2252 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002253 """
2254 if self._cacerts is not None:
2255 return tuple(self._cacerts)
2256
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002257 def set_ca_certificates(self, cacerts):
2258 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002259 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002260
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002261 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2262 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002263 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002264
Dan Sully44e767a2016-06-04 18:05:27 -07002265 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002266 """
2267 if cacerts is None:
2268 self._cacerts = None
2269 else:
2270 cacerts = list(cacerts)
2271 for cert in cacerts:
2272 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002273 raise TypeError(
2274 "iterable must only contain X509 instances"
2275 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002276 self._cacerts = cacerts
2277
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002278 def set_friendlyname(self, name):
2279 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002280 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002281
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002282 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002283 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002284
Dan Sully44e767a2016-06-04 18:05:27 -07002285 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002286 """
2287 if name is None:
2288 self._friendlyname = None
2289 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002290 raise TypeError(
2291 "name must be a byte string or None (not %r)" % (name,)
2292 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002293 self._friendlyname = name
2294
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002295 def get_friendlyname(self):
2296 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002297 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002298
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002299 :returns: The friendly name, or :py:const:`None` if there is none.
2300 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002301 """
2302 return self._friendlyname
2303
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002304 def export(self, passphrase=None, iter=2048, maciter=1):
2305 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002306 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002307
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002308 For more information, see the :c:func:`PKCS12_create` man page.
2309
2310 :param passphrase: The passphrase used to encrypt the structure. Unlike
2311 some other passphrase arguments, this *must* be a string, not a
2312 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002313 :type passphrase: :py:data:`bytes`
2314
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002315 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002316 :type iter: :py:data:`int`
2317
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002318 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002319 :type maciter: :py:data:`int`
2320
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002321 :return: The string representation of the PKCS #12 structure.
2322 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002323 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002324 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002325
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002326 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002327 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002328 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002329 cacerts = _lib.sk_X509_new_null()
2330 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002331 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002332 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002333
2334 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002335 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002336
2337 friendlyname = self._friendlyname
2338 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002339 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002340
2341 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002342 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002343 else:
2344 pkey = self._pkey._pkey
2345
2346 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002347 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002348 else:
2349 cert = self._cert._x509
2350
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002351 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002352 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002353 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2354 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002355 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002356 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002357 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002358 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002359
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002360 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002361 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002362 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002363
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002364
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002365PKCS12Type = PKCS12
2366
2367
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002368class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002369 """
2370 A Netscape SPKI object.
2371 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002372
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002373 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002374 spki = _lib.NETSCAPE_SPKI_new()
2375 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002376
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002377 def sign(self, pkey, digest):
2378 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002379 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002380
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002381 :param pkey: The private key to sign with.
2382 :type pkey: :py:class:`PKey`
2383
2384 :param digest: The message digest to use.
2385 :type digest: :py:class:`bytes`
2386
Dan Sully44e767a2016-06-04 18:05:27 -07002387 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002388 """
2389 if pkey._only_public:
2390 raise ValueError("Key has only public part")
2391
2392 if not pkey._initialized:
2393 raise ValueError("Key is uninitialized")
2394
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002395 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002396 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002397 raise ValueError("No such digest method")
2398
Alex Gaynor5945ea82015-09-05 14:59:06 -04002399 sign_result = _lib.NETSCAPE_SPKI_sign(
2400 self._spki, pkey._pkey, digest_obj
2401 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002402 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002403 # TODO: This is untested.
2404 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002405
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002406 def verify(self, key):
2407 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002408 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002409
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002410 :param key: The public key that signature is supposedly from.
2411 :type pkey: :py:class:`PKey`
2412
2413 :return: :py:const:`True` if the signature is correct.
2414 :rtype: :py:class:`bool`
2415
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002416 :raises Error: If the signature is invalid, or there was a problem
2417 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002418 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002419 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002420 if answer <= 0:
2421 _raise_current_error()
2422 return True
2423
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002424 def b64_encode(self):
2425 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002426 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002427
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002428 :return: The base64 encoded string.
2429 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002430 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002431 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2432 result = _ffi.string(encoded)
Paul Kehrer0dcacf72016-03-17 19:25:39 -04002433 _lib.OPENSSL_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002434 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002435
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002436 def get_pubkey(self):
2437 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002438 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002439
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002440 :return: The public key.
2441 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002442 """
2443 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002444 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2445 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002446 # TODO: This is untested.
2447 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002448 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002449 pkey._only_public = True
2450 return pkey
2451
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002452 def set_pubkey(self, pkey):
2453 """
2454 Set the public key of the certificate
2455
2456 :param pkey: The public key
Dan Sully44e767a2016-06-04 18:05:27 -07002457 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002458 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002459 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002460 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002461 # TODO: This is untested.
2462 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002463
2464
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002465NetscapeSPKIType = NetscapeSPKI
2466
2467
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002468class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002469 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002470 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002471 raise ValueError(
2472 "only FILETYPE_PEM key format supports encryption"
2473 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002474 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002475 self._more_args = more_args
2476 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002477 self._problems = []
2478
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002479 @property
2480 def callback(self):
2481 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002482 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002483 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002484 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002485 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002486 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002487 else:
2488 raise TypeError("Last argument must be string or callable")
2489
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002490 @property
2491 def callback_args(self):
2492 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002493 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002494 elif isinstance(self._passphrase, bytes):
2495 return self._passphrase
2496 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002497 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002498 else:
2499 raise TypeError("Last argument must be string or callable")
2500
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002501 def raise_if_problem(self, exceptionType=Error):
2502 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002503 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002504 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002505 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002506 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002507 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002508 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002509
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002510 def _read_passphrase(self, buf, size, rwflag, userdata):
2511 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002512 if self._more_args:
2513 result = self._passphrase(size, rwflag, userdata)
2514 else:
2515 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002516 if not isinstance(result, bytes):
2517 raise ValueError("String expected")
2518 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002519 if self._truncate:
2520 result = result[:size]
2521 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002522 raise ValueError(
2523 "passphrase returned by callback is too long"
2524 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002525 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002526 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002527 return len(result)
2528 except Exception as e:
2529 self._problems.append(e)
2530 return 0
2531
2532
Cory Benfield6492f7c2015-10-27 16:57:58 +09002533def load_publickey(type, buffer):
2534 """
Cory Benfield11c10192015-10-27 17:23:03 +09002535 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002536
Cory Benfield9c590b92015-10-28 14:55:05 +09002537 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002538 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002539 :param buffer: The buffer the key is stored in.
2540 :type buffer: A Python string object, either unicode or bytestring.
2541 :return: The PKey object.
2542 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002543 """
2544 if isinstance(buffer, _text_type):
2545 buffer = buffer.encode("ascii")
2546
2547 bio = _new_mem_buf(buffer)
2548
2549 if type == FILETYPE_PEM:
2550 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2551 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2552 elif type == FILETYPE_ASN1:
2553 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2554 else:
2555 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2556
2557 if evp_pkey == _ffi.NULL:
2558 _raise_current_error()
2559
2560 pkey = PKey.__new__(PKey)
2561 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Paul Kehrer32fc4e62016-06-03 15:21:44 -07002562 pkey._only_public = True
Cory Benfield6492f7c2015-10-27 16:57:58 +09002563 return pkey
2564
2565
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002566def load_privatekey(type, buffer, passphrase=None):
2567 """
2568 Load a private key from a buffer
2569
2570 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2571 :param buffer: The buffer the key is stored in
2572 :param passphrase: (optional) if encrypted PEM format, this can be
2573 either the passphrase to use, or a callback for
2574 providing the passphrase.
2575
2576 :return: The PKey object
2577 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002578 if isinstance(buffer, _text_type):
2579 buffer = buffer.encode("ascii")
2580
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002581 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002582
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002583 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002584 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002585 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2586 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002587 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002588 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002589 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002590 else:
2591 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2592
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002593 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002594 _raise_current_error()
2595
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002596 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002597 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002598 return pkey
2599
2600
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002601def dump_certificate_request(type, req):
2602 """
2603 Dump a certificate request to a buffer
2604
2605 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2606 :param req: The certificate request to dump
2607 :return: The buffer with the dumped certificate request in
2608 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002609 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002610
2611 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002612 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002613 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002614 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002615 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002616 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002617 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002618 raise ValueError(
2619 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2620 "FILETYPE_TEXT"
2621 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002622
2623 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002624 # TODO: This is untested.
2625 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002626
2627 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002628
2629
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002630def load_certificate_request(type, buffer):
2631 """
2632 Load a certificate request from a buffer
2633
2634 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2635 :param buffer: The buffer the certificate request is stored in
2636 :return: The X509Req object
2637 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002638 if isinstance(buffer, _text_type):
2639 buffer = buffer.encode("ascii")
2640
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002641 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002642
2643 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002644 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002645 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002646 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002647 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002648 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002649
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002650 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002651 # TODO: This is untested.
2652 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002653
2654 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002655 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002656 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002657
2658
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002659def sign(pkey, data, digest):
2660 """
2661 Sign data with a digest
2662
2663 :param pkey: Pkey to sign with
2664 :param data: data to be signed
2665 :param digest: message digest to use
2666 :return: signature
2667 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002668 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002669
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002670 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002671 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002672 raise ValueError("No such digest method")
2673
Alex Gaynor67903a62016-06-02 10:37:13 -07002674 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002675 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002676
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002677 _lib.EVP_SignInit(md_ctx, digest_obj)
2678 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002679
Colleen Murphye09399b2016-03-01 17:40:49 -08002680 pkey_length = (PKey.bits(pkey) + 7) // 8
2681 signature_buffer = _ffi.new("unsigned char[]", pkey_length)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002682 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002683 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002684 md_ctx, signature_buffer, signature_length, pkey._pkey)
2685
2686 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002687 # TODO: This is untested.
2688 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002689
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002690 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002691
2692
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002693def verify(cert, signature, data, digest):
2694 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002695 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002696
2697 :param cert: signing certificate (X509 object)
2698 :param signature: signature returned by sign function
2699 :param data: data to be verified
2700 :param digest: message digest to use
Dan Sully44e767a2016-06-04 18:05:27 -07002701 :return: ``None`` if the signature is correct, raise exception otherwise.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002702 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002703 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002704
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002705 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002706 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002707 raise ValueError("No such digest method")
2708
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002709 pkey = _lib.X509_get_pubkey(cert._x509)
2710 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002711 # TODO: This is untested.
2712 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002713 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002714
Alex Gaynor67903a62016-06-02 10:37:13 -07002715 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002716 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002717
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002718 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2719 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002720 verify_result = _lib.EVP_VerifyFinal(
2721 md_ctx, signature, len(signature), pkey
2722 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002723
2724 if verify_result != 1:
2725 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002726
2727
Dominic Chenf05b2122015-10-13 16:32:35 +00002728def dump_crl(type, crl):
2729 """
2730 Dump a certificate revocation list to a buffer.
2731
2732 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2733 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002734 :param CRL crl: The CRL to dump.
2735
Dominic Chenf05b2122015-10-13 16:32:35 +00002736 :return: The buffer with the CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07002737 :rtype: bytes
Dominic Chenf05b2122015-10-13 16:32:35 +00002738 """
2739 bio = _new_mem_buf()
2740
2741 if type == FILETYPE_PEM:
2742 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2743 elif type == FILETYPE_ASN1:
2744 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2745 elif type == FILETYPE_TEXT:
2746 ret = _lib.X509_CRL_print(bio, crl._crl)
2747 else:
2748 raise ValueError(
2749 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2750 "FILETYPE_TEXT")
2751
2752 assert ret == 1
2753 return _bio_to_string(bio)
2754
2755
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002756def load_crl(type, buffer):
2757 """
2758 Load a certificate revocation list from a buffer
2759
2760 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2761 :param buffer: The buffer the CRL is stored in
2762
2763 :return: The PKey object
2764 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002765 if isinstance(buffer, _text_type):
2766 buffer = buffer.encode("ascii")
2767
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002768 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002769
2770 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002771 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002772 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002773 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002774 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002775 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2776
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002777 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002778 _raise_current_error()
2779
2780 result = CRL.__new__(CRL)
2781 result._crl = crl
2782 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002783
2784
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002785def load_pkcs7_data(type, buffer):
2786 """
2787 Load pkcs7 data from a buffer
2788
2789 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2790 :param buffer: The buffer with the pkcs7 data.
2791 :return: The PKCS7 object
2792 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002793 if isinstance(buffer, _text_type):
2794 buffer = buffer.encode("ascii")
2795
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002796 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002797
2798 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002799 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002800 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002801 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002802 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002803 # TODO: This is untested.
2804 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002805 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2806
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002807 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002808 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002809
2810 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002811 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002812 return pypkcs7
2813
2814
Stephen Holsapple38482622014-04-05 20:29:34 -07002815def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002816 """
2817 Load a PKCS12 object from a buffer
2818
2819 :param buffer: The buffer the certificate is stored in
2820 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2821 :returns: The PKCS12 object
2822 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002823 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002824
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002825 if isinstance(buffer, _text_type):
2826 buffer = buffer.encode("ascii")
2827
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002828 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002829
Stephen Holsapple38482622014-04-05 20:29:34 -07002830 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2831 # password based encryption no password and a zero length password are two
2832 # different things, but OpenSSL implementation will try both to figure out
2833 # which one works.
2834 if not passphrase:
2835 passphrase = _ffi.NULL
2836
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002837 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2838 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002839 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002840 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002841
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002842 pkey = _ffi.new("EVP_PKEY**")
2843 cert = _ffi.new("X509**")
2844 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002845
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002846 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002847 if not parse_result:
2848 _raise_current_error()
2849
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002850 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002851
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002852 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2853 # queue for no particular reason. This error isn't interesting to anyone
2854 # outside this function. It's not even interesting to us. Get rid of it.
2855 try:
2856 _raise_current_error()
2857 except Error:
2858 pass
2859
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002860 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002861 pykey = None
2862 else:
2863 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002864 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002865
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002866 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002867 pycert = None
2868 friendlyname = None
2869 else:
2870 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002871 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002872
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002873 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002874 friendlyname_buffer = _lib.X509_alias_get0(
2875 cert[0], friendlyname_length
2876 )
2877 friendlyname = _ffi.buffer(
2878 friendlyname_buffer, friendlyname_length[0]
2879 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002880 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002881 friendlyname = None
2882
2883 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002884 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002885 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002886 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002887 pycacerts.append(pycacert)
2888 if not pycacerts:
2889 pycacerts = None
2890
2891 pkcs12 = PKCS12.__new__(PKCS12)
2892 pkcs12._pkey = pykey
2893 pkcs12._cert = pycert
2894 pkcs12._cacerts = pycacerts
2895 pkcs12._friendlyname = friendlyname
2896 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002897
2898
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002899# There are no direct unit tests for this initialization. It is tested
2900# indirectly since it is necessary for functions like dump_privatekey when
2901# using encryption.
2902#
2903# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2904# and some other similar tests may fail without this (though they may not if
2905# the Python runtime has already done some initialization of the underlying
2906# OpenSSL library (and is linked against the same one that cryptography is
2907# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002908_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002909
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002910# This is similar but exercised mainly by exception_from_error_queue. It calls
2911# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2912_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002913
2914
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002915# Set the default string mask to match OpenSSL upstream (since 2005) and
2916# RFC5280 recommendations.
2917_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')