blob: 79307b8ef840941f8c661718948ddf53fe0a2686 [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__
6
7from six import (
8 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -04009 text_type as _text_type,
Alex Gaynor03737182020-07-23 20:40:46 -040010 PY2 as _PY2,
11)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080012
Alex Gaynorbb971ae2020-08-05 01:14:16 -040013from cryptography import utils, x509
Paul Kehrer72d968b2016-07-29 15:31:04 +080014from cryptography.hazmat.primitives.asymmetric import dsa, rsa
15
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050016from OpenSSL._util import (
17 ffi as _ffi,
18 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050019 exception_from_error_queue as _exception_from_error_queue,
20 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040021 native as _native,
22 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040023 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Alex Gaynor67903a62016-06-02 10:37:13 -070024 make_assert as _make_assert,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040025)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080026
Nicolas Karolak736c6212017-11-26 14:40:28 +010027__all__ = [
Alex Gaynor03737182020-07-23 20:40:46 -040028 "FILETYPE_PEM",
29 "FILETYPE_ASN1",
30 "FILETYPE_TEXT",
31 "TYPE_RSA",
32 "TYPE_DSA",
33 "Error",
34 "PKey",
35 "get_elliptic_curves",
36 "get_elliptic_curve",
37 "X509Name",
38 "X509Extension",
39 "X509Req",
40 "X509",
41 "X509StoreFlags",
42 "X509Store",
43 "X509StoreContextError",
44 "X509StoreContext",
45 "load_certificate",
46 "dump_certificate",
47 "dump_publickey",
48 "dump_privatekey",
49 "Revoked",
50 "CRL",
51 "PKCS7",
52 "PKCS12",
53 "NetscapeSPKI",
54 "load_publickey",
55 "load_privatekey",
56 "dump_certificate_request",
57 "load_certificate_request",
58 "sign",
59 "verify",
60 "dump_crl",
61 "load_crl",
62 "load_pkcs7_data",
63 "load_pkcs12",
Nicolas Karolak736c6212017-11-26 14:40:28 +010064]
65
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050066FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
67FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080068
69# TODO This was an API mistake. OpenSSL has no such constant.
70FILETYPE_TEXT = 2 ** 16 - 1
71
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050072TYPE_RSA = _lib.EVP_PKEY_RSA
73TYPE_DSA = _lib.EVP_PKEY_DSA
Igr2f874f22019-01-21 21:39:37 +030074TYPE_DH = _lib.EVP_PKEY_DH
75TYPE_EC = _lib.EVP_PKEY_EC
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080076
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080077
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050078class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050079 """
80 An error occurred in an `OpenSSL.crypto` API.
81 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050082
83
84_raise_current_error = partial(_exception_from_error_queue, Error)
Alex Gaynor67903a62016-06-02 10:37:13 -070085_openssl_assert = _make_assert(Error)
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050086
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070087
Paul Kehrereb633842016-10-06 11:22:01 +020088def _get_backend():
89 """
90 Importing the backend from cryptography has the side effect of activating
91 the osrandom engine. This mutates the global state of OpenSSL in the
92 process and causes issues for various programs that use subinterpreters or
93 embed Python. By putting the import in this function we can avoid
94 triggering this side effect unless _get_backend is called.
95 """
96 from cryptography.hazmat.backends.openssl.backend import backend
Alex Gaynor03737182020-07-23 20:40:46 -040097
Paul Kehrereb633842016-10-06 11:22:01 +020098 return backend
99
100
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500101def _untested_error(where):
102 """
103 An OpenSSL API failed somehow. Additionally, the failure which was
104 encountered isn't one that's exercised by the test suite so future behavior
105 of pyOpenSSL is now somewhat less predictable.
106 """
107 raise RuntimeError("Unknown %s failure" % (where,))
108
109
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500110def _new_mem_buf(buffer=None):
111 """
112 Allocate a new OpenSSL memory BIO.
113
114 Arrange for the garbage collector to clean it up automatically.
115
116 :param buffer: None or some bytes to use to put into the BIO so that they
117 can be read out.
118 """
119 if buffer is None:
120 bio = _lib.BIO_new(_lib.BIO_s_mem())
121 free = _lib.BIO_free
122 else:
123 data = _ffi.new("char[]", buffer)
124 bio = _lib.BIO_new_mem_buf(data, len(buffer))
Alex Gaynor5945ea82015-09-05 14:59:06 -0400125
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500126 # Keep the memory alive as long as the bio is alive!
127 def free(bio, ref=data):
128 return _lib.BIO_free(bio)
129
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700130 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500131
132 bio = _ffi.gc(bio, free)
133 return bio
134
135
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800136def _bio_to_string(bio):
137 """
138 Copy the contents of an OpenSSL BIO object into a Python byte string.
139 """
Alex Gaynor03737182020-07-23 20:40:46 -0400140 result_buffer = _ffi.new("char**")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500141 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
142 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800143
144
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800145def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500146 """
147 The the time value of an ASN1 time object.
148
Moriyoshi Koizumi80b25ef2017-06-22 00:54:20 +0900149 @param boundary: An ASN1_TIME pointer (or an object safely
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500150 castable to that type) which will have its value set.
151 @param when: A string representation of the desired time value.
152
153 @raise TypeError: If C{when} is not a L{bytes} string.
154 @raise ValueError: If C{when} does not represent a time in the required
155 format.
156 @raise RuntimeError: If the time value cannot be set for some other
157 (unspecified) reason.
158 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800159 if not isinstance(when, bytes):
160 raise TypeError("when must be a byte string")
161
Moriyoshi Koizumi80b25ef2017-06-22 00:54:20 +0900162 set_result = _lib.ASN1_TIME_set_string(boundary, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800163 if set_result == 0:
Moriyoshi Koizumi80b25ef2017-06-22 00:54:20 +0900164 raise ValueError("Invalid string")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800165
Alex Gaynor510293e2016-06-02 12:07:59 -0700166
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800167def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500168 """
169 Retrieve the time value of an ASN1 time object.
170
171 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
172 that type) from which the time value will be retrieved.
173
174 @return: The time value from C{timestamp} as a L{bytes} string in a certain
175 format. Or C{None} if the object contains no time value.
176 """
Alex Gaynor03737182020-07-23 20:40:46 -0400177 string_timestamp = _ffi.cast("ASN1_STRING*", timestamp)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500178 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800179 return None
Alex Gaynor5945ea82015-09-05 14:59:06 -0400180 elif (
181 _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
182 ):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500183 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800184 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500185 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
186 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
187 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500188 # This may happen:
189 # - if timestamp was not an ASN1_TIME
190 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
191 # - if a copy of the time data from timestamp cannot be made for
192 # the newly allocated ASN1_GENERALIZEDTIME
193 #
194 # These are difficult to test. cffi enforces the ASN1_TIME type.
195 # Memory allocation failures are a pain to trigger
196 # deterministically.
197 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800198 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500199 string_timestamp = _ffi.cast(
Alex Gaynor03737182020-07-23 20:40:46 -0400200 "ASN1_STRING*", generalized_timestamp[0]
201 )
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500202 string_data = _lib.ASN1_STRING_data(string_timestamp)
203 string_result = _ffi.string(string_data)
204 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800205 return string_result
206
207
Alex Gaynor4aa52c32017-11-20 09:04:08 -0500208class _X509NameInvalidator(object):
209 def __init__(self):
210 self._names = []
211
212 def add(self, name):
213 self._names.append(name)
214
215 def clear(self):
216 for name in self._names:
217 # Breaks the object, but also prevents UAF!
218 del name._name
219
220
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800221class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200222 """
223 A class representing an DSA or RSA public key or key pair.
224 """
Alex Gaynor03737182020-07-23 20:40:46 -0400225
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800226 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800227 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800228
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800229 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500230 pkey = _lib.EVP_PKEY_new()
231 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800232 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800233
Paul Kehrer72d968b2016-07-29 15:31:04 +0800234 def to_cryptography_key(self):
235 """
236 Export as a ``cryptography`` key.
237
238 :rtype: One of ``cryptography``'s `key interfaces`_.
239
240 .. _key interfaces: https://cryptography.io/en/latest/hazmat/\
241 primitives/asymmetric/rsa/#key-interfaces
242
243 .. versionadded:: 16.1.0
244 """
Paul Kehrereb633842016-10-06 11:22:01 +0200245 backend = _get_backend()
Paul Kehrer72d968b2016-07-29 15:31:04 +0800246 if self._only_public:
247 return backend._evp_pkey_to_public_key(self._pkey)
248 else:
249 return backend._evp_pkey_to_private_key(self._pkey)
250
251 @classmethod
252 def from_cryptography_key(cls, crypto_key):
253 """
254 Construct based on a ``cryptography`` *crypto_key*.
255
256 :param crypto_key: A ``cryptography`` key.
257 :type crypto_key: One of ``cryptography``'s `key interfaces`_.
258
259 :rtype: PKey
260
261 .. versionadded:: 16.1.0
262 """
263 pkey = cls()
Alex Gaynor03737182020-07-23 20:40:46 -0400264 if not isinstance(
265 crypto_key,
266 (
267 rsa.RSAPublicKey,
268 rsa.RSAPrivateKey,
269 dsa.DSAPublicKey,
270 dsa.DSAPrivateKey,
271 ),
272 ):
Paul Kehrer72d968b2016-07-29 15:31:04 +0800273 raise TypeError("Unsupported key type")
274
275 pkey._pkey = crypto_key._evp_pkey
276 if isinstance(crypto_key, (rsa.RSAPublicKey, dsa.DSAPublicKey)):
277 pkey._only_public = True
278 pkey._initialized = True
279 return pkey
280
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800281 def generate_key(self, type, bits):
282 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700283 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800284
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200285 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800286
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200287 :param type: The key type.
288 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
289 :param bits: The number of bits.
290 :type bits: :py:data:`int` ``>= 0``
291 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
292 of the appropriate type.
293 :raises ValueError: If the number of bits isn't an integer of
294 the appropriate size.
Dan Sully44e767a2016-06-04 18:05:27 -0700295 :return: ``None``
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800296 """
297 if not isinstance(type, int):
298 raise TypeError("type must be an integer")
299
300 if not isinstance(bits, int):
301 raise TypeError("bits must be an integer")
302
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800303 if type == TYPE_RSA:
304 if bits <= 0:
305 raise ValueError("Invalid number of bits")
306
David Benjamin179eb1d2018-06-05 17:56:07 -0400307 # TODO Check error return
308 exponent = _lib.BN_new()
309 exponent = _ffi.gc(exponent, _lib.BN_free)
310 _lib.BN_set_word(exponent, _lib.RSA_F4)
311
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500312 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800313
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500314 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400315 _openssl_assert(result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800316
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500317 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400318 _openssl_assert(result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800319
320 elif type == TYPE_DSA:
Paul Kehrera0860b92016-03-09 21:39:27 -0400321 dsa = _lib.DSA_new()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700322 _openssl_assert(dsa != _ffi.NULL)
Paul Kehrerafa5a662016-03-10 10:29:28 -0400323
324 dsa = _ffi.gc(dsa, _lib.DSA_free)
Paul Kehrera0860b92016-03-09 21:39:27 -0400325 res = _lib.DSA_generate_parameters_ex(
326 dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL
327 )
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700328 _openssl_assert(res == 1)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400329
330 _openssl_assert(_lib.DSA_generate_key(dsa) == 1)
331 _openssl_assert(_lib.EVP_PKEY_set1_DSA(self._pkey, dsa) == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800332 else:
333 raise Error("No such key type")
334
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800335 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800336
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800337 def check(self):
338 """
339 Check the consistency of an RSA private key.
340
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200341 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
342
Hynek Schlawack01c31672016-12-11 15:14:09 +0100343 :return: ``True`` if key is consistent.
344
345 :raise OpenSSL.crypto.Error: if the key is inconsistent.
346
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800347 :raise TypeError: if the key is of a type which cannot be checked.
348 Only RSA keys can currently be checked.
349 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800350 if self._only_public:
351 raise TypeError("public key only")
352
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100353 if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800354 raise TypeError("key type unsupported")
355
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500356 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
357 rsa = _ffi.gc(rsa, _lib.RSA_free)
358 result = _lib.RSA_check_key(rsa)
Mrmaxmeier8cd3b172020-03-11 22:03:59 +0100359 if result == 1:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800360 return True
361 _raise_current_error()
362
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800363 def type(self):
364 """
365 Returns the type of the key
366
367 :return: The type of the key.
368 """
Alex Gaynor0d2aec52017-05-31 04:26:27 -0400369 return _lib.EVP_PKEY_id(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800370
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800371 def bits(self):
372 """
373 Returns the number of bits of the key
374
375 :return: The number of bits of the key.
376 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500377 return _lib.EVP_PKEY_bits(self._pkey)
Alex Chanc6077062016-11-18 13:53:39 +0000378
379
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400380class _EllipticCurve(object):
381 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400382 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400383
384 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
385 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
386 instances each of which represents one curve supported by the system.
387 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400388 """
Alex Gaynor03737182020-07-23 20:40:46 -0400389
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400390 _curves = None
391
Alex Gaynor26f1a922019-11-18 00:37:39 -0500392 if not _PY2:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400393 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400394 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400395 """
396 Implement cooperation with the right-hand side argument of ``!=``.
397
398 Python 3 seems to have dropped this cooperation in this very narrow
399 circumstance.
400 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400401 if isinstance(other, _EllipticCurve):
402 return super(_EllipticCurve, self).__ne__(other)
403 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400404
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400405 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400406 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400407 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400408 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400409
410 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400411
412 :return: A :py:type:`set` of ``cls`` instances giving the names of the
413 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400414 """
Alex Chan84902a22017-04-20 11:50:47 +0100415 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
Alex Gaynor03737182020-07-23 20:40:46 -0400416 builtin_curves = _ffi.new("EC_builtin_curve[]", num_curves)
Alex Chan84902a22017-04-20 11:50:47 +0100417 # The return value on this call should be num_curves again. We
418 # could check it to make sure but if it *isn't* then.. what could
419 # we do? Abort the whole process, I suppose...? -exarkun
420 lib.EC_get_builtin_curves(builtin_curves, num_curves)
Alex Gaynor03737182020-07-23 20:40:46 -0400421 return set(cls.from_nid(lib, c.nid) for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400422
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400423 @classmethod
424 def _get_elliptic_curves(cls, lib):
425 """
426 Get, cache, and return the curves supported by OpenSSL.
427
428 :param lib: The OpenSSL library binding object.
429
430 :return: A :py:type:`set` of ``cls`` instances giving the names of the
431 elliptic curves the underlying library supports.
432 """
433 if cls._curves is None:
434 cls._curves = cls._load_elliptic_curves(lib)
435 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400436
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400437 @classmethod
438 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400439 """
440 Instantiate a new :py:class:`_EllipticCurve` associated with the given
441 OpenSSL NID.
442
443 :param lib: The OpenSSL library binding object.
444
445 :param nid: The OpenSSL NID the resulting curve object will represent.
446 This must be a curve NID (and not, for example, a hash NID) or
447 subsequent operations will fail in unpredictable ways.
448 :type nid: :py:class:`int`
449
450 :return: The curve object.
451 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400452 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
453
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400454 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400455 """
456 :param _lib: The :py:mod:`cryptography` binding instance used to
457 interface with OpenSSL.
458
459 :param _nid: The OpenSSL NID identifying the curve this object
460 represents.
461 :type _nid: :py:class:`int`
462
463 :param name: The OpenSSL short name identifying the curve this object
464 represents.
465 :type name: :py:class:`unicode`
466 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400467 self._lib = lib
468 self._nid = nid
469 self.name = name
470
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400471 def __repr__(self):
472 return "<Curve %r>" % (self.name,)
473
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400474 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400475 """
476 Create a new OpenSSL EC_KEY structure initialized to use this curve.
477
478 The structure is automatically garbage collected when the Python object
479 is garbage collected.
480 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400481 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
482 return _ffi.gc(key, _lib.EC_KEY_free)
483
484
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400485def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400486 """
487 Return a set of objects representing the elliptic curves supported in the
488 OpenSSL build in use.
489
490 The curve objects have a :py:class:`unicode` ``name`` attribute by which
491 they identify themselves.
492
493 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400494 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
495 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400496 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400497 return _EllipticCurve._get_elliptic_curves(_lib)
498
499
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400500def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400501 """
502 Return a single curve object selected by name.
503
504 See :py:func:`get_elliptic_curves` for information about curve objects.
505
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400506 :param name: The OpenSSL short name identifying the curve object to
507 retrieve.
508 :type name: :py:class:`unicode`
509
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400510 If the named curve is not supported then :py:class:`ValueError` is raised.
511 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400512 for curve in get_elliptic_curves():
513 if curve.name == name:
514 return curve
515 raise ValueError("unknown curve name", name)
516
517
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800518class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200519 """
520 An X.509 Distinguished Name.
521
522 :ivar countryName: The country of the entity.
523 :ivar C: Alias for :py:attr:`countryName`.
524
525 :ivar stateOrProvinceName: The state or province of the entity.
526 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
527
528 :ivar localityName: The locality of the entity.
529 :ivar L: Alias for :py:attr:`localityName`.
530
531 :ivar organizationName: The organization name of the entity.
532 :ivar O: Alias for :py:attr:`organizationName`.
533
534 :ivar organizationalUnitName: The organizational unit of the entity.
535 :ivar OU: Alias for :py:attr:`organizationalUnitName`
536
537 :ivar commonName: The common name of the entity.
538 :ivar CN: Alias for :py:attr:`commonName`.
539
540 :ivar emailAddress: The e-mail address of the entity.
541 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400542
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800543 def __init__(self, name):
544 """
545 Create a new X509Name, copying the given X509Name instance.
546
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200547 :param name: The name to copy.
548 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800549 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500550 name = _lib.X509_NAME_dup(name._name)
551 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800552
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800553 def __setattr__(self, name, value):
Alex Gaynor03737182020-07-23 20:40:46 -0400554 if name.startswith("_"):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800555 return super(X509Name, self).__setattr__(name, value)
556
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800557 # Note: we really do not want str subclasses here, so we do not use
558 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800559 if type(name) is not str:
Alex Gaynor03737182020-07-23 20:40:46 -0400560 raise TypeError(
561 "attribute name must be string, not '%.200s'"
562 % (type(value).__name__,)
563 )
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800564
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500565 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500566 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800567 try:
568 _raise_current_error()
569 except Error:
570 pass
571 raise AttributeError("No such attribute")
572
573 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500574 for i in range(_lib.X509_NAME_entry_count(self._name)):
575 ent = _lib.X509_NAME_get_entry(self._name, i)
576 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
577 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800578 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500579 ent = _lib.X509_NAME_delete_entry(self._name, i)
580 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800581 break
582
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500583 if isinstance(value, _text_type):
Alex Gaynor03737182020-07-23 20:40:46 -0400584 value = value.encode("utf-8")
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500586 add_result = _lib.X509_NAME_add_entry_by_NID(
Alex Gaynor03737182020-07-23 20:40:46 -0400587 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0
588 )
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800589 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500590 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800591
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800592 def __getattr__(self, name):
593 """
594 Find attribute. An X509Name object has the following attributes:
595 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400596 organization (alias O), organizationalUnit (alias OU), commonName
597 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800598 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500599 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500600 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800601 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
602 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
603 # push something onto the error queue. If we don't clean that up
604 # now, someone else will bump into it later and be quite confused.
605 # See lp#314814.
606 try:
607 _raise_current_error()
608 except Error:
609 pass
610 return super(X509Name, self).__getattr__(name)
611
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500612 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800613 if entry_index == -1:
614 return None
615
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500616 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
617 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800618
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500619 result_buffer = _ffi.new("unsigned char**")
620 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400621 _openssl_assert(data_length >= 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800622
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700623 try:
Alex Gaynor03737182020-07-23 20:40:46 -0400624 result = _ffi.buffer(result_buffer[0], data_length)[:].decode(
625 "utf-8"
626 )
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700627 finally:
628 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500629 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800630 return result
631
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500632 def _cmp(op):
633 def f(self, other):
634 if not isinstance(other, X509Name):
635 return NotImplemented
636 result = _lib.X509_NAME_cmp(self._name, other._name)
637 return op(result, 0)
Alex Gaynor03737182020-07-23 20:40:46 -0400638
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500639 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800640
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500641 __eq__ = _cmp(__eq__)
642 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800643
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500644 __lt__ = _cmp(__lt__)
645 __le__ = _cmp(__le__)
646
647 __gt__ = _cmp(__gt__)
648 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800649
650 def __repr__(self):
651 """
652 String representation of an X509Name
653 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400654 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500655 format_result = _lib.X509_NAME_oneline(
Alex Gaynor03737182020-07-23 20:40:46 -0400656 self._name, result_buffer, len(result_buffer)
657 )
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700658 _openssl_assert(format_result != _ffi.NULL)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800659
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500660 return "<X509Name object '%s'>" % (
Alex Gaynor03737182020-07-23 20:40:46 -0400661 _native(_ffi.string(result_buffer)),
662 )
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800663
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800664 def hash(self):
665 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200666 Return an integer representation of the first four bytes of the
667 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800668
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200669 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
670
671 :return: The (integer) hash of this name.
672 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800673 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500674 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800675
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800676 def der(self):
677 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200678 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800679
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200680 :return: The DER encoded form of this name.
681 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800682 """
Alex Gaynor03737182020-07-23 20:40:46 -0400683 result_buffer = _ffi.new("unsigned char**")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500684 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400685 _openssl_assert(encode_result >= 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800686
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500687 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
688 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800689 return string_result
690
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800691 def get_components(self):
692 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200693 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800694
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200695 :return: The components of this name.
696 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800697 """
698 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500699 for i in range(_lib.X509_NAME_entry_count(self._name)):
700 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800701
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500702 fname = _lib.X509_NAME_ENTRY_get_object(ent)
703 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800704
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500705 nid = _lib.OBJ_obj2nid(fname)
706 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800707
Romuald Brunet4183beb2019-01-21 19:38:33 +0100708 # ffi.string does not handle strings containing NULL bytes
709 # (which may have been generated by old, broken software)
Alex Gaynor03737182020-07-23 20:40:46 -0400710 value = _ffi.buffer(
711 _lib.ASN1_STRING_data(fval), _lib.ASN1_STRING_length(fval)
712 )[:]
Romuald Brunet4183beb2019-01-21 19:38:33 +0100713 result.append((_ffi.string(name), value))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800714
715 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200716
717
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800718class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200719 """
720 An X.509 v3 certificate extension.
721 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400722
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800723 def __init__(self, type_name, critical, value, subject=None, issuer=None):
724 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200725 Initializes an X509 extension.
726
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100727 :param type_name: The name of the type of extension_ to create.
Alex Gaynor6f719912015-09-20 09:21:29 -0400728 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800729
Alex Gaynor5945ea82015-09-05 14:59:06 -0400730 :param bool critical: A flag indicating whether this is a critical
731 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800732
733 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200734 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800735
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200736 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800737 :type subject: :py:class:`X509`
738
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200739 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800740 :type issuer: :py:class:`X509`
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100741
Alex Chan54005ce2017-03-21 08:08:17 +0000742 .. _extension: https://www.openssl.org/docs/manmaster/man5/
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100743 x509v3_config.html#STANDARD-EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800744 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500745 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800746
Alex Gaynor5945ea82015-09-05 14:59:06 -0400747 # A context is necessary for any extension which uses the r2i
748 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
749 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500750 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800751
752 # We have no configuration database - but perhaps we should (some
753 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500754 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800755
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800756 # Initialize the subject and issuer, if appropriate. ctx is a local,
757 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400758 # any references, so no need to mess with reference counts or
759 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800760 if issuer is not None:
761 if not isinstance(issuer, X509):
762 raise TypeError("issuer must be an X509 instance")
763 ctx.issuer_cert = issuer._x509
764 if subject is not None:
765 if not isinstance(subject, X509):
766 raise TypeError("subject must be an X509 instance")
767 ctx.subject_cert = subject._x509
768
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800769 if critical:
770 # There are other OpenSSL APIs which would let us pass in critical
771 # separately, but they're harder to use, and since value is already
772 # a pile of crappy junk smuggling a ton of utterly important
773 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400774 # with strings? (However, X509V3_EXT_i2d in particular seems like
775 # it would be a better API to invoke. I do not know where to get
776 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500777 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800778
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500779 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
780 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800781 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500782 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800783
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400784 @property
785 def _nid(self):
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400786 return _lib.OBJ_obj2nid(
787 _lib.X509_EXTENSION_get_object(self._extension)
788 )
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400789
790 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500791 _lib.GEN_EMAIL: "email",
792 _lib.GEN_DNS: "DNS",
793 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400794 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400795
796 def _subjectAltNameString(self):
Alex Gaynord61c46a2017-06-29 22:51:33 -0700797 names = _ffi.cast(
798 "GENERAL_NAMES*", _lib.X509V3_EXT_d2i(self._extension)
799 )
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400800
Paul Kehrerb7d79502015-05-04 07:43:51 -0500801 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400802 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500803 for i in range(_lib.sk_GENERAL_NAME_num(names)):
804 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400805 try:
806 label = self._prefixes[name.type]
807 except KeyError:
808 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500809 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500810 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400811 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500812 value = _native(
Alex Gaynor03737182020-07-23 20:40:46 -0400813 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:]
814 )
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500815 parts.append(label + ":" + value)
816 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400817
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800818 def __str__(self):
819 """
820 :return: a nice text representation of the extension
821 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500822 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400823 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800824
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400825 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500826 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400827 _openssl_assert(print_result != 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800828
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500829 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800830
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800831 def get_critical(self):
832 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200833 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800834
835 :return: The critical field.
836 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500837 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800838
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800839 def get_short_name(self):
840 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200841 Returns the short type name of this X.509 extension.
842
843 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800844
845 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200846 :rtype: :py:data:`bytes`
847
848 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800849 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500850 obj = _lib.X509_EXTENSION_get_object(self._extension)
851 nid = _lib.OBJ_obj2nid(obj)
852 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800853
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800854 def get_data(self):
855 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200856 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800857
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200858 :return: The ASN.1 encoded data of this X509 extension.
859 :rtype: :py:data:`bytes`
860
861 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800862 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500863 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
Alex Gaynor03737182020-07-23 20:40:46 -0400864 string_result = _ffi.cast("ASN1_STRING*", octet_result)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500865 char_result = _lib.ASN1_STRING_data(string_result)
866 result_length = _lib.ASN1_STRING_length(string_result)
867 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800868
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200869
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800870class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200871 """
872 An X.509 certificate signing requests.
873 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400874
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800875 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500876 req = _lib.X509_REQ_new()
877 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Alex Gaynor5af32d02016-09-24 01:52:21 -0400878 # Default to version 0.
879 self.set_version(0)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800880
Paul Kehrer41c10242017-06-29 18:24:17 -0500881 def to_cryptography(self):
882 """
883 Export as a ``cryptography`` certificate signing request.
884
885 :rtype: ``cryptography.x509.CertificateSigningRequest``
886
887 .. versionadded:: 17.1.0
888 """
889 from cryptography.hazmat.backends.openssl.x509 import (
Alex Gaynor03737182020-07-23 20:40:46 -0400890 _CertificateSigningRequest,
Paul Kehrer41c10242017-06-29 18:24:17 -0500891 )
Alex Gaynor03737182020-07-23 20:40:46 -0400892
Paul Kehrer41c10242017-06-29 18:24:17 -0500893 backend = _get_backend()
894 return _CertificateSigningRequest(backend, self._req)
895
896 @classmethod
897 def from_cryptography(cls, crypto_req):
898 """
899 Construct based on a ``cryptography`` *crypto_req*.
900
901 :param crypto_req: A ``cryptography`` X.509 certificate signing request
902 :type crypto_req: ``cryptography.x509.CertificateSigningRequest``
903
Gaurav Malhotra4121e252019-01-22 00:09:19 +0530904 :rtype: X509Req
Paul Kehrer41c10242017-06-29 18:24:17 -0500905
906 .. versionadded:: 17.1.0
907 """
908 if not isinstance(crypto_req, x509.CertificateSigningRequest):
909 raise TypeError("Must be a certificate signing request")
910
911 req = cls()
912 req._req = crypto_req._x509_req
913 return req
914
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800915 def set_pubkey(self, pkey):
916 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200917 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800918
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200919 :param pkey: The public key to use.
920 :type pkey: :py:class:`PKey`
921
Dan Sully44e767a2016-06-04 18:05:27 -0700922 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800923 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500924 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400925 _openssl_assert(set_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800926
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800927 def get_pubkey(self):
928 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200929 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800930
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200931 :return: The public key.
932 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800933 """
934 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500935 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700936 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500937 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800938 pkey._only_public = True
939 return pkey
940
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800941 def set_version(self, version):
942 """
943 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
944 request.
945
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200946 :param int version: The version number.
Dan Sully44e767a2016-06-04 18:05:27 -0700947 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800948 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500949 set_result = _lib.X509_REQ_set_version(self._req, version)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400950 _openssl_assert(set_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800951
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800952 def get_version(self):
953 """
954 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
955 request.
956
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200957 :return: The value of the version subfield.
958 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800959 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500960 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800961
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800962 def get_subject(self):
963 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200964 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800965
Cory Benfield881dc8d2015-12-09 08:25:14 +0000966 This creates a new :class:`X509Name` that wraps the underlying subject
967 name field on the certificate signing request. Modifying it will modify
968 the underlying signing request, and will have the effect of modifying
969 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200970
971 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000972 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800973 """
974 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500975 name._name = _lib.X509_REQ_get_subject_name(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700976 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800977
978 # The name is owned by the X509Req structure. As long as the X509Name
979 # Python object is alive, keep the X509Req Python object alive.
980 name._owner = self
981
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800982 return name
983
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800984 def add_extensions(self, extensions):
985 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200986 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800987
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200988 :param extensions: The X.509 extensions to add.
989 :type extensions: iterable of :py:class:`X509Extension`
Dan Sully44e767a2016-06-04 18:05:27 -0700990 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800991 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500992 stack = _lib.sk_X509_EXTENSION_new_null()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700993 _openssl_assert(stack != _ffi.NULL)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800994
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500995 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800996
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800997 for ext in extensions:
998 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800999 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001000
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001001 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001002 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001003
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001004 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001005 _openssl_assert(add_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001006
Stephen Holsappleadfd39d2014-01-28 17:58:31 -08001007 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -08001008 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001009 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -08001010
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001011 :return: The X.509 extensions in this request.
1012 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
1013
1014 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -08001015 """
1016 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -05001017 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -05001018 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -08001019 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -05001020 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -08001021 exts.append(ext)
1022 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -08001023
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001024 def sign(self, pkey, digest):
1025 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001026 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001027
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001028 :param pkey: The key pair to sign with.
1029 :type pkey: :py:class:`PKey`
1030 :param digest: The name of the message digest to use for the signature,
Alex Gaynor239e2d32016-09-11 12:36:35 -04001031 e.g. :py:data:`b"sha256"`.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001032 :type digest: :py:class:`bytes`
Dan Sully44e767a2016-06-04 18:05:27 -07001033 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001034 """
1035 if pkey._only_public:
1036 raise ValueError("Key has only public part")
1037
1038 if not pkey._initialized:
1039 raise ValueError("Key is uninitialized")
1040
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001041 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001042 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001043 raise ValueError("No such digest method")
1044
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001045 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001046 _openssl_assert(sign_result > 0)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001047
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001048 def verify(self, pkey):
1049 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001050 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001051
Hynek Schlawack01c31672016-12-11 15:14:09 +01001052 :param PKey key: A public key.
1053
1054 :return: ``True`` if the signature is correct.
1055 :rtype: bool
1056
1057 :raises OpenSSL.crypto.Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001058 problem verifying the signature.
1059 """
1060 if not isinstance(pkey, PKey):
1061 raise TypeError("pkey must be a PKey instance")
1062
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001063 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001064 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001065 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001066
1067 return result
1068
1069
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001070class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001071 """
1072 An X.509 certificate.
1073 """
Alex Gaynor03737182020-07-23 20:40:46 -04001074
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001075 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001076 x509 = _lib.X509_new()
Hynek Schlawack8a2dd772016-07-31 13:46:20 +02001077 _openssl_assert(x509 != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001078 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001079
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001080 self._issuer_invalidator = _X509NameInvalidator()
1081 self._subject_invalidator = _X509NameInvalidator()
1082
1083 @classmethod
1084 def _from_raw_x509_ptr(cls, x509):
1085 cert = cls.__new__(cls)
1086 cert._x509 = _ffi.gc(x509, _lib.X509_free)
1087 cert._issuer_invalidator = _X509NameInvalidator()
1088 cert._subject_invalidator = _X509NameInvalidator()
1089 return cert
1090
Alex Gaynor9939ba12017-06-25 16:28:24 -04001091 def to_cryptography(self):
1092 """
1093 Export as a ``cryptography`` certificate.
1094
1095 :rtype: ``cryptography.x509.Certificate``
1096
1097 .. versionadded:: 17.1.0
1098 """
1099 from cryptography.hazmat.backends.openssl.x509 import _Certificate
Alex Gaynor03737182020-07-23 20:40:46 -04001100
Alex Gaynor9939ba12017-06-25 16:28:24 -04001101 backend = _get_backend()
1102 return _Certificate(backend, self._x509)
1103
1104 @classmethod
1105 def from_cryptography(cls, crypto_cert):
1106 """
1107 Construct based on a ``cryptography`` *crypto_cert*.
1108
1109 :param crypto_key: A ``cryptography`` X.509 certificate.
1110 :type crypto_key: ``cryptography.x509.Certificate``
1111
Gaurav Malhotra4121e252019-01-22 00:09:19 +05301112 :rtype: X509
Alex Gaynor9939ba12017-06-25 16:28:24 -04001113
1114 .. versionadded:: 17.1.0
1115 """
1116 if not isinstance(crypto_cert, x509.Certificate):
1117 raise TypeError("Must be a certificate")
1118
1119 cert = cls()
1120 cert._x509 = crypto_cert._x509
1121 return cert
1122
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001123 def set_version(self, version):
1124 """
Cyril Stoller6f25ced2018-08-27 13:37:51 +02001125 Set the version number of the certificate. Note that the
1126 version value is zero-based, eg. a value of 0 is V1.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001127
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001128 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001129 :type version: :py:class:`int`
1130
Dan Sully44e767a2016-06-04 18:05:27 -07001131 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001132 """
1133 if not isinstance(version, int):
1134 raise TypeError("version must be an integer")
1135
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001136 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001137
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001138 def get_version(self):
1139 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001140 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001141
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001142 :return: The version number of the certificate.
1143 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001144 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001145 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001146
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001147 def get_pubkey(self):
1148 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001149 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001150
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001151 :return: The public key.
1152 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001153 """
1154 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001155 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1156 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001157 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001158 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001159 pkey._only_public = True
1160 return pkey
1161
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001162 def set_pubkey(self, pkey):
1163 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001164 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001165
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001166 :param pkey: The public key.
1167 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001168
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001169 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001170 """
1171 if not isinstance(pkey, PKey):
1172 raise TypeError("pkey must be a PKey instance")
1173
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001174 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Alex Gaynor7778e792016-07-03 23:38:48 -04001175 _openssl_assert(set_result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001176
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001177 def sign(self, pkey, digest):
1178 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001179 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001180
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001181 :param pkey: The key to sign with.
1182 :type pkey: :py:class:`PKey`
1183
1184 :param digest: The name of the message digest to use.
1185 :type digest: :py:class:`bytes`
1186
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001187 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001188 """
1189 if not isinstance(pkey, PKey):
1190 raise TypeError("pkey must be a PKey instance")
1191
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001192 if pkey._only_public:
1193 raise ValueError("Key only has public part")
1194
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001195 if not pkey._initialized:
1196 raise ValueError("Key is uninitialized")
1197
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001198 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001199 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001200 raise ValueError("No such digest method")
1201
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001202 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -04001203 _openssl_assert(sign_result > 0)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001204
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001205 def get_signature_algorithm(self):
1206 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001207 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001208
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001209 :return: The name of the algorithm.
1210 :rtype: :py:class:`bytes`
1211
1212 :raises ValueError: If the signature algorithm is undefined.
1213
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001214 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001215 """
Alex Gaynor39ea5312016-06-02 09:12:10 -07001216 algor = _lib.X509_get0_tbs_sigalg(self._x509)
1217 nid = _lib.OBJ_obj2nid(algor.algorithm)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001218 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001219 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001220 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001221
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001222 def digest(self, digest_name):
1223 """
1224 Return the digest of the X509 object.
1225
1226 :param digest_name: The name of the digest algorithm to use.
1227 :type digest_name: :py:class:`bytes`
1228
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001229 :return: The digest of the object, formatted as
1230 :py:const:`b":"`-delimited hex pairs.
1231 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001232 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001233 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001234 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001235 raise ValueError("No such digest method")
1236
Paul Kehrer9f9113a2016-09-20 20:10:25 -05001237 result_buffer = _ffi.new("unsigned char[]", _lib.EVP_MAX_MD_SIZE)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001238 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001239 result_length[0] = len(result_buffer)
1240
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001241 digest_result = _lib.X509_digest(
Alex Gaynor03737182020-07-23 20:40:46 -04001242 self._x509, digest, result_buffer, result_length
1243 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04001244 _openssl_assert(digest_result == 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001245
Alex Gaynor03737182020-07-23 20:40:46 -04001246 return b":".join(
1247 [
1248 b16encode(ch).upper()
1249 for ch in _ffi.buffer(result_buffer, result_length[0])
1250 ]
1251 )
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001252
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001253 def subject_name_hash(self):
1254 """
1255 Return the hash of the X509 subject.
1256
1257 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001258 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001259 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001260 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001261
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001262 def set_serial_number(self, serial):
1263 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001264 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001265
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001266 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001267 :type serial: :py:class:`int`
1268
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001269 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001270 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001271 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001272 raise TypeError("serial must be an integer")
1273
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001274 hex_serial = hex(serial)[2:]
1275 if not isinstance(hex_serial, bytes):
Alex Gaynor03737182020-07-23 20:40:46 -04001276 hex_serial = hex_serial.encode("ascii")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001277
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001278 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001279
1280 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001281 # it. If bignum is still NULL after this call, then the return value
1282 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001283 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001284
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001285 if bignum_serial[0] == _ffi.NULL:
1286 set_result = _lib.ASN1_INTEGER_set(
Alex Gaynor03737182020-07-23 20:40:46 -04001287 _lib.X509_get_serialNumber(self._x509), small_serial
1288 )
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001289 if set_result:
1290 # TODO Not tested
1291 _raise_current_error()
1292 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001293 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1294 _lib.BN_free(bignum_serial[0])
1295 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001296 # TODO Not tested
1297 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001298 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1299 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Alex Gaynor37726112016-07-04 09:51:32 -04001300 _openssl_assert(set_result == 1)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001301
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001302 def get_serial_number(self):
1303 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001304 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001305
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001306 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001307 :rtype: int
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001308 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001309 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1310 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001311 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001312 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001313 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001314 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001315 serial = int(hexstring_serial, 16)
1316 return serial
1317 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001318 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001319 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001320 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001321
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001322 def gmtime_adj_notAfter(self, amount):
1323 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001324 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001325
Dan Sully44e767a2016-06-04 18:05:27 -07001326 :param int amount: The number of seconds by which to adjust the
1327 timestamp.
1328 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001329 """
1330 if not isinstance(amount, int):
1331 raise TypeError("amount must be an integer")
1332
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001333 notAfter = _lib.X509_get_notAfter(self._x509)
1334 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001335
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001336 def gmtime_adj_notBefore(self, amount):
1337 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001338 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001339
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001340 :param amount: The number of seconds by which to adjust the timestamp.
Dan Sully44e767a2016-06-04 18:05:27 -07001341 :return: ``None``
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001342 """
1343 if not isinstance(amount, int):
1344 raise TypeError("amount must be an integer")
1345
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001346 notBefore = _lib.X509_get_notBefore(self._x509)
1347 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001348
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001349 def has_expired(self):
1350 """
1351 Check whether the certificate has expired.
1352
Dan Sully44e767a2016-06-04 18:05:27 -07001353 :return: ``True`` if the certificate has expired, ``False`` otherwise.
1354 :rtype: bool
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001355 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001356 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001357 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001358
Paul Kehrerfde45c92016-01-21 12:57:37 -06001359 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001360
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001361 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001362 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001363
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001364 def get_notBefore(self):
1365 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001366 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001367
Paul Kehrerce98ee62017-06-21 06:59:58 -10001368 The timestamp is formatted as an ASN.1 TIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001369
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001370 YYYYMMDDhhmmssZ
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001371
Dan Sully44e767a2016-06-04 18:05:27 -07001372 :return: A timestamp string, or ``None`` if there is none.
1373 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001374 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001375 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001376
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001377 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001378 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001379
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001380 def set_notBefore(self, when):
1381 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001382 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001383
Paul Kehrerce98ee62017-06-21 06:59:58 -10001384 The timestamp is formatted as an ASN.1 TIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001385
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001386 YYYYMMDDhhmmssZ
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001387
Dan Sully44e767a2016-06-04 18:05:27 -07001388 :param bytes when: A timestamp string.
1389 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001390 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001391 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001392
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001393 def get_notAfter(self):
1394 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001395 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001396
Paul Kehrerce98ee62017-06-21 06:59:58 -10001397 The timestamp is formatted as an ASN.1 TIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001398
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001399 YYYYMMDDhhmmssZ
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001400
Dan Sully44e767a2016-06-04 18:05:27 -07001401 :return: A timestamp string, or ``None`` if there is none.
1402 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001403 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001404 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001405
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001406 def set_notAfter(self, when):
1407 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001408 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001409
Paul Kehrerce98ee62017-06-21 06:59:58 -10001410 The timestamp is formatted as an ASN.1 TIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001411
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001412 YYYYMMDDhhmmssZ
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001413
Dan Sully44e767a2016-06-04 18:05:27 -07001414 :param bytes when: A timestamp string.
1415 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001416 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001417 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001418
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001419 def _get_name(self, which):
1420 name = X509Name.__new__(X509Name)
1421 name._name = which(self._x509)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001422 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001423
1424 # The name is owned by the X509 structure. As long as the X509Name
1425 # Python object is alive, keep the X509 Python object alive.
1426 name._owner = self
1427
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001428 return name
1429
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001430 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001431 if not isinstance(name, X509Name):
1432 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001433 set_result = which(self._x509, name._name)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001434 _openssl_assert(set_result == 1)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001435
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001436 def get_issuer(self):
1437 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001438 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001439
Cory Benfielde6bcce82015-12-09 08:40:03 +00001440 This creates a new :class:`X509Name` that wraps the underlying issuer
1441 name field on the certificate. Modifying it will modify the underlying
1442 certificate, and will have the effect of modifying any other
1443 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001444
1445 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001446 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001447 """
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001448 name = self._get_name(_lib.X509_get_issuer_name)
1449 self._issuer_invalidator.add(name)
1450 return name
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001451
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001452 def set_issuer(self, issuer):
1453 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001454 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001455
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001456 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001457 :type issuer: :py:class:`X509Name`
1458
Dan Sully44e767a2016-06-04 18:05:27 -07001459 :return: ``None``
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001460 """
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001461 self._set_name(_lib.X509_set_issuer_name, issuer)
1462 self._issuer_invalidator.clear()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001463
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001464 def get_subject(self):
1465 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001466 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001467
Cory Benfielde6bcce82015-12-09 08:40:03 +00001468 This creates a new :class:`X509Name` that wraps the underlying subject
1469 name field on the certificate. Modifying it will modify the underlying
1470 certificate, and will have the effect of modifying any other
1471 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001472
1473 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001474 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001475 """
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001476 name = self._get_name(_lib.X509_get_subject_name)
1477 self._subject_invalidator.add(name)
1478 return name
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001479
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001480 def set_subject(self, subject):
1481 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001482 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001483
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001484 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001485 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001486
Dan Sully44e767a2016-06-04 18:05:27 -07001487 :return: ``None``
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001488 """
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001489 self._set_name(_lib.X509_set_subject_name, subject)
1490 self._subject_invalidator.clear()
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001491
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001492 def get_extension_count(self):
1493 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001494 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001495
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001496 :return: The number of extensions.
1497 :rtype: :py:class:`int`
1498
1499 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001500 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001501 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001502
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001503 def add_extensions(self, extensions):
1504 """
1505 Add extensions to the certificate.
1506
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001507 :param extensions: The extensions to add.
1508 :type extensions: An iterable of :py:class:`X509Extension` objects.
Dan Sully44e767a2016-06-04 18:05:27 -07001509 :return: ``None``
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001510 """
1511 for ext in extensions:
1512 if not isinstance(ext, X509Extension):
1513 raise ValueError("One of the elements is not an X509Extension")
1514
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001515 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001516 if not add_result:
1517 _raise_current_error()
1518
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001519 def get_extension(self, index):
1520 """
1521 Get a specific extension of the certificate by index.
1522
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001523 Extensions on a certificate are kept in order. The index
1524 parameter selects which extension will be returned.
1525
1526 :param int index: The index of the extension to retrieve.
1527 :return: The extension at the specified index.
1528 :rtype: :py:class:`X509Extension`
1529 :raises IndexError: If the extension index was out of bounds.
1530
1531 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001532 """
1533 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001534 ext._extension = _lib.X509_get_ext(self._x509, index)
1535 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001536 raise IndexError("extension index out of bounds")
1537
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001538 extension = _lib.X509_EXTENSION_dup(ext._extension)
1539 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001540 return ext
1541
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001542
Dan Sully44e767a2016-06-04 18:05:27 -07001543class X509StoreFlags(object):
1544 """
1545 Flags for X509 verification, used to change the behavior of
1546 :class:`X509Store`.
1547
1548 See `OpenSSL Verification Flags`_ for details.
1549
1550 .. _OpenSSL Verification Flags:
Alex Chan54005ce2017-03-21 08:08:17 +00001551 https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_flags.html
Dan Sully44e767a2016-06-04 18:05:27 -07001552 """
Alex Gaynor03737182020-07-23 20:40:46 -04001553
Dan Sully44e767a2016-06-04 18:05:27 -07001554 CRL_CHECK = _lib.X509_V_FLAG_CRL_CHECK
1555 CRL_CHECK_ALL = _lib.X509_V_FLAG_CRL_CHECK_ALL
1556 IGNORE_CRITICAL = _lib.X509_V_FLAG_IGNORE_CRITICAL
1557 X509_STRICT = _lib.X509_V_FLAG_X509_STRICT
1558 ALLOW_PROXY_CERTS = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS
1559 POLICY_CHECK = _lib.X509_V_FLAG_POLICY_CHECK
1560 EXPLICIT_POLICY = _lib.X509_V_FLAG_EXPLICIT_POLICY
1561 INHIBIT_MAP = _lib.X509_V_FLAG_INHIBIT_MAP
1562 NOTIFY_POLICY = _lib.X509_V_FLAG_NOTIFY_POLICY
1563 CHECK_SS_SIGNATURE = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE
1564 CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK
1565
1566
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001567class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001568 """
Dan Sully44e767a2016-06-04 18:05:27 -07001569 An X.509 store.
1570
1571 An X.509 store is used to describe a context in which to verify a
1572 certificate. A description of a context may include a set of certificates
1573 to trust, a set of certificate revocation lists, verification flags and
1574 more.
1575
1576 An X.509 store, being only a description, cannot be used by itself to
1577 verify a certificate. To carry out the actual verification process, see
1578 :class:`X509StoreContext`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001579 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001580
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001581 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001582 store = _lib.X509_STORE_new()
1583 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001584
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001585 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001586 """
Dan Sully44e767a2016-06-04 18:05:27 -07001587 Adds a trusted certificate to this store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001588
Dan Sully44e767a2016-06-04 18:05:27 -07001589 Adding a certificate with this method adds this certificate as a
1590 *trusted* certificate.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001591
1592 :param X509 cert: The certificate to add to this store.
Hynek Schlawack01c31672016-12-11 15:14:09 +01001593
Dan Sully44e767a2016-06-04 18:05:27 -07001594 :raises TypeError: If the certificate is not an :class:`X509`.
Hynek Schlawack01c31672016-12-11 15:14:09 +01001595
1596 :raises OpenSSL.crypto.Error: If OpenSSL was unhappy with your
1597 certificate.
1598
Dan Sully44e767a2016-06-04 18:05:27 -07001599 :return: ``None`` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001600 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001601 if not isinstance(cert, X509):
1602 raise TypeError()
1603
Paul Kehrer0e6c5532018-08-23 10:52:15 -05001604 # As of OpenSSL 1.1.0i adding the same cert to the store more than
1605 # once doesn't cause an error. Accordingly, this code now silences
1606 # the error for OpenSSL < 1.1.0i as well.
1607 if _lib.X509_STORE_add_cert(self._store, cert._x509) == 0:
1608 code = _lib.ERR_peek_error()
1609 err_reason = _lib.ERR_GET_REASON(code)
1610 _openssl_assert(
1611 err_reason == _lib.X509_R_CERT_ALREADY_IN_HASH_TABLE
1612 )
1613 _lib.ERR_clear_error()
Dan Sully44e767a2016-06-04 18:05:27 -07001614
1615 def add_crl(self, crl):
1616 """
1617 Add a certificate revocation list to this store.
1618
1619 The certificate revocation lists added to a store will only be used if
1620 the associated flags are configured to check certificate revocation
1621 lists.
1622
1623 .. versionadded:: 16.1.0
1624
1625 :param CRL crl: The certificate revocation list to add to this store.
1626 :return: ``None`` if the certificate revocation list was added
1627 successfully.
1628 """
1629 _openssl_assert(_lib.X509_STORE_add_crl(self._store, crl._crl) != 0)
1630
1631 def set_flags(self, flags):
1632 """
1633 Set verification flags to this store.
1634
1635 Verification flags can be combined by oring them together.
1636
1637 .. note::
1638
1639 Setting a verification flag sometimes requires clients to add
1640 additional information to the store, otherwise a suitable error will
1641 be raised.
1642
1643 For example, in setting flags to enable CRL checking a
1644 suitable CRL must be added to the store otherwise an error will be
1645 raised.
1646
1647 .. versionadded:: 16.1.0
1648
1649 :param int flags: The verification flags to set on this store.
1650 See :class:`X509StoreFlags` for available constants.
1651 :return: ``None`` if the verification flags were successfully set.
1652 """
1653 _openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0)
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001654
Thomas Sileoe15e60a2016-11-22 18:13:30 +01001655 def set_time(self, vfy_time):
1656 """
1657 Set the time against which the certificates are verified.
1658
1659 Normally the current time is used.
1660
1661 .. note::
1662
1663 For example, you can determine if a certificate was valid at a given
1664 time.
1665
Hynek Schlawackf6c96af2017-04-20 12:34:58 +02001666 .. versionadded:: 17.0.0
Thomas Sileoe15e60a2016-11-22 18:13:30 +01001667
1668 :param datetime vfy_time: The verification time to set on this store.
1669 :return: ``None`` if the verification time was successfully set.
1670 """
1671 param = _lib.X509_VERIFY_PARAM_new()
1672 param = _ffi.gc(param, _lib.X509_VERIFY_PARAM_free)
1673
Alex Gaynor03737182020-07-23 20:40:46 -04001674 _lib.X509_VERIFY_PARAM_set_time(param, int(vfy_time.strftime("%s")))
Thomas Sileoe15e60a2016-11-22 18:13:30 +01001675 _openssl_assert(_lib.X509_STORE_set1_param(self._store, param) != 0)
1676
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001677
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001678class X509StoreContextError(Exception):
1679 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001680 An exception raised when an error occurred while verifying a certificate
1681 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001682
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001683 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001684 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001685 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001686
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001687 def __init__(self, message, certificate):
1688 super(X509StoreContextError, self).__init__(message)
1689 self.certificate = certificate
1690
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001691
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001692class X509StoreContext(object):
1693 """
1694 An X.509 store context.
1695
Dan Sully44e767a2016-06-04 18:05:27 -07001696 An X.509 store context is used to carry out the actual verification process
1697 of a certificate in a described context. For describing such a context, see
1698 :class:`X509Store`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001699
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001700 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1701 instance. It is dynamically allocated and automatically garbage
1702 collected.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001703 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001704 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001705 :param X509Store store: The certificates which will be trusted for the
1706 purposes of any verifications.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001707 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001708 """
1709
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001710 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001711 store_ctx = _lib.X509_STORE_CTX_new()
1712 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1713 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001714 self._cert = certificate
Shane Harvey33c54992020-08-05 16:48:51 -07001715 self._chain = _ffi.NULL
Stephen Holsapple46a09252015-02-12 14:45:43 -08001716 # Make the store context available for use after instantiating this
1717 # class by initializing it now. Per testing, subsequent calls to
Dan Sully44e767a2016-06-04 18:05:27 -07001718 # :meth:`_init` have no adverse affect.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001719 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001720
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001721 def _init(self):
1722 """
1723 Set up the store context for a subsequent verification operation.
Jeremy Cline58193f12017-09-13 21:14:53 -04001724
1725 Calling this method more than once without first calling
1726 :meth:`_cleanup` will leak memory.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001727 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001728 ret = _lib.X509_STORE_CTX_init(
Shane Harvey33c54992020-08-05 16:48:51 -07001729 self._store_ctx, self._store._store, self._cert._x509, self._chain
Alex Gaynor5945ea82015-09-05 14:59:06 -04001730 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001731 if ret <= 0:
1732 _raise_current_error()
1733
1734 def _cleanup(self):
1735 """
1736 Internally cleans up the store context.
1737
Dan Sully44e767a2016-06-04 18:05:27 -07001738 The store context can then be reused with a new call to :meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001739 """
1740 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1741
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001742 def _exception_from_context(self):
1743 """
1744 Convert an OpenSSL native context error failure into a Python
1745 exception.
1746
Alex Gaynor5945ea82015-09-05 14:59:06 -04001747 When a call to native OpenSSL X509_verify_cert fails, additional
1748 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001749 """
1750 errors = [
1751 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1752 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
Alex Gaynor03737182020-07-23 20:40:46 -04001753 _native(
1754 _ffi.string(
1755 _lib.X509_verify_cert_error_string(
1756 _lib.X509_STORE_CTX_get_error(self._store_ctx)
1757 )
1758 )
1759 ),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001760 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001761 # A context error should always be associated with a certificate, so we
1762 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001763 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001764 _cert = _lib.X509_dup(_x509)
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001765 pycert = X509._from_raw_x509_ptr(_cert)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001766 return X509StoreContextError(errors, pycert)
1767
Stephen Holsapple46a09252015-02-12 14:45:43 -08001768 def set_store(self, store):
1769 """
Dan Sully44e767a2016-06-04 18:05:27 -07001770 Set the context's X.509 store.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001771
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001772 .. versionadded:: 0.15
1773
Dan Sully44e767a2016-06-04 18:05:27 -07001774 :param X509Store store: The store description which will be used for
1775 the purposes of any *future* verifications.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001776 """
1777 self._store = store
1778
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001779 def verify_certificate(self):
1780 """
1781 Verify a certificate in a context.
1782
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001783 .. versionadded:: 0.15
1784
Alex Gaynorca87ff62015-09-04 23:31:03 -04001785 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001786 certificate in the context. Sets ``certificate`` attribute to
1787 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001788 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001789 # Always re-initialize the store context in case
Dan Sully44e767a2016-06-04 18:05:27 -07001790 # :meth:`verify_certificate` is called multiple times.
Jeremy Cline58193f12017-09-13 21:14:53 -04001791 #
1792 # :meth:`_init` is called in :meth:`__init__` so _cleanup is called
1793 # before _init to ensure memory is not leaked.
1794 self._cleanup()
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001795 self._init()
1796 ret = _lib.X509_verify_cert(self._store_ctx)
1797 self._cleanup()
1798 if ret <= 0:
1799 raise self._exception_from_context()
1800
Shane Harvey33c54992020-08-05 16:48:51 -07001801 def get_verified_chain(self):
1802 """
1803 Verify a certificate in a context and return the complete validated
1804 chain.
1805
1806 :raises X509StoreContextError: If an error occurred when validating a
1807 certificate in the context. Sets ``certificate`` attribute to
1808 indicate which certificate caused the error.
1809
1810 .. versionadded:: 20.0
1811 """
1812 # Always re-initialize the store context in case
1813 # :meth:`verify_certificate` is called multiple times.
1814 #
1815 # :meth:`_init` is called in :meth:`__init__` so _cleanup is called
1816 # before _init to ensure memory is not leaked.
1817 self._cleanup()
1818 self._init()
1819 ret = _lib.X509_verify_cert(self._store_ctx)
1820 if ret <= 0:
1821 self._cleanup()
1822 raise self._exception_from_context()
1823
1824 # Note: X509_STORE_CTX_get1_chain returns a deep copy of the chain.
1825 cert_stack = _lib.X509_STORE_CTX_get1_chain(self._store_ctx)
1826 _openssl_assert(cert_stack != _ffi.NULL)
1827
1828 result = []
1829 for i in range(_lib.sk_X509_num(cert_stack)):
1830 cert = _lib.sk_X509_value(cert_stack, i)
1831 _openssl_assert(cert != _ffi.NULL)
1832 pycert = X509._from_raw_x509_ptr(cert)
1833 result.append(pycert)
1834
1835 # Free the stack but not the members which are freed by the X509 class.
1836 _lib.sk_X509_free(cert_stack)
1837 self._cleanup()
1838 return result
1839
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001840
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001841def load_certificate(type, buffer):
1842 """
Alex Chand072cae2018-02-15 09:57:59 +00001843 Load a certificate (X509) from the string *buffer* encoded with the
1844 type *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001845
1846 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1847
Dan Sully44e767a2016-06-04 18:05:27 -07001848 :param bytes buffer: The buffer the certificate is stored in
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001849
1850 :return: The X509 object
1851 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001852 if isinstance(buffer, _text_type):
1853 buffer = buffer.encode("ascii")
1854
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001855 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001856
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001857 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001858 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001859 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001860 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001861 else:
Alex Gaynor03737182020-07-23 20:40:46 -04001862 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001863
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001864 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001865 _raise_current_error()
1866
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001867 return X509._from_raw_x509_ptr(x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001868
1869
1870def dump_certificate(type, cert):
1871 """
Alex Chand072cae2018-02-15 09:57:59 +00001872 Dump the certificate *cert* into a buffer string encoded with the type
1873 *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001874
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001875 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1876 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001877 :param cert: The certificate to dump
1878 :return: The buffer with the dumped certificate in
1879 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001880 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001881
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001882 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001883 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001884 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001885 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001886 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001887 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001888 else:
1889 raise ValueError(
1890 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
Alex Gaynor03737182020-07-23 20:40:46 -04001891 "FILETYPE_TEXT"
1892 )
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001893
Adrián Chaves98c57be2020-03-31 16:14:50 +02001894 _openssl_assert(result_code == 1)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001895 return _bio_to_string(bio)
1896
1897
Cory Benfield6492f7c2015-10-27 16:57:58 +09001898def dump_publickey(type, pkey):
1899 """
Cory Benfield11c10192015-10-27 17:23:03 +09001900 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001901
Cory Benfield9c590b92015-10-28 14:55:05 +09001902 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001903 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001904 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001905 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001906 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001907 """
1908 bio = _new_mem_buf()
1909 if type == FILETYPE_PEM:
1910 write_bio = _lib.PEM_write_bio_PUBKEY
1911 elif type == FILETYPE_ASN1:
1912 write_bio = _lib.i2d_PUBKEY_bio
1913 else:
1914 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1915
1916 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001917 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001918 _raise_current_error()
1919
1920 return _bio_to_string(bio)
1921
1922
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001923def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1924 """
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001925 Dump the private key *pkey* into a buffer string encoded with the type
1926 *type*. Optionally (if *type* is :const:`FILETYPE_PEM`) encrypting it
1927 using *cipher* and *passphrase*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001928
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001929 :param type: The file type (one of :const:`FILETYPE_PEM`,
1930 :const:`FILETYPE_ASN1`, or :const:`FILETYPE_TEXT`)
1931 :param PKey pkey: The PKey to dump
1932 :param cipher: (optional) if encrypted PEM format, the cipher to use
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001933 :param passphrase: (optional) if encrypted PEM format, this can be either
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001934 the passphrase to use, or a callback for providing the passphrase.
1935
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001936 :return: The buffer with the dumped key in
Dan Sully44e767a2016-06-04 18:05:27 -07001937 :rtype: bytes
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001938 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001939 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001940
Paul Kehrercded9932017-06-29 18:43:42 -05001941 if not isinstance(pkey, PKey):
1942 raise TypeError("pkey must be a PKey")
1943
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001944 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001945 if passphrase is None:
1946 raise TypeError(
1947 "if a value is given for cipher "
Alex Gaynor03737182020-07-23 20:40:46 -04001948 "one must also be given for passphrase"
1949 )
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001950 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001951 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001952 raise ValueError("Invalid cipher name")
1953 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001954 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001955
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001956 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001957 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001958 result_code = _lib.PEM_write_bio_PrivateKey(
Alex Gaynor03737182020-07-23 20:40:46 -04001959 bio,
1960 pkey._pkey,
1961 cipher_obj,
1962 _ffi.NULL,
1963 0,
1964 helper.callback,
1965 helper.callback_args,
1966 )
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001967 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001968 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001969 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001970 elif type == FILETYPE_TEXT:
Paul Kehrercded9932017-06-29 18:43:42 -05001971 if _lib.EVP_PKEY_id(pkey._pkey) != _lib.EVP_PKEY_RSA:
1972 raise TypeError("Only RSA keys are supported for FILETYPE_TEXT")
1973
Alex Gaynor03737182020-07-23 20:40:46 -04001974 rsa = _ffi.gc(_lib.EVP_PKEY_get1_RSA(pkey._pkey), _lib.RSA_free)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001975 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001976 else:
1977 raise ValueError(
1978 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
Alex Gaynor03737182020-07-23 20:40:46 -04001979 "FILETYPE_TEXT"
1980 )
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001981
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001982 _openssl_assert(result_code != 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001983
1984 return _bio_to_string(bio)
1985
1986
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001987class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001988 """
1989 A certificate revocation.
1990 """
Alex Gaynor03737182020-07-23 20:40:46 -04001991
Cyril Stoller37e60222018-08-27 13:38:10 +02001992 # https://www.openssl.org/docs/manmaster/man5/x509v3_config.html#CRL-distribution-points
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001993 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1994 # OCSP_crl_reason_str. We use the latter, just like the command line
1995 # program.
1996 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001997 b"unspecified",
1998 b"keyCompromise",
1999 b"CACompromise",
2000 b"affiliationChanged",
2001 b"superseded",
2002 b"cessationOfOperation",
2003 b"certificateHold",
2004 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04002005 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002006
2007 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002008 revoked = _lib.X509_REVOKED_new()
2009 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002010
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002011 def set_serial(self, hex_str):
2012 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002013 Set the serial number.
2014
2015 The serial number is formatted as a hexadecimal number encoded in
2016 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002017
Dan Sully44e767a2016-06-04 18:05:27 -07002018 :param bytes hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002019
Dan Sully44e767a2016-06-04 18:05:27 -07002020 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002021 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002022 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
2023 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08002024 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002025 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002026 if not bn_result:
2027 raise ValueError("bad hex string")
2028
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002029 asn1_serial = _ffi.gc(
2030 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
Alex Gaynor03737182020-07-23 20:40:46 -04002031 _lib.ASN1_INTEGER_free,
2032 )
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002033 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002034
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002035 def get_serial(self):
2036 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002037 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002038
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002039 The serial number is formatted as a hexadecimal number encoded in
2040 ASCII.
2041
2042 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07002043 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002044 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08002045 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002046
Alex Gaynor67903a62016-06-02 10:37:13 -07002047 asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked)
2048 _openssl_assert(asn1_int != _ffi.NULL)
2049 result = _lib.i2a_ASN1_INTEGER(bio, asn1_int)
2050 _openssl_assert(result >= 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002051 return _bio_to_string(bio)
2052
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002053 def _delete_reason(self):
Alex Gaynor67903a62016-06-02 10:37:13 -07002054 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
2055 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04002056 obj = _lib.X509_EXTENSION_get_object(ext)
2057 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002058 _lib.X509_EXTENSION_free(ext)
Alex Gaynor67903a62016-06-02 10:37:13 -07002059 _lib.X509_REVOKED_delete_ext(self._revoked, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002060 break
2061
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002062 def set_reason(self, reason):
2063 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002064 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002065
Dan Sully44e767a2016-06-04 18:05:27 -07002066 If :data:`reason` is ``None``, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002067
2068 :param reason: The reason string.
Dan Sully44e767a2016-06-04 18:05:27 -07002069 :type reason: :class:`bytes` or :class:`NoneType`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002070
Dan Sully44e767a2016-06-04 18:05:27 -07002071 :return: ``None``
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002072
2073 .. seealso::
2074
Dan Sully44e767a2016-06-04 18:05:27 -07002075 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002076 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002077 """
2078 if reason is None:
2079 self._delete_reason()
2080 elif not isinstance(reason, bytes):
2081 raise TypeError("reason must be None or a byte string")
2082 else:
Alex Gaynor03737182020-07-23 20:40:46 -04002083 reason = reason.lower().replace(b" ", b"")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002084 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
2085
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002086 new_reason_ext = _lib.ASN1_ENUMERATED_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07002087 _openssl_assert(new_reason_ext != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002088 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002089
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002090 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002091 _openssl_assert(set_result != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002092
2093 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002094 add_result = _lib.X509_REVOKED_add1_ext_i2d(
Alex Gaynor03737182020-07-23 20:40:46 -04002095 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0
2096 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04002097 _openssl_assert(add_result == 1)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002098
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002099 def get_reason(self):
2100 """
Alex Gaynor80262fb2016-04-22 07:53:42 -04002101 Get the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002102
Dan Sully44e767a2016-06-04 18:05:27 -07002103 :return: The reason, or ``None`` if there is none.
2104 :rtype: bytes or NoneType
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002105
2106 .. seealso::
2107
Dan Sully44e767a2016-06-04 18:05:27 -07002108 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002109 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002110 """
Alex Gaynor67903a62016-06-02 10:37:13 -07002111 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
2112 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04002113 obj = _lib.X509_EXTENSION_get_object(ext)
2114 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08002115 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002116
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002117 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002118 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002119 print_result = _lib.M_ASN1_OCTET_STRING_print(
Paul Kehrere8f91cc2016-03-09 21:26:29 -04002120 bio, _lib.X509_EXTENSION_get_data(ext)
Alex Gaynor5945ea82015-09-05 14:59:06 -04002121 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04002122 _openssl_assert(print_result != 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002123
2124 return _bio_to_string(bio)
2125
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002126 def all_reasons(self):
2127 """
2128 Return a list of all the supported reason strings.
2129
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002130 This list is a copy; modifying it does not change the supported reason
2131 strings.
2132
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002133 :return: A list of reason strings.
Dan Sully44e767a2016-06-04 18:05:27 -07002134 :rtype: :class:`list` of :class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002135 """
2136 return self._crl_reasons[:]
2137
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002138 def set_rev_date(self, when):
2139 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002140 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002141
Dan Sully44e767a2016-06-04 18:05:27 -07002142 :param bytes when: The timestamp of the revocation,
Paul Kehrerce98ee62017-06-21 06:59:58 -10002143 as ASN.1 TIME.
Dan Sully44e767a2016-06-04 18:05:27 -07002144 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002145 """
Alex Gaynor67903a62016-06-02 10:37:13 -07002146 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
2147 return _set_asn1_time(dt, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002148
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002149 def get_rev_date(self):
2150 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002151 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002152
Paul Kehrerce98ee62017-06-21 06:59:58 -10002153 :return: The timestamp of the revocation, as ASN.1 TIME.
Dan Sully44e767a2016-06-04 18:05:27 -07002154 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002155 """
Alex Gaynor67903a62016-06-02 10:37:13 -07002156 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
2157 return _get_asn1_time(dt)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002158
2159
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002160class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002161 """
2162 A certificate revocation list.
2163 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002164
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002165 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002166 crl = _lib.X509_CRL_new()
2167 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002168
Paul Kehrer41c10242017-06-29 18:24:17 -05002169 def to_cryptography(self):
2170 """
2171 Export as a ``cryptography`` CRL.
2172
2173 :rtype: ``cryptography.x509.CertificateRevocationList``
2174
2175 .. versionadded:: 17.1.0
2176 """
2177 from cryptography.hazmat.backends.openssl.x509 import (
Alex Gaynor03737182020-07-23 20:40:46 -04002178 _CertificateRevocationList,
Paul Kehrer41c10242017-06-29 18:24:17 -05002179 )
Alex Gaynor03737182020-07-23 20:40:46 -04002180
Paul Kehrer41c10242017-06-29 18:24:17 -05002181 backend = _get_backend()
2182 return _CertificateRevocationList(backend, self._crl)
2183
2184 @classmethod
2185 def from_cryptography(cls, crypto_crl):
2186 """
2187 Construct based on a ``cryptography`` *crypto_crl*.
2188
2189 :param crypto_crl: A ``cryptography`` certificate revocation list
2190 :type crypto_crl: ``cryptography.x509.CertificateRevocationList``
2191
2192 :rtype: CRL
2193
2194 .. versionadded:: 17.1.0
2195 """
2196 if not isinstance(crypto_crl, x509.CertificateRevocationList):
2197 raise TypeError("Must be a certificate revocation list")
2198
2199 crl = cls()
2200 crl._crl = crypto_crl._x509_crl
2201 return crl
2202
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002203 def get_revoked(self):
2204 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002205 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002206
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002207 These revocations will be provided by value, not by reference.
2208 That means it's okay to mutate them: it won't affect this CRL.
2209
2210 :return: The revocations in this CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07002211 :rtype: :class:`tuple` of :class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002212 """
2213 results = []
Alex Gaynor67903a62016-06-02 10:37:13 -07002214 revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002215 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
2216 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Paul Kehrer2fe23b02016-03-09 22:02:15 -04002217 revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002218 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002219 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002220 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002221 if results:
2222 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002223
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002224 def add_revoked(self, revoked):
2225 """
2226 Add a revoked (by value not reference) to the CRL structure
2227
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002228 This revocation will be added by value, not by reference. That
2229 means it's okay to mutate it after adding: it won't affect
2230 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002231
Dan Sully44e767a2016-06-04 18:05:27 -07002232 :param Revoked revoked: The new revocation.
2233 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002234 """
Paul Kehrer8dddb1a2016-03-09 21:48:04 -04002235 copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002236 _openssl_assert(copy != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002237
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002238 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Alex Gaynor09a386e2016-07-03 09:32:44 -04002239 _openssl_assert(add_result != 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002240
Dan Sully44e767a2016-06-04 18:05:27 -07002241 def get_issuer(self):
2242 """
2243 Get the CRL's issuer.
2244
2245 .. versionadded:: 16.1.0
2246
2247 :rtype: X509Name
2248 """
2249 _issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl))
2250 _openssl_assert(_issuer != _ffi.NULL)
2251 _issuer = _ffi.gc(_issuer, _lib.X509_NAME_free)
2252 issuer = X509Name.__new__(X509Name)
2253 issuer._name = _issuer
2254 return issuer
2255
2256 def set_version(self, version):
2257 """
2258 Set the CRL version.
2259
2260 .. versionadded:: 16.1.0
2261
2262 :param int version: The version of the CRL.
2263 :return: ``None``
2264 """
2265 _openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0)
2266
2267 def _set_boundary_time(self, which, when):
2268 return _set_asn1_time(which(self._crl), when)
2269
2270 def set_lastUpdate(self, when):
2271 """
2272 Set when the CRL was last updated.
2273
Paul Kehrerce98ee62017-06-21 06:59:58 -10002274 The timestamp is formatted as an ASN.1 TIME::
Dan Sully44e767a2016-06-04 18:05:27 -07002275
2276 YYYYMMDDhhmmssZ
Dan Sully44e767a2016-06-04 18:05:27 -07002277
2278 .. versionadded:: 16.1.0
2279
2280 :param bytes when: A timestamp string.
2281 :return: ``None``
2282 """
2283 return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when)
2284
2285 def set_nextUpdate(self, when):
2286 """
2287 Set when the CRL will next be udpated.
2288
Paul Kehrerce98ee62017-06-21 06:59:58 -10002289 The timestamp is formatted as an ASN.1 TIME::
Dan Sully44e767a2016-06-04 18:05:27 -07002290
2291 YYYYMMDDhhmmssZ
Dan Sully44e767a2016-06-04 18:05:27 -07002292
2293 .. versionadded:: 16.1.0
2294
2295 :param bytes when: A timestamp string.
2296 :return: ``None``
2297 """
2298 return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when)
2299
2300 def sign(self, issuer_cert, issuer_key, digest):
2301 """
2302 Sign the CRL.
2303
2304 Signing a CRL enables clients to associate the CRL itself with an
2305 issuer. Before a CRL is meaningful to other OpenSSL functions, it must
2306 be signed by an issuer.
2307
2308 This method implicitly sets the issuer's name based on the issuer
2309 certificate and private key used to sign the CRL.
2310
2311 .. versionadded:: 16.1.0
2312
2313 :param X509 issuer_cert: The issuer's certificate.
2314 :param PKey issuer_key: The issuer's private key.
2315 :param bytes digest: The digest method to sign the CRL with.
2316 """
2317 digest_obj = _lib.EVP_get_digestbyname(digest)
2318 _openssl_assert(digest_obj != _ffi.NULL)
2319 _lib.X509_CRL_set_issuer_name(
Alex Gaynor03737182020-07-23 20:40:46 -04002320 self._crl, _lib.X509_get_subject_name(issuer_cert._x509)
2321 )
Dan Sully44e767a2016-06-04 18:05:27 -07002322 _lib.X509_CRL_sort(self._crl)
2323 result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj)
2324 _openssl_assert(result != 0)
2325
Alex Gaynor03737182020-07-23 20:40:46 -04002326 def export(
2327 self, cert, key, type=FILETYPE_PEM, days=100, digest=_UNSPECIFIED
2328 ):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002329 """
Dan Sully44e767a2016-06-04 18:05:27 -07002330 Export the CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002331
Dan Sully44e767a2016-06-04 18:05:27 -07002332 :param X509 cert: The certificate used to sign the CRL.
2333 :param PKey key: The key used to sign the CRL.
2334 :param int type: The export format, either :data:`FILETYPE_PEM`,
2335 :data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`.
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002336 :param int days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002337 :param bytes digest: The name of the message digest to use (eg
Wayne Werner80dcf382019-01-30 15:03:16 -06002338 ``b"sha256"``).
Dan Sully44e767a2016-06-04 18:05:27 -07002339 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002340 """
Dan Sully44e767a2016-06-04 18:05:27 -07002341
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002342 if not isinstance(cert, X509):
2343 raise TypeError("cert must be an X509 instance")
2344 if not isinstance(key, PKey):
2345 raise TypeError("key must be a PKey instance")
2346 if not isinstance(type, int):
2347 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002348
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002349 if digest is _UNSPECIFIED:
Alex Gaynor173e4ba2017-06-30 08:01:12 -07002350 raise TypeError("digest must be provided")
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002351
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002352 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002353 if digest_obj == _ffi.NULL:
2354 raise ValueError("No such digest method")
2355
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002356 bio = _lib.BIO_new(_lib.BIO_s_mem())
Alex Gaynoradd5b072016-06-04 21:04:00 -07002357 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002358
Alex Gaynora738ed52015-09-05 11:17:10 -04002359 # A scratch time object to give different values to different CRL
2360 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002361 sometime = _lib.ASN1_TIME_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07002362 _openssl_assert(sometime != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002363
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002364 _lib.X509_gmtime_adj(sometime, 0)
2365 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002366
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002367 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2368 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002369
Alex Gaynor5945ea82015-09-05 14:59:06 -04002370 _lib.X509_CRL_set_issuer_name(
2371 self._crl, _lib.X509_get_subject_name(cert._x509)
2372 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002373
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002374 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002375 if not sign_result:
2376 _raise_current_error()
2377
Dominic Chenf05b2122015-10-13 16:32:35 +00002378 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002379
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002380
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002381class PKCS7(object):
2382 def type_is_signed(self):
2383 """
2384 Check if this NID_pkcs7_signed object
2385
2386 :return: True if the PKCS7 is of type signed
2387 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002388 return bool(_lib.PKCS7_type_is_signed(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002389
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002390 def type_is_enveloped(self):
2391 """
2392 Check if this NID_pkcs7_enveloped object
2393
2394 :returns: True if the PKCS7 is of type enveloped
2395 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002396 return bool(_lib.PKCS7_type_is_enveloped(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002397
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002398 def type_is_signedAndEnveloped(self):
2399 """
2400 Check if this NID_pkcs7_signedAndEnveloped object
2401
2402 :returns: True if the PKCS7 is of type signedAndEnveloped
2403 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002404 return bool(_lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002405
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002406 def type_is_data(self):
2407 """
2408 Check if this NID_pkcs7_data object
2409
2410 :return: True if the PKCS7 is of type data
2411 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002412 return bool(_lib.PKCS7_type_is_data(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002413
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002414 def get_type_name(self):
2415 """
2416 Returns the type name of the PKCS7 structure
2417
2418 :return: A string with the typename
2419 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002420 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2421 string_type = _lib.OBJ_nid2sn(nid)
2422 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002423
Alex Chanc6077062016-11-18 13:53:39 +00002424
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002425class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002426 """
2427 A PKCS #12 archive.
2428 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002429
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002430 def __init__(self):
2431 self._pkey = None
2432 self._cert = None
2433 self._cacerts = None
2434 self._friendlyname = None
2435
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002436 def get_certificate(self):
2437 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002438 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002439
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002440 :return: The certificate, or :py:const:`None` if there is none.
2441 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002442 """
2443 return self._cert
2444
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002445 def set_certificate(self, cert):
2446 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002447 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002448
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002449 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002450 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002451
Dan Sully44e767a2016-06-04 18:05:27 -07002452 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002453 """
2454 if not isinstance(cert, X509):
2455 raise TypeError("cert must be an X509 instance")
2456 self._cert = cert
2457
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002458 def get_privatekey(self):
2459 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002460 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002461
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002462 :return: The private key, or :py:const:`None` if there is none.
2463 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002464 """
2465 return self._pkey
2466
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002467 def set_privatekey(self, pkey):
2468 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002469 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002470
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002471 :param pkey: The new private key, or :py:const:`None` to unset it.
2472 :type pkey: :py:class:`PKey` or :py:const:`None`
2473
Dan Sully44e767a2016-06-04 18:05:27 -07002474 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002475 """
2476 if not isinstance(pkey, PKey):
2477 raise TypeError("pkey must be a PKey instance")
2478 self._pkey = pkey
2479
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002480 def get_ca_certificates(self):
2481 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002482 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002483
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002484 :return: A tuple with the CA certificates in the chain, or
2485 :py:const:`None` if there are none.
2486 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002487 """
2488 if self._cacerts is not None:
2489 return tuple(self._cacerts)
2490
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002491 def set_ca_certificates(self, cacerts):
2492 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002493 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002494
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002495 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2496 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002497 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002498
Dan Sully44e767a2016-06-04 18:05:27 -07002499 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002500 """
2501 if cacerts is None:
2502 self._cacerts = None
2503 else:
2504 cacerts = list(cacerts)
2505 for cert in cacerts:
2506 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002507 raise TypeError(
2508 "iterable must only contain X509 instances"
2509 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002510 self._cacerts = cacerts
2511
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002512 def set_friendlyname(self, name):
2513 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002514 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002515
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002516 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002517 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002518
Dan Sully44e767a2016-06-04 18:05:27 -07002519 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002520 """
2521 if name is None:
2522 self._friendlyname = None
2523 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002524 raise TypeError(
2525 "name must be a byte string or None (not %r)" % (name,)
2526 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002527 self._friendlyname = name
2528
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002529 def get_friendlyname(self):
2530 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002531 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002532
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002533 :returns: The friendly name, or :py:const:`None` if there is none.
2534 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002535 """
2536 return self._friendlyname
2537
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002538 def export(self, passphrase=None, iter=2048, maciter=1):
2539 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002540 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002541
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002542 For more information, see the :c:func:`PKCS12_create` man page.
2543
2544 :param passphrase: The passphrase used to encrypt the structure. Unlike
2545 some other passphrase arguments, this *must* be a string, not a
2546 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002547 :type passphrase: :py:data:`bytes`
2548
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002549 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002550 :type iter: :py:data:`int`
2551
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002552 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002553 :type maciter: :py:data:`int`
2554
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002555 :return: The string representation of the PKCS #12 structure.
2556 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002557 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002558 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002559
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002560 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002561 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002562 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002563 cacerts = _lib.sk_X509_new_null()
2564 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002565 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002566 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002567
2568 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002569 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002570
2571 friendlyname = self._friendlyname
2572 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002573 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002574
2575 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002576 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002577 else:
2578 pkey = self._pkey._pkey
2579
2580 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002581 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002582 else:
2583 cert = self._cert._x509
2584
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002585 pkcs12 = _lib.PKCS12_create(
Alex Gaynor03737182020-07-23 20:40:46 -04002586 passphrase,
2587 friendlyname,
2588 pkey,
2589 cert,
2590 cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002591 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2592 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Alex Gaynor03737182020-07-23 20:40:46 -04002593 iter,
2594 maciter,
2595 0,
2596 )
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002597 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002598 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002599 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002600
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002601 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002602 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002603 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002604
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002605
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002606class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002607 """
2608 A Netscape SPKI object.
2609 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002610
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002611 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002612 spki = _lib.NETSCAPE_SPKI_new()
2613 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002614
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002615 def sign(self, pkey, digest):
2616 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002617 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002618
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002619 :param pkey: The private key to sign with.
2620 :type pkey: :py:class:`PKey`
2621
2622 :param digest: The message digest to use.
2623 :type digest: :py:class:`bytes`
2624
Dan Sully44e767a2016-06-04 18:05:27 -07002625 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002626 """
2627 if pkey._only_public:
2628 raise ValueError("Key has only public part")
2629
2630 if not pkey._initialized:
2631 raise ValueError("Key is uninitialized")
2632
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002633 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002634 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002635 raise ValueError("No such digest method")
2636
Alex Gaynor5945ea82015-09-05 14:59:06 -04002637 sign_result = _lib.NETSCAPE_SPKI_sign(
2638 self._spki, pkey._pkey, digest_obj
2639 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04002640 _openssl_assert(sign_result > 0)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002641
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002642 def verify(self, key):
2643 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002644 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002645
Hynek Schlawack01c31672016-12-11 15:14:09 +01002646 :param PKey key: The public key that signature is supposedly from.
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002647
Hynek Schlawack01c31672016-12-11 15:14:09 +01002648 :return: ``True`` if the signature is correct.
2649 :rtype: bool
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002650
Hynek Schlawack01c31672016-12-11 15:14:09 +01002651 :raises OpenSSL.crypto.Error: If the signature is invalid, or there was
2652 a problem verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002653 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002654 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002655 if answer <= 0:
2656 _raise_current_error()
2657 return True
2658
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002659 def b64_encode(self):
2660 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002661 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002662
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002663 :return: The base64 encoded string.
2664 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002665 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002666 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2667 result = _ffi.string(encoded)
Paul Kehrer0dcacf72016-03-17 19:25:39 -04002668 _lib.OPENSSL_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002669 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002670
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002671 def get_pubkey(self):
2672 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002673 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002674
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002675 :return: The public key.
2676 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002677 """
2678 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002679 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002680 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002681 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002682 pkey._only_public = True
2683 return pkey
2684
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002685 def set_pubkey(self, pkey):
2686 """
2687 Set the public key of the certificate
2688
2689 :param pkey: The public key
Dan Sully44e767a2016-06-04 18:05:27 -07002690 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002691 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002692 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -04002693 _openssl_assert(set_result == 1)
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002694
2695
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002696class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002697 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002698 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002699 raise ValueError(
2700 "only FILETYPE_PEM key format supports encryption"
2701 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002702 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002703 self._more_args = more_args
2704 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002705 self._problems = []
2706
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002707 @property
2708 def callback(self):
2709 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002710 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002711 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002712 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002713 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002714 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002715 else:
Hynek Schlawack33675f92016-11-18 14:55:06 +01002716 raise TypeError(
2717 "Last argument must be a byte string or a callable."
2718 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002719
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002720 @property
2721 def callback_args(self):
2722 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002723 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002724 elif isinstance(self._passphrase, bytes):
2725 return self._passphrase
2726 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002727 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002728 else:
Hynek Schlawack33675f92016-11-18 14:55:06 +01002729 raise TypeError(
2730 "Last argument must be a byte string or a callable."
2731 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002732
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002733 def raise_if_problem(self, exceptionType=Error):
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002734 if self._problems:
Greg Bowser36eb2de2017-01-24 11:38:55 -05002735
2736 # Flush the OpenSSL error queue
2737 try:
2738 _exception_from_error_queue(exceptionType)
2739 except exceptionType:
2740 pass
2741
2742 raise self._problems.pop(0)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002743
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002744 def _read_passphrase(self, buf, size, rwflag, userdata):
2745 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002746 if self._more_args:
2747 result = self._passphrase(size, rwflag, userdata)
2748 else:
2749 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002750 if not isinstance(result, bytes):
2751 raise ValueError("String expected")
2752 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002753 if self._truncate:
2754 result = result[:size]
2755 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002756 raise ValueError(
2757 "passphrase returned by callback is too long"
2758 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002759 for i in range(len(result)):
Alex Gaynor03737182020-07-23 20:40:46 -04002760 buf[i] = result[i : i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002761 return len(result)
2762 except Exception as e:
2763 self._problems.append(e)
2764 return 0
2765
2766
Cory Benfield6492f7c2015-10-27 16:57:58 +09002767def load_publickey(type, buffer):
2768 """
Cory Benfield11c10192015-10-27 17:23:03 +09002769 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002770
Cory Benfield9c590b92015-10-28 14:55:05 +09002771 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002772 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002773 :param buffer: The buffer the key is stored in.
2774 :type buffer: A Python string object, either unicode or bytestring.
2775 :return: The PKey object.
2776 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002777 """
2778 if isinstance(buffer, _text_type):
2779 buffer = buffer.encode("ascii")
2780
2781 bio = _new_mem_buf(buffer)
2782
2783 if type == FILETYPE_PEM:
2784 evp_pkey = _lib.PEM_read_bio_PUBKEY(
Alex Gaynor03737182020-07-23 20:40:46 -04002785 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL
2786 )
Cory Benfield6492f7c2015-10-27 16:57:58 +09002787 elif type == FILETYPE_ASN1:
2788 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2789 else:
2790 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2791
2792 if evp_pkey == _ffi.NULL:
2793 _raise_current_error()
2794
2795 pkey = PKey.__new__(PKey)
2796 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Paul Kehrer32fc4e62016-06-03 15:21:44 -07002797 pkey._only_public = True
Cory Benfield6492f7c2015-10-27 16:57:58 +09002798 return pkey
2799
2800
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002801def load_privatekey(type, buffer, passphrase=None):
2802 """
Alex Chand072cae2018-02-15 09:57:59 +00002803 Load a private key (PKey) from the string *buffer* encoded with the type
2804 *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002805
2806 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2807 :param buffer: The buffer the key is stored in
2808 :param passphrase: (optional) if encrypted PEM format, this can be
2809 either the passphrase to use, or a callback for
2810 providing the passphrase.
2811
2812 :return: The PKey object
2813 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002814 if isinstance(buffer, _text_type):
2815 buffer = buffer.encode("ascii")
2816
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002817 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002818
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002819 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002820 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002821 evp_pkey = _lib.PEM_read_bio_PrivateKey(
Alex Gaynor03737182020-07-23 20:40:46 -04002822 bio, _ffi.NULL, helper.callback, helper.callback_args
2823 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002824 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002825 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002826 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002827 else:
2828 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2829
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002830 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002831 _raise_current_error()
2832
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002833 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002834 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002835 return pkey
2836
2837
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002838def dump_certificate_request(type, req):
2839 """
Alex Chand072cae2018-02-15 09:57:59 +00002840 Dump the certificate request *req* into a buffer string encoded with the
2841 type *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002842
2843 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2844 :param req: The certificate request to dump
2845 :return: The buffer with the dumped certificate request in
2846 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002847 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002848
2849 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002850 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002851 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002852 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002853 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002854 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002855 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002856 raise ValueError(
2857 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2858 "FILETYPE_TEXT"
2859 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002860
Alex Gaynor09a386e2016-07-03 09:32:44 -04002861 _openssl_assert(result_code != 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002862
2863 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002864
2865
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002866def load_certificate_request(type, buffer):
2867 """
Alex Chand072cae2018-02-15 09:57:59 +00002868 Load a certificate request (X509Req) from the string *buffer* encoded with
2869 the type *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002870
2871 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2872 :param buffer: The buffer the certificate request is stored in
2873 :return: The X509Req object
2874 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002875 if isinstance(buffer, _text_type):
2876 buffer = buffer.encode("ascii")
2877
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002878 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002879
2880 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002881 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002882 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002883 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002884 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002885 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002886
Alex Gaynoradd5b072016-06-04 21:04:00 -07002887 _openssl_assert(req != _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002888
2889 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002890 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002891 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002892
2893
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002894def sign(pkey, data, digest):
2895 """
Alex Chand072cae2018-02-15 09:57:59 +00002896 Sign a data string using the given key and message digest.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002897
Alex Chand072cae2018-02-15 09:57:59 +00002898 :param pkey: PKey to sign with
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002899 :param data: data to be signed
2900 :param digest: message digest to use
2901 :return: signature
Alex Chand072cae2018-02-15 09:57:59 +00002902
2903 .. versionadded:: 0.11
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002904 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002905 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002906
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002907 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002908 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002909 raise ValueError("No such digest method")
2910
Alex Gaynor67903a62016-06-02 10:37:13 -07002911 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002912 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002913
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002914 _lib.EVP_SignInit(md_ctx, digest_obj)
2915 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002916
Paul Kehrer59d26252017-07-20 10:45:54 +02002917 length = _lib.EVP_PKEY_size(pkey._pkey)
2918 _openssl_assert(length > 0)
2919 signature_buffer = _ffi.new("unsigned char[]", length)
2920 signature_length = _ffi.new("unsigned int *")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002921 final_result = _lib.EVP_SignFinal(
Alex Gaynor03737182020-07-23 20:40:46 -04002922 md_ctx, signature_buffer, signature_length, pkey._pkey
2923 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04002924 _openssl_assert(final_result == 1)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002925
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002926 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002927
2928
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002929def verify(cert, signature, data, digest):
2930 """
Alex Chand072cae2018-02-15 09:57:59 +00002931 Verify the signature for a data string.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002932
Alex Chand072cae2018-02-15 09:57:59 +00002933 :param cert: signing certificate (X509 object) corresponding to the
2934 private key which generated the signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002935 :param signature: signature returned by sign function
2936 :param data: data to be verified
2937 :param digest: message digest to use
Dan Sully44e767a2016-06-04 18:05:27 -07002938 :return: ``None`` if the signature is correct, raise exception otherwise.
Alex Chand072cae2018-02-15 09:57:59 +00002939
2940 .. versionadded:: 0.11
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002941 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002942 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002943
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002944 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002945 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002946 raise ValueError("No such digest method")
2947
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002948 pkey = _lib.X509_get_pubkey(cert._x509)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002949 _openssl_assert(pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002950 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002951
Alex Gaynor67903a62016-06-02 10:37:13 -07002952 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002953 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002954
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002955 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2956 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002957 verify_result = _lib.EVP_VerifyFinal(
2958 md_ctx, signature, len(signature), pkey
2959 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002960
2961 if verify_result != 1:
2962 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002963
2964
Dominic Chenf05b2122015-10-13 16:32:35 +00002965def dump_crl(type, crl):
2966 """
2967 Dump a certificate revocation list to a buffer.
2968
2969 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2970 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002971 :param CRL crl: The CRL to dump.
2972
Dominic Chenf05b2122015-10-13 16:32:35 +00002973 :return: The buffer with the CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07002974 :rtype: bytes
Dominic Chenf05b2122015-10-13 16:32:35 +00002975 """
2976 bio = _new_mem_buf()
2977
2978 if type == FILETYPE_PEM:
2979 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2980 elif type == FILETYPE_ASN1:
2981 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2982 elif type == FILETYPE_TEXT:
2983 ret = _lib.X509_CRL_print(bio, crl._crl)
2984 else:
2985 raise ValueError(
2986 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
Alex Gaynor03737182020-07-23 20:40:46 -04002987 "FILETYPE_TEXT"
2988 )
Dominic Chenf05b2122015-10-13 16:32:35 +00002989
Adrián Chaves98c57be2020-03-31 16:14:50 +02002990 _openssl_assert(ret == 1)
Dominic Chenf05b2122015-10-13 16:32:35 +00002991 return _bio_to_string(bio)
2992
2993
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002994def load_crl(type, buffer):
2995 """
Alex Chand072cae2018-02-15 09:57:59 +00002996 Load Certificate Revocation List (CRL) data from a string *buffer*.
2997 *buffer* encoded with the type *type*.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002998
2999 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
3000 :param buffer: The buffer the CRL is stored in
3001
3002 :return: The PKey object
3003 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05003004 if isinstance(buffer, _text_type):
3005 buffer = buffer.encode("ascii")
3006
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08003007 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003008
3009 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003010 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003011 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003012 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003013 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003014 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
3015
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003016 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003017 _raise_current_error()
3018
3019 result = CRL.__new__(CRL)
Jeremy Cline9e15eca2017-09-07 20:11:08 -04003020 result._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003021 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003022
3023
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003024def load_pkcs7_data(type, buffer):
3025 """
Alex Chand072cae2018-02-15 09:57:59 +00003026 Load pkcs7 data from the string *buffer* encoded with the type
3027 *type*.
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003028
3029 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
3030 :param buffer: The buffer with the pkcs7 data.
3031 :return: The PKCS7 object
3032 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05003033 if isinstance(buffer, _text_type):
3034 buffer = buffer.encode("ascii")
3035
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08003036 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003037
3038 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003039 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003040 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07003041 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003042 else:
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003043 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
3044
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003045 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08003046 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003047
3048 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003049 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003050 return pypkcs7
3051
3052
Alex Gaynorbb971ae2020-08-05 01:14:16 -04003053load_pkcs7_data = utils.deprecated(
3054 load_pkcs7_data,
3055 __name__,
3056 (
3057 "PKCS#7 support in pyOpenSSL is deprecated. You should use the APIs "
3058 "in cryptography."
3059 ),
3060 DeprecationWarning,
3061)
3062
3063
Stephen Holsapple38482622014-04-05 20:29:34 -07003064def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003065 """
Alex Chand072cae2018-02-15 09:57:59 +00003066 Load pkcs12 data from the string *buffer*. If the pkcs12 structure is
3067 encrypted, a *passphrase* must be included. The MAC is always
3068 checked and thus required.
3069
3070 See also the man page for the C function :py:func:`PKCS12_parse`.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003071
3072 :param buffer: The buffer the certificate is stored in
3073 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
3074 :returns: The PKCS12 object
3075 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04003076 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00003077
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05003078 if isinstance(buffer, _text_type):
3079 buffer = buffer.encode("ascii")
3080
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08003081 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003082
Stephen Holsapple38482622014-04-05 20:29:34 -07003083 # Use null passphrase if passphrase is None or empty string. With PKCS#12
3084 # password based encryption no password and a zero length password are two
3085 # different things, but OpenSSL implementation will try both to figure out
3086 # which one works.
3087 if not passphrase:
3088 passphrase = _ffi.NULL
3089
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003090 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
3091 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003092 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003093 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003094
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003095 pkey = _ffi.new("EVP_PKEY**")
3096 cert = _ffi.new("X509**")
3097 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003098
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003099 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003100 if not parse_result:
3101 _raise_current_error()
3102
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003103 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08003104
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003105 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
3106 # queue for no particular reason. This error isn't interesting to anyone
3107 # outside this function. It's not even interesting to us. Get rid of it.
3108 try:
3109 _raise_current_error()
3110 except Error:
3111 pass
3112
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003113 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003114 pykey = None
3115 else:
3116 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003117 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003118
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003119 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003120 pycert = None
3121 friendlyname = None
3122 else:
Paul Kehrere7381862017-11-30 20:55:25 +08003123 pycert = X509._from_raw_x509_ptr(cert[0])
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003124
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003125 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04003126 friendlyname_buffer = _lib.X509_alias_get0(
3127 cert[0], friendlyname_length
3128 )
3129 friendlyname = _ffi.buffer(
3130 friendlyname_buffer, friendlyname_length[0]
3131 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003132 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003133 friendlyname = None
3134
3135 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003136 for i in range(_lib.sk_X509_num(cacerts)):
Paul Kehrere7381862017-11-30 20:55:25 +08003137 x509 = _lib.sk_X509_value(cacerts, i)
3138 pycacert = X509._from_raw_x509_ptr(x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003139 pycacerts.append(pycacert)
3140 if not pycacerts:
3141 pycacerts = None
3142
3143 pkcs12 = PKCS12.__new__(PKCS12)
3144 pkcs12._pkey = pykey
3145 pkcs12._cert = pycert
3146 pkcs12._cacerts = pycacerts
3147 pkcs12._friendlyname = friendlyname
3148 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05003149
3150
Alex Gaynorbb971ae2020-08-05 01:14:16 -04003151load_pkcs12 = utils.deprecated(
3152 load_pkcs12,
3153 __name__,
3154 (
3155 "PKCS#12 support in pyOpenSSL is deprecated. You should use the APIs "
3156 "in cryptography."
3157 ),
3158 DeprecationWarning,
3159)
3160
3161
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05003162# There are no direct unit tests for this initialization. It is tested
3163# indirectly since it is necessary for functions like dump_privatekey when
3164# using encryption.
3165#
3166# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
3167# and some other similar tests may fail without this (though they may not if
3168# the Python runtime has already done some initialization of the underlying
3169# OpenSSL library (and is linked against the same one that cryptography is
3170# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05003171_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05003172
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05003173# This is similar but exercised mainly by exception_from_error_queue. It calls
3174# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
3175_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02003176
3177
D.S. Ljungmark349e1362014-05-31 18:40:38 +02003178# Set the default string mask to match OpenSSL upstream (since 2005) and
3179# RFC5280 recommendations.
Alex Gaynor03737182020-07-23 20:40:46 -04003180_lib.ASN1_STRING_set_default_mask_asc(b"utf8only")