blob: ce32f93ea57970766e92be58d29e26da16cabff7 [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):
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400700 return _lib.OBJ_obj2nid(
701 _lib.X509_EXTENSION_get_object(self._extension)
702 )
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400703
704 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500705 _lib.GEN_EMAIL: "email",
706 _lib.GEN_DNS: "DNS",
707 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400708 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400709
710 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500711 method = _lib.X509V3_EXT_get(self._extension)
712 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500713 # TODO: This is untested.
714 _raise_current_error()
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400715 ext_data = _lib.X509_EXTENSION_get_data(self._extension)
716 payload = ext_data.data
717 length = ext_data.length
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400718
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500719 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400720 payloadptr[0] = payload
721
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500722 if method.it != _ffi.NULL:
723 ptr = _lib.ASN1_ITEM_ptr(method.it)
724 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
725 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400726 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500727 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400728 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500729 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400730
Paul Kehrerb7d79502015-05-04 07:43:51 -0500731 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400732 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500733 for i in range(_lib.sk_GENERAL_NAME_num(names)):
734 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400735 try:
736 label = self._prefixes[name.type]
737 except KeyError:
738 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500739 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500740 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400741 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500742 value = _native(
743 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
744 parts.append(label + ":" + value)
745 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400746
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800747 def __str__(self):
748 """
749 :return: a nice text representation of the extension
750 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500751 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400752 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800753
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400754 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500755 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800756 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500757 # TODO: This is untested.
758 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800759
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500760 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800761
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800762 def get_critical(self):
763 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200764 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800765
766 :return: The critical field.
767 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500768 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800769
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800770 def get_short_name(self):
771 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200772 Returns the short type name of this X.509 extension.
773
774 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800775
776 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200777 :rtype: :py:data:`bytes`
778
779 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800780 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500781 obj = _lib.X509_EXTENSION_get_object(self._extension)
782 nid = _lib.OBJ_obj2nid(obj)
783 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800784
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800785 def get_data(self):
786 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200787 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800788
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200789 :return: The ASN.1 encoded data of this X509 extension.
790 :rtype: :py:data:`bytes`
791
792 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800793 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500794 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
795 string_result = _ffi.cast('ASN1_STRING*', octet_result)
796 char_result = _lib.ASN1_STRING_data(string_result)
797 result_length = _lib.ASN1_STRING_length(string_result)
798 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800799
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200800
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800801X509ExtensionType = X509Extension
802
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800803
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800804class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200805 """
806 An X.509 certificate signing requests.
807 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400808
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800809 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500810 req = _lib.X509_REQ_new()
811 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800812
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800813 def set_pubkey(self, pkey):
814 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200815 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800816
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200817 :param pkey: The public key to use.
818 :type pkey: :py:class:`PKey`
819
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200820 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800821 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500822 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800823 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500824 # TODO: This is untested.
825 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800826
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800827 def get_pubkey(self):
828 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200829 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800830
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200831 :return: The public key.
832 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800833 """
834 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500835 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
836 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500837 # TODO: This is untested.
838 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500839 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800840 pkey._only_public = True
841 return pkey
842
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800843 def set_version(self, version):
844 """
845 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
846 request.
847
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200848 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200849 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500851 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800852 if not set_result:
853 _raise_current_error()
854
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800855 def get_version(self):
856 """
857 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
858 request.
859
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200860 :return: The value of the version subfield.
861 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800862 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500863 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800864
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800865 def get_subject(self):
866 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200867 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800868
Cory Benfield881dc8d2015-12-09 08:25:14 +0000869 This creates a new :class:`X509Name` that wraps the underlying subject
870 name field on the certificate signing request. Modifying it will modify
871 the underlying signing request, and will have the effect of modifying
872 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200873
874 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000875 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800876 """
877 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500878 name._name = _lib.X509_REQ_get_subject_name(self._req)
879 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500880 # TODO: This is untested.
881 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800882
883 # The name is owned by the X509Req structure. As long as the X509Name
884 # Python object is alive, keep the X509Req Python object alive.
885 name._owner = self
886
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800887 return name
888
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889 def add_extensions(self, extensions):
890 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200891 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800892
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200893 :param extensions: The X.509 extensions to add.
894 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200895 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800896 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500897 stack = _lib.sk_X509_EXTENSION_new_null()
898 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500899 # TODO: This is untested.
900 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800901
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500902 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800903
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800904 for ext in extensions:
905 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800906 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800907
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800908 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500909 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800910
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500911 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800912 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500913 # TODO: This is untested.
914 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800915
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800916 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800917 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200918 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800919
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200920 :return: The X.509 extensions in this request.
921 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
922
923 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800924 """
925 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500926 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500927 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800928 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500929 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800930 exts.append(ext)
931 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800932
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800933 def sign(self, pkey, digest):
934 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700935 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800936
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200937 :param pkey: The key pair to sign with.
938 :type pkey: :py:class:`PKey`
939 :param digest: The name of the message digest to use for the signature,
940 e.g. :py:data:`b"sha1"`.
941 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200942 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800943 """
944 if pkey._only_public:
945 raise ValueError("Key has only public part")
946
947 if not pkey._initialized:
948 raise ValueError("Key is uninitialized")
949
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500950 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500951 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800952 raise ValueError("No such digest method")
953
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500954 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800955 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500956 # TODO: This is untested.
957 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800958
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800959 def verify(self, pkey):
960 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200961 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800962
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200963 :param key: A public key.
964 :type key: :py:class:`PKey`
965 :return: :py:data:`True` if the signature is correct.
966 :rtype: :py:class:`bool`
967 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800968 problem verifying the signature.
969 """
970 if not isinstance(pkey, PKey):
971 raise TypeError("pkey must be a PKey instance")
972
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500973 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800974 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500975 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800976
977 return result
978
979
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800980X509ReqType = X509Req
981
982
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800983class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200984 """
985 An X.509 certificate.
986 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400987
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800988 def __init__(self):
989 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500990 x509 = _lib.X509_new()
991 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800992
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800993 def set_version(self, version):
994 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200995 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800996
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200997 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800998 :type version: :py:class:`int`
999
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001000 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001001 """
1002 if not isinstance(version, int):
1003 raise TypeError("version must be an integer")
1004
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001005 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001006
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001007 def get_version(self):
1008 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001009 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001010
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001011 :return: The version number of the certificate.
1012 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001013 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001014 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001015
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001016 def get_pubkey(self):
1017 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001018 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001019
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001020 :return: The public key.
1021 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001022 """
1023 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001024 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1025 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001026 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001027 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001028 pkey._only_public = True
1029 return pkey
1030
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001031 def set_pubkey(self, pkey):
1032 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001033 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001034
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001035 :param pkey: The public key.
1036 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001037
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001038 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001039 """
1040 if not isinstance(pkey, PKey):
1041 raise TypeError("pkey must be a PKey instance")
1042
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001043 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001044 if not set_result:
1045 _raise_current_error()
1046
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001047 def sign(self, pkey, digest):
1048 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001049 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001050
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001051 :param pkey: The key to sign with.
1052 :type pkey: :py:class:`PKey`
1053
1054 :param digest: The name of the message digest to use.
1055 :type digest: :py:class:`bytes`
1056
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001057 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001058 """
1059 if not isinstance(pkey, PKey):
1060 raise TypeError("pkey must be a PKey instance")
1061
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001062 if pkey._only_public:
1063 raise ValueError("Key only has public part")
1064
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001065 if not pkey._initialized:
1066 raise ValueError("Key is uninitialized")
1067
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001068 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001069 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001070 raise ValueError("No such digest method")
1071
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001072 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001073 if not sign_result:
1074 _raise_current_error()
1075
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001076 def get_signature_algorithm(self):
1077 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001078 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001079
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001080 :return: The name of the algorithm.
1081 :rtype: :py:class:`bytes`
1082
1083 :raises ValueError: If the signature algorithm is undefined.
1084
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001085 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001086 """
1087 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001088 nid = _lib.OBJ_obj2nid(alg)
1089 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001090 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001091 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001092
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001093 def digest(self, digest_name):
1094 """
1095 Return the digest of the X509 object.
1096
1097 :param digest_name: The name of the digest algorithm to use.
1098 :type digest_name: :py:class:`bytes`
1099
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001100 :return: The digest of the object, formatted as
1101 :py:const:`b":"`-delimited hex pairs.
1102 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001103 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001104 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001105 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001106 raise ValueError("No such digest method")
1107
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001108 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1109 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001110 result_length[0] = len(result_buffer)
1111
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001112 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001113 self._x509, digest, result_buffer, result_length)
1114
1115 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001116 # TODO: This is untested.
1117 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001118
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001119 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001120 b16encode(ch).upper() for ch
1121 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001122
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001123 def subject_name_hash(self):
1124 """
1125 Return the hash of the X509 subject.
1126
1127 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001128 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001129 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001130 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001131
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001132 def set_serial_number(self, serial):
1133 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001134 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001135
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001136 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001137 :type serial: :py:class:`int`
1138
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001139 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001140 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001141 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001142 raise TypeError("serial must be an integer")
1143
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001144 hex_serial = hex(serial)[2:]
1145 if not isinstance(hex_serial, bytes):
1146 hex_serial = hex_serial.encode('ascii')
1147
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001148 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001149
1150 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001151 # it. If bignum is still NULL after this call, then the return value
1152 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001153 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001154
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001155 if bignum_serial[0] == _ffi.NULL:
1156 set_result = _lib.ASN1_INTEGER_set(
1157 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001158 if set_result:
1159 # TODO Not tested
1160 _raise_current_error()
1161 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001162 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1163 _lib.BN_free(bignum_serial[0])
1164 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001165 # TODO Not tested
1166 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001167 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1168 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001169 if not set_result:
1170 # TODO Not tested
1171 _raise_current_error()
1172
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001173 def get_serial_number(self):
1174 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001175 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001176
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001177 :return: The serial number.
1178 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001179 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001180 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1181 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001182 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001183 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001184 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001185 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001186 serial = int(hexstring_serial, 16)
1187 return serial
1188 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001189 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001190 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001191 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001192
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001193 def gmtime_adj_notAfter(self, amount):
1194 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001195 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001196
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001197 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001198 :type amount: :py:class:`int`
1199
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001200 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001201 """
1202 if not isinstance(amount, int):
1203 raise TypeError("amount must be an integer")
1204
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001205 notAfter = _lib.X509_get_notAfter(self._x509)
1206 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001207
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001208 def gmtime_adj_notBefore(self, amount):
1209 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001210 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001211
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001212 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001213 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001214 """
1215 if not isinstance(amount, int):
1216 raise TypeError("amount must be an integer")
1217
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001218 notBefore = _lib.X509_get_notBefore(self._x509)
1219 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001220
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001221 def has_expired(self):
1222 """
1223 Check whether the certificate has expired.
1224
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001225 :return: :py:const:`True` if the certificate has expired,
1226 :py:const:`False` otherwise.
1227 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001228 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001229 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001230 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001231
Paul Kehrerfde45c92016-01-21 12:57:37 -06001232 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001233
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001234 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001235 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001236
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001237 def get_notBefore(self):
1238 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001239 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001240
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001241 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001242
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001243 YYYYMMDDhhmmssZ
1244 YYYYMMDDhhmmss+hhmm
1245 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001246
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001247 :return: A timestamp string, or :py:const:`None` if there is none.
1248 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001249 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001250 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001251
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001252 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001253 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001254
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001255 def set_notBefore(self, when):
1256 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001257 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001258
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001259 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001260
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001261 YYYYMMDDhhmmssZ
1262 YYYYMMDDhhmmss+hhmm
1263 YYYYMMDDhhmmss-hhmm
1264
1265 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001266 :type when: :py:class:`bytes`
1267
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001268 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001269 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001270 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001271
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001272 def get_notAfter(self):
1273 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001274 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001275
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001276 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001277
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001278 YYYYMMDDhhmmssZ
1279 YYYYMMDDhhmmss+hhmm
1280 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001281
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001282 :return: A timestamp string, or :py:const:`None` if there is none.
1283 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001284 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001285 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001286
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001287 def set_notAfter(self, when):
1288 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001289 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001290
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001291 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001292
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001293 YYYYMMDDhhmmssZ
1294 YYYYMMDDhhmmss+hhmm
1295 YYYYMMDDhhmmss-hhmm
1296
1297 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001298 :type when: :py:class:`bytes`
1299
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001300 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001301 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001302 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001303
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001304 def _get_name(self, which):
1305 name = X509Name.__new__(X509Name)
1306 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001307 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001308 # TODO: This is untested.
1309 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001310
1311 # The name is owned by the X509 structure. As long as the X509Name
1312 # Python object is alive, keep the X509 Python object alive.
1313 name._owner = self
1314
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001315 return name
1316
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001317 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001318 if not isinstance(name, X509Name):
1319 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001320 set_result = which(self._x509, name._name)
1321 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001322 # TODO: This is untested.
1323 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001324
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001325 def get_issuer(self):
1326 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001327 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001328
Cory Benfielde6bcce82015-12-09 08:40:03 +00001329 This creates a new :class:`X509Name` that wraps the underlying issuer
1330 name field on the certificate. Modifying it will modify the underlying
1331 certificate, and will have the effect of modifying any other
1332 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001333
1334 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001335 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001336 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001337 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001338
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001339 def set_issuer(self, issuer):
1340 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001341 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001342
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001343 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001344 :type issuer: :py:class:`X509Name`
1345
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001346 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001347 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001348 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001349
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001350 def get_subject(self):
1351 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001352 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001353
Cory Benfielde6bcce82015-12-09 08:40:03 +00001354 This creates a new :class:`X509Name` that wraps the underlying subject
1355 name field on the certificate. Modifying it will modify the underlying
1356 certificate, and will have the effect of modifying any other
1357 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001358
1359 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001360 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001361 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001362 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001363
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001364 def set_subject(self, subject):
1365 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001366 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001367
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001368 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001369 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001370
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001371 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001372 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001373 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001374
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001375 def get_extension_count(self):
1376 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001377 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001378
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001379 :return: The number of extensions.
1380 :rtype: :py:class:`int`
1381
1382 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001383 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001384 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001385
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001386 def add_extensions(self, extensions):
1387 """
1388 Add extensions to the certificate.
1389
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001390 :param extensions: The extensions to add.
1391 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001392 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001393 """
1394 for ext in extensions:
1395 if not isinstance(ext, X509Extension):
1396 raise ValueError("One of the elements is not an X509Extension")
1397
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001398 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001399 if not add_result:
1400 _raise_current_error()
1401
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001402 def get_extension(self, index):
1403 """
1404 Get a specific extension of the certificate by index.
1405
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001406 Extensions on a certificate are kept in order. The index
1407 parameter selects which extension will be returned.
1408
1409 :param int index: The index of the extension to retrieve.
1410 :return: The extension at the specified index.
1411 :rtype: :py:class:`X509Extension`
1412 :raises IndexError: If the extension index was out of bounds.
1413
1414 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001415 """
1416 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001417 ext._extension = _lib.X509_get_ext(self._x509, index)
1418 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001419 raise IndexError("extension index out of bounds")
1420
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001421 extension = _lib.X509_EXTENSION_dup(ext._extension)
1422 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001423 return ext
1424
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001425
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001426X509Type = X509
1427
1428
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001429class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001430 """
1431 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001432 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001433
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001434 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001435 store = _lib.X509_STORE_new()
1436 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001437
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001438 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001439 """
1440 Adds the certificate :py:data:`cert` to this store.
1441
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001442 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001443
1444 :param X509 cert: The certificate to add to this store.
1445 :raises TypeError: If the certificate is not an :py:class:`X509`.
1446 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001447 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001448 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001449 if not isinstance(cert, X509):
1450 raise TypeError()
1451
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001452 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001453 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001454 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001455
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001456
1457X509StoreType = X509Store
1458
1459
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001460class X509StoreContextError(Exception):
1461 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001462 An exception raised when an error occurred while verifying a certificate
1463 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001464
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001465 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001466 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001467 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001468
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001469 def __init__(self, message, certificate):
1470 super(X509StoreContextError, self).__init__(message)
1471 self.certificate = certificate
1472
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001473
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001474class X509StoreContext(object):
1475 """
1476 An X.509 store context.
1477
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001478 An :py:class:`X509StoreContext` is used to define some of the criteria for
1479 certificate verification. The information encapsulated in this object
1480 includes, but is not limited to, a set of trusted certificates,
1481 verification parameters, and revoked certificates.
1482
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001483 .. note::
1484
1485 Currently, one can only set the trusted certificates on an
1486 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1487 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001488
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001489 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1490 instance. It is dynamically allocated and automatically garbage
1491 collected.
1492
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001493 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001494
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001495 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001496
1497 :param X509Store store: The certificates which will be trusted for the
1498 purposes of any verifications.
1499
1500 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001501 """
1502
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001503 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001504 store_ctx = _lib.X509_STORE_CTX_new()
1505 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1506 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001507 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001508 # Make the store context available for use after instantiating this
1509 # class by initializing it now. Per testing, subsequent calls to
1510 # :py:meth:`_init` have no adverse affect.
1511 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001512
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001513 def _init(self):
1514 """
1515 Set up the store context for a subsequent verification operation.
1516 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001517 ret = _lib.X509_STORE_CTX_init(
1518 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1519 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001520 if ret <= 0:
1521 _raise_current_error()
1522
1523 def _cleanup(self):
1524 """
1525 Internally cleans up the store context.
1526
1527 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001528 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001529 """
1530 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1531
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001532 def _exception_from_context(self):
1533 """
1534 Convert an OpenSSL native context error failure into a Python
1535 exception.
1536
Alex Gaynor5945ea82015-09-05 14:59:06 -04001537 When a call to native OpenSSL X509_verify_cert fails, additional
1538 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001539 """
1540 errors = [
1541 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1542 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1543 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001544 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001545 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001546 # A context error should always be associated with a certificate, so we
1547 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001548 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001549 _cert = _lib.X509_dup(_x509)
1550 pycert = X509.__new__(X509)
1551 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001552 return X509StoreContextError(errors, pycert)
1553
Stephen Holsapple46a09252015-02-12 14:45:43 -08001554 def set_store(self, store):
1555 """
1556 Set the context's trust store.
1557
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001558 .. versionadded:: 0.15
1559
Stephen Holsapple46a09252015-02-12 14:45:43 -08001560 :param X509Store store: The certificates which will be trusted for the
1561 purposes of any *future* verifications.
1562 """
1563 self._store = store
1564
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001565 def verify_certificate(self):
1566 """
1567 Verify a certificate in a context.
1568
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001569 .. versionadded:: 0.15
1570
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001571 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001572
Alex Gaynorca87ff62015-09-04 23:31:03 -04001573 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001574 certificate in the context. Sets ``certificate`` attribute to
1575 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001576 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001577 # Always re-initialize the store context in case
1578 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001579 self._init()
1580 ret = _lib.X509_verify_cert(self._store_ctx)
1581 self._cleanup()
1582 if ret <= 0:
1583 raise self._exception_from_context()
1584
1585
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001586def load_certificate(type, buffer):
1587 """
1588 Load a certificate from a buffer
1589
1590 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1591
1592 :param buffer: The buffer the certificate is stored in
1593 :type buffer: :py:class:`bytes`
1594
1595 :return: The X509 object
1596 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001597 if isinstance(buffer, _text_type):
1598 buffer = buffer.encode("ascii")
1599
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001600 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001601
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001602 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001603 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001604 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001605 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001606 else:
1607 raise ValueError(
1608 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001609
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001610 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001611 _raise_current_error()
1612
1613 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001614 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001615 return cert
1616
1617
1618def dump_certificate(type, cert):
1619 """
1620 Dump a certificate to a buffer
1621
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001622 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1623 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001624 :param cert: The certificate to dump
1625 :return: The buffer with the dumped certificate in
1626 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001627 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001628
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001629 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001630 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001631 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001632 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001633 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001634 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001635 else:
1636 raise ValueError(
1637 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1638 "FILETYPE_TEXT")
1639
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001640 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001641 return _bio_to_string(bio)
1642
1643
Cory Benfield6492f7c2015-10-27 16:57:58 +09001644def dump_publickey(type, pkey):
1645 """
Cory Benfield11c10192015-10-27 17:23:03 +09001646 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001647
Cory Benfield9c590b92015-10-28 14:55:05 +09001648 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001649 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001650 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001651 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001652 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001653 """
1654 bio = _new_mem_buf()
1655 if type == FILETYPE_PEM:
1656 write_bio = _lib.PEM_write_bio_PUBKEY
1657 elif type == FILETYPE_ASN1:
1658 write_bio = _lib.i2d_PUBKEY_bio
1659 else:
1660 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1661
1662 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001663 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001664 _raise_current_error()
1665
1666 return _bio_to_string(bio)
1667
1668
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001669def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1670 """
1671 Dump a private key to a buffer
1672
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001673 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1674 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001675 :param pkey: The PKey to dump
1676 :param cipher: (optional) if encrypted PEM format, the cipher to
1677 use
1678 :param passphrase: (optional) if encrypted PEM format, this can be either
1679 the passphrase to use, or a callback for providing the
1680 passphrase.
1681 :return: The buffer with the dumped key in
Maximilian Hils0de43752015-09-18 15:26:54 +02001682 :rtype: :py:data:`bytes`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001683 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001684 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001685
1686 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001687 if passphrase is None:
1688 raise TypeError(
1689 "if a value is given for cipher "
1690 "one must also be given for passphrase")
1691 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001692 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001693 raise ValueError("Invalid cipher name")
1694 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001695 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001696
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001697 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001698 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001699 result_code = _lib.PEM_write_bio_PrivateKey(
1700 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001701 helper.callback, helper.callback_args)
1702 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001703 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001704 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001705 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001706 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1707 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001708 # TODO RSA_free(rsa)?
1709 else:
1710 raise ValueError(
1711 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1712 "FILETYPE_TEXT")
1713
1714 if result_code == 0:
1715 _raise_current_error()
1716
1717 return _bio_to_string(bio)
1718
1719
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001720class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001721 """
1722 A certificate revocation.
1723 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001724 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1725 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1726 # OCSP_crl_reason_str. We use the latter, just like the command line
1727 # program.
1728 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001729 b"unspecified",
1730 b"keyCompromise",
1731 b"CACompromise",
1732 b"affiliationChanged",
1733 b"superseded",
1734 b"cessationOfOperation",
1735 b"certificateHold",
1736 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001737 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001738
1739 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001740 revoked = _lib.X509_REVOKED_new()
1741 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001742
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001743 def set_serial(self, hex_str):
1744 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001745 Set the serial number.
1746
1747 The serial number is formatted as a hexadecimal number encoded in
1748 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001749
1750 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001751 :type hex_str: :py:class:`bytes`
1752
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001753 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001754 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001755 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1756 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001757 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001758 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001759 if not bn_result:
1760 raise ValueError("bad hex string")
1761
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001762 asn1_serial = _ffi.gc(
1763 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1764 _lib.ASN1_INTEGER_free)
1765 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001766
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001767 def get_serial(self):
1768 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001769 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001770
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001771 The serial number is formatted as a hexadecimal number encoded in
1772 ASCII.
1773
1774 :return: The serial number.
1775 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001776 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001777 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001778
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001779 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001780 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001781 # TODO: This is untested.
1782 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001783
1784 return _bio_to_string(bio)
1785
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001786 def _delete_reason(self):
1787 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001788 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1789 ext = _lib.sk_X509_EXTENSION_value(stack, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001790 obj = _lib.X509_EXTENSION_get_object(ext)
1791 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001792 _lib.X509_EXTENSION_free(ext)
1793 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001794 break
1795
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001796 def set_reason(self, reason):
1797 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001798 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001799
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001800 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001801
1802 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001803 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1804
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001805 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001806
1807 .. seealso::
1808
1809 :py:meth:`all_reasons`, which gives you a list of all supported
1810 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001811 """
1812 if reason is None:
1813 self._delete_reason()
1814 elif not isinstance(reason, bytes):
1815 raise TypeError("reason must be None or a byte string")
1816 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001817 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001818 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1819
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001820 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1821 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001822 # TODO: This is untested.
1823 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001824 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001825
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001826 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1827 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001828 # TODO: This is untested.
1829 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001830
1831 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001832 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1833 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001834
1835 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001836 # TODO: This is untested.
1837 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001838
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001839 def get_reason(self):
1840 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001841 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001842
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001843 :return: The reason, or :py:const:`None` if there is none.
1844 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1845
1846 .. seealso::
1847
1848 :py:meth:`all_reasons`, which gives you a list of all supported
1849 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001850 """
1851 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001852 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1853 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001854 obj = _lib.X509_EXTENSION_get_object(ext)
1855 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001856 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001857
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001858 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001859 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001860 print_result = _lib.M_ASN1_OCTET_STRING_print(
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001861 bio, _lib.X509_EXTENSION_get_data(ext)
Alex Gaynor5945ea82015-09-05 14:59:06 -04001862 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001863 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001864 # TODO: This is untested.
1865 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001866
1867 return _bio_to_string(bio)
1868
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001869 def all_reasons(self):
1870 """
1871 Return a list of all the supported reason strings.
1872
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001873 This list is a copy; modifying it does not change the supported reason
1874 strings.
1875
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001876 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001877 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001878 """
1879 return self._crl_reasons[:]
1880
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001881 def set_rev_date(self, when):
1882 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001883 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001884
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001885 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1886 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001887 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001888 """
1889 return _set_asn1_time(self._revoked.revocationDate, when)
1890
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001891 def get_rev_date(self):
1892 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001893 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001894
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001895 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1896 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001897 """
1898 return _get_asn1_time(self._revoked.revocationDate)
1899
1900
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001901class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001902 """
1903 A certificate revocation list.
1904 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001905
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001906 def __init__(self):
1907 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001908 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001909 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001910 crl = _lib.X509_CRL_new()
1911 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001912
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001913 def get_revoked(self):
1914 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001915 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001916
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001917 These revocations will be provided by value, not by reference.
1918 That means it's okay to mutate them: it won't affect this CRL.
1919
1920 :return: The revocations in this CRL.
1921 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001922 """
1923 results = []
1924 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001925 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1926 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Paul Kehrer2fe23b02016-03-09 22:02:15 -04001927 revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001928 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001929 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001930 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001931 if results:
1932 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001933
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001934 def add_revoked(self, revoked):
1935 """
1936 Add a revoked (by value not reference) to the CRL structure
1937
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001938 This revocation will be added by value, not by reference. That
1939 means it's okay to mutate it after adding: it won't affect
1940 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001941
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001942 :param revoked: The new revocation.
1943 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001944
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001945 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001946 """
Paul Kehrer8dddb1a2016-03-09 21:48:04 -04001947 copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001948 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001949 # TODO: This is untested.
1950 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001951
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001952 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001953 if add_result == 0:
1954 # TODO: This is untested.
1955 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001956
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001957 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001958 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001959 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001960 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001961
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001962 :param cert: The certificate used to sign the CRL.
1963 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001964
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001965 :param key: The key used to sign the CRL.
1966 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001967
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001968 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1969 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001970
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001971 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001972
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001973 :param bytes digest: The name of the message digest to use (eg
1974 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001975
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001976 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001977 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001978 if not isinstance(cert, X509):
1979 raise TypeError("cert must be an X509 instance")
1980 if not isinstance(key, PKey):
1981 raise TypeError("key must be a PKey instance")
1982 if not isinstance(type, int):
1983 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001984
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001985 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001986 _warn(
1987 "The default message digest (md5) is deprecated. "
1988 "Pass the name of a message digest explicitly.",
1989 category=DeprecationWarning,
1990 stacklevel=2,
1991 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001992 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001993
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001994 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001995 if digest_obj == _ffi.NULL:
1996 raise ValueError("No such digest method")
1997
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001998 bio = _lib.BIO_new(_lib.BIO_s_mem())
1999 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002000 # TODO: This is untested.
2001 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002002
Alex Gaynora738ed52015-09-05 11:17:10 -04002003 # A scratch time object to give different values to different CRL
2004 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002005 sometime = _lib.ASN1_TIME_new()
2006 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002007 # TODO: This is untested.
2008 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002009
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002010 _lib.X509_gmtime_adj(sometime, 0)
2011 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002012
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002013 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2014 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002015
Alex Gaynor5945ea82015-09-05 14:59:06 -04002016 _lib.X509_CRL_set_issuer_name(
2017 self._crl, _lib.X509_get_subject_name(cert._x509)
2018 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002019
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002020 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002021 if not sign_result:
2022 _raise_current_error()
2023
Dominic Chenf05b2122015-10-13 16:32:35 +00002024 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002025
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002026
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002027CRLType = CRL
2028
2029
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002030class PKCS7(object):
2031 def type_is_signed(self):
2032 """
2033 Check if this NID_pkcs7_signed object
2034
2035 :return: True if the PKCS7 is of type signed
2036 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002037 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002038 return True
2039 return False
2040
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002041 def type_is_enveloped(self):
2042 """
2043 Check if this NID_pkcs7_enveloped object
2044
2045 :returns: True if the PKCS7 is of type enveloped
2046 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002047 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002048 return True
2049 return False
2050
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002051 def type_is_signedAndEnveloped(self):
2052 """
2053 Check if this NID_pkcs7_signedAndEnveloped object
2054
2055 :returns: True if the PKCS7 is of type signedAndEnveloped
2056 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002057 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002058 return True
2059 return False
2060
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002061 def type_is_data(self):
2062 """
2063 Check if this NID_pkcs7_data object
2064
2065 :return: True if the PKCS7 is of type data
2066 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002067 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002068 return True
2069 return False
2070
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002071 def get_type_name(self):
2072 """
2073 Returns the type name of the PKCS7 structure
2074
2075 :return: A string with the typename
2076 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002077 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2078 string_type = _lib.OBJ_nid2sn(nid)
2079 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002080
2081PKCS7Type = PKCS7
2082
2083
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002084class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002085 """
2086 A PKCS #12 archive.
2087 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002088
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002089 def __init__(self):
2090 self._pkey = None
2091 self._cert = None
2092 self._cacerts = None
2093 self._friendlyname = None
2094
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002095 def get_certificate(self):
2096 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002097 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002098
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002099 :return: The certificate, or :py:const:`None` if there is none.
2100 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002101 """
2102 return self._cert
2103
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002104 def set_certificate(self, cert):
2105 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002106 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002107
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002108 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002109 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002110
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002111 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002112 """
2113 if not isinstance(cert, X509):
2114 raise TypeError("cert must be an X509 instance")
2115 self._cert = cert
2116
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002117 def get_privatekey(self):
2118 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002119 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002120
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002121 :return: The private key, or :py:const:`None` if there is none.
2122 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002123 """
2124 return self._pkey
2125
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002126 def set_privatekey(self, pkey):
2127 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002128 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002129
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002130 :param pkey: The new private key, or :py:const:`None` to unset it.
2131 :type pkey: :py:class:`PKey` or :py:const:`None`
2132
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002133 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002134 """
2135 if not isinstance(pkey, PKey):
2136 raise TypeError("pkey must be a PKey instance")
2137 self._pkey = pkey
2138
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002139 def get_ca_certificates(self):
2140 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002141 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002142
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002143 :return: A tuple with the CA certificates in the chain, or
2144 :py:const:`None` if there are none.
2145 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002146 """
2147 if self._cacerts is not None:
2148 return tuple(self._cacerts)
2149
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002150 def set_ca_certificates(self, cacerts):
2151 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002152 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002153
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002154 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2155 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002156 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002157
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002158 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002159 """
2160 if cacerts is None:
2161 self._cacerts = None
2162 else:
2163 cacerts = list(cacerts)
2164 for cert in cacerts:
2165 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002166 raise TypeError(
2167 "iterable must only contain X509 instances"
2168 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002169 self._cacerts = cacerts
2170
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002171 def set_friendlyname(self, name):
2172 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002173 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002174
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002175 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002176 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002177
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002178 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002179 """
2180 if name is None:
2181 self._friendlyname = None
2182 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002183 raise TypeError(
2184 "name must be a byte string or None (not %r)" % (name,)
2185 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002186 self._friendlyname = name
2187
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002188 def get_friendlyname(self):
2189 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002190 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002191
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002192 :returns: The friendly name, or :py:const:`None` if there is none.
2193 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002194 """
2195 return self._friendlyname
2196
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002197 def export(self, passphrase=None, iter=2048, maciter=1):
2198 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002199 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002200
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002201 For more information, see the :c:func:`PKCS12_create` man page.
2202
2203 :param passphrase: The passphrase used to encrypt the structure. Unlike
2204 some other passphrase arguments, this *must* be a string, not a
2205 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002206 :type passphrase: :py:data:`bytes`
2207
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002208 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002209 :type iter: :py:data:`int`
2210
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002211 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002212 :type maciter: :py:data:`int`
2213
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002214 :return: The string representation of the PKCS #12 structure.
2215 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002216 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002217 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002218
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002219 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002220 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002221 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002222 cacerts = _lib.sk_X509_new_null()
2223 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002224 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002225 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002226
2227 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002228 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002229
2230 friendlyname = self._friendlyname
2231 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002232 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002233
2234 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002235 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002236 else:
2237 pkey = self._pkey._pkey
2238
2239 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002240 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002241 else:
2242 cert = self._cert._x509
2243
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002244 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002245 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002246 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2247 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002248 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002249 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002250 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002251 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002252
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002253 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002254 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002255 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002256
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002257
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002258PKCS12Type = PKCS12
2259
2260
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002261class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002262 """
2263 A Netscape SPKI object.
2264 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002265
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002266 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002267 spki = _lib.NETSCAPE_SPKI_new()
2268 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002269
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002270 def sign(self, pkey, digest):
2271 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002272 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002273
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002274 :param pkey: The private key to sign with.
2275 :type pkey: :py:class:`PKey`
2276
2277 :param digest: The message digest to use.
2278 :type digest: :py:class:`bytes`
2279
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002280 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002281 """
2282 if pkey._only_public:
2283 raise ValueError("Key has only public part")
2284
2285 if not pkey._initialized:
2286 raise ValueError("Key is uninitialized")
2287
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002288 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002289 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002290 raise ValueError("No such digest method")
2291
Alex Gaynor5945ea82015-09-05 14:59:06 -04002292 sign_result = _lib.NETSCAPE_SPKI_sign(
2293 self._spki, pkey._pkey, digest_obj
2294 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002295 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002296 # TODO: This is untested.
2297 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002298
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002299 def verify(self, key):
2300 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002301 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002302
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002303 :param key: The public key that signature is supposedly from.
2304 :type pkey: :py:class:`PKey`
2305
2306 :return: :py:const:`True` if the signature is correct.
2307 :rtype: :py:class:`bool`
2308
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002309 :raises Error: If the signature is invalid, or there was a problem
2310 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002311 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002312 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002313 if answer <= 0:
2314 _raise_current_error()
2315 return True
2316
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002317 def b64_encode(self):
2318 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002319 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002320
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002321 :return: The base64 encoded string.
2322 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002323 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002324 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2325 result = _ffi.string(encoded)
2326 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002327 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002328
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002329 def get_pubkey(self):
2330 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002331 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002332
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002333 :return: The public key.
2334 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002335 """
2336 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002337 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2338 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002339 # TODO: This is untested.
2340 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002341 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002342 pkey._only_public = True
2343 return pkey
2344
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002345 def set_pubkey(self, pkey):
2346 """
2347 Set the public key of the certificate
2348
2349 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002350 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002351 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002352 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002353 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002354 # TODO: This is untested.
2355 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002356
2357
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002358NetscapeSPKIType = NetscapeSPKI
2359
2360
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002361class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002362 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002363 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002364 raise ValueError(
2365 "only FILETYPE_PEM key format supports encryption"
2366 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002367 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002368 self._more_args = more_args
2369 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002370 self._problems = []
2371
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002372 @property
2373 def callback(self):
2374 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002375 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002376 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002377 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002378 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002379 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002380 else:
2381 raise TypeError("Last argument must be string or callable")
2382
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002383 @property
2384 def callback_args(self):
2385 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002386 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002387 elif isinstance(self._passphrase, bytes):
2388 return self._passphrase
2389 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002390 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002391 else:
2392 raise TypeError("Last argument must be string or callable")
2393
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002394 def raise_if_problem(self, exceptionType=Error):
2395 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002396 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002397 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002398 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002399 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002400 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002401 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002402
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002403 def _read_passphrase(self, buf, size, rwflag, userdata):
2404 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002405 if self._more_args:
2406 result = self._passphrase(size, rwflag, userdata)
2407 else:
2408 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002409 if not isinstance(result, bytes):
2410 raise ValueError("String expected")
2411 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002412 if self._truncate:
2413 result = result[:size]
2414 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002415 raise ValueError(
2416 "passphrase returned by callback is too long"
2417 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002418 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002419 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002420 return len(result)
2421 except Exception as e:
2422 self._problems.append(e)
2423 return 0
2424
2425
Cory Benfield6492f7c2015-10-27 16:57:58 +09002426def load_publickey(type, buffer):
2427 """
Cory Benfield11c10192015-10-27 17:23:03 +09002428 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002429
Cory Benfield9c590b92015-10-28 14:55:05 +09002430 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002431 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002432 :param buffer: The buffer the key is stored in.
2433 :type buffer: A Python string object, either unicode or bytestring.
2434 :return: The PKey object.
2435 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002436 """
2437 if isinstance(buffer, _text_type):
2438 buffer = buffer.encode("ascii")
2439
2440 bio = _new_mem_buf(buffer)
2441
2442 if type == FILETYPE_PEM:
2443 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2444 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2445 elif type == FILETYPE_ASN1:
2446 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2447 else:
2448 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2449
2450 if evp_pkey == _ffi.NULL:
2451 _raise_current_error()
2452
2453 pkey = PKey.__new__(PKey)
2454 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
2455 return pkey
2456
2457
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002458def load_privatekey(type, buffer, passphrase=None):
2459 """
2460 Load a private key from a buffer
2461
2462 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2463 :param buffer: The buffer the key is stored in
2464 :param passphrase: (optional) if encrypted PEM format, this can be
2465 either the passphrase to use, or a callback for
2466 providing the passphrase.
2467
2468 :return: The PKey object
2469 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002470 if isinstance(buffer, _text_type):
2471 buffer = buffer.encode("ascii")
2472
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002473 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002474
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002475 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002476 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002477 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2478 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002479 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002480 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002481 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002482 else:
2483 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2484
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002485 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002486 _raise_current_error()
2487
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002488 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002489 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002490 return pkey
2491
2492
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002493def dump_certificate_request(type, req):
2494 """
2495 Dump a certificate request to a buffer
2496
2497 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2498 :param req: The certificate request to dump
2499 :return: The buffer with the dumped certificate request in
2500 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002501 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002502
2503 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002504 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002505 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002506 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002507 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002508 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002509 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002510 raise ValueError(
2511 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2512 "FILETYPE_TEXT"
2513 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002514
2515 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002516 # TODO: This is untested.
2517 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002518
2519 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002520
2521
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002522def load_certificate_request(type, buffer):
2523 """
2524 Load a certificate request from a buffer
2525
2526 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2527 :param buffer: The buffer the certificate request is stored in
2528 :return: The X509Req object
2529 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002530 if isinstance(buffer, _text_type):
2531 buffer = buffer.encode("ascii")
2532
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002533 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002534
2535 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002536 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002537 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002538 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002539 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002540 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002541
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002542 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002543 # TODO: This is untested.
2544 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002545
2546 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002547 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002548 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002549
2550
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002551def sign(pkey, data, digest):
2552 """
2553 Sign data with a digest
2554
2555 :param pkey: Pkey to sign with
2556 :param data: data to be signed
2557 :param digest: message digest to use
2558 :return: signature
2559 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002560 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002561
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002562 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002563 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002564 raise ValueError("No such digest method")
2565
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002566 md_ctx = _ffi.new("EVP_MD_CTX*")
2567 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002568
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002569 _lib.EVP_SignInit(md_ctx, digest_obj)
2570 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002571
Colleen Murphye09399b2016-03-01 17:40:49 -08002572 pkey_length = (PKey.bits(pkey) + 7) // 8
2573 signature_buffer = _ffi.new("unsigned char[]", pkey_length)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002574 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002575 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002576 md_ctx, signature_buffer, signature_length, pkey._pkey)
2577
2578 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002579 # TODO: This is untested.
2580 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002581
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002582 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002583
2584
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002585def verify(cert, signature, data, digest):
2586 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002587 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002588
2589 :param cert: signing certificate (X509 object)
2590 :param signature: signature returned by sign function
2591 :param data: data to be verified
2592 :param digest: message digest to use
Alex Gaynor5945ea82015-09-05 14:59:06 -04002593 :return: :py:const:`None` if the signature is correct, raise exception
2594 otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002595 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002596 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002597
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002598 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002599 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002600 raise ValueError("No such digest method")
2601
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002602 pkey = _lib.X509_get_pubkey(cert._x509)
2603 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002604 # TODO: This is untested.
2605 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002606 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002607
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002608 md_ctx = _ffi.new("EVP_MD_CTX*")
2609 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002610
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002611 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2612 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002613 verify_result = _lib.EVP_VerifyFinal(
2614 md_ctx, signature, len(signature), pkey
2615 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002616
2617 if verify_result != 1:
2618 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002619
2620
Dominic Chenf05b2122015-10-13 16:32:35 +00002621def dump_crl(type, crl):
2622 """
2623 Dump a certificate revocation list to a buffer.
2624
2625 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2626 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002627 :param CRL crl: The CRL to dump.
2628
Dominic Chenf05b2122015-10-13 16:32:35 +00002629 :return: The buffer with the CRL.
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002630 :rtype: :data:`bytes`
Dominic Chenf05b2122015-10-13 16:32:35 +00002631 """
2632 bio = _new_mem_buf()
2633
2634 if type == FILETYPE_PEM:
2635 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2636 elif type == FILETYPE_ASN1:
2637 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2638 elif type == FILETYPE_TEXT:
2639 ret = _lib.X509_CRL_print(bio, crl._crl)
2640 else:
2641 raise ValueError(
2642 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2643 "FILETYPE_TEXT")
2644
2645 assert ret == 1
2646 return _bio_to_string(bio)
2647
2648
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002649def load_crl(type, buffer):
2650 """
2651 Load a certificate revocation list from a buffer
2652
2653 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2654 :param buffer: The buffer the CRL is stored in
2655
2656 :return: The PKey object
2657 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002658 if isinstance(buffer, _text_type):
2659 buffer = buffer.encode("ascii")
2660
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002661 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002662
2663 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002664 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002665 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002666 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002667 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002668 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2669
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002670 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002671 _raise_current_error()
2672
2673 result = CRL.__new__(CRL)
2674 result._crl = crl
2675 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002676
2677
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002678def load_pkcs7_data(type, buffer):
2679 """
2680 Load pkcs7 data from a buffer
2681
2682 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2683 :param buffer: The buffer with the pkcs7 data.
2684 :return: The PKCS7 object
2685 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002686 if isinstance(buffer, _text_type):
2687 buffer = buffer.encode("ascii")
2688
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002689 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002690
2691 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002692 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002693 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002694 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002695 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002696 # TODO: This is untested.
2697 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002698 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2699
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002700 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002701 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002702
2703 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002704 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002705 return pypkcs7
2706
2707
Stephen Holsapple38482622014-04-05 20:29:34 -07002708def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002709 """
2710 Load a PKCS12 object from a buffer
2711
2712 :param buffer: The buffer the certificate is stored in
2713 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2714 :returns: The PKCS12 object
2715 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002716 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002717
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002718 if isinstance(buffer, _text_type):
2719 buffer = buffer.encode("ascii")
2720
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002721 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002722
Stephen Holsapple38482622014-04-05 20:29:34 -07002723 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2724 # password based encryption no password and a zero length password are two
2725 # different things, but OpenSSL implementation will try both to figure out
2726 # which one works.
2727 if not passphrase:
2728 passphrase = _ffi.NULL
2729
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002730 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2731 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002732 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002733 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002734
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002735 pkey = _ffi.new("EVP_PKEY**")
2736 cert = _ffi.new("X509**")
2737 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002738
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002739 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002740 if not parse_result:
2741 _raise_current_error()
2742
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002743 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002744
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002745 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2746 # queue for no particular reason. This error isn't interesting to anyone
2747 # outside this function. It's not even interesting to us. Get rid of it.
2748 try:
2749 _raise_current_error()
2750 except Error:
2751 pass
2752
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002753 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002754 pykey = None
2755 else:
2756 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002757 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002758
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002759 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002760 pycert = None
2761 friendlyname = None
2762 else:
2763 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002764 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002765
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002766 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002767 friendlyname_buffer = _lib.X509_alias_get0(
2768 cert[0], friendlyname_length
2769 )
2770 friendlyname = _ffi.buffer(
2771 friendlyname_buffer, friendlyname_length[0]
2772 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002773 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002774 friendlyname = None
2775
2776 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002777 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002778 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002779 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002780 pycacerts.append(pycacert)
2781 if not pycacerts:
2782 pycacerts = None
2783
2784 pkcs12 = PKCS12.__new__(PKCS12)
2785 pkcs12._pkey = pykey
2786 pkcs12._cert = pycert
2787 pkcs12._cacerts = pycacerts
2788 pkcs12._friendlyname = friendlyname
2789 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002790
2791
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002792# There are no direct unit tests for this initialization. It is tested
2793# indirectly since it is necessary for functions like dump_privatekey when
2794# using encryption.
2795#
2796# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2797# and some other similar tests may fail without this (though they may not if
2798# the Python runtime has already done some initialization of the underlying
2799# OpenSSL library (and is linked against the same one that cryptography is
2800# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002801_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002802
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002803# This is similar but exercised mainly by exception_from_error_queue. It calls
2804# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2805_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002806
2807
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002808# Set the default string mask to match OpenSSL upstream (since 2005) and
2809# RFC5280 recommendations.
2810_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')