blob: 173539351d35d20e30e4b75cb1ee6da7974719ee [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)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001283 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001284
1285 # The name is owned by the X509 structure. As long as the X509Name
1286 # Python object is alive, keep the X509 Python object alive.
1287 name._owner = self
1288
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001289 return name
1290
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001291 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001292 if not isinstance(name, X509Name):
1293 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001294 set_result = which(self._x509, name._name)
1295 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001296 # TODO: This is untested.
1297 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001298
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001299 def get_issuer(self):
1300 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001301 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001302
Cory Benfielde6bcce82015-12-09 08:40:03 +00001303 This creates a new :class:`X509Name` that wraps the underlying issuer
1304 name field on the certificate. Modifying it will modify the underlying
1305 certificate, and will have the effect of modifying any other
1306 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001307
1308 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001309 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001310 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001311 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001312
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001313 def set_issuer(self, issuer):
1314 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001315 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001316
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001317 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001318 :type issuer: :py:class:`X509Name`
1319
Dan Sully44e767a2016-06-04 18:05:27 -07001320 :return: ``None``
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001321 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001322 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001323
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001324 def get_subject(self):
1325 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001326 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001327
Cory Benfielde6bcce82015-12-09 08:40:03 +00001328 This creates a new :class:`X509Name` that wraps the underlying subject
1329 name field on the certificate. Modifying it will modify the underlying
1330 certificate, and will have the effect of modifying any other
1331 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001332
1333 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001334 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001335 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001336 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001337
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001338 def set_subject(self, subject):
1339 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001340 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001341
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001342 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001343 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001344
Dan Sully44e767a2016-06-04 18:05:27 -07001345 :return: ``None``
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001346 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001347 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001348
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001349 def get_extension_count(self):
1350 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001351 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001352
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001353 :return: The number of extensions.
1354 :rtype: :py:class:`int`
1355
1356 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001357 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001358 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001359
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001360 def add_extensions(self, extensions):
1361 """
1362 Add extensions to the certificate.
1363
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001364 :param extensions: The extensions to add.
1365 :type extensions: An iterable of :py:class:`X509Extension` objects.
Dan Sully44e767a2016-06-04 18:05:27 -07001366 :return: ``None``
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001367 """
1368 for ext in extensions:
1369 if not isinstance(ext, X509Extension):
1370 raise ValueError("One of the elements is not an X509Extension")
1371
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001372 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001373 if not add_result:
1374 _raise_current_error()
1375
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001376 def get_extension(self, index):
1377 """
1378 Get a specific extension of the certificate by index.
1379
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001380 Extensions on a certificate are kept in order. The index
1381 parameter selects which extension will be returned.
1382
1383 :param int index: The index of the extension to retrieve.
1384 :return: The extension at the specified index.
1385 :rtype: :py:class:`X509Extension`
1386 :raises IndexError: If the extension index was out of bounds.
1387
1388 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001389 """
1390 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001391 ext._extension = _lib.X509_get_ext(self._x509, index)
1392 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001393 raise IndexError("extension index out of bounds")
1394
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001395 extension = _lib.X509_EXTENSION_dup(ext._extension)
1396 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001397 return ext
1398
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001399
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001400X509Type = X509
1401
1402
Dan Sully44e767a2016-06-04 18:05:27 -07001403class X509StoreFlags(object):
1404 """
1405 Flags for X509 verification, used to change the behavior of
1406 :class:`X509Store`.
1407
1408 See `OpenSSL Verification Flags`_ for details.
1409
1410 .. _OpenSSL Verification Flags:
1411 https://www.openssl.org/docs/manmaster/crypto/X509_VERIFY_PARAM_set_flags.html
1412 """
1413 CRL_CHECK = _lib.X509_V_FLAG_CRL_CHECK
1414 CRL_CHECK_ALL = _lib.X509_V_FLAG_CRL_CHECK_ALL
1415 IGNORE_CRITICAL = _lib.X509_V_FLAG_IGNORE_CRITICAL
1416 X509_STRICT = _lib.X509_V_FLAG_X509_STRICT
1417 ALLOW_PROXY_CERTS = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS
1418 POLICY_CHECK = _lib.X509_V_FLAG_POLICY_CHECK
1419 EXPLICIT_POLICY = _lib.X509_V_FLAG_EXPLICIT_POLICY
1420 INHIBIT_MAP = _lib.X509_V_FLAG_INHIBIT_MAP
1421 NOTIFY_POLICY = _lib.X509_V_FLAG_NOTIFY_POLICY
1422 CHECK_SS_SIGNATURE = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE
1423 CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK
1424
1425
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001426class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001427 """
Dan Sully44e767a2016-06-04 18:05:27 -07001428 An X.509 store.
1429
1430 An X.509 store is used to describe a context in which to verify a
1431 certificate. A description of a context may include a set of certificates
1432 to trust, a set of certificate revocation lists, verification flags and
1433 more.
1434
1435 An X.509 store, being only a description, cannot be used by itself to
1436 verify a certificate. To carry out the actual verification process, see
1437 :class:`X509StoreContext`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001438 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001439
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001440 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001441 store = _lib.X509_STORE_new()
1442 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001443
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001444 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001445 """
Dan Sully44e767a2016-06-04 18:05:27 -07001446 Adds a trusted certificate to this store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001447
Dan Sully44e767a2016-06-04 18:05:27 -07001448 Adding a certificate with this method adds this certificate as a
1449 *trusted* certificate.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001450
1451 :param X509 cert: The certificate to add to this store.
Dan Sully44e767a2016-06-04 18:05:27 -07001452 :raises TypeError: If the certificate is not an :class:`X509`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001453 :raises Error: If OpenSSL was unhappy with your certificate.
Dan Sully44e767a2016-06-04 18:05:27 -07001454 :return: ``None`` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001455 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001456 if not isinstance(cert, X509):
1457 raise TypeError()
1458
Dan Sully44e767a2016-06-04 18:05:27 -07001459 _openssl_assert(_lib.X509_STORE_add_cert(self._store, cert._x509) != 0)
1460
1461 def add_crl(self, crl):
1462 """
1463 Add a certificate revocation list to this store.
1464
1465 The certificate revocation lists added to a store will only be used if
1466 the associated flags are configured to check certificate revocation
1467 lists.
1468
1469 .. versionadded:: 16.1.0
1470
1471 :param CRL crl: The certificate revocation list to add to this store.
1472 :return: ``None`` if the certificate revocation list was added
1473 successfully.
1474 """
1475 _openssl_assert(_lib.X509_STORE_add_crl(self._store, crl._crl) != 0)
1476
1477 def set_flags(self, flags):
1478 """
1479 Set verification flags to this store.
1480
1481 Verification flags can be combined by oring them together.
1482
1483 .. note::
1484
1485 Setting a verification flag sometimes requires clients to add
1486 additional information to the store, otherwise a suitable error will
1487 be raised.
1488
1489 For example, in setting flags to enable CRL checking a
1490 suitable CRL must be added to the store otherwise an error will be
1491 raised.
1492
1493 .. versionadded:: 16.1.0
1494
1495 :param int flags: The verification flags to set on this store.
1496 See :class:`X509StoreFlags` for available constants.
1497 :return: ``None`` if the verification flags were successfully set.
1498 """
1499 _openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0)
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001500
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001501
1502X509StoreType = X509Store
1503
1504
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001505class X509StoreContextError(Exception):
1506 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001507 An exception raised when an error occurred while verifying a certificate
1508 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001509
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001510 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001511 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001512 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001513
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001514 def __init__(self, message, certificate):
1515 super(X509StoreContextError, self).__init__(message)
1516 self.certificate = certificate
1517
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001518
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001519class X509StoreContext(object):
1520 """
1521 An X.509 store context.
1522
Dan Sully44e767a2016-06-04 18:05:27 -07001523 An X.509 store context is used to carry out the actual verification process
1524 of a certificate in a described context. For describing such a context, see
1525 :class:`X509Store`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001526
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001527 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1528 instance. It is dynamically allocated and automatically garbage
1529 collected.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001530 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001531 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001532 :param X509Store store: The certificates which will be trusted for the
1533 purposes of any verifications.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001534 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001535 """
1536
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001537 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001538 store_ctx = _lib.X509_STORE_CTX_new()
1539 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1540 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001541 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001542 # Make the store context available for use after instantiating this
1543 # class by initializing it now. Per testing, subsequent calls to
Dan Sully44e767a2016-06-04 18:05:27 -07001544 # :meth:`_init` have no adverse affect.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001545 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001546
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001547 def _init(self):
1548 """
1549 Set up the store context for a subsequent verification operation.
1550 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001551 ret = _lib.X509_STORE_CTX_init(
1552 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1553 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001554 if ret <= 0:
1555 _raise_current_error()
1556
1557 def _cleanup(self):
1558 """
1559 Internally cleans up the store context.
1560
Dan Sully44e767a2016-06-04 18:05:27 -07001561 The store context can then be reused with a new call to :meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001562 """
1563 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1564
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001565 def _exception_from_context(self):
1566 """
1567 Convert an OpenSSL native context error failure into a Python
1568 exception.
1569
Alex Gaynor5945ea82015-09-05 14:59:06 -04001570 When a call to native OpenSSL X509_verify_cert fails, additional
1571 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001572 """
1573 errors = [
1574 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1575 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1576 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001577 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001578 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001579 # A context error should always be associated with a certificate, so we
1580 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001581 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001582 _cert = _lib.X509_dup(_x509)
1583 pycert = X509.__new__(X509)
1584 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001585 return X509StoreContextError(errors, pycert)
1586
Stephen Holsapple46a09252015-02-12 14:45:43 -08001587 def set_store(self, store):
1588 """
Dan Sully44e767a2016-06-04 18:05:27 -07001589 Set the context's X.509 store.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001590
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001591 .. versionadded:: 0.15
1592
Dan Sully44e767a2016-06-04 18:05:27 -07001593 :param X509Store store: The store description which will be used for
1594 the purposes of any *future* verifications.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001595 """
1596 self._store = store
1597
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001598 def verify_certificate(self):
1599 """
1600 Verify a certificate in a context.
1601
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001602 .. versionadded:: 0.15
1603
Alex Gaynorca87ff62015-09-04 23:31:03 -04001604 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001605 certificate in the context. Sets ``certificate`` attribute to
1606 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001607 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001608 # Always re-initialize the store context in case
Dan Sully44e767a2016-06-04 18:05:27 -07001609 # :meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001610 self._init()
1611 ret = _lib.X509_verify_cert(self._store_ctx)
1612 self._cleanup()
1613 if ret <= 0:
1614 raise self._exception_from_context()
1615
1616
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001617def load_certificate(type, buffer):
1618 """
1619 Load a certificate from a buffer
1620
1621 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1622
Dan Sully44e767a2016-06-04 18:05:27 -07001623 :param bytes buffer: The buffer the certificate is stored in
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001624
1625 :return: The X509 object
1626 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001627 if isinstance(buffer, _text_type):
1628 buffer = buffer.encode("ascii")
1629
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001630 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001631
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001632 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001633 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001634 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001635 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001636 else:
1637 raise ValueError(
1638 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001639
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001640 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001641 _raise_current_error()
1642
1643 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001644 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001645 return cert
1646
1647
1648def dump_certificate(type, cert):
1649 """
1650 Dump a certificate to a buffer
1651
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001652 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1653 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001654 :param cert: The certificate to dump
1655 :return: The buffer with the dumped certificate in
1656 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001657 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001658
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001659 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001660 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001661 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001662 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001663 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001664 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001665 else:
1666 raise ValueError(
1667 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1668 "FILETYPE_TEXT")
1669
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001670 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001671 return _bio_to_string(bio)
1672
1673
Cory Benfield6492f7c2015-10-27 16:57:58 +09001674def dump_publickey(type, pkey):
1675 """
Cory Benfield11c10192015-10-27 17:23:03 +09001676 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001677
Cory Benfield9c590b92015-10-28 14:55:05 +09001678 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001679 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001680 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001681 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001682 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001683 """
1684 bio = _new_mem_buf()
1685 if type == FILETYPE_PEM:
1686 write_bio = _lib.PEM_write_bio_PUBKEY
1687 elif type == FILETYPE_ASN1:
1688 write_bio = _lib.i2d_PUBKEY_bio
1689 else:
1690 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1691
1692 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001693 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001694 _raise_current_error()
1695
1696 return _bio_to_string(bio)
1697
1698
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001699def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1700 """
1701 Dump a private key to a buffer
1702
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001703 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1704 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001705 :param pkey: The PKey to dump
1706 :param cipher: (optional) if encrypted PEM format, the cipher to
1707 use
1708 :param passphrase: (optional) if encrypted PEM format, this can be either
1709 the passphrase to use, or a callback for providing the
1710 passphrase.
1711 :return: The buffer with the dumped key in
Dan Sully44e767a2016-06-04 18:05:27 -07001712 :rtype: bytes
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001713 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001714 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001715
1716 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001717 if passphrase is None:
1718 raise TypeError(
1719 "if a value is given for cipher "
1720 "one must also be given for passphrase")
1721 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001722 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001723 raise ValueError("Invalid cipher name")
1724 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001725 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001726
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001727 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001728 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001729 result_code = _lib.PEM_write_bio_PrivateKey(
1730 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001731 helper.callback, helper.callback_args)
1732 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001733 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001734 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001735 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001736 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1737 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001738 # TODO RSA_free(rsa)?
1739 else:
1740 raise ValueError(
1741 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1742 "FILETYPE_TEXT")
1743
1744 if result_code == 0:
1745 _raise_current_error()
1746
1747 return _bio_to_string(bio)
1748
1749
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001750class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001751 """
1752 A certificate revocation.
1753 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001754 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1755 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1756 # OCSP_crl_reason_str. We use the latter, just like the command line
1757 # program.
1758 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001759 b"unspecified",
1760 b"keyCompromise",
1761 b"CACompromise",
1762 b"affiliationChanged",
1763 b"superseded",
1764 b"cessationOfOperation",
1765 b"certificateHold",
1766 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001767 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001768
1769 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001770 revoked = _lib.X509_REVOKED_new()
1771 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001772
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001773 def set_serial(self, hex_str):
1774 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001775 Set the serial number.
1776
1777 The serial number is formatted as a hexadecimal number encoded in
1778 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001779
Dan Sully44e767a2016-06-04 18:05:27 -07001780 :param bytes hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001781
Dan Sully44e767a2016-06-04 18:05:27 -07001782 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001783 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001784 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1785 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001786 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001787 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001788 if not bn_result:
1789 raise ValueError("bad hex string")
1790
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001791 asn1_serial = _ffi.gc(
1792 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1793 _lib.ASN1_INTEGER_free)
1794 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001795
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001796 def get_serial(self):
1797 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001798 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001799
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001800 The serial number is formatted as a hexadecimal number encoded in
1801 ASCII.
1802
1803 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001804 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001805 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001806 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807
Alex Gaynor67903a62016-06-02 10:37:13 -07001808 asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked)
1809 _openssl_assert(asn1_int != _ffi.NULL)
1810 result = _lib.i2a_ASN1_INTEGER(bio, asn1_int)
1811 _openssl_assert(result >= 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001812 return _bio_to_string(bio)
1813
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001814 def _delete_reason(self):
Alex Gaynor67903a62016-06-02 10:37:13 -07001815 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1816 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001817 obj = _lib.X509_EXTENSION_get_object(ext)
1818 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001819 _lib.X509_EXTENSION_free(ext)
Alex Gaynor67903a62016-06-02 10:37:13 -07001820 _lib.X509_REVOKED_delete_ext(self._revoked, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001821 break
1822
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001823 def set_reason(self, reason):
1824 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001825 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001826
Dan Sully44e767a2016-06-04 18:05:27 -07001827 If :data:`reason` is ``None``, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001828
1829 :param reason: The reason string.
Dan Sully44e767a2016-06-04 18:05:27 -07001830 :type reason: :class:`bytes` or :class:`NoneType`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001831
Dan Sully44e767a2016-06-04 18:05:27 -07001832 :return: ``None``
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001833
1834 .. seealso::
1835
Dan Sully44e767a2016-06-04 18:05:27 -07001836 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001837 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001838 """
1839 if reason is None:
1840 self._delete_reason()
1841 elif not isinstance(reason, bytes):
1842 raise TypeError("reason must be None or a byte string")
1843 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001844 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001845 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1846
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001847 new_reason_ext = _lib.ASN1_ENUMERATED_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07001848 _openssl_assert(new_reason_ext != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001849 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001850
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001851 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001852 _openssl_assert(set_result != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001853
1854 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001855 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1856 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001857
1858 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001859 # TODO: This is untested.
1860 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001861
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001862 def get_reason(self):
1863 """
Alex Gaynor80262fb2016-04-22 07:53:42 -04001864 Get the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001865
Dan Sully44e767a2016-06-04 18:05:27 -07001866 :return: The reason, or ``None`` if there is none.
1867 :rtype: bytes or NoneType
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001868
1869 .. seealso::
1870
Dan Sully44e767a2016-06-04 18:05:27 -07001871 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001872 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001873 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001874 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1875 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001876 obj = _lib.X509_EXTENSION_get_object(ext)
1877 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001878 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001879
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001880 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001881 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001882 print_result = _lib.M_ASN1_OCTET_STRING_print(
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001883 bio, _lib.X509_EXTENSION_get_data(ext)
Alex Gaynor5945ea82015-09-05 14:59:06 -04001884 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001885 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001886 # TODO: This is untested.
1887 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001888
1889 return _bio_to_string(bio)
1890
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001891 def all_reasons(self):
1892 """
1893 Return a list of all the supported reason strings.
1894
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001895 This list is a copy; modifying it does not change the supported reason
1896 strings.
1897
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001898 :return: A list of reason strings.
Dan Sully44e767a2016-06-04 18:05:27 -07001899 :rtype: :class:`list` of :class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001900 """
1901 return self._crl_reasons[:]
1902
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001903 def set_rev_date(self, when):
1904 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001905 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001906
Dan Sully44e767a2016-06-04 18:05:27 -07001907 :param bytes when: The timestamp of the revocation,
1908 as ASN.1 GENERALIZEDTIME.
1909 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001910 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001911 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1912 return _set_asn1_time(dt, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001913
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001914 def get_rev_date(self):
1915 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001916 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001917
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001918 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
Dan Sully44e767a2016-06-04 18:05:27 -07001919 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001920 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001921 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1922 return _get_asn1_time(dt)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001923
1924
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001925class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001926 """
1927 A certificate revocation list.
1928 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001929
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001930 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001931 crl = _lib.X509_CRL_new()
1932 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001933
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001934 def get_revoked(self):
1935 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001936 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001937
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001938 These revocations will be provided by value, not by reference.
1939 That means it's okay to mutate them: it won't affect this CRL.
1940
1941 :return: The revocations in this CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07001942 :rtype: :class:`tuple` of :class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001943 """
1944 results = []
Alex Gaynor67903a62016-06-02 10:37:13 -07001945 revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001946 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1947 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Paul Kehrer2fe23b02016-03-09 22:02:15 -04001948 revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001949 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001950 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001951 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001952 if results:
1953 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001954
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001955 def add_revoked(self, revoked):
1956 """
1957 Add a revoked (by value not reference) to the CRL structure
1958
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001959 This revocation will be added by value, not by reference. That
1960 means it's okay to mutate it after adding: it won't affect
1961 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001962
Dan Sully44e767a2016-06-04 18:05:27 -07001963 :param Revoked revoked: The new revocation.
1964 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001965 """
Paul Kehrer8dddb1a2016-03-09 21:48:04 -04001966 copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001967 _openssl_assert(copy != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001968
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001969 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001970 if add_result == 0:
1971 # TODO: This is untested.
1972 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001973
Dan Sully44e767a2016-06-04 18:05:27 -07001974 def get_issuer(self):
1975 """
1976 Get the CRL's issuer.
1977
1978 .. versionadded:: 16.1.0
1979
1980 :rtype: X509Name
1981 """
1982 _issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl))
1983 _openssl_assert(_issuer != _ffi.NULL)
1984 _issuer = _ffi.gc(_issuer, _lib.X509_NAME_free)
1985 issuer = X509Name.__new__(X509Name)
1986 issuer._name = _issuer
1987 return issuer
1988
1989 def set_version(self, version):
1990 """
1991 Set the CRL version.
1992
1993 .. versionadded:: 16.1.0
1994
1995 :param int version: The version of the CRL.
1996 :return: ``None``
1997 """
1998 _openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0)
1999
2000 def _set_boundary_time(self, which, when):
2001 return _set_asn1_time(which(self._crl), when)
2002
2003 def set_lastUpdate(self, when):
2004 """
2005 Set when the CRL was last updated.
2006
2007 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2008
2009 YYYYMMDDhhmmssZ
2010 YYYYMMDDhhmmss+hhmm
2011 YYYYMMDDhhmmss-hhmm
2012
2013 .. versionadded:: 16.1.0
2014
2015 :param bytes when: A timestamp string.
2016 :return: ``None``
2017 """
2018 return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when)
2019
2020 def set_nextUpdate(self, when):
2021 """
2022 Set when the CRL will next be udpated.
2023
2024 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2025
2026 YYYYMMDDhhmmssZ
2027 YYYYMMDDhhmmss+hhmm
2028 YYYYMMDDhhmmss-hhmm
2029
2030 .. versionadded:: 16.1.0
2031
2032 :param bytes when: A timestamp string.
2033 :return: ``None``
2034 """
2035 return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when)
2036
2037 def sign(self, issuer_cert, issuer_key, digest):
2038 """
2039 Sign the CRL.
2040
2041 Signing a CRL enables clients to associate the CRL itself with an
2042 issuer. Before a CRL is meaningful to other OpenSSL functions, it must
2043 be signed by an issuer.
2044
2045 This method implicitly sets the issuer's name based on the issuer
2046 certificate and private key used to sign the CRL.
2047
2048 .. versionadded:: 16.1.0
2049
2050 :param X509 issuer_cert: The issuer's certificate.
2051 :param PKey issuer_key: The issuer's private key.
2052 :param bytes digest: The digest method to sign the CRL with.
2053 """
2054 digest_obj = _lib.EVP_get_digestbyname(digest)
2055 _openssl_assert(digest_obj != _ffi.NULL)
2056 _lib.X509_CRL_set_issuer_name(
2057 self._crl, _lib.X509_get_subject_name(issuer_cert._x509))
2058 _lib.X509_CRL_sort(self._crl)
2059 result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj)
2060 _openssl_assert(result != 0)
2061
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002062 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002063 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002064 """
Dan Sully44e767a2016-06-04 18:05:27 -07002065 Export the CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002066
Dan Sully44e767a2016-06-04 18:05:27 -07002067 :param X509 cert: The certificate used to sign the CRL.
2068 :param PKey key: The key used to sign the CRL.
2069 :param int type: The export format, either :data:`FILETYPE_PEM`,
2070 :data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`.
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002071 :param int days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002072 :param bytes digest: The name of the message digest to use (eg
2073 ``b"sha1"``).
Dan Sully44e767a2016-06-04 18:05:27 -07002074 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002075 """
Dan Sully44e767a2016-06-04 18:05:27 -07002076
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002077 if not isinstance(cert, X509):
2078 raise TypeError("cert must be an X509 instance")
2079 if not isinstance(key, PKey):
2080 raise TypeError("key must be a PKey instance")
2081 if not isinstance(type, int):
2082 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002083
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002084 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002085 _warn(
2086 "The default message digest (md5) is deprecated. "
2087 "Pass the name of a message digest explicitly.",
2088 category=DeprecationWarning,
2089 stacklevel=2,
2090 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002091 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002092
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002093 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002094 if digest_obj == _ffi.NULL:
2095 raise ValueError("No such digest method")
2096
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002097 bio = _lib.BIO_new(_lib.BIO_s_mem())
Alex Gaynoradd5b072016-06-04 21:04:00 -07002098 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002099
Alex Gaynora738ed52015-09-05 11:17:10 -04002100 # A scratch time object to give different values to different CRL
2101 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002102 sometime = _lib.ASN1_TIME_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07002103 _openssl_assert(sometime != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002104
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002105 _lib.X509_gmtime_adj(sometime, 0)
2106 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002107
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002108 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2109 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002110
Alex Gaynor5945ea82015-09-05 14:59:06 -04002111 _lib.X509_CRL_set_issuer_name(
2112 self._crl, _lib.X509_get_subject_name(cert._x509)
2113 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002114
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002115 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002116 if not sign_result:
2117 _raise_current_error()
2118
Dominic Chenf05b2122015-10-13 16:32:35 +00002119 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002120
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002121
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002122CRLType = CRL
2123
2124
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002125class PKCS7(object):
2126 def type_is_signed(self):
2127 """
2128 Check if this NID_pkcs7_signed object
2129
2130 :return: True if the PKCS7 is of type signed
2131 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002132 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002133 return True
2134 return False
2135
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002136 def type_is_enveloped(self):
2137 """
2138 Check if this NID_pkcs7_enveloped object
2139
2140 :returns: True if the PKCS7 is of type enveloped
2141 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002142 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002143 return True
2144 return False
2145
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002146 def type_is_signedAndEnveloped(self):
2147 """
2148 Check if this NID_pkcs7_signedAndEnveloped object
2149
2150 :returns: True if the PKCS7 is of type signedAndEnveloped
2151 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002152 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002153 return True
2154 return False
2155
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002156 def type_is_data(self):
2157 """
2158 Check if this NID_pkcs7_data object
2159
2160 :return: True if the PKCS7 is of type data
2161 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002162 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002163 return True
2164 return False
2165
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002166 def get_type_name(self):
2167 """
2168 Returns the type name of the PKCS7 structure
2169
2170 :return: A string with the typename
2171 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002172 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2173 string_type = _lib.OBJ_nid2sn(nid)
2174 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002175
2176PKCS7Type = PKCS7
2177
2178
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002179class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002180 """
2181 A PKCS #12 archive.
2182 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002183
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002184 def __init__(self):
2185 self._pkey = None
2186 self._cert = None
2187 self._cacerts = None
2188 self._friendlyname = None
2189
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002190 def get_certificate(self):
2191 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002192 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002193
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002194 :return: The certificate, or :py:const:`None` if there is none.
2195 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002196 """
2197 return self._cert
2198
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002199 def set_certificate(self, cert):
2200 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002201 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002202
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002203 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002204 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002205
Dan Sully44e767a2016-06-04 18:05:27 -07002206 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002207 """
2208 if not isinstance(cert, X509):
2209 raise TypeError("cert must be an X509 instance")
2210 self._cert = cert
2211
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002212 def get_privatekey(self):
2213 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002214 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002215
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002216 :return: The private key, or :py:const:`None` if there is none.
2217 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002218 """
2219 return self._pkey
2220
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002221 def set_privatekey(self, pkey):
2222 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002223 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002224
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002225 :param pkey: The new private key, or :py:const:`None` to unset it.
2226 :type pkey: :py:class:`PKey` or :py:const:`None`
2227
Dan Sully44e767a2016-06-04 18:05:27 -07002228 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002229 """
2230 if not isinstance(pkey, PKey):
2231 raise TypeError("pkey must be a PKey instance")
2232 self._pkey = pkey
2233
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002234 def get_ca_certificates(self):
2235 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002236 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002237
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002238 :return: A tuple with the CA certificates in the chain, or
2239 :py:const:`None` if there are none.
2240 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002241 """
2242 if self._cacerts is not None:
2243 return tuple(self._cacerts)
2244
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002245 def set_ca_certificates(self, cacerts):
2246 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002247 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002248
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002249 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2250 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002251 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002252
Dan Sully44e767a2016-06-04 18:05:27 -07002253 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002254 """
2255 if cacerts is None:
2256 self._cacerts = None
2257 else:
2258 cacerts = list(cacerts)
2259 for cert in cacerts:
2260 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002261 raise TypeError(
2262 "iterable must only contain X509 instances"
2263 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002264 self._cacerts = cacerts
2265
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002266 def set_friendlyname(self, name):
2267 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002268 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002269
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002270 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002271 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002272
Dan Sully44e767a2016-06-04 18:05:27 -07002273 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002274 """
2275 if name is None:
2276 self._friendlyname = None
2277 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002278 raise TypeError(
2279 "name must be a byte string or None (not %r)" % (name,)
2280 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002281 self._friendlyname = name
2282
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002283 def get_friendlyname(self):
2284 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002285 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002286
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002287 :returns: The friendly name, or :py:const:`None` if there is none.
2288 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002289 """
2290 return self._friendlyname
2291
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002292 def export(self, passphrase=None, iter=2048, maciter=1):
2293 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002294 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002295
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002296 For more information, see the :c:func:`PKCS12_create` man page.
2297
2298 :param passphrase: The passphrase used to encrypt the structure. Unlike
2299 some other passphrase arguments, this *must* be a string, not a
2300 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002301 :type passphrase: :py:data:`bytes`
2302
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002303 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002304 :type iter: :py:data:`int`
2305
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002306 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002307 :type maciter: :py:data:`int`
2308
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002309 :return: The string representation of the PKCS #12 structure.
2310 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002311 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002312 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002313
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002314 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002315 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002316 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002317 cacerts = _lib.sk_X509_new_null()
2318 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002319 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002320 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002321
2322 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002323 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002324
2325 friendlyname = self._friendlyname
2326 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002327 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002328
2329 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002330 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002331 else:
2332 pkey = self._pkey._pkey
2333
2334 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002335 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002336 else:
2337 cert = self._cert._x509
2338
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002339 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002340 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002341 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2342 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002343 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002344 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002345 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002346 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002347
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002348 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002349 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002350 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002351
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002352
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002353PKCS12Type = PKCS12
2354
2355
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002356class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002357 """
2358 A Netscape SPKI object.
2359 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002360
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002361 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002362 spki = _lib.NETSCAPE_SPKI_new()
2363 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002364
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002365 def sign(self, pkey, digest):
2366 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002367 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002368
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002369 :param pkey: The private key to sign with.
2370 :type pkey: :py:class:`PKey`
2371
2372 :param digest: The message digest to use.
2373 :type digest: :py:class:`bytes`
2374
Dan Sully44e767a2016-06-04 18:05:27 -07002375 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002376 """
2377 if pkey._only_public:
2378 raise ValueError("Key has only public part")
2379
2380 if not pkey._initialized:
2381 raise ValueError("Key is uninitialized")
2382
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002383 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002384 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002385 raise ValueError("No such digest method")
2386
Alex Gaynor5945ea82015-09-05 14:59:06 -04002387 sign_result = _lib.NETSCAPE_SPKI_sign(
2388 self._spki, pkey._pkey, digest_obj
2389 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002390 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002391 # TODO: This is untested.
2392 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002393
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002394 def verify(self, key):
2395 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002396 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002397
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002398 :param key: The public key that signature is supposedly from.
2399 :type pkey: :py:class:`PKey`
2400
2401 :return: :py:const:`True` if the signature is correct.
2402 :rtype: :py:class:`bool`
2403
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002404 :raises Error: If the signature is invalid, or there was a problem
2405 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002406 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002407 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002408 if answer <= 0:
2409 _raise_current_error()
2410 return True
2411
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002412 def b64_encode(self):
2413 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002414 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002415
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002416 :return: The base64 encoded string.
2417 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002418 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002419 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2420 result = _ffi.string(encoded)
Paul Kehrer0dcacf72016-03-17 19:25:39 -04002421 _lib.OPENSSL_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002422 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002423
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002424 def get_pubkey(self):
2425 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002426 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002427
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002428 :return: The public key.
2429 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002430 """
2431 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002432 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002433 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002434 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002435 pkey._only_public = True
2436 return pkey
2437
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002438 def set_pubkey(self, pkey):
2439 """
2440 Set the public key of the certificate
2441
2442 :param pkey: The public key
Dan Sully44e767a2016-06-04 18:05:27 -07002443 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002444 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002445 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002446 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002447 # TODO: This is untested.
2448 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002449
2450
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002451NetscapeSPKIType = NetscapeSPKI
2452
2453
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002454class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002455 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002456 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002457 raise ValueError(
2458 "only FILETYPE_PEM key format supports encryption"
2459 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002460 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002461 self._more_args = more_args
2462 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002463 self._problems = []
2464
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002465 @property
2466 def callback(self):
2467 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002468 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002469 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002470 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002471 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002472 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002473 else:
2474 raise TypeError("Last argument must be string or callable")
2475
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002476 @property
2477 def callback_args(self):
2478 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002479 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002480 elif isinstance(self._passphrase, bytes):
2481 return self._passphrase
2482 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002483 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002484 else:
2485 raise TypeError("Last argument must be string or callable")
2486
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002487 def raise_if_problem(self, exceptionType=Error):
2488 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002489 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002490 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002491 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002492 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002493 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002494 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002495
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002496 def _read_passphrase(self, buf, size, rwflag, userdata):
2497 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002498 if self._more_args:
2499 result = self._passphrase(size, rwflag, userdata)
2500 else:
2501 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002502 if not isinstance(result, bytes):
2503 raise ValueError("String expected")
2504 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002505 if self._truncate:
2506 result = result[:size]
2507 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002508 raise ValueError(
2509 "passphrase returned by callback is too long"
2510 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002511 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002512 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002513 return len(result)
2514 except Exception as e:
2515 self._problems.append(e)
2516 return 0
2517
2518
Cory Benfield6492f7c2015-10-27 16:57:58 +09002519def load_publickey(type, buffer):
2520 """
Cory Benfield11c10192015-10-27 17:23:03 +09002521 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002522
Cory Benfield9c590b92015-10-28 14:55:05 +09002523 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002524 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002525 :param buffer: The buffer the key is stored in.
2526 :type buffer: A Python string object, either unicode or bytestring.
2527 :return: The PKey object.
2528 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002529 """
2530 if isinstance(buffer, _text_type):
2531 buffer = buffer.encode("ascii")
2532
2533 bio = _new_mem_buf(buffer)
2534
2535 if type == FILETYPE_PEM:
2536 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2537 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2538 elif type == FILETYPE_ASN1:
2539 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2540 else:
2541 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2542
2543 if evp_pkey == _ffi.NULL:
2544 _raise_current_error()
2545
2546 pkey = PKey.__new__(PKey)
2547 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Paul Kehrer32fc4e62016-06-03 15:21:44 -07002548 pkey._only_public = True
Cory Benfield6492f7c2015-10-27 16:57:58 +09002549 return pkey
2550
2551
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002552def load_privatekey(type, buffer, passphrase=None):
2553 """
2554 Load a private key from a buffer
2555
2556 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2557 :param buffer: The buffer the key is stored in
2558 :param passphrase: (optional) if encrypted PEM format, this can be
2559 either the passphrase to use, or a callback for
2560 providing the passphrase.
2561
2562 :return: The PKey object
2563 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002564 if isinstance(buffer, _text_type):
2565 buffer = buffer.encode("ascii")
2566
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002567 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002568
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002569 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002570 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002571 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2572 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002573 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002574 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002575 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002576 else:
2577 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2578
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002579 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002580 _raise_current_error()
2581
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002582 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002583 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002584 return pkey
2585
2586
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002587def dump_certificate_request(type, req):
2588 """
2589 Dump a certificate request to a buffer
2590
2591 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2592 :param req: The certificate request to dump
2593 :return: The buffer with the dumped certificate request in
2594 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002595 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002596
2597 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002598 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002599 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002600 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002601 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002602 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002603 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002604 raise ValueError(
2605 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2606 "FILETYPE_TEXT"
2607 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002608
2609 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002610 # TODO: This is untested.
2611 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002612
2613 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002614
2615
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002616def load_certificate_request(type, buffer):
2617 """
2618 Load a certificate request from a buffer
2619
2620 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2621 :param buffer: The buffer the certificate request is stored in
2622 :return: The X509Req object
2623 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002624 if isinstance(buffer, _text_type):
2625 buffer = buffer.encode("ascii")
2626
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002627 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002628
2629 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002630 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002631 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002632 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002633 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002634 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002635
Alex Gaynoradd5b072016-06-04 21:04:00 -07002636 _openssl_assert(req != _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002637
2638 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002639 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002640 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002641
2642
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002643def sign(pkey, data, digest):
2644 """
2645 Sign data with a digest
2646
2647 :param pkey: Pkey to sign with
2648 :param data: data to be signed
2649 :param digest: message digest to use
2650 :return: signature
2651 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002652 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002653
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002654 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002655 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002656 raise ValueError("No such digest method")
2657
Alex Gaynor67903a62016-06-02 10:37:13 -07002658 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002659 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002660
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002661 _lib.EVP_SignInit(md_ctx, digest_obj)
2662 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002663
Colleen Murphye09399b2016-03-01 17:40:49 -08002664 pkey_length = (PKey.bits(pkey) + 7) // 8
2665 signature_buffer = _ffi.new("unsigned char[]", pkey_length)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002666 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002667 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002668 md_ctx, signature_buffer, signature_length, pkey._pkey)
2669
2670 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002671 # TODO: This is untested.
2672 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002673
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002674 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002675
2676
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002677def verify(cert, signature, data, digest):
2678 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002679 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002680
2681 :param cert: signing certificate (X509 object)
2682 :param signature: signature returned by sign function
2683 :param data: data to be verified
2684 :param digest: message digest to use
Dan Sully44e767a2016-06-04 18:05:27 -07002685 :return: ``None`` if the signature is correct, raise exception otherwise.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002686 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002687 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002688
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002689 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002690 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002691 raise ValueError("No such digest method")
2692
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002693 pkey = _lib.X509_get_pubkey(cert._x509)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002694 _openssl_assert(pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002695 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002696
Alex Gaynor67903a62016-06-02 10:37:13 -07002697 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002698 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002699
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002700 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2701 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002702 verify_result = _lib.EVP_VerifyFinal(
2703 md_ctx, signature, len(signature), pkey
2704 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002705
2706 if verify_result != 1:
2707 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002708
2709
Dominic Chenf05b2122015-10-13 16:32:35 +00002710def dump_crl(type, crl):
2711 """
2712 Dump a certificate revocation list to a buffer.
2713
2714 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2715 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002716 :param CRL crl: The CRL to dump.
2717
Dominic Chenf05b2122015-10-13 16:32:35 +00002718 :return: The buffer with the CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07002719 :rtype: bytes
Dominic Chenf05b2122015-10-13 16:32:35 +00002720 """
2721 bio = _new_mem_buf()
2722
2723 if type == FILETYPE_PEM:
2724 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2725 elif type == FILETYPE_ASN1:
2726 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2727 elif type == FILETYPE_TEXT:
2728 ret = _lib.X509_CRL_print(bio, crl._crl)
2729 else:
2730 raise ValueError(
2731 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2732 "FILETYPE_TEXT")
2733
2734 assert ret == 1
2735 return _bio_to_string(bio)
2736
2737
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002738def load_crl(type, buffer):
2739 """
2740 Load a certificate revocation list from a buffer
2741
2742 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2743 :param buffer: The buffer the CRL is stored in
2744
2745 :return: The PKey object
2746 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002747 if isinstance(buffer, _text_type):
2748 buffer = buffer.encode("ascii")
2749
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002750 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002751
2752 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002753 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002754 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002755 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002756 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002757 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2758
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002759 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002760 _raise_current_error()
2761
2762 result = CRL.__new__(CRL)
2763 result._crl = crl
2764 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002765
2766
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002767def load_pkcs7_data(type, buffer):
2768 """
2769 Load pkcs7 data from a buffer
2770
2771 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2772 :param buffer: The buffer with the pkcs7 data.
2773 :return: The PKCS7 object
2774 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002775 if isinstance(buffer, _text_type):
2776 buffer = buffer.encode("ascii")
2777
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002778 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002779
2780 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002781 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002782 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002783 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002784 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002785 # TODO: This is untested.
2786 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002787 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2788
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002789 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002790 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002791
2792 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002793 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002794 return pypkcs7
2795
2796
Stephen Holsapple38482622014-04-05 20:29:34 -07002797def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002798 """
2799 Load a PKCS12 object from a buffer
2800
2801 :param buffer: The buffer the certificate is stored in
2802 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2803 :returns: The PKCS12 object
2804 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002805 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002806
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002807 if isinstance(buffer, _text_type):
2808 buffer = buffer.encode("ascii")
2809
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002810 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002811
Stephen Holsapple38482622014-04-05 20:29:34 -07002812 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2813 # password based encryption no password and a zero length password are two
2814 # different things, but OpenSSL implementation will try both to figure out
2815 # which one works.
2816 if not passphrase:
2817 passphrase = _ffi.NULL
2818
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002819 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2820 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002821 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002822 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002823
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002824 pkey = _ffi.new("EVP_PKEY**")
2825 cert = _ffi.new("X509**")
2826 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002827
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002828 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002829 if not parse_result:
2830 _raise_current_error()
2831
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002832 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002833
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002834 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2835 # queue for no particular reason. This error isn't interesting to anyone
2836 # outside this function. It's not even interesting to us. Get rid of it.
2837 try:
2838 _raise_current_error()
2839 except Error:
2840 pass
2841
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002842 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002843 pykey = None
2844 else:
2845 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002846 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002847
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002848 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002849 pycert = None
2850 friendlyname = None
2851 else:
2852 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002853 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002854
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002855 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002856 friendlyname_buffer = _lib.X509_alias_get0(
2857 cert[0], friendlyname_length
2858 )
2859 friendlyname = _ffi.buffer(
2860 friendlyname_buffer, friendlyname_length[0]
2861 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002862 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002863 friendlyname = None
2864
2865 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002866 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002867 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002868 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002869 pycacerts.append(pycacert)
2870 if not pycacerts:
2871 pycacerts = None
2872
2873 pkcs12 = PKCS12.__new__(PKCS12)
2874 pkcs12._pkey = pykey
2875 pkcs12._cert = pycert
2876 pkcs12._cacerts = pycacerts
2877 pkcs12._friendlyname = friendlyname
2878 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002879
2880
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002881# There are no direct unit tests for this initialization. It is tested
2882# indirectly since it is necessary for functions like dump_privatekey when
2883# using encryption.
2884#
2885# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2886# and some other similar tests may fail without this (though they may not if
2887# the Python runtime has already done some initialization of the underlying
2888# OpenSSL library (and is linked against the same one that cryptography is
2889# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002890_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002891
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002892# This is similar but exercised mainly by exception_from_error_queue. It calls
2893# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2894_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002895
2896
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002897# Set the default string mask to match OpenSSL upstream (since 2005) and
2898# RFC5280 recommendations.
2899_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')