blob: 7bb0cfa5e614d7609abcefd316a1cc162f5376c6 [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
Paul Kehrer72d968b2016-07-29 15:31:04 +080013from cryptography.hazmat.primitives.asymmetric import dsa, rsa
14
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050015from OpenSSL._util import (
16 ffi as _ffi,
17 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050018 exception_from_error_queue as _exception_from_error_queue,
19 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040020 native as _native,
21 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040022 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Alex Gaynor67903a62016-06-02 10:37:13 -070023 make_assert as _make_assert,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040024)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080025
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050026FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
27FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080028
29# TODO This was an API mistake. OpenSSL has no such constant.
30FILETYPE_TEXT = 2 ** 16 - 1
31
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050032TYPE_RSA = _lib.EVP_PKEY_RSA
33TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080034
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080035
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050036class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050037 """
38 An error occurred in an `OpenSSL.crypto` API.
39 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050040
41
42_raise_current_error = partial(_exception_from_error_queue, Error)
Alex Gaynor67903a62016-06-02 10:37:13 -070043_openssl_assert = _make_assert(Error)
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050044
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070045
Paul Kehrereb633842016-10-06 11:22:01 +020046def _get_backend():
47 """
48 Importing the backend from cryptography has the side effect of activating
49 the osrandom engine. This mutates the global state of OpenSSL in the
50 process and causes issues for various programs that use subinterpreters or
51 embed Python. By putting the import in this function we can avoid
52 triggering this side effect unless _get_backend is called.
53 """
54 from cryptography.hazmat.backends.openssl.backend import backend
55 return backend
56
57
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050058def _untested_error(where):
59 """
60 An OpenSSL API failed somehow. Additionally, the failure which was
61 encountered isn't one that's exercised by the test suite so future behavior
62 of pyOpenSSL is now somewhat less predictable.
63 """
64 raise RuntimeError("Unknown %s failure" % (where,))
65
66
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050067def _new_mem_buf(buffer=None):
68 """
69 Allocate a new OpenSSL memory BIO.
70
71 Arrange for the garbage collector to clean it up automatically.
72
73 :param buffer: None or some bytes to use to put into the BIO so that they
74 can be read out.
75 """
76 if buffer is None:
77 bio = _lib.BIO_new(_lib.BIO_s_mem())
78 free = _lib.BIO_free
79 else:
80 data = _ffi.new("char[]", buffer)
81 bio = _lib.BIO_new_mem_buf(data, len(buffer))
Alex Gaynor5945ea82015-09-05 14:59:06 -040082
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050083 # Keep the memory alive as long as the bio is alive!
84 def free(bio, ref=data):
85 return _lib.BIO_free(bio)
86
Alex Gaynorfb8a2a12016-06-04 18:26:26 -070087 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050088
89 bio = _ffi.gc(bio, free)
90 return bio
91
92
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080093def _bio_to_string(bio):
94 """
95 Copy the contents of an OpenSSL BIO object into a Python byte string.
96 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050097 result_buffer = _ffi.new('char**')
98 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
99 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800100
101
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800102def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500103 """
104 The the time value of an ASN1 time object.
105
106 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
107 castable to that type) which will have its value set.
108 @param when: A string representation of the desired time value.
109
110 @raise TypeError: If C{when} is not a L{bytes} string.
111 @raise ValueError: If C{when} does not represent a time in the required
112 format.
113 @raise RuntimeError: If the time value cannot be set for some other
114 (unspecified) reason.
115 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800116 if not isinstance(when, bytes):
117 raise TypeError("when must be a byte string")
118
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500119 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
120 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800121 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500122 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
123 _lib.ASN1_STRING_set(dummy, when, len(when))
124 check_result = _lib.ASN1_GENERALIZEDTIME_check(
125 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800126 if not check_result:
127 raise ValueError("Invalid string")
128 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500129 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800130
Alex Gaynor510293e2016-06-02 12:07:59 -0700131
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800132def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500133 """
134 Retrieve the time value of an ASN1 time object.
135
136 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
137 that type) from which the time value will be retrieved.
138
139 @return: The time value from C{timestamp} as a L{bytes} string in a certain
140 format. Or C{None} if the object contains no time value.
141 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500142 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
143 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800144 return None
Alex Gaynor5945ea82015-09-05 14:59:06 -0400145 elif (
146 _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
147 ):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500148 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800149 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500150 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
151 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
152 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500153 # This may happen:
154 # - if timestamp was not an ASN1_TIME
155 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
156 # - if a copy of the time data from timestamp cannot be made for
157 # the newly allocated ASN1_GENERALIZEDTIME
158 #
159 # These are difficult to test. cffi enforces the ASN1_TIME type.
160 # Memory allocation failures are a pain to trigger
161 # deterministically.
162 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800163 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500164 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800165 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500166 string_data = _lib.ASN1_STRING_data(string_timestamp)
167 string_result = _ffi.string(string_data)
168 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800169 return string_result
170
171
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800172class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200173 """
174 A class representing an DSA or RSA public key or key pair.
175 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800176 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800177 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800178
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800179 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500180 pkey = _lib.EVP_PKEY_new()
181 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800182 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800183
Paul Kehrer72d968b2016-07-29 15:31:04 +0800184 def to_cryptography_key(self):
185 """
186 Export as a ``cryptography`` key.
187
188 :rtype: One of ``cryptography``'s `key interfaces`_.
189
190 .. _key interfaces: https://cryptography.io/en/latest/hazmat/\
191 primitives/asymmetric/rsa/#key-interfaces
192
193 .. versionadded:: 16.1.0
194 """
Paul Kehrereb633842016-10-06 11:22:01 +0200195 backend = _get_backend()
Paul Kehrer72d968b2016-07-29 15:31:04 +0800196 if self._only_public:
197 return backend._evp_pkey_to_public_key(self._pkey)
198 else:
199 return backend._evp_pkey_to_private_key(self._pkey)
200
201 @classmethod
202 def from_cryptography_key(cls, crypto_key):
203 """
204 Construct based on a ``cryptography`` *crypto_key*.
205
206 :param crypto_key: A ``cryptography`` key.
207 :type crypto_key: One of ``cryptography``'s `key interfaces`_.
208
209 :rtype: PKey
210
211 .. versionadded:: 16.1.0
212 """
213 pkey = cls()
214 if not isinstance(crypto_key, (rsa.RSAPublicKey, rsa.RSAPrivateKey,
215 dsa.DSAPublicKey, dsa.DSAPrivateKey)):
216 raise TypeError("Unsupported key type")
217
218 pkey._pkey = crypto_key._evp_pkey
219 if isinstance(crypto_key, (rsa.RSAPublicKey, dsa.DSAPublicKey)):
220 pkey._only_public = True
221 pkey._initialized = True
222 return pkey
223
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800224 def generate_key(self, type, bits):
225 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700226 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800227
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200228 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800229
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200230 :param type: The key type.
231 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
232 :param bits: The number of bits.
233 :type bits: :py:data:`int` ``>= 0``
234 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
235 of the appropriate type.
236 :raises ValueError: If the number of bits isn't an integer of
237 the appropriate size.
Dan Sully44e767a2016-06-04 18:05:27 -0700238 :return: ``None``
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800239 """
240 if not isinstance(type, int):
241 raise TypeError("type must be an integer")
242
243 if not isinstance(bits, int):
244 raise TypeError("bits must be an integer")
245
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800246 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500247 exponent = _lib.BN_new()
248 exponent = _ffi.gc(exponent, _lib.BN_free)
249 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800250
251 if type == TYPE_RSA:
252 if bits <= 0:
253 raise ValueError("Invalid number of bits")
254
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500255 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800256
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500257 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400258 _openssl_assert(result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800259
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500260 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400261 _openssl_assert(result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800262
263 elif type == TYPE_DSA:
Paul Kehrera0860b92016-03-09 21:39:27 -0400264 dsa = _lib.DSA_new()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700265 _openssl_assert(dsa != _ffi.NULL)
Paul Kehrerafa5a662016-03-10 10:29:28 -0400266
267 dsa = _ffi.gc(dsa, _lib.DSA_free)
Paul Kehrera0860b92016-03-09 21:39:27 -0400268 res = _lib.DSA_generate_parameters_ex(
269 dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL
270 )
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700271 _openssl_assert(res == 1)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400272
273 _openssl_assert(_lib.DSA_generate_key(dsa) == 1)
274 _openssl_assert(_lib.EVP_PKEY_set1_DSA(self._pkey, dsa) == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800275 else:
276 raise Error("No such key type")
277
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800278 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800279
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800280 def check(self):
281 """
282 Check the consistency of an RSA private key.
283
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200284 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
285
Hynek Schlawack01c31672016-12-11 15:14:09 +0100286 :return: ``True`` if key is consistent.
287
288 :raise OpenSSL.crypto.Error: if the key is inconsistent.
289
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800290 :raise TypeError: if the key is of a type which cannot be checked.
291 Only RSA keys can currently be checked.
292 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800293 if self._only_public:
294 raise TypeError("public key only")
295
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100296 if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800297 raise TypeError("key type unsupported")
298
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500299 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
300 rsa = _ffi.gc(rsa, _lib.RSA_free)
301 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800302 if result:
303 return True
304 _raise_current_error()
305
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800306 def type(self):
307 """
308 Returns the type of the key
309
310 :return: The type of the key.
311 """
Alex Gaynorc84567b2016-03-16 07:45:09 -0400312 return _lib.Cryptography_EVP_PKEY_id(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800313
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800314 def bits(self):
315 """
316 Returns the number of bits of the key
317
318 :return: The number of bits of the key.
319 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500320 return _lib.EVP_PKEY_bits(self._pkey)
Alex Chanc6077062016-11-18 13:53:39 +0000321
322
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800323PKeyType = PKey
324
325
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400326class _EllipticCurve(object):
327 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400328 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400329
330 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
331 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
332 instances each of which represents one curve supported by the system.
333 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400334 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400335 _curves = None
336
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400337 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400338 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400339 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400340 """
341 Implement cooperation with the right-hand side argument of ``!=``.
342
343 Python 3 seems to have dropped this cooperation in this very narrow
344 circumstance.
345 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400346 if isinstance(other, _EllipticCurve):
347 return super(_EllipticCurve, self).__ne__(other)
348 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400349
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400350 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400351 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400352 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400353 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400354
355 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400356
357 :return: A :py:type:`set` of ``cls`` instances giving the names of the
358 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400359 """
360 if lib.Cryptography_HAS_EC:
361 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
362 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400363 # The return value on this call should be num_curves again. We
364 # could check it to make sure but if it *isn't* then.. what could
365 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400366 lib.EC_get_builtin_curves(builtin_curves, num_curves)
367 return set(
368 cls.from_nid(lib, c.nid)
369 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400370 return set()
371
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400372 @classmethod
373 def _get_elliptic_curves(cls, lib):
374 """
375 Get, cache, and return the curves supported by OpenSSL.
376
377 :param lib: The OpenSSL library binding object.
378
379 :return: A :py:type:`set` of ``cls`` instances giving the names of the
380 elliptic curves the underlying library supports.
381 """
382 if cls._curves is None:
383 cls._curves = cls._load_elliptic_curves(lib)
384 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400385
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400386 @classmethod
387 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400388 """
389 Instantiate a new :py:class:`_EllipticCurve` associated with the given
390 OpenSSL NID.
391
392 :param lib: The OpenSSL library binding object.
393
394 :param nid: The OpenSSL NID the resulting curve object will represent.
395 This must be a curve NID (and not, for example, a hash NID) or
396 subsequent operations will fail in unpredictable ways.
397 :type nid: :py:class:`int`
398
399 :return: The curve object.
400 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400401 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
402
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400403 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400404 """
405 :param _lib: The :py:mod:`cryptography` binding instance used to
406 interface with OpenSSL.
407
408 :param _nid: The OpenSSL NID identifying the curve this object
409 represents.
410 :type _nid: :py:class:`int`
411
412 :param name: The OpenSSL short name identifying the curve this object
413 represents.
414 :type name: :py:class:`unicode`
415 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400416 self._lib = lib
417 self._nid = nid
418 self.name = name
419
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400420 def __repr__(self):
421 return "<Curve %r>" % (self.name,)
422
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400423 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400424 """
425 Create a new OpenSSL EC_KEY structure initialized to use this curve.
426
427 The structure is automatically garbage collected when the Python object
428 is garbage collected.
429 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400430 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
431 return _ffi.gc(key, _lib.EC_KEY_free)
432
433
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400434def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400435 """
436 Return a set of objects representing the elliptic curves supported in the
437 OpenSSL build in use.
438
439 The curve objects have a :py:class:`unicode` ``name`` attribute by which
440 they identify themselves.
441
442 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400443 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
444 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400445 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400446 return _EllipticCurve._get_elliptic_curves(_lib)
447
448
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400449def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400450 """
451 Return a single curve object selected by name.
452
453 See :py:func:`get_elliptic_curves` for information about curve objects.
454
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400455 :param name: The OpenSSL short name identifying the curve object to
456 retrieve.
457 :type name: :py:class:`unicode`
458
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400459 If the named curve is not supported then :py:class:`ValueError` is raised.
460 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400461 for curve in get_elliptic_curves():
462 if curve.name == name:
463 return curve
464 raise ValueError("unknown curve name", name)
465
466
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800467class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200468 """
469 An X.509 Distinguished Name.
470
471 :ivar countryName: The country of the entity.
472 :ivar C: Alias for :py:attr:`countryName`.
473
474 :ivar stateOrProvinceName: The state or province of the entity.
475 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
476
477 :ivar localityName: The locality of the entity.
478 :ivar L: Alias for :py:attr:`localityName`.
479
480 :ivar organizationName: The organization name of the entity.
481 :ivar O: Alias for :py:attr:`organizationName`.
482
483 :ivar organizationalUnitName: The organizational unit of the entity.
484 :ivar OU: Alias for :py:attr:`organizationalUnitName`
485
486 :ivar commonName: The common name of the entity.
487 :ivar CN: Alias for :py:attr:`commonName`.
488
489 :ivar emailAddress: The e-mail address of the entity.
490 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400491
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800492 def __init__(self, name):
493 """
494 Create a new X509Name, copying the given X509Name instance.
495
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200496 :param name: The name to copy.
497 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800498 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500499 name = _lib.X509_NAME_dup(name._name)
500 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800501
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800502 def __setattr__(self, name, value):
503 if name.startswith('_'):
504 return super(X509Name, self).__setattr__(name, value)
505
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800506 # Note: we really do not want str subclasses here, so we do not use
507 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800508 if type(name) is not str:
509 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400510 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800511
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500512 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500513 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800514 try:
515 _raise_current_error()
516 except Error:
517 pass
518 raise AttributeError("No such attribute")
519
520 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500521 for i in range(_lib.X509_NAME_entry_count(self._name)):
522 ent = _lib.X509_NAME_get_entry(self._name, i)
523 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
524 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800525 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500526 ent = _lib.X509_NAME_delete_entry(self._name, i)
527 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800528 break
529
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500530 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800531 value = value.encode('utf-8')
532
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500533 add_result = _lib.X509_NAME_add_entry_by_NID(
534 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800535 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500536 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800537
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800538 def __getattr__(self, name):
539 """
540 Find attribute. An X509Name object has the following attributes:
541 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400542 organization (alias O), organizationalUnit (alias OU), commonName
543 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800544 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500545 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500546 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800547 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
548 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
549 # push something onto the error queue. If we don't clean that up
550 # now, someone else will bump into it later and be quite confused.
551 # See lp#314814.
552 try:
553 _raise_current_error()
554 except Error:
555 pass
556 return super(X509Name, self).__getattr__(name)
557
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500558 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800559 if entry_index == -1:
560 return None
561
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500562 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
563 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800564
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500565 result_buffer = _ffi.new("unsigned char**")
566 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400567 _openssl_assert(data_length >= 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800568
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700569 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400570 result = _ffi.buffer(
571 result_buffer[0], data_length
572 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700573 finally:
574 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500575 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800576 return result
577
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500578 def _cmp(op):
579 def f(self, other):
580 if not isinstance(other, X509Name):
581 return NotImplemented
582 result = _lib.X509_NAME_cmp(self._name, other._name)
583 return op(result, 0)
584 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500586 __eq__ = _cmp(__eq__)
587 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800588
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500589 __lt__ = _cmp(__lt__)
590 __le__ = _cmp(__le__)
591
592 __gt__ = _cmp(__gt__)
593 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800594
595 def __repr__(self):
596 """
597 String representation of an X509Name
598 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400599 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500600 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800601 self._name, result_buffer, len(result_buffer))
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700602 _openssl_assert(format_result != _ffi.NULL)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800603
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500604 return "<X509Name object '%s'>" % (
605 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800606
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800607 def hash(self):
608 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200609 Return an integer representation of the first four bytes of the
610 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800611
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200612 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
613
614 :return: The (integer) hash of this name.
615 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800616 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500617 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800618
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800619 def der(self):
620 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200621 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800622
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200623 :return: The DER encoded form of this name.
624 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800625 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500626 result_buffer = _ffi.new('unsigned char**')
627 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400628 _openssl_assert(encode_result >= 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800629
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500630 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
631 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800632 return string_result
633
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800634 def get_components(self):
635 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200636 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800637
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200638 :return: The components of this name.
639 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800640 """
641 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500642 for i in range(_lib.X509_NAME_entry_count(self._name)):
643 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800644
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500645 fname = _lib.X509_NAME_ENTRY_get_object(ent)
646 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800647
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500648 nid = _lib.OBJ_obj2nid(fname)
649 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800650
651 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400652 _ffi.string(name),
653 _ffi.string(
654 _lib.ASN1_STRING_data(fval),
655 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800656
657 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200658
659
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800660X509NameType = X509Name
661
662
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800663class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200664 """
665 An X.509 v3 certificate extension.
666 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400667
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800668 def __init__(self, type_name, critical, value, subject=None, issuer=None):
669 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200670 Initializes an X509 extension.
671
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100672 :param type_name: The name of the type of extension_ to create.
Alex Gaynor6f719912015-09-20 09:21:29 -0400673 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800674
Alex Gaynor5945ea82015-09-05 14:59:06 -0400675 :param bool critical: A flag indicating whether this is a critical
676 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800677
678 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200679 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800680
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200681 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800682 :type subject: :py:class:`X509`
683
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200684 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800685 :type issuer: :py:class:`X509`
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100686
Hynek Schlawackc3b38e52016-10-15 14:56:14 +0200687 .. _extension: https://www.openssl.org/docs/manmaster/apps/
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100688 x509v3_config.html#STANDARD-EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800689 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500690 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800691
Alex Gaynor5945ea82015-09-05 14:59:06 -0400692 # A context is necessary for any extension which uses the r2i
693 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
694 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500695 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800696
697 # We have no configuration database - but perhaps we should (some
698 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500699 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800700
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800701 # Initialize the subject and issuer, if appropriate. ctx is a local,
702 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400703 # any references, so no need to mess with reference counts or
704 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800705 if issuer is not None:
706 if not isinstance(issuer, X509):
707 raise TypeError("issuer must be an X509 instance")
708 ctx.issuer_cert = issuer._x509
709 if subject is not None:
710 if not isinstance(subject, X509):
711 raise TypeError("subject must be an X509 instance")
712 ctx.subject_cert = subject._x509
713
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800714 if critical:
715 # There are other OpenSSL APIs which would let us pass in critical
716 # separately, but they're harder to use, and since value is already
717 # a pile of crappy junk smuggling a ton of utterly important
718 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400719 # with strings? (However, X509V3_EXT_i2d in particular seems like
720 # it would be a better API to invoke. I do not know where to get
721 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500722 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800723
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500724 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
725 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800726 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500727 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800728
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400729 @property
730 def _nid(self):
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400731 return _lib.OBJ_obj2nid(
732 _lib.X509_EXTENSION_get_object(self._extension)
733 )
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400734
735 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500736 _lib.GEN_EMAIL: "email",
737 _lib.GEN_DNS: "DNS",
738 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400739 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400740
741 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500742 method = _lib.X509V3_EXT_get(self._extension)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700743 _openssl_assert(method != _ffi.NULL)
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400744 ext_data = _lib.X509_EXTENSION_get_data(self._extension)
745 payload = ext_data.data
746 length = ext_data.length
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400747
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500748 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400749 payloadptr[0] = payload
750
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500751 if method.it != _ffi.NULL:
752 ptr = _lib.ASN1_ITEM_ptr(method.it)
753 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
754 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400755 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500756 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400757 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500758 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400759
Paul Kehrerb7d79502015-05-04 07:43:51 -0500760 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400761 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500762 for i in range(_lib.sk_GENERAL_NAME_num(names)):
763 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400764 try:
765 label = self._prefixes[name.type]
766 except KeyError:
767 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500768 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500769 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400770 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500771 value = _native(
772 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
773 parts.append(label + ":" + value)
774 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400775
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800776 def __str__(self):
777 """
778 :return: a nice text representation of the extension
779 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500780 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400781 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800782
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400783 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500784 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400785 _openssl_assert(print_result != 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800786
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500787 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800788
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800789 def get_critical(self):
790 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200791 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800792
793 :return: The critical field.
794 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500795 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800796
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800797 def get_short_name(self):
798 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200799 Returns the short type name of this X.509 extension.
800
801 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800802
803 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200804 :rtype: :py:data:`bytes`
805
806 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800807 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500808 obj = _lib.X509_EXTENSION_get_object(self._extension)
809 nid = _lib.OBJ_obj2nid(obj)
810 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800811
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800812 def get_data(self):
813 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200814 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800815
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200816 :return: The ASN.1 encoded data of this X509 extension.
817 :rtype: :py:data:`bytes`
818
819 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800820 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500821 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
822 string_result = _ffi.cast('ASN1_STRING*', octet_result)
823 char_result = _lib.ASN1_STRING_data(string_result)
824 result_length = _lib.ASN1_STRING_length(string_result)
825 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800826
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200827
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800828X509ExtensionType = X509Extension
829
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800830
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800831class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200832 """
833 An X.509 certificate signing requests.
834 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400835
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800836 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500837 req = _lib.X509_REQ_new()
838 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Alex Gaynor5af32d02016-09-24 01:52:21 -0400839 # Default to version 0.
840 self.set_version(0)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800841
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800842 def set_pubkey(self, pkey):
843 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200844 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800845
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200846 :param pkey: The public key to use.
847 :type pkey: :py:class:`PKey`
848
Dan Sully44e767a2016-06-04 18:05:27 -0700849 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500851 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400852 _openssl_assert(set_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800853
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800854 def get_pubkey(self):
855 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200856 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800857
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200858 :return: The public key.
859 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800860 """
861 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500862 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700863 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500864 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800865 pkey._only_public = True
866 return pkey
867
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800868 def set_version(self, version):
869 """
870 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
871 request.
872
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200873 :param int version: The version number.
Dan Sully44e767a2016-06-04 18:05:27 -0700874 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800875 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500876 set_result = _lib.X509_REQ_set_version(self._req, version)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400877 _openssl_assert(set_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800878
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800879 def get_version(self):
880 """
881 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
882 request.
883
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200884 :return: The value of the version subfield.
885 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800886 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500887 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800888
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889 def get_subject(self):
890 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200891 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800892
Cory Benfield881dc8d2015-12-09 08:25:14 +0000893 This creates a new :class:`X509Name` that wraps the underlying subject
894 name field on the certificate signing request. Modifying it will modify
895 the underlying signing request, and will have the effect of modifying
896 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200897
898 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000899 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800900 """
901 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500902 name._name = _lib.X509_REQ_get_subject_name(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700903 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800904
905 # The name is owned by the X509Req structure. As long as the X509Name
906 # Python object is alive, keep the X509Req Python object alive.
907 name._owner = self
908
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800909 return name
910
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800911 def add_extensions(self, extensions):
912 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200913 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800914
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200915 :param extensions: The X.509 extensions to add.
916 :type extensions: iterable of :py:class:`X509Extension`
Dan Sully44e767a2016-06-04 18:05:27 -0700917 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800918 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500919 stack = _lib.sk_X509_EXTENSION_new_null()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700920 _openssl_assert(stack != _ffi.NULL)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800921
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500922 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800923
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800924 for ext in extensions:
925 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800926 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800927
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800928 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500929 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800930
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500931 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400932 _openssl_assert(add_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800933
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800934 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800935 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200936 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800937
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200938 :return: The X.509 extensions in this request.
939 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
940
941 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800942 """
943 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500944 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500945 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800946 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500947 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800948 exts.append(ext)
949 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800950
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800951 def sign(self, pkey, digest):
952 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700953 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800954
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200955 :param pkey: The key pair to sign with.
956 :type pkey: :py:class:`PKey`
957 :param digest: The name of the message digest to use for the signature,
Alex Gaynor239e2d32016-09-11 12:36:35 -0400958 e.g. :py:data:`b"sha256"`.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200959 :type digest: :py:class:`bytes`
Dan Sully44e767a2016-06-04 18:05:27 -0700960 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800961 """
962 if pkey._only_public:
963 raise ValueError("Key has only public part")
964
965 if not pkey._initialized:
966 raise ValueError("Key is uninitialized")
967
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500968 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500969 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800970 raise ValueError("No such digest method")
971
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500972 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400973 _openssl_assert(sign_result > 0)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800974
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800975 def verify(self, pkey):
976 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200977 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800978
Hynek Schlawack01c31672016-12-11 15:14:09 +0100979 :param PKey key: A public key.
980
981 :return: ``True`` if the signature is correct.
982 :rtype: bool
983
984 :raises OpenSSL.crypto.Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800985 problem verifying the signature.
986 """
987 if not isinstance(pkey, PKey):
988 raise TypeError("pkey must be a PKey instance")
989
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500990 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800991 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500992 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800993
994 return result
995
996
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800997X509ReqType = X509Req
998
999
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001000class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001001 """
1002 An X.509 certificate.
1003 """
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001004 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001005 x509 = _lib.X509_new()
Hynek Schlawack8a2dd772016-07-31 13:46:20 +02001006 _openssl_assert(x509 != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001007 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001008
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001009 def set_version(self, version):
1010 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001011 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001012
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001013 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001014 :type version: :py:class:`int`
1015
Dan Sully44e767a2016-06-04 18:05:27 -07001016 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001017 """
1018 if not isinstance(version, int):
1019 raise TypeError("version must be an integer")
1020
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001021 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001022
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001023 def get_version(self):
1024 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001025 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001026
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001027 :return: The version number of the certificate.
1028 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001029 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001030 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001031
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001032 def get_pubkey(self):
1033 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001034 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001035
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001036 :return: The public key.
1037 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001038 """
1039 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001040 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1041 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001042 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001043 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001044 pkey._only_public = True
1045 return pkey
1046
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001047 def set_pubkey(self, pkey):
1048 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001049 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001050
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001051 :param pkey: The public key.
1052 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001053
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001054 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001055 """
1056 if not isinstance(pkey, PKey):
1057 raise TypeError("pkey must be a PKey instance")
1058
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001059 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Alex Gaynor7778e792016-07-03 23:38:48 -04001060 _openssl_assert(set_result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001061
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001062 def sign(self, pkey, digest):
1063 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001064 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001065
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001066 :param pkey: The key to sign with.
1067 :type pkey: :py:class:`PKey`
1068
1069 :param digest: The name of the message digest to use.
1070 :type digest: :py:class:`bytes`
1071
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001072 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001073 """
1074 if not isinstance(pkey, PKey):
1075 raise TypeError("pkey must be a PKey instance")
1076
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001077 if pkey._only_public:
1078 raise ValueError("Key only has public part")
1079
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001080 if not pkey._initialized:
1081 raise ValueError("Key is uninitialized")
1082
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001083 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001084 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001085 raise ValueError("No such digest method")
1086
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001087 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -04001088 _openssl_assert(sign_result > 0)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001089
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001090 def get_signature_algorithm(self):
1091 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001092 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001093
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001094 :return: The name of the algorithm.
1095 :rtype: :py:class:`bytes`
1096
1097 :raises ValueError: If the signature algorithm is undefined.
1098
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001099 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001100 """
Alex Gaynor39ea5312016-06-02 09:12:10 -07001101 algor = _lib.X509_get0_tbs_sigalg(self._x509)
1102 nid = _lib.OBJ_obj2nid(algor.algorithm)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001103 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001104 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001105 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001106
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001107 def digest(self, digest_name):
1108 """
1109 Return the digest of the X509 object.
1110
1111 :param digest_name: The name of the digest algorithm to use.
1112 :type digest_name: :py:class:`bytes`
1113
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001114 :return: The digest of the object, formatted as
1115 :py:const:`b":"`-delimited hex pairs.
1116 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001117 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001118 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001119 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001120 raise ValueError("No such digest method")
1121
Paul Kehrer9f9113a2016-09-20 20:10:25 -05001122 result_buffer = _ffi.new("unsigned char[]", _lib.EVP_MAX_MD_SIZE)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001123 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001124 result_length[0] = len(result_buffer)
1125
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001126 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001127 self._x509, digest, result_buffer, result_length)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001128 _openssl_assert(digest_result == 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001129
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001130 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001131 b16encode(ch).upper() for ch
1132 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001133
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001134 def subject_name_hash(self):
1135 """
1136 Return the hash of the X509 subject.
1137
1138 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001139 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001140 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001141 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001142
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001143 def set_serial_number(self, serial):
1144 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001145 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001146
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001147 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001148 :type serial: :py:class:`int`
1149
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001150 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001151 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001152 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001153 raise TypeError("serial must be an integer")
1154
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001155 hex_serial = hex(serial)[2:]
1156 if not isinstance(hex_serial, bytes):
1157 hex_serial = hex_serial.encode('ascii')
1158
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001159 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001160
1161 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001162 # it. If bignum is still NULL after this call, then the return value
1163 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001164 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001165
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001166 if bignum_serial[0] == _ffi.NULL:
1167 set_result = _lib.ASN1_INTEGER_set(
1168 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001169 if set_result:
1170 # TODO Not tested
1171 _raise_current_error()
1172 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001173 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1174 _lib.BN_free(bignum_serial[0])
1175 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001176 # TODO Not tested
1177 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001178 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1179 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Alex Gaynor37726112016-07-04 09:51:32 -04001180 _openssl_assert(set_result == 1)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001181
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001182 def get_serial_number(self):
1183 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001184 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001185
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001186 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001187 :rtype: int
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001188 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001189 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1190 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001191 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001192 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001193 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001194 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001195 serial = int(hexstring_serial, 16)
1196 return serial
1197 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001198 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001199 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001200 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001201
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001202 def gmtime_adj_notAfter(self, amount):
1203 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001204 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001205
Dan Sully44e767a2016-06-04 18:05:27 -07001206 :param int amount: The number of seconds by which to adjust the
1207 timestamp.
1208 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001209 """
1210 if not isinstance(amount, int):
1211 raise TypeError("amount must be an integer")
1212
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001213 notAfter = _lib.X509_get_notAfter(self._x509)
1214 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001215
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001216 def gmtime_adj_notBefore(self, amount):
1217 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001218 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001219
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001220 :param amount: The number of seconds by which to adjust the timestamp.
Dan Sully44e767a2016-06-04 18:05:27 -07001221 :return: ``None``
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001222 """
1223 if not isinstance(amount, int):
1224 raise TypeError("amount must be an integer")
1225
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001226 notBefore = _lib.X509_get_notBefore(self._x509)
1227 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001228
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001229 def has_expired(self):
1230 """
1231 Check whether the certificate has expired.
1232
Dan Sully44e767a2016-06-04 18:05:27 -07001233 :return: ``True`` if the certificate has expired, ``False`` otherwise.
1234 :rtype: bool
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001235 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001236 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001237 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001238
Paul Kehrerfde45c92016-01-21 12:57:37 -06001239 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001240
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001241 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001242 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001243
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001244 def get_notBefore(self):
1245 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001246 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001247
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001248 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001249
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001250 YYYYMMDDhhmmssZ
1251 YYYYMMDDhhmmss+hhmm
1252 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001253
Dan Sully44e767a2016-06-04 18:05:27 -07001254 :return: A timestamp string, or ``None`` if there is none.
1255 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001256 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001257 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001258
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001259 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001260 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001261
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001262 def set_notBefore(self, when):
1263 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001264 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001265
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001266 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001267
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001268 YYYYMMDDhhmmssZ
1269 YYYYMMDDhhmmss+hhmm
1270 YYYYMMDDhhmmss-hhmm
1271
Dan Sully44e767a2016-06-04 18:05:27 -07001272 :param bytes when: A timestamp string.
1273 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001274 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001275 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001276
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001277 def get_notAfter(self):
1278 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001279 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001280
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001281 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001282
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001283 YYYYMMDDhhmmssZ
1284 YYYYMMDDhhmmss+hhmm
1285 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001286
Dan Sully44e767a2016-06-04 18:05:27 -07001287 :return: A timestamp string, or ``None`` if there is none.
1288 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001289 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001290 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001291
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001292 def set_notAfter(self, when):
1293 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001294 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001295
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001296 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001297
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001298 YYYYMMDDhhmmssZ
1299 YYYYMMDDhhmmss+hhmm
1300 YYYYMMDDhhmmss-hhmm
1301
Dan Sully44e767a2016-06-04 18:05:27 -07001302 :param bytes when: A timestamp string.
1303 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001304 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001305 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001306
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001307 def _get_name(self, which):
1308 name = X509Name.__new__(X509Name)
1309 name._name = which(self._x509)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001310 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001311
1312 # The name is owned by the X509 structure. As long as the X509Name
1313 # Python object is alive, keep the X509 Python object alive.
1314 name._owner = self
1315
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001316 return name
1317
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001318 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001319 if not isinstance(name, X509Name):
1320 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001321 set_result = which(self._x509, name._name)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001322 _openssl_assert(set_result == 1)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001323
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001324 def get_issuer(self):
1325 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001326 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001327
Cory Benfielde6bcce82015-12-09 08:40:03 +00001328 This creates a new :class:`X509Name` that wraps the underlying issuer
1329 name field on the certificate. Modifying it will modify the underlying
1330 certificate, and will have the effect of modifying any other
1331 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001332
1333 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001334 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001335 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001336 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001337
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001338 def set_issuer(self, issuer):
1339 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001340 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001341
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001342 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001343 :type issuer: :py:class:`X509Name`
1344
Dan Sully44e767a2016-06-04 18:05:27 -07001345 :return: ``None``
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001346 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001347 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001348
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001349 def get_subject(self):
1350 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001351 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001352
Cory Benfielde6bcce82015-12-09 08:40:03 +00001353 This creates a new :class:`X509Name` that wraps the underlying subject
1354 name field on the certificate. Modifying it will modify the underlying
1355 certificate, and will have the effect of modifying any other
1356 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001357
1358 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001359 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001360 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001361 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001362
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001363 def set_subject(self, subject):
1364 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001365 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001366
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001367 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001368 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001369
Dan Sully44e767a2016-06-04 18:05:27 -07001370 :return: ``None``
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001371 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001372 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001373
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001374 def get_extension_count(self):
1375 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001376 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001377
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001378 :return: The number of extensions.
1379 :rtype: :py:class:`int`
1380
1381 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001382 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001383 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001384
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001385 def add_extensions(self, extensions):
1386 """
1387 Add extensions to the certificate.
1388
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001389 :param extensions: The extensions to add.
1390 :type extensions: An iterable of :py:class:`X509Extension` objects.
Dan Sully44e767a2016-06-04 18:05:27 -07001391 :return: ``None``
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001392 """
1393 for ext in extensions:
1394 if not isinstance(ext, X509Extension):
1395 raise ValueError("One of the elements is not an X509Extension")
1396
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001397 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001398 if not add_result:
1399 _raise_current_error()
1400
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001401 def get_extension(self, index):
1402 """
1403 Get a specific extension of the certificate by index.
1404
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001405 Extensions on a certificate are kept in order. The index
1406 parameter selects which extension will be returned.
1407
1408 :param int index: The index of the extension to retrieve.
1409 :return: The extension at the specified index.
1410 :rtype: :py:class:`X509Extension`
1411 :raises IndexError: If the extension index was out of bounds.
1412
1413 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001414 """
1415 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001416 ext._extension = _lib.X509_get_ext(self._x509, index)
1417 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001418 raise IndexError("extension index out of bounds")
1419
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001420 extension = _lib.X509_EXTENSION_dup(ext._extension)
1421 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001422 return ext
1423
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001424
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001425X509Type = X509
1426
1427
Dan Sully44e767a2016-06-04 18:05:27 -07001428class X509StoreFlags(object):
1429 """
1430 Flags for X509 verification, used to change the behavior of
1431 :class:`X509Store`.
1432
1433 See `OpenSSL Verification Flags`_ for details.
1434
1435 .. _OpenSSL Verification Flags:
1436 https://www.openssl.org/docs/manmaster/crypto/X509_VERIFY_PARAM_set_flags.html
1437 """
1438 CRL_CHECK = _lib.X509_V_FLAG_CRL_CHECK
1439 CRL_CHECK_ALL = _lib.X509_V_FLAG_CRL_CHECK_ALL
1440 IGNORE_CRITICAL = _lib.X509_V_FLAG_IGNORE_CRITICAL
1441 X509_STRICT = _lib.X509_V_FLAG_X509_STRICT
1442 ALLOW_PROXY_CERTS = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS
1443 POLICY_CHECK = _lib.X509_V_FLAG_POLICY_CHECK
1444 EXPLICIT_POLICY = _lib.X509_V_FLAG_EXPLICIT_POLICY
1445 INHIBIT_MAP = _lib.X509_V_FLAG_INHIBIT_MAP
1446 NOTIFY_POLICY = _lib.X509_V_FLAG_NOTIFY_POLICY
1447 CHECK_SS_SIGNATURE = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE
1448 CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK
1449
1450
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001451class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001452 """
Dan Sully44e767a2016-06-04 18:05:27 -07001453 An X.509 store.
1454
1455 An X.509 store is used to describe a context in which to verify a
1456 certificate. A description of a context may include a set of certificates
1457 to trust, a set of certificate revocation lists, verification flags and
1458 more.
1459
1460 An X.509 store, being only a description, cannot be used by itself to
1461 verify a certificate. To carry out the actual verification process, see
1462 :class:`X509StoreContext`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001463 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001464
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001465 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001466 store = _lib.X509_STORE_new()
1467 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001468
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001469 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001470 """
Dan Sully44e767a2016-06-04 18:05:27 -07001471 Adds a trusted certificate to this store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001472
Dan Sully44e767a2016-06-04 18:05:27 -07001473 Adding a certificate with this method adds this certificate as a
1474 *trusted* certificate.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001475
1476 :param X509 cert: The certificate to add to this store.
Hynek Schlawack01c31672016-12-11 15:14:09 +01001477
Dan Sully44e767a2016-06-04 18:05:27 -07001478 :raises TypeError: If the certificate is not an :class:`X509`.
Hynek Schlawack01c31672016-12-11 15:14:09 +01001479
1480 :raises OpenSSL.crypto.Error: If OpenSSL was unhappy with your
1481 certificate.
1482
Dan Sully44e767a2016-06-04 18:05:27 -07001483 :return: ``None`` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001484 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001485 if not isinstance(cert, X509):
1486 raise TypeError()
1487
Dan Sully44e767a2016-06-04 18:05:27 -07001488 _openssl_assert(_lib.X509_STORE_add_cert(self._store, cert._x509) != 0)
1489
1490 def add_crl(self, crl):
1491 """
1492 Add a certificate revocation list to this store.
1493
1494 The certificate revocation lists added to a store will only be used if
1495 the associated flags are configured to check certificate revocation
1496 lists.
1497
1498 .. versionadded:: 16.1.0
1499
1500 :param CRL crl: The certificate revocation list to add to this store.
1501 :return: ``None`` if the certificate revocation list was added
1502 successfully.
1503 """
1504 _openssl_assert(_lib.X509_STORE_add_crl(self._store, crl._crl) != 0)
1505
1506 def set_flags(self, flags):
1507 """
1508 Set verification flags to this store.
1509
1510 Verification flags can be combined by oring them together.
1511
1512 .. note::
1513
1514 Setting a verification flag sometimes requires clients to add
1515 additional information to the store, otherwise a suitable error will
1516 be raised.
1517
1518 For example, in setting flags to enable CRL checking a
1519 suitable CRL must be added to the store otherwise an error will be
1520 raised.
1521
1522 .. versionadded:: 16.1.0
1523
1524 :param int flags: The verification flags to set on this store.
1525 See :class:`X509StoreFlags` for available constants.
1526 :return: ``None`` if the verification flags were successfully set.
1527 """
1528 _openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0)
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001529
Thomas Sileoe15e60a2016-11-22 18:13:30 +01001530 def set_time(self, vfy_time):
1531 """
1532 Set the time against which the certificates are verified.
1533
1534 Normally the current time is used.
1535
1536 .. note::
1537
1538 For example, you can determine if a certificate was valid at a given
1539 time.
1540
1541 .. versionadded:: 16.3.0
1542
1543 :param datetime vfy_time: The verification time to set on this store.
1544 :return: ``None`` if the verification time was successfully set.
1545 """
1546 param = _lib.X509_VERIFY_PARAM_new()
1547 param = _ffi.gc(param, _lib.X509_VERIFY_PARAM_free)
1548
1549 _lib.X509_VERIFY_PARAM_set_time(param, int(vfy_time.strftime('%s')))
1550 _openssl_assert(_lib.X509_STORE_set1_param(self._store, param) != 0)
1551
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001552
1553X509StoreType = X509Store
1554
1555
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001556class X509StoreContextError(Exception):
1557 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001558 An exception raised when an error occurred while verifying a certificate
1559 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001560
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001561 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001562 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001563 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001564
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001565 def __init__(self, message, certificate):
1566 super(X509StoreContextError, self).__init__(message)
1567 self.certificate = certificate
1568
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001569
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001570class X509StoreContext(object):
1571 """
1572 An X.509 store context.
1573
Dan Sully44e767a2016-06-04 18:05:27 -07001574 An X.509 store context is used to carry out the actual verification process
1575 of a certificate in a described context. For describing such a context, see
1576 :class:`X509Store`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001577
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001578 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1579 instance. It is dynamically allocated and automatically garbage
1580 collected.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001581 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001582 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001583 :param X509Store store: The certificates which will be trusted for the
1584 purposes of any verifications.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001585 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001586 """
1587
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001588 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001589 store_ctx = _lib.X509_STORE_CTX_new()
1590 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1591 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001592 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001593 # Make the store context available for use after instantiating this
1594 # class by initializing it now. Per testing, subsequent calls to
Dan Sully44e767a2016-06-04 18:05:27 -07001595 # :meth:`_init` have no adverse affect.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001596 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001597
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001598 def _init(self):
1599 """
1600 Set up the store context for a subsequent verification operation.
1601 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001602 ret = _lib.X509_STORE_CTX_init(
1603 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1604 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001605 if ret <= 0:
1606 _raise_current_error()
1607
1608 def _cleanup(self):
1609 """
1610 Internally cleans up the store context.
1611
Dan Sully44e767a2016-06-04 18:05:27 -07001612 The store context can then be reused with a new call to :meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001613 """
1614 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1615
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001616 def _exception_from_context(self):
1617 """
1618 Convert an OpenSSL native context error failure into a Python
1619 exception.
1620
Alex Gaynor5945ea82015-09-05 14:59:06 -04001621 When a call to native OpenSSL X509_verify_cert fails, additional
1622 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001623 """
1624 errors = [
1625 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1626 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1627 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001628 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001629 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001630 # A context error should always be associated with a certificate, so we
1631 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001632 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001633 _cert = _lib.X509_dup(_x509)
1634 pycert = X509.__new__(X509)
1635 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001636 return X509StoreContextError(errors, pycert)
1637
Stephen Holsapple46a09252015-02-12 14:45:43 -08001638 def set_store(self, store):
1639 """
Dan Sully44e767a2016-06-04 18:05:27 -07001640 Set the context's X.509 store.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001641
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001642 .. versionadded:: 0.15
1643
Dan Sully44e767a2016-06-04 18:05:27 -07001644 :param X509Store store: The store description which will be used for
1645 the purposes of any *future* verifications.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001646 """
1647 self._store = store
1648
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001649 def verify_certificate(self):
1650 """
1651 Verify a certificate in a context.
1652
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001653 .. versionadded:: 0.15
1654
Alex Gaynorca87ff62015-09-04 23:31:03 -04001655 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001656 certificate in the context. Sets ``certificate`` attribute to
1657 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001658 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001659 # Always re-initialize the store context in case
Dan Sully44e767a2016-06-04 18:05:27 -07001660 # :meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001661 self._init()
1662 ret = _lib.X509_verify_cert(self._store_ctx)
1663 self._cleanup()
1664 if ret <= 0:
1665 raise self._exception_from_context()
1666
1667
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001668def load_certificate(type, buffer):
1669 """
1670 Load a certificate from a buffer
1671
1672 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1673
Dan Sully44e767a2016-06-04 18:05:27 -07001674 :param bytes buffer: The buffer the certificate is stored in
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001675
1676 :return: The X509 object
1677 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001678 if isinstance(buffer, _text_type):
1679 buffer = buffer.encode("ascii")
1680
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001681 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001682
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001683 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001684 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001685 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001686 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001687 else:
1688 raise ValueError(
1689 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001690
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001691 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001692 _raise_current_error()
1693
1694 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001695 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001696 return cert
1697
1698
1699def dump_certificate(type, cert):
1700 """
1701 Dump a certificate to a buffer
1702
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001703 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1704 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001705 :param cert: The certificate to dump
1706 :return: The buffer with the dumped certificate in
1707 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001708 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001709
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001710 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001711 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001712 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001713 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001714 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001715 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001716 else:
1717 raise ValueError(
1718 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1719 "FILETYPE_TEXT")
1720
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001721 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001722 return _bio_to_string(bio)
1723
1724
Cory Benfield6492f7c2015-10-27 16:57:58 +09001725def dump_publickey(type, pkey):
1726 """
Cory Benfield11c10192015-10-27 17:23:03 +09001727 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001728
Cory Benfield9c590b92015-10-28 14:55:05 +09001729 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001730 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001731 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001732 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001733 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001734 """
1735 bio = _new_mem_buf()
1736 if type == FILETYPE_PEM:
1737 write_bio = _lib.PEM_write_bio_PUBKEY
1738 elif type == FILETYPE_ASN1:
1739 write_bio = _lib.i2d_PUBKEY_bio
1740 else:
1741 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1742
1743 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001744 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001745 _raise_current_error()
1746
1747 return _bio_to_string(bio)
1748
1749
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001750def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1751 """
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001752 Dump the private key *pkey* into a buffer string encoded with the type
1753 *type*. Optionally (if *type* is :const:`FILETYPE_PEM`) encrypting it
1754 using *cipher* and *passphrase*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001755
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001756 :param type: The file type (one of :const:`FILETYPE_PEM`,
1757 :const:`FILETYPE_ASN1`, or :const:`FILETYPE_TEXT`)
1758 :param PKey pkey: The PKey to dump
1759 :param cipher: (optional) if encrypted PEM format, the cipher to use
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001760 :param passphrase: (optional) if encrypted PEM format, this can be either
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001761 the passphrase to use, or a callback for providing the passphrase.
1762
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001763 :return: The buffer with the dumped key in
Dan Sully44e767a2016-06-04 18:05:27 -07001764 :rtype: bytes
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001765 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001766 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001767
1768 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001769 if passphrase is None:
1770 raise TypeError(
1771 "if a value is given for cipher "
1772 "one must also be given for passphrase")
1773 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001774 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001775 raise ValueError("Invalid cipher name")
1776 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001777 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001778
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001779 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001780 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001781 result_code = _lib.PEM_write_bio_PrivateKey(
1782 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001783 helper.callback, helper.callback_args)
1784 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001785 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001786 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001787 elif type == FILETYPE_TEXT:
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001788 rsa = _ffi.gc(
1789 _lib.EVP_PKEY_get1_RSA(pkey._pkey),
1790 _lib.RSA_free
1791 )
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001792 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001793 else:
1794 raise ValueError(
1795 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1796 "FILETYPE_TEXT")
1797
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001798 _openssl_assert(result_code != 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001799
1800 return _bio_to_string(bio)
1801
1802
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001803class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001804 """
1805 A certificate revocation.
1806 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001807 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1808 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1809 # OCSP_crl_reason_str. We use the latter, just like the command line
1810 # program.
1811 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001812 b"unspecified",
1813 b"keyCompromise",
1814 b"CACompromise",
1815 b"affiliationChanged",
1816 b"superseded",
1817 b"cessationOfOperation",
1818 b"certificateHold",
1819 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001820 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001821
1822 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001823 revoked = _lib.X509_REVOKED_new()
1824 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001825
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001826 def set_serial(self, hex_str):
1827 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001828 Set the serial number.
1829
1830 The serial number is formatted as a hexadecimal number encoded in
1831 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001832
Dan Sully44e767a2016-06-04 18:05:27 -07001833 :param bytes hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001834
Dan Sully44e767a2016-06-04 18:05:27 -07001835 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001836 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001837 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1838 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001839 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001840 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001841 if not bn_result:
1842 raise ValueError("bad hex string")
1843
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001844 asn1_serial = _ffi.gc(
1845 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1846 _lib.ASN1_INTEGER_free)
1847 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001848
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001849 def get_serial(self):
1850 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001851 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001852
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001853 The serial number is formatted as a hexadecimal number encoded in
1854 ASCII.
1855
1856 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001857 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001858 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001859 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001860
Alex Gaynor67903a62016-06-02 10:37:13 -07001861 asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked)
1862 _openssl_assert(asn1_int != _ffi.NULL)
1863 result = _lib.i2a_ASN1_INTEGER(bio, asn1_int)
1864 _openssl_assert(result >= 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001865 return _bio_to_string(bio)
1866
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001867 def _delete_reason(self):
Alex Gaynor67903a62016-06-02 10:37:13 -07001868 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1869 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001870 obj = _lib.X509_EXTENSION_get_object(ext)
1871 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001872 _lib.X509_EXTENSION_free(ext)
Alex Gaynor67903a62016-06-02 10:37:13 -07001873 _lib.X509_REVOKED_delete_ext(self._revoked, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001874 break
1875
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001876 def set_reason(self, reason):
1877 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001878 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001879
Dan Sully44e767a2016-06-04 18:05:27 -07001880 If :data:`reason` is ``None``, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001881
1882 :param reason: The reason string.
Dan Sully44e767a2016-06-04 18:05:27 -07001883 :type reason: :class:`bytes` or :class:`NoneType`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001884
Dan Sully44e767a2016-06-04 18:05:27 -07001885 :return: ``None``
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001886
1887 .. seealso::
1888
Dan Sully44e767a2016-06-04 18:05:27 -07001889 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001890 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001891 """
1892 if reason is None:
1893 self._delete_reason()
1894 elif not isinstance(reason, bytes):
1895 raise TypeError("reason must be None or a byte string")
1896 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001897 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001898 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1899
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001900 new_reason_ext = _lib.ASN1_ENUMERATED_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07001901 _openssl_assert(new_reason_ext != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001902 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001903
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001904 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001905 _openssl_assert(set_result != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001906
1907 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001908 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1909 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001910 _openssl_assert(add_result == 1)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001911
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001912 def get_reason(self):
1913 """
Alex Gaynor80262fb2016-04-22 07:53:42 -04001914 Get the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001915
Dan Sully44e767a2016-06-04 18:05:27 -07001916 :return: The reason, or ``None`` if there is none.
1917 :rtype: bytes or NoneType
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001918
1919 .. seealso::
1920
Dan Sully44e767a2016-06-04 18:05:27 -07001921 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001922 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001923 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001924 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1925 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001926 obj = _lib.X509_EXTENSION_get_object(ext)
1927 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001928 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001929
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001930 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001931 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001932 print_result = _lib.M_ASN1_OCTET_STRING_print(
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001933 bio, _lib.X509_EXTENSION_get_data(ext)
Alex Gaynor5945ea82015-09-05 14:59:06 -04001934 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04001935 _openssl_assert(print_result != 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001936
1937 return _bio_to_string(bio)
1938
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001939 def all_reasons(self):
1940 """
1941 Return a list of all the supported reason strings.
1942
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001943 This list is a copy; modifying it does not change the supported reason
1944 strings.
1945
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001946 :return: A list of reason strings.
Dan Sully44e767a2016-06-04 18:05:27 -07001947 :rtype: :class:`list` of :class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001948 """
1949 return self._crl_reasons[:]
1950
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001951 def set_rev_date(self, when):
1952 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001953 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001954
Dan Sully44e767a2016-06-04 18:05:27 -07001955 :param bytes when: The timestamp of the revocation,
1956 as ASN.1 GENERALIZEDTIME.
1957 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001958 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001959 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1960 return _set_asn1_time(dt, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001961
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001962 def get_rev_date(self):
1963 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001964 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001965
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001966 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
Dan Sully44e767a2016-06-04 18:05:27 -07001967 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001968 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001969 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1970 return _get_asn1_time(dt)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001971
1972
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001973class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001974 """
1975 A certificate revocation list.
1976 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001977
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001978 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001979 crl = _lib.X509_CRL_new()
1980 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001981
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001982 def get_revoked(self):
1983 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001984 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001985
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001986 These revocations will be provided by value, not by reference.
1987 That means it's okay to mutate them: it won't affect this CRL.
1988
1989 :return: The revocations in this CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07001990 :rtype: :class:`tuple` of :class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001991 """
1992 results = []
Alex Gaynor67903a62016-06-02 10:37:13 -07001993 revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001994 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1995 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Paul Kehrer2fe23b02016-03-09 22:02:15 -04001996 revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001997 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001998 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001999 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002000 if results:
2001 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002002
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002003 def add_revoked(self, revoked):
2004 """
2005 Add a revoked (by value not reference) to the CRL structure
2006
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002007 This revocation will be added by value, not by reference. That
2008 means it's okay to mutate it after adding: it won't affect
2009 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002010
Dan Sully44e767a2016-06-04 18:05:27 -07002011 :param Revoked revoked: The new revocation.
2012 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002013 """
Paul Kehrer8dddb1a2016-03-09 21:48:04 -04002014 copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002015 _openssl_assert(copy != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002016
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002017 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Alex Gaynor09a386e2016-07-03 09:32:44 -04002018 _openssl_assert(add_result != 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002019
Dan Sully44e767a2016-06-04 18:05:27 -07002020 def get_issuer(self):
2021 """
2022 Get the CRL's issuer.
2023
2024 .. versionadded:: 16.1.0
2025
2026 :rtype: X509Name
2027 """
2028 _issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl))
2029 _openssl_assert(_issuer != _ffi.NULL)
2030 _issuer = _ffi.gc(_issuer, _lib.X509_NAME_free)
2031 issuer = X509Name.__new__(X509Name)
2032 issuer._name = _issuer
2033 return issuer
2034
2035 def set_version(self, version):
2036 """
2037 Set the CRL version.
2038
2039 .. versionadded:: 16.1.0
2040
2041 :param int version: The version of the CRL.
2042 :return: ``None``
2043 """
2044 _openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0)
2045
2046 def _set_boundary_time(self, which, when):
2047 return _set_asn1_time(which(self._crl), when)
2048
2049 def set_lastUpdate(self, when):
2050 """
2051 Set when the CRL was last updated.
2052
2053 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2054
2055 YYYYMMDDhhmmssZ
2056 YYYYMMDDhhmmss+hhmm
2057 YYYYMMDDhhmmss-hhmm
2058
2059 .. versionadded:: 16.1.0
2060
2061 :param bytes when: A timestamp string.
2062 :return: ``None``
2063 """
2064 return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when)
2065
2066 def set_nextUpdate(self, when):
2067 """
2068 Set when the CRL will next be udpated.
2069
2070 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2071
2072 YYYYMMDDhhmmssZ
2073 YYYYMMDDhhmmss+hhmm
2074 YYYYMMDDhhmmss-hhmm
2075
2076 .. versionadded:: 16.1.0
2077
2078 :param bytes when: A timestamp string.
2079 :return: ``None``
2080 """
2081 return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when)
2082
2083 def sign(self, issuer_cert, issuer_key, digest):
2084 """
2085 Sign the CRL.
2086
2087 Signing a CRL enables clients to associate the CRL itself with an
2088 issuer. Before a CRL is meaningful to other OpenSSL functions, it must
2089 be signed by an issuer.
2090
2091 This method implicitly sets the issuer's name based on the issuer
2092 certificate and private key used to sign the CRL.
2093
2094 .. versionadded:: 16.1.0
2095
2096 :param X509 issuer_cert: The issuer's certificate.
2097 :param PKey issuer_key: The issuer's private key.
2098 :param bytes digest: The digest method to sign the CRL with.
2099 """
2100 digest_obj = _lib.EVP_get_digestbyname(digest)
2101 _openssl_assert(digest_obj != _ffi.NULL)
2102 _lib.X509_CRL_set_issuer_name(
2103 self._crl, _lib.X509_get_subject_name(issuer_cert._x509))
2104 _lib.X509_CRL_sort(self._crl)
2105 result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj)
2106 _openssl_assert(result != 0)
2107
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002108 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002109 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002110 """
Dan Sully44e767a2016-06-04 18:05:27 -07002111 Export the CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002112
Dan Sully44e767a2016-06-04 18:05:27 -07002113 :param X509 cert: The certificate used to sign the CRL.
2114 :param PKey key: The key used to sign the CRL.
2115 :param int type: The export format, either :data:`FILETYPE_PEM`,
2116 :data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`.
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002117 :param int days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002118 :param bytes digest: The name of the message digest to use (eg
Alex Gaynor239e2d32016-09-11 12:36:35 -04002119 ``b"sha2566"``).
Dan Sully44e767a2016-06-04 18:05:27 -07002120 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002121 """
Dan Sully44e767a2016-06-04 18:05:27 -07002122
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002123 if not isinstance(cert, X509):
2124 raise TypeError("cert must be an X509 instance")
2125 if not isinstance(key, PKey):
2126 raise TypeError("key must be a PKey instance")
2127 if not isinstance(type, int):
2128 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002129
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002130 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002131 _warn(
2132 "The default message digest (md5) is deprecated. "
2133 "Pass the name of a message digest explicitly.",
2134 category=DeprecationWarning,
2135 stacklevel=2,
2136 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002137 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002138
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002139 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002140 if digest_obj == _ffi.NULL:
2141 raise ValueError("No such digest method")
2142
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002143 bio = _lib.BIO_new(_lib.BIO_s_mem())
Alex Gaynoradd5b072016-06-04 21:04:00 -07002144 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002145
Alex Gaynora738ed52015-09-05 11:17:10 -04002146 # A scratch time object to give different values to different CRL
2147 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002148 sometime = _lib.ASN1_TIME_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07002149 _openssl_assert(sometime != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002150
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002151 _lib.X509_gmtime_adj(sometime, 0)
2152 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002153
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002154 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2155 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002156
Alex Gaynor5945ea82015-09-05 14:59:06 -04002157 _lib.X509_CRL_set_issuer_name(
2158 self._crl, _lib.X509_get_subject_name(cert._x509)
2159 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002160
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002161 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002162 if not sign_result:
2163 _raise_current_error()
2164
Dominic Chenf05b2122015-10-13 16:32:35 +00002165 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002166
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002167
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002168CRLType = CRL
2169
2170
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002171class PKCS7(object):
2172 def type_is_signed(self):
2173 """
2174 Check if this NID_pkcs7_signed object
2175
2176 :return: True if the PKCS7 is of type signed
2177 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002178 return bool(_lib.PKCS7_type_is_signed(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002179
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002180 def type_is_enveloped(self):
2181 """
2182 Check if this NID_pkcs7_enveloped object
2183
2184 :returns: True if the PKCS7 is of type enveloped
2185 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002186 return bool(_lib.PKCS7_type_is_enveloped(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002187
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002188 def type_is_signedAndEnveloped(self):
2189 """
2190 Check if this NID_pkcs7_signedAndEnveloped object
2191
2192 :returns: True if the PKCS7 is of type signedAndEnveloped
2193 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002194 return bool(_lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002195
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002196 def type_is_data(self):
2197 """
2198 Check if this NID_pkcs7_data object
2199
2200 :return: True if the PKCS7 is of type data
2201 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002202 return bool(_lib.PKCS7_type_is_data(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002203
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002204 def get_type_name(self):
2205 """
2206 Returns the type name of the PKCS7 structure
2207
2208 :return: A string with the typename
2209 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002210 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2211 string_type = _lib.OBJ_nid2sn(nid)
2212 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002213
Alex Chanc6077062016-11-18 13:53:39 +00002214
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002215PKCS7Type = PKCS7
2216
2217
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002218class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002219 """
2220 A PKCS #12 archive.
2221 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002222
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002223 def __init__(self):
2224 self._pkey = None
2225 self._cert = None
2226 self._cacerts = None
2227 self._friendlyname = None
2228
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002229 def get_certificate(self):
2230 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002231 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002232
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002233 :return: The certificate, or :py:const:`None` if there is none.
2234 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002235 """
2236 return self._cert
2237
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002238 def set_certificate(self, cert):
2239 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002240 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002241
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002242 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002243 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002244
Dan Sully44e767a2016-06-04 18:05:27 -07002245 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002246 """
2247 if not isinstance(cert, X509):
2248 raise TypeError("cert must be an X509 instance")
2249 self._cert = cert
2250
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002251 def get_privatekey(self):
2252 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002253 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002254
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002255 :return: The private key, or :py:const:`None` if there is none.
2256 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002257 """
2258 return self._pkey
2259
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002260 def set_privatekey(self, pkey):
2261 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002262 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002263
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002264 :param pkey: The new private key, or :py:const:`None` to unset it.
2265 :type pkey: :py:class:`PKey` or :py:const:`None`
2266
Dan Sully44e767a2016-06-04 18:05:27 -07002267 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002268 """
2269 if not isinstance(pkey, PKey):
2270 raise TypeError("pkey must be a PKey instance")
2271 self._pkey = pkey
2272
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002273 def get_ca_certificates(self):
2274 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002275 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002276
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002277 :return: A tuple with the CA certificates in the chain, or
2278 :py:const:`None` if there are none.
2279 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002280 """
2281 if self._cacerts is not None:
2282 return tuple(self._cacerts)
2283
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002284 def set_ca_certificates(self, cacerts):
2285 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002286 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002287
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002288 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2289 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002290 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002291
Dan Sully44e767a2016-06-04 18:05:27 -07002292 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002293 """
2294 if cacerts is None:
2295 self._cacerts = None
2296 else:
2297 cacerts = list(cacerts)
2298 for cert in cacerts:
2299 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002300 raise TypeError(
2301 "iterable must only contain X509 instances"
2302 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002303 self._cacerts = cacerts
2304
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002305 def set_friendlyname(self, name):
2306 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002307 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002308
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002309 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002310 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002311
Dan Sully44e767a2016-06-04 18:05:27 -07002312 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002313 """
2314 if name is None:
2315 self._friendlyname = None
2316 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002317 raise TypeError(
2318 "name must be a byte string or None (not %r)" % (name,)
2319 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002320 self._friendlyname = name
2321
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002322 def get_friendlyname(self):
2323 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002324 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002325
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002326 :returns: The friendly name, or :py:const:`None` if there is none.
2327 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002328 """
2329 return self._friendlyname
2330
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002331 def export(self, passphrase=None, iter=2048, maciter=1):
2332 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002333 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002334
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002335 For more information, see the :c:func:`PKCS12_create` man page.
2336
2337 :param passphrase: The passphrase used to encrypt the structure. Unlike
2338 some other passphrase arguments, this *must* be a string, not a
2339 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002340 :type passphrase: :py:data:`bytes`
2341
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002342 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002343 :type iter: :py:data:`int`
2344
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002345 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002346 :type maciter: :py:data:`int`
2347
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002348 :return: The string representation of the PKCS #12 structure.
2349 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002350 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002351 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002352
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002353 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002354 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002355 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002356 cacerts = _lib.sk_X509_new_null()
2357 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002358 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002359 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002360
2361 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002362 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002363
2364 friendlyname = self._friendlyname
2365 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002366 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002367
2368 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002369 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002370 else:
2371 pkey = self._pkey._pkey
2372
2373 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002374 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002375 else:
2376 cert = self._cert._x509
2377
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002378 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002379 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002380 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2381 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002382 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002383 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002384 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002385 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002386
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002387 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002388 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002389 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002390
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002391
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002392PKCS12Type = PKCS12
2393
2394
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002395class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002396 """
2397 A Netscape SPKI object.
2398 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002399
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002400 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002401 spki = _lib.NETSCAPE_SPKI_new()
2402 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002403
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002404 def sign(self, pkey, digest):
2405 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002406 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002407
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002408 :param pkey: The private key to sign with.
2409 :type pkey: :py:class:`PKey`
2410
2411 :param digest: The message digest to use.
2412 :type digest: :py:class:`bytes`
2413
Dan Sully44e767a2016-06-04 18:05:27 -07002414 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002415 """
2416 if pkey._only_public:
2417 raise ValueError("Key has only public part")
2418
2419 if not pkey._initialized:
2420 raise ValueError("Key is uninitialized")
2421
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002422 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002423 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002424 raise ValueError("No such digest method")
2425
Alex Gaynor5945ea82015-09-05 14:59:06 -04002426 sign_result = _lib.NETSCAPE_SPKI_sign(
2427 self._spki, pkey._pkey, digest_obj
2428 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04002429 _openssl_assert(sign_result > 0)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002430
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002431 def verify(self, key):
2432 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002433 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002434
Hynek Schlawack01c31672016-12-11 15:14:09 +01002435 :param PKey key: The public key that signature is supposedly from.
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002436
Hynek Schlawack01c31672016-12-11 15:14:09 +01002437 :return: ``True`` if the signature is correct.
2438 :rtype: bool
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002439
Hynek Schlawack01c31672016-12-11 15:14:09 +01002440 :raises OpenSSL.crypto.Error: If the signature is invalid, or there was
2441 a problem verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002442 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002443 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002444 if answer <= 0:
2445 _raise_current_error()
2446 return True
2447
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002448 def b64_encode(self):
2449 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002450 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002451
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002452 :return: The base64 encoded string.
2453 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002454 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002455 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2456 result = _ffi.string(encoded)
Paul Kehrer0dcacf72016-03-17 19:25:39 -04002457 _lib.OPENSSL_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002458 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002459
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002460 def get_pubkey(self):
2461 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002462 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002463
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002464 :return: The public key.
2465 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002466 """
2467 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002468 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002469 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002470 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002471 pkey._only_public = True
2472 return pkey
2473
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002474 def set_pubkey(self, pkey):
2475 """
2476 Set the public key of the certificate
2477
2478 :param pkey: The public key
Dan Sully44e767a2016-06-04 18:05:27 -07002479 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002480 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002481 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -04002482 _openssl_assert(set_result == 1)
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002483
2484
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002485NetscapeSPKIType = NetscapeSPKI
2486
2487
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002488class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002489 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002490 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002491 raise ValueError(
2492 "only FILETYPE_PEM key format supports encryption"
2493 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002494 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002495 self._more_args = more_args
2496 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002497 self._problems = []
2498
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002499 @property
2500 def callback(self):
2501 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002502 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002503 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002504 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002505 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002506 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002507 else:
Hynek Schlawack33675f92016-11-18 14:55:06 +01002508 raise TypeError(
2509 "Last argument must be a byte string or a callable."
2510 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002511
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002512 @property
2513 def callback_args(self):
2514 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002515 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002516 elif isinstance(self._passphrase, bytes):
2517 return self._passphrase
2518 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002519 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002520 else:
Hynek Schlawack33675f92016-11-18 14:55:06 +01002521 raise TypeError(
2522 "Last argument must be a byte string or a callable."
2523 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002524
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002525 def raise_if_problem(self, exceptionType=Error):
2526 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002527 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002528 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002529 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002530 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002531 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002532 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002533
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002534 def _read_passphrase(self, buf, size, rwflag, userdata):
2535 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002536 if self._more_args:
2537 result = self._passphrase(size, rwflag, userdata)
2538 else:
2539 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002540 if not isinstance(result, bytes):
2541 raise ValueError("String expected")
2542 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002543 if self._truncate:
2544 result = result[:size]
2545 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002546 raise ValueError(
2547 "passphrase returned by callback is too long"
2548 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002549 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002550 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002551 return len(result)
2552 except Exception as e:
2553 self._problems.append(e)
2554 return 0
2555
2556
Cory Benfield6492f7c2015-10-27 16:57:58 +09002557def load_publickey(type, buffer):
2558 """
Cory Benfield11c10192015-10-27 17:23:03 +09002559 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002560
Cory Benfield9c590b92015-10-28 14:55:05 +09002561 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002562 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002563 :param buffer: The buffer the key is stored in.
2564 :type buffer: A Python string object, either unicode or bytestring.
2565 :return: The PKey object.
2566 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002567 """
2568 if isinstance(buffer, _text_type):
2569 buffer = buffer.encode("ascii")
2570
2571 bio = _new_mem_buf(buffer)
2572
2573 if type == FILETYPE_PEM:
2574 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2575 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2576 elif type == FILETYPE_ASN1:
2577 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2578 else:
2579 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2580
2581 if evp_pkey == _ffi.NULL:
2582 _raise_current_error()
2583
2584 pkey = PKey.__new__(PKey)
2585 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Paul Kehrer32fc4e62016-06-03 15:21:44 -07002586 pkey._only_public = True
Cory Benfield6492f7c2015-10-27 16:57:58 +09002587 return pkey
2588
2589
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002590def load_privatekey(type, buffer, passphrase=None):
2591 """
2592 Load a private key from a buffer
2593
2594 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2595 :param buffer: The buffer the key is stored in
2596 :param passphrase: (optional) if encrypted PEM format, this can be
2597 either the passphrase to use, or a callback for
2598 providing the passphrase.
2599
2600 :return: The PKey object
2601 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002602 if isinstance(buffer, _text_type):
2603 buffer = buffer.encode("ascii")
2604
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002605 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002606
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002607 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002608 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002609 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2610 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002611 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002612 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002613 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002614 else:
2615 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2616
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002617 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002618 _raise_current_error()
2619
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002620 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002621 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002622 return pkey
2623
2624
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002625def dump_certificate_request(type, req):
2626 """
2627 Dump a certificate request to a buffer
2628
2629 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2630 :param req: The certificate request to dump
2631 :return: The buffer with the dumped certificate request in
2632 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002633 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002634
2635 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002636 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002637 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002638 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002639 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002640 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002641 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002642 raise ValueError(
2643 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2644 "FILETYPE_TEXT"
2645 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002646
Alex Gaynor09a386e2016-07-03 09:32:44 -04002647 _openssl_assert(result_code != 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002648
2649 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002650
2651
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002652def load_certificate_request(type, buffer):
2653 """
2654 Load a certificate request from a buffer
2655
2656 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2657 :param buffer: The buffer the certificate request is stored in
2658 :return: The X509Req object
2659 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002660 if isinstance(buffer, _text_type):
2661 buffer = buffer.encode("ascii")
2662
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002663 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002664
2665 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002666 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002667 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002668 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002669 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002670 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002671
Alex Gaynoradd5b072016-06-04 21:04:00 -07002672 _openssl_assert(req != _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002673
2674 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002675 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002676 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002677
2678
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002679def sign(pkey, data, digest):
2680 """
2681 Sign data with a digest
2682
2683 :param pkey: Pkey to sign with
2684 :param data: data to be signed
2685 :param digest: message digest to use
2686 :return: signature
2687 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002688 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002689
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002690 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002691 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002692 raise ValueError("No such digest method")
2693
Alex Gaynor67903a62016-06-02 10:37:13 -07002694 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002695 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002696
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002697 _lib.EVP_SignInit(md_ctx, digest_obj)
2698 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002699
Colleen Murphye09399b2016-03-01 17:40:49 -08002700 pkey_length = (PKey.bits(pkey) + 7) // 8
2701 signature_buffer = _ffi.new("unsigned char[]", pkey_length)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002702 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002703 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002704 md_ctx, signature_buffer, signature_length, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -04002705 _openssl_assert(final_result == 1)
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)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002727 _openssl_assert(pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002728 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002729
Alex Gaynor67903a62016-06-02 10:37:13 -07002730 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002731 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002732
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002733 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2734 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002735 verify_result = _lib.EVP_VerifyFinal(
2736 md_ctx, signature, len(signature), pkey
2737 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002738
2739 if verify_result != 1:
2740 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002741
2742
Dominic Chenf05b2122015-10-13 16:32:35 +00002743def dump_crl(type, crl):
2744 """
2745 Dump a certificate revocation list to a buffer.
2746
2747 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2748 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002749 :param CRL crl: The CRL to dump.
2750
Dominic Chenf05b2122015-10-13 16:32:35 +00002751 :return: The buffer with the CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07002752 :rtype: bytes
Dominic Chenf05b2122015-10-13 16:32:35 +00002753 """
2754 bio = _new_mem_buf()
2755
2756 if type == FILETYPE_PEM:
2757 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2758 elif type == FILETYPE_ASN1:
2759 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2760 elif type == FILETYPE_TEXT:
2761 ret = _lib.X509_CRL_print(bio, crl._crl)
2762 else:
2763 raise ValueError(
2764 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2765 "FILETYPE_TEXT")
2766
2767 assert ret == 1
2768 return _bio_to_string(bio)
2769
2770
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002771def load_crl(type, buffer):
2772 """
2773 Load a certificate revocation list from a buffer
2774
2775 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2776 :param buffer: The buffer the CRL is stored in
2777
2778 :return: The PKey object
2779 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002780 if isinstance(buffer, _text_type):
2781 buffer = buffer.encode("ascii")
2782
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002783 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002784
2785 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002786 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002787 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002788 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002789 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002790 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2791
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002792 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002793 _raise_current_error()
2794
2795 result = CRL.__new__(CRL)
2796 result._crl = crl
2797 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002798
2799
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002800def load_pkcs7_data(type, buffer):
2801 """
2802 Load pkcs7 data from a buffer
2803
2804 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2805 :param buffer: The buffer with the pkcs7 data.
2806 :return: The PKCS7 object
2807 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002808 if isinstance(buffer, _text_type):
2809 buffer = buffer.encode("ascii")
2810
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002811 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002812
2813 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002814 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002815 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002816 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002817 else:
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002818 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2819
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002820 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002821 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002822
2823 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002824 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002825 return pypkcs7
2826
2827
Stephen Holsapple38482622014-04-05 20:29:34 -07002828def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002829 """
2830 Load a PKCS12 object from a buffer
2831
2832 :param buffer: The buffer the certificate is stored in
2833 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2834 :returns: The PKCS12 object
2835 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002836 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002837
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002838 if isinstance(buffer, _text_type):
2839 buffer = buffer.encode("ascii")
2840
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002841 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002842
Stephen Holsapple38482622014-04-05 20:29:34 -07002843 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2844 # password based encryption no password and a zero length password are two
2845 # different things, but OpenSSL implementation will try both to figure out
2846 # which one works.
2847 if not passphrase:
2848 passphrase = _ffi.NULL
2849
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002850 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2851 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002852 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002853 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002854
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002855 pkey = _ffi.new("EVP_PKEY**")
2856 cert = _ffi.new("X509**")
2857 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002858
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002859 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002860 if not parse_result:
2861 _raise_current_error()
2862
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002863 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002864
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002865 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2866 # queue for no particular reason. This error isn't interesting to anyone
2867 # outside this function. It's not even interesting to us. Get rid of it.
2868 try:
2869 _raise_current_error()
2870 except Error:
2871 pass
2872
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002873 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002874 pykey = None
2875 else:
2876 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002877 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002878
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002879 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002880 pycert = None
2881 friendlyname = None
2882 else:
2883 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002884 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002885
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002886 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002887 friendlyname_buffer = _lib.X509_alias_get0(
2888 cert[0], friendlyname_length
2889 )
2890 friendlyname = _ffi.buffer(
2891 friendlyname_buffer, friendlyname_length[0]
2892 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002893 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002894 friendlyname = None
2895
2896 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002897 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002898 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002899 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002900 pycacerts.append(pycacert)
2901 if not pycacerts:
2902 pycacerts = None
2903
2904 pkcs12 = PKCS12.__new__(PKCS12)
2905 pkcs12._pkey = pykey
2906 pkcs12._cert = pycert
2907 pkcs12._cacerts = pycacerts
2908 pkcs12._friendlyname = friendlyname
2909 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002910
2911
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002912# There are no direct unit tests for this initialization. It is tested
2913# indirectly since it is necessary for functions like dump_privatekey when
2914# using encryption.
2915#
2916# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2917# and some other similar tests may fail without this (though they may not if
2918# the Python runtime has already done some initialization of the underlying
2919# OpenSSL library (and is linked against the same one that cryptography is
2920# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002921_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002922
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002923# This is similar but exercised mainly by exception_from_error_queue. It calls
2924# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2925_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002926
2927
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002928# Set the default string mask to match OpenSSL upstream (since 2005) and
2929# RFC5280 recommendations.
2930_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')