blob: a00b5c0f2af2ff3cfcd0f785b2972460a1c78249 [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
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500250 if _lib.EVP_PKEY_type(self._pkey.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 """
266 return self._pkey.type
267
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800268 def bits(self):
269 """
270 Returns the number of bits of the key
271
272 :return: The number of bits of the key.
273 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500274 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800275PKeyType = PKey
276
277
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400278class _EllipticCurve(object):
279 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400280 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400281
282 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
283 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
284 instances each of which represents one curve supported by the system.
285 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400286 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400287 _curves = None
288
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400289 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400290 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400291 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400292 """
293 Implement cooperation with the right-hand side argument of ``!=``.
294
295 Python 3 seems to have dropped this cooperation in this very narrow
296 circumstance.
297 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400298 if isinstance(other, _EllipticCurve):
299 return super(_EllipticCurve, self).__ne__(other)
300 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400301
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400302 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400303 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400304 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400305 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400306
307 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400308
309 :return: A :py:type:`set` of ``cls`` instances giving the names of the
310 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400311 """
312 if lib.Cryptography_HAS_EC:
313 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
314 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400315 # The return value on this call should be num_curves again. We
316 # could check it to make sure but if it *isn't* then.. what could
317 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400318 lib.EC_get_builtin_curves(builtin_curves, num_curves)
319 return set(
320 cls.from_nid(lib, c.nid)
321 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400322 return set()
323
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400324 @classmethod
325 def _get_elliptic_curves(cls, lib):
326 """
327 Get, cache, and return the curves supported by OpenSSL.
328
329 :param lib: The OpenSSL library binding object.
330
331 :return: A :py:type:`set` of ``cls`` instances giving the names of the
332 elliptic curves the underlying library supports.
333 """
334 if cls._curves is None:
335 cls._curves = cls._load_elliptic_curves(lib)
336 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400337
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400338 @classmethod
339 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400340 """
341 Instantiate a new :py:class:`_EllipticCurve` associated with the given
342 OpenSSL NID.
343
344 :param lib: The OpenSSL library binding object.
345
346 :param nid: The OpenSSL NID the resulting curve object will represent.
347 This must be a curve NID (and not, for example, a hash NID) or
348 subsequent operations will fail in unpredictable ways.
349 :type nid: :py:class:`int`
350
351 :return: The curve object.
352 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400353 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
354
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400355 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400356 """
357 :param _lib: The :py:mod:`cryptography` binding instance used to
358 interface with OpenSSL.
359
360 :param _nid: The OpenSSL NID identifying the curve this object
361 represents.
362 :type _nid: :py:class:`int`
363
364 :param name: The OpenSSL short name identifying the curve this object
365 represents.
366 :type name: :py:class:`unicode`
367 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400368 self._lib = lib
369 self._nid = nid
370 self.name = name
371
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400372 def __repr__(self):
373 return "<Curve %r>" % (self.name,)
374
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400375 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400376 """
377 Create a new OpenSSL EC_KEY structure initialized to use this curve.
378
379 The structure is automatically garbage collected when the Python object
380 is garbage collected.
381 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400382 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
383 return _ffi.gc(key, _lib.EC_KEY_free)
384
385
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400386def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400387 """
388 Return a set of objects representing the elliptic curves supported in the
389 OpenSSL build in use.
390
391 The curve objects have a :py:class:`unicode` ``name`` attribute by which
392 they identify themselves.
393
394 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400395 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
396 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400397 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400398 return _EllipticCurve._get_elliptic_curves(_lib)
399
400
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400401def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400402 """
403 Return a single curve object selected by name.
404
405 See :py:func:`get_elliptic_curves` for information about curve objects.
406
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400407 :param name: The OpenSSL short name identifying the curve object to
408 retrieve.
409 :type name: :py:class:`unicode`
410
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400411 If the named curve is not supported then :py:class:`ValueError` is raised.
412 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400413 for curve in get_elliptic_curves():
414 if curve.name == name:
415 return curve
416 raise ValueError("unknown curve name", name)
417
418
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800419class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200420 """
421 An X.509 Distinguished Name.
422
423 :ivar countryName: The country of the entity.
424 :ivar C: Alias for :py:attr:`countryName`.
425
426 :ivar stateOrProvinceName: The state or province of the entity.
427 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
428
429 :ivar localityName: The locality of the entity.
430 :ivar L: Alias for :py:attr:`localityName`.
431
432 :ivar organizationName: The organization name of the entity.
433 :ivar O: Alias for :py:attr:`organizationName`.
434
435 :ivar organizationalUnitName: The organizational unit of the entity.
436 :ivar OU: Alias for :py:attr:`organizationalUnitName`
437
438 :ivar commonName: The common name of the entity.
439 :ivar CN: Alias for :py:attr:`commonName`.
440
441 :ivar emailAddress: The e-mail address of the entity.
442 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400443
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800444 def __init__(self, name):
445 """
446 Create a new X509Name, copying the given X509Name instance.
447
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200448 :param name: The name to copy.
449 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800450 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500451 name = _lib.X509_NAME_dup(name._name)
452 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800453
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800454 def __setattr__(self, name, value):
455 if name.startswith('_'):
456 return super(X509Name, self).__setattr__(name, value)
457
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800458 # Note: we really do not want str subclasses here, so we do not use
459 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800460 if type(name) is not str:
461 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400462 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800463
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500464 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500465 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800466 try:
467 _raise_current_error()
468 except Error:
469 pass
470 raise AttributeError("No such attribute")
471
472 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500473 for i in range(_lib.X509_NAME_entry_count(self._name)):
474 ent = _lib.X509_NAME_get_entry(self._name, i)
475 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
476 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800477 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500478 ent = _lib.X509_NAME_delete_entry(self._name, i)
479 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800480 break
481
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500482 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800483 value = value.encode('utf-8')
484
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500485 add_result = _lib.X509_NAME_add_entry_by_NID(
486 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800487 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500488 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800489
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800490 def __getattr__(self, name):
491 """
492 Find attribute. An X509Name object has the following attributes:
493 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400494 organization (alias O), organizationalUnit (alias OU), commonName
495 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800496 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500497 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500498 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800499 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
500 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
501 # push something onto the error queue. If we don't clean that up
502 # now, someone else will bump into it later and be quite confused.
503 # See lp#314814.
504 try:
505 _raise_current_error()
506 except Error:
507 pass
508 return super(X509Name, self).__getattr__(name)
509
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500510 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800511 if entry_index == -1:
512 return None
513
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500514 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
515 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800516
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500517 result_buffer = _ffi.new("unsigned char**")
518 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800519 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500520 # TODO: This is untested.
521 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800522
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700523 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400524 result = _ffi.buffer(
525 result_buffer[0], data_length
526 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700527 finally:
528 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500529 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800530 return result
531
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500532 def _cmp(op):
533 def f(self, other):
534 if not isinstance(other, X509Name):
535 return NotImplemented
536 result = _lib.X509_NAME_cmp(self._name, other._name)
537 return op(result, 0)
538 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800539
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500540 __eq__ = _cmp(__eq__)
541 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800542
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500543 __lt__ = _cmp(__lt__)
544 __le__ = _cmp(__le__)
545
546 __gt__ = _cmp(__gt__)
547 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800548
549 def __repr__(self):
550 """
551 String representation of an X509Name
552 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400553 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500554 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800555 self._name, result_buffer, len(result_buffer))
556
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500557 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500558 # TODO: This is untested.
559 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800560
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500561 return "<X509Name object '%s'>" % (
562 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800563
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800564 def hash(self):
565 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200566 Return an integer representation of the first four bytes of the
567 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800568
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200569 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
570
571 :return: The (integer) hash of this name.
572 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800573 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500574 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800575
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800576 def der(self):
577 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200578 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800579
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200580 :return: The DER encoded form of this name.
581 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800582 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500583 result_buffer = _ffi.new('unsigned char**')
584 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500586 # TODO: This is untested.
587 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800588
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500589 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
590 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800591 return string_result
592
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800593 def get_components(self):
594 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200595 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800596
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200597 :return: The components of this name.
598 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800599 """
600 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500601 for i in range(_lib.X509_NAME_entry_count(self._name)):
602 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800603
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500604 fname = _lib.X509_NAME_ENTRY_get_object(ent)
605 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800606
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500607 nid = _lib.OBJ_obj2nid(fname)
608 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800609
610 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400611 _ffi.string(name),
612 _ffi.string(
613 _lib.ASN1_STRING_data(fval),
614 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800615
616 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200617
618
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800619X509NameType = X509Name
620
621
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800622class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200623 """
624 An X.509 v3 certificate extension.
625 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400626
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800627 def __init__(self, type_name, critical, value, subject=None, issuer=None):
628 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200629 Initializes an X509 extension.
630
Alex Gaynor6f719912015-09-20 09:21:29 -0400631 :param type_name: The name of the type of extension to create. See
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200632 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Alex Gaynor6f719912015-09-20 09:21:29 -0400633 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800634
Alex Gaynor5945ea82015-09-05 14:59:06 -0400635 :param bool critical: A flag indicating whether this is a critical
636 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800637
638 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200639 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800640
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200641 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800642 :type subject: :py:class:`X509`
643
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200644 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800645 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800646 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500647 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800648
Alex Gaynor5945ea82015-09-05 14:59:06 -0400649 # A context is necessary for any extension which uses the r2i
650 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
651 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500652 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800653
654 # We have no configuration database - but perhaps we should (some
655 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500656 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800657
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800658 # Initialize the subject and issuer, if appropriate. ctx is a local,
659 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400660 # any references, so no need to mess with reference counts or
661 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800662 if issuer is not None:
663 if not isinstance(issuer, X509):
664 raise TypeError("issuer must be an X509 instance")
665 ctx.issuer_cert = issuer._x509
666 if subject is not None:
667 if not isinstance(subject, X509):
668 raise TypeError("subject must be an X509 instance")
669 ctx.subject_cert = subject._x509
670
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800671 if critical:
672 # There are other OpenSSL APIs which would let us pass in critical
673 # separately, but they're harder to use, and since value is already
674 # a pile of crappy junk smuggling a ton of utterly important
675 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400676 # with strings? (However, X509V3_EXT_i2d in particular seems like
677 # it would be a better API to invoke. I do not know where to get
678 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500679 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800680
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500681 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
682 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800683 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500684 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800685
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400686 @property
687 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500688 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400689
690 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500691 _lib.GEN_EMAIL: "email",
692 _lib.GEN_DNS: "DNS",
693 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400694 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400695
696 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500697 method = _lib.X509V3_EXT_get(self._extension)
698 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500699 # TODO: This is untested.
700 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400701 payload = self._extension.value.data
702 length = self._extension.value.length
703
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500704 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400705 payloadptr[0] = payload
706
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500707 if method.it != _ffi.NULL:
708 ptr = _lib.ASN1_ITEM_ptr(method.it)
709 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
710 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400711 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500712 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400713 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500714 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400715
Paul Kehrerb7d79502015-05-04 07:43:51 -0500716 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400717 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500718 for i in range(_lib.sk_GENERAL_NAME_num(names)):
719 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400720 try:
721 label = self._prefixes[name.type]
722 except KeyError:
723 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500724 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500725 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400726 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500727 value = _native(
728 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
729 parts.append(label + ":" + value)
730 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400731
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800732 def __str__(self):
733 """
734 :return: a nice text representation of the extension
735 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500736 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400737 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800738
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400739 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500740 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800741 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500742 # TODO: This is untested.
743 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800744
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500745 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800746
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800747 def get_critical(self):
748 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200749 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800750
751 :return: The critical field.
752 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500753 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800754
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800755 def get_short_name(self):
756 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200757 Returns the short type name of this X.509 extension.
758
759 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800760
761 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200762 :rtype: :py:data:`bytes`
763
764 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800765 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500766 obj = _lib.X509_EXTENSION_get_object(self._extension)
767 nid = _lib.OBJ_obj2nid(obj)
768 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800769
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800770 def get_data(self):
771 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200772 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800773
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200774 :return: The ASN.1 encoded data of this X509 extension.
775 :rtype: :py:data:`bytes`
776
777 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800778 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500779 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
780 string_result = _ffi.cast('ASN1_STRING*', octet_result)
781 char_result = _lib.ASN1_STRING_data(string_result)
782 result_length = _lib.ASN1_STRING_length(string_result)
783 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800784
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200785
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800786X509ExtensionType = X509Extension
787
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800788
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800789class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200790 """
791 An X.509 certificate signing requests.
792 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400793
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800794 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500795 req = _lib.X509_REQ_new()
796 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800797
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800798 def set_pubkey(self, pkey):
799 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200800 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800801
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200802 :param pkey: The public key to use.
803 :type pkey: :py:class:`PKey`
804
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200805 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800806 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500807 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800808 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500809 # TODO: This is untested.
810 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800812 def get_pubkey(self):
813 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200814 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800815
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200816 :return: The public key.
817 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800818 """
819 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500820 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
821 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500822 # TODO: This is untested.
823 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500824 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800825 pkey._only_public = True
826 return pkey
827
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800828 def set_version(self, version):
829 """
830 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
831 request.
832
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200833 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200834 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800835 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500836 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800837 if not set_result:
838 _raise_current_error()
839
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800840 def get_version(self):
841 """
842 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
843 request.
844
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200845 :return: The value of the version subfield.
846 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800847 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500848 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800849
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850 def get_subject(self):
851 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200852 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800853
Cory Benfield881dc8d2015-12-09 08:25:14 +0000854 This creates a new :class:`X509Name` that wraps the underlying subject
855 name field on the certificate signing request. Modifying it will modify
856 the underlying signing request, and will have the effect of modifying
857 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200858
859 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000860 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800861 """
862 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500863 name._name = _lib.X509_REQ_get_subject_name(self._req)
864 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500865 # TODO: This is untested.
866 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800867
868 # The name is owned by the X509Req structure. As long as the X509Name
869 # Python object is alive, keep the X509Req Python object alive.
870 name._owner = self
871
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800872 return name
873
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800874 def add_extensions(self, extensions):
875 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200876 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800877
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200878 :param extensions: The X.509 extensions to add.
879 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200880 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800881 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500882 stack = _lib.sk_X509_EXTENSION_new_null()
883 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500884 # TODO: This is untested.
885 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800886
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500887 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800888
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889 for ext in extensions:
890 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800891 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800892
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800893 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500894 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800895
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500896 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800897 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500898 # TODO: This is untested.
899 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800900
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800901 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800902 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200903 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800904
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200905 :return: The X.509 extensions in this request.
906 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
907
908 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800909 """
910 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500911 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500912 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800913 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500914 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800915 exts.append(ext)
916 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800917
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800918 def sign(self, pkey, digest):
919 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700920 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800921
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200922 :param pkey: The key pair to sign with.
923 :type pkey: :py:class:`PKey`
924 :param digest: The name of the message digest to use for the signature,
925 e.g. :py:data:`b"sha1"`.
926 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200927 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800928 """
929 if pkey._only_public:
930 raise ValueError("Key has only public part")
931
932 if not pkey._initialized:
933 raise ValueError("Key is uninitialized")
934
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500935 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500936 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800937 raise ValueError("No such digest method")
938
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500939 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800940 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500941 # TODO: This is untested.
942 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800943
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800944 def verify(self, pkey):
945 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200946 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800947
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200948 :param key: A public key.
949 :type key: :py:class:`PKey`
950 :return: :py:data:`True` if the signature is correct.
951 :rtype: :py:class:`bool`
952 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800953 problem verifying the signature.
954 """
955 if not isinstance(pkey, PKey):
956 raise TypeError("pkey must be a PKey instance")
957
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500958 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800959 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500960 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800961
962 return result
963
964
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800965X509ReqType = X509Req
966
967
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800968class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200969 """
970 An X.509 certificate.
971 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400972
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800973 def __init__(self):
974 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500975 x509 = _lib.X509_new()
976 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800977
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800978 def set_version(self, version):
979 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200980 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800981
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200982 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800983 :type version: :py:class:`int`
984
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200985 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800986 """
987 if not isinstance(version, int):
988 raise TypeError("version must be an integer")
989
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500990 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800991
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800992 def get_version(self):
993 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200994 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800995
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200996 :return: The version number of the certificate.
997 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800998 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500999 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001000
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001001 def get_pubkey(self):
1002 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001003 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001004
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001005 :return: The public key.
1006 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001007 """
1008 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001009 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1010 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001011 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001012 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001013 pkey._only_public = True
1014 return pkey
1015
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001016 def set_pubkey(self, pkey):
1017 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001018 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001019
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001020 :param pkey: The public key.
1021 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001022
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001023 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001024 """
1025 if not isinstance(pkey, PKey):
1026 raise TypeError("pkey must be a PKey instance")
1027
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001028 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001029 if not set_result:
1030 _raise_current_error()
1031
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001032 def sign(self, pkey, digest):
1033 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001034 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001035
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001036 :param pkey: The key to sign with.
1037 :type pkey: :py:class:`PKey`
1038
1039 :param digest: The name of the message digest to use.
1040 :type digest: :py:class:`bytes`
1041
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001042 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001043 """
1044 if not isinstance(pkey, PKey):
1045 raise TypeError("pkey must be a PKey instance")
1046
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001047 if pkey._only_public:
1048 raise ValueError("Key only has public part")
1049
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001050 if not pkey._initialized:
1051 raise ValueError("Key is uninitialized")
1052
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001053 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001054 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001055 raise ValueError("No such digest method")
1056
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001057 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001058 if not sign_result:
1059 _raise_current_error()
1060
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001061 def get_signature_algorithm(self):
1062 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001063 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001064
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001065 :return: The name of the algorithm.
1066 :rtype: :py:class:`bytes`
1067
1068 :raises ValueError: If the signature algorithm is undefined.
1069
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001070 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001071 """
1072 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001073 nid = _lib.OBJ_obj2nid(alg)
1074 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001075 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001076 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001077
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001078 def digest(self, digest_name):
1079 """
1080 Return the digest of the X509 object.
1081
1082 :param digest_name: The name of the digest algorithm to use.
1083 :type digest_name: :py:class:`bytes`
1084
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001085 :return: The digest of the object, formatted as
1086 :py:const:`b":"`-delimited hex pairs.
1087 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001088 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001089 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001090 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001091 raise ValueError("No such digest method")
1092
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001093 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1094 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001095 result_length[0] = len(result_buffer)
1096
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001097 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001098 self._x509, digest, result_buffer, result_length)
1099
1100 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001101 # TODO: This is untested.
1102 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001103
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001104 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001105 b16encode(ch).upper() for ch
1106 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001107
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001108 def subject_name_hash(self):
1109 """
1110 Return the hash of the X509 subject.
1111
1112 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001113 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001114 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001115 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001116
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001117 def set_serial_number(self, serial):
1118 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001119 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001120
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001121 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001122 :type serial: :py:class:`int`
1123
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001124 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001125 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001126 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001127 raise TypeError("serial must be an integer")
1128
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001129 hex_serial = hex(serial)[2:]
1130 if not isinstance(hex_serial, bytes):
1131 hex_serial = hex_serial.encode('ascii')
1132
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001133 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001134
1135 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001136 # it. If bignum is still NULL after this call, then the return value
1137 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001138 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001139
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001140 if bignum_serial[0] == _ffi.NULL:
1141 set_result = _lib.ASN1_INTEGER_set(
1142 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001143 if set_result:
1144 # TODO Not tested
1145 _raise_current_error()
1146 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001147 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1148 _lib.BN_free(bignum_serial[0])
1149 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001150 # TODO Not tested
1151 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001152 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1153 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001154 if not set_result:
1155 # TODO Not tested
1156 _raise_current_error()
1157
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001158 def get_serial_number(self):
1159 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001160 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001161
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001162 :return: The serial number.
1163 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001164 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001165 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1166 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001167 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001168 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001169 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001170 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001171 serial = int(hexstring_serial, 16)
1172 return serial
1173 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001174 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001175 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001176 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001177
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001178 def gmtime_adj_notAfter(self, amount):
1179 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001180 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001181
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001182 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001183 :type amount: :py:class:`int`
1184
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001185 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001186 """
1187 if not isinstance(amount, int):
1188 raise TypeError("amount must be an integer")
1189
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001190 notAfter = _lib.X509_get_notAfter(self._x509)
1191 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001192
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001193 def gmtime_adj_notBefore(self, amount):
1194 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001195 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001196
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001197 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001198 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001199 """
1200 if not isinstance(amount, int):
1201 raise TypeError("amount must be an integer")
1202
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001203 notBefore = _lib.X509_get_notBefore(self._x509)
1204 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001205
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001206 def has_expired(self):
1207 """
1208 Check whether the certificate has expired.
1209
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001210 :return: :py:const:`True` if the certificate has expired,
1211 :py:const:`False` otherwise.
1212 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001213 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001214 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001215 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001216
Paul Kehrerfde45c92016-01-21 12:57:37 -06001217 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001218
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001219 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001220 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001221
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001222 def get_notBefore(self):
1223 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001224 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001225
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001226 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001227
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001228 YYYYMMDDhhmmssZ
1229 YYYYMMDDhhmmss+hhmm
1230 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001231
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001232 :return: A timestamp string, or :py:const:`None` if there is none.
1233 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001234 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001235 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001236
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001237 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001238 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001239
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001240 def set_notBefore(self, when):
1241 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001242 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001243
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001244 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001245
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001246 YYYYMMDDhhmmssZ
1247 YYYYMMDDhhmmss+hhmm
1248 YYYYMMDDhhmmss-hhmm
1249
1250 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001251 :type when: :py:class:`bytes`
1252
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001253 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001254 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001255 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001256
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001257 def get_notAfter(self):
1258 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001259 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001260
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001261 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001262
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001263 YYYYMMDDhhmmssZ
1264 YYYYMMDDhhmmss+hhmm
1265 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001266
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001267 :return: A timestamp string, or :py:const:`None` if there is none.
1268 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001269 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001270 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001271
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001272 def set_notAfter(self, when):
1273 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001274 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001275
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001276 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001277
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001278 YYYYMMDDhhmmssZ
1279 YYYYMMDDhhmmss+hhmm
1280 YYYYMMDDhhmmss-hhmm
1281
1282 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001283 :type when: :py:class:`bytes`
1284
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001285 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001286 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001287 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001288
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001289 def _get_name(self, which):
1290 name = X509Name.__new__(X509Name)
1291 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001292 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001293 # TODO: This is untested.
1294 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001295
1296 # The name is owned by the X509 structure. As long as the X509Name
1297 # Python object is alive, keep the X509 Python object alive.
1298 name._owner = self
1299
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001300 return name
1301
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001302 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001303 if not isinstance(name, X509Name):
1304 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001305 set_result = which(self._x509, name._name)
1306 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001307 # TODO: This is untested.
1308 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001309
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001310 def get_issuer(self):
1311 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001312 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001313
Cory Benfielde6bcce82015-12-09 08:40:03 +00001314 This creates a new :class:`X509Name` that wraps the underlying issuer
1315 name field on the certificate. Modifying it will modify the underlying
1316 certificate, and will have the effect of modifying any other
1317 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001318
1319 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001320 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001321 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001322 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001323
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001324 def set_issuer(self, issuer):
1325 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001326 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001327
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001328 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001329 :type issuer: :py:class:`X509Name`
1330
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001331 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001332 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001333 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001334
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001335 def get_subject(self):
1336 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001337 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001338
Cory Benfielde6bcce82015-12-09 08:40:03 +00001339 This creates a new :class:`X509Name` that wraps the underlying subject
1340 name field on the certificate. Modifying it will modify the underlying
1341 certificate, and will have the effect of modifying any other
1342 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001343
1344 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001345 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001346 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001347 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001348
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001349 def set_subject(self, subject):
1350 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001351 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001352
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001353 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001354 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001355
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001356 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001357 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001358 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001359
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001360 def get_extension_count(self):
1361 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001362 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001363
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001364 :return: The number of extensions.
1365 :rtype: :py:class:`int`
1366
1367 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001368 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001369 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001370
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001371 def add_extensions(self, extensions):
1372 """
1373 Add extensions to the certificate.
1374
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001375 :param extensions: The extensions to add.
1376 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001377 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001378 """
1379 for ext in extensions:
1380 if not isinstance(ext, X509Extension):
1381 raise ValueError("One of the elements is not an X509Extension")
1382
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001383 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001384 if not add_result:
1385 _raise_current_error()
1386
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001387 def get_extension(self, index):
1388 """
1389 Get a specific extension of the certificate by index.
1390
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001391 Extensions on a certificate are kept in order. The index
1392 parameter selects which extension will be returned.
1393
1394 :param int index: The index of the extension to retrieve.
1395 :return: The extension at the specified index.
1396 :rtype: :py:class:`X509Extension`
1397 :raises IndexError: If the extension index was out of bounds.
1398
1399 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001400 """
1401 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001402 ext._extension = _lib.X509_get_ext(self._x509, index)
1403 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001404 raise IndexError("extension index out of bounds")
1405
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001406 extension = _lib.X509_EXTENSION_dup(ext._extension)
1407 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001408 return ext
1409
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001410
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001411X509Type = X509
1412
1413
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001414class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001415 """
1416 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001417 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001418
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001419 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001420 store = _lib.X509_STORE_new()
1421 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001422
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001423 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001424 """
1425 Adds the certificate :py:data:`cert` to this store.
1426
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001427 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001428
1429 :param X509 cert: The certificate to add to this store.
1430 :raises TypeError: If the certificate is not an :py:class:`X509`.
1431 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001432 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001433 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001434 if not isinstance(cert, X509):
1435 raise TypeError()
1436
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001437 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001438 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001439 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001440
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001441
1442X509StoreType = X509Store
1443
1444
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001445class X509StoreContextError(Exception):
1446 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001447 An exception raised when an error occurred while verifying a certificate
1448 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001449
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001450 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001451 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001452 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001453
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001454 def __init__(self, message, certificate):
1455 super(X509StoreContextError, self).__init__(message)
1456 self.certificate = certificate
1457
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001458
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001459class X509StoreContext(object):
1460 """
1461 An X.509 store context.
1462
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001463 An :py:class:`X509StoreContext` is used to define some of the criteria for
1464 certificate verification. The information encapsulated in this object
1465 includes, but is not limited to, a set of trusted certificates,
1466 verification parameters, and revoked certificates.
1467
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001468 .. note::
1469
1470 Currently, one can only set the trusted certificates on an
1471 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1472 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001473
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001474 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1475 instance. It is dynamically allocated and automatically garbage
1476 collected.
1477
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001478 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001479
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001480 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001481
1482 :param X509Store store: The certificates which will be trusted for the
1483 purposes of any verifications.
1484
1485 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001486 """
1487
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001488 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001489 store_ctx = _lib.X509_STORE_CTX_new()
1490 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1491 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001492 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001493 # Make the store context available for use after instantiating this
1494 # class by initializing it now. Per testing, subsequent calls to
1495 # :py:meth:`_init` have no adverse affect.
1496 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001497
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001498 def _init(self):
1499 """
1500 Set up the store context for a subsequent verification operation.
1501 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001502 ret = _lib.X509_STORE_CTX_init(
1503 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1504 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001505 if ret <= 0:
1506 _raise_current_error()
1507
1508 def _cleanup(self):
1509 """
1510 Internally cleans up the store context.
1511
1512 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001513 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001514 """
1515 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1516
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001517 def _exception_from_context(self):
1518 """
1519 Convert an OpenSSL native context error failure into a Python
1520 exception.
1521
Alex Gaynor5945ea82015-09-05 14:59:06 -04001522 When a call to native OpenSSL X509_verify_cert fails, additional
1523 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001524 """
1525 errors = [
1526 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1527 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1528 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001529 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001530 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001531 # A context error should always be associated with a certificate, so we
1532 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001533 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001534 _cert = _lib.X509_dup(_x509)
1535 pycert = X509.__new__(X509)
1536 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001537 return X509StoreContextError(errors, pycert)
1538
Stephen Holsapple46a09252015-02-12 14:45:43 -08001539 def set_store(self, store):
1540 """
1541 Set the context's trust store.
1542
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001543 .. versionadded:: 0.15
1544
Stephen Holsapple46a09252015-02-12 14:45:43 -08001545 :param X509Store store: The certificates which will be trusted for the
1546 purposes of any *future* verifications.
1547 """
1548 self._store = store
1549
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001550 def verify_certificate(self):
1551 """
1552 Verify a certificate in a context.
1553
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001554 .. versionadded:: 0.15
1555
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001556 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001557
Alex Gaynorca87ff62015-09-04 23:31:03 -04001558 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001559 certificate in the context. Sets ``certificate`` attribute to
1560 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001561 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001562 # Always re-initialize the store context in case
1563 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001564 self._init()
1565 ret = _lib.X509_verify_cert(self._store_ctx)
1566 self._cleanup()
1567 if ret <= 0:
1568 raise self._exception_from_context()
1569
1570
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001571def load_certificate(type, buffer):
1572 """
1573 Load a certificate from a buffer
1574
1575 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1576
1577 :param buffer: The buffer the certificate is stored in
1578 :type buffer: :py:class:`bytes`
1579
1580 :return: The X509 object
1581 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001582 if isinstance(buffer, _text_type):
1583 buffer = buffer.encode("ascii")
1584
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001585 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001586
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001587 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001588 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001589 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001590 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001591 else:
1592 raise ValueError(
1593 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001594
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001595 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001596 _raise_current_error()
1597
1598 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001599 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001600 return cert
1601
1602
1603def dump_certificate(type, cert):
1604 """
1605 Dump a certificate to a buffer
1606
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001607 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1608 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001609 :param cert: The certificate to dump
1610 :return: The buffer with the dumped certificate in
1611 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001612 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001613
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001614 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001615 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001616 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001617 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001618 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001619 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001620 else:
1621 raise ValueError(
1622 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1623 "FILETYPE_TEXT")
1624
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001625 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001626 return _bio_to_string(bio)
1627
1628
Cory Benfield6492f7c2015-10-27 16:57:58 +09001629def dump_publickey(type, pkey):
1630 """
Cory Benfield11c10192015-10-27 17:23:03 +09001631 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001632
Cory Benfield9c590b92015-10-28 14:55:05 +09001633 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001634 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001635 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001636 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001637 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001638 """
1639 bio = _new_mem_buf()
1640 if type == FILETYPE_PEM:
1641 write_bio = _lib.PEM_write_bio_PUBKEY
1642 elif type == FILETYPE_ASN1:
1643 write_bio = _lib.i2d_PUBKEY_bio
1644 else:
1645 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1646
1647 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001648 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001649 _raise_current_error()
1650
1651 return _bio_to_string(bio)
1652
1653
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001654def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1655 """
1656 Dump a private key to a buffer
1657
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001658 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1659 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001660 :param pkey: The PKey to dump
1661 :param cipher: (optional) if encrypted PEM format, the cipher to
1662 use
1663 :param passphrase: (optional) if encrypted PEM format, this can be either
1664 the passphrase to use, or a callback for providing the
1665 passphrase.
1666 :return: The buffer with the dumped key in
Maximilian Hils0de43752015-09-18 15:26:54 +02001667 :rtype: :py:data:`bytes`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001668 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001669 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001670
1671 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001672 if passphrase is None:
1673 raise TypeError(
1674 "if a value is given for cipher "
1675 "one must also be given for passphrase")
1676 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001677 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001678 raise ValueError("Invalid cipher name")
1679 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001680 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001681
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001682 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001683 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001684 result_code = _lib.PEM_write_bio_PrivateKey(
1685 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001686 helper.callback, helper.callback_args)
1687 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001688 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001689 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001690 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001691 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1692 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001693 # TODO RSA_free(rsa)?
1694 else:
1695 raise ValueError(
1696 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1697 "FILETYPE_TEXT")
1698
1699 if result_code == 0:
1700 _raise_current_error()
1701
1702 return _bio_to_string(bio)
1703
1704
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001705def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001706 copy = _lib.X509_REVOKED_new()
1707 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001708 # TODO: This is untested.
1709 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001710
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001711 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001712 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001713 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001714
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001715 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001716 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001717 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001718
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001719 if original.extensions != _ffi.NULL:
1720 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1721 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1722 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1723 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1724 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001725 copy.extensions = extension_stack
1726
1727 copy.sequence = original.sequence
1728 return copy
1729
1730
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001731class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001732 """
1733 A certificate revocation.
1734 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001735 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1736 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1737 # OCSP_crl_reason_str. We use the latter, just like the command line
1738 # program.
1739 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001740 b"unspecified",
1741 b"keyCompromise",
1742 b"CACompromise",
1743 b"affiliationChanged",
1744 b"superseded",
1745 b"cessationOfOperation",
1746 b"certificateHold",
1747 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001748 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001749
1750 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001751 revoked = _lib.X509_REVOKED_new()
1752 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001753
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001754 def set_serial(self, hex_str):
1755 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001756 Set the serial number.
1757
1758 The serial number is formatted as a hexadecimal number encoded in
1759 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001760
1761 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001762 :type hex_str: :py:class:`bytes`
1763
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001764 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001765 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001766 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1767 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001768 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001769 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001770 if not bn_result:
1771 raise ValueError("bad hex string")
1772
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001773 asn1_serial = _ffi.gc(
1774 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1775 _lib.ASN1_INTEGER_free)
1776 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001777
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001778 def get_serial(self):
1779 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001780 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001781
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001782 The serial number is formatted as a hexadecimal number encoded in
1783 ASCII.
1784
1785 :return: The serial number.
1786 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001787 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001788 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001789
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001790 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001791 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001792 # TODO: This is untested.
1793 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001794
1795 return _bio_to_string(bio)
1796
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001797 def _delete_reason(self):
1798 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001799 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1800 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1801 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1802 _lib.X509_EXTENSION_free(ext)
1803 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001804 break
1805
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001806 def set_reason(self, reason):
1807 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001808 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001810 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001811
1812 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001813 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1814
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001815 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001816
1817 .. seealso::
1818
1819 :py:meth:`all_reasons`, which gives you a list of all supported
1820 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001821 """
1822 if reason is None:
1823 self._delete_reason()
1824 elif not isinstance(reason, bytes):
1825 raise TypeError("reason must be None or a byte string")
1826 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001827 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001828 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1829
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001830 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1831 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001832 # TODO: This is untested.
1833 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001834 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001835
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001836 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1837 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001838 # TODO: This is untested.
1839 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001840
1841 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001842 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1843 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001844
1845 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001846 # TODO: This is untested.
1847 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001848
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001849 def get_reason(self):
1850 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001851 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001852
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001853 :return: The reason, or :py:const:`None` if there is none.
1854 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1855
1856 .. seealso::
1857
1858 :py:meth:`all_reasons`, which gives you a list of all supported
1859 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001860 """
1861 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001862 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1863 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1864 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001865 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001866
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001867 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001868 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001869 print_result = _lib.M_ASN1_OCTET_STRING_print(
1870 bio, ext.value
1871 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001872 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001873 # TODO: This is untested.
1874 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001875
1876 return _bio_to_string(bio)
1877
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001878 def all_reasons(self):
1879 """
1880 Return a list of all the supported reason strings.
1881
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001882 This list is a copy; modifying it does not change the supported reason
1883 strings.
1884
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001885 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001886 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001887 """
1888 return self._crl_reasons[:]
1889
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001890 def set_rev_date(self, when):
1891 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001892 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001893
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001894 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1895 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001896 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001897 """
1898 return _set_asn1_time(self._revoked.revocationDate, when)
1899
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001900 def get_rev_date(self):
1901 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001902 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001903
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001904 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1905 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001906 """
1907 return _get_asn1_time(self._revoked.revocationDate)
1908
1909
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001910class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001911 """
1912 A certificate revocation list.
1913 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001914
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001915 def __init__(self):
1916 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001917 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001918 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001919 crl = _lib.X509_CRL_new()
1920 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001921
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001922 def get_revoked(self):
1923 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001924 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001925
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001926 These revocations will be provided by value, not by reference.
1927 That means it's okay to mutate them: it won't affect this CRL.
1928
1929 :return: The revocations in this CRL.
1930 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001931 """
1932 results = []
1933 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001934 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1935 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001936 revoked_copy = _X509_REVOKED_dup(revoked)
1937 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001938 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001939 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001940 if results:
1941 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001942
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001943 def add_revoked(self, revoked):
1944 """
1945 Add a revoked (by value not reference) to the CRL structure
1946
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001947 This revocation will be added by value, not by reference. That
1948 means it's okay to mutate it after adding: it won't affect
1949 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001950
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001951 :param revoked: The new revocation.
1952 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001953
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001954 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001955 """
1956 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001957 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001958 # TODO: This is untested.
1959 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001960
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001961 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001962 if add_result == 0:
1963 # TODO: This is untested.
1964 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001965
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001966 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001967 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001968 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001969 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001970
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001971 :param cert: The certificate used to sign the CRL.
1972 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001973
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001974 :param key: The key used to sign the CRL.
1975 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001976
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001977 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1978 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001979
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001980 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001981
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001982 :param bytes digest: The name of the message digest to use (eg
1983 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001984
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001985 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001986 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001987 if not isinstance(cert, X509):
1988 raise TypeError("cert must be an X509 instance")
1989 if not isinstance(key, PKey):
1990 raise TypeError("key must be a PKey instance")
1991 if not isinstance(type, int):
1992 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001993
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001994 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001995 _warn(
1996 "The default message digest (md5) is deprecated. "
1997 "Pass the name of a message digest explicitly.",
1998 category=DeprecationWarning,
1999 stacklevel=2,
2000 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002001 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002002
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002003 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002004 if digest_obj == _ffi.NULL:
2005 raise ValueError("No such digest method")
2006
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002007 bio = _lib.BIO_new(_lib.BIO_s_mem())
2008 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002009 # TODO: This is untested.
2010 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002011
Alex Gaynora738ed52015-09-05 11:17:10 -04002012 # A scratch time object to give different values to different CRL
2013 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002014 sometime = _lib.ASN1_TIME_new()
2015 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002016 # TODO: This is untested.
2017 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002018
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002019 _lib.X509_gmtime_adj(sometime, 0)
2020 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002021
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002022 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2023 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002024
Alex Gaynor5945ea82015-09-05 14:59:06 -04002025 _lib.X509_CRL_set_issuer_name(
2026 self._crl, _lib.X509_get_subject_name(cert._x509)
2027 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002028
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002029 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002030 if not sign_result:
2031 _raise_current_error()
2032
Dominic Chenf05b2122015-10-13 16:32:35 +00002033 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002034
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002035
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002036CRLType = CRL
2037
2038
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002039class PKCS7(object):
2040 def type_is_signed(self):
2041 """
2042 Check if this NID_pkcs7_signed object
2043
2044 :return: True if the PKCS7 is of type signed
2045 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002046 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002047 return True
2048 return False
2049
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002050 def type_is_enveloped(self):
2051 """
2052 Check if this NID_pkcs7_enveloped object
2053
2054 :returns: True if the PKCS7 is of type enveloped
2055 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002056 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002057 return True
2058 return False
2059
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002060 def type_is_signedAndEnveloped(self):
2061 """
2062 Check if this NID_pkcs7_signedAndEnveloped object
2063
2064 :returns: True if the PKCS7 is of type signedAndEnveloped
2065 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002066 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002067 return True
2068 return False
2069
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002070 def type_is_data(self):
2071 """
2072 Check if this NID_pkcs7_data object
2073
2074 :return: True if the PKCS7 is of type data
2075 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002076 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002077 return True
2078 return False
2079
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002080 def get_type_name(self):
2081 """
2082 Returns the type name of the PKCS7 structure
2083
2084 :return: A string with the typename
2085 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002086 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2087 string_type = _lib.OBJ_nid2sn(nid)
2088 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002089
2090PKCS7Type = PKCS7
2091
2092
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002093class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002094 """
2095 A PKCS #12 archive.
2096 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002097
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002098 def __init__(self):
2099 self._pkey = None
2100 self._cert = None
2101 self._cacerts = None
2102 self._friendlyname = None
2103
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002104 def get_certificate(self):
2105 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002106 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002107
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002108 :return: The certificate, or :py:const:`None` if there is none.
2109 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002110 """
2111 return self._cert
2112
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002113 def set_certificate(self, cert):
2114 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002115 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002116
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002117 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002118 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002119
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002120 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002121 """
2122 if not isinstance(cert, X509):
2123 raise TypeError("cert must be an X509 instance")
2124 self._cert = cert
2125
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002126 def get_privatekey(self):
2127 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002128 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002129
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002130 :return: The private key, or :py:const:`None` if there is none.
2131 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002132 """
2133 return self._pkey
2134
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002135 def set_privatekey(self, pkey):
2136 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002137 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002138
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002139 :param pkey: The new private key, or :py:const:`None` to unset it.
2140 :type pkey: :py:class:`PKey` or :py:const:`None`
2141
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002142 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002143 """
2144 if not isinstance(pkey, PKey):
2145 raise TypeError("pkey must be a PKey instance")
2146 self._pkey = pkey
2147
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002148 def get_ca_certificates(self):
2149 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002150 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002151
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002152 :return: A tuple with the CA certificates in the chain, or
2153 :py:const:`None` if there are none.
2154 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002155 """
2156 if self._cacerts is not None:
2157 return tuple(self._cacerts)
2158
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002159 def set_ca_certificates(self, cacerts):
2160 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002161 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002162
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002163 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2164 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002165 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002166
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002167 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002168 """
2169 if cacerts is None:
2170 self._cacerts = None
2171 else:
2172 cacerts = list(cacerts)
2173 for cert in cacerts:
2174 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002175 raise TypeError(
2176 "iterable must only contain X509 instances"
2177 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002178 self._cacerts = cacerts
2179
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002180 def set_friendlyname(self, name):
2181 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002182 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002183
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002184 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002185 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002186
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002187 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002188 """
2189 if name is None:
2190 self._friendlyname = None
2191 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002192 raise TypeError(
2193 "name must be a byte string or None (not %r)" % (name,)
2194 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002195 self._friendlyname = name
2196
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002197 def get_friendlyname(self):
2198 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002199 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002200
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002201 :returns: The friendly name, or :py:const:`None` if there is none.
2202 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002203 """
2204 return self._friendlyname
2205
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002206 def export(self, passphrase=None, iter=2048, maciter=1):
2207 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002208 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002209
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002210 For more information, see the :c:func:`PKCS12_create` man page.
2211
2212 :param passphrase: The passphrase used to encrypt the structure. Unlike
2213 some other passphrase arguments, this *must* be a string, not a
2214 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002215 :type passphrase: :py:data:`bytes`
2216
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002217 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002218 :type iter: :py:data:`int`
2219
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002220 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002221 :type maciter: :py:data:`int`
2222
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002223 :return: The string representation of the PKCS #12 structure.
2224 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002225 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002226 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002227
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002228 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002229 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002230 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002231 cacerts = _lib.sk_X509_new_null()
2232 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002233 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002234 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002235
2236 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002237 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002238
2239 friendlyname = self._friendlyname
2240 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002241 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002242
2243 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002244 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002245 else:
2246 pkey = self._pkey._pkey
2247
2248 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002249 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002250 else:
2251 cert = self._cert._x509
2252
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002253 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002254 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002255 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2256 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002257 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002258 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002259 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002260 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002261
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002262 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002263 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002264 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002265
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002266
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002267PKCS12Type = PKCS12
2268
2269
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002270class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002271 """
2272 A Netscape SPKI object.
2273 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002274
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002275 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002276 spki = _lib.NETSCAPE_SPKI_new()
2277 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002278
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002279 def sign(self, pkey, digest):
2280 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002281 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002282
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002283 :param pkey: The private key to sign with.
2284 :type pkey: :py:class:`PKey`
2285
2286 :param digest: The message digest to use.
2287 :type digest: :py:class:`bytes`
2288
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002289 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002290 """
2291 if pkey._only_public:
2292 raise ValueError("Key has only public part")
2293
2294 if not pkey._initialized:
2295 raise ValueError("Key is uninitialized")
2296
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002297 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002298 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002299 raise ValueError("No such digest method")
2300
Alex Gaynor5945ea82015-09-05 14:59:06 -04002301 sign_result = _lib.NETSCAPE_SPKI_sign(
2302 self._spki, pkey._pkey, digest_obj
2303 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002304 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002305 # TODO: This is untested.
2306 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002307
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002308 def verify(self, key):
2309 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002310 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002311
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002312 :param key: The public key that signature is supposedly from.
2313 :type pkey: :py:class:`PKey`
2314
2315 :return: :py:const:`True` if the signature is correct.
2316 :rtype: :py:class:`bool`
2317
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002318 :raises Error: If the signature is invalid, or there was a problem
2319 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002320 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002321 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002322 if answer <= 0:
2323 _raise_current_error()
2324 return True
2325
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002326 def b64_encode(self):
2327 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002328 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002329
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002330 :return: The base64 encoded string.
2331 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002332 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002333 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2334 result = _ffi.string(encoded)
2335 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002336 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002337
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002338 def get_pubkey(self):
2339 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002340 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002341
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002342 :return: The public key.
2343 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002344 """
2345 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002346 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2347 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002348 # TODO: This is untested.
2349 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002350 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002351 pkey._only_public = True
2352 return pkey
2353
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002354 def set_pubkey(self, pkey):
2355 """
2356 Set the public key of the certificate
2357
2358 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002359 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002360 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002361 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002362 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002363 # TODO: This is untested.
2364 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002365
2366
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002367NetscapeSPKIType = NetscapeSPKI
2368
2369
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002370class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002371 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002372 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002373 raise ValueError(
2374 "only FILETYPE_PEM key format supports encryption"
2375 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002376 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002377 self._more_args = more_args
2378 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002379 self._problems = []
2380
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002381 @property
2382 def callback(self):
2383 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002384 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002385 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002386 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002387 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002388 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002389 else:
2390 raise TypeError("Last argument must be string or callable")
2391
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002392 @property
2393 def callback_args(self):
2394 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002395 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002396 elif isinstance(self._passphrase, bytes):
2397 return self._passphrase
2398 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002399 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002400 else:
2401 raise TypeError("Last argument must be string or callable")
2402
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002403 def raise_if_problem(self, exceptionType=Error):
2404 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002405 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002406 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002407 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002408 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002409 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002410 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002411
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002412 def _read_passphrase(self, buf, size, rwflag, userdata):
2413 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002414 if self._more_args:
2415 result = self._passphrase(size, rwflag, userdata)
2416 else:
2417 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002418 if not isinstance(result, bytes):
2419 raise ValueError("String expected")
2420 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002421 if self._truncate:
2422 result = result[:size]
2423 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002424 raise ValueError(
2425 "passphrase returned by callback is too long"
2426 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002427 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002428 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002429 return len(result)
2430 except Exception as e:
2431 self._problems.append(e)
2432 return 0
2433
2434
Cory Benfield6492f7c2015-10-27 16:57:58 +09002435def load_publickey(type, buffer):
2436 """
Cory Benfield11c10192015-10-27 17:23:03 +09002437 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002438
Cory Benfield9c590b92015-10-28 14:55:05 +09002439 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002440 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002441 :param buffer: The buffer the key is stored in.
2442 :type buffer: A Python string object, either unicode or bytestring.
2443 :return: The PKey object.
2444 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002445 """
2446 if isinstance(buffer, _text_type):
2447 buffer = buffer.encode("ascii")
2448
2449 bio = _new_mem_buf(buffer)
2450
2451 if type == FILETYPE_PEM:
2452 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2453 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2454 elif type == FILETYPE_ASN1:
2455 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2456 else:
2457 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2458
2459 if evp_pkey == _ffi.NULL:
2460 _raise_current_error()
2461
2462 pkey = PKey.__new__(PKey)
2463 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
2464 return pkey
2465
2466
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002467def load_privatekey(type, buffer, passphrase=None):
2468 """
2469 Load a private key from a buffer
2470
2471 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2472 :param buffer: The buffer the key is stored in
2473 :param passphrase: (optional) if encrypted PEM format, this can be
2474 either the passphrase to use, or a callback for
2475 providing the passphrase.
2476
2477 :return: The PKey object
2478 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002479 if isinstance(buffer, _text_type):
2480 buffer = buffer.encode("ascii")
2481
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002482 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002483
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002484 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002485 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002486 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2487 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002488 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002489 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002490 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002491 else:
2492 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2493
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002494 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002495 _raise_current_error()
2496
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002497 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002498 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002499 return pkey
2500
2501
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002502def dump_certificate_request(type, req):
2503 """
2504 Dump a certificate request to a buffer
2505
2506 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2507 :param req: The certificate request to dump
2508 :return: The buffer with the dumped certificate request in
2509 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002510 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002511
2512 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002513 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002514 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002515 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002516 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002517 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002518 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002519 raise ValueError(
2520 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2521 "FILETYPE_TEXT"
2522 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002523
2524 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002525 # TODO: This is untested.
2526 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002527
2528 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002529
2530
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002531def load_certificate_request(type, buffer):
2532 """
2533 Load a certificate request from a buffer
2534
2535 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2536 :param buffer: The buffer the certificate request is stored in
2537 :return: The X509Req object
2538 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002539 if isinstance(buffer, _text_type):
2540 buffer = buffer.encode("ascii")
2541
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002542 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002543
2544 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002545 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002546 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002547 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002548 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002549 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002550
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002551 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002552 # TODO: This is untested.
2553 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002554
2555 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002556 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002557 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002558
2559
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002560def sign(pkey, data, digest):
2561 """
2562 Sign data with a digest
2563
2564 :param pkey: Pkey to sign with
2565 :param data: data to be signed
2566 :param digest: message digest to use
2567 :return: signature
2568 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002569 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002570
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002571 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002572 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002573 raise ValueError("No such digest method")
2574
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002575 md_ctx = _ffi.new("EVP_MD_CTX*")
2576 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002577
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002578 _lib.EVP_SignInit(md_ctx, digest_obj)
2579 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002580
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002581 signature_buffer = _ffi.new("unsigned char[]", 512)
2582 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002583 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002584 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002585 md_ctx, signature_buffer, signature_length, pkey._pkey)
2586
2587 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002588 # TODO: This is untested.
2589 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002590
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002591 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002592
2593
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002594def verify(cert, signature, data, digest):
2595 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002596 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002597
2598 :param cert: signing certificate (X509 object)
2599 :param signature: signature returned by sign function
2600 :param data: data to be verified
2601 :param digest: message digest to use
Alex Gaynor5945ea82015-09-05 14:59:06 -04002602 :return: :py:const:`None` if the signature is correct, raise exception
2603 otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002604 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002605 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002606
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002607 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002608 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002609 raise ValueError("No such digest method")
2610
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002611 pkey = _lib.X509_get_pubkey(cert._x509)
2612 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002613 # TODO: This is untested.
2614 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002615 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002616
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002617 md_ctx = _ffi.new("EVP_MD_CTX*")
2618 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002619
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002620 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2621 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002622 verify_result = _lib.EVP_VerifyFinal(
2623 md_ctx, signature, len(signature), pkey
2624 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002625
2626 if verify_result != 1:
2627 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002628
2629
Dominic Chenf05b2122015-10-13 16:32:35 +00002630def dump_crl(type, crl):
2631 """
2632 Dump a certificate revocation list to a buffer.
2633
2634 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2635 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002636 :param CRL crl: The CRL to dump.
2637
Dominic Chenf05b2122015-10-13 16:32:35 +00002638 :return: The buffer with the CRL.
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002639 :rtype: :data:`bytes`
Dominic Chenf05b2122015-10-13 16:32:35 +00002640 """
2641 bio = _new_mem_buf()
2642
2643 if type == FILETYPE_PEM:
2644 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2645 elif type == FILETYPE_ASN1:
2646 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2647 elif type == FILETYPE_TEXT:
2648 ret = _lib.X509_CRL_print(bio, crl._crl)
2649 else:
2650 raise ValueError(
2651 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2652 "FILETYPE_TEXT")
2653
2654 assert ret == 1
2655 return _bio_to_string(bio)
2656
2657
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002658def load_crl(type, buffer):
2659 """
2660 Load a certificate revocation list from a buffer
2661
2662 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2663 :param buffer: The buffer the CRL is stored in
2664
2665 :return: The PKey object
2666 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002667 if isinstance(buffer, _text_type):
2668 buffer = buffer.encode("ascii")
2669
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002670 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002671
2672 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002673 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002674 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002675 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002676 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002677 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2678
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002679 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002680 _raise_current_error()
2681
2682 result = CRL.__new__(CRL)
2683 result._crl = crl
2684 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002685
2686
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002687def load_pkcs7_data(type, buffer):
2688 """
2689 Load pkcs7 data from a buffer
2690
2691 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2692 :param buffer: The buffer with the pkcs7 data.
2693 :return: The PKCS7 object
2694 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002695 if isinstance(buffer, _text_type):
2696 buffer = buffer.encode("ascii")
2697
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002698 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002699
2700 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002701 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002702 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002703 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002704 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002705 # TODO: This is untested.
2706 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002707 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2708
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002709 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002710 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002711
2712 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002713 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002714 return pypkcs7
2715
2716
Stephen Holsapple38482622014-04-05 20:29:34 -07002717def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002718 """
2719 Load a PKCS12 object from a buffer
2720
2721 :param buffer: The buffer the certificate is stored in
2722 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2723 :returns: The PKCS12 object
2724 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002725 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002726
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002727 if isinstance(buffer, _text_type):
2728 buffer = buffer.encode("ascii")
2729
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002730 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002731
Stephen Holsapple38482622014-04-05 20:29:34 -07002732 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2733 # password based encryption no password and a zero length password are two
2734 # different things, but OpenSSL implementation will try both to figure out
2735 # which one works.
2736 if not passphrase:
2737 passphrase = _ffi.NULL
2738
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002739 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2740 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002741 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002742 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002743
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002744 pkey = _ffi.new("EVP_PKEY**")
2745 cert = _ffi.new("X509**")
2746 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002747
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002748 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002749 if not parse_result:
2750 _raise_current_error()
2751
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002752 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002753
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002754 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2755 # queue for no particular reason. This error isn't interesting to anyone
2756 # outside this function. It's not even interesting to us. Get rid of it.
2757 try:
2758 _raise_current_error()
2759 except Error:
2760 pass
2761
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002762 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002763 pykey = None
2764 else:
2765 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002766 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002767
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002768 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002769 pycert = None
2770 friendlyname = None
2771 else:
2772 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002773 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002774
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002775 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002776 friendlyname_buffer = _lib.X509_alias_get0(
2777 cert[0], friendlyname_length
2778 )
2779 friendlyname = _ffi.buffer(
2780 friendlyname_buffer, friendlyname_length[0]
2781 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002782 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002783 friendlyname = None
2784
2785 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002786 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002787 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002788 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002789 pycacerts.append(pycacert)
2790 if not pycacerts:
2791 pycacerts = None
2792
2793 pkcs12 = PKCS12.__new__(PKCS12)
2794 pkcs12._pkey = pykey
2795 pkcs12._cert = pycert
2796 pkcs12._cacerts = pycacerts
2797 pkcs12._friendlyname = friendlyname
2798 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002799
2800
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002801# There are no direct unit tests for this initialization. It is tested
2802# indirectly since it is necessary for functions like dump_privatekey when
2803# using encryption.
2804#
2805# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2806# and some other similar tests may fail without this (though they may not if
2807# the Python runtime has already done some initialization of the underlying
2808# OpenSSL library (and is linked against the same one that cryptography is
2809# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002810_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002811
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002812# This is similar but exercised mainly by exception_from_error_queue. It calls
2813# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2814_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002815
2816
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002817# Set the default string mask to match OpenSSL upstream (since 2005) and
2818# RFC5280 recommendations.
2819_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')