blob: 86752d3991e70be0c5da9b92cc6489634a66373a [file] [log] [blame]
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001import datetime
Paul Kehrer8d887e12015-10-24 09:09:55 -05002
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05003from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05004from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05005from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04006from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05007
8from six import (
9 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -040010 text_type as _text_type,
11 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080012
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050013from OpenSSL._util import (
14 ffi as _ffi,
15 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050016 exception_from_error_queue as _exception_from_error_queue,
17 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040018 native as _native,
19 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040020 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040021)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080022
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050023FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
24FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080025
26# TODO This was an API mistake. OpenSSL has no such constant.
27FILETYPE_TEXT = 2 ** 16 - 1
28
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050029TYPE_RSA = _lib.EVP_PKEY_RSA
30TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080031
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080032
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050033class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050034 """
35 An error occurred in an `OpenSSL.crypto` API.
36 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050037
38
39_raise_current_error = partial(_exception_from_error_queue, Error)
40
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070041
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050042def _untested_error(where):
43 """
44 An OpenSSL API failed somehow. Additionally, the failure which was
45 encountered isn't one that's exercised by the test suite so future behavior
46 of pyOpenSSL is now somewhat less predictable.
47 """
48 raise RuntimeError("Unknown %s failure" % (where,))
49
50
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050051def _new_mem_buf(buffer=None):
52 """
53 Allocate a new OpenSSL memory BIO.
54
55 Arrange for the garbage collector to clean it up automatically.
56
57 :param buffer: None or some bytes to use to put into the BIO so that they
58 can be read out.
59 """
60 if buffer is None:
61 bio = _lib.BIO_new(_lib.BIO_s_mem())
62 free = _lib.BIO_free
63 else:
64 data = _ffi.new("char[]", buffer)
65 bio = _lib.BIO_new_mem_buf(data, len(buffer))
Alex Gaynor5945ea82015-09-05 14:59:06 -040066
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050067 # Keep the memory alive as long as the bio is alive!
68 def free(bio, ref=data):
69 return _lib.BIO_free(bio)
70
71 if bio == _ffi.NULL:
72 # TODO: This is untested.
73 _raise_current_error()
74
75 bio = _ffi.gc(bio, free)
76 return bio
77
78
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080079def _bio_to_string(bio):
80 """
81 Copy the contents of an OpenSSL BIO object into a Python byte string.
82 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050083 result_buffer = _ffi.new('char**')
84 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
85 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080086
87
Jean-Paul Calderone57122982013-02-21 08:47:05 -080088def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050089 """
90 The the time value of an ASN1 time object.
91
92 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
93 castable to that type) which will have its value set.
94 @param when: A string representation of the desired time value.
95
96 @raise TypeError: If C{when} is not a L{bytes} string.
97 @raise ValueError: If C{when} does not represent a time in the required
98 format.
99 @raise RuntimeError: If the time value cannot be set for some other
100 (unspecified) reason.
101 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800102 if not isinstance(when, bytes):
103 raise TypeError("when must be a byte string")
104
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500105 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
106 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800107 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500108 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
109 _lib.ASN1_STRING_set(dummy, when, len(when))
110 check_result = _lib.ASN1_GENERALIZEDTIME_check(
111 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800112 if not check_result:
113 raise ValueError("Invalid string")
114 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500115 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800116
117
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800118def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500119 """
120 Retrieve the time value of an ASN1 time object.
121
122 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
123 that type) from which the time value will be retrieved.
124
125 @return: The time value from C{timestamp} as a L{bytes} string in a certain
126 format. Or C{None} if the object contains no time value.
127 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500128 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
129 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800130 return None
Alex Gaynor5945ea82015-09-05 14:59:06 -0400131 elif (
132 _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
133 ):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500134 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800135 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500136 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
137 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
138 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500139 # This may happen:
140 # - if timestamp was not an ASN1_TIME
141 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
142 # - if a copy of the time data from timestamp cannot be made for
143 # the newly allocated ASN1_GENERALIZEDTIME
144 #
145 # These are difficult to test. cffi enforces the ASN1_TIME type.
146 # Memory allocation failures are a pain to trigger
147 # deterministically.
148 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800149 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500150 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800151 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500152 string_data = _lib.ASN1_STRING_data(string_timestamp)
153 string_result = _ffi.string(string_data)
154 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800155 return string_result
156
157
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800158class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200159 """
160 A class representing an DSA or RSA public key or key pair.
161 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800162 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800163 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800164
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800165 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500166 pkey = _lib.EVP_PKEY_new()
167 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800168 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800169
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800170 def generate_key(self, type, bits):
171 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700172 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800173
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200174 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800175
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200176 :param type: The key type.
177 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
178 :param bits: The number of bits.
179 :type bits: :py:data:`int` ``>= 0``
180 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
181 of the appropriate type.
182 :raises ValueError: If the number of bits isn't an integer of
183 the appropriate size.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200184 :return: :py:const:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800185 """
186 if not isinstance(type, int):
187 raise TypeError("type must be an integer")
188
189 if not isinstance(bits, int):
190 raise TypeError("bits must be an integer")
191
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800192 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500193 exponent = _lib.BN_new()
194 exponent = _ffi.gc(exponent, _lib.BN_free)
195 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800196
197 if type == TYPE_RSA:
198 if bits <= 0:
199 raise ValueError("Invalid number of bits")
200
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500201 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800202
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500203 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500204 if result == 0:
205 # TODO: The test for this case is commented out. Different
206 # builds of OpenSSL appear to have different failure modes that
207 # make it hard to test. Visual inspection of the OpenSSL
208 # source reveals that a return value of 0 signals an error.
209 # Manual testing on a particular build of OpenSSL suggests that
210 # this is probably the appropriate way to handle those errors.
211 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800212
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500213 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800214 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500215 # TODO: It appears as though this can fail if an engine is in
216 # use which does not support RSA.
217 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800218
219 elif type == TYPE_DSA:
Paul Kehrera0860b92016-03-09 21:39:27 -0400220 dsa = _lib.DSA_new()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500221 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500222 # TODO: This is untested.
223 _raise_current_error()
Paul Kehrerafa5a662016-03-10 10:29:28 -0400224
225 dsa = _ffi.gc(dsa, _lib.DSA_free)
Paul Kehrera0860b92016-03-09 21:39:27 -0400226 res = _lib.DSA_generate_parameters_ex(
227 dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL
228 )
229 if not res == 1:
230 # TODO: This is untested.
231 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500232 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500233 # TODO: This is untested.
234 _raise_current_error()
Paul Kehrerafa5a662016-03-10 10:29:28 -0400235 if not _lib.EVP_PKEY_set1_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500236 # TODO: This is untested.
237 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800238 else:
239 raise Error("No such key type")
240
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800241 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800242
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800243 def check(self):
244 """
245 Check the consistency of an RSA private key.
246
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200247 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
248
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800249 :return: True if key is consistent.
250 :raise Error: if the key is inconsistent.
251 :raise TypeError: if the key is of a type which cannot be checked.
252 Only RSA keys can currently be checked.
253 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800254 if self._only_public:
255 raise TypeError("public key only")
256
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100257 if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800258 raise TypeError("key type unsupported")
259
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500260 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
261 rsa = _ffi.gc(rsa, _lib.RSA_free)
262 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800263 if result:
264 return True
265 _raise_current_error()
266
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800267 def type(self):
268 """
269 Returns the type of the key
270
271 :return: The type of the key.
272 """
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100273 try:
274 # cryptography 1.2+
275 return _lib.Cryptography_EVP_PKEY_id(self._pkey)
276 except AttributeError:
277 # Older releases of cryptography.
278 return self._pkey.type
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800279
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800280 def bits(self):
281 """
282 Returns the number of bits of the key
283
284 :return: The number of bits of the key.
285 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500286 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800287PKeyType = PKey
288
289
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400290class _EllipticCurve(object):
291 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400292 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400293
294 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
295 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
296 instances each of which represents one curve supported by the system.
297 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400298 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400299 _curves = None
300
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400301 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400302 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400303 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400304 """
305 Implement cooperation with the right-hand side argument of ``!=``.
306
307 Python 3 seems to have dropped this cooperation in this very narrow
308 circumstance.
309 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400310 if isinstance(other, _EllipticCurve):
311 return super(_EllipticCurve, self).__ne__(other)
312 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400313
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400314 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400315 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400316 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400317 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400318
319 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400320
321 :return: A :py:type:`set` of ``cls`` instances giving the names of the
322 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400323 """
324 if lib.Cryptography_HAS_EC:
325 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
326 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400327 # The return value on this call should be num_curves again. We
328 # could check it to make sure but if it *isn't* then.. what could
329 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400330 lib.EC_get_builtin_curves(builtin_curves, num_curves)
331 return set(
332 cls.from_nid(lib, c.nid)
333 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400334 return set()
335
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400336 @classmethod
337 def _get_elliptic_curves(cls, lib):
338 """
339 Get, cache, and return the curves supported by OpenSSL.
340
341 :param lib: The OpenSSL library binding object.
342
343 :return: A :py:type:`set` of ``cls`` instances giving the names of the
344 elliptic curves the underlying library supports.
345 """
346 if cls._curves is None:
347 cls._curves = cls._load_elliptic_curves(lib)
348 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400349
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400350 @classmethod
351 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400352 """
353 Instantiate a new :py:class:`_EllipticCurve` associated with the given
354 OpenSSL NID.
355
356 :param lib: The OpenSSL library binding object.
357
358 :param nid: The OpenSSL NID the resulting curve object will represent.
359 This must be a curve NID (and not, for example, a hash NID) or
360 subsequent operations will fail in unpredictable ways.
361 :type nid: :py:class:`int`
362
363 :return: The curve object.
364 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400365 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
366
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400367 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400368 """
369 :param _lib: The :py:mod:`cryptography` binding instance used to
370 interface with OpenSSL.
371
372 :param _nid: The OpenSSL NID identifying the curve this object
373 represents.
374 :type _nid: :py:class:`int`
375
376 :param name: The OpenSSL short name identifying the curve this object
377 represents.
378 :type name: :py:class:`unicode`
379 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400380 self._lib = lib
381 self._nid = nid
382 self.name = name
383
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400384 def __repr__(self):
385 return "<Curve %r>" % (self.name,)
386
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400387 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400388 """
389 Create a new OpenSSL EC_KEY structure initialized to use this curve.
390
391 The structure is automatically garbage collected when the Python object
392 is garbage collected.
393 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400394 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
395 return _ffi.gc(key, _lib.EC_KEY_free)
396
397
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400398def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400399 """
400 Return a set of objects representing the elliptic curves supported in the
401 OpenSSL build in use.
402
403 The curve objects have a :py:class:`unicode` ``name`` attribute by which
404 they identify themselves.
405
406 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400407 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
408 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400409 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400410 return _EllipticCurve._get_elliptic_curves(_lib)
411
412
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400413def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400414 """
415 Return a single curve object selected by name.
416
417 See :py:func:`get_elliptic_curves` for information about curve objects.
418
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400419 :param name: The OpenSSL short name identifying the curve object to
420 retrieve.
421 :type name: :py:class:`unicode`
422
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400423 If the named curve is not supported then :py:class:`ValueError` is raised.
424 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400425 for curve in get_elliptic_curves():
426 if curve.name == name:
427 return curve
428 raise ValueError("unknown curve name", name)
429
430
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800431class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200432 """
433 An X.509 Distinguished Name.
434
435 :ivar countryName: The country of the entity.
436 :ivar C: Alias for :py:attr:`countryName`.
437
438 :ivar stateOrProvinceName: The state or province of the entity.
439 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
440
441 :ivar localityName: The locality of the entity.
442 :ivar L: Alias for :py:attr:`localityName`.
443
444 :ivar organizationName: The organization name of the entity.
445 :ivar O: Alias for :py:attr:`organizationName`.
446
447 :ivar organizationalUnitName: The organizational unit of the entity.
448 :ivar OU: Alias for :py:attr:`organizationalUnitName`
449
450 :ivar commonName: The common name of the entity.
451 :ivar CN: Alias for :py:attr:`commonName`.
452
453 :ivar emailAddress: The e-mail address of the entity.
454 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400455
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800456 def __init__(self, name):
457 """
458 Create a new X509Name, copying the given X509Name instance.
459
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200460 :param name: The name to copy.
461 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800462 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500463 name = _lib.X509_NAME_dup(name._name)
464 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800465
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800466 def __setattr__(self, name, value):
467 if name.startswith('_'):
468 return super(X509Name, self).__setattr__(name, value)
469
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800470 # Note: we really do not want str subclasses here, so we do not use
471 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800472 if type(name) is not str:
473 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400474 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800475
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500476 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500477 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800478 try:
479 _raise_current_error()
480 except Error:
481 pass
482 raise AttributeError("No such attribute")
483
484 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500485 for i in range(_lib.X509_NAME_entry_count(self._name)):
486 ent = _lib.X509_NAME_get_entry(self._name, i)
487 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
488 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800489 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500490 ent = _lib.X509_NAME_delete_entry(self._name, i)
491 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800492 break
493
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500494 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800495 value = value.encode('utf-8')
496
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500497 add_result = _lib.X509_NAME_add_entry_by_NID(
498 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800499 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500500 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800501
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800502 def __getattr__(self, name):
503 """
504 Find attribute. An X509Name object has the following attributes:
505 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400506 organization (alias O), organizationalUnit (alias OU), commonName
507 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800508 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500509 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500510 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800511 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
512 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
513 # push something onto the error queue. If we don't clean that up
514 # now, someone else will bump into it later and be quite confused.
515 # See lp#314814.
516 try:
517 _raise_current_error()
518 except Error:
519 pass
520 return super(X509Name, self).__getattr__(name)
521
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500522 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800523 if entry_index == -1:
524 return None
525
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500526 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
527 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800528
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500529 result_buffer = _ffi.new("unsigned char**")
530 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800531 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500532 # TODO: This is untested.
533 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800534
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700535 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400536 result = _ffi.buffer(
537 result_buffer[0], data_length
538 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700539 finally:
540 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500541 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800542 return result
543
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500544 def _cmp(op):
545 def f(self, other):
546 if not isinstance(other, X509Name):
547 return NotImplemented
548 result = _lib.X509_NAME_cmp(self._name, other._name)
549 return op(result, 0)
550 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800551
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500552 __eq__ = _cmp(__eq__)
553 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800554
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500555 __lt__ = _cmp(__lt__)
556 __le__ = _cmp(__le__)
557
558 __gt__ = _cmp(__gt__)
559 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800560
561 def __repr__(self):
562 """
563 String representation of an X509Name
564 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400565 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500566 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800567 self._name, result_buffer, len(result_buffer))
568
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500569 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500570 # TODO: This is untested.
571 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800572
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500573 return "<X509Name object '%s'>" % (
574 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800575
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800576 def hash(self):
577 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200578 Return an integer representation of the first four bytes of the
579 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800580
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200581 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
582
583 :return: The (integer) hash of this name.
584 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500586 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800587
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800588 def der(self):
589 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200590 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800591
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200592 :return: The DER encoded form of this name.
593 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800594 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500595 result_buffer = _ffi.new('unsigned char**')
596 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800597 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500598 # TODO: This is untested.
599 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800600
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500601 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
602 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800603 return string_result
604
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800605 def get_components(self):
606 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200607 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800608
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200609 :return: The components of this name.
610 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800611 """
612 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500613 for i in range(_lib.X509_NAME_entry_count(self._name)):
614 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800615
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500616 fname = _lib.X509_NAME_ENTRY_get_object(ent)
617 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800618
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500619 nid = _lib.OBJ_obj2nid(fname)
620 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800621
622 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400623 _ffi.string(name),
624 _ffi.string(
625 _lib.ASN1_STRING_data(fval),
626 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800627
628 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200629
630
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800631X509NameType = X509Name
632
633
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800634class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200635 """
636 An X.509 v3 certificate extension.
637 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400638
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800639 def __init__(self, type_name, critical, value, subject=None, issuer=None):
640 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200641 Initializes an X509 extension.
642
Alex Gaynor6f719912015-09-20 09:21:29 -0400643 :param type_name: The name of the type of extension to create. See
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200644 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Alex Gaynor6f719912015-09-20 09:21:29 -0400645 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800646
Alex Gaynor5945ea82015-09-05 14:59:06 -0400647 :param bool critical: A flag indicating whether this is a critical
648 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800649
650 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200651 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800652
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200653 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800654 :type subject: :py:class:`X509`
655
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200656 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800657 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800658 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500659 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800660
Alex Gaynor5945ea82015-09-05 14:59:06 -0400661 # A context is necessary for any extension which uses the r2i
662 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
663 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500664 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800665
666 # We have no configuration database - but perhaps we should (some
667 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500668 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800669
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800670 # Initialize the subject and issuer, if appropriate. ctx is a local,
671 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400672 # any references, so no need to mess with reference counts or
673 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800674 if issuer is not None:
675 if not isinstance(issuer, X509):
676 raise TypeError("issuer must be an X509 instance")
677 ctx.issuer_cert = issuer._x509
678 if subject is not None:
679 if not isinstance(subject, X509):
680 raise TypeError("subject must be an X509 instance")
681 ctx.subject_cert = subject._x509
682
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800683 if critical:
684 # There are other OpenSSL APIs which would let us pass in critical
685 # separately, but they're harder to use, and since value is already
686 # a pile of crappy junk smuggling a ton of utterly important
687 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400688 # with strings? (However, X509V3_EXT_i2d in particular seems like
689 # it would be a better API to invoke. I do not know where to get
690 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500691 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800692
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500693 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
694 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800695 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500696 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800697
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400698 @property
699 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500700 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400701
702 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500703 _lib.GEN_EMAIL: "email",
704 _lib.GEN_DNS: "DNS",
705 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400706 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400707
708 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500709 method = _lib.X509V3_EXT_get(self._extension)
710 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500711 # TODO: This is untested.
712 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400713 payload = self._extension.value.data
714 length = self._extension.value.length
715
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500716 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400717 payloadptr[0] = payload
718
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500719 if method.it != _ffi.NULL:
720 ptr = _lib.ASN1_ITEM_ptr(method.it)
721 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
722 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400723 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500724 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400725 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500726 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400727
Paul Kehrerb7d79502015-05-04 07:43:51 -0500728 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400729 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500730 for i in range(_lib.sk_GENERAL_NAME_num(names)):
731 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400732 try:
733 label = self._prefixes[name.type]
734 except KeyError:
735 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500736 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500737 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400738 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500739 value = _native(
740 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
741 parts.append(label + ":" + value)
742 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400743
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800744 def __str__(self):
745 """
746 :return: a nice text representation of the extension
747 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500748 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400749 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800750
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400751 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500752 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800753 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500754 # TODO: This is untested.
755 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800756
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500757 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800758
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800759 def get_critical(self):
760 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200761 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800762
763 :return: The critical field.
764 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500765 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800766
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800767 def get_short_name(self):
768 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200769 Returns the short type name of this X.509 extension.
770
771 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800772
773 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200774 :rtype: :py:data:`bytes`
775
776 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800777 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500778 obj = _lib.X509_EXTENSION_get_object(self._extension)
779 nid = _lib.OBJ_obj2nid(obj)
780 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800781
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800782 def get_data(self):
783 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200784 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800785
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200786 :return: The ASN.1 encoded data of this X509 extension.
787 :rtype: :py:data:`bytes`
788
789 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800790 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500791 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
792 string_result = _ffi.cast('ASN1_STRING*', octet_result)
793 char_result = _lib.ASN1_STRING_data(string_result)
794 result_length = _lib.ASN1_STRING_length(string_result)
795 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800796
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200797
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800798X509ExtensionType = X509Extension
799
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800800
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800801class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200802 """
803 An X.509 certificate signing requests.
804 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400805
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800806 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500807 req = _lib.X509_REQ_new()
808 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800809
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800810 def set_pubkey(self, pkey):
811 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200812 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800813
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200814 :param pkey: The public key to use.
815 :type pkey: :py:class:`PKey`
816
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200817 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800818 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500819 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800820 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500821 # TODO: This is untested.
822 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800823
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800824 def get_pubkey(self):
825 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200826 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800827
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200828 :return: The public key.
829 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800830 """
831 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500832 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
833 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500834 # TODO: This is untested.
835 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500836 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800837 pkey._only_public = True
838 return pkey
839
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800840 def set_version(self, version):
841 """
842 Set 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 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200846 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800847 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500848 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800849 if not set_result:
850 _raise_current_error()
851
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800852 def get_version(self):
853 """
854 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
855 request.
856
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200857 :return: The value of the version subfield.
858 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800859 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500860 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800861
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800862 def get_subject(self):
863 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200864 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800865
Cory Benfield881dc8d2015-12-09 08:25:14 +0000866 This creates a new :class:`X509Name` that wraps the underlying subject
867 name field on the certificate signing request. Modifying it will modify
868 the underlying signing request, and will have the effect of modifying
869 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200870
871 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000872 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800873 """
874 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500875 name._name = _lib.X509_REQ_get_subject_name(self._req)
876 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500877 # TODO: This is untested.
878 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800879
880 # The name is owned by the X509Req structure. As long as the X509Name
881 # Python object is alive, keep the X509Req Python object alive.
882 name._owner = self
883
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800884 return name
885
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800886 def add_extensions(self, extensions):
887 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200888 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200890 :param extensions: The X.509 extensions to add.
891 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200892 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800893 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500894 stack = _lib.sk_X509_EXTENSION_new_null()
895 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500896 # TODO: This is untested.
897 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800898
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500899 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800900
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800901 for ext in extensions:
902 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800903 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800904
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800905 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500906 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800907
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500908 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800909 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500910 # TODO: This is untested.
911 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800912
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800913 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800914 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200915 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800916
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200917 :return: The X.509 extensions in this request.
918 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
919
920 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800921 """
922 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500923 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500924 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800925 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500926 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800927 exts.append(ext)
928 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800929
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800930 def sign(self, pkey, digest):
931 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700932 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800933
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200934 :param pkey: The key pair to sign with.
935 :type pkey: :py:class:`PKey`
936 :param digest: The name of the message digest to use for the signature,
937 e.g. :py:data:`b"sha1"`.
938 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200939 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800940 """
941 if pkey._only_public:
942 raise ValueError("Key has only public part")
943
944 if not pkey._initialized:
945 raise ValueError("Key is uninitialized")
946
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500947 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500948 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800949 raise ValueError("No such digest method")
950
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500951 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800952 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500953 # TODO: This is untested.
954 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800955
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800956 def verify(self, pkey):
957 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200958 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800959
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200960 :param key: A public key.
961 :type key: :py:class:`PKey`
962 :return: :py:data:`True` if the signature is correct.
963 :rtype: :py:class:`bool`
964 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800965 problem verifying the signature.
966 """
967 if not isinstance(pkey, PKey):
968 raise TypeError("pkey must be a PKey instance")
969
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500970 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800971 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500972 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800973
974 return result
975
976
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800977X509ReqType = X509Req
978
979
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800980class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200981 """
982 An X.509 certificate.
983 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400984
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800985 def __init__(self):
986 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500987 x509 = _lib.X509_new()
988 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800989
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800990 def set_version(self, version):
991 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200992 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800993
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200994 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800995 :type version: :py:class:`int`
996
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200997 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800998 """
999 if not isinstance(version, int):
1000 raise TypeError("version must be an integer")
1001
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001002 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001003
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001004 def get_version(self):
1005 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001006 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001007
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001008 :return: The version number of the certificate.
1009 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001010 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001011 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001012
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001013 def get_pubkey(self):
1014 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001015 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001016
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001017 :return: The public key.
1018 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001019 """
1020 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001021 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1022 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001023 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001024 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001025 pkey._only_public = True
1026 return pkey
1027
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001028 def set_pubkey(self, pkey):
1029 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001030 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001031
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001032 :param pkey: The public key.
1033 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001034
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001035 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001036 """
1037 if not isinstance(pkey, PKey):
1038 raise TypeError("pkey must be a PKey instance")
1039
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001040 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001041 if not set_result:
1042 _raise_current_error()
1043
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001044 def sign(self, pkey, digest):
1045 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001046 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001047
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001048 :param pkey: The key to sign with.
1049 :type pkey: :py:class:`PKey`
1050
1051 :param digest: The name of the message digest to use.
1052 :type digest: :py:class:`bytes`
1053
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001054 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001055 """
1056 if not isinstance(pkey, PKey):
1057 raise TypeError("pkey must be a PKey instance")
1058
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001059 if pkey._only_public:
1060 raise ValueError("Key only has public part")
1061
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001062 if not pkey._initialized:
1063 raise ValueError("Key is uninitialized")
1064
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001065 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001066 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001067 raise ValueError("No such digest method")
1068
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001069 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001070 if not sign_result:
1071 _raise_current_error()
1072
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001073 def get_signature_algorithm(self):
1074 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001075 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001076
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001077 :return: The name of the algorithm.
1078 :rtype: :py:class:`bytes`
1079
1080 :raises ValueError: If the signature algorithm is undefined.
1081
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001082 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001083 """
1084 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001085 nid = _lib.OBJ_obj2nid(alg)
1086 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001087 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001088 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001089
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001090 def digest(self, digest_name):
1091 """
1092 Return the digest of the X509 object.
1093
1094 :param digest_name: The name of the digest algorithm to use.
1095 :type digest_name: :py:class:`bytes`
1096
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001097 :return: The digest of the object, formatted as
1098 :py:const:`b":"`-delimited hex pairs.
1099 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001100 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001101 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001102 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001103 raise ValueError("No such digest method")
1104
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001105 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1106 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001107 result_length[0] = len(result_buffer)
1108
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001109 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001110 self._x509, digest, result_buffer, result_length)
1111
1112 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001113 # TODO: This is untested.
1114 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001115
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001116 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001117 b16encode(ch).upper() for ch
1118 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001119
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001120 def subject_name_hash(self):
1121 """
1122 Return the hash of the X509 subject.
1123
1124 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001125 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001126 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001127 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001128
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001129 def set_serial_number(self, serial):
1130 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001131 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001132
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001133 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001134 :type serial: :py:class:`int`
1135
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001136 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001137 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001138 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001139 raise TypeError("serial must be an integer")
1140
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001141 hex_serial = hex(serial)[2:]
1142 if not isinstance(hex_serial, bytes):
1143 hex_serial = hex_serial.encode('ascii')
1144
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001145 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001146
1147 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001148 # it. If bignum is still NULL after this call, then the return value
1149 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001150 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001151
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001152 if bignum_serial[0] == _ffi.NULL:
1153 set_result = _lib.ASN1_INTEGER_set(
1154 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001155 if set_result:
1156 # TODO Not tested
1157 _raise_current_error()
1158 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001159 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1160 _lib.BN_free(bignum_serial[0])
1161 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001162 # TODO Not tested
1163 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001164 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1165 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001166 if not set_result:
1167 # TODO Not tested
1168 _raise_current_error()
1169
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001170 def get_serial_number(self):
1171 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001172 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001173
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001174 :return: The serial number.
1175 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001176 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001177 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1178 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001179 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001180 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001181 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001182 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001183 serial = int(hexstring_serial, 16)
1184 return serial
1185 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001186 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001187 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001188 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001189
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001190 def gmtime_adj_notAfter(self, amount):
1191 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001192 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001193
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001194 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001195 :type amount: :py:class:`int`
1196
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001197 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001198 """
1199 if not isinstance(amount, int):
1200 raise TypeError("amount must be an integer")
1201
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001202 notAfter = _lib.X509_get_notAfter(self._x509)
1203 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001204
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001205 def gmtime_adj_notBefore(self, amount):
1206 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001207 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001208
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001209 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001210 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001211 """
1212 if not isinstance(amount, int):
1213 raise TypeError("amount must be an integer")
1214
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001215 notBefore = _lib.X509_get_notBefore(self._x509)
1216 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001217
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001218 def has_expired(self):
1219 """
1220 Check whether the certificate has expired.
1221
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001222 :return: :py:const:`True` if the certificate has expired,
1223 :py:const:`False` otherwise.
1224 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001225 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001226 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001227 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001228
Paul Kehrerfde45c92016-01-21 12:57:37 -06001229 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001230
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001231 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001232 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001233
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001234 def get_notBefore(self):
1235 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001236 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001237
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001238 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001239
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001240 YYYYMMDDhhmmssZ
1241 YYYYMMDDhhmmss+hhmm
1242 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001243
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001244 :return: A timestamp string, or :py:const:`None` if there is none.
1245 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001246 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001247 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001248
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001249 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001250 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001251
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001252 def set_notBefore(self, when):
1253 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001254 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001255
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001256 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001257
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001258 YYYYMMDDhhmmssZ
1259 YYYYMMDDhhmmss+hhmm
1260 YYYYMMDDhhmmss-hhmm
1261
1262 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001263 :type when: :py:class:`bytes`
1264
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001265 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001266 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001267 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001268
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001269 def get_notAfter(self):
1270 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001271 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001272
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001273 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001274
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001275 YYYYMMDDhhmmssZ
1276 YYYYMMDDhhmmss+hhmm
1277 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001278
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001279 :return: A timestamp string, or :py:const:`None` if there is none.
1280 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001281 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001282 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001283
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001284 def set_notAfter(self, when):
1285 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001286 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001287
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001288 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001289
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001290 YYYYMMDDhhmmssZ
1291 YYYYMMDDhhmmss+hhmm
1292 YYYYMMDDhhmmss-hhmm
1293
1294 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001295 :type when: :py:class:`bytes`
1296
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001297 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001298 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001299 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001300
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001301 def _get_name(self, which):
1302 name = X509Name.__new__(X509Name)
1303 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001304 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001305 # TODO: This is untested.
1306 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001307
1308 # The name is owned by the X509 structure. As long as the X509Name
1309 # Python object is alive, keep the X509 Python object alive.
1310 name._owner = self
1311
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001312 return name
1313
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001314 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001315 if not isinstance(name, X509Name):
1316 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001317 set_result = which(self._x509, name._name)
1318 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001319 # TODO: This is untested.
1320 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001321
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001322 def get_issuer(self):
1323 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001324 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001325
Cory Benfielde6bcce82015-12-09 08:40:03 +00001326 This creates a new :class:`X509Name` that wraps the underlying issuer
1327 name field on the certificate. Modifying it will modify the underlying
1328 certificate, and will have the effect of modifying any other
1329 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001330
1331 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001332 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001333 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001334 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001335
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001336 def set_issuer(self, issuer):
1337 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001338 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001339
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001340 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001341 :type issuer: :py:class:`X509Name`
1342
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001343 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001344 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001345 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001346
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001347 def get_subject(self):
1348 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001349 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001350
Cory Benfielde6bcce82015-12-09 08:40:03 +00001351 This creates a new :class:`X509Name` that wraps the underlying subject
1352 name field on the certificate. Modifying it will modify the underlying
1353 certificate, and will have the effect of modifying any other
1354 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001355
1356 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001357 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001358 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001359 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001360
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001361 def set_subject(self, subject):
1362 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001363 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001364
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001365 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001366 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001367
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001368 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001369 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001370 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001371
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001372 def get_extension_count(self):
1373 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001374 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001375
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001376 :return: The number of extensions.
1377 :rtype: :py:class:`int`
1378
1379 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001380 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001381 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001382
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001383 def add_extensions(self, extensions):
1384 """
1385 Add extensions to the certificate.
1386
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001387 :param extensions: The extensions to add.
1388 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001389 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001390 """
1391 for ext in extensions:
1392 if not isinstance(ext, X509Extension):
1393 raise ValueError("One of the elements is not an X509Extension")
1394
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001395 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001396 if not add_result:
1397 _raise_current_error()
1398
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001399 def get_extension(self, index):
1400 """
1401 Get a specific extension of the certificate by index.
1402
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001403 Extensions on a certificate are kept in order. The index
1404 parameter selects which extension will be returned.
1405
1406 :param int index: The index of the extension to retrieve.
1407 :return: The extension at the specified index.
1408 :rtype: :py:class:`X509Extension`
1409 :raises IndexError: If the extension index was out of bounds.
1410
1411 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001412 """
1413 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001414 ext._extension = _lib.X509_get_ext(self._x509, index)
1415 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001416 raise IndexError("extension index out of bounds")
1417
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001418 extension = _lib.X509_EXTENSION_dup(ext._extension)
1419 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001420 return ext
1421
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001422
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001423X509Type = X509
1424
1425
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001426class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001427 """
1428 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001429 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001430
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001431 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001432 store = _lib.X509_STORE_new()
1433 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001434
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001435 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001436 """
1437 Adds the certificate :py:data:`cert` to this store.
1438
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001439 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001440
1441 :param X509 cert: The certificate to add to this store.
1442 :raises TypeError: If the certificate is not an :py:class:`X509`.
1443 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001444 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001445 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001446 if not isinstance(cert, X509):
1447 raise TypeError()
1448
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001449 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001450 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001451 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001452
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001453
1454X509StoreType = X509Store
1455
1456
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001457class X509StoreContextError(Exception):
1458 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001459 An exception raised when an error occurred while verifying a certificate
1460 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001461
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001462 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001463 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001464 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001465
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001466 def __init__(self, message, certificate):
1467 super(X509StoreContextError, self).__init__(message)
1468 self.certificate = certificate
1469
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001470
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001471class X509StoreContext(object):
1472 """
1473 An X.509 store context.
1474
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001475 An :py:class:`X509StoreContext` is used to define some of the criteria for
1476 certificate verification. The information encapsulated in this object
1477 includes, but is not limited to, a set of trusted certificates,
1478 verification parameters, and revoked certificates.
1479
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001480 .. note::
1481
1482 Currently, one can only set the trusted certificates on an
1483 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1484 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001485
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001486 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1487 instance. It is dynamically allocated and automatically garbage
1488 collected.
1489
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001490 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001491
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001492 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001493
1494 :param X509Store store: The certificates which will be trusted for the
1495 purposes of any verifications.
1496
1497 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001498 """
1499
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001500 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001501 store_ctx = _lib.X509_STORE_CTX_new()
1502 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1503 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001504 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001505 # Make the store context available for use after instantiating this
1506 # class by initializing it now. Per testing, subsequent calls to
1507 # :py:meth:`_init` have no adverse affect.
1508 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001509
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001510 def _init(self):
1511 """
1512 Set up the store context for a subsequent verification operation.
1513 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001514 ret = _lib.X509_STORE_CTX_init(
1515 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1516 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001517 if ret <= 0:
1518 _raise_current_error()
1519
1520 def _cleanup(self):
1521 """
1522 Internally cleans up the store context.
1523
1524 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001525 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001526 """
1527 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1528
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001529 def _exception_from_context(self):
1530 """
1531 Convert an OpenSSL native context error failure into a Python
1532 exception.
1533
Alex Gaynor5945ea82015-09-05 14:59:06 -04001534 When a call to native OpenSSL X509_verify_cert fails, additional
1535 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001536 """
1537 errors = [
1538 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1539 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1540 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001541 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001542 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001543 # A context error should always be associated with a certificate, so we
1544 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001545 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001546 _cert = _lib.X509_dup(_x509)
1547 pycert = X509.__new__(X509)
1548 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001549 return X509StoreContextError(errors, pycert)
1550
Stephen Holsapple46a09252015-02-12 14:45:43 -08001551 def set_store(self, store):
1552 """
1553 Set the context's trust store.
1554
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001555 .. versionadded:: 0.15
1556
Stephen Holsapple46a09252015-02-12 14:45:43 -08001557 :param X509Store store: The certificates which will be trusted for the
1558 purposes of any *future* verifications.
1559 """
1560 self._store = store
1561
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001562 def verify_certificate(self):
1563 """
1564 Verify a certificate in a context.
1565
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001566 .. versionadded:: 0.15
1567
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001568 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001569
Alex Gaynorca87ff62015-09-04 23:31:03 -04001570 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001571 certificate in the context. Sets ``certificate`` attribute to
1572 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001573 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001574 # Always re-initialize the store context in case
1575 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001576 self._init()
1577 ret = _lib.X509_verify_cert(self._store_ctx)
1578 self._cleanup()
1579 if ret <= 0:
1580 raise self._exception_from_context()
1581
1582
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001583def load_certificate(type, buffer):
1584 """
1585 Load a certificate from a buffer
1586
1587 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1588
1589 :param buffer: The buffer the certificate is stored in
1590 :type buffer: :py:class:`bytes`
1591
1592 :return: The X509 object
1593 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001594 if isinstance(buffer, _text_type):
1595 buffer = buffer.encode("ascii")
1596
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001597 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001598
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001599 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001600 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001601 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001602 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001603 else:
1604 raise ValueError(
1605 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001606
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001607 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001608 _raise_current_error()
1609
1610 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001611 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001612 return cert
1613
1614
1615def dump_certificate(type, cert):
1616 """
1617 Dump a certificate to a buffer
1618
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001619 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1620 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001621 :param cert: The certificate to dump
1622 :return: The buffer with the dumped certificate in
1623 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001624 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001625
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001626 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001627 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001628 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001629 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001630 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001631 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001632 else:
1633 raise ValueError(
1634 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1635 "FILETYPE_TEXT")
1636
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001637 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001638 return _bio_to_string(bio)
1639
1640
Cory Benfield6492f7c2015-10-27 16:57:58 +09001641def dump_publickey(type, pkey):
1642 """
Cory Benfield11c10192015-10-27 17:23:03 +09001643 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001644
Cory Benfield9c590b92015-10-28 14:55:05 +09001645 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001646 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001647 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001648 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001649 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001650 """
1651 bio = _new_mem_buf()
1652 if type == FILETYPE_PEM:
1653 write_bio = _lib.PEM_write_bio_PUBKEY
1654 elif type == FILETYPE_ASN1:
1655 write_bio = _lib.i2d_PUBKEY_bio
1656 else:
1657 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1658
1659 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001660 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001661 _raise_current_error()
1662
1663 return _bio_to_string(bio)
1664
1665
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001666def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1667 """
1668 Dump a private key to a buffer
1669
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001670 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1671 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001672 :param pkey: The PKey to dump
1673 :param cipher: (optional) if encrypted PEM format, the cipher to
1674 use
1675 :param passphrase: (optional) if encrypted PEM format, this can be either
1676 the passphrase to use, or a callback for providing the
1677 passphrase.
1678 :return: The buffer with the dumped key in
Maximilian Hils0de43752015-09-18 15:26:54 +02001679 :rtype: :py:data:`bytes`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001680 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001681 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001682
1683 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001684 if passphrase is None:
1685 raise TypeError(
1686 "if a value is given for cipher "
1687 "one must also be given for passphrase")
1688 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001689 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001690 raise ValueError("Invalid cipher name")
1691 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001692 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001693
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001694 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001695 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001696 result_code = _lib.PEM_write_bio_PrivateKey(
1697 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001698 helper.callback, helper.callback_args)
1699 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001700 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001701 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001702 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001703 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1704 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001705 # TODO RSA_free(rsa)?
1706 else:
1707 raise ValueError(
1708 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1709 "FILETYPE_TEXT")
1710
1711 if result_code == 0:
1712 _raise_current_error()
1713
1714 return _bio_to_string(bio)
1715
1716
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001717def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001718 copy = _lib.X509_REVOKED_new()
1719 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001720 # TODO: This is untested.
1721 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001722
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001723 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001724 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001725 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001726
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001727 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001728 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001729 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001730
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001731 if original.extensions != _ffi.NULL:
1732 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1733 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1734 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1735 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1736 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001737 copy.extensions = extension_stack
1738
1739 copy.sequence = original.sequence
1740 return copy
1741
1742
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001743class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001744 """
1745 A certificate revocation.
1746 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001747 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1748 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1749 # OCSP_crl_reason_str. We use the latter, just like the command line
1750 # program.
1751 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001752 b"unspecified",
1753 b"keyCompromise",
1754 b"CACompromise",
1755 b"affiliationChanged",
1756 b"superseded",
1757 b"cessationOfOperation",
1758 b"certificateHold",
1759 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001760 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001761
1762 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001763 revoked = _lib.X509_REVOKED_new()
1764 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001765
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001766 def set_serial(self, hex_str):
1767 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001768 Set the serial number.
1769
1770 The serial number is formatted as a hexadecimal number encoded in
1771 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001772
1773 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001774 :type hex_str: :py:class:`bytes`
1775
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001776 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001777 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001778 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1779 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001780 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001781 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001782 if not bn_result:
1783 raise ValueError("bad hex string")
1784
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001785 asn1_serial = _ffi.gc(
1786 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1787 _lib.ASN1_INTEGER_free)
1788 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001789
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001790 def get_serial(self):
1791 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001792 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001793
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001794 The serial number is formatted as a hexadecimal number encoded in
1795 ASCII.
1796
1797 :return: The serial number.
1798 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001799 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001800 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001801
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001802 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001803 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001804 # TODO: This is untested.
1805 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001806
1807 return _bio_to_string(bio)
1808
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809 def _delete_reason(self):
1810 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001811 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1812 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1813 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1814 _lib.X509_EXTENSION_free(ext)
1815 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001816 break
1817
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001818 def set_reason(self, reason):
1819 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001820 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001821
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001822 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001823
1824 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001825 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1826
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001827 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001828
1829 .. seealso::
1830
1831 :py:meth:`all_reasons`, which gives you a list of all supported
1832 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001833 """
1834 if reason is None:
1835 self._delete_reason()
1836 elif not isinstance(reason, bytes):
1837 raise TypeError("reason must be None or a byte string")
1838 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001839 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001840 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1841
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001842 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1843 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001844 # TODO: This is untested.
1845 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001846 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001847
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001848 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1849 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001850 # TODO: This is untested.
1851 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001852
1853 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001854 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1855 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001856
1857 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001858 # TODO: This is untested.
1859 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001860
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001861 def get_reason(self):
1862 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001863 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001864
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001865 :return: The reason, or :py:const:`None` if there is none.
1866 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1867
1868 .. seealso::
1869
1870 :py:meth:`all_reasons`, which gives you a list of all supported
1871 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001872 """
1873 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001874 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1875 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1876 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001877 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001878
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001879 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001880 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001881 print_result = _lib.M_ASN1_OCTET_STRING_print(
1882 bio, ext.value
1883 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001884 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001885 # TODO: This is untested.
1886 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001887
1888 return _bio_to_string(bio)
1889
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001890 def all_reasons(self):
1891 """
1892 Return a list of all the supported reason strings.
1893
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001894 This list is a copy; modifying it does not change the supported reason
1895 strings.
1896
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001897 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001898 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001899 """
1900 return self._crl_reasons[:]
1901
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001902 def set_rev_date(self, when):
1903 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001904 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001905
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001906 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1907 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001908 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001909 """
1910 return _set_asn1_time(self._revoked.revocationDate, when)
1911
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001912 def get_rev_date(self):
1913 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001914 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001915
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001916 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1917 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001918 """
1919 return _get_asn1_time(self._revoked.revocationDate)
1920
1921
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001922class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001923 """
1924 A certificate revocation list.
1925 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001926
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001927 def __init__(self):
1928 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001929 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001930 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001931 crl = _lib.X509_CRL_new()
1932 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001933
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001934 def get_revoked(self):
1935 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001936 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001937
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001938 These revocations will be provided by value, not by reference.
1939 That means it's okay to mutate them: it won't affect this CRL.
1940
1941 :return: The revocations in this CRL.
1942 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001943 """
1944 results = []
1945 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001946 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1947 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001948 revoked_copy = _X509_REVOKED_dup(revoked)
1949 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001950 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001951 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001952 if results:
1953 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001954
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001955 def add_revoked(self, revoked):
1956 """
1957 Add a revoked (by value not reference) to the CRL structure
1958
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001959 This revocation will be added by value, not by reference. That
1960 means it's okay to mutate it after adding: it won't affect
1961 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001962
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001963 :param revoked: The new revocation.
1964 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001965
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001966 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001967 """
1968 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001969 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001970 # TODO: This is untested.
1971 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001972
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001973 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001974 if add_result == 0:
1975 # TODO: This is untested.
1976 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001977
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001978 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001979 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001980 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001981 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001982
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001983 :param cert: The certificate used to sign the CRL.
1984 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001985
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001986 :param key: The key used to sign the CRL.
1987 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001988
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001989 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1990 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001991
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001992 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001993
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001994 :param bytes digest: The name of the message digest to use (eg
1995 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001996
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001997 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001998 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001999 if not isinstance(cert, X509):
2000 raise TypeError("cert must be an X509 instance")
2001 if not isinstance(key, PKey):
2002 raise TypeError("key must be a PKey instance")
2003 if not isinstance(type, int):
2004 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002005
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002006 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002007 _warn(
2008 "The default message digest (md5) is deprecated. "
2009 "Pass the name of a message digest explicitly.",
2010 category=DeprecationWarning,
2011 stacklevel=2,
2012 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002013 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002014
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002015 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002016 if digest_obj == _ffi.NULL:
2017 raise ValueError("No such digest method")
2018
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002019 bio = _lib.BIO_new(_lib.BIO_s_mem())
2020 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002021 # TODO: This is untested.
2022 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002023
Alex Gaynora738ed52015-09-05 11:17:10 -04002024 # A scratch time object to give different values to different CRL
2025 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002026 sometime = _lib.ASN1_TIME_new()
2027 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002028 # TODO: This is untested.
2029 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002030
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002031 _lib.X509_gmtime_adj(sometime, 0)
2032 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002033
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002034 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2035 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002036
Alex Gaynor5945ea82015-09-05 14:59:06 -04002037 _lib.X509_CRL_set_issuer_name(
2038 self._crl, _lib.X509_get_subject_name(cert._x509)
2039 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002040
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002041 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002042 if not sign_result:
2043 _raise_current_error()
2044
Dominic Chenf05b2122015-10-13 16:32:35 +00002045 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002046
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002047
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002048CRLType = CRL
2049
2050
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002051class PKCS7(object):
2052 def type_is_signed(self):
2053 """
2054 Check if this NID_pkcs7_signed object
2055
2056 :return: True if the PKCS7 is of type signed
2057 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002058 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002059 return True
2060 return False
2061
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002062 def type_is_enveloped(self):
2063 """
2064 Check if this NID_pkcs7_enveloped object
2065
2066 :returns: True if the PKCS7 is of type enveloped
2067 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002068 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002069 return True
2070 return False
2071
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002072 def type_is_signedAndEnveloped(self):
2073 """
2074 Check if this NID_pkcs7_signedAndEnveloped object
2075
2076 :returns: True if the PKCS7 is of type signedAndEnveloped
2077 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002078 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002079 return True
2080 return False
2081
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002082 def type_is_data(self):
2083 """
2084 Check if this NID_pkcs7_data object
2085
2086 :return: True if the PKCS7 is of type data
2087 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002088 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002089 return True
2090 return False
2091
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002092 def get_type_name(self):
2093 """
2094 Returns the type name of the PKCS7 structure
2095
2096 :return: A string with the typename
2097 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002098 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2099 string_type = _lib.OBJ_nid2sn(nid)
2100 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002101
2102PKCS7Type = PKCS7
2103
2104
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002105class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002106 """
2107 A PKCS #12 archive.
2108 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002109
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002110 def __init__(self):
2111 self._pkey = None
2112 self._cert = None
2113 self._cacerts = None
2114 self._friendlyname = None
2115
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002116 def get_certificate(self):
2117 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002118 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002119
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002120 :return: The certificate, or :py:const:`None` if there is none.
2121 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002122 """
2123 return self._cert
2124
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002125 def set_certificate(self, cert):
2126 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002127 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002128
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002129 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002130 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002131
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002132 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002133 """
2134 if not isinstance(cert, X509):
2135 raise TypeError("cert must be an X509 instance")
2136 self._cert = cert
2137
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002138 def get_privatekey(self):
2139 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002140 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002141
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002142 :return: The private key, or :py:const:`None` if there is none.
2143 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002144 """
2145 return self._pkey
2146
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002147 def set_privatekey(self, pkey):
2148 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002149 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002150
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002151 :param pkey: The new private key, or :py:const:`None` to unset it.
2152 :type pkey: :py:class:`PKey` or :py:const:`None`
2153
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002154 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002155 """
2156 if not isinstance(pkey, PKey):
2157 raise TypeError("pkey must be a PKey instance")
2158 self._pkey = pkey
2159
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002160 def get_ca_certificates(self):
2161 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002162 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002163
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002164 :return: A tuple with the CA certificates in the chain, or
2165 :py:const:`None` if there are none.
2166 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002167 """
2168 if self._cacerts is not None:
2169 return tuple(self._cacerts)
2170
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002171 def set_ca_certificates(self, cacerts):
2172 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002173 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002174
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002175 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2176 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002177 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002178
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002179 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002180 """
2181 if cacerts is None:
2182 self._cacerts = None
2183 else:
2184 cacerts = list(cacerts)
2185 for cert in cacerts:
2186 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002187 raise TypeError(
2188 "iterable must only contain X509 instances"
2189 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002190 self._cacerts = cacerts
2191
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002192 def set_friendlyname(self, name):
2193 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002194 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002195
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002196 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002197 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002198
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002199 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002200 """
2201 if name is None:
2202 self._friendlyname = None
2203 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002204 raise TypeError(
2205 "name must be a byte string or None (not %r)" % (name,)
2206 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002207 self._friendlyname = name
2208
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002209 def get_friendlyname(self):
2210 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002211 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002212
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002213 :returns: The friendly name, or :py:const:`None` if there is none.
2214 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002215 """
2216 return self._friendlyname
2217
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002218 def export(self, passphrase=None, iter=2048, maciter=1):
2219 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002220 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002221
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002222 For more information, see the :c:func:`PKCS12_create` man page.
2223
2224 :param passphrase: The passphrase used to encrypt the structure. Unlike
2225 some other passphrase arguments, this *must* be a string, not a
2226 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002227 :type passphrase: :py:data:`bytes`
2228
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002229 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002230 :type iter: :py:data:`int`
2231
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002232 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002233 :type maciter: :py:data:`int`
2234
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002235 :return: The string representation of the PKCS #12 structure.
2236 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002237 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002238 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002239
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002240 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002241 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002242 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002243 cacerts = _lib.sk_X509_new_null()
2244 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002245 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002246 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002247
2248 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002249 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002250
2251 friendlyname = self._friendlyname
2252 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002253 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002254
2255 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002256 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002257 else:
2258 pkey = self._pkey._pkey
2259
2260 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002261 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002262 else:
2263 cert = self._cert._x509
2264
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002265 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002266 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002267 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2268 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002269 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002270 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002271 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002272 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002273
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002274 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002275 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002276 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002277
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002278
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002279PKCS12Type = PKCS12
2280
2281
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002282class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002283 """
2284 A Netscape SPKI object.
2285 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002286
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002287 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002288 spki = _lib.NETSCAPE_SPKI_new()
2289 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002290
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002291 def sign(self, pkey, digest):
2292 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002293 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002294
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002295 :param pkey: The private key to sign with.
2296 :type pkey: :py:class:`PKey`
2297
2298 :param digest: The message digest to use.
2299 :type digest: :py:class:`bytes`
2300
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002301 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002302 """
2303 if pkey._only_public:
2304 raise ValueError("Key has only public part")
2305
2306 if not pkey._initialized:
2307 raise ValueError("Key is uninitialized")
2308
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002309 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002310 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002311 raise ValueError("No such digest method")
2312
Alex Gaynor5945ea82015-09-05 14:59:06 -04002313 sign_result = _lib.NETSCAPE_SPKI_sign(
2314 self._spki, pkey._pkey, digest_obj
2315 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002316 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002317 # TODO: This is untested.
2318 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002319
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002320 def verify(self, key):
2321 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002322 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002323
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002324 :param key: The public key that signature is supposedly from.
2325 :type pkey: :py:class:`PKey`
2326
2327 :return: :py:const:`True` if the signature is correct.
2328 :rtype: :py:class:`bool`
2329
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002330 :raises Error: If the signature is invalid, or there was a problem
2331 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002332 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002333 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002334 if answer <= 0:
2335 _raise_current_error()
2336 return True
2337
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002338 def b64_encode(self):
2339 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002340 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002341
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002342 :return: The base64 encoded string.
2343 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002344 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002345 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2346 result = _ffi.string(encoded)
2347 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002348 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002349
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002350 def get_pubkey(self):
2351 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002352 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002353
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002354 :return: The public key.
2355 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002356 """
2357 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002358 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2359 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002360 # TODO: This is untested.
2361 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002362 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002363 pkey._only_public = True
2364 return pkey
2365
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002366 def set_pubkey(self, pkey):
2367 """
2368 Set the public key of the certificate
2369
2370 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002371 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002372 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002373 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002374 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002375 # TODO: This is untested.
2376 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002377
2378
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002379NetscapeSPKIType = NetscapeSPKI
2380
2381
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002382class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002383 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002384 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002385 raise ValueError(
2386 "only FILETYPE_PEM key format supports encryption"
2387 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002388 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002389 self._more_args = more_args
2390 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002391 self._problems = []
2392
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002393 @property
2394 def callback(self):
2395 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002396 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002397 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002398 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002399 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002400 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002401 else:
2402 raise TypeError("Last argument must be string or callable")
2403
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002404 @property
2405 def callback_args(self):
2406 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002407 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002408 elif isinstance(self._passphrase, bytes):
2409 return self._passphrase
2410 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002411 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002412 else:
2413 raise TypeError("Last argument must be string or callable")
2414
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002415 def raise_if_problem(self, exceptionType=Error):
2416 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002417 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002418 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002419 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002420 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002421 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002422 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002423
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002424 def _read_passphrase(self, buf, size, rwflag, userdata):
2425 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002426 if self._more_args:
2427 result = self._passphrase(size, rwflag, userdata)
2428 else:
2429 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002430 if not isinstance(result, bytes):
2431 raise ValueError("String expected")
2432 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002433 if self._truncate:
2434 result = result[:size]
2435 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002436 raise ValueError(
2437 "passphrase returned by callback is too long"
2438 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002439 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002440 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002441 return len(result)
2442 except Exception as e:
2443 self._problems.append(e)
2444 return 0
2445
2446
Cory Benfield6492f7c2015-10-27 16:57:58 +09002447def load_publickey(type, buffer):
2448 """
Cory Benfield11c10192015-10-27 17:23:03 +09002449 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002450
Cory Benfield9c590b92015-10-28 14:55:05 +09002451 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002452 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002453 :param buffer: The buffer the key is stored in.
2454 :type buffer: A Python string object, either unicode or bytestring.
2455 :return: The PKey object.
2456 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002457 """
2458 if isinstance(buffer, _text_type):
2459 buffer = buffer.encode("ascii")
2460
2461 bio = _new_mem_buf(buffer)
2462
2463 if type == FILETYPE_PEM:
2464 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2465 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2466 elif type == FILETYPE_ASN1:
2467 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2468 else:
2469 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2470
2471 if evp_pkey == _ffi.NULL:
2472 _raise_current_error()
2473
2474 pkey = PKey.__new__(PKey)
2475 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
2476 return pkey
2477
2478
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002479def load_privatekey(type, buffer, passphrase=None):
2480 """
2481 Load a private key from a buffer
2482
2483 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2484 :param buffer: The buffer the key is stored in
2485 :param passphrase: (optional) if encrypted PEM format, this can be
2486 either the passphrase to use, or a callback for
2487 providing the passphrase.
2488
2489 :return: The PKey object
2490 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002491 if isinstance(buffer, _text_type):
2492 buffer = buffer.encode("ascii")
2493
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002494 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002495
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002496 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002497 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002498 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2499 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002500 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002501 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002502 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002503 else:
2504 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2505
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002506 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002507 _raise_current_error()
2508
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002509 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002510 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002511 return pkey
2512
2513
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002514def dump_certificate_request(type, req):
2515 """
2516 Dump a certificate request to a buffer
2517
2518 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2519 :param req: The certificate request to dump
2520 :return: The buffer with the dumped certificate request in
2521 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002522 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002523
2524 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002525 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002526 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002527 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002528 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002529 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002530 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002531 raise ValueError(
2532 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2533 "FILETYPE_TEXT"
2534 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002535
2536 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002537 # TODO: This is untested.
2538 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002539
2540 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002541
2542
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002543def load_certificate_request(type, buffer):
2544 """
2545 Load a certificate request from a buffer
2546
2547 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2548 :param buffer: The buffer the certificate request is stored in
2549 :return: The X509Req object
2550 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002551 if isinstance(buffer, _text_type):
2552 buffer = buffer.encode("ascii")
2553
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002554 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002555
2556 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002557 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002558 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002559 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002560 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002561 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002562
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002563 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002564 # TODO: This is untested.
2565 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002566
2567 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002568 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002569 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002570
2571
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002572def sign(pkey, data, digest):
2573 """
2574 Sign data with a digest
2575
2576 :param pkey: Pkey to sign with
2577 :param data: data to be signed
2578 :param digest: message digest to use
2579 :return: signature
2580 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002581 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002582
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002583 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002584 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002585 raise ValueError("No such digest method")
2586
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002587 md_ctx = _ffi.new("EVP_MD_CTX*")
2588 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002589
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002590 _lib.EVP_SignInit(md_ctx, digest_obj)
2591 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002592
Colleen Murphye09399b2016-03-01 17:40:49 -08002593 pkey_length = (PKey.bits(pkey) + 7) // 8
2594 signature_buffer = _ffi.new("unsigned char[]", pkey_length)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002595 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002596 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002597 md_ctx, signature_buffer, signature_length, pkey._pkey)
2598
2599 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002600 # TODO: This is untested.
2601 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002602
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002603 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002604
2605
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002606def verify(cert, signature, data, digest):
2607 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002608 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002609
2610 :param cert: signing certificate (X509 object)
2611 :param signature: signature returned by sign function
2612 :param data: data to be verified
2613 :param digest: message digest to use
Alex Gaynor5945ea82015-09-05 14:59:06 -04002614 :return: :py:const:`None` if the signature is correct, raise exception
2615 otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002616 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002617 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002618
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002619 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002620 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002621 raise ValueError("No such digest method")
2622
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002623 pkey = _lib.X509_get_pubkey(cert._x509)
2624 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002625 # TODO: This is untested.
2626 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002627 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002628
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002629 md_ctx = _ffi.new("EVP_MD_CTX*")
2630 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002631
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002632 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2633 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002634 verify_result = _lib.EVP_VerifyFinal(
2635 md_ctx, signature, len(signature), pkey
2636 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002637
2638 if verify_result != 1:
2639 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002640
2641
Dominic Chenf05b2122015-10-13 16:32:35 +00002642def dump_crl(type, crl):
2643 """
2644 Dump a certificate revocation list to a buffer.
2645
2646 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2647 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002648 :param CRL crl: The CRL to dump.
2649
Dominic Chenf05b2122015-10-13 16:32:35 +00002650 :return: The buffer with the CRL.
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002651 :rtype: :data:`bytes`
Dominic Chenf05b2122015-10-13 16:32:35 +00002652 """
2653 bio = _new_mem_buf()
2654
2655 if type == FILETYPE_PEM:
2656 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2657 elif type == FILETYPE_ASN1:
2658 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2659 elif type == FILETYPE_TEXT:
2660 ret = _lib.X509_CRL_print(bio, crl._crl)
2661 else:
2662 raise ValueError(
2663 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2664 "FILETYPE_TEXT")
2665
2666 assert ret == 1
2667 return _bio_to_string(bio)
2668
2669
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002670def load_crl(type, buffer):
2671 """
2672 Load a certificate revocation list from a buffer
2673
2674 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2675 :param buffer: The buffer the CRL is stored in
2676
2677 :return: The PKey object
2678 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002679 if isinstance(buffer, _text_type):
2680 buffer = buffer.encode("ascii")
2681
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002682 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002683
2684 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002685 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002686 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002687 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002688 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002689 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2690
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002691 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002692 _raise_current_error()
2693
2694 result = CRL.__new__(CRL)
2695 result._crl = crl
2696 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002697
2698
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002699def load_pkcs7_data(type, buffer):
2700 """
2701 Load pkcs7 data from a buffer
2702
2703 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2704 :param buffer: The buffer with the pkcs7 data.
2705 :return: The PKCS7 object
2706 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002707 if isinstance(buffer, _text_type):
2708 buffer = buffer.encode("ascii")
2709
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002710 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002711
2712 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002713 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002714 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002715 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002716 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002717 # TODO: This is untested.
2718 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002719 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2720
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002721 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002722 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002723
2724 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002725 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002726 return pypkcs7
2727
2728
Stephen Holsapple38482622014-04-05 20:29:34 -07002729def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002730 """
2731 Load a PKCS12 object from a buffer
2732
2733 :param buffer: The buffer the certificate is stored in
2734 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2735 :returns: The PKCS12 object
2736 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002737 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002738
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002739 if isinstance(buffer, _text_type):
2740 buffer = buffer.encode("ascii")
2741
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002742 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002743
Stephen Holsapple38482622014-04-05 20:29:34 -07002744 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2745 # password based encryption no password and a zero length password are two
2746 # different things, but OpenSSL implementation will try both to figure out
2747 # which one works.
2748 if not passphrase:
2749 passphrase = _ffi.NULL
2750
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002751 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2752 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002753 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002754 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002755
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002756 pkey = _ffi.new("EVP_PKEY**")
2757 cert = _ffi.new("X509**")
2758 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002759
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002760 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002761 if not parse_result:
2762 _raise_current_error()
2763
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002764 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002765
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002766 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2767 # queue for no particular reason. This error isn't interesting to anyone
2768 # outside this function. It's not even interesting to us. Get rid of it.
2769 try:
2770 _raise_current_error()
2771 except Error:
2772 pass
2773
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002774 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002775 pykey = None
2776 else:
2777 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002778 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002779
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002780 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002781 pycert = None
2782 friendlyname = None
2783 else:
2784 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002785 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002786
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002787 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002788 friendlyname_buffer = _lib.X509_alias_get0(
2789 cert[0], friendlyname_length
2790 )
2791 friendlyname = _ffi.buffer(
2792 friendlyname_buffer, friendlyname_length[0]
2793 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002794 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002795 friendlyname = None
2796
2797 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002798 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002799 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002800 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002801 pycacerts.append(pycacert)
2802 if not pycacerts:
2803 pycacerts = None
2804
2805 pkcs12 = PKCS12.__new__(PKCS12)
2806 pkcs12._pkey = pykey
2807 pkcs12._cert = pycert
2808 pkcs12._cacerts = pycacerts
2809 pkcs12._friendlyname = friendlyname
2810 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002811
2812
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002813# There are no direct unit tests for this initialization. It is tested
2814# indirectly since it is necessary for functions like dump_privatekey when
2815# using encryption.
2816#
2817# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2818# and some other similar tests may fail without this (though they may not if
2819# the Python runtime has already done some initialization of the underlying
2820# OpenSSL library (and is linked against the same one that cryptography is
2821# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002822_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002823
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002824# This is similar but exercised mainly by exception_from_error_queue. It calls
2825# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2826_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002827
2828
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002829# Set the default string mask to match OpenSSL upstream (since 2005) and
2830# RFC5280 recommendations.
2831_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')