blob: 92ec8153f7f98f95c3594ef792561fb13014f701 [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 (
Alex Gaynorb9521c82015-09-04 09:18:59 -040013 binding as _binding,
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050014 ffi as _ffi,
15 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050016 exception_from_error_queue as _exception_from_error_queue,
17 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040018 native as _native,
19 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040020 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040021)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080022
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050023FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
24FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080025
26# TODO This was an API mistake. OpenSSL has no such constant.
27FILETYPE_TEXT = 2 ** 16 - 1
28
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050029TYPE_RSA = _lib.EVP_PKEY_RSA
30TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080031
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080032
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070033
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050034class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050035 """
36 An error occurred in an `OpenSSL.crypto` API.
37 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050038
39
40_raise_current_error = partial(_exception_from_error_queue, Error)
41
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070042
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050043
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050044def _untested_error(where):
45 """
46 An OpenSSL API failed somehow. Additionally, the failure which was
47 encountered isn't one that's exercised by the test suite so future behavior
48 of pyOpenSSL is now somewhat less predictable.
49 """
50 raise RuntimeError("Unknown %s failure" % (where,))
51
52
53
54def _new_mem_buf(buffer=None):
55 """
56 Allocate a new OpenSSL memory BIO.
57
58 Arrange for the garbage collector to clean it up automatically.
59
60 :param buffer: None or some bytes to use to put into the BIO so that they
61 can be read out.
62 """
63 if buffer is None:
64 bio = _lib.BIO_new(_lib.BIO_s_mem())
65 free = _lib.BIO_free
66 else:
67 data = _ffi.new("char[]", buffer)
68 bio = _lib.BIO_new_mem_buf(data, len(buffer))
69 # Keep the memory alive as long as the bio is alive!
70 def free(bio, ref=data):
71 return _lib.BIO_free(bio)
72
73 if bio == _ffi.NULL:
74 # TODO: This is untested.
75 _raise_current_error()
76
77 bio = _ffi.gc(bio, free)
78 return bio
79
80
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050081
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080082def _bio_to_string(bio):
83 """
84 Copy the contents of an OpenSSL BIO object into a Python byte string.
85 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050086 result_buffer = _ffi.new('char**')
87 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
88 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080089
90
91
Jean-Paul Calderone57122982013-02-21 08:47:05 -080092def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050093 """
94 The the time value of an ASN1 time object.
95
96 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
97 castable to that type) which will have its value set.
98 @param when: A string representation of the desired time value.
99
100 @raise TypeError: If C{when} is not a L{bytes} string.
101 @raise ValueError: If C{when} does not represent a time in the required
102 format.
103 @raise RuntimeError: If the time value cannot be set for some other
104 (unspecified) reason.
105 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800106 if not isinstance(when, bytes):
107 raise TypeError("when must be a byte string")
108
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500109 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
110 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800111 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500112 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
113 _lib.ASN1_STRING_set(dummy, when, len(when))
114 check_result = _lib.ASN1_GENERALIZEDTIME_check(
115 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800116 if not check_result:
117 raise ValueError("Invalid string")
118 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500119 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800120
121
122
123def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500124 """
125 Retrieve the time value of an ASN1 time object.
126
127 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
128 that type) from which the time value will be retrieved.
129
130 @return: The time value from C{timestamp} as a L{bytes} string in a certain
131 format. Or C{None} if the object contains no time value.
132 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500133 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
134 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800135 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500136 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
137 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800138 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500139 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
140 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
141 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500142 # This may happen:
143 # - if timestamp was not an ASN1_TIME
144 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
145 # - if a copy of the time data from timestamp cannot be made for
146 # the newly allocated ASN1_GENERALIZEDTIME
147 #
148 # These are difficult to test. cffi enforces the ASN1_TIME type.
149 # Memory allocation failures are a pain to trigger
150 # deterministically.
151 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800152 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500153 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800154 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500155 string_data = _lib.ASN1_STRING_data(string_timestamp)
156 string_result = _ffi.string(string_data)
157 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800158 return string_result
159
160
161
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800162class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200163 """
164 A class representing an DSA or RSA public key or key pair.
165 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800166 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800167 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800168
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800169 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500170 pkey = _lib.EVP_PKEY_new()
171 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800172 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800173
174
175 def generate_key(self, type, bits):
176 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700177 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800178
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200179 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800180
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200181 :param type: The key type.
182 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
183 :param bits: The number of bits.
184 :type bits: :py:data:`int` ``>= 0``
185 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
186 of the appropriate type.
187 :raises ValueError: If the number of bits isn't an integer of
188 the appropriate size.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200189 :return: :py:const:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800190 """
191 if not isinstance(type, int):
192 raise TypeError("type must be an integer")
193
194 if not isinstance(bits, int):
195 raise TypeError("bits must be an integer")
196
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800197 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500198 exponent = _lib.BN_new()
199 exponent = _ffi.gc(exponent, _lib.BN_free)
200 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800201
202 if type == TYPE_RSA:
203 if bits <= 0:
204 raise ValueError("Invalid number of bits")
205
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500206 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800207
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500208 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500209 if result == 0:
210 # TODO: The test for this case is commented out. Different
211 # builds of OpenSSL appear to have different failure modes that
212 # make it hard to test. Visual inspection of the OpenSSL
213 # source reveals that a return value of 0 signals an error.
214 # Manual testing on a particular build of OpenSSL suggests that
215 # this is probably the appropriate way to handle those errors.
216 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800217
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500218 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800219 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500220 # TODO: It appears as though this can fail if an engine is in
221 # use which does not support RSA.
222 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800223
224 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500225 dsa = _lib.DSA_generate_parameters(
226 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
227 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500228 # TODO: This is untested.
229 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500230 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500231 # TODO: This is untested.
232 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500233 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500234 # TODO: This is untested.
235 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800236 else:
237 raise Error("No such key type")
238
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800239 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800240
241
242 def check(self):
243 """
244 Check the consistency of an RSA private key.
245
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200246 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
247
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800248 :return: True if key is consistent.
249 :raise Error: if the key is inconsistent.
250 :raise TypeError: if the key is of a type which cannot be checked.
251 Only RSA keys can currently be checked.
252 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800253 if self._only_public:
254 raise TypeError("public key only")
255
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500256 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800257 raise TypeError("key type unsupported")
258
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500259 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
260 rsa = _ffi.gc(rsa, _lib.RSA_free)
261 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800262 if result:
263 return True
264 _raise_current_error()
265
266
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800267 def type(self):
268 """
269 Returns the type of the key
270
271 :return: The type of the key.
272 """
273 return self._pkey.type
274
275
276 def bits(self):
277 """
278 Returns the number of bits of the key
279
280 :return: The number of bits of the key.
281 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500282 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800283PKeyType = PKey
284
285
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800286
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400287class _EllipticCurve(object):
288 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400289 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400290
291 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
292 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
293 instances each of which represents one curve supported by the system.
294 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400295 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400296 _curves = None
297
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400298 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400299 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400300 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400301 """
302 Implement cooperation with the right-hand side argument of ``!=``.
303
304 Python 3 seems to have dropped this cooperation in this very narrow
305 circumstance.
306 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400307 if isinstance(other, _EllipticCurve):
308 return super(_EllipticCurve, self).__ne__(other)
309 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400310
311
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400312 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400313 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400314 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400315 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400316
317 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400318
319 :return: A :py:type:`set` of ``cls`` instances giving the names of the
320 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400321 """
322 if lib.Cryptography_HAS_EC:
323 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
324 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
325 # The return value on this call should be num_curves again. We could
326 # check it to make sure but if it *isn't* then.. what could we do?
327 # Abort the whole process, I suppose...? -exarkun
328 lib.EC_get_builtin_curves(builtin_curves, num_curves)
329 return set(
330 cls.from_nid(lib, c.nid)
331 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400332 return set()
333
334
335 @classmethod
336 def _get_elliptic_curves(cls, lib):
337 """
338 Get, cache, and return the curves supported by OpenSSL.
339
340 :param lib: The OpenSSL library binding object.
341
342 :return: A :py:type:`set` of ``cls`` instances giving the names of the
343 elliptic curves the underlying library supports.
344 """
345 if cls._curves is None:
346 cls._curves = cls._load_elliptic_curves(lib)
347 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400348
349
350 @classmethod
351 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400352 """
353 Instantiate a new :py:class:`_EllipticCurve` associated with the given
354 OpenSSL NID.
355
356 :param lib: The OpenSSL library binding object.
357
358 :param nid: The OpenSSL NID the resulting curve object will represent.
359 This must be a curve NID (and not, for example, a hash NID) or
360 subsequent operations will fail in unpredictable ways.
361 :type nid: :py:class:`int`
362
363 :return: The curve object.
364 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400365 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
366
367
368 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400369 """
370 :param _lib: The :py:mod:`cryptography` binding instance used to
371 interface with OpenSSL.
372
373 :param _nid: The OpenSSL NID identifying the curve this object
374 represents.
375 :type _nid: :py:class:`int`
376
377 :param name: The OpenSSL short name identifying the curve this object
378 represents.
379 :type name: :py:class:`unicode`
380 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400381 self._lib = lib
382 self._nid = nid
383 self.name = name
384
385
386 def __repr__(self):
387 return "<Curve %r>" % (self.name,)
388
389
390 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400391 """
392 Create a new OpenSSL EC_KEY structure initialized to use this curve.
393
394 The structure is automatically garbage collected when the Python object
395 is garbage collected.
396 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400397 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
398 return _ffi.gc(key, _lib.EC_KEY_free)
399
400
401
402def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400403 """
404 Return a set of objects representing the elliptic curves supported in the
405 OpenSSL build in use.
406
407 The curve objects have a :py:class:`unicode` ``name`` attribute by which
408 they identify themselves.
409
410 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400411 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
412 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400413 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400414 return _EllipticCurve._get_elliptic_curves(_lib)
415
416
417
418def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400419 """
420 Return a single curve object selected by name.
421
422 See :py:func:`get_elliptic_curves` for information about curve objects.
423
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400424 :param name: The OpenSSL short name identifying the curve object to
425 retrieve.
426 :type name: :py:class:`unicode`
427
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400428 If the named curve is not supported then :py:class:`ValueError` is raised.
429 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400430 for curve in get_elliptic_curves():
431 if curve.name == name:
432 return curve
433 raise ValueError("unknown curve name", name)
434
435
436
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800437class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200438 """
439 An X.509 Distinguished Name.
440
441 :ivar countryName: The country of the entity.
442 :ivar C: Alias for :py:attr:`countryName`.
443
444 :ivar stateOrProvinceName: The state or province of the entity.
445 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
446
447 :ivar localityName: The locality of the entity.
448 :ivar L: Alias for :py:attr:`localityName`.
449
450 :ivar organizationName: The organization name of the entity.
451 :ivar O: Alias for :py:attr:`organizationName`.
452
453 :ivar organizationalUnitName: The organizational unit of the entity.
454 :ivar OU: Alias for :py:attr:`organizationalUnitName`
455
456 :ivar commonName: The common name of the entity.
457 :ivar CN: Alias for :py:attr:`commonName`.
458
459 :ivar emailAddress: The e-mail address of the entity.
460 """
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800461 def __init__(self, name):
462 """
463 Create a new X509Name, copying the given X509Name instance.
464
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200465 :param name: The name to copy.
466 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800467 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500468 name = _lib.X509_NAME_dup(name._name)
469 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800470
471
472 def __setattr__(self, name, value):
473 if name.startswith('_'):
474 return super(X509Name, self).__setattr__(name, value)
475
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800476 # Note: we really do not want str subclasses here, so we do not use
477 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800478 if type(name) is not str:
479 raise TypeError("attribute name must be string, not '%.200s'" % (
480 type(value).__name__,))
481
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500482 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500483 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800484 try:
485 _raise_current_error()
486 except Error:
487 pass
488 raise AttributeError("No such attribute")
489
490 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500491 for i in range(_lib.X509_NAME_entry_count(self._name)):
492 ent = _lib.X509_NAME_get_entry(self._name, i)
493 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
494 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800495 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500496 ent = _lib.X509_NAME_delete_entry(self._name, i)
497 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800498 break
499
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500500 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800501 value = value.encode('utf-8')
502
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500503 add_result = _lib.X509_NAME_add_entry_by_NID(
504 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800505 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500506 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800507
508
509 def __getattr__(self, name):
510 """
511 Find attribute. An X509Name object has the following attributes:
512 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
513 organization (alias O), organizationalUnit (alias OU), commonName (alias
514 CN) and more...
515 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500516 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500517 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800518 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
519 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
520 # push something onto the error queue. If we don't clean that up
521 # now, someone else will bump into it later and be quite confused.
522 # See lp#314814.
523 try:
524 _raise_current_error()
525 except Error:
526 pass
527 return super(X509Name, self).__getattr__(name)
528
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500529 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800530 if entry_index == -1:
531 return None
532
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500533 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
534 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800535
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500536 result_buffer = _ffi.new("unsigned char**")
537 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800538 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500539 # TODO: This is untested.
540 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800541
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700542 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500543 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700544 finally:
545 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500546 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800547 return result
548
549
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500550 def _cmp(op):
551 def f(self, other):
552 if not isinstance(other, X509Name):
553 return NotImplemented
554 result = _lib.X509_NAME_cmp(self._name, other._name)
555 return op(result, 0)
556 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800557
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500558 __eq__ = _cmp(__eq__)
559 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800560
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500561 __lt__ = _cmp(__lt__)
562 __le__ = _cmp(__le__)
563
564 __gt__ = _cmp(__gt__)
565 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800566
567 def __repr__(self):
568 """
569 String representation of an X509Name
570 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400571 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500572 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800573 self._name, result_buffer, len(result_buffer))
574
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500575 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500576 # TODO: This is untested.
577 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800578
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500579 return "<X509Name object '%s'>" % (
580 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800581
582
583 def hash(self):
584 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200585 Return an integer representation of the first four bytes of the
586 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800587
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200588 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
589
590 :return: The (integer) hash of this name.
591 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800592 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500593 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800594
595
596 def der(self):
597 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200598 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800599
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200600 :return: The DER encoded form of this name.
601 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800602 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500603 result_buffer = _ffi.new('unsigned char**')
604 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800605 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500606 # TODO: This is untested.
607 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800608
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500609 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
610 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800611 return string_result
612
613
614 def get_components(self):
615 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200616 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800617
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200618 :return: The components of this name.
619 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800620 """
621 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500622 for i in range(_lib.X509_NAME_entry_count(self._name)):
623 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800624
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500625 fname = _lib.X509_NAME_ENTRY_get_object(ent)
626 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800627
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500628 nid = _lib.OBJ_obj2nid(fname)
629 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800630
631 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500632 _ffi.string(name),
633 _ffi.string(
634 _lib.ASN1_STRING_data(fval),
635 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800636
637 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200638
639
640
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800641X509NameType = X509Name
642
643
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200644
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800645class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200646 """
647 An X.509 v3 certificate extension.
648 """
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800649 def __init__(self, type_name, critical, value, subject=None, issuer=None):
650 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200651 Initializes an X509 extension.
652
653 :param typename: The name of the type of extension to create. See
654 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800655 :type typename: :py:data:`str`
656
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200657 :param bool critical: A flag indicating whether this is a critical extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800658
659 :param value: The value of the extension.
660 :type value: :py:data:`str`
661
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200662 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800663 :type subject: :py:class:`X509`
664
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200665 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800666 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800667 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500668 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800669
670 # A context is necessary for any extension which uses the r2i conversion
671 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
672 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500673 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800674
675 # We have no configuration database - but perhaps we should (some
676 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500677 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800678
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800679 # Initialize the subject and issuer, if appropriate. ctx is a local,
680 # and as far as I can tell none of the X509V3_* APIs invoked here steal
681 # any references, so no need to mess with reference counts or duplicates.
682 if issuer is not None:
683 if not isinstance(issuer, X509):
684 raise TypeError("issuer must be an X509 instance")
685 ctx.issuer_cert = issuer._x509
686 if subject is not None:
687 if not isinstance(subject, X509):
688 raise TypeError("subject must be an X509 instance")
689 ctx.subject_cert = subject._x509
690
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800691 if critical:
692 # There are other OpenSSL APIs which would let us pass in critical
693 # separately, but they're harder to use, and since value is already
694 # a pile of crappy junk smuggling a ton of utterly important
695 # structured data, what's the point of trying to avoid nasty stuff
696 # with strings? (However, X509V3_EXT_i2d in particular seems like it
697 # would be a better API to invoke. I do not know where to get the
698 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500699 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800700
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500701 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
702 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800703 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500704 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800705
706
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400707 @property
708 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500709 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400710
711 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500712 _lib.GEN_EMAIL: "email",
713 _lib.GEN_DNS: "DNS",
714 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400715 }
716
717 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500718 method = _lib.X509V3_EXT_get(self._extension)
719 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500720 # TODO: This is untested.
721 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400722 payload = self._extension.value.data
723 length = self._extension.value.length
724
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500725 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400726 payloadptr[0] = payload
727
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500728 if method.it != _ffi.NULL:
729 ptr = _lib.ASN1_ITEM_ptr(method.it)
730 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
731 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400732 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500733 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400734 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500735 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400736
Paul Kehrerb7d79502015-05-04 07:43:51 -0500737 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400738 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500739 for i in range(_lib.sk_GENERAL_NAME_num(names)):
740 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400741 try:
742 label = self._prefixes[name.type]
743 except KeyError:
744 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500745 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500746 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400747 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500748 value = _native(
749 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
750 parts.append(label + ":" + value)
751 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400752
753
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800754 def __str__(self):
755 """
756 :return: a nice text representation of the extension
757 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500758 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400759 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800760
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400761 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500762 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800763 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500764 # TODO: This is untested.
765 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800766
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500767 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800768
769
770 def get_critical(self):
771 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200772 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800773
774 :return: The critical field.
775 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500776 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800777
778
779 def get_short_name(self):
780 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200781 Returns the short type name of this X.509 extension.
782
783 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800784
785 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200786 :rtype: :py:data:`bytes`
787
788 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800789 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500790 obj = _lib.X509_EXTENSION_get_object(self._extension)
791 nid = _lib.OBJ_obj2nid(obj)
792 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800793
794
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800795 def get_data(self):
796 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200797 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800798
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200799 :return: The ASN.1 encoded data of this X509 extension.
800 :rtype: :py:data:`bytes`
801
802 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800803 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500804 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
805 string_result = _ffi.cast('ASN1_STRING*', octet_result)
806 char_result = _lib.ASN1_STRING_data(string_result)
807 result_length = _lib.ASN1_STRING_length(string_result)
808 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800809
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200810
811
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800812X509ExtensionType = X509Extension
813
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800814
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200815
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800816class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200817 """
818 An X.509 certificate signing requests.
819 """
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800820 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500821 req = _lib.X509_REQ_new()
822 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800823
824
825 def set_pubkey(self, pkey):
826 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200827 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800828
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200829 :param pkey: The public key to use.
830 :type pkey: :py:class:`PKey`
831
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200832 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800833 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500834 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800835 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500836 # TODO: This is untested.
837 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800838
839
840 def get_pubkey(self):
841 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200842 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800843
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200844 :return: The public key.
845 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800846 """
847 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500848 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
849 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500850 # TODO: This is untested.
851 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500852 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800853 pkey._only_public = True
854 return pkey
855
856
857 def set_version(self, version):
858 """
859 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
860 request.
861
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200862 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200863 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800864 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500865 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800866 if not set_result:
867 _raise_current_error()
868
869
870 def get_version(self):
871 """
872 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
873 request.
874
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200875 :return: The value of the version subfield.
876 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800877 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500878 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800879
880
881 def get_subject(self):
882 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200883 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800884
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200885 This creates a new :py:class:`X509Name`: modifying it does not affect
886 this request.
887
888 :return: The subject of this certificate signing request.
889 :rtype: :py:class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800890 """
891 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500892 name._name = _lib.X509_REQ_get_subject_name(self._req)
893 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500894 # TODO: This is untested.
895 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800896
897 # The name is owned by the X509Req structure. As long as the X509Name
898 # Python object is alive, keep the X509Req Python object alive.
899 name._owner = self
900
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800901 return name
902
903
904 def add_extensions(self, extensions):
905 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200906 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800907
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200908 :param extensions: The X.509 extensions to add.
909 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200910 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800911 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500912 stack = _lib.sk_X509_EXTENSION_new_null()
913 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500914 # TODO: This is untested.
915 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800916
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500917 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800918
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800919 for ext in extensions:
920 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800921 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800922
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800923 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500924 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800925
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500926 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800927 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500928 # TODO: This is untested.
929 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800930
931
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800932 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800933 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200934 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800935
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200936 :return: The X.509 extensions in this request.
937 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
938
939 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800940 """
941 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500942 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500943 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800944 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500945 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800946 exts.append(ext)
947 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800948
949
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800950 def sign(self, pkey, digest):
951 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700952 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800953
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200954 :param pkey: The key pair to sign with.
955 :type pkey: :py:class:`PKey`
956 :param digest: The name of the message digest to use for the signature,
957 e.g. :py:data:`b"sha1"`.
958 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200959 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800960 """
961 if pkey._only_public:
962 raise ValueError("Key has only public part")
963
964 if not pkey._initialized:
965 raise ValueError("Key is uninitialized")
966
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500967 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500968 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800969 raise ValueError("No such digest method")
970
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500971 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800972 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500973 # TODO: This is untested.
974 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800975
976
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800977 def verify(self, pkey):
978 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200979 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800980
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200981 :param key: A public key.
982 :type key: :py:class:`PKey`
983 :return: :py:data:`True` if the signature is correct.
984 :rtype: :py:class:`bool`
985 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800986 problem verifying the signature.
987 """
988 if not isinstance(pkey, PKey):
989 raise TypeError("pkey must be a PKey instance")
990
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500991 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800992 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500993 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800994
995 return result
996
997
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200998
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800999X509ReqType = X509Req
1000
1001
1002
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001003class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001004 """
1005 An X.509 certificate.
1006 """
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001007 def __init__(self):
1008 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001009 x509 = _lib.X509_new()
1010 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001011
1012
1013 def set_version(self, version):
1014 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001015 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001016
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001017 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001018 :type version: :py:class:`int`
1019
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001020 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001021 """
1022 if not isinstance(version, int):
1023 raise TypeError("version must be an integer")
1024
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001025 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001026
1027
1028 def get_version(self):
1029 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001030 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001031
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001032 :return: The version number of the certificate.
1033 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001034 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001035 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001036
1037
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001038 def get_pubkey(self):
1039 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001040 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001041
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001042 :return: The public key.
1043 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001044 """
1045 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001046 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1047 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001048 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001049 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001050 pkey._only_public = True
1051 return pkey
1052
1053
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001054 def set_pubkey(self, pkey):
1055 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001056 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001057
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001058 :param pkey: The public key.
1059 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001060
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001061 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001062 """
1063 if not isinstance(pkey, PKey):
1064 raise TypeError("pkey must be a PKey instance")
1065
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001066 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001067 if not set_result:
1068 _raise_current_error()
1069
1070
1071 def sign(self, pkey, digest):
1072 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001073 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001074
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001075 :param pkey: The key to sign with.
1076 :type pkey: :py:class:`PKey`
1077
1078 :param digest: The name of the message digest to use.
1079 :type digest: :py:class:`bytes`
1080
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001081 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001082 """
1083 if not isinstance(pkey, PKey):
1084 raise TypeError("pkey must be a PKey instance")
1085
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001086 if pkey._only_public:
1087 raise ValueError("Key only has public part")
1088
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001089 if not pkey._initialized:
1090 raise ValueError("Key is uninitialized")
1091
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001092 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001093 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001094 raise ValueError("No such digest method")
1095
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001096 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001097 if not sign_result:
1098 _raise_current_error()
1099
1100
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001101 def get_signature_algorithm(self):
1102 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001103 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001104
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001105 :return: The name of the algorithm.
1106 :rtype: :py:class:`bytes`
1107
1108 :raises ValueError: If the signature algorithm is undefined.
1109
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001110 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001111 """
1112 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001113 nid = _lib.OBJ_obj2nid(alg)
1114 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001115 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001116 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001117
1118
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001119 def digest(self, digest_name):
1120 """
1121 Return the digest of the X509 object.
1122
1123 :param digest_name: The name of the digest algorithm to use.
1124 :type digest_name: :py:class:`bytes`
1125
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001126 :return: The digest of the object, formatted as
1127 :py:const:`b":"`-delimited hex pairs.
1128 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001129 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001130 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001131 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001132 raise ValueError("No such digest method")
1133
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001134 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1135 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001136 result_length[0] = len(result_buffer)
1137
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001138 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001139 self._x509, digest, result_buffer, result_length)
1140
1141 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001142 # TODO: This is untested.
1143 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001144
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001145 return b":".join([
1146 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001147 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001148
1149
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001150 def subject_name_hash(self):
1151 """
1152 Return the hash of the X509 subject.
1153
1154 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001155 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001156 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001157 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001158
1159
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001160 def set_serial_number(self, serial):
1161 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001162 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001163
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001164 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001165 :type serial: :py:class:`int`
1166
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001167 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001168 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001169 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001170 raise TypeError("serial must be an integer")
1171
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001172 hex_serial = hex(serial)[2:]
1173 if not isinstance(hex_serial, bytes):
1174 hex_serial = hex_serial.encode('ascii')
1175
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001176 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001177
1178 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1179 # it. If bignum is still NULL after this call, then the return value is
1180 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001181 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001182
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001183 if bignum_serial[0] == _ffi.NULL:
1184 set_result = _lib.ASN1_INTEGER_set(
1185 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001186 if set_result:
1187 # TODO Not tested
1188 _raise_current_error()
1189 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001190 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1191 _lib.BN_free(bignum_serial[0])
1192 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001193 # TODO Not tested
1194 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001195 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1196 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001197 if not set_result:
1198 # TODO Not tested
1199 _raise_current_error()
1200
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001201
1202 def get_serial_number(self):
1203 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001204 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001205
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001206 :return: The serial number.
1207 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001208 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001209 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1210 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001211 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001212 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001213 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001214 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001215 serial = int(hexstring_serial, 16)
1216 return serial
1217 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001218 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001219 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001220 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001221
1222
1223 def gmtime_adj_notAfter(self, amount):
1224 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001225 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001226
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001227 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001228 :type amount: :py:class:`int`
1229
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001230 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001231 """
1232 if not isinstance(amount, int):
1233 raise TypeError("amount must be an integer")
1234
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001235 notAfter = _lib.X509_get_notAfter(self._x509)
1236 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001237
1238
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001239 def gmtime_adj_notBefore(self, amount):
1240 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001241 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001242
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001243 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001244 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001245 """
1246 if not isinstance(amount, int):
1247 raise TypeError("amount must be an integer")
1248
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001249 notBefore = _lib.X509_get_notBefore(self._x509)
1250 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001251
1252
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001253 def has_expired(self):
1254 """
1255 Check whether the certificate has expired.
1256
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001257 :return: :py:const:`True` if the certificate has expired,
1258 :py:const:`False` otherwise.
1259 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001260 """
1261 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001262 notAfter = _lib.X509_get_notAfter(self._x509)
1263 return _lib.ASN1_UTCTIME_cmp_time_t(
1264 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001265
1266
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001267 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001268 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001269
1270
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001271 def get_notBefore(self):
1272 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001273 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001274
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001275 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001276
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001277 YYYYMMDDhhmmssZ
1278 YYYYMMDDhhmmss+hhmm
1279 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001280
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001281 :return: A timestamp string, or :py:const:`None` if there is none.
1282 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001283 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001284 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001285
1286
1287 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001288 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001289
1290
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001291 def set_notBefore(self, when):
1292 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001293 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001294
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001295 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001296
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001297 YYYYMMDDhhmmssZ
1298 YYYYMMDDhhmmss+hhmm
1299 YYYYMMDDhhmmss-hhmm
1300
1301 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001302 :type when: :py:class:`bytes`
1303
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001304 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001305 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001306 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001307
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001308
1309 def get_notAfter(self):
1310 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001311 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001312
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001313 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001314
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001315 YYYYMMDDhhmmssZ
1316 YYYYMMDDhhmmss+hhmm
1317 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001318
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001319 :return: A timestamp string, or :py:const:`None` if there is none.
1320 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001321 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001322 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001323
1324
1325 def set_notAfter(self, when):
1326 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001327 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001328
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001329 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001330
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001331 YYYYMMDDhhmmssZ
1332 YYYYMMDDhhmmss+hhmm
1333 YYYYMMDDhhmmss-hhmm
1334
1335 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001336 :type when: :py:class:`bytes`
1337
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001338 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001339 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001340 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001341
1342
1343 def _get_name(self, which):
1344 name = X509Name.__new__(X509Name)
1345 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001346 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001347 # TODO: This is untested.
1348 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001349
1350 # The name is owned by the X509 structure. As long as the X509Name
1351 # Python object is alive, keep the X509 Python object alive.
1352 name._owner = self
1353
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001354 return name
1355
1356
1357 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001358 if not isinstance(name, X509Name):
1359 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001360 set_result = which(self._x509, name._name)
1361 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001362 # TODO: This is untested.
1363 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001364
1365
1366 def get_issuer(self):
1367 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001368 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001369
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001370 This creates a new :py:class:`X509Name`: modifying it does not affect
1371 this certificate.
1372
1373 :return: The issuer of this certificate.
1374 :rtype: :py:class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001375 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001376 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001377
1378
1379 def set_issuer(self, issuer):
1380 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001381 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001382
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001383 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001384 :type issuer: :py:class:`X509Name`
1385
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001386 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001387 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001388 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001389
1390
1391 def get_subject(self):
1392 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001393 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001394
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001395 This creates a new :py:class:`X509Name`: modifying it does not affect
1396 this certificate.
1397
1398 :return: The subject of this certificate.
1399 :rtype: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001400 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001401 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001402
1403
1404 def set_subject(self, subject):
1405 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001406 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001407
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001408 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001409 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001410
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001411 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001412 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001413 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001414
1415
1416 def get_extension_count(self):
1417 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001418 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001419
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001420 :return: The number of extensions.
1421 :rtype: :py:class:`int`
1422
1423 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001424 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001425 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001426
1427
1428 def add_extensions(self, extensions):
1429 """
1430 Add extensions to the certificate.
1431
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001432 :param extensions: The extensions to add.
1433 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001434 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001435 """
1436 for ext in extensions:
1437 if not isinstance(ext, X509Extension):
1438 raise ValueError("One of the elements is not an X509Extension")
1439
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001440 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001441 if not add_result:
1442 _raise_current_error()
1443
1444
1445 def get_extension(self, index):
1446 """
1447 Get a specific extension of the certificate by index.
1448
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001449 Extensions on a certificate are kept in order. The index
1450 parameter selects which extension will be returned.
1451
1452 :param int index: The index of the extension to retrieve.
1453 :return: The extension at the specified index.
1454 :rtype: :py:class:`X509Extension`
1455 :raises IndexError: If the extension index was out of bounds.
1456
1457 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001458 """
1459 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001460 ext._extension = _lib.X509_get_ext(self._x509, index)
1461 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001462 raise IndexError("extension index out of bounds")
1463
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001464 extension = _lib.X509_EXTENSION_dup(ext._extension)
1465 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001466 return ext
1467
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001468
1469
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001470X509Type = X509
1471
1472
1473
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001474class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001475 """
1476 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001477 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001478 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001479 store = _lib.X509_STORE_new()
1480 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001481
1482
1483 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001484 """
1485 Adds the certificate :py:data:`cert` to this store.
1486
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001487 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001488
1489 :param X509 cert: The certificate to add to this store.
1490 :raises TypeError: If the certificate is not an :py:class:`X509`.
1491 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001492 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001493 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001494 if not isinstance(cert, X509):
1495 raise TypeError()
1496
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001497 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001498 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001499 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001500
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001501
1502X509StoreType = X509Store
1503
1504
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001505class X509StoreContextError(Exception):
1506 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001507 An exception raised when an error occurred while verifying a certificate
1508 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001509
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001510 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001511 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001512 """
1513 def __init__(self, message, certificate):
1514 super(X509StoreContextError, self).__init__(message)
1515 self.certificate = certificate
1516
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001517
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001518class X509StoreContext(object):
1519 """
1520 An X.509 store context.
1521
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001522 An :py:class:`X509StoreContext` is used to define some of the criteria for
1523 certificate verification. The information encapsulated in this object
1524 includes, but is not limited to, a set of trusted certificates,
1525 verification parameters, and revoked certificates.
1526
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001527 .. note::
1528
1529 Currently, one can only set the trusted certificates on an
1530 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1531 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001532
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001533 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1534 instance. It is dynamically allocated and automatically garbage
1535 collected.
1536
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001537 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001538
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001539 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001540
1541 :param X509Store store: The certificates which will be trusted for the
1542 purposes of any verifications.
1543
1544 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001545 """
1546
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001547 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001548 store_ctx = _lib.X509_STORE_CTX_new()
1549 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1550 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001551 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001552 # Make the store context available for use after instantiating this
1553 # class by initializing it now. Per testing, subsequent calls to
1554 # :py:meth:`_init` have no adverse affect.
1555 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001556
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001557
1558 def _init(self):
1559 """
1560 Set up the store context for a subsequent verification operation.
1561 """
1562 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1563 if ret <= 0:
1564 _raise_current_error()
1565
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001566
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001567 def _cleanup(self):
1568 """
1569 Internally cleans up the store context.
1570
1571 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001572 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001573 """
1574 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1575
1576
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001577 def _exception_from_context(self):
1578 """
1579 Convert an OpenSSL native context error failure into a Python
1580 exception.
1581
1582 When a call to native OpenSSL X509_verify_cert fails, additonal information
1583 about the failure can be obtained from the store context.
1584 """
1585 errors = [
1586 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1587 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1588 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1589 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1590 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001591 # A context error should always be associated with a certificate, so we
1592 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001593 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001594 _cert = _lib.X509_dup(_x509)
1595 pycert = X509.__new__(X509)
1596 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001597 return X509StoreContextError(errors, pycert)
1598
1599
Stephen Holsapple46a09252015-02-12 14:45:43 -08001600 def set_store(self, store):
1601 """
1602 Set the context's trust store.
1603
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001604 .. versionadded:: 0.15
1605
Stephen Holsapple46a09252015-02-12 14:45:43 -08001606 :param X509Store store: The certificates which will be trusted for the
1607 purposes of any *future* verifications.
1608 """
1609 self._store = store
1610
1611
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001612 def verify_certificate(self):
1613 """
1614 Verify a certificate in a context.
1615
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001616 .. versionadded:: 0.15
1617
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001618 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001619
1620 :raises X509StoreContextError: If an error occured when validating a
1621 certificate in the context. Sets ``certificate`` attribute to indicate
1622 which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001623 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001624 # Always re-initialize the store context in case
1625 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001626 self._init()
1627 ret = _lib.X509_verify_cert(self._store_ctx)
1628 self._cleanup()
1629 if ret <= 0:
1630 raise self._exception_from_context()
1631
1632
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001633
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001634def load_certificate(type, buffer):
1635 """
1636 Load a certificate from a buffer
1637
1638 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001639
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001640 :param buffer: The buffer the certificate is stored in
1641 :type buffer: :py:class:`bytes`
1642
1643 :return: The X509 object
1644 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001645 if isinstance(buffer, _text_type):
1646 buffer = buffer.encode("ascii")
1647
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001648 bio = _new_mem_buf(buffer)
1649
1650 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001651 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001652 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001653 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001654 else:
1655 raise ValueError(
1656 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1657
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001658 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001659 _raise_current_error()
1660
1661 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001662 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001663 return cert
1664
1665
1666def dump_certificate(type, cert):
1667 """
1668 Dump a certificate to a buffer
1669
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001670 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1671 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001672 :param cert: The certificate to dump
1673 :return: The buffer with the dumped certificate in
1674 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001675 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001676
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001677 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001678 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001679 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001680 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001681 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001682 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001683 else:
1684 raise ValueError(
1685 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1686 "FILETYPE_TEXT")
1687
1688 return _bio_to_string(bio)
1689
1690
1691
1692def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1693 """
1694 Dump a private key to a buffer
1695
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001696 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1697 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001698 :param pkey: The PKey to dump
1699 :param cipher: (optional) if encrypted PEM format, the cipher to
1700 use
1701 :param passphrase: (optional) if encrypted PEM format, this can be either
1702 the passphrase to use, or a callback for providing the
1703 passphrase.
1704 :return: The buffer with the dumped key in
1705 :rtype: :py:data:`str`
1706 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001707 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001708
1709 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001710 if passphrase is None:
1711 raise TypeError(
1712 "if a value is given for cipher "
1713 "one must also be given for passphrase")
1714 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001715 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001716 raise ValueError("Invalid cipher name")
1717 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001718 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001719
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001720 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001721 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001722 result_code = _lib.PEM_write_bio_PrivateKey(
1723 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001724 helper.callback, helper.callback_args)
1725 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001726 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001727 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001728 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001729 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1730 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001731 # TODO RSA_free(rsa)?
1732 else:
1733 raise ValueError(
1734 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1735 "FILETYPE_TEXT")
1736
1737 if result_code == 0:
1738 _raise_current_error()
1739
1740 return _bio_to_string(bio)
1741
1742
1743
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001744def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001745 copy = _lib.X509_REVOKED_new()
1746 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001747 # TODO: This is untested.
1748 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001749
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001750 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001751 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001752 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001753
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001754 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001755 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001756 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001757
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001758 if original.extensions != _ffi.NULL:
1759 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1760 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1761 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1762 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1763 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001764 copy.extensions = extension_stack
1765
1766 copy.sequence = original.sequence
1767 return copy
1768
1769
1770
1771class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001772 """
1773 A certificate revocation.
1774 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001775 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1776 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1777 # OCSP_crl_reason_str. We use the latter, just like the command line
1778 # program.
1779 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001780 b"unspecified",
1781 b"keyCompromise",
1782 b"CACompromise",
1783 b"affiliationChanged",
1784 b"superseded",
1785 b"cessationOfOperation",
1786 b"certificateHold",
1787 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001788 ]
1789
1790 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001791 revoked = _lib.X509_REVOKED_new()
1792 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001793
1794
1795 def set_serial(self, hex_str):
1796 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001797 Set the serial number.
1798
1799 The serial number is formatted as a hexadecimal number encoded in
1800 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001801
1802 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001803 :type hex_str: :py:class:`bytes`
1804
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001805 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001806 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001807 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1808 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001809 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001810 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001811 if not bn_result:
1812 raise ValueError("bad hex string")
1813
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001814 asn1_serial = _ffi.gc(
1815 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1816 _lib.ASN1_INTEGER_free)
1817 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001818
1819
1820 def get_serial(self):
1821 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001822 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001823
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001824 The serial number is formatted as a hexadecimal number encoded in
1825 ASCII.
1826
1827 :return: The serial number.
1828 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001829 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001830 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001831
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001832 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001833 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001834 # TODO: This is untested.
1835 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001836
1837 return _bio_to_string(bio)
1838
1839
1840 def _delete_reason(self):
1841 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001842 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1843 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1844 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1845 _lib.X509_EXTENSION_free(ext)
1846 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001847 break
1848
1849
1850 def set_reason(self, reason):
1851 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001852 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001853
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001854 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001855
1856 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001857 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1858
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001859 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001860
1861 .. seealso::
1862
1863 :py:meth:`all_reasons`, which gives you a list of all supported
1864 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001865 """
1866 if reason is None:
1867 self._delete_reason()
1868 elif not isinstance(reason, bytes):
1869 raise TypeError("reason must be None or a byte string")
1870 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001871 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001872 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1873
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001874 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1875 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001876 # TODO: This is untested.
1877 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001878 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001879
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001880 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1881 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001882 # TODO: This is untested.
1883 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001884
1885 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001886 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1887 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001888
1889 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001890 # TODO: This is untested.
1891 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001892
1893
1894 def get_reason(self):
1895 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001896 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001897
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001898 :return: The reason, or :py:const:`None` if there is none.
1899 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1900
1901 .. seealso::
1902
1903 :py:meth:`all_reasons`, which gives you a list of all supported
1904 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001905 """
1906 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001907 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1908 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1909 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001910 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001911
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001912 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001913 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001914 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001915 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001916 # TODO: This is untested.
1917 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001918
1919 return _bio_to_string(bio)
1920
1921
1922 def all_reasons(self):
1923 """
1924 Return a list of all the supported reason strings.
1925
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001926 This list is a copy; modifying it does not change the supported reason
1927 strings.
1928
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001929 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001930 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001931 """
1932 return self._crl_reasons[:]
1933
1934
1935 def set_rev_date(self, when):
1936 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001937 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001938
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001939 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1940 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001941 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001942 """
1943 return _set_asn1_time(self._revoked.revocationDate, when)
1944
1945
1946 def get_rev_date(self):
1947 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001948 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001949
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001950 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1951 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001952 """
1953 return _get_asn1_time(self._revoked.revocationDate)
1954
1955
1956
1957class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001958 """
1959 A certificate revocation list.
1960 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001961 def __init__(self):
1962 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001963 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001964 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001965 crl = _lib.X509_CRL_new()
1966 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001967
1968
1969 def get_revoked(self):
1970 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001971 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001972
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001973 These revocations will be provided by value, not by reference.
1974 That means it's okay to mutate them: it won't affect this CRL.
1975
1976 :return: The revocations in this CRL.
1977 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001978 """
1979 results = []
1980 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001981 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1982 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001983 revoked_copy = _X509_REVOKED_dup(revoked)
1984 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001985 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001986 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001987 if results:
1988 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001989
1990
1991 def add_revoked(self, revoked):
1992 """
1993 Add a revoked (by value not reference) to the CRL structure
1994
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001995 This revocation will be added by value, not by reference. That
1996 means it's okay to mutate it after adding: it won't affect
1997 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001998
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001999 :param revoked: The new revocation.
2000 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002001
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002002 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002003 """
2004 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002005 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002006 # TODO: This is untested.
2007 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002008
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002009 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002010 if add_result == 0:
2011 # TODO: This is untested.
2012 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002013
2014
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002015 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002016 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002017 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002018 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002019
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002020 :param cert: The certificate used to sign the CRL.
2021 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002022
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002023 :param key: The key used to sign the CRL.
2024 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002025
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002026 :param type: The export format, either :py:data:`FILETYPE_PEM`,
2027 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002028
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002029 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04002030
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002031 :param bytes digest: The name of the message digest to use (eg
2032 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002033
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002034 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002035 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002036 if not isinstance(cert, X509):
2037 raise TypeError("cert must be an X509 instance")
2038 if not isinstance(key, PKey):
2039 raise TypeError("key must be a PKey instance")
2040 if not isinstance(type, int):
2041 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002042
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002043 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002044 _warn(
2045 "The default message digest (md5) is deprecated. "
2046 "Pass the name of a message digest explicitly.",
2047 category=DeprecationWarning,
2048 stacklevel=2,
2049 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002050 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002051
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002052 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002053 if digest_obj == _ffi.NULL:
2054 raise ValueError("No such digest method")
2055
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002056 bio = _lib.BIO_new(_lib.BIO_s_mem())
2057 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002058 # TODO: This is untested.
2059 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002060
2061 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002062 sometime = _lib.ASN1_TIME_new()
2063 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002064 # TODO: This is untested.
2065 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002066
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002067 _lib.X509_gmtime_adj(sometime, 0)
2068 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002069
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002070 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2071 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002072
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002073 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002074
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002075 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002076 if not sign_result:
2077 _raise_current_error()
2078
2079 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002080 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002081 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002082 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002083 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002084 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002085 else:
2086 raise ValueError(
2087 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
2088
2089 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002090 # TODO: This is untested.
2091 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002092
2093 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002094CRLType = CRL
2095
2096
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002097
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002098class PKCS7(object):
2099 def type_is_signed(self):
2100 """
2101 Check if this NID_pkcs7_signed object
2102
2103 :return: True if the PKCS7 is of type signed
2104 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002105 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002106 return True
2107 return False
2108
2109
2110 def type_is_enveloped(self):
2111 """
2112 Check if this NID_pkcs7_enveloped object
2113
2114 :returns: True if the PKCS7 is of type enveloped
2115 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002116 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002117 return True
2118 return False
2119
2120
2121 def type_is_signedAndEnveloped(self):
2122 """
2123 Check if this NID_pkcs7_signedAndEnveloped object
2124
2125 :returns: True if the PKCS7 is of type signedAndEnveloped
2126 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002127 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002128 return True
2129 return False
2130
2131
2132 def type_is_data(self):
2133 """
2134 Check if this NID_pkcs7_data object
2135
2136 :return: True if the PKCS7 is of type data
2137 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002138 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002139 return True
2140 return False
2141
2142
2143 def get_type_name(self):
2144 """
2145 Returns the type name of the PKCS7 structure
2146
2147 :return: A string with the typename
2148 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002149 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2150 string_type = _lib.OBJ_nid2sn(nid)
2151 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002152
2153PKCS7Type = PKCS7
2154
2155
2156
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002157class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002158 """
2159 A PKCS #12 archive.
2160 """
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002161 def __init__(self):
2162 self._pkey = None
2163 self._cert = None
2164 self._cacerts = None
2165 self._friendlyname = None
2166
2167
2168 def get_certificate(self):
2169 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002170 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002171
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002172 :return: The certificate, or :py:const:`None` if there is none.
2173 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002174 """
2175 return self._cert
2176
2177
2178 def set_certificate(self, cert):
2179 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002180 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002181
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002182 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002183 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002184
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002185 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002186 """
2187 if not isinstance(cert, X509):
2188 raise TypeError("cert must be an X509 instance")
2189 self._cert = cert
2190
2191
2192 def get_privatekey(self):
2193 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002194 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002195
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002196 :return: The private key, or :py:const:`None` if there is none.
2197 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002198 """
2199 return self._pkey
2200
2201
2202 def set_privatekey(self, pkey):
2203 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002204 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002205
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002206 :param pkey: The new private key, or :py:const:`None` to unset it.
2207 :type pkey: :py:class:`PKey` or :py:const:`None`
2208
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002209 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002210 """
2211 if not isinstance(pkey, PKey):
2212 raise TypeError("pkey must be a PKey instance")
2213 self._pkey = pkey
2214
2215
2216 def get_ca_certificates(self):
2217 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002218 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002219
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002220 :return: A tuple with the CA certificates in the chain, or
2221 :py:const:`None` if there are none.
2222 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002223 """
2224 if self._cacerts is not None:
2225 return tuple(self._cacerts)
2226
2227
2228 def set_ca_certificates(self, cacerts):
2229 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002230 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002231
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002232 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2233 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002234 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002235
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002236 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002237 """
2238 if cacerts is None:
2239 self._cacerts = None
2240 else:
2241 cacerts = list(cacerts)
2242 for cert in cacerts:
2243 if not isinstance(cert, X509):
2244 raise TypeError("iterable must only contain X509 instances")
2245 self._cacerts = cacerts
2246
2247
2248 def set_friendlyname(self, name):
2249 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002250 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002251
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002252 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002253 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002254
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002255 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002256 """
2257 if name is None:
2258 self._friendlyname = None
2259 elif not isinstance(name, bytes):
2260 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2261 self._friendlyname = name
2262
2263
2264 def get_friendlyname(self):
2265 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002266 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002267
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002268 :returns: The friendly name, or :py:const:`None` if there is none.
2269 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002270 """
2271 return self._friendlyname
2272
2273
2274 def export(self, passphrase=None, iter=2048, maciter=1):
2275 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002276 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002277
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002278 For more information, see the :c:func:`PKCS12_create` man page.
2279
2280 :param passphrase: The passphrase used to encrypt the structure. Unlike
2281 some other passphrase arguments, this *must* be a string, not a
2282 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002283 :type passphrase: :py:data:`bytes`
2284
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002285 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002286 :type iter: :py:data:`int`
2287
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002288 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002289 :type maciter: :py:data:`int`
2290
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002291 :return: The string representation of the PKCS #12 structure.
2292 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002293 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002294 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002295
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002296 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002297 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002298 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002299 cacerts = _lib.sk_X509_new_null()
2300 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002301 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002302 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002303
2304 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002305 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002306
2307 friendlyname = self._friendlyname
2308 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002309 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002310
2311 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002312 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002313 else:
2314 pkey = self._pkey._pkey
2315
2316 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002317 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002318 else:
2319 cert = self._cert._x509
2320
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002321 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002322 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002323 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2324 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002325 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002326 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002327 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002328 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002329
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002330 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002331 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002332 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002333
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002334
2335
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002336PKCS12Type = PKCS12
2337
2338
2339
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002340class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002341 """
2342 A Netscape SPKI object.
2343 """
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002344 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002345 spki = _lib.NETSCAPE_SPKI_new()
2346 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002347
2348
2349 def sign(self, pkey, digest):
2350 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002351 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002352
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002353 :param pkey: The private key to sign with.
2354 :type pkey: :py:class:`PKey`
2355
2356 :param digest: The message digest to use.
2357 :type digest: :py:class:`bytes`
2358
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002359 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002360 """
2361 if pkey._only_public:
2362 raise ValueError("Key has only public part")
2363
2364 if not pkey._initialized:
2365 raise ValueError("Key is uninitialized")
2366
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002367 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002368 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002369 raise ValueError("No such digest method")
2370
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002371 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002372 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002373 # TODO: This is untested.
2374 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002375
2376
2377 def verify(self, key):
2378 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002379 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002380
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002381 :param key: The public key that signature is supposedly from.
2382 :type pkey: :py:class:`PKey`
2383
2384 :return: :py:const:`True` if the signature is correct.
2385 :rtype: :py:class:`bool`
2386
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002387 :raises Error: If the signature is invalid, or there was a problem
2388 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002389 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002390 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002391 if answer <= 0:
2392 _raise_current_error()
2393 return True
2394
2395
2396 def b64_encode(self):
2397 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002398 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002399
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002400 :return: The base64 encoded string.
2401 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002402 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002403 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2404 result = _ffi.string(encoded)
2405 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002406 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002407
2408
2409 def get_pubkey(self):
2410 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002411 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002412
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002413 :return: The public key.
2414 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002415 """
2416 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002417 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2418 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002419 # TODO: This is untested.
2420 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002421 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002422 pkey._only_public = True
2423 return pkey
2424
2425
2426 def set_pubkey(self, pkey):
2427 """
2428 Set the public key of the certificate
2429
2430 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002431 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002432 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002433 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002434 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002435 # TODO: This is untested.
2436 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002437
2438
2439
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002440NetscapeSPKIType = NetscapeSPKI
2441
2442
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002443
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002444class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002445 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002446 if type != FILETYPE_PEM and passphrase is not None:
2447 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002448 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002449 self._more_args = more_args
2450 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002451 self._problems = []
2452
2453
2454 @property
2455 def callback(self):
2456 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002457 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002458 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002459 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002460 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002461 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002462 else:
2463 raise TypeError("Last argument must be string or callable")
2464
2465
2466 @property
2467 def callback_args(self):
2468 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002469 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002470 elif isinstance(self._passphrase, bytes):
2471 return self._passphrase
2472 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002473 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002474 else:
2475 raise TypeError("Last argument must be string or callable")
2476
2477
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002478 def raise_if_problem(self, exceptionType=Error):
2479 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002480 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002481 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002482 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002483 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002484 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002485 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002486
2487
2488 def _read_passphrase(self, buf, size, rwflag, userdata):
2489 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002490 if self._more_args:
2491 result = self._passphrase(size, rwflag, userdata)
2492 else:
2493 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002494 if not isinstance(result, bytes):
2495 raise ValueError("String expected")
2496 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002497 if self._truncate:
2498 result = result[:size]
2499 else:
2500 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002501 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002502 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002503 return len(result)
2504 except Exception as e:
2505 self._problems.append(e)
2506 return 0
2507
2508
2509
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002510def load_privatekey(type, buffer, passphrase=None):
2511 """
2512 Load a private key from a buffer
2513
2514 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2515 :param buffer: The buffer the key is stored in
2516 :param passphrase: (optional) if encrypted PEM format, this can be
2517 either the passphrase to use, or a callback for
2518 providing the passphrase.
2519
2520 :return: The PKey object
2521 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002522 if isinstance(buffer, _text_type):
2523 buffer = buffer.encode("ascii")
2524
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002525 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002526
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002527 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002528 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002529 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2530 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002531 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002532 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002533 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002534 else:
2535 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2536
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002537 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002538 _raise_current_error()
2539
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002540 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002541 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002542 return pkey
2543
2544
2545
2546def dump_certificate_request(type, req):
2547 """
2548 Dump a certificate request to a buffer
2549
2550 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2551 :param req: The certificate request to dump
2552 :return: The buffer with the dumped certificate request in
2553 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002554 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002555
2556 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002557 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002558 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002559 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002560 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002561 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002562 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002563 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002564
2565 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002566 # TODO: This is untested.
2567 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002568
2569 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002570
2571
2572
2573def load_certificate_request(type, buffer):
2574 """
2575 Load a certificate request from a buffer
2576
2577 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2578 :param buffer: The buffer the certificate request is stored in
2579 :return: The X509Req object
2580 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002581 if isinstance(buffer, _text_type):
2582 buffer = buffer.encode("ascii")
2583
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002584 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002585
2586 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002587 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002588 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002589 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002590 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002591 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002592
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002593 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002594 # TODO: This is untested.
2595 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002596
2597 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002598 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002599 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002600
2601
2602
2603def sign(pkey, data, digest):
2604 """
2605 Sign data with a digest
2606
2607 :param pkey: Pkey to sign with
2608 :param data: data to be signed
2609 :param digest: message digest to use
2610 :return: signature
2611 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002612 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002613
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002614 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002615 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002616 raise ValueError("No such digest method")
2617
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002618 md_ctx = _ffi.new("EVP_MD_CTX*")
2619 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002620
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002621 _lib.EVP_SignInit(md_ctx, digest_obj)
2622 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002623
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002624 signature_buffer = _ffi.new("unsigned char[]", 512)
2625 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002626 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002627 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002628 md_ctx, signature_buffer, signature_length, pkey._pkey)
2629
2630 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002631 # TODO: This is untested.
2632 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002633
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002634 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002635
2636
2637
2638def verify(cert, signature, data, digest):
2639 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002640 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002641
2642 :param cert: signing certificate (X509 object)
2643 :param signature: signature returned by sign function
2644 :param data: data to be verified
2645 :param digest: message digest to use
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002646 :return: :py:const:`None` if the signature is correct, raise exception otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002647 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002648 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002649
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002650 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002651 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002652 raise ValueError("No such digest method")
2653
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002654 pkey = _lib.X509_get_pubkey(cert._x509)
2655 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002656 # TODO: This is untested.
2657 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002658 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002659
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002660 md_ctx = _ffi.new("EVP_MD_CTX*")
2661 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002662
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002663 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2664 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2665 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002666
2667 if verify_result != 1:
2668 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002669
2670
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002671def load_crl(type, buffer):
2672 """
2673 Load a certificate revocation list from a buffer
2674
2675 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2676 :param buffer: The buffer the CRL is stored in
2677
2678 :return: The PKey object
2679 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002680 if isinstance(buffer, _text_type):
2681 buffer = buffer.encode("ascii")
2682
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002683 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002684
2685 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002686 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002687 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002688 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002689 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002690 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2691
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002692 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002693 _raise_current_error()
2694
2695 result = CRL.__new__(CRL)
2696 result._crl = crl
2697 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002698
2699
2700
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002701def load_pkcs7_data(type, buffer):
2702 """
2703 Load pkcs7 data from a buffer
2704
2705 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2706 :param buffer: The buffer with the pkcs7 data.
2707 :return: The PKCS7 object
2708 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002709 if isinstance(buffer, _text_type):
2710 buffer = buffer.encode("ascii")
2711
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002712 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002713
2714 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002715 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002716 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002717 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002718 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002719 # TODO: This is untested.
2720 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002721 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2722
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002723 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002724 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002725
2726 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002727 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002728 return pypkcs7
2729
2730
2731
Stephen Holsapple38482622014-04-05 20:29:34 -07002732def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002733 """
2734 Load a PKCS12 object from a buffer
2735
2736 :param buffer: The buffer the certificate is stored in
2737 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2738 :returns: The PKCS12 object
2739 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002740 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002741
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002742 if isinstance(buffer, _text_type):
2743 buffer = buffer.encode("ascii")
2744
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002745 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002746
Stephen Holsapple38482622014-04-05 20:29:34 -07002747 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2748 # password based encryption no password and a zero length password are two
2749 # different things, but OpenSSL implementation will try both to figure out
2750 # which one works.
2751 if not passphrase:
2752 passphrase = _ffi.NULL
2753
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002754 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2755 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002756 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002757 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002758
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002759 pkey = _ffi.new("EVP_PKEY**")
2760 cert = _ffi.new("X509**")
2761 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002762
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002763 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002764 if not parse_result:
2765 _raise_current_error()
2766
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002767 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002768
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002769 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2770 # queue for no particular reason. This error isn't interesting to anyone
2771 # outside this function. It's not even interesting to us. Get rid of it.
2772 try:
2773 _raise_current_error()
2774 except Error:
2775 pass
2776
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002777 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002778 pykey = None
2779 else:
2780 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002781 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002782
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002783 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002784 pycert = None
2785 friendlyname = None
2786 else:
2787 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002788 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002789
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002790 friendlyname_length = _ffi.new("int*")
2791 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2792 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2793 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002794 friendlyname = None
2795
2796 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002797 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002798 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002799 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002800 pycacerts.append(pycacert)
2801 if not pycacerts:
2802 pycacerts = None
2803
2804 pkcs12 = PKCS12.__new__(PKCS12)
2805 pkcs12._pkey = pykey
2806 pkcs12._cert = pycert
2807 pkcs12._cacerts = pycacerts
2808 pkcs12._friendlyname = friendlyname
2809 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002810
2811
Alex Gaynorb9521c82015-09-04 09:18:59 -04002812_binding.init_static_locks()
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002813
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002814# There are no direct unit tests for this initialization. It is tested
2815# indirectly since it is necessary for functions like dump_privatekey when
2816# using encryption.
2817#
2818# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2819# and some other similar tests may fail without this (though they may not if
2820# the Python runtime has already done some initialization of the underlying
2821# OpenSSL library (and is linked against the same one that cryptography is
2822# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002823_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002824
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002825# This is similar but exercised mainly by exception_from_error_queue. It calls
2826# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2827_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002828
2829
2830
2831# Set the default string mask to match OpenSSL upstream (since 2005) and
2832# RFC5280 recommendations.
2833_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')