blob: 6d78bd76c34d4cb736d5aee9c59337616793abfd [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:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500220 dsa = _lib.DSA_generate_parameters(
221 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
222 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500223 # TODO: This is untested.
224 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500225 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500226 # TODO: This is untested.
227 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500228 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500229 # TODO: This is untested.
230 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800231 else:
232 raise Error("No such key type")
233
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800234 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800235
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800236 def check(self):
237 """
238 Check the consistency of an RSA private key.
239
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200240 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
241
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800242 :return: True if key is consistent.
243 :raise Error: if the key is inconsistent.
244 :raise TypeError: if the key is of a type which cannot be checked.
245 Only RSA keys can currently be checked.
246 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800247 if self._only_public:
248 raise TypeError("public key only")
249
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100250 if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800251 raise TypeError("key type unsupported")
252
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500253 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
254 rsa = _ffi.gc(rsa, _lib.RSA_free)
255 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800256 if result:
257 return True
258 _raise_current_error()
259
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800260 def type(self):
261 """
262 Returns the type of the key
263
264 :return: The type of the key.
265 """
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100266 try:
267 # cryptography 1.2+
268 return _lib.Cryptography_EVP_PKEY_id(self._pkey)
269 except AttributeError:
270 # Older releases of cryptography.
271 return self._pkey.type
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800272
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800273 def bits(self):
274 """
275 Returns the number of bits of the key
276
277 :return: The number of bits of the key.
278 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500279 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800280PKeyType = PKey
281
282
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400283class _EllipticCurve(object):
284 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400285 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400286
287 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
288 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
289 instances each of which represents one curve supported by the system.
290 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400291 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400292 _curves = None
293
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400294 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400295 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400296 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400297 """
298 Implement cooperation with the right-hand side argument of ``!=``.
299
300 Python 3 seems to have dropped this cooperation in this very narrow
301 circumstance.
302 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400303 if isinstance(other, _EllipticCurve):
304 return super(_EllipticCurve, self).__ne__(other)
305 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400306
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400307 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400308 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400309 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400310 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400311
312 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400313
314 :return: A :py:type:`set` of ``cls`` instances giving the names of the
315 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400316 """
317 if lib.Cryptography_HAS_EC:
318 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
319 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400320 # The return value on this call should be num_curves again. We
321 # could check it to make sure but if it *isn't* then.. what could
322 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400323 lib.EC_get_builtin_curves(builtin_curves, num_curves)
324 return set(
325 cls.from_nid(lib, c.nid)
326 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400327 return set()
328
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400329 @classmethod
330 def _get_elliptic_curves(cls, lib):
331 """
332 Get, cache, and return the curves supported by OpenSSL.
333
334 :param lib: The OpenSSL library binding object.
335
336 :return: A :py:type:`set` of ``cls`` instances giving the names of the
337 elliptic curves the underlying library supports.
338 """
339 if cls._curves is None:
340 cls._curves = cls._load_elliptic_curves(lib)
341 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400342
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400343 @classmethod
344 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400345 """
346 Instantiate a new :py:class:`_EllipticCurve` associated with the given
347 OpenSSL NID.
348
349 :param lib: The OpenSSL library binding object.
350
351 :param nid: The OpenSSL NID the resulting curve object will represent.
352 This must be a curve NID (and not, for example, a hash NID) or
353 subsequent operations will fail in unpredictable ways.
354 :type nid: :py:class:`int`
355
356 :return: The curve object.
357 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400358 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
359
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400360 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400361 """
362 :param _lib: The :py:mod:`cryptography` binding instance used to
363 interface with OpenSSL.
364
365 :param _nid: The OpenSSL NID identifying the curve this object
366 represents.
367 :type _nid: :py:class:`int`
368
369 :param name: The OpenSSL short name identifying the curve this object
370 represents.
371 :type name: :py:class:`unicode`
372 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400373 self._lib = lib
374 self._nid = nid
375 self.name = name
376
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400377 def __repr__(self):
378 return "<Curve %r>" % (self.name,)
379
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400380 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400381 """
382 Create a new OpenSSL EC_KEY structure initialized to use this curve.
383
384 The structure is automatically garbage collected when the Python object
385 is garbage collected.
386 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400387 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
388 return _ffi.gc(key, _lib.EC_KEY_free)
389
390
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400391def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400392 """
393 Return a set of objects representing the elliptic curves supported in the
394 OpenSSL build in use.
395
396 The curve objects have a :py:class:`unicode` ``name`` attribute by which
397 they identify themselves.
398
399 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400400 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
401 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400402 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400403 return _EllipticCurve._get_elliptic_curves(_lib)
404
405
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400406def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400407 """
408 Return a single curve object selected by name.
409
410 See :py:func:`get_elliptic_curves` for information about curve objects.
411
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400412 :param name: The OpenSSL short name identifying the curve object to
413 retrieve.
414 :type name: :py:class:`unicode`
415
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400416 If the named curve is not supported then :py:class:`ValueError` is raised.
417 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400418 for curve in get_elliptic_curves():
419 if curve.name == name:
420 return curve
421 raise ValueError("unknown curve name", name)
422
423
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800424class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200425 """
426 An X.509 Distinguished Name.
427
428 :ivar countryName: The country of the entity.
429 :ivar C: Alias for :py:attr:`countryName`.
430
431 :ivar stateOrProvinceName: The state or province of the entity.
432 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
433
434 :ivar localityName: The locality of the entity.
435 :ivar L: Alias for :py:attr:`localityName`.
436
437 :ivar organizationName: The organization name of the entity.
438 :ivar O: Alias for :py:attr:`organizationName`.
439
440 :ivar organizationalUnitName: The organizational unit of the entity.
441 :ivar OU: Alias for :py:attr:`organizationalUnitName`
442
443 :ivar commonName: The common name of the entity.
444 :ivar CN: Alias for :py:attr:`commonName`.
445
446 :ivar emailAddress: The e-mail address of the entity.
447 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400448
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800449 def __init__(self, name):
450 """
451 Create a new X509Name, copying the given X509Name instance.
452
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200453 :param name: The name to copy.
454 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800455 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500456 name = _lib.X509_NAME_dup(name._name)
457 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800458
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800459 def __setattr__(self, name, value):
460 if name.startswith('_'):
461 return super(X509Name, self).__setattr__(name, value)
462
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800463 # Note: we really do not want str subclasses here, so we do not use
464 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800465 if type(name) is not str:
466 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400467 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800468
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500469 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500470 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800471 try:
472 _raise_current_error()
473 except Error:
474 pass
475 raise AttributeError("No such attribute")
476
477 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500478 for i in range(_lib.X509_NAME_entry_count(self._name)):
479 ent = _lib.X509_NAME_get_entry(self._name, i)
480 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
481 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800482 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500483 ent = _lib.X509_NAME_delete_entry(self._name, i)
484 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800485 break
486
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500487 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800488 value = value.encode('utf-8')
489
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500490 add_result = _lib.X509_NAME_add_entry_by_NID(
491 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800492 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500493 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800494
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800495 def __getattr__(self, name):
496 """
497 Find attribute. An X509Name object has the following attributes:
498 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400499 organization (alias O), organizationalUnit (alias OU), commonName
500 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800501 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500502 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500503 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800504 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
505 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
506 # push something onto the error queue. If we don't clean that up
507 # now, someone else will bump into it later and be quite confused.
508 # See lp#314814.
509 try:
510 _raise_current_error()
511 except Error:
512 pass
513 return super(X509Name, self).__getattr__(name)
514
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500515 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800516 if entry_index == -1:
517 return None
518
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500519 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
520 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800521
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500522 result_buffer = _ffi.new("unsigned char**")
523 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800524 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500525 # TODO: This is untested.
526 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800527
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700528 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400529 result = _ffi.buffer(
530 result_buffer[0], data_length
531 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700532 finally:
533 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500534 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800535 return result
536
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500537 def _cmp(op):
538 def f(self, other):
539 if not isinstance(other, X509Name):
540 return NotImplemented
541 result = _lib.X509_NAME_cmp(self._name, other._name)
542 return op(result, 0)
543 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800544
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500545 __eq__ = _cmp(__eq__)
546 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800547
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500548 __lt__ = _cmp(__lt__)
549 __le__ = _cmp(__le__)
550
551 __gt__ = _cmp(__gt__)
552 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800553
554 def __repr__(self):
555 """
556 String representation of an X509Name
557 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400558 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500559 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800560 self._name, result_buffer, len(result_buffer))
561
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500562 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500563 # TODO: This is untested.
564 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800565
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500566 return "<X509Name object '%s'>" % (
567 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800568
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800569 def hash(self):
570 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200571 Return an integer representation of the first four bytes of the
572 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800573
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200574 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
575
576 :return: The (integer) hash of this name.
577 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800578 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500579 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800580
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800581 def der(self):
582 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200583 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800584
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200585 :return: The DER encoded form of this name.
586 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800587 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500588 result_buffer = _ffi.new('unsigned char**')
589 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800590 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500591 # TODO: This is untested.
592 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800593
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500594 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
595 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800596 return string_result
597
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800598 def get_components(self):
599 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200600 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800601
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200602 :return: The components of this name.
603 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800604 """
605 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500606 for i in range(_lib.X509_NAME_entry_count(self._name)):
607 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800608
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500609 fname = _lib.X509_NAME_ENTRY_get_object(ent)
610 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800611
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500612 nid = _lib.OBJ_obj2nid(fname)
613 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800614
615 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400616 _ffi.string(name),
617 _ffi.string(
618 _lib.ASN1_STRING_data(fval),
619 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800620
621 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200622
623
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800624X509NameType = X509Name
625
626
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800627class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200628 """
629 An X.509 v3 certificate extension.
630 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400631
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800632 def __init__(self, type_name, critical, value, subject=None, issuer=None):
633 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200634 Initializes an X509 extension.
635
Alex Gaynor6f719912015-09-20 09:21:29 -0400636 :param type_name: The name of the type of extension to create. See
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200637 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Alex Gaynor6f719912015-09-20 09:21:29 -0400638 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800639
Alex Gaynor5945ea82015-09-05 14:59:06 -0400640 :param bool critical: A flag indicating whether this is a critical
641 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800642
643 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200644 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800645
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200646 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800647 :type subject: :py:class:`X509`
648
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200649 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800650 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800651 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500652 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800653
Alex Gaynor5945ea82015-09-05 14:59:06 -0400654 # A context is necessary for any extension which uses the r2i
655 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
656 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500657 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800658
659 # We have no configuration database - but perhaps we should (some
660 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500661 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800662
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800663 # Initialize the subject and issuer, if appropriate. ctx is a local,
664 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400665 # any references, so no need to mess with reference counts or
666 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800667 if issuer is not None:
668 if not isinstance(issuer, X509):
669 raise TypeError("issuer must be an X509 instance")
670 ctx.issuer_cert = issuer._x509
671 if subject is not None:
672 if not isinstance(subject, X509):
673 raise TypeError("subject must be an X509 instance")
674 ctx.subject_cert = subject._x509
675
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800676 if critical:
677 # There are other OpenSSL APIs which would let us pass in critical
678 # separately, but they're harder to use, and since value is already
679 # a pile of crappy junk smuggling a ton of utterly important
680 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400681 # with strings? (However, X509V3_EXT_i2d in particular seems like
682 # it would be a better API to invoke. I do not know where to get
683 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500684 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800685
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500686 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
687 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800688 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500689 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800690
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400691 @property
692 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500693 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400694
695 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500696 _lib.GEN_EMAIL: "email",
697 _lib.GEN_DNS: "DNS",
698 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400699 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400700
701 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500702 method = _lib.X509V3_EXT_get(self._extension)
703 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500704 # TODO: This is untested.
705 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400706 payload = self._extension.value.data
707 length = self._extension.value.length
708
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500709 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400710 payloadptr[0] = payload
711
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500712 if method.it != _ffi.NULL:
713 ptr = _lib.ASN1_ITEM_ptr(method.it)
714 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
715 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400716 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500717 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400718 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500719 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400720
Paul Kehrerb7d79502015-05-04 07:43:51 -0500721 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400722 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500723 for i in range(_lib.sk_GENERAL_NAME_num(names)):
724 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400725 try:
726 label = self._prefixes[name.type]
727 except KeyError:
728 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500729 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500730 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400731 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500732 value = _native(
733 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
734 parts.append(label + ":" + value)
735 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400736
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800737 def __str__(self):
738 """
739 :return: a nice text representation of the extension
740 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500741 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400742 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800743
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400744 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500745 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800746 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500747 # TODO: This is untested.
748 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800749
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500750 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800751
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800752 def get_critical(self):
753 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200754 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800755
756 :return: The critical field.
757 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500758 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800759
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800760 def get_short_name(self):
761 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200762 Returns the short type name of this X.509 extension.
763
764 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800765
766 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200767 :rtype: :py:data:`bytes`
768
769 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800770 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500771 obj = _lib.X509_EXTENSION_get_object(self._extension)
772 nid = _lib.OBJ_obj2nid(obj)
773 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800774
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800775 def get_data(self):
776 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200777 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800778
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200779 :return: The ASN.1 encoded data of this X509 extension.
780 :rtype: :py:data:`bytes`
781
782 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800783 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500784 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
785 string_result = _ffi.cast('ASN1_STRING*', octet_result)
786 char_result = _lib.ASN1_STRING_data(string_result)
787 result_length = _lib.ASN1_STRING_length(string_result)
788 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800789
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200790
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800791X509ExtensionType = X509Extension
792
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800793
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800794class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200795 """
796 An X.509 certificate signing requests.
797 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400798
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800799 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500800 req = _lib.X509_REQ_new()
801 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800802
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800803 def set_pubkey(self, pkey):
804 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200805 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800806
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200807 :param pkey: The public key to use.
808 :type pkey: :py:class:`PKey`
809
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200810 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500812 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800813 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500814 # TODO: This is untested.
815 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800816
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800817 def get_pubkey(self):
818 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200819 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800820
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200821 :return: The public key.
822 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800823 """
824 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500825 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
826 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500827 # TODO: This is untested.
828 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500829 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800830 pkey._only_public = True
831 return pkey
832
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800833 def set_version(self, version):
834 """
835 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
836 request.
837
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200838 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200839 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800840 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500841 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800842 if not set_result:
843 _raise_current_error()
844
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800845 def get_version(self):
846 """
847 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
848 request.
849
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200850 :return: The value of the version subfield.
851 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800852 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500853 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800855 def get_subject(self):
856 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200857 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800858
Cory Benfield881dc8d2015-12-09 08:25:14 +0000859 This creates a new :class:`X509Name` that wraps the underlying subject
860 name field on the certificate signing request. Modifying it will modify
861 the underlying signing request, and will have the effect of modifying
862 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200863
864 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000865 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800866 """
867 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500868 name._name = _lib.X509_REQ_get_subject_name(self._req)
869 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500870 # TODO: This is untested.
871 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800872
873 # The name is owned by the X509Req structure. As long as the X509Name
874 # Python object is alive, keep the X509Req Python object alive.
875 name._owner = self
876
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800877 return name
878
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800879 def add_extensions(self, extensions):
880 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200881 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800882
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200883 :param extensions: The X.509 extensions to add.
884 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200885 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800886 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500887 stack = _lib.sk_X509_EXTENSION_new_null()
888 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500889 # TODO: This is untested.
890 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800891
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500892 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800893
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800894 for ext in extensions:
895 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800896 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800897
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800898 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500899 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800900
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500901 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800902 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500903 # TODO: This is untested.
904 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800905
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800906 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800907 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200908 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800909
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200910 :return: The X.509 extensions in this request.
911 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
912
913 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800914 """
915 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500916 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500917 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800918 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500919 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800920 exts.append(ext)
921 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800922
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800923 def sign(self, pkey, digest):
924 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700925 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800926
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200927 :param pkey: The key pair to sign with.
928 :type pkey: :py:class:`PKey`
929 :param digest: The name of the message digest to use for the signature,
930 e.g. :py:data:`b"sha1"`.
931 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200932 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800933 """
934 if pkey._only_public:
935 raise ValueError("Key has only public part")
936
937 if not pkey._initialized:
938 raise ValueError("Key is uninitialized")
939
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500940 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500941 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800942 raise ValueError("No such digest method")
943
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500944 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800945 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500946 # TODO: This is untested.
947 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800948
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800949 def verify(self, pkey):
950 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200951 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800952
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200953 :param key: A public key.
954 :type key: :py:class:`PKey`
955 :return: :py:data:`True` if the signature is correct.
956 :rtype: :py:class:`bool`
957 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800958 problem verifying the signature.
959 """
960 if not isinstance(pkey, PKey):
961 raise TypeError("pkey must be a PKey instance")
962
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500963 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800964 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500965 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800966
967 return result
968
969
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800970X509ReqType = X509Req
971
972
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800973class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200974 """
975 An X.509 certificate.
976 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400977
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800978 def __init__(self):
979 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500980 x509 = _lib.X509_new()
981 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800982
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800983 def set_version(self, version):
984 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200985 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800986
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200987 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800988 :type version: :py:class:`int`
989
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200990 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800991 """
992 if not isinstance(version, int):
993 raise TypeError("version must be an integer")
994
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500995 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800996
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800997 def get_version(self):
998 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200999 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001000
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001001 :return: The version number of the certificate.
1002 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001003 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001004 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001005
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001006 def get_pubkey(self):
1007 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001008 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001009
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001010 :return: The public key.
1011 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001012 """
1013 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001014 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1015 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001016 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001017 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001018 pkey._only_public = True
1019 return pkey
1020
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001021 def set_pubkey(self, pkey):
1022 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001023 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001024
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001025 :param pkey: The public key.
1026 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001027
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001028 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001029 """
1030 if not isinstance(pkey, PKey):
1031 raise TypeError("pkey must be a PKey instance")
1032
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001033 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001034 if not set_result:
1035 _raise_current_error()
1036
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001037 def sign(self, pkey, digest):
1038 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001039 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001040
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001041 :param pkey: The key to sign with.
1042 :type pkey: :py:class:`PKey`
1043
1044 :param digest: The name of the message digest to use.
1045 :type digest: :py:class:`bytes`
1046
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001047 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001048 """
1049 if not isinstance(pkey, PKey):
1050 raise TypeError("pkey must be a PKey instance")
1051
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001052 if pkey._only_public:
1053 raise ValueError("Key only has public part")
1054
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001055 if not pkey._initialized:
1056 raise ValueError("Key is uninitialized")
1057
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001058 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001059 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001060 raise ValueError("No such digest method")
1061
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001062 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001063 if not sign_result:
1064 _raise_current_error()
1065
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001066 def get_signature_algorithm(self):
1067 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001068 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001069
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001070 :return: The name of the algorithm.
1071 :rtype: :py:class:`bytes`
1072
1073 :raises ValueError: If the signature algorithm is undefined.
1074
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001075 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001076 """
1077 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001078 nid = _lib.OBJ_obj2nid(alg)
1079 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001080 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001081 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001082
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001083 def digest(self, digest_name):
1084 """
1085 Return the digest of the X509 object.
1086
1087 :param digest_name: The name of the digest algorithm to use.
1088 :type digest_name: :py:class:`bytes`
1089
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001090 :return: The digest of the object, formatted as
1091 :py:const:`b":"`-delimited hex pairs.
1092 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001093 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001094 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001095 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001096 raise ValueError("No such digest method")
1097
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001098 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1099 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001100 result_length[0] = len(result_buffer)
1101
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001102 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001103 self._x509, digest, result_buffer, result_length)
1104
1105 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001106 # TODO: This is untested.
1107 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001108
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001109 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001110 b16encode(ch).upper() for ch
1111 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001112
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001113 def subject_name_hash(self):
1114 """
1115 Return the hash of the X509 subject.
1116
1117 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001118 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001119 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001120 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001121
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001122 def set_serial_number(self, serial):
1123 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001124 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001125
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001126 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001127 :type serial: :py:class:`int`
1128
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001129 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001130 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001131 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001132 raise TypeError("serial must be an integer")
1133
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001134 hex_serial = hex(serial)[2:]
1135 if not isinstance(hex_serial, bytes):
1136 hex_serial = hex_serial.encode('ascii')
1137
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001138 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001139
1140 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001141 # it. If bignum is still NULL after this call, then the return value
1142 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001143 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001144
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001145 if bignum_serial[0] == _ffi.NULL:
1146 set_result = _lib.ASN1_INTEGER_set(
1147 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001148 if set_result:
1149 # TODO Not tested
1150 _raise_current_error()
1151 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001152 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1153 _lib.BN_free(bignum_serial[0])
1154 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001155 # TODO Not tested
1156 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001157 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1158 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001159 if not set_result:
1160 # TODO Not tested
1161 _raise_current_error()
1162
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001163 def get_serial_number(self):
1164 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001165 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001166
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001167 :return: The serial number.
1168 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001169 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001170 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1171 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001172 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001173 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001174 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001175 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001176 serial = int(hexstring_serial, 16)
1177 return serial
1178 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001179 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001180 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001181 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001182
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001183 def gmtime_adj_notAfter(self, amount):
1184 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001185 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001186
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001187 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001188 :type amount: :py:class:`int`
1189
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001190 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001191 """
1192 if not isinstance(amount, int):
1193 raise TypeError("amount must be an integer")
1194
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001195 notAfter = _lib.X509_get_notAfter(self._x509)
1196 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001197
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001198 def gmtime_adj_notBefore(self, amount):
1199 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001200 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001201
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001202 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001203 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001204 """
1205 if not isinstance(amount, int):
1206 raise TypeError("amount must be an integer")
1207
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001208 notBefore = _lib.X509_get_notBefore(self._x509)
1209 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001210
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001211 def has_expired(self):
1212 """
1213 Check whether the certificate has expired.
1214
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001215 :return: :py:const:`True` if the certificate has expired,
1216 :py:const:`False` otherwise.
1217 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001218 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001219 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001220 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001221
Paul Kehrerfde45c92016-01-21 12:57:37 -06001222 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001223
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001224 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001225 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001226
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001227 def get_notBefore(self):
1228 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001229 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001230
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001231 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001232
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001233 YYYYMMDDhhmmssZ
1234 YYYYMMDDhhmmss+hhmm
1235 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001236
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001237 :return: A timestamp string, or :py:const:`None` if there is none.
1238 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001239 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001240 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001241
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001242 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001243 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001244
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001245 def set_notBefore(self, when):
1246 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001247 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001248
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001249 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001250
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001251 YYYYMMDDhhmmssZ
1252 YYYYMMDDhhmmss+hhmm
1253 YYYYMMDDhhmmss-hhmm
1254
1255 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001256 :type when: :py:class:`bytes`
1257
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001258 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001259 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001260 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001261
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001262 def get_notAfter(self):
1263 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001264 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001265
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001266 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001267
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001268 YYYYMMDDhhmmssZ
1269 YYYYMMDDhhmmss+hhmm
1270 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001271
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001272 :return: A timestamp string, or :py:const:`None` if there is none.
1273 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001274 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001275 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001276
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001277 def set_notAfter(self, when):
1278 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001279 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001280
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001281 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001282
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001283 YYYYMMDDhhmmssZ
1284 YYYYMMDDhhmmss+hhmm
1285 YYYYMMDDhhmmss-hhmm
1286
1287 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001288 :type when: :py:class:`bytes`
1289
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001290 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001291 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001292 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001293
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001294 def _get_name(self, which):
1295 name = X509Name.__new__(X509Name)
1296 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001297 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001298 # TODO: This is untested.
1299 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001300
1301 # The name is owned by the X509 structure. As long as the X509Name
1302 # Python object is alive, keep the X509 Python object alive.
1303 name._owner = self
1304
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001305 return name
1306
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001307 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001308 if not isinstance(name, X509Name):
1309 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001310 set_result = which(self._x509, name._name)
1311 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001312 # TODO: This is untested.
1313 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001314
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001315 def get_issuer(self):
1316 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001317 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001318
Cory Benfielde6bcce82015-12-09 08:40:03 +00001319 This creates a new :class:`X509Name` that wraps the underlying issuer
1320 name field on the certificate. Modifying it will modify the underlying
1321 certificate, and will have the effect of modifying any other
1322 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001323
1324 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001325 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001326 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001327 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001328
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001329 def set_issuer(self, issuer):
1330 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001331 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001332
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001333 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001334 :type issuer: :py:class:`X509Name`
1335
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001336 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001337 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001338 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001339
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001340 def get_subject(self):
1341 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001342 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001343
Cory Benfielde6bcce82015-12-09 08:40:03 +00001344 This creates a new :class:`X509Name` that wraps the underlying subject
1345 name field on the certificate. Modifying it will modify the underlying
1346 certificate, and will have the effect of modifying any other
1347 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001348
1349 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001350 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001351 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001352 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001353
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001354 def set_subject(self, subject):
1355 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001356 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001357
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001358 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001359 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001360
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001361 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001362 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001363 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001364
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001365 def get_extension_count(self):
1366 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001367 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001368
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001369 :return: The number of extensions.
1370 :rtype: :py:class:`int`
1371
1372 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001373 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001374 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001375
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001376 def add_extensions(self, extensions):
1377 """
1378 Add extensions to the certificate.
1379
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001380 :param extensions: The extensions to add.
1381 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001382 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001383 """
1384 for ext in extensions:
1385 if not isinstance(ext, X509Extension):
1386 raise ValueError("One of the elements is not an X509Extension")
1387
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001388 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001389 if not add_result:
1390 _raise_current_error()
1391
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001392 def get_extension(self, index):
1393 """
1394 Get a specific extension of the certificate by index.
1395
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001396 Extensions on a certificate are kept in order. The index
1397 parameter selects which extension will be returned.
1398
1399 :param int index: The index of the extension to retrieve.
1400 :return: The extension at the specified index.
1401 :rtype: :py:class:`X509Extension`
1402 :raises IndexError: If the extension index was out of bounds.
1403
1404 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001405 """
1406 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001407 ext._extension = _lib.X509_get_ext(self._x509, index)
1408 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001409 raise IndexError("extension index out of bounds")
1410
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001411 extension = _lib.X509_EXTENSION_dup(ext._extension)
1412 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001413 return ext
1414
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001415
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001416X509Type = X509
1417
1418
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001419class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001420 """
1421 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001422 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001423
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001424 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001425 store = _lib.X509_STORE_new()
1426 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001427
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001428 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001429 """
1430 Adds the certificate :py:data:`cert` to this store.
1431
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001432 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001433
1434 :param X509 cert: The certificate to add to this store.
1435 :raises TypeError: If the certificate is not an :py:class:`X509`.
1436 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001437 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001438 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001439 if not isinstance(cert, X509):
1440 raise TypeError()
1441
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001442 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001443 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001444 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001445
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001446
1447X509StoreType = X509Store
1448
1449
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001450class X509StoreContextError(Exception):
1451 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001452 An exception raised when an error occurred while verifying a certificate
1453 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001454
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001455 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001456 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001457 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001458
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001459 def __init__(self, message, certificate):
1460 super(X509StoreContextError, self).__init__(message)
1461 self.certificate = certificate
1462
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001463
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001464class X509StoreContext(object):
1465 """
1466 An X.509 store context.
1467
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001468 An :py:class:`X509StoreContext` is used to define some of the criteria for
1469 certificate verification. The information encapsulated in this object
1470 includes, but is not limited to, a set of trusted certificates,
1471 verification parameters, and revoked certificates.
1472
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001473 .. note::
1474
1475 Currently, one can only set the trusted certificates on an
1476 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1477 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001478
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001479 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1480 instance. It is dynamically allocated and automatically garbage
1481 collected.
1482
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001483 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001484
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001485 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001486
1487 :param X509Store store: The certificates which will be trusted for the
1488 purposes of any verifications.
1489
1490 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001491 """
1492
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001493 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001494 store_ctx = _lib.X509_STORE_CTX_new()
1495 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1496 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001497 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001498 # Make the store context available for use after instantiating this
1499 # class by initializing it now. Per testing, subsequent calls to
1500 # :py:meth:`_init` have no adverse affect.
1501 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001502
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001503 def _init(self):
1504 """
1505 Set up the store context for a subsequent verification operation.
1506 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001507 ret = _lib.X509_STORE_CTX_init(
1508 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1509 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001510 if ret <= 0:
1511 _raise_current_error()
1512
1513 def _cleanup(self):
1514 """
1515 Internally cleans up the store context.
1516
1517 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001518 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001519 """
1520 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1521
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001522 def _exception_from_context(self):
1523 """
1524 Convert an OpenSSL native context error failure into a Python
1525 exception.
1526
Alex Gaynor5945ea82015-09-05 14:59:06 -04001527 When a call to native OpenSSL X509_verify_cert fails, additional
1528 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001529 """
1530 errors = [
1531 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1532 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1533 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001534 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001535 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001536 # A context error should always be associated with a certificate, so we
1537 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001538 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001539 _cert = _lib.X509_dup(_x509)
1540 pycert = X509.__new__(X509)
1541 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001542 return X509StoreContextError(errors, pycert)
1543
Stephen Holsapple46a09252015-02-12 14:45:43 -08001544 def set_store(self, store):
1545 """
1546 Set the context's trust store.
1547
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001548 .. versionadded:: 0.15
1549
Stephen Holsapple46a09252015-02-12 14:45:43 -08001550 :param X509Store store: The certificates which will be trusted for the
1551 purposes of any *future* verifications.
1552 """
1553 self._store = store
1554
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001555 def verify_certificate(self):
1556 """
1557 Verify a certificate in a context.
1558
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001559 .. versionadded:: 0.15
1560
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001561 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001562
Alex Gaynorca87ff62015-09-04 23:31:03 -04001563 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001564 certificate in the context. Sets ``certificate`` attribute to
1565 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001566 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001567 # Always re-initialize the store context in case
1568 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001569 self._init()
1570 ret = _lib.X509_verify_cert(self._store_ctx)
1571 self._cleanup()
1572 if ret <= 0:
1573 raise self._exception_from_context()
1574
1575
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001576def load_certificate(type, buffer):
1577 """
1578 Load a certificate from a buffer
1579
1580 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1581
1582 :param buffer: The buffer the certificate is stored in
1583 :type buffer: :py:class:`bytes`
1584
1585 :return: The X509 object
1586 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001587 if isinstance(buffer, _text_type):
1588 buffer = buffer.encode("ascii")
1589
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001590 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001591
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001592 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001593 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001594 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001595 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001596 else:
1597 raise ValueError(
1598 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001599
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001600 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001601 _raise_current_error()
1602
1603 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001604 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001605 return cert
1606
1607
1608def dump_certificate(type, cert):
1609 """
1610 Dump a certificate to a buffer
1611
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001612 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1613 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001614 :param cert: The certificate to dump
1615 :return: The buffer with the dumped certificate in
1616 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001617 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001618
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001619 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001620 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001621 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001622 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001623 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001624 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001625 else:
1626 raise ValueError(
1627 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1628 "FILETYPE_TEXT")
1629
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001630 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001631 return _bio_to_string(bio)
1632
1633
Cory Benfield6492f7c2015-10-27 16:57:58 +09001634def dump_publickey(type, pkey):
1635 """
Cory Benfield11c10192015-10-27 17:23:03 +09001636 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001637
Cory Benfield9c590b92015-10-28 14:55:05 +09001638 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001639 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001640 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001641 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001642 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001643 """
1644 bio = _new_mem_buf()
1645 if type == FILETYPE_PEM:
1646 write_bio = _lib.PEM_write_bio_PUBKEY
1647 elif type == FILETYPE_ASN1:
1648 write_bio = _lib.i2d_PUBKEY_bio
1649 else:
1650 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1651
1652 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001653 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001654 _raise_current_error()
1655
1656 return _bio_to_string(bio)
1657
1658
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001659def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1660 """
1661 Dump a private key to a buffer
1662
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001663 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1664 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001665 :param pkey: The PKey to dump
1666 :param cipher: (optional) if encrypted PEM format, the cipher to
1667 use
1668 :param passphrase: (optional) if encrypted PEM format, this can be either
1669 the passphrase to use, or a callback for providing the
1670 passphrase.
1671 :return: The buffer with the dumped key in
Maximilian Hils0de43752015-09-18 15:26:54 +02001672 :rtype: :py:data:`bytes`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001673 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001674 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001675
1676 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001677 if passphrase is None:
1678 raise TypeError(
1679 "if a value is given for cipher "
1680 "one must also be given for passphrase")
1681 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001682 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001683 raise ValueError("Invalid cipher name")
1684 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001685 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001686
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001687 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001688 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001689 result_code = _lib.PEM_write_bio_PrivateKey(
1690 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001691 helper.callback, helper.callback_args)
1692 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001693 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001694 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001695 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001696 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1697 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001698 # TODO RSA_free(rsa)?
1699 else:
1700 raise ValueError(
1701 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1702 "FILETYPE_TEXT")
1703
1704 if result_code == 0:
1705 _raise_current_error()
1706
1707 return _bio_to_string(bio)
1708
1709
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001710def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001711 copy = _lib.X509_REVOKED_new()
1712 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001713 # TODO: This is untested.
1714 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001715
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001716 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001717 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001718 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001719
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001720 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001721 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001722 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001723
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001724 if original.extensions != _ffi.NULL:
1725 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1726 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1727 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1728 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1729 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001730 copy.extensions = extension_stack
1731
1732 copy.sequence = original.sequence
1733 return copy
1734
1735
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001736class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001737 """
1738 A certificate revocation.
1739 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001740 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1741 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1742 # OCSP_crl_reason_str. We use the latter, just like the command line
1743 # program.
1744 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001745 b"unspecified",
1746 b"keyCompromise",
1747 b"CACompromise",
1748 b"affiliationChanged",
1749 b"superseded",
1750 b"cessationOfOperation",
1751 b"certificateHold",
1752 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001753 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001754
1755 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001756 revoked = _lib.X509_REVOKED_new()
1757 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001758
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001759 def set_serial(self, hex_str):
1760 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001761 Set the serial number.
1762
1763 The serial number is formatted as a hexadecimal number encoded in
1764 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001765
1766 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001767 :type hex_str: :py:class:`bytes`
1768
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001769 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001770 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001771 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1772 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001773 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001774 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001775 if not bn_result:
1776 raise ValueError("bad hex string")
1777
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001778 asn1_serial = _ffi.gc(
1779 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1780 _lib.ASN1_INTEGER_free)
1781 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001782
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001783 def get_serial(self):
1784 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001785 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001786
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001787 The serial number is formatted as a hexadecimal number encoded in
1788 ASCII.
1789
1790 :return: The serial number.
1791 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001792 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001793 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001794
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001795 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001796 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001797 # TODO: This is untested.
1798 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001799
1800 return _bio_to_string(bio)
1801
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001802 def _delete_reason(self):
1803 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001804 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1805 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1806 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1807 _lib.X509_EXTENSION_free(ext)
1808 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809 break
1810
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001811 def set_reason(self, reason):
1812 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001813 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001814
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001815 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001816
1817 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001818 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1819
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001820 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001821
1822 .. seealso::
1823
1824 :py:meth:`all_reasons`, which gives you a list of all supported
1825 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001826 """
1827 if reason is None:
1828 self._delete_reason()
1829 elif not isinstance(reason, bytes):
1830 raise TypeError("reason must be None or a byte string")
1831 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001832 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001833 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1834
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001835 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1836 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001837 # TODO: This is untested.
1838 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001839 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001840
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001841 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1842 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001843 # TODO: This is untested.
1844 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001845
1846 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001847 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1848 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001849
1850 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001851 # TODO: This is untested.
1852 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001853
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001854 def get_reason(self):
1855 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001856 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001857
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001858 :return: The reason, or :py:const:`None` if there is none.
1859 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1860
1861 .. seealso::
1862
1863 :py:meth:`all_reasons`, which gives you a list of all supported
1864 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001865 """
1866 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001867 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1868 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1869 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001870 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001871
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001872 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001873 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001874 print_result = _lib.M_ASN1_OCTET_STRING_print(
1875 bio, ext.value
1876 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001877 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001878 # TODO: This is untested.
1879 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001880
1881 return _bio_to_string(bio)
1882
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001883 def all_reasons(self):
1884 """
1885 Return a list of all the supported reason strings.
1886
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001887 This list is a copy; modifying it does not change the supported reason
1888 strings.
1889
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001890 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001891 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001892 """
1893 return self._crl_reasons[:]
1894
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001895 def set_rev_date(self, when):
1896 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001897 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001898
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001899 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1900 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001901 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001902 """
1903 return _set_asn1_time(self._revoked.revocationDate, when)
1904
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001905 def get_rev_date(self):
1906 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001907 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001908
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001909 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1910 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001911 """
1912 return _get_asn1_time(self._revoked.revocationDate)
1913
1914
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001915class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001916 """
1917 A certificate revocation list.
1918 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001919
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001920 def __init__(self):
1921 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001922 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001923 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001924 crl = _lib.X509_CRL_new()
1925 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001926
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001927 def get_revoked(self):
1928 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001929 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001930
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001931 These revocations will be provided by value, not by reference.
1932 That means it's okay to mutate them: it won't affect this CRL.
1933
1934 :return: The revocations in this CRL.
1935 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001936 """
1937 results = []
1938 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001939 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1940 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001941 revoked_copy = _X509_REVOKED_dup(revoked)
1942 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001943 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001944 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001945 if results:
1946 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001947
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001948 def add_revoked(self, revoked):
1949 """
1950 Add a revoked (by value not reference) to the CRL structure
1951
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001952 This revocation will be added by value, not by reference. That
1953 means it's okay to mutate it after adding: it won't affect
1954 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001955
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001956 :param revoked: The new revocation.
1957 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001958
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001959 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001960 """
1961 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001962 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001963 # TODO: This is untested.
1964 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001965
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001966 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001967 if add_result == 0:
1968 # TODO: This is untested.
1969 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001970
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001971 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001972 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001973 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001974 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001975
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001976 :param cert: The certificate used to sign the CRL.
1977 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001978
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001979 :param key: The key used to sign the CRL.
1980 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001981
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001982 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1983 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001984
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001985 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001986
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001987 :param bytes digest: The name of the message digest to use (eg
1988 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001989
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001990 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001991 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001992 if not isinstance(cert, X509):
1993 raise TypeError("cert must be an X509 instance")
1994 if not isinstance(key, PKey):
1995 raise TypeError("key must be a PKey instance")
1996 if not isinstance(type, int):
1997 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001998
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001999 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002000 _warn(
2001 "The default message digest (md5) is deprecated. "
2002 "Pass the name of a message digest explicitly.",
2003 category=DeprecationWarning,
2004 stacklevel=2,
2005 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002006 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002007
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002008 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002009 if digest_obj == _ffi.NULL:
2010 raise ValueError("No such digest method")
2011
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002012 bio = _lib.BIO_new(_lib.BIO_s_mem())
2013 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002014 # TODO: This is untested.
2015 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002016
Alex Gaynora738ed52015-09-05 11:17:10 -04002017 # A scratch time object to give different values to different CRL
2018 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002019 sometime = _lib.ASN1_TIME_new()
2020 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002021 # TODO: This is untested.
2022 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002023
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002024 _lib.X509_gmtime_adj(sometime, 0)
2025 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002026
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002027 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2028 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002029
Alex Gaynor5945ea82015-09-05 14:59:06 -04002030 _lib.X509_CRL_set_issuer_name(
2031 self._crl, _lib.X509_get_subject_name(cert._x509)
2032 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002033
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002034 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002035 if not sign_result:
2036 _raise_current_error()
2037
Dominic Chenf05b2122015-10-13 16:32:35 +00002038 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002039
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002040
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002041CRLType = CRL
2042
2043
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002044class PKCS7(object):
2045 def type_is_signed(self):
2046 """
2047 Check if this NID_pkcs7_signed object
2048
2049 :return: True if the PKCS7 is of type signed
2050 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002051 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002052 return True
2053 return False
2054
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002055 def type_is_enveloped(self):
2056 """
2057 Check if this NID_pkcs7_enveloped object
2058
2059 :returns: True if the PKCS7 is of type enveloped
2060 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002061 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002062 return True
2063 return False
2064
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002065 def type_is_signedAndEnveloped(self):
2066 """
2067 Check if this NID_pkcs7_signedAndEnveloped object
2068
2069 :returns: True if the PKCS7 is of type signedAndEnveloped
2070 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002071 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002072 return True
2073 return False
2074
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002075 def type_is_data(self):
2076 """
2077 Check if this NID_pkcs7_data object
2078
2079 :return: True if the PKCS7 is of type data
2080 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002081 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002082 return True
2083 return False
2084
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002085 def get_type_name(self):
2086 """
2087 Returns the type name of the PKCS7 structure
2088
2089 :return: A string with the typename
2090 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002091 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2092 string_type = _lib.OBJ_nid2sn(nid)
2093 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002094
2095PKCS7Type = PKCS7
2096
2097
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002098class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002099 """
2100 A PKCS #12 archive.
2101 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002102
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002103 def __init__(self):
2104 self._pkey = None
2105 self._cert = None
2106 self._cacerts = None
2107 self._friendlyname = None
2108
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002109 def get_certificate(self):
2110 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002111 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002112
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002113 :return: The certificate, or :py:const:`None` if there is none.
2114 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002115 """
2116 return self._cert
2117
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002118 def set_certificate(self, cert):
2119 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002120 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002121
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002122 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002123 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002124
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002125 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002126 """
2127 if not isinstance(cert, X509):
2128 raise TypeError("cert must be an X509 instance")
2129 self._cert = cert
2130
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002131 def get_privatekey(self):
2132 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002133 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002134
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002135 :return: The private key, or :py:const:`None` if there is none.
2136 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002137 """
2138 return self._pkey
2139
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002140 def set_privatekey(self, pkey):
2141 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002142 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002143
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002144 :param pkey: The new private key, or :py:const:`None` to unset it.
2145 :type pkey: :py:class:`PKey` or :py:const:`None`
2146
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002147 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002148 """
2149 if not isinstance(pkey, PKey):
2150 raise TypeError("pkey must be a PKey instance")
2151 self._pkey = pkey
2152
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002153 def get_ca_certificates(self):
2154 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002155 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002156
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002157 :return: A tuple with the CA certificates in the chain, or
2158 :py:const:`None` if there are none.
2159 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002160 """
2161 if self._cacerts is not None:
2162 return tuple(self._cacerts)
2163
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002164 def set_ca_certificates(self, cacerts):
2165 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002166 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002167
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002168 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2169 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002170 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002171
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002172 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002173 """
2174 if cacerts is None:
2175 self._cacerts = None
2176 else:
2177 cacerts = list(cacerts)
2178 for cert in cacerts:
2179 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002180 raise TypeError(
2181 "iterable must only contain X509 instances"
2182 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002183 self._cacerts = cacerts
2184
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002185 def set_friendlyname(self, name):
2186 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002187 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002188
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002189 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002190 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002191
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002192 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002193 """
2194 if name is None:
2195 self._friendlyname = None
2196 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002197 raise TypeError(
2198 "name must be a byte string or None (not %r)" % (name,)
2199 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002200 self._friendlyname = name
2201
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002202 def get_friendlyname(self):
2203 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002204 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002205
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002206 :returns: The friendly name, or :py:const:`None` if there is none.
2207 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002208 """
2209 return self._friendlyname
2210
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002211 def export(self, passphrase=None, iter=2048, maciter=1):
2212 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002213 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002214
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002215 For more information, see the :c:func:`PKCS12_create` man page.
2216
2217 :param passphrase: The passphrase used to encrypt the structure. Unlike
2218 some other passphrase arguments, this *must* be a string, not a
2219 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002220 :type passphrase: :py:data:`bytes`
2221
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002222 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002223 :type iter: :py:data:`int`
2224
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002225 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002226 :type maciter: :py:data:`int`
2227
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002228 :return: The string representation of the PKCS #12 structure.
2229 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002230 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002231 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002232
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002233 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002234 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002235 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002236 cacerts = _lib.sk_X509_new_null()
2237 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002238 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002239 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002240
2241 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002242 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002243
2244 friendlyname = self._friendlyname
2245 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002246 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002247
2248 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002249 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002250 else:
2251 pkey = self._pkey._pkey
2252
2253 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002254 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002255 else:
2256 cert = self._cert._x509
2257
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002258 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002259 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002260 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2261 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002262 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002263 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002264 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002265 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002266
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002267 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002268 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002269 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002270
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002271
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002272PKCS12Type = PKCS12
2273
2274
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002275class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002276 """
2277 A Netscape SPKI object.
2278 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002279
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002280 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002281 spki = _lib.NETSCAPE_SPKI_new()
2282 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002283
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002284 def sign(self, pkey, digest):
2285 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002286 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002287
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002288 :param pkey: The private key to sign with.
2289 :type pkey: :py:class:`PKey`
2290
2291 :param digest: The message digest to use.
2292 :type digest: :py:class:`bytes`
2293
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002294 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002295 """
2296 if pkey._only_public:
2297 raise ValueError("Key has only public part")
2298
2299 if not pkey._initialized:
2300 raise ValueError("Key is uninitialized")
2301
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002302 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002303 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002304 raise ValueError("No such digest method")
2305
Alex Gaynor5945ea82015-09-05 14:59:06 -04002306 sign_result = _lib.NETSCAPE_SPKI_sign(
2307 self._spki, pkey._pkey, digest_obj
2308 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002309 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002310 # TODO: This is untested.
2311 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002312
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002313 def verify(self, key):
2314 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002315 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002316
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002317 :param key: The public key that signature is supposedly from.
2318 :type pkey: :py:class:`PKey`
2319
2320 :return: :py:const:`True` if the signature is correct.
2321 :rtype: :py:class:`bool`
2322
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002323 :raises Error: If the signature is invalid, or there was a problem
2324 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002325 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002326 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002327 if answer <= 0:
2328 _raise_current_error()
2329 return True
2330
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002331 def b64_encode(self):
2332 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002333 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002334
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002335 :return: The base64 encoded string.
2336 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002337 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002338 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2339 result = _ffi.string(encoded)
2340 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002341 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002342
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002343 def get_pubkey(self):
2344 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002345 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002346
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002347 :return: The public key.
2348 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002349 """
2350 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002351 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2352 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002353 # TODO: This is untested.
2354 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002355 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002356 pkey._only_public = True
2357 return pkey
2358
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002359 def set_pubkey(self, pkey):
2360 """
2361 Set the public key of the certificate
2362
2363 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002364 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002365 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002366 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002367 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002368 # TODO: This is untested.
2369 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002370
2371
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002372NetscapeSPKIType = NetscapeSPKI
2373
2374
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002375class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002376 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002377 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002378 raise ValueError(
2379 "only FILETYPE_PEM key format supports encryption"
2380 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002381 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002382 self._more_args = more_args
2383 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002384 self._problems = []
2385
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002386 @property
2387 def callback(self):
2388 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002389 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002390 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002391 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002392 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002393 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002394 else:
2395 raise TypeError("Last argument must be string or callable")
2396
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002397 @property
2398 def callback_args(self):
2399 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002400 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002401 elif isinstance(self._passphrase, bytes):
2402 return self._passphrase
2403 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002404 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002405 else:
2406 raise TypeError("Last argument must be string or callable")
2407
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002408 def raise_if_problem(self, exceptionType=Error):
2409 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002410 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002411 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002412 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002413 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002414 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002415 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002416
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002417 def _read_passphrase(self, buf, size, rwflag, userdata):
2418 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002419 if self._more_args:
2420 result = self._passphrase(size, rwflag, userdata)
2421 else:
2422 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002423 if not isinstance(result, bytes):
2424 raise ValueError("String expected")
2425 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002426 if self._truncate:
2427 result = result[:size]
2428 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002429 raise ValueError(
2430 "passphrase returned by callback is too long"
2431 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002432 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002433 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002434 return len(result)
2435 except Exception as e:
2436 self._problems.append(e)
2437 return 0
2438
2439
Cory Benfield6492f7c2015-10-27 16:57:58 +09002440def load_publickey(type, buffer):
2441 """
Cory Benfield11c10192015-10-27 17:23:03 +09002442 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002443
Cory Benfield9c590b92015-10-28 14:55:05 +09002444 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002445 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002446 :param buffer: The buffer the key is stored in.
2447 :type buffer: A Python string object, either unicode or bytestring.
2448 :return: The PKey object.
2449 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002450 """
2451 if isinstance(buffer, _text_type):
2452 buffer = buffer.encode("ascii")
2453
2454 bio = _new_mem_buf(buffer)
2455
2456 if type == FILETYPE_PEM:
2457 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2458 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2459 elif type == FILETYPE_ASN1:
2460 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2461 else:
2462 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2463
2464 if evp_pkey == _ffi.NULL:
2465 _raise_current_error()
2466
2467 pkey = PKey.__new__(PKey)
2468 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
2469 return pkey
2470
2471
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002472def load_privatekey(type, buffer, passphrase=None):
2473 """
2474 Load a private key from a buffer
2475
2476 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2477 :param buffer: The buffer the key is stored in
2478 :param passphrase: (optional) if encrypted PEM format, this can be
2479 either the passphrase to use, or a callback for
2480 providing the passphrase.
2481
2482 :return: The PKey object
2483 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002484 if isinstance(buffer, _text_type):
2485 buffer = buffer.encode("ascii")
2486
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002487 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002488
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002489 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002490 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002491 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2492 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002493 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002494 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002495 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002496 else:
2497 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2498
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002499 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002500 _raise_current_error()
2501
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002502 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002503 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002504 return pkey
2505
2506
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002507def dump_certificate_request(type, req):
2508 """
2509 Dump a certificate request to a buffer
2510
2511 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2512 :param req: The certificate request to dump
2513 :return: The buffer with the dumped certificate request in
2514 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002515 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002516
2517 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002518 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002519 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002520 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002521 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002522 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002523 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002524 raise ValueError(
2525 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2526 "FILETYPE_TEXT"
2527 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002528
2529 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002530 # TODO: This is untested.
2531 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002532
2533 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002534
2535
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002536def load_certificate_request(type, buffer):
2537 """
2538 Load a certificate request from a buffer
2539
2540 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2541 :param buffer: The buffer the certificate request is stored in
2542 :return: The X509Req object
2543 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002544 if isinstance(buffer, _text_type):
2545 buffer = buffer.encode("ascii")
2546
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002547 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002548
2549 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002550 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002551 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002552 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002553 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002554 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002555
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002556 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002557 # TODO: This is untested.
2558 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002559
2560 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002561 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002562 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002563
2564
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002565def sign(pkey, data, digest):
2566 """
2567 Sign data with a digest
2568
2569 :param pkey: Pkey to sign with
2570 :param data: data to be signed
2571 :param digest: message digest to use
2572 :return: signature
2573 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002574 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002575
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002576 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002577 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002578 raise ValueError("No such digest method")
2579
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002580 md_ctx = _ffi.new("EVP_MD_CTX*")
2581 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002582
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002583 _lib.EVP_SignInit(md_ctx, digest_obj)
2584 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002585
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002586 signature_buffer = _ffi.new("unsigned char[]", 512)
2587 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002588 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002589 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002590 md_ctx, signature_buffer, signature_length, pkey._pkey)
2591
2592 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002593 # TODO: This is untested.
2594 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002595
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002596 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002597
2598
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002599def verify(cert, signature, data, digest):
2600 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002601 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002602
2603 :param cert: signing certificate (X509 object)
2604 :param signature: signature returned by sign function
2605 :param data: data to be verified
2606 :param digest: message digest to use
Alex Gaynor5945ea82015-09-05 14:59:06 -04002607 :return: :py:const:`None` if the signature is correct, raise exception
2608 otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002609 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002610 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002611
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002612 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002613 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002614 raise ValueError("No such digest method")
2615
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002616 pkey = _lib.X509_get_pubkey(cert._x509)
2617 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002618 # TODO: This is untested.
2619 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002620 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002621
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002622 md_ctx = _ffi.new("EVP_MD_CTX*")
2623 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002624
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002625 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2626 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002627 verify_result = _lib.EVP_VerifyFinal(
2628 md_ctx, signature, len(signature), pkey
2629 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002630
2631 if verify_result != 1:
2632 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002633
2634
Dominic Chenf05b2122015-10-13 16:32:35 +00002635def dump_crl(type, crl):
2636 """
2637 Dump a certificate revocation list to a buffer.
2638
2639 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2640 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002641 :param CRL crl: The CRL to dump.
2642
Dominic Chenf05b2122015-10-13 16:32:35 +00002643 :return: The buffer with the CRL.
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002644 :rtype: :data:`bytes`
Dominic Chenf05b2122015-10-13 16:32:35 +00002645 """
2646 bio = _new_mem_buf()
2647
2648 if type == FILETYPE_PEM:
2649 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2650 elif type == FILETYPE_ASN1:
2651 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2652 elif type == FILETYPE_TEXT:
2653 ret = _lib.X509_CRL_print(bio, crl._crl)
2654 else:
2655 raise ValueError(
2656 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2657 "FILETYPE_TEXT")
2658
2659 assert ret == 1
2660 return _bio_to_string(bio)
2661
2662
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002663def load_crl(type, buffer):
2664 """
2665 Load a certificate revocation list from a buffer
2666
2667 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2668 :param buffer: The buffer the CRL is stored in
2669
2670 :return: The PKey object
2671 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002672 if isinstance(buffer, _text_type):
2673 buffer = buffer.encode("ascii")
2674
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002675 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002676
2677 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002678 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002679 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002680 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002681 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002682 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2683
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002684 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002685 _raise_current_error()
2686
2687 result = CRL.__new__(CRL)
2688 result._crl = crl
2689 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002690
2691
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002692def load_pkcs7_data(type, buffer):
2693 """
2694 Load pkcs7 data from a buffer
2695
2696 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2697 :param buffer: The buffer with the pkcs7 data.
2698 :return: The PKCS7 object
2699 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002700 if isinstance(buffer, _text_type):
2701 buffer = buffer.encode("ascii")
2702
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002703 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002704
2705 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002706 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002707 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002708 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002709 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002710 # TODO: This is untested.
2711 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002712 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2713
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002714 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002715 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002716
2717 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002718 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002719 return pypkcs7
2720
2721
Stephen Holsapple38482622014-04-05 20:29:34 -07002722def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002723 """
2724 Load a PKCS12 object from a buffer
2725
2726 :param buffer: The buffer the certificate is stored in
2727 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2728 :returns: The PKCS12 object
2729 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002730 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002731
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002732 if isinstance(buffer, _text_type):
2733 buffer = buffer.encode("ascii")
2734
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002735 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002736
Stephen Holsapple38482622014-04-05 20:29:34 -07002737 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2738 # password based encryption no password and a zero length password are two
2739 # different things, but OpenSSL implementation will try both to figure out
2740 # which one works.
2741 if not passphrase:
2742 passphrase = _ffi.NULL
2743
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002744 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2745 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002746 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002747 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002748
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002749 pkey = _ffi.new("EVP_PKEY**")
2750 cert = _ffi.new("X509**")
2751 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002752
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002753 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002754 if not parse_result:
2755 _raise_current_error()
2756
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002757 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002758
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002759 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2760 # queue for no particular reason. This error isn't interesting to anyone
2761 # outside this function. It's not even interesting to us. Get rid of it.
2762 try:
2763 _raise_current_error()
2764 except Error:
2765 pass
2766
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002767 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002768 pykey = None
2769 else:
2770 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002771 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002772
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002773 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002774 pycert = None
2775 friendlyname = None
2776 else:
2777 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002778 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002779
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002780 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002781 friendlyname_buffer = _lib.X509_alias_get0(
2782 cert[0], friendlyname_length
2783 )
2784 friendlyname = _ffi.buffer(
2785 friendlyname_buffer, friendlyname_length[0]
2786 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002787 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002788 friendlyname = None
2789
2790 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002791 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002792 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002793 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002794 pycacerts.append(pycacert)
2795 if not pycacerts:
2796 pycacerts = None
2797
2798 pkcs12 = PKCS12.__new__(PKCS12)
2799 pkcs12._pkey = pykey
2800 pkcs12._cert = pycert
2801 pkcs12._cacerts = pycacerts
2802 pkcs12._friendlyname = friendlyname
2803 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002804
2805
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002806# There are no direct unit tests for this initialization. It is tested
2807# indirectly since it is necessary for functions like dump_privatekey when
2808# using encryption.
2809#
2810# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2811# and some other similar tests may fail without this (though they may not if
2812# the Python runtime has already done some initialization of the underlying
2813# OpenSSL library (and is linked against the same one that cryptography is
2814# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002815_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002816
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002817# This is similar but exercised mainly by exception_from_error_queue. It calls
2818# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2819_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002820
2821
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002822# Set the default string mask to match OpenSSL upstream (since 2005) and
2823# RFC5280 recommendations.
2824_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')