blob: 845c0c12a69e9e41d60a59a9b3fef3698b1d533d [file] [log] [blame]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001from time import time
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05003from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05004from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04005from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05006
7from six import (
8 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -04009 text_type as _text_type,
10 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080011
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050012from OpenSSL._util import (
13 ffi as _ffi,
14 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050015 exception_from_error_queue as _exception_from_error_queue,
16 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040017 native as _native,
18 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040019 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040020)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080021
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050022FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
23FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080024
25# TODO This was an API mistake. OpenSSL has no such constant.
26FILETYPE_TEXT = 2 ** 16 - 1
27
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050028TYPE_RSA = _lib.EVP_PKEY_RSA
29TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080030
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080031
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050032class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050033 """
34 An error occurred in an `OpenSSL.crypto` API.
35 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050036
37
38_raise_current_error = partial(_exception_from_error_queue, Error)
39
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070040
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050041def _untested_error(where):
42 """
43 An OpenSSL API failed somehow. Additionally, the failure which was
44 encountered isn't one that's exercised by the test suite so future behavior
45 of pyOpenSSL is now somewhat less predictable.
46 """
47 raise RuntimeError("Unknown %s failure" % (where,))
48
49
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050050def _new_mem_buf(buffer=None):
51 """
52 Allocate a new OpenSSL memory BIO.
53
54 Arrange for the garbage collector to clean it up automatically.
55
56 :param buffer: None or some bytes to use to put into the BIO so that they
57 can be read out.
58 """
59 if buffer is None:
60 bio = _lib.BIO_new(_lib.BIO_s_mem())
61 free = _lib.BIO_free
62 else:
63 data = _ffi.new("char[]", buffer)
64 bio = _lib.BIO_new_mem_buf(data, len(buffer))
65 # Keep the memory alive as long as the bio is alive!
66 def free(bio, ref=data):
67 return _lib.BIO_free(bio)
68
69 if bio == _ffi.NULL:
70 # TODO: This is untested.
71 _raise_current_error()
72
73 bio = _ffi.gc(bio, free)
74 return bio
75
76
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080077def _bio_to_string(bio):
78 """
79 Copy the contents of an OpenSSL BIO object into a Python byte string.
80 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050081 result_buffer = _ffi.new('char**')
82 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
83 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080084
85
Jean-Paul Calderone57122982013-02-21 08:47:05 -080086def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050087 """
88 The the time value of an ASN1 time object.
89
90 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
91 castable to that type) which will have its value set.
92 @param when: A string representation of the desired time value.
93
94 @raise TypeError: If C{when} is not a L{bytes} string.
95 @raise ValueError: If C{when} does not represent a time in the required
96 format.
97 @raise RuntimeError: If the time value cannot be set for some other
98 (unspecified) reason.
99 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800100 if not isinstance(when, bytes):
101 raise TypeError("when must be a byte string")
102
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500103 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
104 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800105 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500106 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
107 _lib.ASN1_STRING_set(dummy, when, len(when))
108 check_result = _lib.ASN1_GENERALIZEDTIME_check(
109 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800110 if not check_result:
111 raise ValueError("Invalid string")
112 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500113 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800114
115
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800116def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500117 """
118 Retrieve the time value of an ASN1 time object.
119
120 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
121 that type) from which the time value will be retrieved.
122
123 @return: The time value from C{timestamp} as a L{bytes} string in a certain
124 format. Or C{None} if the object contains no time value.
125 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500126 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
127 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800128 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500129 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
130 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800131 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500132 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
133 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
134 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500135 # This may happen:
136 # - if timestamp was not an ASN1_TIME
137 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
138 # - if a copy of the time data from timestamp cannot be made for
139 # the newly allocated ASN1_GENERALIZEDTIME
140 #
141 # These are difficult to test. cffi enforces the ASN1_TIME type.
142 # Memory allocation failures are a pain to trigger
143 # deterministically.
144 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800145 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500146 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800147 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500148 string_data = _lib.ASN1_STRING_data(string_timestamp)
149 string_result = _ffi.string(string_data)
150 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800151 return string_result
152
153
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800154class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200155 """
156 A class representing an DSA or RSA public key or key pair.
157 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800158 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800159 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800160
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800161 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500162 pkey = _lib.EVP_PKEY_new()
163 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800164 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800165
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800166 def generate_key(self, type, bits):
167 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700168 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800169
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200170 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800171
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200172 :param type: The key type.
173 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
174 :param bits: The number of bits.
175 :type bits: :py:data:`int` ``>= 0``
176 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
177 of the appropriate type.
178 :raises ValueError: If the number of bits isn't an integer of
179 the appropriate size.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200180 :return: :py:const:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800181 """
182 if not isinstance(type, int):
183 raise TypeError("type must be an integer")
184
185 if not isinstance(bits, int):
186 raise TypeError("bits must be an integer")
187
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800188 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500189 exponent = _lib.BN_new()
190 exponent = _ffi.gc(exponent, _lib.BN_free)
191 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800192
193 if type == TYPE_RSA:
194 if bits <= 0:
195 raise ValueError("Invalid number of bits")
196
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500197 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800198
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500199 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500200 if result == 0:
201 # TODO: The test for this case is commented out. Different
202 # builds of OpenSSL appear to have different failure modes that
203 # make it hard to test. Visual inspection of the OpenSSL
204 # source reveals that a return value of 0 signals an error.
205 # Manual testing on a particular build of OpenSSL suggests that
206 # this is probably the appropriate way to handle those errors.
207 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800208
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500209 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800210 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500211 # TODO: It appears as though this can fail if an engine is in
212 # use which does not support RSA.
213 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800214
215 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500216 dsa = _lib.DSA_generate_parameters(
217 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
218 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500219 # TODO: This is untested.
220 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500221 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500222 # TODO: This is untested.
223 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500224 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500225 # TODO: This is untested.
226 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800227 else:
228 raise Error("No such key type")
229
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800230 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800231
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800232 def check(self):
233 """
234 Check the consistency of an RSA private key.
235
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200236 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
237
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800238 :return: True if key is consistent.
239 :raise Error: if the key is inconsistent.
240 :raise TypeError: if the key is of a type which cannot be checked.
241 Only RSA keys can currently be checked.
242 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800243 if self._only_public:
244 raise TypeError("public key only")
245
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500246 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800247 raise TypeError("key type unsupported")
248
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500249 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
250 rsa = _ffi.gc(rsa, _lib.RSA_free)
251 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800252 if result:
253 return True
254 _raise_current_error()
255
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800256 def type(self):
257 """
258 Returns the type of the key
259
260 :return: The type of the key.
261 """
262 return self._pkey.type
263
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800264 def bits(self):
265 """
266 Returns the number of bits of the key
267
268 :return: The number of bits of the key.
269 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500270 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800271PKeyType = PKey
272
273
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400274class _EllipticCurve(object):
275 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400276 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400277
278 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
279 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
280 instances each of which represents one curve supported by the system.
281 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400282 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400283 _curves = None
284
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400285 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400286 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400287 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400288 """
289 Implement cooperation with the right-hand side argument of ``!=``.
290
291 Python 3 seems to have dropped this cooperation in this very narrow
292 circumstance.
293 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400294 if isinstance(other, _EllipticCurve):
295 return super(_EllipticCurve, self).__ne__(other)
296 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400297
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400298 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400299 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400300 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400301 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400302
303 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400304
305 :return: A :py:type:`set` of ``cls`` instances giving the names of the
306 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400307 """
308 if lib.Cryptography_HAS_EC:
309 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
310 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
311 # The return value on this call should be num_curves again. We could
312 # check it to make sure but if it *isn't* then.. what could we do?
313 # Abort the whole process, I suppose...? -exarkun
314 lib.EC_get_builtin_curves(builtin_curves, num_curves)
315 return set(
316 cls.from_nid(lib, c.nid)
317 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400318 return set()
319
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400320 @classmethod
321 def _get_elliptic_curves(cls, lib):
322 """
323 Get, cache, and return the curves supported by OpenSSL.
324
325 :param lib: The OpenSSL library binding object.
326
327 :return: A :py:type:`set` of ``cls`` instances giving the names of the
328 elliptic curves the underlying library supports.
329 """
330 if cls._curves is None:
331 cls._curves = cls._load_elliptic_curves(lib)
332 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400333
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400334 @classmethod
335 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400336 """
337 Instantiate a new :py:class:`_EllipticCurve` associated with the given
338 OpenSSL NID.
339
340 :param lib: The OpenSSL library binding object.
341
342 :param nid: The OpenSSL NID the resulting curve object will represent.
343 This must be a curve NID (and not, for example, a hash NID) or
344 subsequent operations will fail in unpredictable ways.
345 :type nid: :py:class:`int`
346
347 :return: The curve object.
348 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400349 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
350
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400351 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400352 """
353 :param _lib: The :py:mod:`cryptography` binding instance used to
354 interface with OpenSSL.
355
356 :param _nid: The OpenSSL NID identifying the curve this object
357 represents.
358 :type _nid: :py:class:`int`
359
360 :param name: The OpenSSL short name identifying the curve this object
361 represents.
362 :type name: :py:class:`unicode`
363 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400364 self._lib = lib
365 self._nid = nid
366 self.name = name
367
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400368 def __repr__(self):
369 return "<Curve %r>" % (self.name,)
370
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400371 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400372 """
373 Create a new OpenSSL EC_KEY structure initialized to use this curve.
374
375 The structure is automatically garbage collected when the Python object
376 is garbage collected.
377 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400378 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
379 return _ffi.gc(key, _lib.EC_KEY_free)
380
381
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400382def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400383 """
384 Return a set of objects representing the elliptic curves supported in the
385 OpenSSL build in use.
386
387 The curve objects have a :py:class:`unicode` ``name`` attribute by which
388 they identify themselves.
389
390 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400391 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
392 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400393 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400394 return _EllipticCurve._get_elliptic_curves(_lib)
395
396
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400397def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400398 """
399 Return a single curve object selected by name.
400
401 See :py:func:`get_elliptic_curves` for information about curve objects.
402
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400403 :param name: The OpenSSL short name identifying the curve object to
404 retrieve.
405 :type name: :py:class:`unicode`
406
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400407 If the named curve is not supported then :py:class:`ValueError` is raised.
408 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400409 for curve in get_elliptic_curves():
410 if curve.name == name:
411 return curve
412 raise ValueError("unknown curve name", name)
413
414
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800415class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200416 """
417 An X.509 Distinguished Name.
418
419 :ivar countryName: The country of the entity.
420 :ivar C: Alias for :py:attr:`countryName`.
421
422 :ivar stateOrProvinceName: The state or province of the entity.
423 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
424
425 :ivar localityName: The locality of the entity.
426 :ivar L: Alias for :py:attr:`localityName`.
427
428 :ivar organizationName: The organization name of the entity.
429 :ivar O: Alias for :py:attr:`organizationName`.
430
431 :ivar organizationalUnitName: The organizational unit of the entity.
432 :ivar OU: Alias for :py:attr:`organizationalUnitName`
433
434 :ivar commonName: The common name of the entity.
435 :ivar CN: Alias for :py:attr:`commonName`.
436
437 :ivar emailAddress: The e-mail address of the entity.
438 """
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800439 def __init__(self, name):
440 """
441 Create a new X509Name, copying the given X509Name instance.
442
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200443 :param name: The name to copy.
444 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800445 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500446 name = _lib.X509_NAME_dup(name._name)
447 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800448
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800449 def __setattr__(self, name, value):
450 if name.startswith('_'):
451 return super(X509Name, self).__setattr__(name, value)
452
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800453 # Note: we really do not want str subclasses here, so we do not use
454 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800455 if type(name) is not str:
456 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400457 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800458
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500459 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500460 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800461 try:
462 _raise_current_error()
463 except Error:
464 pass
465 raise AttributeError("No such attribute")
466
467 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500468 for i in range(_lib.X509_NAME_entry_count(self._name)):
469 ent = _lib.X509_NAME_get_entry(self._name, i)
470 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
471 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800472 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500473 ent = _lib.X509_NAME_delete_entry(self._name, i)
474 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800475 break
476
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500477 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800478 value = value.encode('utf-8')
479
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500480 add_result = _lib.X509_NAME_add_entry_by_NID(
481 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800482 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500483 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800484
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800485 def __getattr__(self, name):
486 """
487 Find attribute. An X509Name object has the following attributes:
488 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
489 organization (alias O), organizationalUnit (alias OU), commonName (alias
490 CN) and more...
491 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500492 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500493 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800494 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
495 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
496 # push something onto the error queue. If we don't clean that up
497 # now, someone else will bump into it later and be quite confused.
498 # See lp#314814.
499 try:
500 _raise_current_error()
501 except Error:
502 pass
503 return super(X509Name, self).__getattr__(name)
504
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500505 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800506 if entry_index == -1:
507 return None
508
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500509 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
510 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800511
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500512 result_buffer = _ffi.new("unsigned char**")
513 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800514 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500515 # TODO: This is untested.
516 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800517
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700518 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500519 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700520 finally:
521 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500522 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800523 return result
524
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500525 def _cmp(op):
526 def f(self, other):
527 if not isinstance(other, X509Name):
528 return NotImplemented
529 result = _lib.X509_NAME_cmp(self._name, other._name)
530 return op(result, 0)
531 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800532
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500533 __eq__ = _cmp(__eq__)
534 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800535
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500536 __lt__ = _cmp(__lt__)
537 __le__ = _cmp(__le__)
538
539 __gt__ = _cmp(__gt__)
540 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800541
542 def __repr__(self):
543 """
544 String representation of an X509Name
545 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400546 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500547 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800548 self._name, result_buffer, len(result_buffer))
549
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500550 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500551 # TODO: This is untested.
552 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800553
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500554 return "<X509Name object '%s'>" % (
555 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800556
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800557 def hash(self):
558 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200559 Return an integer representation of the first four bytes of the
560 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800561
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200562 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
563
564 :return: The (integer) hash of this name.
565 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800566 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500567 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800568
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800569 def der(self):
570 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200571 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800572
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200573 :return: The DER encoded form of this name.
574 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800575 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500576 result_buffer = _ffi.new('unsigned char**')
577 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800578 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500579 # TODO: This is untested.
580 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800581
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500582 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
583 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800584 return string_result
585
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800586 def get_components(self):
587 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200588 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800589
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200590 :return: The components of this name.
591 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800592 """
593 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500594 for i in range(_lib.X509_NAME_entry_count(self._name)):
595 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800596
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500597 fname = _lib.X509_NAME_ENTRY_get_object(ent)
598 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800599
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500600 nid = _lib.OBJ_obj2nid(fname)
601 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800602
603 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400604 _ffi.string(name),
605 _ffi.string(
606 _lib.ASN1_STRING_data(fval),
607 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800608
609 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200610
611
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800612X509NameType = X509Name
613
614
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800615class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200616 """
617 An X.509 v3 certificate extension.
618 """
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800619 def __init__(self, type_name, critical, value, subject=None, issuer=None):
620 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200621 Initializes an X509 extension.
622
623 :param typename: The name of the type of extension to create. See
624 http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800625 :type typename: :py:data:`str`
626
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200627 :param bool critical: A flag indicating whether this is a critical extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800628
629 :param value: The value of the extension.
630 :type value: :py:data:`str`
631
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200632 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800633 :type subject: :py:class:`X509`
634
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200635 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800636 :type issuer: :py:class:`X509`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800637 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500638 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800639
640 # A context is necessary for any extension which uses the r2i conversion
641 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
642 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500643 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800644
645 # We have no configuration database - but perhaps we should (some
646 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500647 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800648
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800649 # Initialize the subject and issuer, if appropriate. ctx is a local,
650 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400651 # any references, so no need to mess with reference counts or
652 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800653 if issuer is not None:
654 if not isinstance(issuer, X509):
655 raise TypeError("issuer must be an X509 instance")
656 ctx.issuer_cert = issuer._x509
657 if subject is not None:
658 if not isinstance(subject, X509):
659 raise TypeError("subject must be an X509 instance")
660 ctx.subject_cert = subject._x509
661
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800662 if critical:
663 # There are other OpenSSL APIs which would let us pass in critical
664 # separately, but they're harder to use, and since value is already
665 # a pile of crappy junk smuggling a ton of utterly important
666 # structured data, what's the point of trying to avoid nasty stuff
667 # with strings? (However, X509V3_EXT_i2d in particular seems like it
668 # would be a better API to invoke. I do not know where to get the
669 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500670 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800671
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500672 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
673 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800674 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500675 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800676
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400677 @property
678 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500679 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400680
681 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500682 _lib.GEN_EMAIL: "email",
683 _lib.GEN_DNS: "DNS",
684 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400685 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400686
687 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500688 method = _lib.X509V3_EXT_get(self._extension)
689 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500690 # TODO: This is untested.
691 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400692 payload = self._extension.value.data
693 length = self._extension.value.length
694
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500695 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400696 payloadptr[0] = payload
697
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500698 if method.it != _ffi.NULL:
699 ptr = _lib.ASN1_ITEM_ptr(method.it)
700 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
701 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400702 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500703 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400704 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500705 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400706
Paul Kehrerb7d79502015-05-04 07:43:51 -0500707 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400708 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500709 for i in range(_lib.sk_GENERAL_NAME_num(names)):
710 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400711 try:
712 label = self._prefixes[name.type]
713 except KeyError:
714 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500715 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500716 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400717 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500718 value = _native(
719 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
720 parts.append(label + ":" + value)
721 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400722
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800723 def __str__(self):
724 """
725 :return: a nice text representation of the extension
726 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500727 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400728 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800729
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400730 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500731 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800732 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500733 # TODO: This is untested.
734 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800735
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500736 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800737
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800738 def get_critical(self):
739 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200740 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800741
742 :return: The critical field.
743 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500744 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800745
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800746 def get_short_name(self):
747 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200748 Returns the short type name of this X.509 extension.
749
750 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800751
752 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200753 :rtype: :py:data:`bytes`
754
755 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800756 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500757 obj = _lib.X509_EXTENSION_get_object(self._extension)
758 nid = _lib.OBJ_obj2nid(obj)
759 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800760
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800761 def get_data(self):
762 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200763 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800764
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200765 :return: The ASN.1 encoded data of this X509 extension.
766 :rtype: :py:data:`bytes`
767
768 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800769 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500770 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
771 string_result = _ffi.cast('ASN1_STRING*', octet_result)
772 char_result = _lib.ASN1_STRING_data(string_result)
773 result_length = _lib.ASN1_STRING_length(string_result)
774 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800775
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200776
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800777X509ExtensionType = X509Extension
778
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800779
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800780class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200781 """
782 An X.509 certificate signing requests.
783 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400784
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800785 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500786 req = _lib.X509_REQ_new()
787 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800788
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800789 def set_pubkey(self, pkey):
790 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200791 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800792
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200793 :param pkey: The public key to use.
794 :type pkey: :py:class:`PKey`
795
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200796 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800797 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500798 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800799 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500800 # TODO: This is untested.
801 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800802
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800803 def get_pubkey(self):
804 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200805 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800806
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200807 :return: The public key.
808 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800809 """
810 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500811 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
812 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500813 # TODO: This is untested.
814 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500815 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800816 pkey._only_public = True
817 return pkey
818
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800819 def set_version(self, version):
820 """
821 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
822 request.
823
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200824 :param int version: The version number.
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200825 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800826 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500827 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800828 if not set_result:
829 _raise_current_error()
830
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800831 def get_version(self):
832 """
833 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
834 request.
835
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200836 :return: The value of the version subfield.
837 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800838 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500839 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800840
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800841 def get_subject(self):
842 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200843 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800844
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200845 This creates a new :py:class:`X509Name`: modifying it does not affect
846 this request.
847
848 :return: The subject of this certificate signing request.
849 :rtype: :py:class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850 """
851 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500852 name._name = _lib.X509_REQ_get_subject_name(self._req)
853 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500854 # TODO: This is untested.
855 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800856
857 # The name is owned by the X509Req structure. As long as the X509Name
858 # Python object is alive, keep the X509Req Python object alive.
859 name._owner = self
860
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800861 return name
862
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800863 def add_extensions(self, extensions):
864 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200865 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800866
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200867 :param extensions: The X.509 extensions to add.
868 :type extensions: iterable of :py:class:`X509Extension`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200869 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800870 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500871 stack = _lib.sk_X509_EXTENSION_new_null()
872 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500873 # TODO: This is untested.
874 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800875
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500876 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800877
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800878 for ext in extensions:
879 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800880 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800881
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800882 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500883 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800884
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500885 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800886 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500887 # TODO: This is untested.
888 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800890 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800891 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200892 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800893
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200894 :return: The X.509 extensions in this request.
895 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
896
897 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800898 """
899 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500900 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500901 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800902 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500903 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800904 exts.append(ext)
905 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800906
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800907 def sign(self, pkey, digest):
908 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700909 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800910
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200911 :param pkey: The key pair to sign with.
912 :type pkey: :py:class:`PKey`
913 :param digest: The name of the message digest to use for the signature,
914 e.g. :py:data:`b"sha1"`.
915 :type digest: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200916 :return: :py:const:`None`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800917 """
918 if pkey._only_public:
919 raise ValueError("Key has only public part")
920
921 if not pkey._initialized:
922 raise ValueError("Key is uninitialized")
923
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500924 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500925 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800926 raise ValueError("No such digest method")
927
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500928 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800929 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500930 # TODO: This is untested.
931 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800932
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800933 def verify(self, pkey):
934 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200935 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800936
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200937 :param key: A public key.
938 :type key: :py:class:`PKey`
939 :return: :py:data:`True` if the signature is correct.
940 :rtype: :py:class:`bool`
941 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800942 problem verifying the signature.
943 """
944 if not isinstance(pkey, PKey):
945 raise TypeError("pkey must be a PKey instance")
946
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500947 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800948 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500949 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800950
951 return result
952
953
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800954X509ReqType = X509Req
955
956
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800957class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200958 """
959 An X.509 certificate.
960 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400961
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800962 def __init__(self):
963 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500964 x509 = _lib.X509_new()
965 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800966
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800967 def set_version(self, version):
968 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200969 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800970
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200971 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800972 :type version: :py:class:`int`
973
Laurens Van Houtvena7904582014-06-19 12:33:04 +0200974 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800975 """
976 if not isinstance(version, int):
977 raise TypeError("version must be an integer")
978
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500979 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800980
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800981 def get_version(self):
982 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200983 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800984
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200985 :return: The version number of the certificate.
986 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800987 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500988 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800989
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800990 def get_pubkey(self):
991 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200992 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800993
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200994 :return: The public key.
995 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800996 """
997 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500998 pkey._pkey = _lib.X509_get_pubkey(self._x509)
999 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001000 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001001 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001002 pkey._only_public = True
1003 return pkey
1004
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001005 def set_pubkey(self, pkey):
1006 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001007 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001008
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001009 :param pkey: The public key.
1010 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001011
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001012 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001013 """
1014 if not isinstance(pkey, PKey):
1015 raise TypeError("pkey must be a PKey instance")
1016
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001017 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001018 if not set_result:
1019 _raise_current_error()
1020
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001021 def sign(self, pkey, digest):
1022 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001023 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001024
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001025 :param pkey: The key to sign with.
1026 :type pkey: :py:class:`PKey`
1027
1028 :param digest: The name of the message digest to use.
1029 :type digest: :py:class:`bytes`
1030
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001031 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001032 """
1033 if not isinstance(pkey, PKey):
1034 raise TypeError("pkey must be a PKey instance")
1035
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001036 if pkey._only_public:
1037 raise ValueError("Key only has public part")
1038
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001039 if not pkey._initialized:
1040 raise ValueError("Key is uninitialized")
1041
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001042 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001043 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001044 raise ValueError("No such digest method")
1045
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001046 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001047 if not sign_result:
1048 _raise_current_error()
1049
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001050 def get_signature_algorithm(self):
1051 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001052 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001053
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001054 :return: The name of the algorithm.
1055 :rtype: :py:class:`bytes`
1056
1057 :raises ValueError: If the signature algorithm is undefined.
1058
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001059 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001060 """
1061 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001062 nid = _lib.OBJ_obj2nid(alg)
1063 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001064 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001065 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001066
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001067 def digest(self, digest_name):
1068 """
1069 Return the digest of the X509 object.
1070
1071 :param digest_name: The name of the digest algorithm to use.
1072 :type digest_name: :py:class:`bytes`
1073
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001074 :return: The digest of the object, formatted as
1075 :py:const:`b":"`-delimited hex pairs.
1076 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001077 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001078 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001079 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001080 raise ValueError("No such digest method")
1081
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001082 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1083 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001084 result_length[0] = len(result_buffer)
1085
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001086 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001087 self._x509, digest, result_buffer, result_length)
1088
1089 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001090 # TODO: This is untested.
1091 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001092
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001093 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001094 b16encode(ch).upper() for ch
1095 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001096
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001097 def subject_name_hash(self):
1098 """
1099 Return the hash of the X509 subject.
1100
1101 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001102 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001103 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001104 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001105
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001106 def set_serial_number(self, serial):
1107 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001108 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001109
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001110 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001111 :type serial: :py:class:`int`
1112
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001113 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001114 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001115 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001116 raise TypeError("serial must be an integer")
1117
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001118 hex_serial = hex(serial)[2:]
1119 if not isinstance(hex_serial, bytes):
1120 hex_serial = hex_serial.encode('ascii')
1121
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001122 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001123
1124 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1125 # it. If bignum is still NULL after this call, then the return value is
1126 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001127 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001128
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001129 if bignum_serial[0] == _ffi.NULL:
1130 set_result = _lib.ASN1_INTEGER_set(
1131 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001132 if set_result:
1133 # TODO Not tested
1134 _raise_current_error()
1135 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001136 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1137 _lib.BN_free(bignum_serial[0])
1138 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001139 # TODO Not tested
1140 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001141 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1142 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001143 if not set_result:
1144 # TODO Not tested
1145 _raise_current_error()
1146
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001147 def get_serial_number(self):
1148 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001149 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001150
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001151 :return: The serial number.
1152 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001153 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001154 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1155 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001156 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001157 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001158 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001159 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001160 serial = int(hexstring_serial, 16)
1161 return serial
1162 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001163 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001164 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001165 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001166
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001167 def gmtime_adj_notAfter(self, amount):
1168 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001169 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001170
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001171 :param amount: The number of seconds by which to adjust the timestamp.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001172 :type amount: :py:class:`int`
1173
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001174 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001175 """
1176 if not isinstance(amount, int):
1177 raise TypeError("amount must be an integer")
1178
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001179 notAfter = _lib.X509_get_notAfter(self._x509)
1180 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001181
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001182 def gmtime_adj_notBefore(self, amount):
1183 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001184 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001185
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001186 :param amount: The number of seconds by which to adjust the timestamp.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001187 :return: :py:const:`None`
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001188 """
1189 if not isinstance(amount, int):
1190 raise TypeError("amount must be an integer")
1191
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001192 notBefore = _lib.X509_get_notBefore(self._x509)
1193 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001194
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001195 def has_expired(self):
1196 """
1197 Check whether the certificate has expired.
1198
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001199 :return: :py:const:`True` if the certificate has expired,
1200 :py:const:`False` otherwise.
1201 :rtype: :py:class:`bool`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001202 """
1203 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001204 notAfter = _lib.X509_get_notAfter(self._x509)
1205 return _lib.ASN1_UTCTIME_cmp_time_t(
1206 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001207
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001208 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001209 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001210
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001211 def get_notBefore(self):
1212 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001213 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001214
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001215 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001216
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001217 YYYYMMDDhhmmssZ
1218 YYYYMMDDhhmmss+hhmm
1219 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001220
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001221 :return: A timestamp string, or :py:const:`None` if there is none.
1222 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001223 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001224 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001225
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001226 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001227 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001228
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001229 def set_notBefore(self, when):
1230 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001231 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001232
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001233 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001234
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001235 YYYYMMDDhhmmssZ
1236 YYYYMMDDhhmmss+hhmm
1237 YYYYMMDDhhmmss-hhmm
1238
1239 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001240 :type when: :py:class:`bytes`
1241
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001242 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001243 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001244 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001245
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001246 def get_notAfter(self):
1247 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001248 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001249
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001250 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001251
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001252 YYYYMMDDhhmmssZ
1253 YYYYMMDDhhmmss+hhmm
1254 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001255
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001256 :return: A timestamp string, or :py:const:`None` if there is none.
1257 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001258 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001259 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001260
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001261 def set_notAfter(self, when):
1262 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001263 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001264
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001265 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001266
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001267 YYYYMMDDhhmmssZ
1268 YYYYMMDDhhmmss+hhmm
1269 YYYYMMDDhhmmss-hhmm
1270
1271 :param when: A timestamp string.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001272 :type when: :py:class:`bytes`
1273
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001274 :return: :py:const:`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001275 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001276 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001277
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001278 def _get_name(self, which):
1279 name = X509Name.__new__(X509Name)
1280 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001281 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001282 # TODO: This is untested.
1283 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001284
1285 # The name is owned by the X509 structure. As long as the X509Name
1286 # Python object is alive, keep the X509 Python object alive.
1287 name._owner = self
1288
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001289 return name
1290
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001291 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001292 if not isinstance(name, X509Name):
1293 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001294 set_result = which(self._x509, name._name)
1295 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001296 # TODO: This is untested.
1297 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001298
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001299 def get_issuer(self):
1300 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001301 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001302
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001303 This creates a new :py:class:`X509Name`: modifying it does not affect
1304 this certificate.
1305
1306 :return: The issuer of this certificate.
1307 :rtype: :py:class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001308 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001309 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001310
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001311 def set_issuer(self, issuer):
1312 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001313 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001314
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001315 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001316 :type issuer: :py:class:`X509Name`
1317
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001318 :return: :py:const:`None`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001319 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001320 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001321
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001322 def get_subject(self):
1323 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001324 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001325
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001326 This creates a new :py:class:`X509Name`: modifying it does not affect
1327 this certificate.
1328
1329 :return: The subject of this certificate.
1330 :rtype: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001331 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001332 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001333
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001334 def set_subject(self, subject):
1335 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001336 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001337
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001338 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001339 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001340
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001341 :return: :py:const:`None`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001342 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001343 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001344
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001345 def get_extension_count(self):
1346 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001347 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001348
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001349 :return: The number of extensions.
1350 :rtype: :py:class:`int`
1351
1352 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001353 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001354 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001355
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001356 def add_extensions(self, extensions):
1357 """
1358 Add extensions to the certificate.
1359
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001360 :param extensions: The extensions to add.
1361 :type extensions: An iterable of :py:class:`X509Extension` objects.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001362 :return: :py:const:`None`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001363 """
1364 for ext in extensions:
1365 if not isinstance(ext, X509Extension):
1366 raise ValueError("One of the elements is not an X509Extension")
1367
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001368 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001369 if not add_result:
1370 _raise_current_error()
1371
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001372 def get_extension(self, index):
1373 """
1374 Get a specific extension of the certificate by index.
1375
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001376 Extensions on a certificate are kept in order. The index
1377 parameter selects which extension will be returned.
1378
1379 :param int index: The index of the extension to retrieve.
1380 :return: The extension at the specified index.
1381 :rtype: :py:class:`X509Extension`
1382 :raises IndexError: If the extension index was out of bounds.
1383
1384 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001385 """
1386 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001387 ext._extension = _lib.X509_get_ext(self._x509, index)
1388 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001389 raise IndexError("extension index out of bounds")
1390
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001391 extension = _lib.X509_EXTENSION_dup(ext._extension)
1392 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001393 return ext
1394
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001395
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001396X509Type = X509
1397
1398
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001399class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001400 """
1401 An X509 certificate store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001402 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001403
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001404 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001405 store = _lib.X509_STORE_new()
1406 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001407
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001408 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001409 """
1410 Adds the certificate :py:data:`cert` to this store.
1411
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +02001412 This is the Python equivalent of OpenSSL's ``X509_STORE_add_cert``.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001413
1414 :param X509 cert: The certificate to add to this store.
1415 :raises TypeError: If the certificate is not an :py:class:`X509`.
1416 :raises Error: If OpenSSL was unhappy with your certificate.
Laurens Van Houtven5ee60b32015-04-23 10:51:16 -07001417 :return: :py:data:`None` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001418 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001419 if not isinstance(cert, X509):
1420 raise TypeError()
1421
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001422 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001423 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001424 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001425
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001426
1427X509StoreType = X509Store
1428
1429
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001430class X509StoreContextError(Exception):
1431 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001432 An exception raised when an error occurred while verifying a certificate
1433 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001434
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001435 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001436 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001437 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001438
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001439 def __init__(self, message, certificate):
1440 super(X509StoreContextError, self).__init__(message)
1441 self.certificate = certificate
1442
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001443
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001444class X509StoreContext(object):
1445 """
1446 An X.509 store context.
1447
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001448 An :py:class:`X509StoreContext` is used to define some of the criteria for
1449 certificate verification. The information encapsulated in this object
1450 includes, but is not limited to, a set of trusted certificates,
1451 verification parameters, and revoked certificates.
1452
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001453 .. note::
1454
1455 Currently, one can only set the trusted certificates on an
1456 :py:class:`X509StoreContext`. Future versions of pyOpenSSL will expose
1457 verification parameters and certificate revocation lists.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001458
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001459 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1460 instance. It is dynamically allocated and automatically garbage
1461 collected.
1462
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001463 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001464
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001465 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001466
1467 :param X509Store store: The certificates which will be trusted for the
1468 purposes of any verifications.
1469
1470 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001471 """
1472
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001473 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001474 store_ctx = _lib.X509_STORE_CTX_new()
1475 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1476 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001477 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001478 # Make the store context available for use after instantiating this
1479 # class by initializing it now. Per testing, subsequent calls to
1480 # :py:meth:`_init` have no adverse affect.
1481 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001482
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001483 def _init(self):
1484 """
1485 Set up the store context for a subsequent verification operation.
1486 """
1487 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1488 if ret <= 0:
1489 _raise_current_error()
1490
1491 def _cleanup(self):
1492 """
1493 Internally cleans up the store context.
1494
1495 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001496 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001497 """
1498 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1499
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001500 def _exception_from_context(self):
1501 """
1502 Convert an OpenSSL native context error failure into a Python
1503 exception.
1504
Alex Gaynorca87ff62015-09-04 23:31:03 -04001505 When a call to native OpenSSL X509_verify_cert fails, additional information
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001506 about the failure can be obtained from the store context.
1507 """
1508 errors = [
1509 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1510 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1511 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1512 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1513 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001514 # A context error should always be associated with a certificate, so we
1515 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001516 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001517 _cert = _lib.X509_dup(_x509)
1518 pycert = X509.__new__(X509)
1519 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001520 return X509StoreContextError(errors, pycert)
1521
Stephen Holsapple46a09252015-02-12 14:45:43 -08001522 def set_store(self, store):
1523 """
1524 Set the context's trust store.
1525
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001526 .. versionadded:: 0.15
1527
Stephen Holsapple46a09252015-02-12 14:45:43 -08001528 :param X509Store store: The certificates which will be trusted for the
1529 purposes of any *future* verifications.
1530 """
1531 self._store = store
1532
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001533 def verify_certificate(self):
1534 """
1535 Verify a certificate in a context.
1536
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001537 .. versionadded:: 0.15
1538
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001539 :param store_ctx: The :py:class:`X509StoreContext` to verify.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001540
Alex Gaynorca87ff62015-09-04 23:31:03 -04001541 :raises X509StoreContextError: If an error occurred when validating a
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001542 certificate in the context. Sets ``certificate`` attribute to indicate
1543 which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001544 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001545 # Always re-initialize the store context in case
1546 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001547 self._init()
1548 ret = _lib.X509_verify_cert(self._store_ctx)
1549 self._cleanup()
1550 if ret <= 0:
1551 raise self._exception_from_context()
1552
1553
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001554def load_certificate(type, buffer):
1555 """
1556 Load a certificate from a buffer
1557
1558 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1559
1560 :param buffer: The buffer the certificate is stored in
1561 :type buffer: :py:class:`bytes`
1562
1563 :return: The X509 object
1564 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001565 if isinstance(buffer, _text_type):
1566 buffer = buffer.encode("ascii")
1567
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001568 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001569
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001570 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001571 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001572 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001573 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001574 else:
1575 raise ValueError(
1576 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001577
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001578 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001579 _raise_current_error()
1580
1581 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001582 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001583 return cert
1584
1585
1586def dump_certificate(type, cert):
1587 """
1588 Dump a certificate to a buffer
1589
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001590 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1591 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001592 :param cert: The certificate to dump
1593 :return: The buffer with the dumped certificate in
1594 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001595 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001596
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001597 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001598 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001599 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001600 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001601 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001602 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001603 else:
1604 raise ValueError(
1605 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1606 "FILETYPE_TEXT")
1607
1608 return _bio_to_string(bio)
1609
1610
1611
1612def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1613 """
1614 Dump a private key to a buffer
1615
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001616 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1617 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001618 :param pkey: The PKey to dump
1619 :param cipher: (optional) if encrypted PEM format, the cipher to
1620 use
1621 :param passphrase: (optional) if encrypted PEM format, this can be either
1622 the passphrase to use, or a callback for providing the
1623 passphrase.
1624 :return: The buffer with the dumped key in
1625 :rtype: :py:data:`str`
1626 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001627 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001628
1629 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001630 if passphrase is None:
1631 raise TypeError(
1632 "if a value is given for cipher "
1633 "one must also be given for passphrase")
1634 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001635 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001636 raise ValueError("Invalid cipher name")
1637 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001638 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001639
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001640 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001641 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001642 result_code = _lib.PEM_write_bio_PrivateKey(
1643 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001644 helper.callback, helper.callback_args)
1645 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001646 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001647 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001648 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001649 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1650 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001651 # TODO RSA_free(rsa)?
1652 else:
1653 raise ValueError(
1654 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1655 "FILETYPE_TEXT")
1656
1657 if result_code == 0:
1658 _raise_current_error()
1659
1660 return _bio_to_string(bio)
1661
1662
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001663def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001664 copy = _lib.X509_REVOKED_new()
1665 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001666 # TODO: This is untested.
1667 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001668
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001669 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001670 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001671 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001672
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001673 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001674 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001675 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001676
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001677 if original.extensions != _ffi.NULL:
1678 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1679 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1680 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1681 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1682 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001683 copy.extensions = extension_stack
1684
1685 copy.sequence = original.sequence
1686 return copy
1687
1688
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001689class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001690 """
1691 A certificate revocation.
1692 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001693 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1694 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1695 # OCSP_crl_reason_str. We use the latter, just like the command line
1696 # program.
1697 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001698 b"unspecified",
1699 b"keyCompromise",
1700 b"CACompromise",
1701 b"affiliationChanged",
1702 b"superseded",
1703 b"cessationOfOperation",
1704 b"certificateHold",
1705 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001706 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001707
1708 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001709 revoked = _lib.X509_REVOKED_new()
1710 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001711
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001712 def set_serial(self, hex_str):
1713 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001714 Set the serial number.
1715
1716 The serial number is formatted as a hexadecimal number encoded in
1717 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001718
1719 :param hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001720 :type hex_str: :py:class:`bytes`
1721
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001722 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001723 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001724 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1725 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001726 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001727 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001728 if not bn_result:
1729 raise ValueError("bad hex string")
1730
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001731 asn1_serial = _ffi.gc(
1732 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1733 _lib.ASN1_INTEGER_free)
1734 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001735
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001736 def get_serial(self):
1737 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001738 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001739
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001740 The serial number is formatted as a hexadecimal number encoded in
1741 ASCII.
1742
1743 :return: The serial number.
1744 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001745 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001746 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001747
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001748 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001749 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001750 # TODO: This is untested.
1751 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001752
1753 return _bio_to_string(bio)
1754
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001755 def _delete_reason(self):
1756 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001757 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1758 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1759 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1760 _lib.X509_EXTENSION_free(ext)
1761 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001762 break
1763
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001764 def set_reason(self, reason):
1765 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001766 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001767
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001768 If :py:data:`reason` is :py:const:`None`, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001769
1770 :param reason: The reason string.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001771 :type reason: :py:class:`bytes` or :py:class:`NoneType`
1772
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001773 :return: :py:const:`None`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001774
1775 .. seealso::
1776
1777 :py:meth:`all_reasons`, which gives you a list of all supported
1778 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001779 """
1780 if reason is None:
1781 self._delete_reason()
1782 elif not isinstance(reason, bytes):
1783 raise TypeError("reason must be None or a byte string")
1784 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001785 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001786 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1787
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001788 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1789 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001790 # TODO: This is untested.
1791 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001792 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001793
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001794 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1795 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001796 # TODO: This is untested.
1797 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001798
1799 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001800 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1801 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001802
1803 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001804 # TODO: This is untested.
1805 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001806
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807 def get_reason(self):
1808 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001809 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001810
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001811 :return: The reason, or :py:const:`None` if there is none.
1812 :rtype: :py:class:`bytes` or :py:class:`NoneType`
1813
1814 .. seealso::
1815
1816 :py:meth:`all_reasons`, which gives you a list of all supported
1817 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001818 """
1819 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001820 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1821 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1822 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001823 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001824
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001825 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001826 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001827 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001828 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001829 # TODO: This is untested.
1830 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001831
1832 return _bio_to_string(bio)
1833
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001834 def all_reasons(self):
1835 """
1836 Return a list of all the supported reason strings.
1837
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001838 This list is a copy; modifying it does not change the supported reason
1839 strings.
1840
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001841 :return: A list of reason strings.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001842 :rtype: :py:class:`list` of :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001843 """
1844 return self._crl_reasons[:]
1845
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001846 def set_rev_date(self, when):
1847 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001848 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001849
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001850 :param when: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1851 :type when: :py:class:`bytes`
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001852 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001853 """
1854 return _set_asn1_time(self._revoked.revocationDate, when)
1855
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001856 def get_rev_date(self):
1857 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001858 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001859
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001860 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
1861 :rtype: :py:class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001862 """
1863 return _get_asn1_time(self._revoked.revocationDate)
1864
1865
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001866class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001867 """
1868 A certificate revocation list.
1869 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001870
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001871 def __init__(self):
1872 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001873 Create a new empty certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001874 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001875 crl = _lib.X509_CRL_new()
1876 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001877
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001878 def get_revoked(self):
1879 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001880 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001881
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001882 These revocations will be provided by value, not by reference.
1883 That means it's okay to mutate them: it won't affect this CRL.
1884
1885 :return: The revocations in this CRL.
1886 :rtype: :py:class:`tuple` of :py:class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001887 """
1888 results = []
1889 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001890 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1891 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001892 revoked_copy = _X509_REVOKED_dup(revoked)
1893 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001894 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001895 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001896 if results:
1897 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001898
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001899 def add_revoked(self, revoked):
1900 """
1901 Add a revoked (by value not reference) to the CRL structure
1902
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001903 This revocation will be added by value, not by reference. That
1904 means it's okay to mutate it after adding: it won't affect
1905 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001906
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001907 :param revoked: The new revocation.
1908 :type revoked: :class:`Revoked`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001909
Laurens Van Houtvena7904582014-06-19 12:33:04 +02001910 :return: :py:const:`None`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001911 """
1912 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001913 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001914 # TODO: This is untested.
1915 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001916
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001917 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001918 if add_result == 0:
1919 # TODO: This is untested.
1920 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001921
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001922 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001923 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001924 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001925 Export a CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001926
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001927 :param cert: The certificate used to sign the CRL.
1928 :type cert: :py:class:`X509`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001929
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001930 :param key: The key used to sign the CRL.
1931 :type key: :py:class:`PKey`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001932
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001933 :param type: The export format, either :py:data:`FILETYPE_PEM`,
1934 :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001935
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04001936 :param int days: The number of days until the next update of this CRL.
Bulat Gaifullin5f9eea42014-09-23 19:35:15 +04001937
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001938 :param bytes digest: The name of the message digest to use (eg
1939 ``b"sha1"``).
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001940
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001941 :return: :py:data:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001942 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001943 if not isinstance(cert, X509):
1944 raise TypeError("cert must be an X509 instance")
1945 if not isinstance(key, PKey):
1946 raise TypeError("key must be a PKey instance")
1947 if not isinstance(type, int):
1948 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001949
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04001950 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001951 _warn(
1952 "The default message digest (md5) is deprecated. "
1953 "Pass the name of a message digest explicitly.",
1954 category=DeprecationWarning,
1955 stacklevel=2,
1956 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001957 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04001958
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04001959 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001960 if digest_obj == _ffi.NULL:
1961 raise ValueError("No such digest method")
1962
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001963 bio = _lib.BIO_new(_lib.BIO_s_mem())
1964 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001965 # TODO: This is untested.
1966 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001967
Alex Gaynora738ed52015-09-05 11:17:10 -04001968 # A scratch time object to give different values to different CRL
1969 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001970 sometime = _lib.ASN1_TIME_new()
1971 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001972 # TODO: This is untested.
1973 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001974
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001975 _lib.X509_gmtime_adj(sometime, 0)
1976 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001977
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001978 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1979 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001980
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001981 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001982
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04001983 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001984 if not sign_result:
1985 _raise_current_error()
1986
1987 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001988 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001989 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001990 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001991 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001992 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001993 else:
1994 raise ValueError(
1995 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1996
1997 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001998 # TODO: This is untested.
1999 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002000
2001 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002002CRLType = CRL
2003
2004
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002005class PKCS7(object):
2006 def type_is_signed(self):
2007 """
2008 Check if this NID_pkcs7_signed object
2009
2010 :return: True if the PKCS7 is of type signed
2011 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002012 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002013 return True
2014 return False
2015
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002016 def type_is_enveloped(self):
2017 """
2018 Check if this NID_pkcs7_enveloped object
2019
2020 :returns: True if the PKCS7 is of type enveloped
2021 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002022 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002023 return True
2024 return False
2025
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002026 def type_is_signedAndEnveloped(self):
2027 """
2028 Check if this NID_pkcs7_signedAndEnveloped object
2029
2030 :returns: True if the PKCS7 is of type signedAndEnveloped
2031 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002032 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002033 return True
2034 return False
2035
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002036 def type_is_data(self):
2037 """
2038 Check if this NID_pkcs7_data object
2039
2040 :return: True if the PKCS7 is of type data
2041 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002042 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002043 return True
2044 return False
2045
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002046 def get_type_name(self):
2047 """
2048 Returns the type name of the PKCS7 structure
2049
2050 :return: A string with the typename
2051 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002052 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2053 string_type = _lib.OBJ_nid2sn(nid)
2054 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002055
2056PKCS7Type = PKCS7
2057
2058
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002059class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002060 """
2061 A PKCS #12 archive.
2062 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002063
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002064 def __init__(self):
2065 self._pkey = None
2066 self._cert = None
2067 self._cacerts = None
2068 self._friendlyname = None
2069
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002070 def get_certificate(self):
2071 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002072 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002073
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002074 :return: The certificate, or :py:const:`None` if there is none.
2075 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002076 """
2077 return self._cert
2078
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002079 def set_certificate(self, cert):
2080 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002081 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002082
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002083 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002084 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002085
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002086 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002087 """
2088 if not isinstance(cert, X509):
2089 raise TypeError("cert must be an X509 instance")
2090 self._cert = cert
2091
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002092 def get_privatekey(self):
2093 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002094 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002095
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002096 :return: The private key, or :py:const:`None` if there is none.
2097 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002098 """
2099 return self._pkey
2100
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002101 def set_privatekey(self, pkey):
2102 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002103 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002104
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002105 :param pkey: The new private key, or :py:const:`None` to unset it.
2106 :type pkey: :py:class:`PKey` or :py:const:`None`
2107
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002108 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002109 """
2110 if not isinstance(pkey, PKey):
2111 raise TypeError("pkey must be a PKey instance")
2112 self._pkey = pkey
2113
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002114 def get_ca_certificates(self):
2115 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002116 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002117
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002118 :return: A tuple with the CA certificates in the chain, or
2119 :py:const:`None` if there are none.
2120 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002121 """
2122 if self._cacerts is not None:
2123 return tuple(self._cacerts)
2124
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002125 def set_ca_certificates(self, cacerts):
2126 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002127 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002128
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002129 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2130 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002131 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002132
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002133 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002134 """
2135 if cacerts is None:
2136 self._cacerts = None
2137 else:
2138 cacerts = list(cacerts)
2139 for cert in cacerts:
2140 if not isinstance(cert, X509):
2141 raise TypeError("iterable must only contain X509 instances")
2142 self._cacerts = cacerts
2143
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002144 def set_friendlyname(self, name):
2145 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002146 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002147
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002148 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002149 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002150
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002151 :return: :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002152 """
2153 if name is None:
2154 self._friendlyname = None
2155 elif not isinstance(name, bytes):
2156 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2157 self._friendlyname = name
2158
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002159 def get_friendlyname(self):
2160 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002161 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002162
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002163 :returns: The friendly name, or :py:const:`None` if there is none.
2164 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002165 """
2166 return self._friendlyname
2167
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002168 def export(self, passphrase=None, iter=2048, maciter=1):
2169 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002170 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002171
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002172 For more information, see the :c:func:`PKCS12_create` man page.
2173
2174 :param passphrase: The passphrase used to encrypt the structure. Unlike
2175 some other passphrase arguments, this *must* be a string, not a
2176 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002177 :type passphrase: :py:data:`bytes`
2178
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002179 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002180 :type iter: :py:data:`int`
2181
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002182 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002183 :type maciter: :py:data:`int`
2184
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002185 :return: The string representation of the PKCS #12 structure.
2186 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002187 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002188 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002189
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002190 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002191 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002192 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002193 cacerts = _lib.sk_X509_new_null()
2194 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002195 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002196 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002197
2198 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002199 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002200
2201 friendlyname = self._friendlyname
2202 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002203 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002204
2205 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002206 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002207 else:
2208 pkey = self._pkey._pkey
2209
2210 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002211 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002212 else:
2213 cert = self._cert._x509
2214
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002215 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002216 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002217 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2218 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002219 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002220 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002221 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002222 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002223
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002224 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002225 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002226 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002227
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002228
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002229PKCS12Type = PKCS12
2230
2231
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002232class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002233 """
2234 A Netscape SPKI object.
2235 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002236
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002237 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002238 spki = _lib.NETSCAPE_SPKI_new()
2239 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002240
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002241 def sign(self, pkey, digest):
2242 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002243 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002244
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002245 :param pkey: The private key to sign with.
2246 :type pkey: :py:class:`PKey`
2247
2248 :param digest: The message digest to use.
2249 :type digest: :py:class:`bytes`
2250
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002251 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002252 """
2253 if pkey._only_public:
2254 raise ValueError("Key has only public part")
2255
2256 if not pkey._initialized:
2257 raise ValueError("Key is uninitialized")
2258
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002259 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002260 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002261 raise ValueError("No such digest method")
2262
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002263 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002264 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002265 # TODO: This is untested.
2266 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002267
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002268 def verify(self, key):
2269 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002270 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002271
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002272 :param key: The public key that signature is supposedly from.
2273 :type pkey: :py:class:`PKey`
2274
2275 :return: :py:const:`True` if the signature is correct.
2276 :rtype: :py:class:`bool`
2277
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002278 :raises Error: If the signature is invalid, or there was a problem
2279 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002280 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002281 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002282 if answer <= 0:
2283 _raise_current_error()
2284 return True
2285
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002286 def b64_encode(self):
2287 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002288 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002289
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002290 :return: The base64 encoded string.
2291 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002292 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002293 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2294 result = _ffi.string(encoded)
2295 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002296 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002297
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002298 def get_pubkey(self):
2299 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002300 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002301
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002302 :return: The public key.
2303 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002304 """
2305 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002306 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2307 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002308 # TODO: This is untested.
2309 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002310 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002311 pkey._only_public = True
2312 return pkey
2313
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002314 def set_pubkey(self, pkey):
2315 """
2316 Set the public key of the certificate
2317
2318 :param pkey: The public key
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002319 :return: :py:const:`None`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002320 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002321 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002322 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002323 # TODO: This is untested.
2324 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002325
2326
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002327NetscapeSPKIType = NetscapeSPKI
2328
2329
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002330class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002331 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002332 if type != FILETYPE_PEM and passphrase is not None:
2333 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002334 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002335 self._more_args = more_args
2336 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002337 self._problems = []
2338
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002339 @property
2340 def callback(self):
2341 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002342 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002343 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002344 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002345 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002346 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002347 else:
2348 raise TypeError("Last argument must be string or callable")
2349
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002350 @property
2351 def callback_args(self):
2352 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002353 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002354 elif isinstance(self._passphrase, bytes):
2355 return self._passphrase
2356 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002357 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002358 else:
2359 raise TypeError("Last argument must be string or callable")
2360
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002361 def raise_if_problem(self, exceptionType=Error):
2362 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002363 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002364 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002365 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002366 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002367 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002368 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002369
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002370 def _read_passphrase(self, buf, size, rwflag, userdata):
2371 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002372 if self._more_args:
2373 result = self._passphrase(size, rwflag, userdata)
2374 else:
2375 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002376 if not isinstance(result, bytes):
2377 raise ValueError("String expected")
2378 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002379 if self._truncate:
2380 result = result[:size]
2381 else:
2382 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002383 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002384 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002385 return len(result)
2386 except Exception as e:
2387 self._problems.append(e)
2388 return 0
2389
2390
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002391def load_privatekey(type, buffer, passphrase=None):
2392 """
2393 Load a private key from a buffer
2394
2395 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2396 :param buffer: The buffer the key is stored in
2397 :param passphrase: (optional) if encrypted PEM format, this can be
2398 either the passphrase to use, or a callback for
2399 providing the passphrase.
2400
2401 :return: The PKey object
2402 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002403 if isinstance(buffer, _text_type):
2404 buffer = buffer.encode("ascii")
2405
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002406 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002407
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002408 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002409 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002410 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2411 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002412 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002413 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002414 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002415 else:
2416 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2417
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002418 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002419 _raise_current_error()
2420
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002421 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002422 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002423 return pkey
2424
2425
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002426def dump_certificate_request(type, req):
2427 """
2428 Dump a certificate request to a buffer
2429
2430 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2431 :param req: The certificate request to dump
2432 :return: The buffer with the dumped certificate request in
2433 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002434 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002435
2436 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002437 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002438 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002439 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002440 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002441 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002442 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002443 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002444
2445 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002446 # TODO: This is untested.
2447 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002448
2449 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002450
2451
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002452def load_certificate_request(type, buffer):
2453 """
2454 Load a certificate request from a buffer
2455
2456 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2457 :param buffer: The buffer the certificate request is stored in
2458 :return: The X509Req object
2459 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002460 if isinstance(buffer, _text_type):
2461 buffer = buffer.encode("ascii")
2462
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002463 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002464
2465 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002466 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002467 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002468 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002469 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002470 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002471
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002472 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002473 # TODO: This is untested.
2474 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002475
2476 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002477 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002478 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002479
2480
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002481def sign(pkey, data, digest):
2482 """
2483 Sign data with a digest
2484
2485 :param pkey: Pkey to sign with
2486 :param data: data to be signed
2487 :param digest: message digest to use
2488 :return: signature
2489 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002490 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002491
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002492 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002493 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002494 raise ValueError("No such digest method")
2495
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002496 md_ctx = _ffi.new("EVP_MD_CTX*")
2497 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002498
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002499 _lib.EVP_SignInit(md_ctx, digest_obj)
2500 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002501
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002502 signature_buffer = _ffi.new("unsigned char[]", 512)
2503 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002504 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002505 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002506 md_ctx, signature_buffer, signature_length, pkey._pkey)
2507
2508 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002509 # TODO: This is untested.
2510 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002511
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002512 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002513
2514
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002515def verify(cert, signature, data, digest):
2516 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002517 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002518
2519 :param cert: signing certificate (X509 object)
2520 :param signature: signature returned by sign function
2521 :param data: data to be verified
2522 :param digest: message digest to use
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002523 :return: :py:const:`None` if the signature is correct, raise exception otherwise
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002524 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002525 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002526
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002527 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002528 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002529 raise ValueError("No such digest method")
2530
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002531 pkey = _lib.X509_get_pubkey(cert._x509)
2532 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002533 # TODO: This is untested.
2534 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002535 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002536
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002537 md_ctx = _ffi.new("EVP_MD_CTX*")
2538 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002539
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002540 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2541 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2542 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002543
2544 if verify_result != 1:
2545 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002546
2547
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002548def load_crl(type, buffer):
2549 """
2550 Load a certificate revocation list from a buffer
2551
2552 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2553 :param buffer: The buffer the CRL is stored in
2554
2555 :return: The PKey object
2556 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002557 if isinstance(buffer, _text_type):
2558 buffer = buffer.encode("ascii")
2559
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002560 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002561
2562 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002563 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002564 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002565 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002566 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002567 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2568
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002569 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002570 _raise_current_error()
2571
2572 result = CRL.__new__(CRL)
2573 result._crl = crl
2574 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002575
2576
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002577def load_pkcs7_data(type, buffer):
2578 """
2579 Load pkcs7 data from a buffer
2580
2581 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2582 :param buffer: The buffer with the pkcs7 data.
2583 :return: The PKCS7 object
2584 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002585 if isinstance(buffer, _text_type):
2586 buffer = buffer.encode("ascii")
2587
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002588 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002589
2590 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002591 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002592 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002593 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002594 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002595 # TODO: This is untested.
2596 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002597 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2598
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002599 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002600 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002601
2602 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002603 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002604 return pypkcs7
2605
2606
Stephen Holsapple38482622014-04-05 20:29:34 -07002607def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002608 """
2609 Load a PKCS12 object from a buffer
2610
2611 :param buffer: The buffer the certificate is stored in
2612 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2613 :returns: The PKCS12 object
2614 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002615 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002616
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002617 if isinstance(buffer, _text_type):
2618 buffer = buffer.encode("ascii")
2619
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002620 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002621
Stephen Holsapple38482622014-04-05 20:29:34 -07002622 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2623 # password based encryption no password and a zero length password are two
2624 # different things, but OpenSSL implementation will try both to figure out
2625 # which one works.
2626 if not passphrase:
2627 passphrase = _ffi.NULL
2628
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002629 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2630 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002631 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002632 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002633
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002634 pkey = _ffi.new("EVP_PKEY**")
2635 cert = _ffi.new("X509**")
2636 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002637
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002638 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002639 if not parse_result:
2640 _raise_current_error()
2641
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002642 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002643
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002644 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2645 # queue for no particular reason. This error isn't interesting to anyone
2646 # outside this function. It's not even interesting to us. Get rid of it.
2647 try:
2648 _raise_current_error()
2649 except Error:
2650 pass
2651
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002652 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002653 pykey = None
2654 else:
2655 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002656 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002657
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002658 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002659 pycert = None
2660 friendlyname = None
2661 else:
2662 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002663 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002664
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002665 friendlyname_length = _ffi.new("int*")
2666 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2667 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2668 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002669 friendlyname = None
2670
2671 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002672 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002673 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002674 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002675 pycacerts.append(pycacert)
2676 if not pycacerts:
2677 pycacerts = None
2678
2679 pkcs12 = PKCS12.__new__(PKCS12)
2680 pkcs12._pkey = pykey
2681 pkcs12._cert = pycert
2682 pkcs12._cacerts = pycacerts
2683 pkcs12._friendlyname = friendlyname
2684 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002685
2686
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002687# There are no direct unit tests for this initialization. It is tested
2688# indirectly since it is necessary for functions like dump_privatekey when
2689# using encryption.
2690#
2691# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2692# and some other similar tests may fail without this (though they may not if
2693# the Python runtime has already done some initialization of the underlying
2694# OpenSSL library (and is linked against the same one that cryptography is
2695# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002696_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002697
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002698# This is similar but exercised mainly by exception_from_error_queue. It calls
2699# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2700_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002701
2702
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002703# Set the default string mask to match OpenSSL upstream (since 2005) and
2704# RFC5280 recommendations.
2705_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')