blob: a6cd2635b9096853b6fd9e6d24462627df08ea9b [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,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040021)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080022
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050023FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
24FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080025
26# TODO This was an API mistake. OpenSSL has no such constant.
27FILETYPE_TEXT = 2 ** 16 - 1
28
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050029TYPE_RSA = _lib.EVP_PKEY_RSA
30TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080031
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080032
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050033class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050034 """
35 An error occurred in an `OpenSSL.crypto` API.
36 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050037
38
39_raise_current_error = partial(_exception_from_error_queue, Error)
40
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070041
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050042def _untested_error(where):
43 """
44 An OpenSSL API failed somehow. Additionally, the failure which was
45 encountered isn't one that's exercised by the test suite so future behavior
46 of pyOpenSSL is now somewhat less predictable.
47 """
48 raise RuntimeError("Unknown %s failure" % (where,))
49
50
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050051def _new_mem_buf(buffer=None):
52 """
53 Allocate a new OpenSSL memory BIO.
54
55 Arrange for the garbage collector to clean it up automatically.
56
57 :param buffer: None or some bytes to use to put into the BIO so that they
58 can be read out.
59 """
60 if buffer is None:
61 bio = _lib.BIO_new(_lib.BIO_s_mem())
62 free = _lib.BIO_free
63 else:
64 data = _ffi.new("char[]", buffer)
65 bio = _lib.BIO_new_mem_buf(data, len(buffer))
Alex Gaynor5945ea82015-09-05 14:59:06 -040066
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050067 # Keep the memory alive as long as the bio is alive!
68 def free(bio, ref=data):
69 return _lib.BIO_free(bio)
70
71 if bio == _ffi.NULL:
72 # TODO: This is untested.
73 _raise_current_error()
74
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
117
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.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200184 :return: :py:const:`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()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500221 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500222 # TODO: This is untested.
223 _raise_current_error()
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 )
227 if not res == 1:
228 # TODO: This is untested.
229 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500230 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500231 # TODO: This is untested.
232 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500233 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500234 # TODO: This is untested.
235 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800236 else:
237 raise Error("No such key type")
238
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800239 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800240
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800241 def check(self):
242 """
243 Check the consistency of an RSA private key.
244
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200245 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
246
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800247 :return: True if key is consistent.
248 :raise Error: if the key is inconsistent.
249 :raise TypeError: if the key is of a type which cannot be checked.
250 Only RSA keys can currently be checked.
251 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800252 if self._only_public:
253 raise TypeError("public key only")
254
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100255 if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800256 raise TypeError("key type unsupported")
257
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500258 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
259 rsa = _ffi.gc(rsa, _lib.RSA_free)
260 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800261 if result:
262 return True
263 _raise_current_error()
264
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800265 def type(self):
266 """
267 Returns the type of the key
268
269 :return: The type of the key.
270 """
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100271 try:
272 # cryptography 1.2+
273 return _lib.Cryptography_EVP_PKEY_id(self._pkey)
274 except AttributeError:
275 # Older releases of cryptography.
276 return self._pkey.type
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800277
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800278 def bits(self):
279 """
280 Returns the number of bits of the key
281
282 :return: The number of bits of the key.
283 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500284 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800285PKeyType = PKey
286
287
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400288class _EllipticCurve(object):
289 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400290 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400291
292 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
293 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
294 instances each of which represents one curve supported by the system.
295 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400296 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400297 _curves = None
298
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400299 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400300 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400301 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400302 """
303 Implement cooperation with the right-hand side argument of ``!=``.
304
305 Python 3 seems to have dropped this cooperation in this very narrow
306 circumstance.
307 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400308 if isinstance(other, _EllipticCurve):
309 return super(_EllipticCurve, self).__ne__(other)
310 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400311
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400312 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400313 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400314 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400315 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400316
317 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400318
319 :return: A :py:type:`set` of ``cls`` instances giving the names of the
320 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400321 """
322 if lib.Cryptography_HAS_EC:
323 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
324 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400325 # The return value on this call should be num_curves again. We
326 # could check it to make sure but if it *isn't* then.. what could
327 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400328 lib.EC_get_builtin_curves(builtin_curves, num_curves)
329 return set(
330 cls.from_nid(lib, c.nid)
331 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400332 return set()
333
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400334 @classmethod
335 def _get_elliptic_curves(cls, lib):
336 """
337 Get, cache, and return the curves supported by OpenSSL.
338
339 :param lib: The OpenSSL library binding object.
340
341 :return: A :py:type:`set` of ``cls`` instances giving the names of the
342 elliptic curves the underlying library supports.
343 """
344 if cls._curves is None:
345 cls._curves = cls._load_elliptic_curves(lib)
346 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400347
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400348 @classmethod
349 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400350 """
351 Instantiate a new :py:class:`_EllipticCurve` associated with the given
352 OpenSSL NID.
353
354 :param lib: The OpenSSL library binding object.
355
356 :param nid: The OpenSSL NID the resulting curve object will represent.
357 This must be a curve NID (and not, for example, a hash NID) or
358 subsequent operations will fail in unpredictable ways.
359 :type nid: :py:class:`int`
360
361 :return: The curve object.
362 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400363 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
364
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400365 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400366 """
367 :param _lib: The :py:mod:`cryptography` binding instance used to
368 interface with OpenSSL.
369
370 :param _nid: The OpenSSL NID identifying the curve this object
371 represents.
372 :type _nid: :py:class:`int`
373
374 :param name: The OpenSSL short name identifying the curve this object
375 represents.
376 :type name: :py:class:`unicode`
377 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400378 self._lib = lib
379 self._nid = nid
380 self.name = name
381
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400382 def __repr__(self):
383 return "<Curve %r>" % (self.name,)
384
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400385 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400386 """
387 Create a new OpenSSL EC_KEY structure initialized to use this curve.
388
389 The structure is automatically garbage collected when the Python object
390 is garbage collected.
391 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400392 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
393 return _ffi.gc(key, _lib.EC_KEY_free)
394
395
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400396def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400397 """
398 Return a set of objects representing the elliptic curves supported in the
399 OpenSSL build in use.
400
401 The curve objects have a :py:class:`unicode` ``name`` attribute by which
402 they identify themselves.
403
404 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400405 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
406 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400407 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400408 return _EllipticCurve._get_elliptic_curves(_lib)
409
410
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400411def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400412 """
413 Return a single curve object selected by name.
414
415 See :py:func:`get_elliptic_curves` for information about curve objects.
416
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400417 :param name: The OpenSSL short name identifying the curve object to
418 retrieve.
419 :type name: :py:class:`unicode`
420
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400421 If the named curve is not supported then :py:class:`ValueError` is raised.
422 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400423 for curve in get_elliptic_curves():
424 if curve.name == name:
425 return curve
426 raise ValueError("unknown curve name", name)
427
428
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800429class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200430 """
431 An X.509 Distinguished Name.
432
433 :ivar countryName: The country of the entity.
434 :ivar C: Alias for :py:attr:`countryName`.
435
436 :ivar stateOrProvinceName: The state or province of the entity.
437 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
438
439 :ivar localityName: The locality of the entity.
440 :ivar L: Alias for :py:attr:`localityName`.
441
442 :ivar organizationName: The organization name of the entity.
443 :ivar O: Alias for :py:attr:`organizationName`.
444
445 :ivar organizationalUnitName: The organizational unit of the entity.
446 :ivar OU: Alias for :py:attr:`organizationalUnitName`
447
448 :ivar commonName: The common name of the entity.
449 :ivar CN: Alias for :py:attr:`commonName`.
450
451 :ivar emailAddress: The e-mail address of the entity.
452 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400453
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800454 def __init__(self, name):
455 """
456 Create a new X509Name, copying the given X509Name instance.
457
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200458 :param name: The name to copy.
459 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800460 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500461 name = _lib.X509_NAME_dup(name._name)
462 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800463
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800464 def __setattr__(self, name, value):
465 if name.startswith('_'):
466 return super(X509Name, self).__setattr__(name, value)
467
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800468 # Note: we really do not want str subclasses here, so we do not use
469 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800470 if type(name) is not str:
471 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400472 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800473
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500474 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500475 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800476 try:
477 _raise_current_error()
478 except Error:
479 pass
480 raise AttributeError("No such attribute")
481
482 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500483 for i in range(_lib.X509_NAME_entry_count(self._name)):
484 ent = _lib.X509_NAME_get_entry(self._name, i)
485 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
486 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800487 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500488 ent = _lib.X509_NAME_delete_entry(self._name, i)
489 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800490 break
491
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500492 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800493 value = value.encode('utf-8')
494
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500495 add_result = _lib.X509_NAME_add_entry_by_NID(
496 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800497 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500498 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800499
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800500 def __getattr__(self, name):
501 """
502 Find attribute. An X509Name object has the following attributes:
503 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400504 organization (alias O), organizationalUnit (alias OU), commonName
505 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800506 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500507 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500508 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800509 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
510 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
511 # push something onto the error queue. If we don't clean that up
512 # now, someone else will bump into it later and be quite confused.
513 # See lp#314814.
514 try:
515 _raise_current_error()
516 except Error:
517 pass
518 return super(X509Name, self).__getattr__(name)
519
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500520 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800521 if entry_index == -1:
522 return None
523
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500524 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
525 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800526
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500527 result_buffer = _ffi.new("unsigned char**")
528 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800529 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500530 # TODO: This is untested.
531 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800532
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700533 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400534 result = _ffi.buffer(
535 result_buffer[0], data_length
536 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700537 finally:
538 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500539 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800540 return result
541
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500542 def _cmp(op):
543 def f(self, other):
544 if not isinstance(other, X509Name):
545 return NotImplemented
546 result = _lib.X509_NAME_cmp(self._name, other._name)
547 return op(result, 0)
548 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800549
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500550 __eq__ = _cmp(__eq__)
551 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800552
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500553 __lt__ = _cmp(__lt__)
554 __le__ = _cmp(__le__)
555
556 __gt__ = _cmp(__gt__)
557 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800558
559 def __repr__(self):
560 """
561 String representation of an X509Name
562 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400563 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500564 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800565 self._name, result_buffer, len(result_buffer))
566
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500567 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500568 # TODO: This is untested.
569 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800570
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500571 return "<X509Name object '%s'>" % (
572 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800573
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800574 def hash(self):
575 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200576 Return an integer representation of the first four bytes of the
577 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800578
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200579 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
580
581 :return: The (integer) hash of this name.
582 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800583 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500584 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800586 def der(self):
587 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200588 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800589
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200590 :return: The DER encoded form of this name.
591 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800592 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500593 result_buffer = _ffi.new('unsigned char**')
594 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800595 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500596 # TODO: This is untested.
597 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800598
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500599 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
600 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800601 return string_result
602
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800603 def get_components(self):
604 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200605 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800606
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200607 :return: The components of this name.
608 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800609 """
610 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500611 for i in range(_lib.X509_NAME_entry_count(self._name)):
612 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800613
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500614 fname = _lib.X509_NAME_ENTRY_get_object(ent)
615 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800616
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500617 nid = _lib.OBJ_obj2nid(fname)
618 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800619
620 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400621 _ffi.string(name),
622 _ffi.string(
623 _lib.ASN1_STRING_data(fval),
624 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800625
626 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200627
628
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800629X509NameType = X509Name
630
631
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800632class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200633 """
634 An X.509 v3 certificate extension.
635 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400636
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800637 def __init__(self, type_name, critical, value, subject=None, issuer=None):
638 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200639 Initializes an X509 extension.
640
Alex Gaynor6f719912015-09-20 09:21:29 -0400641 :param type_name: The name of the type of extension to create. See
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200642 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Alex Gaynor6f719912015-09-20 09:21:29 -0400643 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800644
Alex Gaynor5945ea82015-09-05 14:59:06 -0400645 :param bool critical: A flag indicating whether this is a critical
646 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800647
648 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200649 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800650
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200651 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800652 :type subject: :py:class:`X509`
653
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200654 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800655 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800656 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500657 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800658
Alex Gaynor5945ea82015-09-05 14:59:06 -0400659 # A context is necessary for any extension which uses the r2i
660 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
661 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500662 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800663
664 # We have no configuration database - but perhaps we should (some
665 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500666 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800667
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800668 # Initialize the subject and issuer, if appropriate. ctx is a local,
669 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400670 # any references, so no need to mess with reference counts or
671 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800672 if issuer is not None:
673 if not isinstance(issuer, X509):
674 raise TypeError("issuer must be an X509 instance")
675 ctx.issuer_cert = issuer._x509
676 if subject is not None:
677 if not isinstance(subject, X509):
678 raise TypeError("subject must be an X509 instance")
679 ctx.subject_cert = subject._x509
680
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800681 if critical:
682 # There are other OpenSSL APIs which would let us pass in critical
683 # separately, but they're harder to use, and since value is already
684 # a pile of crappy junk smuggling a ton of utterly important
685 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400686 # with strings? (However, X509V3_EXT_i2d in particular seems like
687 # it would be a better API to invoke. I do not know where to get
688 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500689 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800690
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500691 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
692 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800693 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500694 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800695
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400696 @property
697 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500698 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400699
700 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500701 _lib.GEN_EMAIL: "email",
702 _lib.GEN_DNS: "DNS",
703 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400704 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400705
706 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500707 method = _lib.X509V3_EXT_get(self._extension)
708 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500709 # TODO: This is untested.
710 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400711 payload = self._extension.value.data
712 length = self._extension.value.length
713
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500714 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400715 payloadptr[0] = payload
716
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500717 if method.it != _ffi.NULL:
718 ptr = _lib.ASN1_ITEM_ptr(method.it)
719 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
720 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400721 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500722 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400723 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500724 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400725
Paul Kehrerb7d79502015-05-04 07:43:51 -0500726 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400727 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500728 for i in range(_lib.sk_GENERAL_NAME_num(names)):
729 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400730 try:
731 label = self._prefixes[name.type]
732 except KeyError:
733 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500734 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500735 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400736 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500737 value = _native(
738 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
739 parts.append(label + ":" + value)
740 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400741
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800742 def __str__(self):
743 """
744 :return: a nice text representation of the extension
745 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500746 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400747 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800748
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400749 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500750 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800751 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500752 # TODO: This is untested.
753 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800754
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500755 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800756
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800757 def get_critical(self):
758 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200759 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800760
761 :return: The critical field.
762 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500763 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800764
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800765 def get_short_name(self):
766 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200767 Returns the short type name of this X.509 extension.
768
769 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800770
771 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200772 :rtype: :py:data:`bytes`
773
774 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800775 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500776 obj = _lib.X509_EXTENSION_get_object(self._extension)
777 nid = _lib.OBJ_obj2nid(obj)
778 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800779
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800780 def get_data(self):
781 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200782 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800783
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200784 :return: The ASN.1 encoded data of this X509 extension.
785 :rtype: :py:data:`bytes`
786
787 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800788 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500789 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
790 string_result = _ffi.cast('ASN1_STRING*', octet_result)
791 char_result = _lib.ASN1_STRING_data(string_result)
792 result_length = _lib.ASN1_STRING_length(string_result)
793 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800794
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200795
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800796X509ExtensionType = X509Extension
797
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800798
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800799class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200800 """
801 An X.509 certificate signing requests.
802 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400803
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800804 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500805 req = _lib.X509_REQ_new()
806 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800807
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800808 def set_pubkey(self, pkey):
809 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200810 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200812 :param pkey: The public key to use.
813 :type pkey: :py:class:`PKey`
814
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200815 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800816 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500817 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800818 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500819 # TODO: This is untested.
820 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800821
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800822 def get_pubkey(self):
823 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200824 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800825
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200826 :return: The public key.
827 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800828 """
829 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500830 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
831 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500832 # TODO: This is untested.
833 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500834 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800835 pkey._only_public = True
836 return pkey
837
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800838 def set_version(self, version):
839 """
840 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
841 request.
842
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200843 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200844 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800845 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500846 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800847 if not set_result:
848 _raise_current_error()
849
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850 def get_version(self):
851 """
852 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
853 request.
854
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200855 :return: The value of the version subfield.
856 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800857 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500858 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800859
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800860 def get_subject(self):
861 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200862 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800863
Cory Benfield881dc8d2015-12-09 08:25:14 +0000864 This creates a new :class:`X509Name` that wraps the underlying subject
865 name field on the certificate signing request. Modifying it will modify
866 the underlying signing request, and will have the effect of modifying
867 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200868
869 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000870 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800871 """
872 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500873 name._name = _lib.X509_REQ_get_subject_name(self._req)
874 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500875 # TODO: This is untested.
876 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800877
878 # The name is owned by the X509Req structure. As long as the X509Name
879 # Python object is alive, keep the X509Req Python object alive.
880 name._owner = self
881
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800882 return name
883
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800884 def add_extensions(self, extensions):
885 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200886 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800887
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200888 :param extensions: The X.509 extensions to add.
889 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200890 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800891 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500892 stack = _lib.sk_X509_EXTENSION_new_null()
893 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500894 # TODO: This is untested.
895 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800896
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500897 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800898
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800899 for ext in extensions:
900 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800901 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800902
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800903 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500904 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800905
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500906 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800907 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500908 # TODO: This is untested.
909 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800910
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800911 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800912 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200913 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800914
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200915 :return: The X.509 extensions in this request.
916 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
917
918 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800919 """
920 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500921 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500922 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800923 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500924 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800925 exts.append(ext)
926 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800927
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800928 def sign(self, pkey, digest):
929 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700930 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800931
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200932 :param pkey: The key pair to sign with.
933 :type pkey: :py:class:`PKey`
934 :param digest: The name of the message digest to use for the signature,
935 e.g. :py:data:`b"sha1"`.
936 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200937 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800938 """
939 if pkey._only_public:
940 raise ValueError("Key has only public part")
941
942 if not pkey._initialized:
943 raise ValueError("Key is uninitialized")
944
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500945 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500946 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800947 raise ValueError("No such digest method")
948
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500949 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800950 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500951 # TODO: This is untested.
952 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800953
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800954 def verify(self, pkey):
955 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200956 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800957
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200958 :param key: A public key.
959 :type key: :py:class:`PKey`
960 :return: :py:data:`True` if the signature is correct.
961 :rtype: :py:class:`bool`
962 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800963 problem verifying the signature.
964 """
965 if not isinstance(pkey, PKey):
966 raise TypeError("pkey must be a PKey instance")
967
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500968 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800969 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500970 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800971
972 return result
973
974
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800975X509ReqType = X509Req
976
977
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800978class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200979 """
980 An X.509 certificate.
981 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400982
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800983 def __init__(self):
984 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500985 x509 = _lib.X509_new()
986 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800987
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800988 def set_version(self, version):
989 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200990 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800991
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200992 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800993 :type version: :py:class:`int`
994
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200995 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800996 """
997 if not isinstance(version, int):
998 raise TypeError("version must be an integer")
999
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001000 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001001
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001002 def get_version(self):
1003 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001004 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001005
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001006 :return: The version number of the certificate.
1007 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001008 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001009 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001010
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001011 def get_pubkey(self):
1012 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001013 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001014
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001015 :return: The public key.
1016 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001017 """
1018 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001019 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1020 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001021 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001022 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001023 pkey._only_public = True
1024 return pkey
1025
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001026 def set_pubkey(self, pkey):
1027 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001028 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001029
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001030 :param pkey: The public key.
1031 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001032
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001033 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001034 """
1035 if not isinstance(pkey, PKey):
1036 raise TypeError("pkey must be a PKey instance")
1037
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001038 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001039 if not set_result:
1040 _raise_current_error()
1041
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001042 def sign(self, pkey, digest):
1043 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001044 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001045
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001046 :param pkey: The key to sign with.
1047 :type pkey: :py:class:`PKey`
1048
1049 :param digest: The name of the message digest to use.
1050 :type digest: :py:class:`bytes`
1051
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001052 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001053 """
1054 if not isinstance(pkey, PKey):
1055 raise TypeError("pkey must be a PKey instance")
1056
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001057 if pkey._only_public:
1058 raise ValueError("Key only has public part")
1059
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001060 if not pkey._initialized:
1061 raise ValueError("Key is uninitialized")
1062
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001063 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001064 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001065 raise ValueError("No such digest method")
1066
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001067 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001068 if not sign_result:
1069 _raise_current_error()
1070
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001071 def get_signature_algorithm(self):
1072 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001073 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001074
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001075 :return: The name of the algorithm.
1076 :rtype: :py:class:`bytes`
1077
1078 :raises ValueError: If the signature algorithm is undefined.
1079
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001080 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001081 """
1082 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001083 nid = _lib.OBJ_obj2nid(alg)
1084 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001085 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001086 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001087
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001088 def digest(self, digest_name):
1089 """
1090 Return the digest of the X509 object.
1091
1092 :param digest_name: The name of the digest algorithm to use.
1093 :type digest_name: :py:class:`bytes`
1094
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001095 :return: The digest of the object, formatted as
1096 :py:const:`b":"`-delimited hex pairs.
1097 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001098 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001099 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001100 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001101 raise ValueError("No such digest method")
1102
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001103 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1104 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001105 result_length[0] = len(result_buffer)
1106
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001107 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001108 self._x509, digest, result_buffer, result_length)
1109
1110 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001111 # TODO: This is untested.
1112 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001113
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001114 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001115 b16encode(ch).upper() for ch
1116 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001117
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001118 def subject_name_hash(self):
1119 """
1120 Return the hash of the X509 subject.
1121
1122 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001123 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001124 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001125 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001126
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001127 def set_serial_number(self, serial):
1128 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001129 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001130
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001131 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001132 :type serial: :py:class:`int`
1133
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001134 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001135 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001136 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001137 raise TypeError("serial must be an integer")
1138
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001139 hex_serial = hex(serial)[2:]
1140 if not isinstance(hex_serial, bytes):
1141 hex_serial = hex_serial.encode('ascii')
1142
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001143 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001144
1145 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001146 # it. If bignum is still NULL after this call, then the return value
1147 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001148 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001149
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001150 if bignum_serial[0] == _ffi.NULL:
1151 set_result = _lib.ASN1_INTEGER_set(
1152 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001153 if set_result:
1154 # TODO Not tested
1155 _raise_current_error()
1156 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001157 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1158 _lib.BN_free(bignum_serial[0])
1159 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001160 # TODO Not tested
1161 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001162 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1163 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001164 if not set_result:
1165 # TODO Not tested
1166 _raise_current_error()
1167
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001168 def get_serial_number(self):
1169 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001170 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001171
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001172 :return: The serial number.
1173 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001174 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001175 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1176 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001177 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001178 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001179 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001180 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001181 serial = int(hexstring_serial, 16)
1182 return serial
1183 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001184 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001185 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001186 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001187
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001188 def gmtime_adj_notAfter(self, amount):
1189 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001190 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001191
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001192 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001193 :type amount: :py:class:`int`
1194
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001195 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001196 """
1197 if not isinstance(amount, int):
1198 raise TypeError("amount must be an integer")
1199
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001200 notAfter = _lib.X509_get_notAfter(self._x509)
1201 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001202
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001203 def gmtime_adj_notBefore(self, amount):
1204 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001205 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001206
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001207 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001208 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001209 """
1210 if not isinstance(amount, int):
1211 raise TypeError("amount must be an integer")
1212
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001213 notBefore = _lib.X509_get_notBefore(self._x509)
1214 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001215
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001216 def has_expired(self):
1217 """
1218 Check whether the certificate has expired.
1219
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001220 :return: :py:const:`True` if the certificate has expired,
1221 :py:const:`False` otherwise.
1222 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001223 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001224 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001225 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001226
Paul Kehrerfde45c92016-01-21 12:57:37 -06001227 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001228
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001229 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001230 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001231
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001232 def get_notBefore(self):
1233 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001234 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001235
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001236 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001237
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001238 YYYYMMDDhhmmssZ
1239 YYYYMMDDhhmmss+hhmm
1240 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001241
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001242 :return: A timestamp string, or :py:const:`None` if there is none.
1243 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001244 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001245 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001246
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001247 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001248 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001249
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001250 def set_notBefore(self, when):
1251 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001252 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001253
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001254 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001255
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001256 YYYYMMDDhhmmssZ
1257 YYYYMMDDhhmmss+hhmm
1258 YYYYMMDDhhmmss-hhmm
1259
1260 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001261 :type when: :py:class:`bytes`
1262
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001263 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001264 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001265 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001266
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001267 def get_notAfter(self):
1268 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001269 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001270
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001271 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001272
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001273 YYYYMMDDhhmmssZ
1274 YYYYMMDDhhmmss+hhmm
1275 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001276
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001277 :return: A timestamp string, or :py:const:`None` if there is none.
1278 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001279 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001280 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001281
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001282 def set_notAfter(self, when):
1283 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001284 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001285
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001286 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001287
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001288 YYYYMMDDhhmmssZ
1289 YYYYMMDDhhmmss+hhmm
1290 YYYYMMDDhhmmss-hhmm
1291
1292 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001293 :type when: :py:class:`bytes`
1294
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001295 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001296 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001297 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001298
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001299 def _get_name(self, which):
1300 name = X509Name.__new__(X509Name)
1301 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001302 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001303 # TODO: This is untested.
1304 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001305
1306 # The name is owned by the X509 structure. As long as the X509Name
1307 # Python object is alive, keep the X509 Python object alive.
1308 name._owner = self
1309
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001310 return name
1311
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001312 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001313 if not isinstance(name, X509Name):
1314 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001315 set_result = which(self._x509, name._name)
1316 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001317 # TODO: This is untested.
1318 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001319
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001320 def get_issuer(self):
1321 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001322 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001323
Cory Benfielde6bcce82015-12-09 08:40:03 +00001324 This creates a new :class:`X509Name` that wraps the underlying issuer
1325 name field on the certificate. Modifying it will modify the underlying
1326 certificate, and will have the effect of modifying any other
1327 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001328
1329 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001330 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001331 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001332 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001333
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001334 def set_issuer(self, issuer):
1335 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001336 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001337
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001338 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001339 :type issuer: :py:class:`X509Name`
1340
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001341 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001342 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001343 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001344
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001345 def get_subject(self):
1346 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001347 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001348
Cory Benfielde6bcce82015-12-09 08:40:03 +00001349 This creates a new :class:`X509Name` that wraps the underlying subject
1350 name field on the certificate. Modifying it will modify the underlying
1351 certificate, and will have the effect of modifying any other
1352 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001353
1354 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001355 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001356 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001357 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001358
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001359 def set_subject(self, subject):
1360 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001361 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001362
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001363 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001364 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001365
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001366 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001367 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001368 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001369
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001370 def get_extension_count(self):
1371 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001372 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001373
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001374 :return: The number of extensions.
1375 :rtype: :py:class:`int`
1376
1377 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001378 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001379 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001380
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001381 def add_extensions(self, extensions):
1382 """
1383 Add extensions to the certificate.
1384
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001385 :param extensions: The extensions to add.
1386 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001387 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001388 """
1389 for ext in extensions:
1390 if not isinstance(ext, X509Extension):
1391 raise ValueError("One of the elements is not an X509Extension")
1392
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001393 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001394 if not add_result:
1395 _raise_current_error()
1396
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001397 def get_extension(self, index):
1398 """
1399 Get a specific extension of the certificate by index.
1400
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001401 Extensions on a certificate are kept in order. The index
1402 parameter selects which extension will be returned.
1403
1404 :param int index: The index of the extension to retrieve.
1405 :return: The extension at the specified index.
1406 :rtype: :py:class:`X509Extension`
1407 :raises IndexError: If the extension index was out of bounds.
1408
1409 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001410 """
1411 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001412 ext._extension = _lib.X509_get_ext(self._x509, index)
1413 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001414 raise IndexError("extension index out of bounds")
1415
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001416 extension = _lib.X509_EXTENSION_dup(ext._extension)
1417 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001418 return ext
1419
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001420
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001421X509Type = X509
1422
1423
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001424class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001425 """
1426 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001427 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001428
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001429 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001430 store = _lib.X509_STORE_new()
1431 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001432
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001433 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001434 """
1435 Adds the certificate :py:data:`cert` to this store.
1436
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001437 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001438
1439 :param X509 cert: The certificate to add to this store.
1440 :raises TypeError: If the certificate is not an :py:class:`X509`.
1441 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001442 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001443 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001444 if not isinstance(cert, X509):
1445 raise TypeError()
1446
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001447 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001448 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001449 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001450
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001451
1452X509StoreType = X509Store
1453
1454
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001455class X509StoreContextError(Exception):
1456 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001457 An exception raised when an error occurred while verifying a certificate
1458 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001459
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001460 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001461 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001462 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001463
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001464 def __init__(self, message, certificate):
1465 super(X509StoreContextError, self).__init__(message)
1466 self.certificate = certificate
1467
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001468
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001469class X509StoreContext(object):
1470 """
1471 An X.509 store context.
1472
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001473 An :py:class:`X509StoreContext` is used to define some of the criteria for
1474 certificate verification. The information encapsulated in this object
1475 includes, but is not limited to, a set of trusted certificates,
1476 verification parameters, and revoked certificates.
1477
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001478 .. note::
1479
1480 Currently, one can only set the trusted certificates on an
1481 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1482 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001483
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001484 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1485 instance. It is dynamically allocated and automatically garbage
1486 collected.
1487
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001488 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001489
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001490 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001491
1492 :param X509Store store: The certificates which will be trusted for the
1493 purposes of any verifications.
1494
1495 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001496 """
1497
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001498 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001499 store_ctx = _lib.X509_STORE_CTX_new()
1500 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1501 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001502 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001503 # Make the store context available for use after instantiating this
1504 # class by initializing it now. Per testing, subsequent calls to
1505 # :py:meth:`_init` have no adverse affect.
1506 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001507
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001508 def _init(self):
1509 """
1510 Set up the store context for a subsequent verification operation.
1511 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001512 ret = _lib.X509_STORE_CTX_init(
1513 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1514 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001515 if ret <= 0:
1516 _raise_current_error()
1517
1518 def _cleanup(self):
1519 """
1520 Internally cleans up the store context.
1521
1522 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001523 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001524 """
1525 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1526
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001527 def _exception_from_context(self):
1528 """
1529 Convert an OpenSSL native context error failure into a Python
1530 exception.
1531
Alex Gaynor5945ea82015-09-05 14:59:06 -04001532 When a call to native OpenSSL X509_verify_cert fails, additional
1533 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001534 """
1535 errors = [
1536 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1537 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1538 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001539 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001540 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001541 # A context error should always be associated with a certificate, so we
1542 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001543 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001544 _cert = _lib.X509_dup(_x509)
1545 pycert = X509.__new__(X509)
1546 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001547 return X509StoreContextError(errors, pycert)
1548
Stephen Holsapple46a09252015-02-12 14:45:43 -08001549 def set_store(self, store):
1550 """
1551 Set the context's trust store.
1552
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001553 .. versionadded:: 0.15
1554
Stephen Holsapple46a09252015-02-12 14:45:43 -08001555 :param X509Store store: The certificates which will be trusted for the
1556 purposes of any *future* verifications.
1557 """
1558 self._store = store
1559
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001560 def verify_certificate(self):
1561 """
1562 Verify a certificate in a context.
1563
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001564 .. versionadded:: 0.15
1565
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001566 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001567
Alex Gaynorca87ff62015-09-04 23:31:03 -04001568 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001569 certificate in the context. Sets ``certificate`` attribute to
1570 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001571 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001572 # Always re-initialize the store context in case
1573 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001574 self._init()
1575 ret = _lib.X509_verify_cert(self._store_ctx)
1576 self._cleanup()
1577 if ret <= 0:
1578 raise self._exception_from_context()
1579
1580
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001581def load_certificate(type, buffer):
1582 """
1583 Load a certificate from a buffer
1584
1585 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1586
1587 :param buffer: The buffer the certificate is stored in
1588 :type buffer: :py:class:`bytes`
1589
1590 :return: The X509 object
1591 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001592 if isinstance(buffer, _text_type):
1593 buffer = buffer.encode("ascii")
1594
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001595 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001596
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001597 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001598 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001599 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001600 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001601 else:
1602 raise ValueError(
1603 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001604
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001605 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001606 _raise_current_error()
1607
1608 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001609 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001610 return cert
1611
1612
1613def dump_certificate(type, cert):
1614 """
1615 Dump a certificate to a buffer
1616
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001617 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1618 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001619 :param cert: The certificate to dump
1620 :return: The buffer with the dumped certificate in
1621 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001622 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001623
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001624 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001625 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001626 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001627 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001628 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001629 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001630 else:
1631 raise ValueError(
1632 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1633 "FILETYPE_TEXT")
1634
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001635 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001636 return _bio_to_string(bio)
1637
1638
Cory Benfield6492f7c2015-10-27 16:57:58 +09001639def dump_publickey(type, pkey):
1640 """
Cory Benfield11c10192015-10-27 17:23:03 +09001641 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001642
Cory Benfield9c590b92015-10-28 14:55:05 +09001643 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001644 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001645 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001646 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001647 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001648 """
1649 bio = _new_mem_buf()
1650 if type == FILETYPE_PEM:
1651 write_bio = _lib.PEM_write_bio_PUBKEY
1652 elif type == FILETYPE_ASN1:
1653 write_bio = _lib.i2d_PUBKEY_bio
1654 else:
1655 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1656
1657 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001658 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001659 _raise_current_error()
1660
1661 return _bio_to_string(bio)
1662
1663
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001664def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1665 """
1666 Dump a private key to a buffer
1667
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001668 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1669 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001670 :param pkey: The PKey to dump
1671 :param cipher: (optional) if encrypted PEM format, the cipher to
1672 use
1673 :param passphrase: (optional) if encrypted PEM format, this can be either
1674 the passphrase to use, or a callback for providing the
1675 passphrase.
1676 :return: The buffer with the dumped key in
Maximilian Hils0de43752015-09-18 15:26:54 +02001677 :rtype: :py:data:`bytes`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001678 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001679 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001680
1681 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001682 if passphrase is None:
1683 raise TypeError(
1684 "if a value is given for cipher "
1685 "one must also be given for passphrase")
1686 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001687 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001688 raise ValueError("Invalid cipher name")
1689 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001690 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001691
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001692 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001693 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001694 result_code = _lib.PEM_write_bio_PrivateKey(
1695 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001696 helper.callback, helper.callback_args)
1697 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001698 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001699 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001700 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001701 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1702 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001703 # TODO RSA_free(rsa)?
1704 else:
1705 raise ValueError(
1706 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1707 "FILETYPE_TEXT")
1708
1709 if result_code == 0:
1710 _raise_current_error()
1711
1712 return _bio_to_string(bio)
1713
1714
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001715def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001716 copy = _lib.X509_REVOKED_new()
1717 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001718 # TODO: This is untested.
1719 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001720
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001721 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001722 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001723 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001724
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001725 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001726 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001727 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001728
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001729 if original.extensions != _ffi.NULL:
1730 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1731 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1732 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1733 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1734 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001735 copy.extensions = extension_stack
1736
1737 copy.sequence = original.sequence
1738 return copy
1739
1740
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001741class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001742 """
1743 A certificate revocation.
1744 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001745 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1746 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1747 # OCSP_crl_reason_str. We use the latter, just like the command line
1748 # program.
1749 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001750 b"unspecified",
1751 b"keyCompromise",
1752 b"CACompromise",
1753 b"affiliationChanged",
1754 b"superseded",
1755 b"cessationOfOperation",
1756 b"certificateHold",
1757 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001758 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001759
1760 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001761 revoked = _lib.X509_REVOKED_new()
1762 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001763
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001764 def set_serial(self, hex_str):
1765 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001766 Set the serial number.
1767
1768 The serial number is formatted as a hexadecimal number encoded in
1769 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001770
1771 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001772 :type hex_str: :py:class:`bytes`
1773
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001774 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001775 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001776 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1777 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001778 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001779 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001780 if not bn_result:
1781 raise ValueError("bad hex string")
1782
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001783 asn1_serial = _ffi.gc(
1784 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1785 _lib.ASN1_INTEGER_free)
1786 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001787
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001788 def get_serial(self):
1789 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001790 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001791
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001792 The serial number is formatted as a hexadecimal number encoded in
1793 ASCII.
1794
1795 :return: The serial number.
1796 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001797 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001798 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001799
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001800 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001801 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001802 # TODO: This is untested.
1803 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001804
1805 return _bio_to_string(bio)
1806
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807 def _delete_reason(self):
1808 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001809 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1810 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1811 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1812 _lib.X509_EXTENSION_free(ext)
1813 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001814 break
1815
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001816 def set_reason(self, reason):
1817 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001818 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001819
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001820 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001821
1822 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001823 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1824
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001825 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001826
1827 .. seealso::
1828
1829 :py:meth:`all_reasons`, which gives you a list of all supported
1830 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001831 """
1832 if reason is None:
1833 self._delete_reason()
1834 elif not isinstance(reason, bytes):
1835 raise TypeError("reason must be None or a byte string")
1836 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001837 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001838 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1839
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001840 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1841 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001842 # TODO: This is untested.
1843 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001844 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001845
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001846 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1847 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001848 # TODO: This is untested.
1849 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001850
1851 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001852 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1853 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001854
1855 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001856 # TODO: This is untested.
1857 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001858
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001859 def get_reason(self):
1860 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001861 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001862
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001863 :return: The reason, or :py:const:`None` if there is none.
1864 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1865
1866 .. seealso::
1867
1868 :py:meth:`all_reasons`, which gives you a list of all supported
1869 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001870 """
1871 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001872 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1873 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1874 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001875 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001876
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001877 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001878 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001879 print_result = _lib.M_ASN1_OCTET_STRING_print(
1880 bio, ext.value
1881 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001882 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001883 # TODO: This is untested.
1884 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001885
1886 return _bio_to_string(bio)
1887
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001888 def all_reasons(self):
1889 """
1890 Return a list of all the supported reason strings.
1891
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001892 This list is a copy; modifying it does not change the supported reason
1893 strings.
1894
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001895 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001896 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001897 """
1898 return self._crl_reasons[:]
1899
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001900 def set_rev_date(self, when):
1901 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001902 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001903
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001904 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1905 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001906 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001907 """
1908 return _set_asn1_time(self._revoked.revocationDate, when)
1909
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001910 def get_rev_date(self):
1911 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001912 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001913
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001914 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1915 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001916 """
1917 return _get_asn1_time(self._revoked.revocationDate)
1918
1919
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001920class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001921 """
1922 A certificate revocation list.
1923 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001924
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001925 def __init__(self):
1926 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001927 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001928 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001929 crl = _lib.X509_CRL_new()
1930 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001931
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001932 def get_revoked(self):
1933 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001934 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001935
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001936 These revocations will be provided by value, not by reference.
1937 That means it's okay to mutate them: it won't affect this CRL.
1938
1939 :return: The revocations in this CRL.
1940 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001941 """
1942 results = []
1943 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001944 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1945 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001946 revoked_copy = _X509_REVOKED_dup(revoked)
1947 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001948 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001949 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001950 if results:
1951 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001952
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001953 def add_revoked(self, revoked):
1954 """
1955 Add a revoked (by value not reference) to the CRL structure
1956
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001957 This revocation will be added by value, not by reference. That
1958 means it's okay to mutate it after adding: it won't affect
1959 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001960
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001961 :param revoked: The new revocation.
1962 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001963
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001964 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001965 """
1966 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001967 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001968 # TODO: This is untested.
1969 _raise_current_error()
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
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001976 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001977 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001978 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001979 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001980
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001981 :param cert: The certificate used to sign the CRL.
1982 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001983
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001984 :param key: The key used to sign the CRL.
1985 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001986
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001987 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1988 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001989
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001990 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001991
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001992 :param bytes digest: The name of the message digest to use (eg
1993 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001994
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001995 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001996 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001997 if not isinstance(cert, X509):
1998 raise TypeError("cert must be an X509 instance")
1999 if not isinstance(key, PKey):
2000 raise TypeError("key must be a PKey instance")
2001 if not isinstance(type, int):
2002 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002003
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002004 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002005 _warn(
2006 "The default message digest (md5) is deprecated. "
2007 "Pass the name of a message digest explicitly.",
2008 category=DeprecationWarning,
2009 stacklevel=2,
2010 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002011 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002012
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002013 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002014 if digest_obj == _ffi.NULL:
2015 raise ValueError("No such digest method")
2016
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002017 bio = _lib.BIO_new(_lib.BIO_s_mem())
2018 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002019 # TODO: This is untested.
2020 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002021
Alex Gaynora738ed52015-09-05 11:17:10 -04002022 # A scratch time object to give different values to different CRL
2023 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002024 sometime = _lib.ASN1_TIME_new()
2025 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002026 # TODO: This is untested.
2027 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002028
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002029 _lib.X509_gmtime_adj(sometime, 0)
2030 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002031
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002032 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2033 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002034
Alex Gaynor5945ea82015-09-05 14:59:06 -04002035 _lib.X509_CRL_set_issuer_name(
2036 self._crl, _lib.X509_get_subject_name(cert._x509)
2037 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002038
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002039 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002040 if not sign_result:
2041 _raise_current_error()
2042
Dominic Chenf05b2122015-10-13 16:32:35 +00002043 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002044
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002045
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002046CRLType = CRL
2047
2048
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002049class PKCS7(object):
2050 def type_is_signed(self):
2051 """
2052 Check if this NID_pkcs7_signed object
2053
2054 :return: True if the PKCS7 is of type signed
2055 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002056 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002057 return True
2058 return False
2059
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002060 def type_is_enveloped(self):
2061 """
2062 Check if this NID_pkcs7_enveloped object
2063
2064 :returns: True if the PKCS7 is of type enveloped
2065 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002066 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002067 return True
2068 return False
2069
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002070 def type_is_signedAndEnveloped(self):
2071 """
2072 Check if this NID_pkcs7_signedAndEnveloped object
2073
2074 :returns: True if the PKCS7 is of type signedAndEnveloped
2075 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002076 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002077 return True
2078 return False
2079
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002080 def type_is_data(self):
2081 """
2082 Check if this NID_pkcs7_data object
2083
2084 :return: True if the PKCS7 is of type data
2085 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002086 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002087 return True
2088 return False
2089
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002090 def get_type_name(self):
2091 """
2092 Returns the type name of the PKCS7 structure
2093
2094 :return: A string with the typename
2095 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002096 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2097 string_type = _lib.OBJ_nid2sn(nid)
2098 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002099
2100PKCS7Type = PKCS7
2101
2102
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002103class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002104 """
2105 A PKCS #12 archive.
2106 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002107
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002108 def __init__(self):
2109 self._pkey = None
2110 self._cert = None
2111 self._cacerts = None
2112 self._friendlyname = None
2113
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002114 def get_certificate(self):
2115 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002116 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002117
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002118 :return: The certificate, or :py:const:`None` if there is none.
2119 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002120 """
2121 return self._cert
2122
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002123 def set_certificate(self, cert):
2124 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002125 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002126
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002127 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002128 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002129
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002130 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002131 """
2132 if not isinstance(cert, X509):
2133 raise TypeError("cert must be an X509 instance")
2134 self._cert = cert
2135
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002136 def get_privatekey(self):
2137 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002138 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002139
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002140 :return: The private key, or :py:const:`None` if there is none.
2141 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002142 """
2143 return self._pkey
2144
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002145 def set_privatekey(self, pkey):
2146 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002147 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002148
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002149 :param pkey: The new private key, or :py:const:`None` to unset it.
2150 :type pkey: :py:class:`PKey` or :py:const:`None`
2151
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002152 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002153 """
2154 if not isinstance(pkey, PKey):
2155 raise TypeError("pkey must be a PKey instance")
2156 self._pkey = pkey
2157
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002158 def get_ca_certificates(self):
2159 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002160 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002161
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002162 :return: A tuple with the CA certificates in the chain, or
2163 :py:const:`None` if there are none.
2164 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002165 """
2166 if self._cacerts is not None:
2167 return tuple(self._cacerts)
2168
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002169 def set_ca_certificates(self, cacerts):
2170 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002171 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002172
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002173 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2174 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002175 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002176
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002177 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002178 """
2179 if cacerts is None:
2180 self._cacerts = None
2181 else:
2182 cacerts = list(cacerts)
2183 for cert in cacerts:
2184 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002185 raise TypeError(
2186 "iterable must only contain X509 instances"
2187 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002188 self._cacerts = cacerts
2189
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002190 def set_friendlyname(self, name):
2191 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002192 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002193
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002194 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002195 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002196
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002197 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002198 """
2199 if name is None:
2200 self._friendlyname = None
2201 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002202 raise TypeError(
2203 "name must be a byte string or None (not %r)" % (name,)
2204 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002205 self._friendlyname = name
2206
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002207 def get_friendlyname(self):
2208 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002209 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002210
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002211 :returns: The friendly name, or :py:const:`None` if there is none.
2212 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002213 """
2214 return self._friendlyname
2215
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002216 def export(self, passphrase=None, iter=2048, maciter=1):
2217 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002218 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002219
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002220 For more information, see the :c:func:`PKCS12_create` man page.
2221
2222 :param passphrase: The passphrase used to encrypt the structure. Unlike
2223 some other passphrase arguments, this *must* be a string, not a
2224 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002225 :type passphrase: :py:data:`bytes`
2226
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002227 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002228 :type iter: :py:data:`int`
2229
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002230 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002231 :type maciter: :py:data:`int`
2232
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002233 :return: The string representation of the PKCS #12 structure.
2234 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002235 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002236 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002237
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002238 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002239 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002240 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002241 cacerts = _lib.sk_X509_new_null()
2242 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002243 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002244 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002245
2246 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002247 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002248
2249 friendlyname = self._friendlyname
2250 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002251 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002252
2253 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002254 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002255 else:
2256 pkey = self._pkey._pkey
2257
2258 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002259 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002260 else:
2261 cert = self._cert._x509
2262
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002263 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002264 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002265 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2266 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002267 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002268 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002269 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002270 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002271
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002272 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002273 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002274 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002275
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002276
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002277PKCS12Type = PKCS12
2278
2279
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002280class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002281 """
2282 A Netscape SPKI object.
2283 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002284
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002285 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002286 spki = _lib.NETSCAPE_SPKI_new()
2287 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002288
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002289 def sign(self, pkey, digest):
2290 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002291 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002292
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002293 :param pkey: The private key to sign with.
2294 :type pkey: :py:class:`PKey`
2295
2296 :param digest: The message digest to use.
2297 :type digest: :py:class:`bytes`
2298
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002299 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002300 """
2301 if pkey._only_public:
2302 raise ValueError("Key has only public part")
2303
2304 if not pkey._initialized:
2305 raise ValueError("Key is uninitialized")
2306
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002307 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002308 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002309 raise ValueError("No such digest method")
2310
Alex Gaynor5945ea82015-09-05 14:59:06 -04002311 sign_result = _lib.NETSCAPE_SPKI_sign(
2312 self._spki, pkey._pkey, digest_obj
2313 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002314 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002315 # TODO: This is untested.
2316 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002317
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002318 def verify(self, key):
2319 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002320 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002321
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002322 :param key: The public key that signature is supposedly from.
2323 :type pkey: :py:class:`PKey`
2324
2325 :return: :py:const:`True` if the signature is correct.
2326 :rtype: :py:class:`bool`
2327
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002328 :raises Error: If the signature is invalid, or there was a problem
2329 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002330 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002331 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002332 if answer <= 0:
2333 _raise_current_error()
2334 return True
2335
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002336 def b64_encode(self):
2337 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002338 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002339
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002340 :return: The base64 encoded string.
2341 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002342 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002343 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2344 result = _ffi.string(encoded)
2345 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002346 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002347
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002348 def get_pubkey(self):
2349 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002350 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002351
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002352 :return: The public key.
2353 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002354 """
2355 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002356 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2357 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002358 # TODO: This is untested.
2359 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002360 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002361 pkey._only_public = True
2362 return pkey
2363
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002364 def set_pubkey(self, pkey):
2365 """
2366 Set the public key of the certificate
2367
2368 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002369 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002370 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002371 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002372 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002373 # TODO: This is untested.
2374 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002375
2376
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002377NetscapeSPKIType = NetscapeSPKI
2378
2379
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002380class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002381 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002382 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002383 raise ValueError(
2384 "only FILETYPE_PEM key format supports encryption"
2385 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002386 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002387 self._more_args = more_args
2388 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002389 self._problems = []
2390
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002391 @property
2392 def callback(self):
2393 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002394 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002395 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002396 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002397 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002398 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002399 else:
2400 raise TypeError("Last argument must be string or callable")
2401
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002402 @property
2403 def callback_args(self):
2404 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002405 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002406 elif isinstance(self._passphrase, bytes):
2407 return self._passphrase
2408 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002409 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002410 else:
2411 raise TypeError("Last argument must be string or callable")
2412
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002413 def raise_if_problem(self, exceptionType=Error):
2414 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002415 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002416 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002417 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002418 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002419 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002420 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002421
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002422 def _read_passphrase(self, buf, size, rwflag, userdata):
2423 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002424 if self._more_args:
2425 result = self._passphrase(size, rwflag, userdata)
2426 else:
2427 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002428 if not isinstance(result, bytes):
2429 raise ValueError("String expected")
2430 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002431 if self._truncate:
2432 result = result[:size]
2433 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002434 raise ValueError(
2435 "passphrase returned by callback is too long"
2436 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002437 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002438 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002439 return len(result)
2440 except Exception as e:
2441 self._problems.append(e)
2442 return 0
2443
2444
Cory Benfield6492f7c2015-10-27 16:57:58 +09002445def load_publickey(type, buffer):
2446 """
Cory Benfield11c10192015-10-27 17:23:03 +09002447 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002448
Cory Benfield9c590b92015-10-28 14:55:05 +09002449 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002450 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002451 :param buffer: The buffer the key is stored in.
2452 :type buffer: A Python string object, either unicode or bytestring.
2453 :return: The PKey object.
2454 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002455 """
2456 if isinstance(buffer, _text_type):
2457 buffer = buffer.encode("ascii")
2458
2459 bio = _new_mem_buf(buffer)
2460
2461 if type == FILETYPE_PEM:
2462 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2463 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2464 elif type == FILETYPE_ASN1:
2465 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2466 else:
2467 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2468
2469 if evp_pkey == _ffi.NULL:
2470 _raise_current_error()
2471
2472 pkey = PKey.__new__(PKey)
2473 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
2474 return pkey
2475
2476
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002477def load_privatekey(type, buffer, passphrase=None):
2478 """
2479 Load a private key from a buffer
2480
2481 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2482 :param buffer: The buffer the key is stored in
2483 :param passphrase: (optional) if encrypted PEM format, this can be
2484 either the passphrase to use, or a callback for
2485 providing the passphrase.
2486
2487 :return: The PKey object
2488 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002489 if isinstance(buffer, _text_type):
2490 buffer = buffer.encode("ascii")
2491
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002492 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002493
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002494 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002495 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002496 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2497 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002498 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002499 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002500 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002501 else:
2502 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2503
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002504 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002505 _raise_current_error()
2506
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002507 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002508 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002509 return pkey
2510
2511
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002512def dump_certificate_request(type, req):
2513 """
2514 Dump a certificate request to a buffer
2515
2516 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2517 :param req: The certificate request to dump
2518 :return: The buffer with the dumped certificate request in
2519 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002520 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002521
2522 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002523 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002524 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002525 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002526 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002527 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002528 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002529 raise ValueError(
2530 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2531 "FILETYPE_TEXT"
2532 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002533
2534 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002535 # TODO: This is untested.
2536 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002537
2538 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002539
2540
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002541def load_certificate_request(type, buffer):
2542 """
2543 Load a certificate request from a buffer
2544
2545 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2546 :param buffer: The buffer the certificate request is stored in
2547 :return: The X509Req object
2548 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002549 if isinstance(buffer, _text_type):
2550 buffer = buffer.encode("ascii")
2551
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002552 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002553
2554 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002555 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002556 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002557 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002558 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002559 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002560
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002561 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002562 # TODO: This is untested.
2563 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002564
2565 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002566 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002567 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002568
2569
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002570def sign(pkey, data, digest):
2571 """
2572 Sign data with a digest
2573
2574 :param pkey: Pkey to sign with
2575 :param data: data to be signed
2576 :param digest: message digest to use
2577 :return: signature
2578 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002579 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002580
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002581 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002582 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002583 raise ValueError("No such digest method")
2584
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002585 md_ctx = _ffi.new("EVP_MD_CTX*")
2586 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002587
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002588 _lib.EVP_SignInit(md_ctx, digest_obj)
2589 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002590
Colleen Murphye09399b2016-03-01 17:40:49 -08002591 pkey_length = (PKey.bits(pkey) + 7) // 8
2592 signature_buffer = _ffi.new("unsigned char[]", pkey_length)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002593 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002594 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002595 md_ctx, signature_buffer, signature_length, pkey._pkey)
2596
2597 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002598 # TODO: This is untested.
2599 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002600
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002601 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002602
2603
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002604def verify(cert, signature, data, digest):
2605 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002606 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002607
2608 :param cert: signing certificate (X509 object)
2609 :param signature: signature returned by sign function
2610 :param data: data to be verified
2611 :param digest: message digest to use
Alex Gaynor5945ea82015-09-05 14:59:06 -04002612 :return: :py:const:`None` if the signature is correct, raise exception
2613 otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002614 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002615 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002616
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002617 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002618 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002619 raise ValueError("No such digest method")
2620
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002621 pkey = _lib.X509_get_pubkey(cert._x509)
2622 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002623 # TODO: This is untested.
2624 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002625 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002626
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002627 md_ctx = _ffi.new("EVP_MD_CTX*")
2628 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002629
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002630 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2631 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002632 verify_result = _lib.EVP_VerifyFinal(
2633 md_ctx, signature, len(signature), pkey
2634 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002635
2636 if verify_result != 1:
2637 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002638
2639
Dominic Chenf05b2122015-10-13 16:32:35 +00002640def dump_crl(type, crl):
2641 """
2642 Dump a certificate revocation list to a buffer.
2643
2644 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2645 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002646 :param CRL crl: The CRL to dump.
2647
Dominic Chenf05b2122015-10-13 16:32:35 +00002648 :return: The buffer with the CRL.
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002649 :rtype: :data:`bytes`
Dominic Chenf05b2122015-10-13 16:32:35 +00002650 """
2651 bio = _new_mem_buf()
2652
2653 if type == FILETYPE_PEM:
2654 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2655 elif type == FILETYPE_ASN1:
2656 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2657 elif type == FILETYPE_TEXT:
2658 ret = _lib.X509_CRL_print(bio, crl._crl)
2659 else:
2660 raise ValueError(
2661 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2662 "FILETYPE_TEXT")
2663
2664 assert ret == 1
2665 return _bio_to_string(bio)
2666
2667
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002668def load_crl(type, buffer):
2669 """
2670 Load a certificate revocation list from a buffer
2671
2672 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2673 :param buffer: The buffer the CRL is stored in
2674
2675 :return: The PKey object
2676 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002677 if isinstance(buffer, _text_type):
2678 buffer = buffer.encode("ascii")
2679
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002680 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002681
2682 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002683 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002684 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002685 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002686 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002687 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2688
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002689 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002690 _raise_current_error()
2691
2692 result = CRL.__new__(CRL)
2693 result._crl = crl
2694 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002695
2696
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002697def load_pkcs7_data(type, buffer):
2698 """
2699 Load pkcs7 data from a buffer
2700
2701 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2702 :param buffer: The buffer with the pkcs7 data.
2703 :return: The PKCS7 object
2704 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002705 if isinstance(buffer, _text_type):
2706 buffer = buffer.encode("ascii")
2707
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002708 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002709
2710 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002711 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002712 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002713 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002714 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002715 # TODO: This is untested.
2716 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002717 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2718
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002719 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002720 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002721
2722 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002723 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002724 return pypkcs7
2725
2726
Stephen Holsapple38482622014-04-05 20:29:34 -07002727def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002728 """
2729 Load a PKCS12 object from a buffer
2730
2731 :param buffer: The buffer the certificate is stored in
2732 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2733 :returns: The PKCS12 object
2734 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002735 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002736
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002737 if isinstance(buffer, _text_type):
2738 buffer = buffer.encode("ascii")
2739
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002740 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002741
Stephen Holsapple38482622014-04-05 20:29:34 -07002742 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2743 # password based encryption no password and a zero length password are two
2744 # different things, but OpenSSL implementation will try both to figure out
2745 # which one works.
2746 if not passphrase:
2747 passphrase = _ffi.NULL
2748
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002749 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2750 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002751 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002752 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002753
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002754 pkey = _ffi.new("EVP_PKEY**")
2755 cert = _ffi.new("X509**")
2756 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002757
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002758 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002759 if not parse_result:
2760 _raise_current_error()
2761
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002762 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002763
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002764 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2765 # queue for no particular reason. This error isn't interesting to anyone
2766 # outside this function. It's not even interesting to us. Get rid of it.
2767 try:
2768 _raise_current_error()
2769 except Error:
2770 pass
2771
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002772 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002773 pykey = None
2774 else:
2775 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002776 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002777
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002778 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002779 pycert = None
2780 friendlyname = None
2781 else:
2782 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002783 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002784
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002785 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002786 friendlyname_buffer = _lib.X509_alias_get0(
2787 cert[0], friendlyname_length
2788 )
2789 friendlyname = _ffi.buffer(
2790 friendlyname_buffer, friendlyname_length[0]
2791 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002792 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002793 friendlyname = None
2794
2795 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002796 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002797 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002798 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002799 pycacerts.append(pycacert)
2800 if not pycacerts:
2801 pycacerts = None
2802
2803 pkcs12 = PKCS12.__new__(PKCS12)
2804 pkcs12._pkey = pykey
2805 pkcs12._cert = pycert
2806 pkcs12._cacerts = pycacerts
2807 pkcs12._friendlyname = friendlyname
2808 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002809
2810
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002811# There are no direct unit tests for this initialization. It is tested
2812# indirectly since it is necessary for functions like dump_privatekey when
2813# using encryption.
2814#
2815# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2816# and some other similar tests may fail without this (though they may not if
2817# the Python runtime has already done some initialization of the underlying
2818# OpenSSL library (and is linked against the same one that cryptography is
2819# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002820_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002821
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002822# This is similar but exercised mainly by exception_from_error_queue. It calls
2823# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2824_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002825
2826
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002827# Set the default string mask to match OpenSSL upstream (since 2005) and
2828# RFC5280 recommendations.
2829_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')