blob: 9b0b3c911ac9bdad55207dd5811b27b75bc9880b [file] [log] [blame]
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001import datetime
Paul Kehrer8d887e12015-10-24 09:09:55 -05002
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05003from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05004from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05005from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04006from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05007
8from six import (
9 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -040010 text_type as _text_type,
11 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080012
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050013from OpenSSL._util import (
14 ffi as _ffi,
15 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050016 exception_from_error_queue as _exception_from_error_queue,
17 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040018 native as _native,
19 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040020 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Alex Gaynor67903a62016-06-02 10:37:13 -070021 make_assert as _make_assert,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040022)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080023
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050024FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
25FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080026
27# TODO This was an API mistake. OpenSSL has no such constant.
28FILETYPE_TEXT = 2 ** 16 - 1
29
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050030TYPE_RSA = _lib.EVP_PKEY_RSA
31TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080032
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080033
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050034class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050035 """
36 An error occurred in an `OpenSSL.crypto` API.
37 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050038
39
40_raise_current_error = partial(_exception_from_error_queue, Error)
Alex Gaynor67903a62016-06-02 10:37:13 -070041_openssl_assert = _make_assert(Error)
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050042
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070043
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050044def _untested_error(where):
45 """
46 An OpenSSL API failed somehow. Additionally, the failure which was
47 encountered isn't one that's exercised by the test suite so future behavior
48 of pyOpenSSL is now somewhat less predictable.
49 """
50 raise RuntimeError("Unknown %s failure" % (where,))
51
52
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050053def _new_mem_buf(buffer=None):
54 """
55 Allocate a new OpenSSL memory BIO.
56
57 Arrange for the garbage collector to clean it up automatically.
58
59 :param buffer: None or some bytes to use to put into the BIO so that they
60 can be read out.
61 """
62 if buffer is None:
63 bio = _lib.BIO_new(_lib.BIO_s_mem())
64 free = _lib.BIO_free
65 else:
66 data = _ffi.new("char[]", buffer)
67 bio = _lib.BIO_new_mem_buf(data, len(buffer))
Alex Gaynor5945ea82015-09-05 14:59:06 -040068
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050069 # Keep the memory alive as long as the bio is alive!
70 def free(bio, ref=data):
71 return _lib.BIO_free(bio)
72
73 if bio == _ffi.NULL:
74 # TODO: This is untested.
75 _raise_current_error()
76
77 bio = _ffi.gc(bio, free)
78 return bio
79
80
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080081def _bio_to_string(bio):
82 """
83 Copy the contents of an OpenSSL BIO object into a Python byte string.
84 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050085 result_buffer = _ffi.new('char**')
86 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
87 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080088
89
Jean-Paul Calderone57122982013-02-21 08:47:05 -080090def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050091 """
92 The the time value of an ASN1 time object.
93
94 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
95 castable to that type) which will have its value set.
96 @param when: A string representation of the desired time value.
97
98 @raise TypeError: If C{when} is not a L{bytes} string.
99 @raise ValueError: If C{when} does not represent a time in the required
100 format.
101 @raise RuntimeError: If the time value cannot be set for some other
102 (unspecified) reason.
103 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800104 if not isinstance(when, bytes):
105 raise TypeError("when must be a byte string")
106
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500107 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
108 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800109 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500110 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
111 _lib.ASN1_STRING_set(dummy, when, len(when))
112 check_result = _lib.ASN1_GENERALIZEDTIME_check(
113 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800114 if not check_result:
115 raise ValueError("Invalid string")
116 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500117 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800118
Alex Gaynor510293e2016-06-02 12:07:59 -0700119
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800120def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500121 """
122 Retrieve the time value of an ASN1 time object.
123
124 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
125 that type) from which the time value will be retrieved.
126
127 @return: The time value from C{timestamp} as a L{bytes} string in a certain
128 format. Or C{None} if the object contains no time value.
129 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500130 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
131 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800132 return None
Alex Gaynor5945ea82015-09-05 14:59:06 -0400133 elif (
134 _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
135 ):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500136 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800137 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500138 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
139 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
140 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500141 # This may happen:
142 # - if timestamp was not an ASN1_TIME
143 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
144 # - if a copy of the time data from timestamp cannot be made for
145 # the newly allocated ASN1_GENERALIZEDTIME
146 #
147 # These are difficult to test. cffi enforces the ASN1_TIME type.
148 # Memory allocation failures are a pain to trigger
149 # deterministically.
150 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800151 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500152 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800153 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500154 string_data = _lib.ASN1_STRING_data(string_timestamp)
155 string_result = _ffi.string(string_data)
156 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800157 return string_result
158
159
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800160class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200161 """
162 A class representing an DSA or RSA public key or key pair.
163 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800164 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800165 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800166
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800167 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500168 pkey = _lib.EVP_PKEY_new()
169 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800170 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800171
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800172 def generate_key(self, type, bits):
173 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700174 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800175
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200176 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800177
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200178 :param type: The key type.
179 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
180 :param bits: The number of bits.
181 :type bits: :py:data:`int` ``>= 0``
182 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
183 of the appropriate type.
184 :raises ValueError: If the number of bits isn't an integer of
185 the appropriate size.
Dan Sully44e767a2016-06-04 18:05:27 -0700186 :return: ``None``
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800187 """
188 if not isinstance(type, int):
189 raise TypeError("type must be an integer")
190
191 if not isinstance(bits, int):
192 raise TypeError("bits must be an integer")
193
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800194 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500195 exponent = _lib.BN_new()
196 exponent = _ffi.gc(exponent, _lib.BN_free)
197 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800198
199 if type == TYPE_RSA:
200 if bits <= 0:
201 raise ValueError("Invalid number of bits")
202
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500203 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800204
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500205 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500206 if result == 0:
207 # TODO: The test for this case is commented out. Different
208 # builds of OpenSSL appear to have different failure modes that
209 # make it hard to test. Visual inspection of the OpenSSL
210 # source reveals that a return value of 0 signals an error.
211 # Manual testing on a particular build of OpenSSL suggests that
212 # this is probably the appropriate way to handle those errors.
213 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800214
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500215 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800216 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500217 # TODO: It appears as though this can fail if an engine is in
218 # use which does not support RSA.
219 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800220
221 elif type == TYPE_DSA:
Paul Kehrera0860b92016-03-09 21:39:27 -0400222 dsa = _lib.DSA_new()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500223 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500224 # TODO: This is untested.
225 _raise_current_error()
Paul Kehrerafa5a662016-03-10 10:29:28 -0400226
227 dsa = _ffi.gc(dsa, _lib.DSA_free)
Paul Kehrera0860b92016-03-09 21:39:27 -0400228 res = _lib.DSA_generate_parameters_ex(
229 dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL
230 )
231 if not res == 1:
232 # TODO: This is untested.
233 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500234 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500235 # TODO: This is untested.
236 _raise_current_error()
Paul Kehrerafa5a662016-03-10 10:29:28 -0400237 if not _lib.EVP_PKEY_set1_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500238 # TODO: This is untested.
239 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800240 else:
241 raise Error("No such key type")
242
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800243 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800244
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800245 def check(self):
246 """
247 Check the consistency of an RSA private key.
248
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200249 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
250
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800251 :return: True if key is consistent.
252 :raise Error: if the key is inconsistent.
253 :raise TypeError: if the key is of a type which cannot be checked.
254 Only RSA keys can currently be checked.
255 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800256 if self._only_public:
257 raise TypeError("public key only")
258
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100259 if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800260 raise TypeError("key type unsupported")
261
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500262 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
263 rsa = _ffi.gc(rsa, _lib.RSA_free)
264 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800265 if result:
266 return True
267 _raise_current_error()
268
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800269 def type(self):
270 """
271 Returns the type of the key
272
273 :return: The type of the key.
274 """
Alex Gaynorc84567b2016-03-16 07:45:09 -0400275 return _lib.Cryptography_EVP_PKEY_id(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800276
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800277 def bits(self):
278 """
279 Returns the number of bits of the key
280
281 :return: The number of bits of the key.
282 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500283 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800284PKeyType = PKey
285
286
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400287class _EllipticCurve(object):
288 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400289 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400290
291 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
292 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
293 instances each of which represents one curve supported by the system.
294 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400295 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400296 _curves = None
297
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400298 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400299 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400300 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400301 """
302 Implement cooperation with the right-hand side argument of ``!=``.
303
304 Python 3 seems to have dropped this cooperation in this very narrow
305 circumstance.
306 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400307 if isinstance(other, _EllipticCurve):
308 return super(_EllipticCurve, self).__ne__(other)
309 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400310
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400311 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400312 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400313 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400314 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400315
316 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400317
318 :return: A :py:type:`set` of ``cls`` instances giving the names of the
319 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400320 """
321 if lib.Cryptography_HAS_EC:
322 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
323 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400324 # The return value on this call should be num_curves again. We
325 # could check it to make sure but if it *isn't* then.. what could
326 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400327 lib.EC_get_builtin_curves(builtin_curves, num_curves)
328 return set(
329 cls.from_nid(lib, c.nid)
330 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400331 return set()
332
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400333 @classmethod
334 def _get_elliptic_curves(cls, lib):
335 """
336 Get, cache, and return the curves supported by OpenSSL.
337
338 :param lib: The OpenSSL library binding object.
339
340 :return: A :py:type:`set` of ``cls`` instances giving the names of the
341 elliptic curves the underlying library supports.
342 """
343 if cls._curves is None:
344 cls._curves = cls._load_elliptic_curves(lib)
345 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400346
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400347 @classmethod
348 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400349 """
350 Instantiate a new :py:class:`_EllipticCurve` associated with the given
351 OpenSSL NID.
352
353 :param lib: The OpenSSL library binding object.
354
355 :param nid: The OpenSSL NID the resulting curve object will represent.
356 This must be a curve NID (and not, for example, a hash NID) or
357 subsequent operations will fail in unpredictable ways.
358 :type nid: :py:class:`int`
359
360 :return: The curve object.
361 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400362 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
363
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400364 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400365 """
366 :param _lib: The :py:mod:`cryptography` binding instance used to
367 interface with OpenSSL.
368
369 :param _nid: The OpenSSL NID identifying the curve this object
370 represents.
371 :type _nid: :py:class:`int`
372
373 :param name: The OpenSSL short name identifying the curve this object
374 represents.
375 :type name: :py:class:`unicode`
376 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400377 self._lib = lib
378 self._nid = nid
379 self.name = name
380
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400381 def __repr__(self):
382 return "<Curve %r>" % (self.name,)
383
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400384 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400385 """
386 Create a new OpenSSL EC_KEY structure initialized to use this curve.
387
388 The structure is automatically garbage collected when the Python object
389 is garbage collected.
390 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400391 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
392 return _ffi.gc(key, _lib.EC_KEY_free)
393
394
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400395def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400396 """
397 Return a set of objects representing the elliptic curves supported in the
398 OpenSSL build in use.
399
400 The curve objects have a :py:class:`unicode` ``name`` attribute by which
401 they identify themselves.
402
403 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400404 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
405 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400406 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400407 return _EllipticCurve._get_elliptic_curves(_lib)
408
409
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400410def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400411 """
412 Return a single curve object selected by name.
413
414 See :py:func:`get_elliptic_curves` for information about curve objects.
415
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400416 :param name: The OpenSSL short name identifying the curve object to
417 retrieve.
418 :type name: :py:class:`unicode`
419
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400420 If the named curve is not supported then :py:class:`ValueError` is raised.
421 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400422 for curve in get_elliptic_curves():
423 if curve.name == name:
424 return curve
425 raise ValueError("unknown curve name", name)
426
427
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800428class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200429 """
430 An X.509 Distinguished Name.
431
432 :ivar countryName: The country of the entity.
433 :ivar C: Alias for :py:attr:`countryName`.
434
435 :ivar stateOrProvinceName: The state or province of the entity.
436 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
437
438 :ivar localityName: The locality of the entity.
439 :ivar L: Alias for :py:attr:`localityName`.
440
441 :ivar organizationName: The organization name of the entity.
442 :ivar O: Alias for :py:attr:`organizationName`.
443
444 :ivar organizationalUnitName: The organizational unit of the entity.
445 :ivar OU: Alias for :py:attr:`organizationalUnitName`
446
447 :ivar commonName: The common name of the entity.
448 :ivar CN: Alias for :py:attr:`commonName`.
449
450 :ivar emailAddress: The e-mail address of the entity.
451 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400452
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800453 def __init__(self, name):
454 """
455 Create a new X509Name, copying the given X509Name instance.
456
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200457 :param name: The name to copy.
458 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800459 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500460 name = _lib.X509_NAME_dup(name._name)
461 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800462
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800463 def __setattr__(self, name, value):
464 if name.startswith('_'):
465 return super(X509Name, self).__setattr__(name, value)
466
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800467 # Note: we really do not want str subclasses here, so we do not use
468 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800469 if type(name) is not str:
470 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400471 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800472
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500473 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500474 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800475 try:
476 _raise_current_error()
477 except Error:
478 pass
479 raise AttributeError("No such attribute")
480
481 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500482 for i in range(_lib.X509_NAME_entry_count(self._name)):
483 ent = _lib.X509_NAME_get_entry(self._name, i)
484 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
485 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800486 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500487 ent = _lib.X509_NAME_delete_entry(self._name, i)
488 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800489 break
490
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500491 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800492 value = value.encode('utf-8')
493
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500494 add_result = _lib.X509_NAME_add_entry_by_NID(
495 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800496 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500497 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800498
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800499 def __getattr__(self, name):
500 """
501 Find attribute. An X509Name object has the following attributes:
502 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400503 organization (alias O), organizationalUnit (alias OU), commonName
504 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800505 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500506 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500507 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800508 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
509 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
510 # push something onto the error queue. If we don't clean that up
511 # now, someone else will bump into it later and be quite confused.
512 # See lp#314814.
513 try:
514 _raise_current_error()
515 except Error:
516 pass
517 return super(X509Name, self).__getattr__(name)
518
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500519 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800520 if entry_index == -1:
521 return None
522
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500523 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
524 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800525
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500526 result_buffer = _ffi.new("unsigned char**")
527 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800528 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500529 # TODO: This is untested.
530 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800531
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700532 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400533 result = _ffi.buffer(
534 result_buffer[0], data_length
535 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700536 finally:
537 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500538 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800539 return result
540
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500541 def _cmp(op):
542 def f(self, other):
543 if not isinstance(other, X509Name):
544 return NotImplemented
545 result = _lib.X509_NAME_cmp(self._name, other._name)
546 return op(result, 0)
547 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800548
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500549 __eq__ = _cmp(__eq__)
550 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800551
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500552 __lt__ = _cmp(__lt__)
553 __le__ = _cmp(__le__)
554
555 __gt__ = _cmp(__gt__)
556 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800557
558 def __repr__(self):
559 """
560 String representation of an X509Name
561 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400562 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500563 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800564 self._name, result_buffer, len(result_buffer))
565
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500566 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500567 # TODO: This is untested.
568 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800569
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500570 return "<X509Name object '%s'>" % (
571 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800572
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800573 def hash(self):
574 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200575 Return an integer representation of the first four bytes of the
576 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800577
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200578 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
579
580 :return: The (integer) hash of this name.
581 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800582 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500583 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800584
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585 def der(self):
586 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200587 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800588
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200589 :return: The DER encoded form of this name.
590 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800591 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500592 result_buffer = _ffi.new('unsigned char**')
593 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800594 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500595 # TODO: This is untested.
596 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800597
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500598 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
599 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800600 return string_result
601
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800602 def get_components(self):
603 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200604 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800605
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200606 :return: The components of this name.
607 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800608 """
609 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500610 for i in range(_lib.X509_NAME_entry_count(self._name)):
611 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800612
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500613 fname = _lib.X509_NAME_ENTRY_get_object(ent)
614 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800615
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500616 nid = _lib.OBJ_obj2nid(fname)
617 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800618
619 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400620 _ffi.string(name),
621 _ffi.string(
622 _lib.ASN1_STRING_data(fval),
623 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800624
625 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200626
627
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800628X509NameType = X509Name
629
630
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800631class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200632 """
633 An X.509 v3 certificate extension.
634 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400635
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800636 def __init__(self, type_name, critical, value, subject=None, issuer=None):
637 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200638 Initializes an X509 extension.
639
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100640 :param type_name: The name of the type of extension_ to create.
Alex Gaynor6f719912015-09-20 09:21:29 -0400641 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800642
Alex Gaynor5945ea82015-09-05 14:59:06 -0400643 :param bool critical: A flag indicating whether this is a critical
644 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800645
646 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200647 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800648
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200649 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800650 :type subject: :py:class:`X509`
651
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200652 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800653 :type issuer: :py:class:`X509`
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100654
655 .. _extension: https://openssl.org/docs/manmaster/apps/
656 x509v3_config.html#STANDARD-EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800657 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500658 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800659
Alex Gaynor5945ea82015-09-05 14:59:06 -0400660 # A context is necessary for any extension which uses the r2i
661 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
662 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500663 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800664
665 # We have no configuration database - but perhaps we should (some
666 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500667 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800668
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800669 # Initialize the subject and issuer, if appropriate. ctx is a local,
670 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400671 # any references, so no need to mess with reference counts or
672 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800673 if issuer is not None:
674 if not isinstance(issuer, X509):
675 raise TypeError("issuer must be an X509 instance")
676 ctx.issuer_cert = issuer._x509
677 if subject is not None:
678 if not isinstance(subject, X509):
679 raise TypeError("subject must be an X509 instance")
680 ctx.subject_cert = subject._x509
681
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800682 if critical:
683 # There are other OpenSSL APIs which would let us pass in critical
684 # separately, but they're harder to use, and since value is already
685 # a pile of crappy junk smuggling a ton of utterly important
686 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400687 # with strings? (However, X509V3_EXT_i2d in particular seems like
688 # it would be a better API to invoke. I do not know where to get
689 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500690 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800691
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500692 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
693 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800694 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500695 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800696
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400697 @property
698 def _nid(self):
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400699 return _lib.OBJ_obj2nid(
700 _lib.X509_EXTENSION_get_object(self._extension)
701 )
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400702
703 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500704 _lib.GEN_EMAIL: "email",
705 _lib.GEN_DNS: "DNS",
706 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400707 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400708
709 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500710 method = _lib.X509V3_EXT_get(self._extension)
711 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500712 # TODO: This is untested.
713 _raise_current_error()
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400714 ext_data = _lib.X509_EXTENSION_get_data(self._extension)
715 payload = ext_data.data
716 length = ext_data.length
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400717
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500718 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400719 payloadptr[0] = payload
720
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500721 if method.it != _ffi.NULL:
722 ptr = _lib.ASN1_ITEM_ptr(method.it)
723 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
724 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400725 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500726 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400727 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500728 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400729
Paul Kehrerb7d79502015-05-04 07:43:51 -0500730 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400731 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500732 for i in range(_lib.sk_GENERAL_NAME_num(names)):
733 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400734 try:
735 label = self._prefixes[name.type]
736 except KeyError:
737 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500738 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500739 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400740 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500741 value = _native(
742 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
743 parts.append(label + ":" + value)
744 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400745
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800746 def __str__(self):
747 """
748 :return: a nice text representation of the extension
749 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500750 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400751 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800752
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400753 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500754 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800755 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500756 # TODO: This is untested.
757 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800758
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500759 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800760
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800761 def get_critical(self):
762 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200763 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800764
765 :return: The critical field.
766 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500767 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800768
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800769 def get_short_name(self):
770 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200771 Returns the short type name of this X.509 extension.
772
773 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800774
775 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200776 :rtype: :py:data:`bytes`
777
778 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800779 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500780 obj = _lib.X509_EXTENSION_get_object(self._extension)
781 nid = _lib.OBJ_obj2nid(obj)
782 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800783
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800784 def get_data(self):
785 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200786 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800787
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200788 :return: The ASN.1 encoded data of this X509 extension.
789 :rtype: :py:data:`bytes`
790
791 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800792 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500793 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
794 string_result = _ffi.cast('ASN1_STRING*', octet_result)
795 char_result = _lib.ASN1_STRING_data(string_result)
796 result_length = _lib.ASN1_STRING_length(string_result)
797 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800798
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200799
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800800X509ExtensionType = X509Extension
801
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800802
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800803class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200804 """
805 An X.509 certificate signing requests.
806 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400807
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800808 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500809 req = _lib.X509_REQ_new()
810 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800811
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800812 def set_pubkey(self, pkey):
813 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200814 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800815
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200816 :param pkey: The public key to use.
817 :type pkey: :py:class:`PKey`
818
Dan Sully44e767a2016-06-04 18:05:27 -0700819 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800820 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500821 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800822 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500823 # TODO: This is untested.
824 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800825
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800826 def get_pubkey(self):
827 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200828 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800829
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200830 :return: The public key.
831 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800832 """
833 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500834 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
835 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500836 # TODO: This is untested.
837 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500838 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800839 pkey._only_public = True
840 return pkey
841
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800842 def set_version(self, version):
843 """
844 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
845 request.
846
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200847 :param int version: The version number.
Dan Sully44e767a2016-06-04 18:05:27 -0700848 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800849 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500850 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800851 if not set_result:
852 _raise_current_error()
853
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854 def get_version(self):
855 """
856 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
857 request.
858
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200859 :return: The value of the version subfield.
860 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800861 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500862 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800863
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800864 def get_subject(self):
865 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200866 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800867
Cory Benfield881dc8d2015-12-09 08:25:14 +0000868 This creates a new :class:`X509Name` that wraps the underlying subject
869 name field on the certificate signing request. Modifying it will modify
870 the underlying signing request, and will have the effect of modifying
871 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200872
873 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000874 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800875 """
876 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500877 name._name = _lib.X509_REQ_get_subject_name(self._req)
878 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500879 # TODO: This is untested.
880 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800881
882 # The name is owned by the X509Req structure. As long as the X509Name
883 # Python object is alive, keep the X509Req Python object alive.
884 name._owner = self
885
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800886 return name
887
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800888 def add_extensions(self, extensions):
889 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200890 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800891
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200892 :param extensions: The X.509 extensions to add.
893 :type extensions: iterable of :py:class:`X509Extension`
Dan Sully44e767a2016-06-04 18:05:27 -0700894 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800895 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500896 stack = _lib.sk_X509_EXTENSION_new_null()
897 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500898 # TODO: This is untested.
899 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800900
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500901 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800902
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800903 for ext in extensions:
904 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800905 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800906
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800907 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500908 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800909
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500910 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800911 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500912 # TODO: This is untested.
913 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800914
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800915 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800916 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200917 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800918
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200919 :return: The X.509 extensions in this request.
920 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
921
922 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800923 """
924 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500925 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500926 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800927 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500928 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800929 exts.append(ext)
930 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800931
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800932 def sign(self, pkey, digest):
933 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700934 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800935
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200936 :param pkey: The key pair to sign with.
937 :type pkey: :py:class:`PKey`
938 :param digest: The name of the message digest to use for the signature,
939 e.g. :py:data:`b"sha1"`.
940 :type digest: :py:class:`bytes`
Dan Sully44e767a2016-06-04 18:05:27 -0700941 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800942 """
943 if pkey._only_public:
944 raise ValueError("Key has only public part")
945
946 if not pkey._initialized:
947 raise ValueError("Key is uninitialized")
948
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500949 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500950 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800951 raise ValueError("No such digest method")
952
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500953 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800954 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500955 # TODO: This is untested.
956 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800957
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800958 def verify(self, pkey):
959 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200960 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800961
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200962 :param key: A public key.
963 :type key: :py:class:`PKey`
964 :return: :py:data:`True` if the signature is correct.
965 :rtype: :py:class:`bool`
966 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800967 problem verifying the signature.
968 """
969 if not isinstance(pkey, PKey):
970 raise TypeError("pkey must be a PKey instance")
971
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500972 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800973 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500974 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800975
976 return result
977
978
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800979X509ReqType = X509Req
980
981
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800982class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200983 """
984 An X.509 certificate.
985 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400986
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800987 def __init__(self):
988 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500989 x509 = _lib.X509_new()
990 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800991
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800992 def set_version(self, version):
993 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200994 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800995
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200996 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800997 :type version: :py:class:`int`
998
Dan Sully44e767a2016-06-04 18:05:27 -0700999 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001000 """
1001 if not isinstance(version, int):
1002 raise TypeError("version must be an integer")
1003
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001004 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001005
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001006 def get_version(self):
1007 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001008 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001009
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001010 :return: The version number of the certificate.
1011 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001012 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001013 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001014
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001015 def get_pubkey(self):
1016 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001017 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001018
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001019 :return: The public key.
1020 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001021 """
1022 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001023 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1024 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001025 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001026 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001027 pkey._only_public = True
1028 return pkey
1029
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001030 def set_pubkey(self, pkey):
1031 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001032 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001033
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001034 :param pkey: The public key.
1035 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001036
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001037 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001038 """
1039 if not isinstance(pkey, PKey):
1040 raise TypeError("pkey must be a PKey instance")
1041
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001042 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001043 if not set_result:
1044 _raise_current_error()
1045
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001046 def sign(self, pkey, digest):
1047 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001048 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001049
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001050 :param pkey: The key to sign with.
1051 :type pkey: :py:class:`PKey`
1052
1053 :param digest: The name of the message digest to use.
1054 :type digest: :py:class:`bytes`
1055
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001056 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001057 """
1058 if not isinstance(pkey, PKey):
1059 raise TypeError("pkey must be a PKey instance")
1060
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001061 if pkey._only_public:
1062 raise ValueError("Key only has public part")
1063
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001064 if not pkey._initialized:
1065 raise ValueError("Key is uninitialized")
1066
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001067 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001068 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001069 raise ValueError("No such digest method")
1070
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001071 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001072 if not sign_result:
1073 _raise_current_error()
1074
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001075 def get_signature_algorithm(self):
1076 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001077 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001078
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001079 :return: The name of the algorithm.
1080 :rtype: :py:class:`bytes`
1081
1082 :raises ValueError: If the signature algorithm is undefined.
1083
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001084 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001085 """
Alex Gaynor39ea5312016-06-02 09:12:10 -07001086 algor = _lib.X509_get0_tbs_sigalg(self._x509)
1087 nid = _lib.OBJ_obj2nid(algor.algorithm)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001088 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001089 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001090 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001091
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001092 def digest(self, digest_name):
1093 """
1094 Return the digest of the X509 object.
1095
1096 :param digest_name: The name of the digest algorithm to use.
1097 :type digest_name: :py:class:`bytes`
1098
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001099 :return: The digest of the object, formatted as
1100 :py:const:`b":"`-delimited hex pairs.
1101 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001102 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001103 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001104 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001105 raise ValueError("No such digest method")
1106
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001107 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1108 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001109 result_length[0] = len(result_buffer)
1110
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001111 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001112 self._x509, digest, result_buffer, result_length)
1113
1114 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001115 # TODO: This is untested.
1116 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001117
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001118 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001119 b16encode(ch).upper() for ch
1120 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001121
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001122 def subject_name_hash(self):
1123 """
1124 Return the hash of the X509 subject.
1125
1126 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001127 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001128 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001129 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001130
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001131 def set_serial_number(self, serial):
1132 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001133 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001134
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001135 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001136 :type serial: :py:class:`int`
1137
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001138 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001139 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001140 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001141 raise TypeError("serial must be an integer")
1142
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001143 hex_serial = hex(serial)[2:]
1144 if not isinstance(hex_serial, bytes):
1145 hex_serial = hex_serial.encode('ascii')
1146
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001147 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001148
1149 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001150 # it. If bignum is still NULL after this call, then the return value
1151 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001152 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001153
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001154 if bignum_serial[0] == _ffi.NULL:
1155 set_result = _lib.ASN1_INTEGER_set(
1156 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001157 if set_result:
1158 # TODO Not tested
1159 _raise_current_error()
1160 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001161 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1162 _lib.BN_free(bignum_serial[0])
1163 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001164 # TODO Not tested
1165 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001166 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1167 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001168 if not set_result:
1169 # TODO Not tested
1170 _raise_current_error()
1171
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001172 def get_serial_number(self):
1173 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001174 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001175
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001176 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001177 :rtype: int
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001178 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001179 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1180 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001181 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001182 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001183 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001184 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001185 serial = int(hexstring_serial, 16)
1186 return serial
1187 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001188 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001189 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001190 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001191
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001192 def gmtime_adj_notAfter(self, amount):
1193 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001194 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001195
Dan Sully44e767a2016-06-04 18:05:27 -07001196 :param int amount: The number of seconds by which to adjust the
1197 timestamp.
1198 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001199 """
1200 if not isinstance(amount, int):
1201 raise TypeError("amount must be an integer")
1202
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001203 notAfter = _lib.X509_get_notAfter(self._x509)
1204 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001205
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001206 def gmtime_adj_notBefore(self, amount):
1207 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001208 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001209
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001210 :param amount: The number of seconds by which to adjust the timestamp.
Dan Sully44e767a2016-06-04 18:05:27 -07001211 :return: ``None``
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001212 """
1213 if not isinstance(amount, int):
1214 raise TypeError("amount must be an integer")
1215
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001216 notBefore = _lib.X509_get_notBefore(self._x509)
1217 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001218
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001219 def has_expired(self):
1220 """
1221 Check whether the certificate has expired.
1222
Dan Sully44e767a2016-06-04 18:05:27 -07001223 :return: ``True`` if the certificate has expired, ``False`` otherwise.
1224 :rtype: bool
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001225 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001226 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001227 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001228
Paul Kehrerfde45c92016-01-21 12:57:37 -06001229 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001230
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001231 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001232 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001233
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001234 def get_notBefore(self):
1235 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001236 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001237
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001238 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001239
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001240 YYYYMMDDhhmmssZ
1241 YYYYMMDDhhmmss+hhmm
1242 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001243
Dan Sully44e767a2016-06-04 18:05:27 -07001244 :return: A timestamp string, or ``None`` if there is none.
1245 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001246 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001247 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001248
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001249 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001250 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001251
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001252 def set_notBefore(self, when):
1253 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001254 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001255
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001256 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001257
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001258 YYYYMMDDhhmmssZ
1259 YYYYMMDDhhmmss+hhmm
1260 YYYYMMDDhhmmss-hhmm
1261
Dan Sully44e767a2016-06-04 18:05:27 -07001262 :param bytes when: A timestamp string.
1263 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001264 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001265 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001266
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001267 def get_notAfter(self):
1268 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001269 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001270
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001271 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001272
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001273 YYYYMMDDhhmmssZ
1274 YYYYMMDDhhmmss+hhmm
1275 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001276
Dan Sully44e767a2016-06-04 18:05:27 -07001277 :return: A timestamp string, or ``None`` if there is none.
1278 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001279 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001280 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001281
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001282 def set_notAfter(self, when):
1283 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001284 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001285
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001286 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001287
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001288 YYYYMMDDhhmmssZ
1289 YYYYMMDDhhmmss+hhmm
1290 YYYYMMDDhhmmss-hhmm
1291
Dan Sully44e767a2016-06-04 18:05:27 -07001292 :param bytes when: A timestamp string.
1293 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001294 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001295 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001296
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001297 def _get_name(self, which):
1298 name = X509Name.__new__(X509Name)
1299 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001300 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001301 # TODO: This is untested.
1302 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001303
1304 # The name is owned by the X509 structure. As long as the X509Name
1305 # Python object is alive, keep the X509 Python object alive.
1306 name._owner = self
1307
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001308 return name
1309
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001310 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001311 if not isinstance(name, X509Name):
1312 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001313 set_result = which(self._x509, name._name)
1314 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001315 # TODO: This is untested.
1316 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001317
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001318 def get_issuer(self):
1319 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001320 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001321
Cory Benfielde6bcce82015-12-09 08:40:03 +00001322 This creates a new :class:`X509Name` that wraps the underlying issuer
1323 name field on the certificate. Modifying it will modify the underlying
1324 certificate, and will have the effect of modifying any other
1325 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001326
1327 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001328 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001329 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001330 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001331
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001332 def set_issuer(self, issuer):
1333 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001334 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001335
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001336 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001337 :type issuer: :py:class:`X509Name`
1338
Dan Sully44e767a2016-06-04 18:05:27 -07001339 :return: ``None``
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001340 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001341 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001342
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001343 def get_subject(self):
1344 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001345 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001346
Cory Benfielde6bcce82015-12-09 08:40:03 +00001347 This creates a new :class:`X509Name` that wraps the underlying subject
1348 name field on the certificate. Modifying it will modify the underlying
1349 certificate, and will have the effect of modifying any other
1350 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001351
1352 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001353 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001354 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001355 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001356
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001357 def set_subject(self, subject):
1358 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001359 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001360
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001361 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001362 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001363
Dan Sully44e767a2016-06-04 18:05:27 -07001364 :return: ``None``
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001365 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001366 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001367
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001368 def get_extension_count(self):
1369 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001370 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001371
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001372 :return: The number of extensions.
1373 :rtype: :py:class:`int`
1374
1375 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001376 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001377 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001378
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001379 def add_extensions(self, extensions):
1380 """
1381 Add extensions to the certificate.
1382
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001383 :param extensions: The extensions to add.
1384 :type extensions: An iterable of :py:class:`X509Extension` objects.
Dan Sully44e767a2016-06-04 18:05:27 -07001385 :return: ``None``
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001386 """
1387 for ext in extensions:
1388 if not isinstance(ext, X509Extension):
1389 raise ValueError("One of the elements is not an X509Extension")
1390
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001391 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001392 if not add_result:
1393 _raise_current_error()
1394
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001395 def get_extension(self, index):
1396 """
1397 Get a specific extension of the certificate by index.
1398
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001399 Extensions on a certificate are kept in order. The index
1400 parameter selects which extension will be returned.
1401
1402 :param int index: The index of the extension to retrieve.
1403 :return: The extension at the specified index.
1404 :rtype: :py:class:`X509Extension`
1405 :raises IndexError: If the extension index was out of bounds.
1406
1407 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001408 """
1409 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001410 ext._extension = _lib.X509_get_ext(self._x509, index)
1411 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001412 raise IndexError("extension index out of bounds")
1413
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001414 extension = _lib.X509_EXTENSION_dup(ext._extension)
1415 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001416 return ext
1417
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001418
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001419X509Type = X509
1420
1421
Dan Sully44e767a2016-06-04 18:05:27 -07001422class X509StoreFlags(object):
1423 """
1424 Flags for X509 verification, used to change the behavior of
1425 :class:`X509Store`.
1426
1427 See `OpenSSL Verification Flags`_ for details.
1428
1429 .. _OpenSSL Verification Flags:
1430 https://www.openssl.org/docs/manmaster/crypto/X509_VERIFY_PARAM_set_flags.html
1431 """
1432 CRL_CHECK = _lib.X509_V_FLAG_CRL_CHECK
1433 CRL_CHECK_ALL = _lib.X509_V_FLAG_CRL_CHECK_ALL
1434 IGNORE_CRITICAL = _lib.X509_V_FLAG_IGNORE_CRITICAL
1435 X509_STRICT = _lib.X509_V_FLAG_X509_STRICT
1436 ALLOW_PROXY_CERTS = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS
1437 POLICY_CHECK = _lib.X509_V_FLAG_POLICY_CHECK
1438 EXPLICIT_POLICY = _lib.X509_V_FLAG_EXPLICIT_POLICY
1439 INHIBIT_MAP = _lib.X509_V_FLAG_INHIBIT_MAP
1440 NOTIFY_POLICY = _lib.X509_V_FLAG_NOTIFY_POLICY
1441 CHECK_SS_SIGNATURE = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE
1442 CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK
1443
1444
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001445class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001446 """
Dan Sully44e767a2016-06-04 18:05:27 -07001447 An X.509 store.
1448
1449 An X.509 store is used to describe a context in which to verify a
1450 certificate. A description of a context may include a set of certificates
1451 to trust, a set of certificate revocation lists, verification flags and
1452 more.
1453
1454 An X.509 store, being only a description, cannot be used by itself to
1455 verify a certificate. To carry out the actual verification process, see
1456 :class:`X509StoreContext`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001457 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001458
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001459 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001460 store = _lib.X509_STORE_new()
1461 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001462
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001463 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001464 """
Dan Sully44e767a2016-06-04 18:05:27 -07001465 Adds a trusted certificate to this store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001466
Dan Sully44e767a2016-06-04 18:05:27 -07001467 Adding a certificate with this method adds this certificate as a
1468 *trusted* certificate.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001469
1470 :param X509 cert: The certificate to add to this store.
Dan Sully44e767a2016-06-04 18:05:27 -07001471 :raises TypeError: If the certificate is not an :class:`X509`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001472 :raises Error: If OpenSSL was unhappy with your certificate.
Dan Sully44e767a2016-06-04 18:05:27 -07001473 :return: ``None`` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001474 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001475 if not isinstance(cert, X509):
1476 raise TypeError()
1477
Dan Sully44e767a2016-06-04 18:05:27 -07001478 _openssl_assert(_lib.X509_STORE_add_cert(self._store, cert._x509) != 0)
1479
1480 def add_crl(self, crl):
1481 """
1482 Add a certificate revocation list to this store.
1483
1484 The certificate revocation lists added to a store will only be used if
1485 the associated flags are configured to check certificate revocation
1486 lists.
1487
1488 .. versionadded:: 16.1.0
1489
1490 :param CRL crl: The certificate revocation list to add to this store.
1491 :return: ``None`` if the certificate revocation list was added
1492 successfully.
1493 """
1494 _openssl_assert(_lib.X509_STORE_add_crl(self._store, crl._crl) != 0)
1495
1496 def set_flags(self, flags):
1497 """
1498 Set verification flags to this store.
1499
1500 Verification flags can be combined by oring them together.
1501
1502 .. note::
1503
1504 Setting a verification flag sometimes requires clients to add
1505 additional information to the store, otherwise a suitable error will
1506 be raised.
1507
1508 For example, in setting flags to enable CRL checking a
1509 suitable CRL must be added to the store otherwise an error will be
1510 raised.
1511
1512 .. versionadded:: 16.1.0
1513
1514 :param int flags: The verification flags to set on this store.
1515 See :class:`X509StoreFlags` for available constants.
1516 :return: ``None`` if the verification flags were successfully set.
1517 """
1518 _openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0)
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001519
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001520
1521X509StoreType = X509Store
1522
1523
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001524class X509StoreContextError(Exception):
1525 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001526 An exception raised when an error occurred while verifying a certificate
1527 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001528
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001529 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001530 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001531 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001532
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001533 def __init__(self, message, certificate):
1534 super(X509StoreContextError, self).__init__(message)
1535 self.certificate = certificate
1536
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001537
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001538class X509StoreContext(object):
1539 """
1540 An X.509 store context.
1541
Dan Sully44e767a2016-06-04 18:05:27 -07001542 An X.509 store context is used to carry out the actual verification process
1543 of a certificate in a described context. For describing such a context, see
1544 :class:`X509Store`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001545
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001546 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1547 instance. It is dynamically allocated and automatically garbage
1548 collected.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001549 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001550 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001551 :param X509Store store: The certificates which will be trusted for the
1552 purposes of any verifications.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001553 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001554 """
1555
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001556 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001557 store_ctx = _lib.X509_STORE_CTX_new()
1558 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1559 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001560 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001561 # Make the store context available for use after instantiating this
1562 # class by initializing it now. Per testing, subsequent calls to
Dan Sully44e767a2016-06-04 18:05:27 -07001563 # :meth:`_init` have no adverse affect.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001564 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001565
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001566 def _init(self):
1567 """
1568 Set up the store context for a subsequent verification operation.
1569 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001570 ret = _lib.X509_STORE_CTX_init(
1571 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1572 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001573 if ret <= 0:
1574 _raise_current_error()
1575
1576 def _cleanup(self):
1577 """
1578 Internally cleans up the store context.
1579
Dan Sully44e767a2016-06-04 18:05:27 -07001580 The store context can then be reused with a new call to :meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001581 """
1582 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1583
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001584 def _exception_from_context(self):
1585 """
1586 Convert an OpenSSL native context error failure into a Python
1587 exception.
1588
Alex Gaynor5945ea82015-09-05 14:59:06 -04001589 When a call to native OpenSSL X509_verify_cert fails, additional
1590 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001591 """
1592 errors = [
1593 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1594 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1595 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001596 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001597 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001598 # A context error should always be associated with a certificate, so we
1599 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001600 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001601 _cert = _lib.X509_dup(_x509)
1602 pycert = X509.__new__(X509)
1603 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001604 return X509StoreContextError(errors, pycert)
1605
Stephen Holsapple46a09252015-02-12 14:45:43 -08001606 def set_store(self, store):
1607 """
Dan Sully44e767a2016-06-04 18:05:27 -07001608 Set the context's X.509 store.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001609
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001610 .. versionadded:: 0.15
1611
Dan Sully44e767a2016-06-04 18:05:27 -07001612 :param X509Store store: The store description which will be used for
1613 the purposes of any *future* verifications.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001614 """
1615 self._store = store
1616
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001617 def verify_certificate(self):
1618 """
1619 Verify a certificate in a context.
1620
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001621 .. versionadded:: 0.15
1622
Alex Gaynorca87ff62015-09-04 23:31:03 -04001623 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001624 certificate in the context. Sets ``certificate`` attribute to
1625 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001626 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001627 # Always re-initialize the store context in case
Dan Sully44e767a2016-06-04 18:05:27 -07001628 # :meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001629 self._init()
1630 ret = _lib.X509_verify_cert(self._store_ctx)
1631 self._cleanup()
1632 if ret <= 0:
1633 raise self._exception_from_context()
1634
1635
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001636def load_certificate(type, buffer):
1637 """
1638 Load a certificate from a buffer
1639
1640 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1641
Dan Sully44e767a2016-06-04 18:05:27 -07001642 :param bytes buffer: The buffer the certificate is stored in
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001643
1644 :return: The X509 object
1645 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001646 if isinstance(buffer, _text_type):
1647 buffer = buffer.encode("ascii")
1648
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001649 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001650
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001651 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001652 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001653 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001654 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001655 else:
1656 raise ValueError(
1657 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001658
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001659 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001660 _raise_current_error()
1661
1662 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001663 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001664 return cert
1665
1666
1667def dump_certificate(type, cert):
1668 """
1669 Dump a certificate to a buffer
1670
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001671 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1672 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001673 :param cert: The certificate to dump
1674 :return: The buffer with the dumped certificate in
1675 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001676 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001677
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001678 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001679 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001680 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001681 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001682 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001683 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001684 else:
1685 raise ValueError(
1686 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1687 "FILETYPE_TEXT")
1688
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001689 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001690 return _bio_to_string(bio)
1691
1692
Cory Benfield6492f7c2015-10-27 16:57:58 +09001693def dump_publickey(type, pkey):
1694 """
Cory Benfield11c10192015-10-27 17:23:03 +09001695 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001696
Cory Benfield9c590b92015-10-28 14:55:05 +09001697 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001698 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001699 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001700 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001701 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001702 """
1703 bio = _new_mem_buf()
1704 if type == FILETYPE_PEM:
1705 write_bio = _lib.PEM_write_bio_PUBKEY
1706 elif type == FILETYPE_ASN1:
1707 write_bio = _lib.i2d_PUBKEY_bio
1708 else:
1709 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1710
1711 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001712 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001713 _raise_current_error()
1714
1715 return _bio_to_string(bio)
1716
1717
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001718def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1719 """
1720 Dump a private key to a buffer
1721
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001722 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1723 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001724 :param pkey: The PKey to dump
1725 :param cipher: (optional) if encrypted PEM format, the cipher to
1726 use
1727 :param passphrase: (optional) if encrypted PEM format, this can be either
1728 the passphrase to use, or a callback for providing the
1729 passphrase.
1730 :return: The buffer with the dumped key in
Dan Sully44e767a2016-06-04 18:05:27 -07001731 :rtype: bytes
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001732 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001733 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001734
1735 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001736 if passphrase is None:
1737 raise TypeError(
1738 "if a value is given for cipher "
1739 "one must also be given for passphrase")
1740 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001741 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001742 raise ValueError("Invalid cipher name")
1743 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001744 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001745
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001746 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001747 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001748 result_code = _lib.PEM_write_bio_PrivateKey(
1749 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001750 helper.callback, helper.callback_args)
1751 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001752 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001753 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001754 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001755 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1756 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001757 # TODO RSA_free(rsa)?
1758 else:
1759 raise ValueError(
1760 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1761 "FILETYPE_TEXT")
1762
1763 if result_code == 0:
1764 _raise_current_error()
1765
1766 return _bio_to_string(bio)
1767
1768
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001769class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001770 """
1771 A certificate revocation.
1772 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001773 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1774 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1775 # OCSP_crl_reason_str. We use the latter, just like the command line
1776 # program.
1777 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001778 b"unspecified",
1779 b"keyCompromise",
1780 b"CACompromise",
1781 b"affiliationChanged",
1782 b"superseded",
1783 b"cessationOfOperation",
1784 b"certificateHold",
1785 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001786 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001787
1788 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001789 revoked = _lib.X509_REVOKED_new()
1790 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001791
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001792 def set_serial(self, hex_str):
1793 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001794 Set the serial number.
1795
1796 The serial number is formatted as a hexadecimal number encoded in
1797 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001798
Dan Sully44e767a2016-06-04 18:05:27 -07001799 :param bytes hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001800
Dan Sully44e767a2016-06-04 18:05:27 -07001801 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001802 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001803 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1804 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001805 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001806 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807 if not bn_result:
1808 raise ValueError("bad hex string")
1809
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001810 asn1_serial = _ffi.gc(
1811 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1812 _lib.ASN1_INTEGER_free)
1813 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001814
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001815 def get_serial(self):
1816 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001817 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001818
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001819 The serial number is formatted as a hexadecimal number encoded in
1820 ASCII.
1821
1822 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001823 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001824 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001825 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001826
Alex Gaynor67903a62016-06-02 10:37:13 -07001827 asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked)
1828 _openssl_assert(asn1_int != _ffi.NULL)
1829 result = _lib.i2a_ASN1_INTEGER(bio, asn1_int)
1830 _openssl_assert(result >= 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001831 return _bio_to_string(bio)
1832
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001833 def _delete_reason(self):
Alex Gaynor67903a62016-06-02 10:37:13 -07001834 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1835 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001836 obj = _lib.X509_EXTENSION_get_object(ext)
1837 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001838 _lib.X509_EXTENSION_free(ext)
Alex Gaynor67903a62016-06-02 10:37:13 -07001839 _lib.X509_REVOKED_delete_ext(self._revoked, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001840 break
1841
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001842 def set_reason(self, reason):
1843 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001844 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001845
Dan Sully44e767a2016-06-04 18:05:27 -07001846 If :data:`reason` is ``None``, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001847
1848 :param reason: The reason string.
Dan Sully44e767a2016-06-04 18:05:27 -07001849 :type reason: :class:`bytes` or :class:`NoneType`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001850
Dan Sully44e767a2016-06-04 18:05:27 -07001851 :return: ``None``
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001852
1853 .. seealso::
1854
Dan Sully44e767a2016-06-04 18:05:27 -07001855 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001856 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001857 """
1858 if reason is None:
1859 self._delete_reason()
1860 elif not isinstance(reason, bytes):
1861 raise TypeError("reason must be None or a byte string")
1862 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001863 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001864 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1865
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001866 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1867 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001868 # TODO: This is untested.
1869 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001870 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001871
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001872 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1873 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001874 # TODO: This is untested.
1875 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001876
1877 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001878 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1879 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001880
1881 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001882 # TODO: This is untested.
1883 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001884
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001885 def get_reason(self):
1886 """
Alex Gaynor80262fb2016-04-22 07:53:42 -04001887 Get the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001888
Dan Sully44e767a2016-06-04 18:05:27 -07001889 :return: The reason, or ``None`` if there is none.
1890 :rtype: bytes or NoneType
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001891
1892 .. seealso::
1893
Dan Sully44e767a2016-06-04 18:05:27 -07001894 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001895 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001896 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001897 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1898 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001899 obj = _lib.X509_EXTENSION_get_object(ext)
1900 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001901 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001902
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001903 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001904 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001905 print_result = _lib.M_ASN1_OCTET_STRING_print(
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001906 bio, _lib.X509_EXTENSION_get_data(ext)
Alex Gaynor5945ea82015-09-05 14:59:06 -04001907 )
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001908 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001909 # TODO: This is untested.
1910 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001911
1912 return _bio_to_string(bio)
1913
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001914 def all_reasons(self):
1915 """
1916 Return a list of all the supported reason strings.
1917
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001918 This list is a copy; modifying it does not change the supported reason
1919 strings.
1920
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001921 :return: A list of reason strings.
Dan Sully44e767a2016-06-04 18:05:27 -07001922 :rtype: :class:`list` of :class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001923 """
1924 return self._crl_reasons[:]
1925
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001926 def set_rev_date(self, when):
1927 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001928 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001929
Dan Sully44e767a2016-06-04 18:05:27 -07001930 :param bytes when: The timestamp of the revocation,
1931 as ASN.1 GENERALIZEDTIME.
1932 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001933 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001934 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1935 return _set_asn1_time(dt, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001936
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001937 def get_rev_date(self):
1938 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001939 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001940
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001941 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
Dan Sully44e767a2016-06-04 18:05:27 -07001942 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001943 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001944 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1945 return _get_asn1_time(dt)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001946
1947
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001948class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001949 """
1950 A certificate revocation list.
1951 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001952
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001953 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001954 crl = _lib.X509_CRL_new()
1955 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001956
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001957 def get_revoked(self):
1958 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001959 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001960
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001961 These revocations will be provided by value, not by reference.
1962 That means it's okay to mutate them: it won't affect this CRL.
1963
1964 :return: The revocations in this CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07001965 :rtype: :class:`tuple` of :class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001966 """
1967 results = []
Alex Gaynor67903a62016-06-02 10:37:13 -07001968 revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001969 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1970 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Paul Kehrer2fe23b02016-03-09 22:02:15 -04001971 revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001972 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001973 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001974 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001975 if results:
1976 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001977
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001978 def add_revoked(self, revoked):
1979 """
1980 Add a revoked (by value not reference) to the CRL structure
1981
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001982 This revocation will be added by value, not by reference. That
1983 means it's okay to mutate it after adding: it won't affect
1984 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001985
Dan Sully44e767a2016-06-04 18:05:27 -07001986 :param Revoked revoked: The new revocation.
1987 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001988 """
Paul Kehrer8dddb1a2016-03-09 21:48:04 -04001989 copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001990 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001991 # TODO: This is untested.
1992 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001993
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001994 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001995 if add_result == 0:
1996 # TODO: This is untested.
1997 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001998
Dan Sully44e767a2016-06-04 18:05:27 -07001999 def get_issuer(self):
2000 """
2001 Get the CRL's issuer.
2002
2003 .. versionadded:: 16.1.0
2004
2005 :rtype: X509Name
2006 """
2007 _issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl))
2008 _openssl_assert(_issuer != _ffi.NULL)
2009 _issuer = _ffi.gc(_issuer, _lib.X509_NAME_free)
2010 issuer = X509Name.__new__(X509Name)
2011 issuer._name = _issuer
2012 return issuer
2013
2014 def set_version(self, version):
2015 """
2016 Set the CRL version.
2017
2018 .. versionadded:: 16.1.0
2019
2020 :param int version: The version of the CRL.
2021 :return: ``None``
2022 """
2023 _openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0)
2024
2025 def _set_boundary_time(self, which, when):
2026 return _set_asn1_time(which(self._crl), when)
2027
2028 def set_lastUpdate(self, when):
2029 """
2030 Set when the CRL was last updated.
2031
2032 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2033
2034 YYYYMMDDhhmmssZ
2035 YYYYMMDDhhmmss+hhmm
2036 YYYYMMDDhhmmss-hhmm
2037
2038 .. versionadded:: 16.1.0
2039
2040 :param bytes when: A timestamp string.
2041 :return: ``None``
2042 """
2043 return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when)
2044
2045 def set_nextUpdate(self, when):
2046 """
2047 Set when the CRL will next be udpated.
2048
2049 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2050
2051 YYYYMMDDhhmmssZ
2052 YYYYMMDDhhmmss+hhmm
2053 YYYYMMDDhhmmss-hhmm
2054
2055 .. versionadded:: 16.1.0
2056
2057 :param bytes when: A timestamp string.
2058 :return: ``None``
2059 """
2060 return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when)
2061
2062 def sign(self, issuer_cert, issuer_key, digest):
2063 """
2064 Sign the CRL.
2065
2066 Signing a CRL enables clients to associate the CRL itself with an
2067 issuer. Before a CRL is meaningful to other OpenSSL functions, it must
2068 be signed by an issuer.
2069
2070 This method implicitly sets the issuer's name based on the issuer
2071 certificate and private key used to sign the CRL.
2072
2073 .. versionadded:: 16.1.0
2074
2075 :param X509 issuer_cert: The issuer's certificate.
2076 :param PKey issuer_key: The issuer's private key.
2077 :param bytes digest: The digest method to sign the CRL with.
2078 """
2079 digest_obj = _lib.EVP_get_digestbyname(digest)
2080 _openssl_assert(digest_obj != _ffi.NULL)
2081 _lib.X509_CRL_set_issuer_name(
2082 self._crl, _lib.X509_get_subject_name(issuer_cert._x509))
2083 _lib.X509_CRL_sort(self._crl)
2084 result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj)
2085 _openssl_assert(result != 0)
2086
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002087 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002088 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002089 """
Dan Sully44e767a2016-06-04 18:05:27 -07002090 Export the CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002091
Dan Sully44e767a2016-06-04 18:05:27 -07002092 :param X509 cert: The certificate used to sign the CRL.
2093 :param PKey key: The key used to sign the CRL.
2094 :param int type: The export format, either :data:`FILETYPE_PEM`,
2095 :data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`.
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002096 :param int days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002097 :param bytes digest: The name of the message digest to use (eg
2098 ``b"sha1"``).
Dan Sully44e767a2016-06-04 18:05:27 -07002099 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002100 """
Dan Sully44e767a2016-06-04 18:05:27 -07002101
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002102 if not isinstance(cert, X509):
2103 raise TypeError("cert must be an X509 instance")
2104 if not isinstance(key, PKey):
2105 raise TypeError("key must be a PKey instance")
2106 if not isinstance(type, int):
2107 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002108
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002109 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002110 _warn(
2111 "The default message digest (md5) is deprecated. "
2112 "Pass the name of a message digest explicitly.",
2113 category=DeprecationWarning,
2114 stacklevel=2,
2115 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002116 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002117
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002118 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002119 if digest_obj == _ffi.NULL:
2120 raise ValueError("No such digest method")
2121
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002122 bio = _lib.BIO_new(_lib.BIO_s_mem())
2123 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002124 # TODO: This is untested.
2125 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002126
Alex Gaynora738ed52015-09-05 11:17:10 -04002127 # A scratch time object to give different values to different CRL
2128 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002129 sometime = _lib.ASN1_TIME_new()
2130 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002131 # TODO: This is untested.
2132 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002133
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002134 _lib.X509_gmtime_adj(sometime, 0)
2135 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002136
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002137 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2138 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002139
Alex Gaynor5945ea82015-09-05 14:59:06 -04002140 _lib.X509_CRL_set_issuer_name(
2141 self._crl, _lib.X509_get_subject_name(cert._x509)
2142 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002143
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002144 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002145 if not sign_result:
2146 _raise_current_error()
2147
Dominic Chenf05b2122015-10-13 16:32:35 +00002148 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002149
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002150
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002151CRLType = CRL
2152
2153
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002154class PKCS7(object):
2155 def type_is_signed(self):
2156 """
2157 Check if this NID_pkcs7_signed object
2158
2159 :return: True if the PKCS7 is of type signed
2160 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002161 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002162 return True
2163 return False
2164
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002165 def type_is_enveloped(self):
2166 """
2167 Check if this NID_pkcs7_enveloped object
2168
2169 :returns: True if the PKCS7 is of type enveloped
2170 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002171 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002172 return True
2173 return False
2174
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002175 def type_is_signedAndEnveloped(self):
2176 """
2177 Check if this NID_pkcs7_signedAndEnveloped object
2178
2179 :returns: True if the PKCS7 is of type signedAndEnveloped
2180 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002181 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002182 return True
2183 return False
2184
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002185 def type_is_data(self):
2186 """
2187 Check if this NID_pkcs7_data object
2188
2189 :return: True if the PKCS7 is of type data
2190 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002191 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002192 return True
2193 return False
2194
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002195 def get_type_name(self):
2196 """
2197 Returns the type name of the PKCS7 structure
2198
2199 :return: A string with the typename
2200 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002201 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2202 string_type = _lib.OBJ_nid2sn(nid)
2203 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002204
2205PKCS7Type = PKCS7
2206
2207
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002208class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002209 """
2210 A PKCS #12 archive.
2211 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002212
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002213 def __init__(self):
2214 self._pkey = None
2215 self._cert = None
2216 self._cacerts = None
2217 self._friendlyname = None
2218
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002219 def get_certificate(self):
2220 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002221 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002222
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002223 :return: The certificate, or :py:const:`None` if there is none.
2224 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002225 """
2226 return self._cert
2227
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002228 def set_certificate(self, cert):
2229 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002230 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002231
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002232 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002233 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002234
Dan Sully44e767a2016-06-04 18:05:27 -07002235 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002236 """
2237 if not isinstance(cert, X509):
2238 raise TypeError("cert must be an X509 instance")
2239 self._cert = cert
2240
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002241 def get_privatekey(self):
2242 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002243 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002244
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002245 :return: The private key, or :py:const:`None` if there is none.
2246 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002247 """
2248 return self._pkey
2249
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002250 def set_privatekey(self, pkey):
2251 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002252 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002253
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002254 :param pkey: The new private key, or :py:const:`None` to unset it.
2255 :type pkey: :py:class:`PKey` or :py:const:`None`
2256
Dan Sully44e767a2016-06-04 18:05:27 -07002257 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002258 """
2259 if not isinstance(pkey, PKey):
2260 raise TypeError("pkey must be a PKey instance")
2261 self._pkey = pkey
2262
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002263 def get_ca_certificates(self):
2264 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002265 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002266
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002267 :return: A tuple with the CA certificates in the chain, or
2268 :py:const:`None` if there are none.
2269 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002270 """
2271 if self._cacerts is not None:
2272 return tuple(self._cacerts)
2273
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002274 def set_ca_certificates(self, cacerts):
2275 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002276 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002277
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002278 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2279 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002280 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002281
Dan Sully44e767a2016-06-04 18:05:27 -07002282 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002283 """
2284 if cacerts is None:
2285 self._cacerts = None
2286 else:
2287 cacerts = list(cacerts)
2288 for cert in cacerts:
2289 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002290 raise TypeError(
2291 "iterable must only contain X509 instances"
2292 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002293 self._cacerts = cacerts
2294
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002295 def set_friendlyname(self, name):
2296 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002297 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002298
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002299 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002300 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002301
Dan Sully44e767a2016-06-04 18:05:27 -07002302 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002303 """
2304 if name is None:
2305 self._friendlyname = None
2306 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002307 raise TypeError(
2308 "name must be a byte string or None (not %r)" % (name,)
2309 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002310 self._friendlyname = name
2311
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002312 def get_friendlyname(self):
2313 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002314 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002315
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002316 :returns: The friendly name, or :py:const:`None` if there is none.
2317 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002318 """
2319 return self._friendlyname
2320
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002321 def export(self, passphrase=None, iter=2048, maciter=1):
2322 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002323 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002324
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002325 For more information, see the :c:func:`PKCS12_create` man page.
2326
2327 :param passphrase: The passphrase used to encrypt the structure. Unlike
2328 some other passphrase arguments, this *must* be a string, not a
2329 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002330 :type passphrase: :py:data:`bytes`
2331
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002332 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002333 :type iter: :py:data:`int`
2334
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002335 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002336 :type maciter: :py:data:`int`
2337
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002338 :return: The string representation of the PKCS #12 structure.
2339 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002340 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002341 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002342
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002343 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002344 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002345 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002346 cacerts = _lib.sk_X509_new_null()
2347 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002348 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002349 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002350
2351 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002352 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002353
2354 friendlyname = self._friendlyname
2355 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002356 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002357
2358 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002359 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002360 else:
2361 pkey = self._pkey._pkey
2362
2363 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002364 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002365 else:
2366 cert = self._cert._x509
2367
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002368 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002369 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002370 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2371 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002372 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002373 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002374 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002375 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002376
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002377 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002378 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002379 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002380
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002381
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002382PKCS12Type = PKCS12
2383
2384
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002385class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002386 """
2387 A Netscape SPKI object.
2388 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002389
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002390 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002391 spki = _lib.NETSCAPE_SPKI_new()
2392 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002393
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002394 def sign(self, pkey, digest):
2395 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002396 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002397
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002398 :param pkey: The private key to sign with.
2399 :type pkey: :py:class:`PKey`
2400
2401 :param digest: The message digest to use.
2402 :type digest: :py:class:`bytes`
2403
Dan Sully44e767a2016-06-04 18:05:27 -07002404 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002405 """
2406 if pkey._only_public:
2407 raise ValueError("Key has only public part")
2408
2409 if not pkey._initialized:
2410 raise ValueError("Key is uninitialized")
2411
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002412 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002413 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002414 raise ValueError("No such digest method")
2415
Alex Gaynor5945ea82015-09-05 14:59:06 -04002416 sign_result = _lib.NETSCAPE_SPKI_sign(
2417 self._spki, pkey._pkey, digest_obj
2418 )
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002419 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002420 # TODO: This is untested.
2421 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002422
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002423 def verify(self, key):
2424 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002425 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002426
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002427 :param key: The public key that signature is supposedly from.
2428 :type pkey: :py:class:`PKey`
2429
2430 :return: :py:const:`True` if the signature is correct.
2431 :rtype: :py:class:`bool`
2432
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002433 :raises Error: If the signature is invalid, or there was a problem
2434 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002435 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002436 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002437 if answer <= 0:
2438 _raise_current_error()
2439 return True
2440
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002441 def b64_encode(self):
2442 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002443 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002444
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002445 :return: The base64 encoded string.
2446 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002447 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002448 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2449 result = _ffi.string(encoded)
Paul Kehrer0dcacf72016-03-17 19:25:39 -04002450 _lib.OPENSSL_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002451 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002452
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002453 def get_pubkey(self):
2454 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002455 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002456
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002457 :return: The public key.
2458 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002459 """
2460 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002461 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2462 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002463 # TODO: This is untested.
2464 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002465 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002466 pkey._only_public = True
2467 return pkey
2468
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002469 def set_pubkey(self, pkey):
2470 """
2471 Set the public key of the certificate
2472
2473 :param pkey: The public key
Dan Sully44e767a2016-06-04 18:05:27 -07002474 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002475 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002476 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002477 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002478 # TODO: This is untested.
2479 _raise_current_error()
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002480
2481
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002482NetscapeSPKIType = NetscapeSPKI
2483
2484
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002485class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002486 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002487 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002488 raise ValueError(
2489 "only FILETYPE_PEM key format supports encryption"
2490 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002491 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002492 self._more_args = more_args
2493 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002494 self._problems = []
2495
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002496 @property
2497 def callback(self):
2498 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002499 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002500 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002501 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002502 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002503 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002504 else:
2505 raise TypeError("Last argument must be string or callable")
2506
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002507 @property
2508 def callback_args(self):
2509 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002510 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002511 elif isinstance(self._passphrase, bytes):
2512 return self._passphrase
2513 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002514 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002515 else:
2516 raise TypeError("Last argument must be string or callable")
2517
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002518 def raise_if_problem(self, exceptionType=Error):
2519 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002520 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002521 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002522 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002523 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002524 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002525 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002526
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002527 def _read_passphrase(self, buf, size, rwflag, userdata):
2528 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002529 if self._more_args:
2530 result = self._passphrase(size, rwflag, userdata)
2531 else:
2532 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002533 if not isinstance(result, bytes):
2534 raise ValueError("String expected")
2535 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002536 if self._truncate:
2537 result = result[:size]
2538 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002539 raise ValueError(
2540 "passphrase returned by callback is too long"
2541 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002542 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002543 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002544 return len(result)
2545 except Exception as e:
2546 self._problems.append(e)
2547 return 0
2548
2549
Cory Benfield6492f7c2015-10-27 16:57:58 +09002550def load_publickey(type, buffer):
2551 """
Cory Benfield11c10192015-10-27 17:23:03 +09002552 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002553
Cory Benfield9c590b92015-10-28 14:55:05 +09002554 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002555 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002556 :param buffer: The buffer the key is stored in.
2557 :type buffer: A Python string object, either unicode or bytestring.
2558 :return: The PKey object.
2559 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002560 """
2561 if isinstance(buffer, _text_type):
2562 buffer = buffer.encode("ascii")
2563
2564 bio = _new_mem_buf(buffer)
2565
2566 if type == FILETYPE_PEM:
2567 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2568 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2569 elif type == FILETYPE_ASN1:
2570 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2571 else:
2572 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2573
2574 if evp_pkey == _ffi.NULL:
2575 _raise_current_error()
2576
2577 pkey = PKey.__new__(PKey)
2578 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Paul Kehrer32fc4e62016-06-03 15:21:44 -07002579 pkey._only_public = True
Cory Benfield6492f7c2015-10-27 16:57:58 +09002580 return pkey
2581
2582
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002583def load_privatekey(type, buffer, passphrase=None):
2584 """
2585 Load a private key from a buffer
2586
2587 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2588 :param buffer: The buffer the key is stored in
2589 :param passphrase: (optional) if encrypted PEM format, this can be
2590 either the passphrase to use, or a callback for
2591 providing the passphrase.
2592
2593 :return: The PKey object
2594 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002595 if isinstance(buffer, _text_type):
2596 buffer = buffer.encode("ascii")
2597
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002598 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002599
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002600 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002601 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002602 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2603 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002604 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002605 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002606 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002607 else:
2608 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2609
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002610 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002611 _raise_current_error()
2612
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002613 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002614 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002615 return pkey
2616
2617
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002618def dump_certificate_request(type, req):
2619 """
2620 Dump a certificate request to a buffer
2621
2622 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2623 :param req: The certificate request to dump
2624 :return: The buffer with the dumped certificate request in
2625 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002626 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002627
2628 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002629 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002630 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002631 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002632 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002633 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002634 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002635 raise ValueError(
2636 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2637 "FILETYPE_TEXT"
2638 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002639
2640 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002641 # TODO: This is untested.
2642 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002643
2644 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002645
2646
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002647def load_certificate_request(type, buffer):
2648 """
2649 Load a certificate request from a buffer
2650
2651 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2652 :param buffer: The buffer the certificate request is stored in
2653 :return: The X509Req object
2654 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002655 if isinstance(buffer, _text_type):
2656 buffer = buffer.encode("ascii")
2657
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002658 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002659
2660 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002661 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002662 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002663 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002664 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002665 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002666
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002667 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002668 # TODO: This is untested.
2669 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002670
2671 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002672 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002673 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002674
2675
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002676def sign(pkey, data, digest):
2677 """
2678 Sign data with a digest
2679
2680 :param pkey: Pkey to sign with
2681 :param data: data to be signed
2682 :param digest: message digest to use
2683 :return: signature
2684 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002685 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002686
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002687 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002688 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002689 raise ValueError("No such digest method")
2690
Alex Gaynor67903a62016-06-02 10:37:13 -07002691 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002692 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002693
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002694 _lib.EVP_SignInit(md_ctx, digest_obj)
2695 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002696
Colleen Murphye09399b2016-03-01 17:40:49 -08002697 pkey_length = (PKey.bits(pkey) + 7) // 8
2698 signature_buffer = _ffi.new("unsigned char[]", pkey_length)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002699 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002700 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002701 md_ctx, signature_buffer, signature_length, pkey._pkey)
2702
2703 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002704 # TODO: This is untested.
2705 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002706
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002707 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002708
2709
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002710def verify(cert, signature, data, digest):
2711 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002712 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002713
2714 :param cert: signing certificate (X509 object)
2715 :param signature: signature returned by sign function
2716 :param data: data to be verified
2717 :param digest: message digest to use
Dan Sully44e767a2016-06-04 18:05:27 -07002718 :return: ``None`` if the signature is correct, raise exception otherwise.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002719 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002720 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002721
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002722 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002723 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002724 raise ValueError("No such digest method")
2725
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002726 pkey = _lib.X509_get_pubkey(cert._x509)
2727 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002728 # TODO: This is untested.
2729 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002730 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002731
Alex Gaynor67903a62016-06-02 10:37:13 -07002732 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002733 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002734
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002735 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2736 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002737 verify_result = _lib.EVP_VerifyFinal(
2738 md_ctx, signature, len(signature), pkey
2739 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002740
2741 if verify_result != 1:
2742 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002743
2744
Dominic Chenf05b2122015-10-13 16:32:35 +00002745def dump_crl(type, crl):
2746 """
2747 Dump a certificate revocation list to a buffer.
2748
2749 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2750 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002751 :param CRL crl: The CRL to dump.
2752
Dominic Chenf05b2122015-10-13 16:32:35 +00002753 :return: The buffer with the CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07002754 :rtype: bytes
Dominic Chenf05b2122015-10-13 16:32:35 +00002755 """
2756 bio = _new_mem_buf()
2757
2758 if type == FILETYPE_PEM:
2759 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2760 elif type == FILETYPE_ASN1:
2761 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2762 elif type == FILETYPE_TEXT:
2763 ret = _lib.X509_CRL_print(bio, crl._crl)
2764 else:
2765 raise ValueError(
2766 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2767 "FILETYPE_TEXT")
2768
2769 assert ret == 1
2770 return _bio_to_string(bio)
2771
2772
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002773def load_crl(type, buffer):
2774 """
2775 Load a certificate revocation list from a buffer
2776
2777 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2778 :param buffer: The buffer the CRL is stored in
2779
2780 :return: The PKey object
2781 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002782 if isinstance(buffer, _text_type):
2783 buffer = buffer.encode("ascii")
2784
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002785 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002786
2787 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002788 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002789 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002790 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002791 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002792 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2793
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002794 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002795 _raise_current_error()
2796
2797 result = CRL.__new__(CRL)
2798 result._crl = crl
2799 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002800
2801
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002802def load_pkcs7_data(type, buffer):
2803 """
2804 Load pkcs7 data from a buffer
2805
2806 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2807 :param buffer: The buffer with the pkcs7 data.
2808 :return: The PKCS7 object
2809 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002810 if isinstance(buffer, _text_type):
2811 buffer = buffer.encode("ascii")
2812
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002813 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002814
2815 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002816 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002817 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002818 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002819 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002820 # TODO: This is untested.
2821 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002822 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2823
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002824 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002825 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002826
2827 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002828 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002829 return pypkcs7
2830
2831
Stephen Holsapple38482622014-04-05 20:29:34 -07002832def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002833 """
2834 Load a PKCS12 object from a buffer
2835
2836 :param buffer: The buffer the certificate is stored in
2837 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2838 :returns: The PKCS12 object
2839 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002840 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002841
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002842 if isinstance(buffer, _text_type):
2843 buffer = buffer.encode("ascii")
2844
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002845 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002846
Stephen Holsapple38482622014-04-05 20:29:34 -07002847 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2848 # password based encryption no password and a zero length password are two
2849 # different things, but OpenSSL implementation will try both to figure out
2850 # which one works.
2851 if not passphrase:
2852 passphrase = _ffi.NULL
2853
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002854 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2855 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002856 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002857 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002858
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002859 pkey = _ffi.new("EVP_PKEY**")
2860 cert = _ffi.new("X509**")
2861 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002862
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002863 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002864 if not parse_result:
2865 _raise_current_error()
2866
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002867 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002868
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002869 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2870 # queue for no particular reason. This error isn't interesting to anyone
2871 # outside this function. It's not even interesting to us. Get rid of it.
2872 try:
2873 _raise_current_error()
2874 except Error:
2875 pass
2876
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002877 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002878 pykey = None
2879 else:
2880 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002881 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002882
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002883 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002884 pycert = None
2885 friendlyname = None
2886 else:
2887 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002888 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002889
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002890 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002891 friendlyname_buffer = _lib.X509_alias_get0(
2892 cert[0], friendlyname_length
2893 )
2894 friendlyname = _ffi.buffer(
2895 friendlyname_buffer, friendlyname_length[0]
2896 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002897 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002898 friendlyname = None
2899
2900 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002901 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002902 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002903 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002904 pycacerts.append(pycacert)
2905 if not pycacerts:
2906 pycacerts = None
2907
2908 pkcs12 = PKCS12.__new__(PKCS12)
2909 pkcs12._pkey = pykey
2910 pkcs12._cert = pycert
2911 pkcs12._cacerts = pycacerts
2912 pkcs12._friendlyname = friendlyname
2913 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002914
2915
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002916# There are no direct unit tests for this initialization. It is tested
2917# indirectly since it is necessary for functions like dump_privatekey when
2918# using encryption.
2919#
2920# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2921# and some other similar tests may fail without this (though they may not if
2922# the Python runtime has already done some initialization of the underlying
2923# OpenSSL library (and is linked against the same one that cryptography is
2924# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002925_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002926
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002927# This is similar but exercised mainly by exception_from_error_queue. It calls
2928# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2929_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002930
2931
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002932# Set the default string mask to match OpenSSL upstream (since 2005) and
2933# RFC5280 recommendations.
2934_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')