blob: 56dad181caccb9ed7f9d751ed66fae8923f45ee9 [file] [log] [blame]
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001import datetime
Paul Kehrer8d887e12015-10-24 09:09:55 -05002
3from time import mktime
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05004from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05005from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05006from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04007from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05008
9from six import (
10 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -040011 text_type as _text_type,
12 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080013
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050014from OpenSSL._util import (
15 ffi as _ffi,
16 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050017 exception_from_error_queue as _exception_from_error_queue,
18 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040019 native as _native,
20 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040021 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040022)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080023
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050024FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
25FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080026
27# TODO This was an API mistake. OpenSSL has no such constant.
28FILETYPE_TEXT = 2 ** 16 - 1
29
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050030TYPE_RSA = _lib.EVP_PKEY_RSA
31TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080032
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080033
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050034class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050035 """
36 An error occurred in an `OpenSSL.crypto` API.
37 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050038
39
40_raise_current_error = partial(_exception_from_error_queue, Error)
41
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070042
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050043def _untested_error(where):
44 """
45 An OpenSSL API failed somehow. Additionally, the failure which was
46 encountered isn't one that's exercised by the test suite so future behavior
47 of pyOpenSSL is now somewhat less predictable.
48 """
49 raise RuntimeError("Unknown %s failure" % (where,))
50
51
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050052def _new_mem_buf(buffer=None):
53 """
54 Allocate a new OpenSSL memory BIO.
55
56 Arrange for the garbage collector to clean it up automatically.
57
58 :param buffer: None or some bytes to use to put into the BIO so that they
59 can be read out.
60 """
61 if buffer is None:
62 bio = _lib.BIO_new(_lib.BIO_s_mem())
63 free = _lib.BIO_free
64 else:
65 data = _ffi.new("char[]", buffer)
66 bio = _lib.BIO_new_mem_buf(data, len(buffer))
Alex Gaynor5945ea82015-09-05 14:59:06 -040067
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050068 # Keep the memory alive as long as the bio is alive!
69 def free(bio, ref=data):
70 return _lib.BIO_free(bio)
71
72 if bio == _ffi.NULL:
73 # TODO: This is untested.
74 _raise_current_error()
75
76 bio = _ffi.gc(bio, free)
77 return bio
78
79
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080080def _bio_to_string(bio):
81 """
82 Copy the contents of an OpenSSL BIO object into a Python byte string.
83 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050084 result_buffer = _ffi.new('char**')
85 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
86 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080087
88
Jean-Paul Calderone57122982013-02-21 08:47:05 -080089def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050090 """
91 The the time value of an ASN1 time object.
92
93 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
94 castable to that type) which will have its value set.
95 @param when: A string representation of the desired time value.
96
97 @raise TypeError: If C{when} is not a L{bytes} string.
98 @raise ValueError: If C{when} does not represent a time in the required
99 format.
100 @raise RuntimeError: If the time value cannot be set for some other
101 (unspecified) reason.
102 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800103 if not isinstance(when, bytes):
104 raise TypeError("when must be a byte string")
105
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500106 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
107 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800108 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500109 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
110 _lib.ASN1_STRING_set(dummy, when, len(when))
111 check_result = _lib.ASN1_GENERALIZEDTIME_check(
112 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800113 if not check_result:
114 raise ValueError("Invalid string")
115 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500116 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800117
118
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800119def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500120 """
121 Retrieve the time value of an ASN1 time object.
122
123 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
124 that type) from which the time value will be retrieved.
125
126 @return: The time value from C{timestamp} as a L{bytes} string in a certain
127 format. Or C{None} if the object contains no time value.
128 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500129 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
130 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800131 return None
Alex Gaynor5945ea82015-09-05 14:59:06 -0400132 elif (
133 _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
134 ):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500135 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800136 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500137 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
138 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
139 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500140 # This may happen:
141 # - if timestamp was not an ASN1_TIME
142 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
143 # - if a copy of the time data from timestamp cannot be made for
144 # the newly allocated ASN1_GENERALIZEDTIME
145 #
146 # These are difficult to test. cffi enforces the ASN1_TIME type.
147 # Memory allocation failures are a pain to trigger
148 # deterministically.
149 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800150 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500151 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800152 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500153 string_data = _lib.ASN1_STRING_data(string_timestamp)
154 string_result = _ffi.string(string_data)
155 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800156 return string_result
157
158
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800159class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200160 """
161 A class representing an DSA or RSA public key or key pair.
162 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800163 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800164 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800165
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800166 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500167 pkey = _lib.EVP_PKEY_new()
168 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800169 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800170
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800171 def generate_key(self, type, bits):
172 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700173 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800174
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200175 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800176
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200177 :param type: The key type.
178 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
179 :param bits: The number of bits.
180 :type bits: :py:data:`int` ``>= 0``
181 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
182 of the appropriate type.
183 :raises ValueError: If the number of bits isn't an integer of
184 the appropriate size.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200185 :return: :py:const:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800186 """
187 if not isinstance(type, int):
188 raise TypeError("type must be an integer")
189
190 if not isinstance(bits, int):
191 raise TypeError("bits must be an integer")
192
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800193 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500194 exponent = _lib.BN_new()
195 exponent = _ffi.gc(exponent, _lib.BN_free)
196 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800197
198 if type == TYPE_RSA:
199 if bits <= 0:
200 raise ValueError("Invalid number of bits")
201
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500202 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800203
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500204 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500205 if result == 0:
206 # TODO: The test for this case is commented out. Different
207 # builds of OpenSSL appear to have different failure modes that
208 # make it hard to test. Visual inspection of the OpenSSL
209 # source reveals that a return value of 0 signals an error.
210 # Manual testing on a particular build of OpenSSL suggests that
211 # this is probably the appropriate way to handle those errors.
212 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800213
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500214 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800215 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500216 # TODO: It appears as though this can fail if an engine is in
217 # use which does not support RSA.
218 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800219
220 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500221 dsa = _lib.DSA_generate_parameters(
222 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
223 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500224 # TODO: This is untested.
225 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500226 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500227 # TODO: This is untested.
228 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500229 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500230 # TODO: This is untested.
231 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800232 else:
233 raise Error("No such key type")
234
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800235 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800236
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800237 def check(self):
238 """
239 Check the consistency of an RSA private key.
240
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200241 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
242
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800243 :return: True if key is consistent.
244 :raise Error: if the key is inconsistent.
245 :raise TypeError: if the key is of a type which cannot be checked.
246 Only RSA keys can currently be checked.
247 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800248 if self._only_public:
249 raise TypeError("public key only")
250
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500251 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800252 raise TypeError("key type unsupported")
253
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500254 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
255 rsa = _ffi.gc(rsa, _lib.RSA_free)
256 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800257 if result:
258 return True
259 _raise_current_error()
260
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800261 def type(self):
262 """
263 Returns the type of the key
264
265 :return: The type of the key.
266 """
267 return self._pkey.type
268
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800269 def bits(self):
270 """
271 Returns the number of bits of the key
272
273 :return: The number of bits of the key.
274 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500275 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800276PKeyType = PKey
277
278
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400279class _EllipticCurve(object):
280 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400281 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400282
283 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
284 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
285 instances each of which represents one curve supported by the system.
286 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400287 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400288 _curves = None
289
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400290 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400291 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400292 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400293 """
294 Implement cooperation with the right-hand side argument of ``!=``.
295
296 Python 3 seems to have dropped this cooperation in this very narrow
297 circumstance.
298 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400299 if isinstance(other, _EllipticCurve):
300 return super(_EllipticCurve, self).__ne__(other)
301 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400302
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400303 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400304 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400305 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400306 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400307
308 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400309
310 :return: A :py:type:`set` of ``cls`` instances giving the names of the
311 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400312 """
313 if lib.Cryptography_HAS_EC:
314 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
315 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400316 # The return value on this call should be num_curves again. We
317 # could check it to make sure but if it *isn't* then.. what could
318 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400319 lib.EC_get_builtin_curves(builtin_curves, num_curves)
320 return set(
321 cls.from_nid(lib, c.nid)
322 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400323 return set()
324
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400325 @classmethod
326 def _get_elliptic_curves(cls, lib):
327 """
328 Get, cache, and return the curves supported by OpenSSL.
329
330 :param lib: The OpenSSL library binding object.
331
332 :return: A :py:type:`set` of ``cls`` instances giving the names of the
333 elliptic curves the underlying library supports.
334 """
335 if cls._curves is None:
336 cls._curves = cls._load_elliptic_curves(lib)
337 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400338
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400339 @classmethod
340 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400341 """
342 Instantiate a new :py:class:`_EllipticCurve` associated with the given
343 OpenSSL NID.
344
345 :param lib: The OpenSSL library binding object.
346
347 :param nid: The OpenSSL NID the resulting curve object will represent.
348 This must be a curve NID (and not, for example, a hash NID) or
349 subsequent operations will fail in unpredictable ways.
350 :type nid: :py:class:`int`
351
352 :return: The curve object.
353 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400354 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
355
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400356 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400357 """
358 :param _lib: The :py:mod:`cryptography` binding instance used to
359 interface with OpenSSL.
360
361 :param _nid: The OpenSSL NID identifying the curve this object
362 represents.
363 :type _nid: :py:class:`int`
364
365 :param name: The OpenSSL short name identifying the curve this object
366 represents.
367 :type name: :py:class:`unicode`
368 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400369 self._lib = lib
370 self._nid = nid
371 self.name = name
372
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400373 def __repr__(self):
374 return "<Curve %r>" % (self.name,)
375
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400376 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400377 """
378 Create a new OpenSSL EC_KEY structure initialized to use this curve.
379
380 The structure is automatically garbage collected when the Python object
381 is garbage collected.
382 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400383 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
384 return _ffi.gc(key, _lib.EC_KEY_free)
385
386
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400387def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400388 """
389 Return a set of objects representing the elliptic curves supported in the
390 OpenSSL build in use.
391
392 The curve objects have a :py:class:`unicode` ``name`` attribute by which
393 they identify themselves.
394
395 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400396 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
397 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400398 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400399 return _EllipticCurve._get_elliptic_curves(_lib)
400
401
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400402def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400403 """
404 Return a single curve object selected by name.
405
406 See :py:func:`get_elliptic_curves` for information about curve objects.
407
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400408 :param name: The OpenSSL short name identifying the curve object to
409 retrieve.
410 :type name: :py:class:`unicode`
411
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400412 If the named curve is not supported then :py:class:`ValueError` is raised.
413 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400414 for curve in get_elliptic_curves():
415 if curve.name == name:
416 return curve
417 raise ValueError("unknown curve name", name)
418
419
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800420class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200421 """
422 An X.509 Distinguished Name.
423
424 :ivar countryName: The country of the entity.
425 :ivar C: Alias for :py:attr:`countryName`.
426
427 :ivar stateOrProvinceName: The state or province of the entity.
428 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
429
430 :ivar localityName: The locality of the entity.
431 :ivar L: Alias for :py:attr:`localityName`.
432
433 :ivar organizationName: The organization name of the entity.
434 :ivar O: Alias for :py:attr:`organizationName`.
435
436 :ivar organizationalUnitName: The organizational unit of the entity.
437 :ivar OU: Alias for :py:attr:`organizationalUnitName`
438
439 :ivar commonName: The common name of the entity.
440 :ivar CN: Alias for :py:attr:`commonName`.
441
442 :ivar emailAddress: The e-mail address of the entity.
443 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400444
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800445 def __init__(self, name):
446 """
447 Create a new X509Name, copying the given X509Name instance.
448
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200449 :param name: The name to copy.
450 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800451 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500452 name = _lib.X509_NAME_dup(name._name)
453 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800454
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800455 def __setattr__(self, name, value):
456 if name.startswith('_'):
457 return super(X509Name, self).__setattr__(name, value)
458
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800459 # Note: we really do not want str subclasses here, so we do not use
460 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800461 if type(name) is not str:
462 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400463 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800464
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500465 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500466 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800467 try:
468 _raise_current_error()
469 except Error:
470 pass
471 raise AttributeError("No such attribute")
472
473 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500474 for i in range(_lib.X509_NAME_entry_count(self._name)):
475 ent = _lib.X509_NAME_get_entry(self._name, i)
476 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
477 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800478 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500479 ent = _lib.X509_NAME_delete_entry(self._name, i)
480 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800481 break
482
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500483 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800484 value = value.encode('utf-8')
485
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500486 add_result = _lib.X509_NAME_add_entry_by_NID(
487 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800488 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500489 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800490
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800491 def __getattr__(self, name):
492 """
493 Find attribute. An X509Name object has the following attributes:
494 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400495 organization (alias O), organizationalUnit (alias OU), commonName
496 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800497 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500498 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500499 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800500 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
501 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
502 # push something onto the error queue. If we don't clean that up
503 # now, someone else will bump into it later and be quite confused.
504 # See lp#314814.
505 try:
506 _raise_current_error()
507 except Error:
508 pass
509 return super(X509Name, self).__getattr__(name)
510
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500511 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800512 if entry_index == -1:
513 return None
514
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500515 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
516 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800517
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500518 result_buffer = _ffi.new("unsigned char**")
519 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800520 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500521 # TODO: This is untested.
522 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800523
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700524 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400525 result = _ffi.buffer(
526 result_buffer[0], data_length
527 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700528 finally:
529 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500530 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800531 return result
532
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500533 def _cmp(op):
534 def f(self, other):
535 if not isinstance(other, X509Name):
536 return NotImplemented
537 result = _lib.X509_NAME_cmp(self._name, other._name)
538 return op(result, 0)
539 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800540
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500541 __eq__ = _cmp(__eq__)
542 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800543
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500544 __lt__ = _cmp(__lt__)
545 __le__ = _cmp(__le__)
546
547 __gt__ = _cmp(__gt__)
548 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800549
550 def __repr__(self):
551 """
552 String representation of an X509Name
553 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400554 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500555 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800556 self._name, result_buffer, len(result_buffer))
557
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500558 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500559 # TODO: This is untested.
560 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800561
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500562 return "<X509Name object '%s'>" % (
563 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800564
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800565 def hash(self):
566 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200567 Return an integer representation of the first four bytes of the
568 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800569
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200570 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
571
572 :return: The (integer) hash of this name.
573 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800574 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500575 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800576
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800577 def der(self):
578 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200579 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800580
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200581 :return: The DER encoded form of this name.
582 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800583 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500584 result_buffer = _ffi.new('unsigned char**')
585 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800586 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500587 # TODO: This is untested.
588 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800589
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500590 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
591 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800592 return string_result
593
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800594 def get_components(self):
595 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200596 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800597
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200598 :return: The components of this name.
599 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800600 """
601 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500602 for i in range(_lib.X509_NAME_entry_count(self._name)):
603 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800604
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500605 fname = _lib.X509_NAME_ENTRY_get_object(ent)
606 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800607
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500608 nid = _lib.OBJ_obj2nid(fname)
609 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800610
611 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400612 _ffi.string(name),
613 _ffi.string(
614 _lib.ASN1_STRING_data(fval),
615 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800616
617 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200618
619
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800620X509NameType = X509Name
621
622
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800623class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200624 """
625 An X.509 v3 certificate extension.
626 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400627
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800628 def __init__(self, type_name, critical, value, subject=None, issuer=None):
629 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200630 Initializes an X509 extension.
631
Alex Gaynor6f719912015-09-20 09:21:29 -0400632 :param type_name: The name of the type of extension to create. See
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200633 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Alex Gaynor6f719912015-09-20 09:21:29 -0400634 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800635
Alex Gaynor5945ea82015-09-05 14:59:06 -0400636 :param bool critical: A flag indicating whether this is a critical
637 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800638
639 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200640 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800641
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200642 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800643 :type subject: :py:class:`X509`
644
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200645 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800646 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800647 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500648 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800649
Alex Gaynor5945ea82015-09-05 14:59:06 -0400650 # A context is necessary for any extension which uses the r2i
651 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
652 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500653 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800654
655 # We have no configuration database - but perhaps we should (some
656 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500657 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800658
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800659 # Initialize the subject and issuer, if appropriate. ctx is a local,
660 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400661 # any references, so no need to mess with reference counts or
662 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800663 if issuer is not None:
664 if not isinstance(issuer, X509):
665 raise TypeError("issuer must be an X509 instance")
666 ctx.issuer_cert = issuer._x509
667 if subject is not None:
668 if not isinstance(subject, X509):
669 raise TypeError("subject must be an X509 instance")
670 ctx.subject_cert = subject._x509
671
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800672 if critical:
673 # There are other OpenSSL APIs which would let us pass in critical
674 # separately, but they're harder to use, and since value is already
675 # a pile of crappy junk smuggling a ton of utterly important
676 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400677 # with strings? (However, X509V3_EXT_i2d in particular seems like
678 # it would be a better API to invoke. I do not know where to get
679 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500680 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800681
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500682 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
683 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800684 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500685 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800686
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400687 @property
688 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500689 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400690
691 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500692 _lib.GEN_EMAIL: "email",
693 _lib.GEN_DNS: "DNS",
694 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400695 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400696
697 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500698 method = _lib.X509V3_EXT_get(self._extension)
699 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500700 # TODO: This is untested.
701 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400702 payload = self._extension.value.data
703 length = self._extension.value.length
704
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500705 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400706 payloadptr[0] = payload
707
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500708 if method.it != _ffi.NULL:
709 ptr = _lib.ASN1_ITEM_ptr(method.it)
710 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
711 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400712 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500713 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400714 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500715 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400716
Paul Kehrerb7d79502015-05-04 07:43:51 -0500717 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400718 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500719 for i in range(_lib.sk_GENERAL_NAME_num(names)):
720 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400721 try:
722 label = self._prefixes[name.type]
723 except KeyError:
724 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500725 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500726 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400727 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500728 value = _native(
729 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
730 parts.append(label + ":" + value)
731 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400732
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800733 def __str__(self):
734 """
735 :return: a nice text representation of the extension
736 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500737 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400738 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800739
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400740 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500741 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800742 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500743 # TODO: This is untested.
744 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800745
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500746 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800747
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800748 def get_critical(self):
749 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200750 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800751
752 :return: The critical field.
753 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500754 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800755
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800756 def get_short_name(self):
757 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200758 Returns the short type name of this X.509 extension.
759
760 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800761
762 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200763 :rtype: :py:data:`bytes`
764
765 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800766 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500767 obj = _lib.X509_EXTENSION_get_object(self._extension)
768 nid = _lib.OBJ_obj2nid(obj)
769 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800770
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800771 def get_data(self):
772 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200773 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800774
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200775 :return: The ASN.1 encoded data of this X509 extension.
776 :rtype: :py:data:`bytes`
777
778 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800779 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500780 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
781 string_result = _ffi.cast('ASN1_STRING*', octet_result)
782 char_result = _lib.ASN1_STRING_data(string_result)
783 result_length = _lib.ASN1_STRING_length(string_result)
784 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800785
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200786
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800787X509ExtensionType = X509Extension
788
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800789
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800790class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200791 """
792 An X.509 certificate signing requests.
793 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400794
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800795 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500796 req = _lib.X509_REQ_new()
797 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800798
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800799 def set_pubkey(self, pkey):
800 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200801 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800802
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200803 :param pkey: The public key to use.
804 :type pkey: :py:class:`PKey`
805
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200806 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800807 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500808 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800809 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500810 # TODO: This is untested.
811 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800812
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800813 def get_pubkey(self):
814 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200815 Get 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 :return: The public key.
818 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800819 """
820 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500821 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
822 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500823 # TODO: This is untested.
824 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500825 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800826 pkey._only_public = True
827 return pkey
828
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800829 def set_version(self, version):
830 """
831 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
832 request.
833
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200834 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200835 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800836 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500837 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800838 if not set_result:
839 _raise_current_error()
840
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800841 def get_version(self):
842 """
843 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
844 request.
845
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200846 :return: The value of the version subfield.
847 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800848 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500849 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800851 def get_subject(self):
852 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200853 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854
Cory Benfield881dc8d2015-12-09 08:25:14 +0000855 This creates a new :class:`X509Name` that wraps the underlying subject
856 name field on the certificate signing request. Modifying it will modify
857 the underlying signing request, and will have the effect of modifying
858 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200859
860 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000861 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800862 """
863 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500864 name._name = _lib.X509_REQ_get_subject_name(self._req)
865 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500866 # TODO: This is untested.
867 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800868
869 # The name is owned by the X509Req structure. As long as the X509Name
870 # Python object is alive, keep the X509Req Python object alive.
871 name._owner = self
872
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800873 return name
874
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800875 def add_extensions(self, extensions):
876 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200877 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800878
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200879 :param extensions: The X.509 extensions to add.
880 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200881 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800882 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500883 stack = _lib.sk_X509_EXTENSION_new_null()
884 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500885 # TODO: This is untested.
886 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800887
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500888 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800889
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800890 for ext in extensions:
891 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800892 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800893
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800894 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500895 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800896
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500897 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800898 if not add_result:
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
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800902 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800903 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200904 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800905
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200906 :return: The X.509 extensions in this request.
907 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
908
909 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800910 """
911 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500912 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500913 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800914 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500915 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800916 exts.append(ext)
917 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800918
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800919 def sign(self, pkey, digest):
920 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700921 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800922
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200923 :param pkey: The key pair to sign with.
924 :type pkey: :py:class:`PKey`
925 :param digest: The name of the message digest to use for the signature,
926 e.g. :py:data:`b"sha1"`.
927 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200928 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800929 """
930 if pkey._only_public:
931 raise ValueError("Key has only public part")
932
933 if not pkey._initialized:
934 raise ValueError("Key is uninitialized")
935
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500936 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500937 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800938 raise ValueError("No such digest method")
939
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500940 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800941 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500942 # TODO: This is untested.
943 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800944
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800945 def verify(self, pkey):
946 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200947 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800948
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200949 :param key: A public key.
950 :type key: :py:class:`PKey`
951 :return: :py:data:`True` if the signature is correct.
952 :rtype: :py:class:`bool`
953 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800954 problem verifying the signature.
955 """
956 if not isinstance(pkey, PKey):
957 raise TypeError("pkey must be a PKey instance")
958
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500959 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800960 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500961 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800962
963 return result
964
965
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800966X509ReqType = X509Req
967
968
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800969class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200970 """
971 An X.509 certificate.
972 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400973
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800974 def __init__(self):
975 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500976 x509 = _lib.X509_new()
977 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800978
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800979 def set_version(self, version):
980 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200981 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800982
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200983 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800984 :type version: :py:class:`int`
985
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200986 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800987 """
988 if not isinstance(version, int):
989 raise TypeError("version must be an integer")
990
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500991 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800992
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800993 def get_version(self):
994 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200995 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800996
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200997 :return: The version number of the certificate.
998 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800999 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001000 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001001
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001002 def get_pubkey(self):
1003 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001004 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001005
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001006 :return: The public key.
1007 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001008 """
1009 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001010 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1011 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001012 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001013 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001014 pkey._only_public = True
1015 return pkey
1016
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001017 def set_pubkey(self, pkey):
1018 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001019 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001020
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001021 :param pkey: The public key.
1022 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001023
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001024 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001025 """
1026 if not isinstance(pkey, PKey):
1027 raise TypeError("pkey must be a PKey instance")
1028
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001029 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001030 if not set_result:
1031 _raise_current_error()
1032
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001033 def sign(self, pkey, digest):
1034 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001035 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001036
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001037 :param pkey: The key to sign with.
1038 :type pkey: :py:class:`PKey`
1039
1040 :param digest: The name of the message digest to use.
1041 :type digest: :py:class:`bytes`
1042
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001043 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001044 """
1045 if not isinstance(pkey, PKey):
1046 raise TypeError("pkey must be a PKey instance")
1047
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001048 if pkey._only_public:
1049 raise ValueError("Key only has public part")
1050
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001051 if not pkey._initialized:
1052 raise ValueError("Key is uninitialized")
1053
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001054 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001055 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001056 raise ValueError("No such digest method")
1057
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001058 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001059 if not sign_result:
1060 _raise_current_error()
1061
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001062 def get_signature_algorithm(self):
1063 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001064 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001065
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001066 :return: The name of the algorithm.
1067 :rtype: :py:class:`bytes`
1068
1069 :raises ValueError: If the signature algorithm is undefined.
1070
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001071 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001072 """
1073 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001074 nid = _lib.OBJ_obj2nid(alg)
1075 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001076 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001077 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001078
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001079 def digest(self, digest_name):
1080 """
1081 Return the digest of the X509 object.
1082
1083 :param digest_name: The name of the digest algorithm to use.
1084 :type digest_name: :py:class:`bytes`
1085
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001086 :return: The digest of the object, formatted as
1087 :py:const:`b":"`-delimited hex pairs.
1088 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001089 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001090 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001091 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001092 raise ValueError("No such digest method")
1093
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001094 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1095 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001096 result_length[0] = len(result_buffer)
1097
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001098 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001099 self._x509, digest, result_buffer, result_length)
1100
1101 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001102 # TODO: This is untested.
1103 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001104
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001105 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001106 b16encode(ch).upper() for ch
1107 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001108
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001109 def subject_name_hash(self):
1110 """
1111 Return the hash of the X509 subject.
1112
1113 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001114 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001115 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001116 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001117
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001118 def set_serial_number(self, serial):
1119 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001120 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001121
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001122 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001123 :type serial: :py:class:`int`
1124
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001125 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001126 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001127 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001128 raise TypeError("serial must be an integer")
1129
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001130 hex_serial = hex(serial)[2:]
1131 if not isinstance(hex_serial, bytes):
1132 hex_serial = hex_serial.encode('ascii')
1133
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001134 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001135
1136 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001137 # it. If bignum is still NULL after this call, then the return value
1138 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001139 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001140
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001141 if bignum_serial[0] == _ffi.NULL:
1142 set_result = _lib.ASN1_INTEGER_set(
1143 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001144 if set_result:
1145 # TODO Not tested
1146 _raise_current_error()
1147 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001148 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1149 _lib.BN_free(bignum_serial[0])
1150 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001151 # TODO Not tested
1152 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001153 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1154 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001155 if not set_result:
1156 # TODO Not tested
1157 _raise_current_error()
1158
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001159 def get_serial_number(self):
1160 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001161 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001162
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001163 :return: The serial number.
1164 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001165 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001166 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1167 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001168 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001169 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001170 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001171 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001172 serial = int(hexstring_serial, 16)
1173 return serial
1174 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001175 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001176 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001177 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001178
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001179 def gmtime_adj_notAfter(self, amount):
1180 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001181 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001182
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001183 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001184 :type amount: :py:class:`int`
1185
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001186 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001187 """
1188 if not isinstance(amount, int):
1189 raise TypeError("amount must be an integer")
1190
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001191 notAfter = _lib.X509_get_notAfter(self._x509)
1192 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001193
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001194 def gmtime_adj_notBefore(self, amount):
1195 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001196 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001197
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001198 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001199 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001200 """
1201 if not isinstance(amount, int):
1202 raise TypeError("amount must be an integer")
1203
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001204 notBefore = _lib.X509_get_notBefore(self._x509)
1205 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001206
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001207 def has_expired(self):
1208 """
1209 Check whether the certificate has expired.
1210
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001211 :return: :py:const:`True` if the certificate has expired,
1212 :py:const:`False` otherwise.
1213 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001214 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001215 time_string = _native(self.get_notAfter())
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001216 timestamp = mktime(datetime.datetime.strptime(
1217 time_string, "%Y%m%d%H%M%SZ").timetuple())
1218 now = mktime(datetime.datetime.utcnow().timetuple())
1219
1220 return timestamp < now
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001221
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001222 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001223 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001224
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001225 def get_notBefore(self):
1226 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001227 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001228
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001229 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001230
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001231 YYYYMMDDhhmmssZ
1232 YYYYMMDDhhmmss+hhmm
1233 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001234
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001235 :return: A timestamp string, or :py:const:`None` if there is none.
1236 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001237 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001238 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001239
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001240 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001241 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001242
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001243 def set_notBefore(self, when):
1244 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001245 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001246
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001247 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001248
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001249 YYYYMMDDhhmmssZ
1250 YYYYMMDDhhmmss+hhmm
1251 YYYYMMDDhhmmss-hhmm
1252
1253 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001254 :type when: :py:class:`bytes`
1255
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001256 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001257 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001258 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001259
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001260 def get_notAfter(self):
1261 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001262 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001263
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001264 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001265
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001266 YYYYMMDDhhmmssZ
1267 YYYYMMDDhhmmss+hhmm
1268 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001269
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001270 :return: A timestamp string, or :py:const:`None` if there is none.
1271 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001272 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001273 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001274
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001275 def set_notAfter(self, when):
1276 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001277 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001278
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001279 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001280
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001281 YYYYMMDDhhmmssZ
1282 YYYYMMDDhhmmss+hhmm
1283 YYYYMMDDhhmmss-hhmm
1284
1285 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001286 :type when: :py:class:`bytes`
1287
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001288 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001289 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001290 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001291
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001292 def _get_name(self, which):
1293 name = X509Name.__new__(X509Name)
1294 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001295 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001296 # TODO: This is untested.
1297 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001298
1299 # The name is owned by the X509 structure. As long as the X509Name
1300 # Python object is alive, keep the X509 Python object alive.
1301 name._owner = self
1302
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001303 return name
1304
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001305 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001306 if not isinstance(name, X509Name):
1307 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001308 set_result = which(self._x509, name._name)
1309 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001310 # TODO: This is untested.
1311 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001312
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001313 def get_issuer(self):
1314 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001315 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001316
Cory Benfielde6bcce82015-12-09 08:40:03 +00001317 This creates a new :class:`X509Name` that wraps the underlying issuer
1318 name field on the certificate. Modifying it will modify the underlying
1319 certificate, and will have the effect of modifying any other
1320 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001321
1322 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001323 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001324 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001325 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001326
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001327 def set_issuer(self, issuer):
1328 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001329 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001330
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001331 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001332 :type issuer: :py:class:`X509Name`
1333
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001334 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001335 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001336 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001337
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001338 def get_subject(self):
1339 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001340 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001341
Cory Benfielde6bcce82015-12-09 08:40:03 +00001342 This creates a new :class:`X509Name` that wraps the underlying subject
1343 name field on the certificate. Modifying it will modify the underlying
1344 certificate, and will have the effect of modifying any other
1345 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001346
1347 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001348 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001349 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001350 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001351
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001352 def set_subject(self, subject):
1353 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001354 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001355
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001356 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001357 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001358
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001359 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001360 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001361 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001362
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001363 def get_extension_count(self):
1364 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001365 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001366
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001367 :return: The number of extensions.
1368 :rtype: :py:class:`int`
1369
1370 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001371 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001372 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001373
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001374 def add_extensions(self, extensions):
1375 """
1376 Add extensions to the certificate.
1377
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001378 :param extensions: The extensions to add.
1379 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001380 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001381 """
1382 for ext in extensions:
1383 if not isinstance(ext, X509Extension):
1384 raise ValueError("One of the elements is not an X509Extension")
1385
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001386 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001387 if not add_result:
1388 _raise_current_error()
1389
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001390 def get_extension(self, index):
1391 """
1392 Get a specific extension of the certificate by index.
1393
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001394 Extensions on a certificate are kept in order. The index
1395 parameter selects which extension will be returned.
1396
1397 :param int index: The index of the extension to retrieve.
1398 :return: The extension at the specified index.
1399 :rtype: :py:class:`X509Extension`
1400 :raises IndexError: If the extension index was out of bounds.
1401
1402 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001403 """
1404 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001405 ext._extension = _lib.X509_get_ext(self._x509, index)
1406 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001407 raise IndexError("extension index out of bounds")
1408
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001409 extension = _lib.X509_EXTENSION_dup(ext._extension)
1410 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001411 return ext
1412
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001413
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001414X509Type = X509
1415
1416
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001417class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001418 """
1419 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001420 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001421
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001422 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001423 store = _lib.X509_STORE_new()
1424 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001425
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001426 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001427 """
1428 Adds the certificate :py:data:`cert` to this store.
1429
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001430 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001431
1432 :param X509 cert: The certificate to add to this store.
1433 :raises TypeError: If the certificate is not an :py:class:`X509`.
1434 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001435 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001436 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001437 if not isinstance(cert, X509):
1438 raise TypeError()
1439
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001440 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001441 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001442 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001443
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001444
1445X509StoreType = X509Store
1446
1447
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001448class X509StoreContextError(Exception):
1449 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001450 An exception raised when an error occurred while verifying a certificate
1451 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001452
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001453 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001454 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001455 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001456
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001457 def __init__(self, message, certificate):
1458 super(X509StoreContextError, self).__init__(message)
1459 self.certificate = certificate
1460
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001461
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001462class X509StoreContext(object):
1463 """
1464 An X.509 store context.
1465
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001466 An :py:class:`X509StoreContext` is used to define some of the criteria for
1467 certificate verification. The information encapsulated in this object
1468 includes, but is not limited to, a set of trusted certificates,
1469 verification parameters, and revoked certificates.
1470
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001471 .. note::
1472
1473 Currently, one can only set the trusted certificates on an
1474 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1475 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001476
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001477 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1478 instance. It is dynamically allocated and automatically garbage
1479 collected.
1480
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001481 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001482
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001483 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001484
1485 :param X509Store store: The certificates which will be trusted for the
1486 purposes of any verifications.
1487
1488 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001489 """
1490
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001491 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001492 store_ctx = _lib.X509_STORE_CTX_new()
1493 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1494 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001495 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001496 # Make the store context available for use after instantiating this
1497 # class by initializing it now. Per testing, subsequent calls to
1498 # :py:meth:`_init` have no adverse affect.
1499 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001500
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001501 def _init(self):
1502 """
1503 Set up the store context for a subsequent verification operation.
1504 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001505 ret = _lib.X509_STORE_CTX_init(
1506 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1507 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001508 if ret <= 0:
1509 _raise_current_error()
1510
1511 def _cleanup(self):
1512 """
1513 Internally cleans up the store context.
1514
1515 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001516 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001517 """
1518 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1519
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001520 def _exception_from_context(self):
1521 """
1522 Convert an OpenSSL native context error failure into a Python
1523 exception.
1524
Alex Gaynor5945ea82015-09-05 14:59:06 -04001525 When a call to native OpenSSL X509_verify_cert fails, additional
1526 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001527 """
1528 errors = [
1529 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1530 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1531 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001532 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001533 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001534 # A context error should always be associated with a certificate, so we
1535 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001536 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001537 _cert = _lib.X509_dup(_x509)
1538 pycert = X509.__new__(X509)
1539 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001540 return X509StoreContextError(errors, pycert)
1541
Stephen Holsapple46a09252015-02-12 14:45:43 -08001542 def set_store(self, store):
1543 """
1544 Set the context's trust store.
1545
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001546 .. versionadded:: 0.15
1547
Stephen Holsapple46a09252015-02-12 14:45:43 -08001548 :param X509Store store: The certificates which will be trusted for the
1549 purposes of any *future* verifications.
1550 """
1551 self._store = store
1552
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001553 def verify_certificate(self):
1554 """
1555 Verify a certificate in a context.
1556
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001557 .. versionadded:: 0.15
1558
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001559 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001560
Alex Gaynorca87ff62015-09-04 23:31:03 -04001561 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001562 certificate in the context. Sets ``certificate`` attribute to
1563 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001564 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001565 # Always re-initialize the store context in case
1566 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001567 self._init()
1568 ret = _lib.X509_verify_cert(self._store_ctx)
1569 self._cleanup()
1570 if ret <= 0:
1571 raise self._exception_from_context()
1572
1573
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001574def load_certificate(type, buffer):
1575 """
1576 Load a certificate from a buffer
1577
1578 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1579
1580 :param buffer: The buffer the certificate is stored in
1581 :type buffer: :py:class:`bytes`
1582
1583 :return: The X509 object
1584 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001585 if isinstance(buffer, _text_type):
1586 buffer = buffer.encode("ascii")
1587
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001588 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001589
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001590 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001591 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001592 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001593 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001594 else:
1595 raise ValueError(
1596 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001597
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001598 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001599 _raise_current_error()
1600
1601 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001602 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001603 return cert
1604
1605
1606def dump_certificate(type, cert):
1607 """
1608 Dump a certificate to a buffer
1609
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001610 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1611 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001612 :param cert: The certificate to dump
1613 :return: The buffer with the dumped certificate in
1614 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001615 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001616
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001617 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001618 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001619 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001620 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001621 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001622 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001623 else:
1624 raise ValueError(
1625 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1626 "FILETYPE_TEXT")
1627
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001628 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001629 return _bio_to_string(bio)
1630
1631
Cory Benfield6492f7c2015-10-27 16:57:58 +09001632def dump_publickey(type, pkey):
1633 """
Cory Benfield11c10192015-10-27 17:23:03 +09001634 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001635
Cory Benfield9c590b92015-10-28 14:55:05 +09001636 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001637 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001638 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001639 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001640 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001641 """
1642 bio = _new_mem_buf()
1643 if type == FILETYPE_PEM:
1644 write_bio = _lib.PEM_write_bio_PUBKEY
1645 elif type == FILETYPE_ASN1:
1646 write_bio = _lib.i2d_PUBKEY_bio
1647 else:
1648 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1649
1650 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001651 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001652 _raise_current_error()
1653
1654 return _bio_to_string(bio)
1655
1656
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001657def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1658 """
1659 Dump a private key to a buffer
1660
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001661 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1662 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001663 :param pkey: The PKey to dump
1664 :param cipher: (optional) if encrypted PEM format, the cipher to
1665 use
1666 :param passphrase: (optional) if encrypted PEM format, this can be either
1667 the passphrase to use, or a callback for providing the
1668 passphrase.
1669 :return: The buffer with the dumped key in
Maximilian Hils0de43752015-09-18 15:26:54 +02001670 :rtype: :py:data:`bytes`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001671 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001672 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001673
1674 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001675 if passphrase is None:
1676 raise TypeError(
1677 "if a value is given for cipher "
1678 "one must also be given for passphrase")
1679 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001680 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001681 raise ValueError("Invalid cipher name")
1682 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001683 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001684
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001685 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001686 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001687 result_code = _lib.PEM_write_bio_PrivateKey(
1688 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001689 helper.callback, helper.callback_args)
1690 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001691 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001692 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001693 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001694 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1695 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001696 # TODO RSA_free(rsa)?
1697 else:
1698 raise ValueError(
1699 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1700 "FILETYPE_TEXT")
1701
1702 if result_code == 0:
1703 _raise_current_error()
1704
1705 return _bio_to_string(bio)
1706
1707
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001708def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001709 copy = _lib.X509_REVOKED_new()
1710 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001711 # TODO: This is untested.
1712 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001713
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001714 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001715 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001716 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001717
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001718 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001719 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001720 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001721
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001722 if original.extensions != _ffi.NULL:
1723 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1724 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1725 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1726 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1727 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001728 copy.extensions = extension_stack
1729
1730 copy.sequence = original.sequence
1731 return copy
1732
1733
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001734class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001735 """
1736 A certificate revocation.
1737 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001738 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1739 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1740 # OCSP_crl_reason_str. We use the latter, just like the command line
1741 # program.
1742 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001743 b"unspecified",
1744 b"keyCompromise",
1745 b"CACompromise",
1746 b"affiliationChanged",
1747 b"superseded",
1748 b"cessationOfOperation",
1749 b"certificateHold",
1750 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001751 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001752
1753 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001754 revoked = _lib.X509_REVOKED_new()
1755 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001756
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001757 def set_serial(self, hex_str):
1758 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001759 Set the serial number.
1760
1761 The serial number is formatted as a hexadecimal number encoded in
1762 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001763
1764 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001765 :type hex_str: :py:class:`bytes`
1766
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001767 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001768 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001769 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1770 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001771 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001772 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001773 if not bn_result:
1774 raise ValueError("bad hex string")
1775
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001776 asn1_serial = _ffi.gc(
1777 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1778 _lib.ASN1_INTEGER_free)
1779 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001780
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001781 def get_serial(self):
1782 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001783 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001784
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001785 The serial number is formatted as a hexadecimal number encoded in
1786 ASCII.
1787
1788 :return: The serial number.
1789 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001790 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001791 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001792
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001793 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001794 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001795 # TODO: This is untested.
1796 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001797
1798 return _bio_to_string(bio)
1799
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001800 def _delete_reason(self):
1801 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001802 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1803 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1804 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1805 _lib.X509_EXTENSION_free(ext)
1806 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807 break
1808
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001809 def set_reason(self, reason):
1810 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001811 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001812
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001813 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001814
1815 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001816 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1817
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001818 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001819
1820 .. seealso::
1821
1822 :py:meth:`all_reasons`, which gives you a list of all supported
1823 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001824 """
1825 if reason is None:
1826 self._delete_reason()
1827 elif not isinstance(reason, bytes):
1828 raise TypeError("reason must be None or a byte string")
1829 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001830 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001831 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1832
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001833 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1834 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001835 # TODO: This is untested.
1836 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001837 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001838
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001839 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1840 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001841 # TODO: This is untested.
1842 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001843
1844 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001845 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1846 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001847
1848 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001849 # TODO: This is untested.
1850 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001851
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001852 def get_reason(self):
1853 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001854 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001855
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001856 :return: The reason, or :py:const:`None` if there is none.
1857 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1858
1859 .. seealso::
1860
1861 :py:meth:`all_reasons`, which gives you a list of all supported
1862 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001863 """
1864 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001865 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1866 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1867 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001868 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001869
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001870 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001871 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001872 print_result = _lib.M_ASN1_OCTET_STRING_print(
1873 bio, ext.value
1874 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001875 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001876 # TODO: This is untested.
1877 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001878
1879 return _bio_to_string(bio)
1880
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001881 def all_reasons(self):
1882 """
1883 Return a list of all the supported reason strings.
1884
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001885 This list is a copy; modifying it does not change the supported reason
1886 strings.
1887
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001888 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001889 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001890 """
1891 return self._crl_reasons[:]
1892
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001893 def set_rev_date(self, when):
1894 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001895 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001896
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001897 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1898 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001899 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001900 """
1901 return _set_asn1_time(self._revoked.revocationDate, when)
1902
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001903 def get_rev_date(self):
1904 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001905 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001906
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001907 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1908 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001909 """
1910 return _get_asn1_time(self._revoked.revocationDate)
1911
1912
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001913class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001914 """
1915 A certificate revocation list.
1916 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001917
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001918 def __init__(self):
1919 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001920 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001921 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001922 crl = _lib.X509_CRL_new()
1923 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001924
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001925 def get_revoked(self):
1926 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001927 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001928
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001929 These revocations will be provided by value, not by reference.
1930 That means it's okay to mutate them: it won't affect this CRL.
1931
1932 :return: The revocations in this CRL.
1933 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001934 """
1935 results = []
1936 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001937 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1938 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001939 revoked_copy = _X509_REVOKED_dup(revoked)
1940 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001941 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001942 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001943 if results:
1944 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001945
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001946 def add_revoked(self, revoked):
1947 """
1948 Add a revoked (by value not reference) to the CRL structure
1949
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001950 This revocation will be added by value, not by reference. That
1951 means it's okay to mutate it after adding: it won't affect
1952 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001953
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001954 :param revoked: The new revocation.
1955 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001956
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001957 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001958 """
1959 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001960 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001961 # TODO: This is untested.
1962 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001963
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001964 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001965 if add_result == 0:
1966 # TODO: This is untested.
1967 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001968
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001969 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001970 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001971 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001972 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001973
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001974 :param cert: The certificate used to sign the CRL.
1975 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001976
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001977 :param key: The key used to sign the CRL.
1978 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001979
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001980 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1981 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001982
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001983 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001984
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001985 :param bytes digest: The name of the message digest to use (eg
1986 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001987
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001988 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001989 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001990 if not isinstance(cert, X509):
1991 raise TypeError("cert must be an X509 instance")
1992 if not isinstance(key, PKey):
1993 raise TypeError("key must be a PKey instance")
1994 if not isinstance(type, int):
1995 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001996
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001997 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001998 _warn(
1999 "The default message digest (md5) is deprecated. "
2000 "Pass the name of a message digest explicitly.",
2001 category=DeprecationWarning,
2002 stacklevel=2,
2003 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002004 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002005
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002006 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002007 if digest_obj == _ffi.NULL:
2008 raise ValueError("No such digest method")
2009
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002010 bio = _lib.BIO_new(_lib.BIO_s_mem())
2011 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002012 # TODO: This is untested.
2013 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002014
Alex Gaynora738ed52015-09-05 11:17:10 -04002015 # A scratch time object to give different values to different CRL
2016 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002017 sometime = _lib.ASN1_TIME_new()
2018 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002019 # TODO: This is untested.
2020 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002021
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002022 _lib.X509_gmtime_adj(sometime, 0)
2023 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002024
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002025 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2026 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002027
Alex Gaynor5945ea82015-09-05 14:59:06 -04002028 _lib.X509_CRL_set_issuer_name(
2029 self._crl, _lib.X509_get_subject_name(cert._x509)
2030 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002031
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002032 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002033 if not sign_result:
2034 _raise_current_error()
2035
Dominic Chenf05b2122015-10-13 16:32:35 +00002036 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002037
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002038
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002039CRLType = CRL
2040
2041
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002042class PKCS7(object):
2043 def type_is_signed(self):
2044 """
2045 Check if this NID_pkcs7_signed object
2046
2047 :return: True if the PKCS7 is of type signed
2048 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002049 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002050 return True
2051 return False
2052
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002053 def type_is_enveloped(self):
2054 """
2055 Check if this NID_pkcs7_enveloped object
2056
2057 :returns: True if the PKCS7 is of type enveloped
2058 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002059 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002060 return True
2061 return False
2062
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002063 def type_is_signedAndEnveloped(self):
2064 """
2065 Check if this NID_pkcs7_signedAndEnveloped object
2066
2067 :returns: True if the PKCS7 is of type signedAndEnveloped
2068 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002069 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002070 return True
2071 return False
2072
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002073 def type_is_data(self):
2074 """
2075 Check if this NID_pkcs7_data object
2076
2077 :return: True if the PKCS7 is of type data
2078 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002079 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002080 return True
2081 return False
2082
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002083 def get_type_name(self):
2084 """
2085 Returns the type name of the PKCS7 structure
2086
2087 :return: A string with the typename
2088 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002089 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2090 string_type = _lib.OBJ_nid2sn(nid)
2091 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002092
2093PKCS7Type = PKCS7
2094
2095
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002096class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002097 """
2098 A PKCS #12 archive.
2099 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002100
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002101 def __init__(self):
2102 self._pkey = None
2103 self._cert = None
2104 self._cacerts = None
2105 self._friendlyname = None
2106
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002107 def get_certificate(self):
2108 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002109 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002110
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002111 :return: The certificate, or :py:const:`None` if there is none.
2112 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002113 """
2114 return self._cert
2115
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002116 def set_certificate(self, cert):
2117 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002118 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002119
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002120 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002121 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002122
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002123 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002124 """
2125 if not isinstance(cert, X509):
2126 raise TypeError("cert must be an X509 instance")
2127 self._cert = cert
2128
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002129 def get_privatekey(self):
2130 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002131 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002132
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002133 :return: The private key, or :py:const:`None` if there is none.
2134 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002135 """
2136 return self._pkey
2137
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002138 def set_privatekey(self, pkey):
2139 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002140 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002141
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002142 :param pkey: The new private key, or :py:const:`None` to unset it.
2143 :type pkey: :py:class:`PKey` or :py:const:`None`
2144
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002145 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002146 """
2147 if not isinstance(pkey, PKey):
2148 raise TypeError("pkey must be a PKey instance")
2149 self._pkey = pkey
2150
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002151 def get_ca_certificates(self):
2152 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002153 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002154
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002155 :return: A tuple with the CA certificates in the chain, or
2156 :py:const:`None` if there are none.
2157 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002158 """
2159 if self._cacerts is not None:
2160 return tuple(self._cacerts)
2161
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002162 def set_ca_certificates(self, cacerts):
2163 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002164 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002165
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002166 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2167 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002168 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002169
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002170 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002171 """
2172 if cacerts is None:
2173 self._cacerts = None
2174 else:
2175 cacerts = list(cacerts)
2176 for cert in cacerts:
2177 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002178 raise TypeError(
2179 "iterable must only contain X509 instances"
2180 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002181 self._cacerts = cacerts
2182
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002183 def set_friendlyname(self, name):
2184 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002185 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002186
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002187 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002188 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002189
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002190 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002191 """
2192 if name is None:
2193 self._friendlyname = None
2194 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002195 raise TypeError(
2196 "name must be a byte string or None (not %r)" % (name,)
2197 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002198 self._friendlyname = name
2199
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002200 def get_friendlyname(self):
2201 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002202 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002203
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002204 :returns: The friendly name, or :py:const:`None` if there is none.
2205 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002206 """
2207 return self._friendlyname
2208
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002209 def export(self, passphrase=None, iter=2048, maciter=1):
2210 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002211 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002212
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002213 For more information, see the :c:func:`PKCS12_create` man page.
2214
2215 :param passphrase: The passphrase used to encrypt the structure. Unlike
2216 some other passphrase arguments, this *must* be a string, not a
2217 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002218 :type passphrase: :py:data:`bytes`
2219
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002220 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002221 :type iter: :py:data:`int`
2222
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002223 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002224 :type maciter: :py:data:`int`
2225
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002226 :return: The string representation of the PKCS #12 structure.
2227 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002228 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002229 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002230
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002231 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002232 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002233 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002234 cacerts = _lib.sk_X509_new_null()
2235 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002236 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002237 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002238
2239 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002240 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002241
2242 friendlyname = self._friendlyname
2243 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002244 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002245
2246 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002247 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002248 else:
2249 pkey = self._pkey._pkey
2250
2251 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002252 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002253 else:
2254 cert = self._cert._x509
2255
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002256 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002257 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002258 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2259 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002260 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002261 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002262 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002263 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002264
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002265 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002266 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002267 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002268
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002269
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002270PKCS12Type = PKCS12
2271
2272
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002273class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002274 """
2275 A Netscape SPKI object.
2276 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002277
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002278 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002279 spki = _lib.NETSCAPE_SPKI_new()
2280 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002281
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002282 def sign(self, pkey, digest):
2283 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002284 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002285
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002286 :param pkey: The private key to sign with.
2287 :type pkey: :py:class:`PKey`
2288
2289 :param digest: The message digest to use.
2290 :type digest: :py:class:`bytes`
2291
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002292 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002293 """
2294 if pkey._only_public:
2295 raise ValueError("Key has only public part")
2296
2297 if not pkey._initialized:
2298 raise ValueError("Key is uninitialized")
2299
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002300 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002301 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002302 raise ValueError("No such digest method")
2303
Alex Gaynor5945ea82015-09-05 14:59:06 -04002304 sign_result = _lib.NETSCAPE_SPKI_sign(
2305 self._spki, pkey._pkey, digest_obj
2306 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002307 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002308 # TODO: This is untested.
2309 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002310
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002311 def verify(self, key):
2312 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002313 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002314
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002315 :param key: The public key that signature is supposedly from.
2316 :type pkey: :py:class:`PKey`
2317
2318 :return: :py:const:`True` if the signature is correct.
2319 :rtype: :py:class:`bool`
2320
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002321 :raises Error: If the signature is invalid, or there was a problem
2322 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002323 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002324 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002325 if answer <= 0:
2326 _raise_current_error()
2327 return True
2328
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002329 def b64_encode(self):
2330 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002331 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002332
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002333 :return: The base64 encoded string.
2334 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002335 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002336 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2337 result = _ffi.string(encoded)
2338 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002339 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002340
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002341 def get_pubkey(self):
2342 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002343 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002344
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002345 :return: The public key.
2346 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002347 """
2348 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002349 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2350 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002351 # TODO: This is untested.
2352 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002353 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002354 pkey._only_public = True
2355 return pkey
2356
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002357 def set_pubkey(self, pkey):
2358 """
2359 Set the public key of the certificate
2360
2361 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002362 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002363 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002364 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002365 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002366 # TODO: This is untested.
2367 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002368
2369
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002370NetscapeSPKIType = NetscapeSPKI
2371
2372
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002373class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002374 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002375 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002376 raise ValueError(
2377 "only FILETYPE_PEM key format supports encryption"
2378 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002379 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002380 self._more_args = more_args
2381 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002382 self._problems = []
2383
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002384 @property
2385 def callback(self):
2386 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002387 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002388 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002389 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002390 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002391 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002392 else:
2393 raise TypeError("Last argument must be string or callable")
2394
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002395 @property
2396 def callback_args(self):
2397 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002398 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002399 elif isinstance(self._passphrase, bytes):
2400 return self._passphrase
2401 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002402 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002403 else:
2404 raise TypeError("Last argument must be string or callable")
2405
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002406 def raise_if_problem(self, exceptionType=Error):
2407 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002408 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002409 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002410 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002411 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002412 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002413 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002414
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002415 def _read_passphrase(self, buf, size, rwflag, userdata):
2416 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002417 if self._more_args:
2418 result = self._passphrase(size, rwflag, userdata)
2419 else:
2420 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002421 if not isinstance(result, bytes):
2422 raise ValueError("String expected")
2423 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002424 if self._truncate:
2425 result = result[:size]
2426 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002427 raise ValueError(
2428 "passphrase returned by callback is too long"
2429 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002430 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002431 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002432 return len(result)
2433 except Exception as e:
2434 self._problems.append(e)
2435 return 0
2436
2437
Cory Benfield6492f7c2015-10-27 16:57:58 +09002438def load_publickey(type, buffer):
2439 """
Cory Benfield11c10192015-10-27 17:23:03 +09002440 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002441
Cory Benfield9c590b92015-10-28 14:55:05 +09002442 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002443 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002444 :param buffer: The buffer the key is stored in.
2445 :type buffer: A Python string object, either unicode or bytestring.
2446 :return: The PKey object.
2447 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002448 """
2449 if isinstance(buffer, _text_type):
2450 buffer = buffer.encode("ascii")
2451
2452 bio = _new_mem_buf(buffer)
2453
2454 if type == FILETYPE_PEM:
2455 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2456 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2457 elif type == FILETYPE_ASN1:
2458 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2459 else:
2460 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2461
2462 if evp_pkey == _ffi.NULL:
2463 _raise_current_error()
2464
2465 pkey = PKey.__new__(PKey)
2466 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
2467 return pkey
2468
2469
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002470def load_privatekey(type, buffer, passphrase=None):
2471 """
2472 Load a private key from a buffer
2473
2474 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2475 :param buffer: The buffer the key is stored in
2476 :param passphrase: (optional) if encrypted PEM format, this can be
2477 either the passphrase to use, or a callback for
2478 providing the passphrase.
2479
2480 :return: The PKey object
2481 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002482 if isinstance(buffer, _text_type):
2483 buffer = buffer.encode("ascii")
2484
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002485 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002486
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002487 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002488 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002489 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2490 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002491 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002492 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002493 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002494 else:
2495 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2496
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002497 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002498 _raise_current_error()
2499
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002500 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002501 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002502 return pkey
2503
2504
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002505def dump_certificate_request(type, req):
2506 """
2507 Dump a certificate request to a buffer
2508
2509 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2510 :param req: The certificate request to dump
2511 :return: The buffer with the dumped certificate request in
2512 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002513 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002514
2515 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002516 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002517 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002518 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002519 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002520 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002521 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002522 raise ValueError(
2523 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2524 "FILETYPE_TEXT"
2525 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002526
2527 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002528 # TODO: This is untested.
2529 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002530
2531 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002532
2533
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002534def load_certificate_request(type, buffer):
2535 """
2536 Load a certificate request from a buffer
2537
2538 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2539 :param buffer: The buffer the certificate request is stored in
2540 :return: The X509Req object
2541 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002542 if isinstance(buffer, _text_type):
2543 buffer = buffer.encode("ascii")
2544
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002545 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002546
2547 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002548 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002549 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002550 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002551 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002552 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002553
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002554 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002555 # TODO: This is untested.
2556 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002557
2558 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002559 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002560 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002561
2562
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002563def sign(pkey, data, digest):
2564 """
2565 Sign data with a digest
2566
2567 :param pkey: Pkey to sign with
2568 :param data: data to be signed
2569 :param digest: message digest to use
2570 :return: signature
2571 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002572 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002573
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002574 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002575 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002576 raise ValueError("No such digest method")
2577
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002578 md_ctx = _ffi.new("EVP_MD_CTX*")
2579 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002580
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002581 _lib.EVP_SignInit(md_ctx, digest_obj)
2582 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002583
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002584 signature_buffer = _ffi.new("unsigned char[]", 512)
2585 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002586 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002587 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002588 md_ctx, signature_buffer, signature_length, pkey._pkey)
2589
2590 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002591 # TODO: This is untested.
2592 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002593
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002594 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002595
2596
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002597def verify(cert, signature, data, digest):
2598 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002599 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002600
2601 :param cert: signing certificate (X509 object)
2602 :param signature: signature returned by sign function
2603 :param data: data to be verified
2604 :param digest: message digest to use
Alex Gaynor5945ea82015-09-05 14:59:06 -04002605 :return: :py:const:`None` if the signature is correct, raise exception
2606 otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002607 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002608 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002609
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002610 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002611 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002612 raise ValueError("No such digest method")
2613
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002614 pkey = _lib.X509_get_pubkey(cert._x509)
2615 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002616 # TODO: This is untested.
2617 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002618 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002619
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002620 md_ctx = _ffi.new("EVP_MD_CTX*")
2621 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002622
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002623 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2624 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002625 verify_result = _lib.EVP_VerifyFinal(
2626 md_ctx, signature, len(signature), pkey
2627 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002628
2629 if verify_result != 1:
2630 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002631
2632
Dominic Chenf05b2122015-10-13 16:32:35 +00002633def dump_crl(type, crl):
2634 """
2635 Dump a certificate revocation list to a buffer.
2636
2637 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2638 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002639 :param CRL crl: The CRL to dump.
2640
Dominic Chenf05b2122015-10-13 16:32:35 +00002641 :return: The buffer with the CRL.
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002642 :rtype: :data:`bytes`
Dominic Chenf05b2122015-10-13 16:32:35 +00002643 """
2644 bio = _new_mem_buf()
2645
2646 if type == FILETYPE_PEM:
2647 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2648 elif type == FILETYPE_ASN1:
2649 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2650 elif type == FILETYPE_TEXT:
2651 ret = _lib.X509_CRL_print(bio, crl._crl)
2652 else:
2653 raise ValueError(
2654 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2655 "FILETYPE_TEXT")
2656
2657 assert ret == 1
2658 return _bio_to_string(bio)
2659
2660
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002661def load_crl(type, buffer):
2662 """
2663 Load a certificate revocation list from a buffer
2664
2665 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2666 :param buffer: The buffer the CRL is stored in
2667
2668 :return: The PKey object
2669 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002670 if isinstance(buffer, _text_type):
2671 buffer = buffer.encode("ascii")
2672
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002673 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002674
2675 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002676 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002677 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002678 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002679 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002680 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2681
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002682 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002683 _raise_current_error()
2684
2685 result = CRL.__new__(CRL)
2686 result._crl = crl
2687 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002688
2689
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002690def load_pkcs7_data(type, buffer):
2691 """
2692 Load pkcs7 data from a buffer
2693
2694 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2695 :param buffer: The buffer with the pkcs7 data.
2696 :return: The PKCS7 object
2697 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002698 if isinstance(buffer, _text_type):
2699 buffer = buffer.encode("ascii")
2700
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002701 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002702
2703 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002704 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002705 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002706 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002707 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002708 # TODO: This is untested.
2709 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002710 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2711
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002712 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002713 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002714
2715 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002716 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002717 return pypkcs7
2718
2719
Stephen Holsapple38482622014-04-05 20:29:34 -07002720def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002721 """
2722 Load a PKCS12 object from a buffer
2723
2724 :param buffer: The buffer the certificate is stored in
2725 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2726 :returns: The PKCS12 object
2727 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002728 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002729
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002730 if isinstance(buffer, _text_type):
2731 buffer = buffer.encode("ascii")
2732
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002733 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002734
Stephen Holsapple38482622014-04-05 20:29:34 -07002735 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2736 # password based encryption no password and a zero length password are two
2737 # different things, but OpenSSL implementation will try both to figure out
2738 # which one works.
2739 if not passphrase:
2740 passphrase = _ffi.NULL
2741
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002742 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2743 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002744 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002745 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002746
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002747 pkey = _ffi.new("EVP_PKEY**")
2748 cert = _ffi.new("X509**")
2749 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002750
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002751 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002752 if not parse_result:
2753 _raise_current_error()
2754
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002755 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002756
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002757 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2758 # queue for no particular reason. This error isn't interesting to anyone
2759 # outside this function. It's not even interesting to us. Get rid of it.
2760 try:
2761 _raise_current_error()
2762 except Error:
2763 pass
2764
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002765 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002766 pykey = None
2767 else:
2768 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002769 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002770
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002771 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002772 pycert = None
2773 friendlyname = None
2774 else:
2775 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002776 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002777
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002778 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002779 friendlyname_buffer = _lib.X509_alias_get0(
2780 cert[0], friendlyname_length
2781 )
2782 friendlyname = _ffi.buffer(
2783 friendlyname_buffer, friendlyname_length[0]
2784 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002785 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002786 friendlyname = None
2787
2788 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002789 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002790 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002791 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002792 pycacerts.append(pycacert)
2793 if not pycacerts:
2794 pycacerts = None
2795
2796 pkcs12 = PKCS12.__new__(PKCS12)
2797 pkcs12._pkey = pykey
2798 pkcs12._cert = pycert
2799 pkcs12._cacerts = pycacerts
2800 pkcs12._friendlyname = friendlyname
2801 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002802
2803
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002804# There are no direct unit tests for this initialization. It is tested
2805# indirectly since it is necessary for functions like dump_privatekey when
2806# using encryption.
2807#
2808# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2809# and some other similar tests may fail without this (though they may not if
2810# the Python runtime has already done some initialization of the underlying
2811# OpenSSL library (and is linked against the same one that cryptography is
2812# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002813_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002814
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002815# This is similar but exercised mainly by exception_from_error_queue. It calls
2816# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2817_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002818
2819
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002820# Set the default string mask to match OpenSSL upstream (since 2005) and
2821# RFC5280 recommendations.
2822_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')