blob: 78d491e863a4a36438e411e6d6aa13e09abc9120 [file] [log] [blame]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001from time import time
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05003from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05004from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04005from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05006
7from six import (
8 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -04009 text_type as _text_type,
10 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080011
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050012from OpenSSL._util import (
13 ffi as _ffi,
14 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050015 exception_from_error_queue as _exception_from_error_queue,
16 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040017 native as _native,
18 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040019 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040020)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080021
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050022FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
23FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080024
25# TODO This was an API mistake. OpenSSL has no such constant.
26FILETYPE_TEXT = 2 ** 16 - 1
27
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050028TYPE_RSA = _lib.EVP_PKEY_RSA
29TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080030
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080031
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050032class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050033 """
34 An error occurred in an `OpenSSL.crypto` API.
35 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050036
37
38_raise_current_error = partial(_exception_from_error_queue, Error)
39
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070040
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050041def _untested_error(where):
42 """
43 An OpenSSL API failed somehow. Additionally, the failure which was
44 encountered isn't one that's exercised by the test suite so future behavior
45 of pyOpenSSL is now somewhat less predictable.
46 """
47 raise RuntimeError("Unknown %s failure" % (where,))
48
49
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050050def _new_mem_buf(buffer=None):
51 """
52 Allocate a new OpenSSL memory BIO.
53
54 Arrange for the garbage collector to clean it up automatically.
55
56 :param buffer: None or some bytes to use to put into the BIO so that they
57 can be read out.
58 """
59 if buffer is None:
60 bio = _lib.BIO_new(_lib.BIO_s_mem())
61 free = _lib.BIO_free
62 else:
63 data = _ffi.new("char[]", buffer)
64 bio = _lib.BIO_new_mem_buf(data, len(buffer))
Alex Gaynor5945ea82015-09-05 14:59:06 -040065
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050066 # Keep the memory alive as long as the bio is alive!
67 def free(bio, ref=data):
68 return _lib.BIO_free(bio)
69
70 if bio == _ffi.NULL:
71 # TODO: This is untested.
72 _raise_current_error()
73
74 bio = _ffi.gc(bio, free)
75 return bio
76
77
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080078def _bio_to_string(bio):
79 """
80 Copy the contents of an OpenSSL BIO object into a Python byte string.
81 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050082 result_buffer = _ffi.new('char**')
83 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
84 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080085
86
Jean-Paul Calderone57122982013-02-21 08:47:05 -080087def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050088 """
89 The the time value of an ASN1 time object.
90
91 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
92 castable to that type) which will have its value set.
93 @param when: A string representation of the desired time value.
94
95 @raise TypeError: If C{when} is not a L{bytes} string.
96 @raise ValueError: If C{when} does not represent a time in the required
97 format.
98 @raise RuntimeError: If the time value cannot be set for some other
99 (unspecified) reason.
100 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800101 if not isinstance(when, bytes):
102 raise TypeError("when must be a byte string")
103
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500104 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
105 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800106 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500107 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
108 _lib.ASN1_STRING_set(dummy, when, len(when))
109 check_result = _lib.ASN1_GENERALIZEDTIME_check(
110 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800111 if not check_result:
112 raise ValueError("Invalid string")
113 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500114 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800115
116
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800117def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500118 """
119 Retrieve the time value of an ASN1 time object.
120
121 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
122 that type) from which the time value will be retrieved.
123
124 @return: The time value from C{timestamp} as a L{bytes} string in a certain
125 format. Or C{None} if the object contains no time value.
126 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500127 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
128 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800129 return None
Alex Gaynor5945ea82015-09-05 14:59:06 -0400130 elif (
131 _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
132 ):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500133 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800134 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500135 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
136 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
137 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500138 # This may happen:
139 # - if timestamp was not an ASN1_TIME
140 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
141 # - if a copy of the time data from timestamp cannot be made for
142 # the newly allocated ASN1_GENERALIZEDTIME
143 #
144 # These are difficult to test. cffi enforces the ASN1_TIME type.
145 # Memory allocation failures are a pain to trigger
146 # deterministically.
147 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800148 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500149 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800150 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500151 string_data = _lib.ASN1_STRING_data(string_timestamp)
152 string_result = _ffi.string(string_data)
153 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800154 return string_result
155
156
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800157class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200158 """
159 A class representing an DSA or RSA public key or key pair.
160 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800161 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800162 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800163
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800164 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500165 pkey = _lib.EVP_PKEY_new()
166 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800167 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800168
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800169 def generate_key(self, type, bits):
170 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700171 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800172
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200173 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800174
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200175 :param type: The key type.
176 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
177 :param bits: The number of bits.
178 :type bits: :py:data:`int` ``>= 0``
179 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
180 of the appropriate type.
181 :raises ValueError: If the number of bits isn't an integer of
182 the appropriate size.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200183 :return: :py:const:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800184 """
185 if not isinstance(type, int):
186 raise TypeError("type must be an integer")
187
188 if not isinstance(bits, int):
189 raise TypeError("bits must be an integer")
190
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800191 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500192 exponent = _lib.BN_new()
193 exponent = _ffi.gc(exponent, _lib.BN_free)
194 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800195
196 if type == TYPE_RSA:
197 if bits <= 0:
198 raise ValueError("Invalid number of bits")
199
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500200 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800201
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500202 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500203 if result == 0:
204 # TODO: The test for this case is commented out. Different
205 # builds of OpenSSL appear to have different failure modes that
206 # make it hard to test. Visual inspection of the OpenSSL
207 # source reveals that a return value of 0 signals an error.
208 # Manual testing on a particular build of OpenSSL suggests that
209 # this is probably the appropriate way to handle those errors.
210 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800211
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500212 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800213 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500214 # TODO: It appears as though this can fail if an engine is in
215 # use which does not support RSA.
216 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800217
218 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500219 dsa = _lib.DSA_generate_parameters(
220 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
221 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500222 # TODO: This is untested.
223 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500224 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500225 # TODO: This is untested.
226 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500227 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500228 # TODO: This is untested.
229 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800230 else:
231 raise Error("No such key type")
232
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800233 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800234
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800235 def check(self):
236 """
237 Check the consistency of an RSA private key.
238
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200239 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
240
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800241 :return: True if key is consistent.
242 :raise Error: if the key is inconsistent.
243 :raise TypeError: if the key is of a type which cannot be checked.
244 Only RSA keys can currently be checked.
245 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800246 if self._only_public:
247 raise TypeError("public key only")
248
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500249 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800250 raise TypeError("key type unsupported")
251
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500252 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
253 rsa = _ffi.gc(rsa, _lib.RSA_free)
254 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800255 if result:
256 return True
257 _raise_current_error()
258
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800259 def type(self):
260 """
261 Returns the type of the key
262
263 :return: The type of the key.
264 """
265 return self._pkey.type
266
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800267 def bits(self):
268 """
269 Returns the number of bits of the key
270
271 :return: The number of bits of the key.
272 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500273 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800274PKeyType = PKey
275
276
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400277class _EllipticCurve(object):
278 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400279 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400280
281 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
282 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
283 instances each of which represents one curve supported by the system.
284 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400285 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400286 _curves = None
287
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400288 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400289 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400290 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400291 """
292 Implement cooperation with the right-hand side argument of ``!=``.
293
294 Python 3 seems to have dropped this cooperation in this very narrow
295 circumstance.
296 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400297 if isinstance(other, _EllipticCurve):
298 return super(_EllipticCurve, self).__ne__(other)
299 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400300
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400301 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400302 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400303 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400304 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400305
306 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400307
308 :return: A :py:type:`set` of ``cls`` instances giving the names of the
309 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400310 """
311 if lib.Cryptography_HAS_EC:
312 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
313 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400314 # The return value on this call should be num_curves again. We
315 # could check it to make sure but if it *isn't* then.. what could
316 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400317 lib.EC_get_builtin_curves(builtin_curves, num_curves)
318 return set(
319 cls.from_nid(lib, c.nid)
320 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400321 return set()
322
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400323 @classmethod
324 def _get_elliptic_curves(cls, lib):
325 """
326 Get, cache, and return the curves supported by OpenSSL.
327
328 :param lib: The OpenSSL library binding object.
329
330 :return: A :py:type:`set` of ``cls`` instances giving the names of the
331 elliptic curves the underlying library supports.
332 """
333 if cls._curves is None:
334 cls._curves = cls._load_elliptic_curves(lib)
335 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400336
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400337 @classmethod
338 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400339 """
340 Instantiate a new :py:class:`_EllipticCurve` associated with the given
341 OpenSSL NID.
342
343 :param lib: The OpenSSL library binding object.
344
345 :param nid: The OpenSSL NID the resulting curve object will represent.
346 This must be a curve NID (and not, for example, a hash NID) or
347 subsequent operations will fail in unpredictable ways.
348 :type nid: :py:class:`int`
349
350 :return: The curve object.
351 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400352 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
353
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400354 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400355 """
356 :param _lib: The :py:mod:`cryptography` binding instance used to
357 interface with OpenSSL.
358
359 :param _nid: The OpenSSL NID identifying the curve this object
360 represents.
361 :type _nid: :py:class:`int`
362
363 :param name: The OpenSSL short name identifying the curve this object
364 represents.
365 :type name: :py:class:`unicode`
366 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400367 self._lib = lib
368 self._nid = nid
369 self.name = name
370
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400371 def __repr__(self):
372 return "<Curve %r>" % (self.name,)
373
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400374 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400375 """
376 Create a new OpenSSL EC_KEY structure initialized to use this curve.
377
378 The structure is automatically garbage collected when the Python object
379 is garbage collected.
380 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400381 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
382 return _ffi.gc(key, _lib.EC_KEY_free)
383
384
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400385def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400386 """
387 Return a set of objects representing the elliptic curves supported in the
388 OpenSSL build in use.
389
390 The curve objects have a :py:class:`unicode` ``name`` attribute by which
391 they identify themselves.
392
393 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400394 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
395 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400396 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400397 return _EllipticCurve._get_elliptic_curves(_lib)
398
399
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400400def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400401 """
402 Return a single curve object selected by name.
403
404 See :py:func:`get_elliptic_curves` for information about curve objects.
405
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400406 :param name: The OpenSSL short name identifying the curve object to
407 retrieve.
408 :type name: :py:class:`unicode`
409
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400410 If the named curve is not supported then :py:class:`ValueError` is raised.
411 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400412 for curve in get_elliptic_curves():
413 if curve.name == name:
414 return curve
415 raise ValueError("unknown curve name", name)
416
417
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800418class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200419 """
420 An X.509 Distinguished Name.
421
422 :ivar countryName: The country of the entity.
423 :ivar C: Alias for :py:attr:`countryName`.
424
425 :ivar stateOrProvinceName: The state or province of the entity.
426 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
427
428 :ivar localityName: The locality of the entity.
429 :ivar L: Alias for :py:attr:`localityName`.
430
431 :ivar organizationName: The organization name of the entity.
432 :ivar O: Alias for :py:attr:`organizationName`.
433
434 :ivar organizationalUnitName: The organizational unit of the entity.
435 :ivar OU: Alias for :py:attr:`organizationalUnitName`
436
437 :ivar commonName: The common name of the entity.
438 :ivar CN: Alias for :py:attr:`commonName`.
439
440 :ivar emailAddress: The e-mail address of the entity.
441 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400442
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800443 def __init__(self, name):
444 """
445 Create a new X509Name, copying the given X509Name instance.
446
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200447 :param name: The name to copy.
448 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800449 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500450 name = _lib.X509_NAME_dup(name._name)
451 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800452
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800453 def __setattr__(self, name, value):
454 if name.startswith('_'):
455 return super(X509Name, self).__setattr__(name, value)
456
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800457 # Note: we really do not want str subclasses here, so we do not use
458 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800459 if type(name) is not str:
460 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400461 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800462
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500463 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500464 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800465 try:
466 _raise_current_error()
467 except Error:
468 pass
469 raise AttributeError("No such attribute")
470
471 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500472 for i in range(_lib.X509_NAME_entry_count(self._name)):
473 ent = _lib.X509_NAME_get_entry(self._name, i)
474 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
475 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800476 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500477 ent = _lib.X509_NAME_delete_entry(self._name, i)
478 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800479 break
480
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500481 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800482 value = value.encode('utf-8')
483
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500484 add_result = _lib.X509_NAME_add_entry_by_NID(
485 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800486 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500487 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800488
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800489 def __getattr__(self, name):
490 """
491 Find attribute. An X509Name object has the following attributes:
492 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400493 organization (alias O), organizationalUnit (alias OU), commonName
494 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800495 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500496 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500497 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800498 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
499 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
500 # push something onto the error queue. If we don't clean that up
501 # now, someone else will bump into it later and be quite confused.
502 # See lp#314814.
503 try:
504 _raise_current_error()
505 except Error:
506 pass
507 return super(X509Name, self).__getattr__(name)
508
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500509 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800510 if entry_index == -1:
511 return None
512
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500513 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
514 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800515
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500516 result_buffer = _ffi.new("unsigned char**")
517 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800518 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500519 # TODO: This is untested.
520 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800521
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700522 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400523 result = _ffi.buffer(
524 result_buffer[0], data_length
525 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700526 finally:
527 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500528 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800529 return result
530
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500531 def _cmp(op):
532 def f(self, other):
533 if not isinstance(other, X509Name):
534 return NotImplemented
535 result = _lib.X509_NAME_cmp(self._name, other._name)
536 return op(result, 0)
537 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800538
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500539 __eq__ = _cmp(__eq__)
540 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800541
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500542 __lt__ = _cmp(__lt__)
543 __le__ = _cmp(__le__)
544
545 __gt__ = _cmp(__gt__)
546 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800547
548 def __repr__(self):
549 """
550 String representation of an X509Name
551 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400552 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500553 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800554 self._name, result_buffer, len(result_buffer))
555
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500556 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500557 # TODO: This is untested.
558 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800559
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500560 return "<X509Name object '%s'>" % (
561 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800562
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800563 def hash(self):
564 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200565 Return an integer representation of the first four bytes of the
566 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800567
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200568 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
569
570 :return: The (integer) hash of this name.
571 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800572 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500573 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800574
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800575 def der(self):
576 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200577 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800578
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200579 :return: The DER encoded form of this name.
580 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800581 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500582 result_buffer = _ffi.new('unsigned char**')
583 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800584 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500585 # TODO: This is untested.
586 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800587
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500588 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
589 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800590 return string_result
591
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800592 def get_components(self):
593 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200594 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800595
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200596 :return: The components of this name.
597 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800598 """
599 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500600 for i in range(_lib.X509_NAME_entry_count(self._name)):
601 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800602
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500603 fname = _lib.X509_NAME_ENTRY_get_object(ent)
604 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800605
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500606 nid = _lib.OBJ_obj2nid(fname)
607 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800608
609 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400610 _ffi.string(name),
611 _ffi.string(
612 _lib.ASN1_STRING_data(fval),
613 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800614
615 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200616
617
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800618X509NameType = X509Name
619
620
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800621class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200622 """
623 An X.509 v3 certificate extension.
624 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400625
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800626 def __init__(self, type_name, critical, value, subject=None, issuer=None):
627 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200628 Initializes an X509 extension.
629
Alex Gaynor6f719912015-09-20 09:21:29 -0400630 :param type_name: The name of the type of extension to create. See
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200631 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Alex Gaynor6f719912015-09-20 09:21:29 -0400632 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800633
Alex Gaynor5945ea82015-09-05 14:59:06 -0400634 :param bool critical: A flag indicating whether this is a critical
635 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800636
637 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200638 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800639
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200640 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800641 :type subject: :py:class:`X509`
642
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200643 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800644 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800645 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500646 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800647
Alex Gaynor5945ea82015-09-05 14:59:06 -0400648 # A context is necessary for any extension which uses the r2i
649 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
650 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500651 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800652
653 # We have no configuration database - but perhaps we should (some
654 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500655 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800656
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800657 # Initialize the subject and issuer, if appropriate. ctx is a local,
658 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400659 # any references, so no need to mess with reference counts or
660 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800661 if issuer is not None:
662 if not isinstance(issuer, X509):
663 raise TypeError("issuer must be an X509 instance")
664 ctx.issuer_cert = issuer._x509
665 if subject is not None:
666 if not isinstance(subject, X509):
667 raise TypeError("subject must be an X509 instance")
668 ctx.subject_cert = subject._x509
669
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800670 if critical:
671 # There are other OpenSSL APIs which would let us pass in critical
672 # separately, but they're harder to use, and since value is already
673 # a pile of crappy junk smuggling a ton of utterly important
674 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400675 # with strings? (However, X509V3_EXT_i2d in particular seems like
676 # it would be a better API to invoke. I do not know where to get
677 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500678 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800679
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500680 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
681 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800682 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500683 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800684
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400685 @property
686 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500687 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400688
689 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500690 _lib.GEN_EMAIL: "email",
691 _lib.GEN_DNS: "DNS",
692 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400693 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400694
695 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500696 method = _lib.X509V3_EXT_get(self._extension)
697 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500698 # TODO: This is untested.
699 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400700 payload = self._extension.value.data
701 length = self._extension.value.length
702
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500703 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400704 payloadptr[0] = payload
705
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500706 if method.it != _ffi.NULL:
707 ptr = _lib.ASN1_ITEM_ptr(method.it)
708 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
709 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400710 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500711 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400712 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500713 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400714
Paul Kehrerb7d79502015-05-04 07:43:51 -0500715 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400716 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500717 for i in range(_lib.sk_GENERAL_NAME_num(names)):
718 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400719 try:
720 label = self._prefixes[name.type]
721 except KeyError:
722 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500723 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500724 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400725 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500726 value = _native(
727 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
728 parts.append(label + ":" + value)
729 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400730
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800731 def __str__(self):
732 """
733 :return: a nice text representation of the extension
734 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500735 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400736 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800737
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400738 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500739 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800740 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500741 # TODO: This is untested.
742 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800743
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500744 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800745
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800746 def get_critical(self):
747 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200748 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800749
750 :return: The critical field.
751 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500752 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800753
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800754 def get_short_name(self):
755 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200756 Returns the short type name of this X.509 extension.
757
758 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800759
760 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200761 :rtype: :py:data:`bytes`
762
763 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800764 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500765 obj = _lib.X509_EXTENSION_get_object(self._extension)
766 nid = _lib.OBJ_obj2nid(obj)
767 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800768
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800769 def get_data(self):
770 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200771 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800772
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200773 :return: The ASN.1 encoded data of this X509 extension.
774 :rtype: :py:data:`bytes`
775
776 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800777 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500778 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
779 string_result = _ffi.cast('ASN1_STRING*', octet_result)
780 char_result = _lib.ASN1_STRING_data(string_result)
781 result_length = _lib.ASN1_STRING_length(string_result)
782 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800783
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200784
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800785X509ExtensionType = X509Extension
786
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800787
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800788class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200789 """
790 An X.509 certificate signing requests.
791 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400792
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800793 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500794 req = _lib.X509_REQ_new()
795 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800796
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800797 def set_pubkey(self, pkey):
798 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200799 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800800
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200801 :param pkey: The public key to use.
802 :type pkey: :py:class:`PKey`
803
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200804 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800805 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500806 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800807 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500808 # TODO: This is untested.
809 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800810
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811 def get_pubkey(self):
812 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200813 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800814
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200815 :return: The public key.
816 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800817 """
818 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500819 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
820 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500821 # TODO: This is untested.
822 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500823 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800824 pkey._only_public = True
825 return pkey
826
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800827 def set_version(self, version):
828 """
829 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
830 request.
831
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200832 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200833 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800834 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500835 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800836 if not set_result:
837 _raise_current_error()
838
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800839 def get_version(self):
840 """
841 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
842 request.
843
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200844 :return: The value of the version subfield.
845 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800846 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500847 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800848
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800849 def get_subject(self):
850 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200851 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800852
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200853 This creates a new :py:class:`X509Name`: modifying it does not affect
854 this request.
855
856 :return: The subject of this certificate signing request.
857 :rtype: :py:class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800858 """
859 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500860 name._name = _lib.X509_REQ_get_subject_name(self._req)
861 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500862 # TODO: This is untested.
863 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800864
865 # The name is owned by the X509Req structure. As long as the X509Name
866 # Python object is alive, keep the X509Req Python object alive.
867 name._owner = self
868
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800869 return name
870
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800871 def add_extensions(self, extensions):
872 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200873 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800874
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200875 :param extensions: The X.509 extensions to add.
876 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200877 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800878 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500879 stack = _lib.sk_X509_EXTENSION_new_null()
880 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500881 # TODO: This is untested.
882 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800883
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500884 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800885
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800886 for ext in extensions:
887 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800888 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800890 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500891 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800892
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500893 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800894 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500895 # TODO: This is untested.
896 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800897
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800898 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800899 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200900 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800901
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200902 :return: The X.509 extensions in this request.
903 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
904
905 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800906 """
907 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500908 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500909 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800910 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500911 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800912 exts.append(ext)
913 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800914
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800915 def sign(self, pkey, digest):
916 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700917 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800918
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200919 :param pkey: The key pair to sign with.
920 :type pkey: :py:class:`PKey`
921 :param digest: The name of the message digest to use for the signature,
922 e.g. :py:data:`b"sha1"`.
923 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200924 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800925 """
926 if pkey._only_public:
927 raise ValueError("Key has only public part")
928
929 if not pkey._initialized:
930 raise ValueError("Key is uninitialized")
931
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500932 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500933 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800934 raise ValueError("No such digest method")
935
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500936 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800937 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500938 # TODO: This is untested.
939 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800940
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800941 def verify(self, pkey):
942 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200943 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800944
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200945 :param key: A public key.
946 :type key: :py:class:`PKey`
947 :return: :py:data:`True` if the signature is correct.
948 :rtype: :py:class:`bool`
949 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800950 problem verifying the signature.
951 """
952 if not isinstance(pkey, PKey):
953 raise TypeError("pkey must be a PKey instance")
954
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500955 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800956 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500957 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800958
959 return result
960
961
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800962X509ReqType = X509Req
963
964
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800965class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200966 """
967 An X.509 certificate.
968 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400969
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800970 def __init__(self):
971 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500972 x509 = _lib.X509_new()
973 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800974
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800975 def set_version(self, version):
976 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200977 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800978
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200979 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800980 :type version: :py:class:`int`
981
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200982 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800983 """
984 if not isinstance(version, int):
985 raise TypeError("version must be an integer")
986
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500987 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800988
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800989 def get_version(self):
990 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200991 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800992
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200993 :return: The version number of the certificate.
994 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800995 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500996 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800997
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800998 def get_pubkey(self):
999 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001000 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001001
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001002 :return: The public key.
1003 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001004 """
1005 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001006 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1007 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001008 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001009 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001010 pkey._only_public = True
1011 return pkey
1012
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001013 def set_pubkey(self, pkey):
1014 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001015 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001016
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001017 :param pkey: The public key.
1018 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001019
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001020 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001021 """
1022 if not isinstance(pkey, PKey):
1023 raise TypeError("pkey must be a PKey instance")
1024
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001025 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001026 if not set_result:
1027 _raise_current_error()
1028
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001029 def sign(self, pkey, digest):
1030 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001031 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001032
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001033 :param pkey: The key to sign with.
1034 :type pkey: :py:class:`PKey`
1035
1036 :param digest: The name of the message digest to use.
1037 :type digest: :py:class:`bytes`
1038
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001039 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001040 """
1041 if not isinstance(pkey, PKey):
1042 raise TypeError("pkey must be a PKey instance")
1043
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001044 if pkey._only_public:
1045 raise ValueError("Key only has public part")
1046
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001047 if not pkey._initialized:
1048 raise ValueError("Key is uninitialized")
1049
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001050 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001051 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001052 raise ValueError("No such digest method")
1053
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001054 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001055 if not sign_result:
1056 _raise_current_error()
1057
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001058 def get_signature_algorithm(self):
1059 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001060 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001061
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001062 :return: The name of the algorithm.
1063 :rtype: :py:class:`bytes`
1064
1065 :raises ValueError: If the signature algorithm is undefined.
1066
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001067 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001068 """
1069 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001070 nid = _lib.OBJ_obj2nid(alg)
1071 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001072 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001073 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001074
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001075 def digest(self, digest_name):
1076 """
1077 Return the digest of the X509 object.
1078
1079 :param digest_name: The name of the digest algorithm to use.
1080 :type digest_name: :py:class:`bytes`
1081
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001082 :return: The digest of the object, formatted as
1083 :py:const:`b":"`-delimited hex pairs.
1084 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001085 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001086 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001087 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001088 raise ValueError("No such digest method")
1089
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001090 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1091 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001092 result_length[0] = len(result_buffer)
1093
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001094 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001095 self._x509, digest, result_buffer, result_length)
1096
1097 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001098 # TODO: This is untested.
1099 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001100
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001101 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001102 b16encode(ch).upper() for ch
1103 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001104
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001105 def subject_name_hash(self):
1106 """
1107 Return the hash of the X509 subject.
1108
1109 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001110 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001111 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001112 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001113
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001114 def set_serial_number(self, serial):
1115 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001116 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001117
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001118 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001119 :type serial: :py:class:`int`
1120
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001121 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001122 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001123 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001124 raise TypeError("serial must be an integer")
1125
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001126 hex_serial = hex(serial)[2:]
1127 if not isinstance(hex_serial, bytes):
1128 hex_serial = hex_serial.encode('ascii')
1129
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001130 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001131
1132 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001133 # it. If bignum is still NULL after this call, then the return value
1134 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001135 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001136
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001137 if bignum_serial[0] == _ffi.NULL:
1138 set_result = _lib.ASN1_INTEGER_set(
1139 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001140 if set_result:
1141 # TODO Not tested
1142 _raise_current_error()
1143 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001144 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1145 _lib.BN_free(bignum_serial[0])
1146 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001147 # TODO Not tested
1148 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001149 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1150 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001151 if not set_result:
1152 # TODO Not tested
1153 _raise_current_error()
1154
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001155 def get_serial_number(self):
1156 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001157 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001158
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001159 :return: The serial number.
1160 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001161 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001162 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1163 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001164 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001165 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001166 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001167 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001168 serial = int(hexstring_serial, 16)
1169 return serial
1170 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001171 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001172 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001173 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001174
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001175 def gmtime_adj_notAfter(self, amount):
1176 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001177 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001178
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001179 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001180 :type amount: :py:class:`int`
1181
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001182 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001183 """
1184 if not isinstance(amount, int):
1185 raise TypeError("amount must be an integer")
1186
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001187 notAfter = _lib.X509_get_notAfter(self._x509)
1188 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001189
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001190 def gmtime_adj_notBefore(self, amount):
1191 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001192 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001193
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001194 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001195 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001196 """
1197 if not isinstance(amount, int):
1198 raise TypeError("amount must be an integer")
1199
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001200 notBefore = _lib.X509_get_notBefore(self._x509)
1201 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001202
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001203 def has_expired(self):
1204 """
1205 Check whether the certificate has expired.
1206
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001207 :return: :py:const:`True` if the certificate has expired,
1208 :py:const:`False` otherwise.
1209 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001210 """
1211 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001212 notAfter = _lib.X509_get_notAfter(self._x509)
1213 return _lib.ASN1_UTCTIME_cmp_time_t(
1214 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001215
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001216 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001217 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001218
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001219 def get_notBefore(self):
1220 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001221 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001222
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001223 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001224
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001225 YYYYMMDDhhmmssZ
1226 YYYYMMDDhhmmss+hhmm
1227 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001228
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001229 :return: A timestamp string, or :py:const:`None` if there is none.
1230 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001231 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001232 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001233
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001234 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001235 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001236
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001237 def set_notBefore(self, when):
1238 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001239 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001240
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001241 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001242
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001243 YYYYMMDDhhmmssZ
1244 YYYYMMDDhhmmss+hhmm
1245 YYYYMMDDhhmmss-hhmm
1246
1247 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001248 :type when: :py:class:`bytes`
1249
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001250 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001251 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001252 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001253
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001254 def get_notAfter(self):
1255 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001256 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001257
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001258 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001259
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001260 YYYYMMDDhhmmssZ
1261 YYYYMMDDhhmmss+hhmm
1262 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001263
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001264 :return: A timestamp string, or :py:const:`None` if there is none.
1265 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001266 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001267 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001268
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001269 def set_notAfter(self, when):
1270 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001271 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001272
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001273 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001274
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001275 YYYYMMDDhhmmssZ
1276 YYYYMMDDhhmmss+hhmm
1277 YYYYMMDDhhmmss-hhmm
1278
1279 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001280 :type when: :py:class:`bytes`
1281
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001282 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001283 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001284 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001285
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001286 def _get_name(self, which):
1287 name = X509Name.__new__(X509Name)
1288 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001289 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001290 # TODO: This is untested.
1291 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001292
1293 # The name is owned by the X509 structure. As long as the X509Name
1294 # Python object is alive, keep the X509 Python object alive.
1295 name._owner = self
1296
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001297 return name
1298
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001299 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001300 if not isinstance(name, X509Name):
1301 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001302 set_result = which(self._x509, name._name)
1303 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001304 # TODO: This is untested.
1305 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001306
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001307 def get_issuer(self):
1308 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001309 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001310
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001311 This creates a new :py:class:`X509Name`: modifying it does not affect
1312 this certificate.
1313
1314 :return: The issuer of this certificate.
1315 :rtype: :py:class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001316 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001317 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001318
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001319 def set_issuer(self, issuer):
1320 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001321 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001322
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001323 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001324 :type issuer: :py:class:`X509Name`
1325
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001326 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001327 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001328 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001329
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001330 def get_subject(self):
1331 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001332 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001333
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001334 This creates a new :py:class:`X509Name`: modifying it does not affect
1335 this certificate.
1336
1337 :return: The subject of this certificate.
1338 :rtype: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001339 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001340 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001341
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001342 def set_subject(self, subject):
1343 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001344 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001345
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001346 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001347 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001348
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001349 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001350 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001351 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001352
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001353 def get_extension_count(self):
1354 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001355 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001356
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001357 :return: The number of extensions.
1358 :rtype: :py:class:`int`
1359
1360 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001361 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001362 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001363
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001364 def add_extensions(self, extensions):
1365 """
1366 Add extensions to the certificate.
1367
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001368 :param extensions: The extensions to add.
1369 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001370 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001371 """
1372 for ext in extensions:
1373 if not isinstance(ext, X509Extension):
1374 raise ValueError("One of the elements is not an X509Extension")
1375
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001376 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001377 if not add_result:
1378 _raise_current_error()
1379
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001380 def get_extension(self, index):
1381 """
1382 Get a specific extension of the certificate by index.
1383
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001384 Extensions on a certificate are kept in order. The index
1385 parameter selects which extension will be returned.
1386
1387 :param int index: The index of the extension to retrieve.
1388 :return: The extension at the specified index.
1389 :rtype: :py:class:`X509Extension`
1390 :raises IndexError: If the extension index was out of bounds.
1391
1392 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001393 """
1394 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001395 ext._extension = _lib.X509_get_ext(self._x509, index)
1396 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001397 raise IndexError("extension index out of bounds")
1398
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001399 extension = _lib.X509_EXTENSION_dup(ext._extension)
1400 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001401 return ext
1402
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001403
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001404X509Type = X509
1405
1406
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001407class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001408 """
1409 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001410 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001411
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001412 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001413 store = _lib.X509_STORE_new()
1414 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001415
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001416 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001417 """
1418 Adds the certificate :py:data:`cert` to this store.
1419
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001420 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001421
1422 :param X509 cert: The certificate to add to this store.
1423 :raises TypeError: If the certificate is not an :py:class:`X509`.
1424 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001425 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001426 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001427 if not isinstance(cert, X509):
1428 raise TypeError()
1429
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001430 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001431 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001432 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001433
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001434
1435X509StoreType = X509Store
1436
1437
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001438class X509StoreContextError(Exception):
1439 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001440 An exception raised when an error occurred while verifying a certificate
1441 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001442
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001443 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001444 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001445 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001446
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001447 def __init__(self, message, certificate):
1448 super(X509StoreContextError, self).__init__(message)
1449 self.certificate = certificate
1450
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001451
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001452class X509StoreContext(object):
1453 """
1454 An X.509 store context.
1455
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001456 An :py:class:`X509StoreContext` is used to define some of the criteria for
1457 certificate verification. The information encapsulated in this object
1458 includes, but is not limited to, a set of trusted certificates,
1459 verification parameters, and revoked certificates.
1460
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001461 .. note::
1462
1463 Currently, one can only set the trusted certificates on an
1464 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1465 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001466
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001467 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1468 instance. It is dynamically allocated and automatically garbage
1469 collected.
1470
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001471 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001472
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001473 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001474
1475 :param X509Store store: The certificates which will be trusted for the
1476 purposes of any verifications.
1477
1478 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001479 """
1480
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001481 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001482 store_ctx = _lib.X509_STORE_CTX_new()
1483 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1484 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001485 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001486 # Make the store context available for use after instantiating this
1487 # class by initializing it now. Per testing, subsequent calls to
1488 # :py:meth:`_init` have no adverse affect.
1489 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001490
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001491 def _init(self):
1492 """
1493 Set up the store context for a subsequent verification operation.
1494 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001495 ret = _lib.X509_STORE_CTX_init(
1496 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1497 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001498 if ret <= 0:
1499 _raise_current_error()
1500
1501 def _cleanup(self):
1502 """
1503 Internally cleans up the store context.
1504
1505 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001506 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001507 """
1508 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1509
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001510 def _exception_from_context(self):
1511 """
1512 Convert an OpenSSL native context error failure into a Python
1513 exception.
1514
Alex Gaynor5945ea82015-09-05 14:59:06 -04001515 When a call to native OpenSSL X509_verify_cert fails, additional
1516 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001517 """
1518 errors = [
1519 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1520 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1521 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001522 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001523 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001524 # A context error should always be associated with a certificate, so we
1525 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001526 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001527 _cert = _lib.X509_dup(_x509)
1528 pycert = X509.__new__(X509)
1529 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001530 return X509StoreContextError(errors, pycert)
1531
Stephen Holsapple46a09252015-02-12 14:45:43 -08001532 def set_store(self, store):
1533 """
1534 Set the context's trust store.
1535
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001536 .. versionadded:: 0.15
1537
Stephen Holsapple46a09252015-02-12 14:45:43 -08001538 :param X509Store store: The certificates which will be trusted for the
1539 purposes of any *future* verifications.
1540 """
1541 self._store = store
1542
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001543 def verify_certificate(self):
1544 """
1545 Verify a certificate in a context.
1546
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001547 .. versionadded:: 0.15
1548
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001549 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001550
Alex Gaynorca87ff62015-09-04 23:31:03 -04001551 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001552 certificate in the context. Sets ``certificate`` attribute to
1553 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001554 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001555 # Always re-initialize the store context in case
1556 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001557 self._init()
1558 ret = _lib.X509_verify_cert(self._store_ctx)
1559 self._cleanup()
1560 if ret <= 0:
1561 raise self._exception_from_context()
1562
1563
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001564def load_certificate(type, buffer):
1565 """
1566 Load a certificate from a buffer
1567
1568 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1569
1570 :param buffer: The buffer the certificate is stored in
1571 :type buffer: :py:class:`bytes`
1572
1573 :return: The X509 object
1574 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001575 if isinstance(buffer, _text_type):
1576 buffer = buffer.encode("ascii")
1577
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001578 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001579
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001580 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001581 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001582 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001583 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001584 else:
1585 raise ValueError(
1586 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001587
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001588 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001589 _raise_current_error()
1590
1591 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001592 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001593 return cert
1594
1595
1596def dump_certificate(type, cert):
1597 """
1598 Dump a certificate to a buffer
1599
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001600 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1601 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001602 :param cert: The certificate to dump
1603 :return: The buffer with the dumped certificate in
1604 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001605 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001606
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001607 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001608 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001609 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001610 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001611 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001612 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001613 else:
1614 raise ValueError(
1615 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1616 "FILETYPE_TEXT")
1617
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001618 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001619 return _bio_to_string(bio)
1620
1621
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001622def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1623 """
1624 Dump a private key to a buffer
1625
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001626 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1627 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001628 :param pkey: The PKey to dump
1629 :param cipher: (optional) if encrypted PEM format, the cipher to
1630 use
1631 :param passphrase: (optional) if encrypted PEM format, this can be either
1632 the passphrase to use, or a callback for providing the
1633 passphrase.
1634 :return: The buffer with the dumped key in
Maximilian Hils0de43752015-09-18 15:26:54 +02001635 :rtype: :py:data:`bytes`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001636 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001637 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001638
1639 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001640 if passphrase is None:
1641 raise TypeError(
1642 "if a value is given for cipher "
1643 "one must also be given for passphrase")
1644 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001645 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001646 raise ValueError("Invalid cipher name")
1647 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001648 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001649
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001650 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001651 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001652 result_code = _lib.PEM_write_bio_PrivateKey(
1653 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001654 helper.callback, helper.callback_args)
1655 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001656 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001657 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001658 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001659 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1660 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001661 # TODO RSA_free(rsa)?
1662 else:
1663 raise ValueError(
1664 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1665 "FILETYPE_TEXT")
1666
1667 if result_code == 0:
1668 _raise_current_error()
1669
1670 return _bio_to_string(bio)
1671
1672
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001673def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001674 copy = _lib.X509_REVOKED_new()
1675 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001676 # TODO: This is untested.
1677 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001678
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001679 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001680 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001681 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001682
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001683 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001684 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001685 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001686
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001687 if original.extensions != _ffi.NULL:
1688 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1689 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1690 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1691 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1692 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001693 copy.extensions = extension_stack
1694
1695 copy.sequence = original.sequence
1696 return copy
1697
1698
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001699class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001700 """
1701 A certificate revocation.
1702 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001703 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1704 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1705 # OCSP_crl_reason_str. We use the latter, just like the command line
1706 # program.
1707 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001708 b"unspecified",
1709 b"keyCompromise",
1710 b"CACompromise",
1711 b"affiliationChanged",
1712 b"superseded",
1713 b"cessationOfOperation",
1714 b"certificateHold",
1715 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001716 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001717
1718 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001719 revoked = _lib.X509_REVOKED_new()
1720 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001721
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001722 def set_serial(self, hex_str):
1723 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001724 Set the serial number.
1725
1726 The serial number is formatted as a hexadecimal number encoded in
1727 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001728
1729 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001730 :type hex_str: :py:class:`bytes`
1731
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001732 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001733 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001734 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1735 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001736 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001737 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001738 if not bn_result:
1739 raise ValueError("bad hex string")
1740
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001741 asn1_serial = _ffi.gc(
1742 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1743 _lib.ASN1_INTEGER_free)
1744 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001745
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001746 def get_serial(self):
1747 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001748 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001749
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001750 The serial number is formatted as a hexadecimal number encoded in
1751 ASCII.
1752
1753 :return: The serial number.
1754 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001755 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001756 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001757
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001758 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001759 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001760 # TODO: This is untested.
1761 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001762
1763 return _bio_to_string(bio)
1764
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001765 def _delete_reason(self):
1766 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001767 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1768 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1769 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1770 _lib.X509_EXTENSION_free(ext)
1771 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001772 break
1773
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001774 def set_reason(self, reason):
1775 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001776 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001777
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001778 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001779
1780 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001781 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1782
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001783 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001784
1785 .. seealso::
1786
1787 :py:meth:`all_reasons`, which gives you a list of all supported
1788 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001789 """
1790 if reason is None:
1791 self._delete_reason()
1792 elif not isinstance(reason, bytes):
1793 raise TypeError("reason must be None or a byte string")
1794 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001795 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001796 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1797
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001798 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1799 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001800 # TODO: This is untested.
1801 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001802 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001803
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001804 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1805 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001806 # TODO: This is untested.
1807 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001808
1809 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001810 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1811 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001812
1813 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001814 # TODO: This is untested.
1815 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001816
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001817 def get_reason(self):
1818 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001819 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001820
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001821 :return: The reason, or :py:const:`None` if there is none.
1822 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1823
1824 .. seealso::
1825
1826 :py:meth:`all_reasons`, which gives you a list of all supported
1827 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001828 """
1829 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001830 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1831 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1832 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001833 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001834
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001835 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001836 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001837 print_result = _lib.M_ASN1_OCTET_STRING_print(
1838 bio, ext.value
1839 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001840 if print_result == 0:
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 return _bio_to_string(bio)
1845
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001846 def all_reasons(self):
1847 """
1848 Return a list of all the supported reason strings.
1849
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001850 This list is a copy; modifying it does not change the supported reason
1851 strings.
1852
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001853 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001854 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001855 """
1856 return self._crl_reasons[:]
1857
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001858 def set_rev_date(self, when):
1859 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001860 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001861
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001862 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1863 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001864 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001865 """
1866 return _set_asn1_time(self._revoked.revocationDate, when)
1867
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001868 def get_rev_date(self):
1869 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001870 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001871
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001872 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1873 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001874 """
1875 return _get_asn1_time(self._revoked.revocationDate)
1876
1877
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001878class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001879 """
1880 A certificate revocation list.
1881 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001882
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001883 def __init__(self):
1884 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001885 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001886 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001887 crl = _lib.X509_CRL_new()
1888 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001889
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001890 def get_revoked(self):
1891 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001892 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001893
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001894 These revocations will be provided by value, not by reference.
1895 That means it's okay to mutate them: it won't affect this CRL.
1896
1897 :return: The revocations in this CRL.
1898 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001899 """
1900 results = []
1901 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001902 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1903 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001904 revoked_copy = _X509_REVOKED_dup(revoked)
1905 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001906 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001907 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001908 if results:
1909 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001910
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001911 def add_revoked(self, revoked):
1912 """
1913 Add a revoked (by value not reference) to the CRL structure
1914
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001915 This revocation will be added by value, not by reference. That
1916 means it's okay to mutate it after adding: it won't affect
1917 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001918
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001919 :param revoked: The new revocation.
1920 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001921
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001922 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001923 """
1924 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001925 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001926 # TODO: This is untested.
1927 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001928
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001929 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001930 if add_result == 0:
1931 # TODO: This is untested.
1932 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001933
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001934 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001935 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001936 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001937 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001938
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001939 :param cert: The certificate used to sign the CRL.
1940 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001941
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001942 :param key: The key used to sign the CRL.
1943 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001944
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001945 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1946 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001947
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001948 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001949
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001950 :param bytes digest: The name of the message digest to use (eg
1951 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001952
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001953 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001954 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001955 if not isinstance(cert, X509):
1956 raise TypeError("cert must be an X509 instance")
1957 if not isinstance(key, PKey):
1958 raise TypeError("key must be a PKey instance")
1959 if not isinstance(type, int):
1960 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001961
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001962 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001963 _warn(
1964 "The default message digest (md5) is deprecated. "
1965 "Pass the name of a message digest explicitly.",
1966 category=DeprecationWarning,
1967 stacklevel=2,
1968 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001969 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001970
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001971 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001972 if digest_obj == _ffi.NULL:
1973 raise ValueError("No such digest method")
1974
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001975 bio = _lib.BIO_new(_lib.BIO_s_mem())
1976 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001977 # TODO: This is untested.
1978 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001979
Alex Gaynora738ed52015-09-05 11:17:10 -04001980 # A scratch time object to give different values to different CRL
1981 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001982 sometime = _lib.ASN1_TIME_new()
1983 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001984 # TODO: This is untested.
1985 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001986
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001987 _lib.X509_gmtime_adj(sometime, 0)
1988 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001989
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001990 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1991 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001992
Alex Gaynor5945ea82015-09-05 14:59:06 -04001993 _lib.X509_CRL_set_issuer_name(
1994 self._crl, _lib.X509_get_subject_name(cert._x509)
1995 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001996
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001997 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001998 if not sign_result:
1999 _raise_current_error()
2000
Dominic Chenf05b2122015-10-13 16:32:35 +00002001 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002002
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002003
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002004CRLType = CRL
2005
2006
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002007class PKCS7(object):
2008 def type_is_signed(self):
2009 """
2010 Check if this NID_pkcs7_signed object
2011
2012 :return: True if the PKCS7 is of type signed
2013 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002014 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002015 return True
2016 return False
2017
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002018 def type_is_enveloped(self):
2019 """
2020 Check if this NID_pkcs7_enveloped object
2021
2022 :returns: True if the PKCS7 is of type enveloped
2023 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002024 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002025 return True
2026 return False
2027
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002028 def type_is_signedAndEnveloped(self):
2029 """
2030 Check if this NID_pkcs7_signedAndEnveloped object
2031
2032 :returns: True if the PKCS7 is of type signedAndEnveloped
2033 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002034 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002035 return True
2036 return False
2037
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002038 def type_is_data(self):
2039 """
2040 Check if this NID_pkcs7_data object
2041
2042 :return: True if the PKCS7 is of type data
2043 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002044 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002045 return True
2046 return False
2047
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002048 def get_type_name(self):
2049 """
2050 Returns the type name of the PKCS7 structure
2051
2052 :return: A string with the typename
2053 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002054 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2055 string_type = _lib.OBJ_nid2sn(nid)
2056 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002057
2058PKCS7Type = PKCS7
2059
2060
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002061class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002062 """
2063 A PKCS #12 archive.
2064 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002065
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002066 def __init__(self):
2067 self._pkey = None
2068 self._cert = None
2069 self._cacerts = None
2070 self._friendlyname = None
2071
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002072 def get_certificate(self):
2073 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002074 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002075
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002076 :return: The certificate, or :py:const:`None` if there is none.
2077 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002078 """
2079 return self._cert
2080
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002081 def set_certificate(self, cert):
2082 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002083 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002084
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002085 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002086 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002087
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002088 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002089 """
2090 if not isinstance(cert, X509):
2091 raise TypeError("cert must be an X509 instance")
2092 self._cert = cert
2093
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002094 def get_privatekey(self):
2095 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002096 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002097
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002098 :return: The private key, or :py:const:`None` if there is none.
2099 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002100 """
2101 return self._pkey
2102
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002103 def set_privatekey(self, pkey):
2104 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002105 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002106
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002107 :param pkey: The new private key, or :py:const:`None` to unset it.
2108 :type pkey: :py:class:`PKey` or :py:const:`None`
2109
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002110 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002111 """
2112 if not isinstance(pkey, PKey):
2113 raise TypeError("pkey must be a PKey instance")
2114 self._pkey = pkey
2115
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002116 def get_ca_certificates(self):
2117 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002118 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002119
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002120 :return: A tuple with the CA certificates in the chain, or
2121 :py:const:`None` if there are none.
2122 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002123 """
2124 if self._cacerts is not None:
2125 return tuple(self._cacerts)
2126
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002127 def set_ca_certificates(self, cacerts):
2128 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002129 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002130
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002131 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2132 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002133 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002134
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002135 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002136 """
2137 if cacerts is None:
2138 self._cacerts = None
2139 else:
2140 cacerts = list(cacerts)
2141 for cert in cacerts:
2142 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002143 raise TypeError(
2144 "iterable must only contain X509 instances"
2145 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002146 self._cacerts = cacerts
2147
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002148 def set_friendlyname(self, name):
2149 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002150 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002151
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002152 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002153 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002154
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002155 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002156 """
2157 if name is None:
2158 self._friendlyname = None
2159 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002160 raise TypeError(
2161 "name must be a byte string or None (not %r)" % (name,)
2162 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002163 self._friendlyname = name
2164
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002165 def get_friendlyname(self):
2166 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002167 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002168
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002169 :returns: The friendly name, or :py:const:`None` if there is none.
2170 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002171 """
2172 return self._friendlyname
2173
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002174 def export(self, passphrase=None, iter=2048, maciter=1):
2175 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002176 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002177
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002178 For more information, see the :c:func:`PKCS12_create` man page.
2179
2180 :param passphrase: The passphrase used to encrypt the structure. Unlike
2181 some other passphrase arguments, this *must* be a string, not a
2182 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002183 :type passphrase: :py:data:`bytes`
2184
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002185 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002186 :type iter: :py:data:`int`
2187
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002188 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002189 :type maciter: :py:data:`int`
2190
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002191 :return: The string representation of the PKCS #12 structure.
2192 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002193 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002194 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002195
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002196 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002197 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002198 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002199 cacerts = _lib.sk_X509_new_null()
2200 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002201 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002202 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002203
2204 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002205 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002206
2207 friendlyname = self._friendlyname
2208 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002209 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002210
2211 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002212 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002213 else:
2214 pkey = self._pkey._pkey
2215
2216 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002217 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002218 else:
2219 cert = self._cert._x509
2220
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002221 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002222 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002223 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2224 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002225 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002226 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002227 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002228 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002229
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002230 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002231 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002232 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002233
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002234
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002235PKCS12Type = PKCS12
2236
2237
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002238class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002239 """
2240 A Netscape SPKI object.
2241 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002242
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002243 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002244 spki = _lib.NETSCAPE_SPKI_new()
2245 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002246
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002247 def sign(self, pkey, digest):
2248 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002249 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002250
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002251 :param pkey: The private key to sign with.
2252 :type pkey: :py:class:`PKey`
2253
2254 :param digest: The message digest to use.
2255 :type digest: :py:class:`bytes`
2256
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002257 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002258 """
2259 if pkey._only_public:
2260 raise ValueError("Key has only public part")
2261
2262 if not pkey._initialized:
2263 raise ValueError("Key is uninitialized")
2264
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002265 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002266 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002267 raise ValueError("No such digest method")
2268
Alex Gaynor5945ea82015-09-05 14:59:06 -04002269 sign_result = _lib.NETSCAPE_SPKI_sign(
2270 self._spki, pkey._pkey, digest_obj
2271 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002272 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002273 # TODO: This is untested.
2274 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002275
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002276 def verify(self, key):
2277 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002278 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002279
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002280 :param key: The public key that signature is supposedly from.
2281 :type pkey: :py:class:`PKey`
2282
2283 :return: :py:const:`True` if the signature is correct.
2284 :rtype: :py:class:`bool`
2285
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002286 :raises Error: If the signature is invalid, or there was a problem
2287 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002288 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002289 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002290 if answer <= 0:
2291 _raise_current_error()
2292 return True
2293
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002294 def b64_encode(self):
2295 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002296 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002297
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002298 :return: The base64 encoded string.
2299 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002300 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002301 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2302 result = _ffi.string(encoded)
2303 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002304 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002305
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002306 def get_pubkey(self):
2307 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002308 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002309
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002310 :return: The public key.
2311 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002312 """
2313 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002314 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2315 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002316 # TODO: This is untested.
2317 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002318 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002319 pkey._only_public = True
2320 return pkey
2321
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002322 def set_pubkey(self, pkey):
2323 """
2324 Set the public key of the certificate
2325
2326 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002327 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002328 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002329 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002330 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002331 # TODO: This is untested.
2332 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002333
2334
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002335NetscapeSPKIType = NetscapeSPKI
2336
2337
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002338class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002339 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002340 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002341 raise ValueError(
2342 "only FILETYPE_PEM key format supports encryption"
2343 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002344 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002345 self._more_args = more_args
2346 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002347 self._problems = []
2348
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002349 @property
2350 def callback(self):
2351 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002352 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002353 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002354 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002355 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002356 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002357 else:
2358 raise TypeError("Last argument must be string or callable")
2359
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002360 @property
2361 def callback_args(self):
2362 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002363 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002364 elif isinstance(self._passphrase, bytes):
2365 return self._passphrase
2366 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002367 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002368 else:
2369 raise TypeError("Last argument must be string or callable")
2370
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002371 def raise_if_problem(self, exceptionType=Error):
2372 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002373 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002374 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002375 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002376 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002377 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002378 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002379
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002380 def _read_passphrase(self, buf, size, rwflag, userdata):
2381 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002382 if self._more_args:
2383 result = self._passphrase(size, rwflag, userdata)
2384 else:
2385 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002386 if not isinstance(result, bytes):
2387 raise ValueError("String expected")
2388 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002389 if self._truncate:
2390 result = result[:size]
2391 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002392 raise ValueError(
2393 "passphrase returned by callback is too long"
2394 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002395 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002396 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002397 return len(result)
2398 except Exception as e:
2399 self._problems.append(e)
2400 return 0
2401
2402
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002403def load_privatekey(type, buffer, passphrase=None):
2404 """
2405 Load a private key from a buffer
2406
2407 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2408 :param buffer: The buffer the key is stored in
2409 :param passphrase: (optional) if encrypted PEM format, this can be
2410 either the passphrase to use, or a callback for
2411 providing the passphrase.
2412
2413 :return: The PKey object
2414 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002415 if isinstance(buffer, _text_type):
2416 buffer = buffer.encode("ascii")
2417
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002418 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002419
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002420 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002421 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002422 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2423 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002424 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002425 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002426 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002427 else:
2428 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2429
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002430 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002431 _raise_current_error()
2432
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002433 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002434 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002435 return pkey
2436
2437
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002438def dump_certificate_request(type, req):
2439 """
2440 Dump a certificate request to a buffer
2441
2442 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2443 :param req: The certificate request to dump
2444 :return: The buffer with the dumped certificate request in
2445 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002446 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002447
2448 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002449 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002450 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002451 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002452 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002453 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002454 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002455 raise ValueError(
2456 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2457 "FILETYPE_TEXT"
2458 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002459
2460 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002461 # TODO: This is untested.
2462 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002463
2464 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002465
2466
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002467def load_certificate_request(type, buffer):
2468 """
2469 Load a certificate request from a buffer
2470
2471 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2472 :param buffer: The buffer the certificate request is stored in
2473 :return: The X509Req object
2474 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002475 if isinstance(buffer, _text_type):
2476 buffer = buffer.encode("ascii")
2477
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002478 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002479
2480 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002481 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002482 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002483 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002484 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002485 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002486
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002487 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002488 # TODO: This is untested.
2489 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002490
2491 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002492 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002493 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002494
2495
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002496def sign(pkey, data, digest):
2497 """
2498 Sign data with a digest
2499
2500 :param pkey: Pkey to sign with
2501 :param data: data to be signed
2502 :param digest: message digest to use
2503 :return: signature
2504 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002505 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002506
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002507 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002508 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002509 raise ValueError("No such digest method")
2510
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002511 md_ctx = _ffi.new("EVP_MD_CTX*")
2512 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002513
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002514 _lib.EVP_SignInit(md_ctx, digest_obj)
2515 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002516
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002517 signature_buffer = _ffi.new("unsigned char[]", 512)
2518 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002519 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002520 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002521 md_ctx, signature_buffer, signature_length, pkey._pkey)
2522
2523 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002524 # TODO: This is untested.
2525 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002526
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002527 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002528
2529
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002530def verify(cert, signature, data, digest):
2531 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002532 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002533
2534 :param cert: signing certificate (X509 object)
2535 :param signature: signature returned by sign function
2536 :param data: data to be verified
2537 :param digest: message digest to use
Alex Gaynor5945ea82015-09-05 14:59:06 -04002538 :return: :py:const:`None` if the signature is correct, raise exception
2539 otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002540 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002541 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002542
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002543 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002544 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002545 raise ValueError("No such digest method")
2546
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002547 pkey = _lib.X509_get_pubkey(cert._x509)
2548 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002549 # TODO: This is untested.
2550 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002551 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002552
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002553 md_ctx = _ffi.new("EVP_MD_CTX*")
2554 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002555
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002556 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2557 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002558 verify_result = _lib.EVP_VerifyFinal(
2559 md_ctx, signature, len(signature), pkey
2560 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002561
2562 if verify_result != 1:
2563 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002564
2565
Dominic Chenf05b2122015-10-13 16:32:35 +00002566def dump_crl(type, crl):
2567 """
2568 Dump a certificate revocation list to a buffer.
2569
2570 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2571 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002572 :param CRL crl: The CRL to dump.
2573
Dominic Chenf05b2122015-10-13 16:32:35 +00002574 :return: The buffer with the CRL.
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002575 :rtype: :data:`bytes`
Dominic Chenf05b2122015-10-13 16:32:35 +00002576 """
2577 bio = _new_mem_buf()
2578
2579 if type == FILETYPE_PEM:
2580 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2581 elif type == FILETYPE_ASN1:
2582 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2583 elif type == FILETYPE_TEXT:
2584 ret = _lib.X509_CRL_print(bio, crl._crl)
2585 else:
2586 raise ValueError(
2587 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2588 "FILETYPE_TEXT")
2589
2590 assert ret == 1
2591 return _bio_to_string(bio)
2592
2593
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002594def load_crl(type, buffer):
2595 """
2596 Load a certificate revocation list from a buffer
2597
2598 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2599 :param buffer: The buffer the CRL is stored in
2600
2601 :return: The PKey object
2602 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002603 if isinstance(buffer, _text_type):
2604 buffer = buffer.encode("ascii")
2605
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002606 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002607
2608 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002609 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002610 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002611 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002612 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002613 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2614
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002615 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002616 _raise_current_error()
2617
2618 result = CRL.__new__(CRL)
2619 result._crl = crl
2620 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002621
2622
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002623def load_pkcs7_data(type, buffer):
2624 """
2625 Load pkcs7 data from a buffer
2626
2627 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2628 :param buffer: The buffer with the pkcs7 data.
2629 :return: The PKCS7 object
2630 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002631 if isinstance(buffer, _text_type):
2632 buffer = buffer.encode("ascii")
2633
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002634 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002635
2636 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002637 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002638 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002639 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002640 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002641 # TODO: This is untested.
2642 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002643 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2644
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002645 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002646 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002647
2648 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002649 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002650 return pypkcs7
2651
2652
Stephen Holsapple38482622014-04-05 20:29:34 -07002653def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002654 """
2655 Load a PKCS12 object from a buffer
2656
2657 :param buffer: The buffer the certificate is stored in
2658 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2659 :returns: The PKCS12 object
2660 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002661 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002662
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002663 if isinstance(buffer, _text_type):
2664 buffer = buffer.encode("ascii")
2665
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002666 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002667
Stephen Holsapple38482622014-04-05 20:29:34 -07002668 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2669 # password based encryption no password and a zero length password are two
2670 # different things, but OpenSSL implementation will try both to figure out
2671 # which one works.
2672 if not passphrase:
2673 passphrase = _ffi.NULL
2674
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002675 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2676 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002677 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002678 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002679
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002680 pkey = _ffi.new("EVP_PKEY**")
2681 cert = _ffi.new("X509**")
2682 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002683
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002684 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002685 if not parse_result:
2686 _raise_current_error()
2687
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002688 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002689
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002690 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2691 # queue for no particular reason. This error isn't interesting to anyone
2692 # outside this function. It's not even interesting to us. Get rid of it.
2693 try:
2694 _raise_current_error()
2695 except Error:
2696 pass
2697
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002698 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002699 pykey = None
2700 else:
2701 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002702 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002703
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002704 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002705 pycert = None
2706 friendlyname = None
2707 else:
2708 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002709 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002710
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002711 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002712 friendlyname_buffer = _lib.X509_alias_get0(
2713 cert[0], friendlyname_length
2714 )
2715 friendlyname = _ffi.buffer(
2716 friendlyname_buffer, friendlyname_length[0]
2717 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002718 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002719 friendlyname = None
2720
2721 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002722 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002723 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002724 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002725 pycacerts.append(pycacert)
2726 if not pycacerts:
2727 pycacerts = None
2728
2729 pkcs12 = PKCS12.__new__(PKCS12)
2730 pkcs12._pkey = pykey
2731 pkcs12._cert = pycert
2732 pkcs12._cacerts = pycacerts
2733 pkcs12._friendlyname = friendlyname
2734 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002735
2736
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002737# There are no direct unit tests for this initialization. It is tested
2738# indirectly since it is necessary for functions like dump_privatekey when
2739# using encryption.
2740#
2741# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2742# and some other similar tests may fail without this (though they may not if
2743# the Python runtime has already done some initialization of the underlying
2744# OpenSSL library (and is linked against the same one that cryptography is
2745# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002746_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002747
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002748# This is similar but exercised mainly by exception_from_error_queue. It calls
2749# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2750_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002751
2752
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002753# Set the default string mask to match OpenSSL upstream (since 2005) and
2754# RFC5280 recommendations.
2755_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')