blob: 1116d5ed089d215400415f9a9abb37da269cb03c [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 """
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001701 Dump the private key *pkey* into a buffer string encoded with the type
1702 *type*. Optionally (if *type* is :const:`FILETYPE_PEM`) encrypting it
1703 using *cipher* and *passphrase*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001704
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001705 :param type: The file type (one of :const:`FILETYPE_PEM`,
1706 :const:`FILETYPE_ASN1`, or :const:`FILETYPE_TEXT`)
1707 :param PKey pkey: The PKey to dump
1708 :param cipher: (optional) if encrypted PEM format, the cipher to use
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001709 :param passphrase: (optional) if encrypted PEM format, this can be either
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001710 the passphrase to use, or a callback for providing the passphrase.
1711
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001712 :return: The buffer with the dumped key in
Dan Sully44e767a2016-06-04 18:05:27 -07001713 :rtype: bytes
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001714 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001715 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001716
1717 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001718 if passphrase is None:
1719 raise TypeError(
1720 "if a value is given for cipher "
1721 "one must also be given for passphrase")
1722 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001723 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001724 raise ValueError("Invalid cipher name")
1725 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001726 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001727
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001728 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001729 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001730 result_code = _lib.PEM_write_bio_PrivateKey(
1731 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001732 helper.callback, helper.callback_args)
1733 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001734 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001735 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001736 elif type == FILETYPE_TEXT:
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001737 rsa = _ffi.gc(
1738 _lib.EVP_PKEY_get1_RSA(pkey._pkey),
1739 _lib.RSA_free
1740 )
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001741 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001742 else:
1743 raise ValueError(
1744 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1745 "FILETYPE_TEXT")
1746
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001747 _openssl_assert(result_code != 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001748
1749 return _bio_to_string(bio)
1750
1751
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001752class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001753 """
1754 A certificate revocation.
1755 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001756 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1757 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1758 # OCSP_crl_reason_str. We use the latter, just like the command line
1759 # program.
1760 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001761 b"unspecified",
1762 b"keyCompromise",
1763 b"CACompromise",
1764 b"affiliationChanged",
1765 b"superseded",
1766 b"cessationOfOperation",
1767 b"certificateHold",
1768 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001769 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001770
1771 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001772 revoked = _lib.X509_REVOKED_new()
1773 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001774
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001775 def set_serial(self, hex_str):
1776 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001777 Set the serial number.
1778
1779 The serial number is formatted as a hexadecimal number encoded in
1780 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001781
Dan Sully44e767a2016-06-04 18:05:27 -07001782 :param bytes hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001783
Dan Sully44e767a2016-06-04 18:05:27 -07001784 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001785 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001786 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1787 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001788 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001789 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001790 if not bn_result:
1791 raise ValueError("bad hex string")
1792
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001793 asn1_serial = _ffi.gc(
1794 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1795 _lib.ASN1_INTEGER_free)
1796 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001797
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001798 def get_serial(self):
1799 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001800 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001801
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001802 The serial number is formatted as a hexadecimal number encoded in
1803 ASCII.
1804
1805 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001806 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001808 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809
Alex Gaynor67903a62016-06-02 10:37:13 -07001810 asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked)
1811 _openssl_assert(asn1_int != _ffi.NULL)
1812 result = _lib.i2a_ASN1_INTEGER(bio, asn1_int)
1813 _openssl_assert(result >= 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001814 return _bio_to_string(bio)
1815
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001816 def _delete_reason(self):
Alex Gaynor67903a62016-06-02 10:37:13 -07001817 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1818 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001819 obj = _lib.X509_EXTENSION_get_object(ext)
1820 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001821 _lib.X509_EXTENSION_free(ext)
Alex Gaynor67903a62016-06-02 10:37:13 -07001822 _lib.X509_REVOKED_delete_ext(self._revoked, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001823 break
1824
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001825 def set_reason(self, reason):
1826 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001827 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001828
Dan Sully44e767a2016-06-04 18:05:27 -07001829 If :data:`reason` is ``None``, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001830
1831 :param reason: The reason string.
Dan Sully44e767a2016-06-04 18:05:27 -07001832 :type reason: :class:`bytes` or :class:`NoneType`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001833
Dan Sully44e767a2016-06-04 18:05:27 -07001834 :return: ``None``
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001835
1836 .. seealso::
1837
Dan Sully44e767a2016-06-04 18:05:27 -07001838 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001839 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001840 """
1841 if reason is None:
1842 self._delete_reason()
1843 elif not isinstance(reason, bytes):
1844 raise TypeError("reason must be None or a byte string")
1845 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001846 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001847 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1848
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001849 new_reason_ext = _lib.ASN1_ENUMERATED_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07001850 _openssl_assert(new_reason_ext != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001851 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001852
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001853 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001854 _openssl_assert(set_result != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001855
1856 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001857 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1858 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001859
1860 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001861 # TODO: This is untested.
1862 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001863
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001864 def get_reason(self):
1865 """
Alex Gaynor80262fb2016-04-22 07:53:42 -04001866 Get the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001867
Dan Sully44e767a2016-06-04 18:05:27 -07001868 :return: The reason, or ``None`` if there is none.
1869 :rtype: bytes or NoneType
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001870
1871 .. seealso::
1872
Dan Sully44e767a2016-06-04 18:05:27 -07001873 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001874 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001875 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001876 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1877 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001878 obj = _lib.X509_EXTENSION_get_object(ext)
1879 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001880 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001881
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001882 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001883 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001884 print_result = _lib.M_ASN1_OCTET_STRING_print(
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001885 bio, _lib.X509_EXTENSION_get_data(ext)
Alex Gaynor5945ea82015-09-05 14:59:06 -04001886 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001887 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001888 # TODO: This is untested.
1889 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001890
1891 return _bio_to_string(bio)
1892
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001893 def all_reasons(self):
1894 """
1895 Return a list of all the supported reason strings.
1896
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001897 This list is a copy; modifying it does not change the supported reason
1898 strings.
1899
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001900 :return: A list of reason strings.
Dan Sully44e767a2016-06-04 18:05:27 -07001901 :rtype: :class:`list` of :class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001902 """
1903 return self._crl_reasons[:]
1904
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001905 def set_rev_date(self, when):
1906 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001907 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001908
Dan Sully44e767a2016-06-04 18:05:27 -07001909 :param bytes when: The timestamp of the revocation,
1910 as ASN.1 GENERALIZEDTIME.
1911 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001912 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001913 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1914 return _set_asn1_time(dt, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001915
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001916 def get_rev_date(self):
1917 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001918 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001919
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001920 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
Dan Sully44e767a2016-06-04 18:05:27 -07001921 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001922 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001923 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1924 return _get_asn1_time(dt)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001925
1926
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001927class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001928 """
1929 A certificate revocation list.
1930 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001931
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001932 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001933 crl = _lib.X509_CRL_new()
1934 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001935
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001936 def get_revoked(self):
1937 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001938 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001939
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001940 These revocations will be provided by value, not by reference.
1941 That means it's okay to mutate them: it won't affect this CRL.
1942
1943 :return: The revocations in this CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07001944 :rtype: :class:`tuple` of :class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001945 """
1946 results = []
Alex Gaynor67903a62016-06-02 10:37:13 -07001947 revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001948 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1949 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Paul Kehrer2fe23b02016-03-09 22:02:15 -04001950 revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001951 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001952 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001953 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001954 if results:
1955 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001956
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001957 def add_revoked(self, revoked):
1958 """
1959 Add a revoked (by value not reference) to the CRL structure
1960
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001961 This revocation will be added by value, not by reference. That
1962 means it's okay to mutate it after adding: it won't affect
1963 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001964
Dan Sully44e767a2016-06-04 18:05:27 -07001965 :param Revoked revoked: The new revocation.
1966 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001967 """
Paul Kehrer8dddb1a2016-03-09 21:48:04 -04001968 copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001969 _openssl_assert(copy != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001970
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001971 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001972 if add_result == 0:
1973 # TODO: This is untested.
1974 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001975
Dan Sully44e767a2016-06-04 18:05:27 -07001976 def get_issuer(self):
1977 """
1978 Get the CRL's issuer.
1979
1980 .. versionadded:: 16.1.0
1981
1982 :rtype: X509Name
1983 """
1984 _issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl))
1985 _openssl_assert(_issuer != _ffi.NULL)
1986 _issuer = _ffi.gc(_issuer, _lib.X509_NAME_free)
1987 issuer = X509Name.__new__(X509Name)
1988 issuer._name = _issuer
1989 return issuer
1990
1991 def set_version(self, version):
1992 """
1993 Set the CRL version.
1994
1995 .. versionadded:: 16.1.0
1996
1997 :param int version: The version of the CRL.
1998 :return: ``None``
1999 """
2000 _openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0)
2001
2002 def _set_boundary_time(self, which, when):
2003 return _set_asn1_time(which(self._crl), when)
2004
2005 def set_lastUpdate(self, when):
2006 """
2007 Set when the CRL was last updated.
2008
2009 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2010
2011 YYYYMMDDhhmmssZ
2012 YYYYMMDDhhmmss+hhmm
2013 YYYYMMDDhhmmss-hhmm
2014
2015 .. versionadded:: 16.1.0
2016
2017 :param bytes when: A timestamp string.
2018 :return: ``None``
2019 """
2020 return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when)
2021
2022 def set_nextUpdate(self, when):
2023 """
2024 Set when the CRL will next be udpated.
2025
2026 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2027
2028 YYYYMMDDhhmmssZ
2029 YYYYMMDDhhmmss+hhmm
2030 YYYYMMDDhhmmss-hhmm
2031
2032 .. versionadded:: 16.1.0
2033
2034 :param bytes when: A timestamp string.
2035 :return: ``None``
2036 """
2037 return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when)
2038
2039 def sign(self, issuer_cert, issuer_key, digest):
2040 """
2041 Sign the CRL.
2042
2043 Signing a CRL enables clients to associate the CRL itself with an
2044 issuer. Before a CRL is meaningful to other OpenSSL functions, it must
2045 be signed by an issuer.
2046
2047 This method implicitly sets the issuer's name based on the issuer
2048 certificate and private key used to sign the CRL.
2049
2050 .. versionadded:: 16.1.0
2051
2052 :param X509 issuer_cert: The issuer's certificate.
2053 :param PKey issuer_key: The issuer's private key.
2054 :param bytes digest: The digest method to sign the CRL with.
2055 """
2056 digest_obj = _lib.EVP_get_digestbyname(digest)
2057 _openssl_assert(digest_obj != _ffi.NULL)
2058 _lib.X509_CRL_set_issuer_name(
2059 self._crl, _lib.X509_get_subject_name(issuer_cert._x509))
2060 _lib.X509_CRL_sort(self._crl)
2061 result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj)
2062 _openssl_assert(result != 0)
2063
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002064 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002065 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002066 """
Dan Sully44e767a2016-06-04 18:05:27 -07002067 Export the CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002068
Dan Sully44e767a2016-06-04 18:05:27 -07002069 :param X509 cert: The certificate used to sign the CRL.
2070 :param PKey key: The key used to sign the CRL.
2071 :param int type: The export format, either :data:`FILETYPE_PEM`,
2072 :data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`.
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002073 :param int days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002074 :param bytes digest: The name of the message digest to use (eg
2075 ``b"sha1"``).
Dan Sully44e767a2016-06-04 18:05:27 -07002076 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002077 """
Dan Sully44e767a2016-06-04 18:05:27 -07002078
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002079 if not isinstance(cert, X509):
2080 raise TypeError("cert must be an X509 instance")
2081 if not isinstance(key, PKey):
2082 raise TypeError("key must be a PKey instance")
2083 if not isinstance(type, int):
2084 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002085
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002086 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002087 _warn(
2088 "The default message digest (md5) is deprecated. "
2089 "Pass the name of a message digest explicitly.",
2090 category=DeprecationWarning,
2091 stacklevel=2,
2092 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002093 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002094
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002095 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002096 if digest_obj == _ffi.NULL:
2097 raise ValueError("No such digest method")
2098
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002099 bio = _lib.BIO_new(_lib.BIO_s_mem())
Alex Gaynoradd5b072016-06-04 21:04:00 -07002100 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002101
Alex Gaynora738ed52015-09-05 11:17:10 -04002102 # A scratch time object to give different values to different CRL
2103 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002104 sometime = _lib.ASN1_TIME_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07002105 _openssl_assert(sometime != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002106
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002107 _lib.X509_gmtime_adj(sometime, 0)
2108 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002109
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002110 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2111 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002112
Alex Gaynor5945ea82015-09-05 14:59:06 -04002113 _lib.X509_CRL_set_issuer_name(
2114 self._crl, _lib.X509_get_subject_name(cert._x509)
2115 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002116
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002117 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002118 if not sign_result:
2119 _raise_current_error()
2120
Dominic Chenf05b2122015-10-13 16:32:35 +00002121 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002122
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002123
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002124CRLType = CRL
2125
2126
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002127class PKCS7(object):
2128 def type_is_signed(self):
2129 """
2130 Check if this NID_pkcs7_signed object
2131
2132 :return: True if the PKCS7 is of type signed
2133 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002134 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002135 return True
2136 return False
2137
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002138 def type_is_enveloped(self):
2139 """
2140 Check if this NID_pkcs7_enveloped object
2141
2142 :returns: True if the PKCS7 is of type enveloped
2143 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002144 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002145 return True
2146 return False
2147
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002148 def type_is_signedAndEnveloped(self):
2149 """
2150 Check if this NID_pkcs7_signedAndEnveloped object
2151
2152 :returns: True if the PKCS7 is of type signedAndEnveloped
2153 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002154 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002155 return True
2156 return False
2157
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002158 def type_is_data(self):
2159 """
2160 Check if this NID_pkcs7_data object
2161
2162 :return: True if the PKCS7 is of type data
2163 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002164 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002165 return True
2166 return False
2167
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002168 def get_type_name(self):
2169 """
2170 Returns the type name of the PKCS7 structure
2171
2172 :return: A string with the typename
2173 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002174 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2175 string_type = _lib.OBJ_nid2sn(nid)
2176 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002177
2178PKCS7Type = PKCS7
2179
2180
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002181class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002182 """
2183 A PKCS #12 archive.
2184 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002185
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002186 def __init__(self):
2187 self._pkey = None
2188 self._cert = None
2189 self._cacerts = None
2190 self._friendlyname = None
2191
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002192 def get_certificate(self):
2193 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002194 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002195
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002196 :return: The certificate, or :py:const:`None` if there is none.
2197 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002198 """
2199 return self._cert
2200
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002201 def set_certificate(self, cert):
2202 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002203 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002204
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002205 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002206 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002207
Dan Sully44e767a2016-06-04 18:05:27 -07002208 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002209 """
2210 if not isinstance(cert, X509):
2211 raise TypeError("cert must be an X509 instance")
2212 self._cert = cert
2213
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002214 def get_privatekey(self):
2215 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002216 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002217
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002218 :return: The private key, or :py:const:`None` if there is none.
2219 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002220 """
2221 return self._pkey
2222
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002223 def set_privatekey(self, pkey):
2224 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002225 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002226
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002227 :param pkey: The new private key, or :py:const:`None` to unset it.
2228 :type pkey: :py:class:`PKey` or :py:const:`None`
2229
Dan Sully44e767a2016-06-04 18:05:27 -07002230 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002231 """
2232 if not isinstance(pkey, PKey):
2233 raise TypeError("pkey must be a PKey instance")
2234 self._pkey = pkey
2235
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002236 def get_ca_certificates(self):
2237 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002238 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002239
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002240 :return: A tuple with the CA certificates in the chain, or
2241 :py:const:`None` if there are none.
2242 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002243 """
2244 if self._cacerts is not None:
2245 return tuple(self._cacerts)
2246
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002247 def set_ca_certificates(self, cacerts):
2248 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002249 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002250
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002251 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2252 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002253 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002254
Dan Sully44e767a2016-06-04 18:05:27 -07002255 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002256 """
2257 if cacerts is None:
2258 self._cacerts = None
2259 else:
2260 cacerts = list(cacerts)
2261 for cert in cacerts:
2262 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002263 raise TypeError(
2264 "iterable must only contain X509 instances"
2265 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002266 self._cacerts = cacerts
2267
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002268 def set_friendlyname(self, name):
2269 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002270 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002271
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002272 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002273 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002274
Dan Sully44e767a2016-06-04 18:05:27 -07002275 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002276 """
2277 if name is None:
2278 self._friendlyname = None
2279 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002280 raise TypeError(
2281 "name must be a byte string or None (not %r)" % (name,)
2282 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002283 self._friendlyname = name
2284
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002285 def get_friendlyname(self):
2286 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002287 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002288
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002289 :returns: The friendly name, or :py:const:`None` if there is none.
2290 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002291 """
2292 return self._friendlyname
2293
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002294 def export(self, passphrase=None, iter=2048, maciter=1):
2295 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002296 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002297
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002298 For more information, see the :c:func:`PKCS12_create` man page.
2299
2300 :param passphrase: The passphrase used to encrypt the structure. Unlike
2301 some other passphrase arguments, this *must* be a string, not a
2302 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002303 :type passphrase: :py:data:`bytes`
2304
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002305 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002306 :type iter: :py:data:`int`
2307
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002308 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002309 :type maciter: :py:data:`int`
2310
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002311 :return: The string representation of the PKCS #12 structure.
2312 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002313 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002314 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002315
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002316 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002317 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002318 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002319 cacerts = _lib.sk_X509_new_null()
2320 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002321 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002322 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002323
2324 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002325 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002326
2327 friendlyname = self._friendlyname
2328 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002329 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002330
2331 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002332 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002333 else:
2334 pkey = self._pkey._pkey
2335
2336 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002337 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002338 else:
2339 cert = self._cert._x509
2340
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002341 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002342 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002343 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2344 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002345 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002346 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002347 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002348 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002349
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002350 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002351 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002352 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002353
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002354
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002355PKCS12Type = PKCS12
2356
2357
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002358class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002359 """
2360 A Netscape SPKI object.
2361 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002362
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002363 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002364 spki = _lib.NETSCAPE_SPKI_new()
2365 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002366
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002367 def sign(self, pkey, digest):
2368 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002369 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002370
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002371 :param pkey: The private key to sign with.
2372 :type pkey: :py:class:`PKey`
2373
2374 :param digest: The message digest to use.
2375 :type digest: :py:class:`bytes`
2376
Dan Sully44e767a2016-06-04 18:05:27 -07002377 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002378 """
2379 if pkey._only_public:
2380 raise ValueError("Key has only public part")
2381
2382 if not pkey._initialized:
2383 raise ValueError("Key is uninitialized")
2384
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002385 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002386 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002387 raise ValueError("No such digest method")
2388
Alex Gaynor5945ea82015-09-05 14:59:06 -04002389 sign_result = _lib.NETSCAPE_SPKI_sign(
2390 self._spki, pkey._pkey, digest_obj
2391 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002392 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002393 # TODO: This is untested.
2394 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002395
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002396 def verify(self, key):
2397 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002398 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002399
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002400 :param key: The public key that signature is supposedly from.
2401 :type pkey: :py:class:`PKey`
2402
2403 :return: :py:const:`True` if the signature is correct.
2404 :rtype: :py:class:`bool`
2405
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002406 :raises Error: If the signature is invalid, or there was a problem
2407 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002408 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002409 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002410 if answer <= 0:
2411 _raise_current_error()
2412 return True
2413
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002414 def b64_encode(self):
2415 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002416 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002417
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002418 :return: The base64 encoded string.
2419 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002420 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002421 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2422 result = _ffi.string(encoded)
Paul Kehrer0dcacf72016-03-17 19:25:39 -04002423 _lib.OPENSSL_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002424 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002425
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002426 def get_pubkey(self):
2427 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002428 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002429
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002430 :return: The public key.
2431 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002432 """
2433 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002434 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002435 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002436 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002437 pkey._only_public = True
2438 return pkey
2439
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002440 def set_pubkey(self, pkey):
2441 """
2442 Set the public key of the certificate
2443
2444 :param pkey: The public key
Dan Sully44e767a2016-06-04 18:05:27 -07002445 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002446 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002447 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002448 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002449 # TODO: This is untested.
2450 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002451
2452
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002453NetscapeSPKIType = NetscapeSPKI
2454
2455
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002456class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002457 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002458 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002459 raise ValueError(
2460 "only FILETYPE_PEM key format supports encryption"
2461 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002462 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002463 self._more_args = more_args
2464 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002465 self._problems = []
2466
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002467 @property
2468 def callback(self):
2469 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002470 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002471 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002472 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002473 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002474 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002475 else:
2476 raise TypeError("Last argument must be string or callable")
2477
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002478 @property
2479 def callback_args(self):
2480 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002481 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002482 elif isinstance(self._passphrase, bytes):
2483 return self._passphrase
2484 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002485 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002486 else:
2487 raise TypeError("Last argument must be string or callable")
2488
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002489 def raise_if_problem(self, exceptionType=Error):
2490 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002491 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002492 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002493 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002494 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002495 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002496 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002497
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002498 def _read_passphrase(self, buf, size, rwflag, userdata):
2499 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002500 if self._more_args:
2501 result = self._passphrase(size, rwflag, userdata)
2502 else:
2503 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002504 if not isinstance(result, bytes):
2505 raise ValueError("String expected")
2506 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002507 if self._truncate:
2508 result = result[:size]
2509 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002510 raise ValueError(
2511 "passphrase returned by callback is too long"
2512 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002513 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002514 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002515 return len(result)
2516 except Exception as e:
2517 self._problems.append(e)
2518 return 0
2519
2520
Cory Benfield6492f7c2015-10-27 16:57:58 +09002521def load_publickey(type, buffer):
2522 """
Cory Benfield11c10192015-10-27 17:23:03 +09002523 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002524
Cory Benfield9c590b92015-10-28 14:55:05 +09002525 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002526 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002527 :param buffer: The buffer the key is stored in.
2528 :type buffer: A Python string object, either unicode or bytestring.
2529 :return: The PKey object.
2530 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002531 """
2532 if isinstance(buffer, _text_type):
2533 buffer = buffer.encode("ascii")
2534
2535 bio = _new_mem_buf(buffer)
2536
2537 if type == FILETYPE_PEM:
2538 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2539 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2540 elif type == FILETYPE_ASN1:
2541 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2542 else:
2543 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2544
2545 if evp_pkey == _ffi.NULL:
2546 _raise_current_error()
2547
2548 pkey = PKey.__new__(PKey)
2549 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Paul Kehrer32fc4e62016-06-03 15:21:44 -07002550 pkey._only_public = True
Cory Benfield6492f7c2015-10-27 16:57:58 +09002551 return pkey
2552
2553
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002554def load_privatekey(type, buffer, passphrase=None):
2555 """
2556 Load a private key from a buffer
2557
2558 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2559 :param buffer: The buffer the key is stored in
2560 :param passphrase: (optional) if encrypted PEM format, this can be
2561 either the passphrase to use, or a callback for
2562 providing the passphrase.
2563
2564 :return: The PKey object
2565 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002566 if isinstance(buffer, _text_type):
2567 buffer = buffer.encode("ascii")
2568
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002569 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002570
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002571 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002572 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002573 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2574 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002575 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002576 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002577 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002578 else:
2579 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2580
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002581 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002582 _raise_current_error()
2583
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002584 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002585 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002586 return pkey
2587
2588
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002589def dump_certificate_request(type, req):
2590 """
2591 Dump a certificate request to a buffer
2592
2593 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2594 :param req: The certificate request to dump
2595 :return: The buffer with the dumped certificate request in
2596 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002597 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002598
2599 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002600 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002601 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002602 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002603 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002604 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002605 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002606 raise ValueError(
2607 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2608 "FILETYPE_TEXT"
2609 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002610
2611 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002612 # TODO: This is untested.
2613 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002614
2615 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002616
2617
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002618def load_certificate_request(type, buffer):
2619 """
2620 Load a certificate request from a buffer
2621
2622 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2623 :param buffer: The buffer the certificate request is stored in
2624 :return: The X509Req object
2625 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002626 if isinstance(buffer, _text_type):
2627 buffer = buffer.encode("ascii")
2628
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002629 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002630
2631 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002632 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002633 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002634 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002635 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002636 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002637
Alex Gaynoradd5b072016-06-04 21:04:00 -07002638 _openssl_assert(req != _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002639
2640 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002641 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002642 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002643
2644
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002645def sign(pkey, data, digest):
2646 """
2647 Sign data with a digest
2648
2649 :param pkey: Pkey to sign with
2650 :param data: data to be signed
2651 :param digest: message digest to use
2652 :return: signature
2653 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002654 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002655
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002656 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002657 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002658 raise ValueError("No such digest method")
2659
Alex Gaynor67903a62016-06-02 10:37:13 -07002660 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002661 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002662
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002663 _lib.EVP_SignInit(md_ctx, digest_obj)
2664 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002665
Colleen Murphye09399b2016-03-01 17:40:49 -08002666 pkey_length = (PKey.bits(pkey) + 7) // 8
2667 signature_buffer = _ffi.new("unsigned char[]", pkey_length)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002668 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002669 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002670 md_ctx, signature_buffer, signature_length, pkey._pkey)
2671
2672 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002673 # TODO: This is untested.
2674 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002675
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002676 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002677
2678
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002679def verify(cert, signature, data, digest):
2680 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002681 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002682
2683 :param cert: signing certificate (X509 object)
2684 :param signature: signature returned by sign function
2685 :param data: data to be verified
2686 :param digest: message digest to use
Dan Sully44e767a2016-06-04 18:05:27 -07002687 :return: ``None`` if the signature is correct, raise exception otherwise.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002688 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002689 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002690
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002691 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002692 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002693 raise ValueError("No such digest method")
2694
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002695 pkey = _lib.X509_get_pubkey(cert._x509)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002696 _openssl_assert(pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002697 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002698
Alex Gaynor67903a62016-06-02 10:37:13 -07002699 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002700 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002701
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002702 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2703 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002704 verify_result = _lib.EVP_VerifyFinal(
2705 md_ctx, signature, len(signature), pkey
2706 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002707
2708 if verify_result != 1:
2709 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002710
2711
Dominic Chenf05b2122015-10-13 16:32:35 +00002712def dump_crl(type, crl):
2713 """
2714 Dump a certificate revocation list to a buffer.
2715
2716 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2717 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002718 :param CRL crl: The CRL to dump.
2719
Dominic Chenf05b2122015-10-13 16:32:35 +00002720 :return: The buffer with the CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07002721 :rtype: bytes
Dominic Chenf05b2122015-10-13 16:32:35 +00002722 """
2723 bio = _new_mem_buf()
2724
2725 if type == FILETYPE_PEM:
2726 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2727 elif type == FILETYPE_ASN1:
2728 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2729 elif type == FILETYPE_TEXT:
2730 ret = _lib.X509_CRL_print(bio, crl._crl)
2731 else:
2732 raise ValueError(
2733 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2734 "FILETYPE_TEXT")
2735
2736 assert ret == 1
2737 return _bio_to_string(bio)
2738
2739
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002740def load_crl(type, buffer):
2741 """
2742 Load a certificate revocation list from a buffer
2743
2744 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2745 :param buffer: The buffer the CRL is stored in
2746
2747 :return: The PKey object
2748 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002749 if isinstance(buffer, _text_type):
2750 buffer = buffer.encode("ascii")
2751
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002752 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002753
2754 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002755 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002756 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002757 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002758 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002759 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2760
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002761 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002762 _raise_current_error()
2763
2764 result = CRL.__new__(CRL)
2765 result._crl = crl
2766 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002767
2768
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002769def load_pkcs7_data(type, buffer):
2770 """
2771 Load pkcs7 data from a buffer
2772
2773 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2774 :param buffer: The buffer with the pkcs7 data.
2775 :return: The PKCS7 object
2776 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002777 if isinstance(buffer, _text_type):
2778 buffer = buffer.encode("ascii")
2779
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002780 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002781
2782 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002783 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002784 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002785 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002786 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002787 # TODO: This is untested.
2788 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002789 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2790
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002791 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002792 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002793
2794 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002795 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002796 return pypkcs7
2797
2798
Stephen Holsapple38482622014-04-05 20:29:34 -07002799def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002800 """
2801 Load a PKCS12 object from a buffer
2802
2803 :param buffer: The buffer the certificate is stored in
2804 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2805 :returns: The PKCS12 object
2806 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002807 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002808
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002809 if isinstance(buffer, _text_type):
2810 buffer = buffer.encode("ascii")
2811
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002812 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002813
Stephen Holsapple38482622014-04-05 20:29:34 -07002814 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2815 # password based encryption no password and a zero length password are two
2816 # different things, but OpenSSL implementation will try both to figure out
2817 # which one works.
2818 if not passphrase:
2819 passphrase = _ffi.NULL
2820
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002821 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2822 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002823 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002824 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002825
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002826 pkey = _ffi.new("EVP_PKEY**")
2827 cert = _ffi.new("X509**")
2828 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002829
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002830 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002831 if not parse_result:
2832 _raise_current_error()
2833
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002834 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002835
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002836 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2837 # queue for no particular reason. This error isn't interesting to anyone
2838 # outside this function. It's not even interesting to us. Get rid of it.
2839 try:
2840 _raise_current_error()
2841 except Error:
2842 pass
2843
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002844 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002845 pykey = None
2846 else:
2847 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002848 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002849
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002850 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002851 pycert = None
2852 friendlyname = None
2853 else:
2854 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002855 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002856
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002857 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002858 friendlyname_buffer = _lib.X509_alias_get0(
2859 cert[0], friendlyname_length
2860 )
2861 friendlyname = _ffi.buffer(
2862 friendlyname_buffer, friendlyname_length[0]
2863 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002864 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002865 friendlyname = None
2866
2867 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002868 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002869 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002870 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002871 pycacerts.append(pycacert)
2872 if not pycacerts:
2873 pycacerts = None
2874
2875 pkcs12 = PKCS12.__new__(PKCS12)
2876 pkcs12._pkey = pykey
2877 pkcs12._cert = pycert
2878 pkcs12._cacerts = pycacerts
2879 pkcs12._friendlyname = friendlyname
2880 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002881
2882
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002883# There are no direct unit tests for this initialization. It is tested
2884# indirectly since it is necessary for functions like dump_privatekey when
2885# using encryption.
2886#
2887# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2888# and some other similar tests may fail without this (though they may not if
2889# the Python runtime has already done some initialization of the underlying
2890# OpenSSL library (and is linked against the same one that cryptography is
2891# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002892_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002893
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002894# This is similar but exercised mainly by exception_from_error_queue. It calls
2895# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2896_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002897
2898
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002899# Set the default string mask to match OpenSSL upstream (since 2005) and
2900# RFC5280 recommendations.
2901_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')