blob: 673da3f931a34c45aec25e130a9b7f7462929961 [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,
Sándor Oroszi43c97762020-09-11 17:17:31 +020022 path_string as _path_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040023 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040024 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Alex Gaynor67903a62016-06-02 10:37:13 -070025 make_assert as _make_assert,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040026)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080027
Nicolas Karolak736c6212017-11-26 14:40:28 +010028__all__ = [
Alex Gaynor03737182020-07-23 20:40:46 -040029 "FILETYPE_PEM",
30 "FILETYPE_ASN1",
31 "FILETYPE_TEXT",
32 "TYPE_RSA",
33 "TYPE_DSA",
34 "Error",
35 "PKey",
36 "get_elliptic_curves",
37 "get_elliptic_curve",
38 "X509Name",
39 "X509Extension",
40 "X509Req",
41 "X509",
42 "X509StoreFlags",
43 "X509Store",
44 "X509StoreContextError",
45 "X509StoreContext",
46 "load_certificate",
47 "dump_certificate",
48 "dump_publickey",
49 "dump_privatekey",
50 "Revoked",
51 "CRL",
52 "PKCS7",
53 "PKCS12",
54 "NetscapeSPKI",
55 "load_publickey",
56 "load_privatekey",
57 "dump_certificate_request",
58 "load_certificate_request",
59 "sign",
60 "verify",
61 "dump_crl",
62 "load_crl",
63 "load_pkcs7_data",
64 "load_pkcs12",
Nicolas Karolak736c6212017-11-26 14:40:28 +010065]
66
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050067FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
68FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080069
70# TODO This was an API mistake. OpenSSL has no such constant.
71FILETYPE_TEXT = 2 ** 16 - 1
72
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050073TYPE_RSA = _lib.EVP_PKEY_RSA
74TYPE_DSA = _lib.EVP_PKEY_DSA
Igr2f874f22019-01-21 21:39:37 +030075TYPE_DH = _lib.EVP_PKEY_DH
76TYPE_EC = _lib.EVP_PKEY_EC
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080077
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080078
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050079class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050080 """
81 An error occurred in an `OpenSSL.crypto` API.
82 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050083
84
85_raise_current_error = partial(_exception_from_error_queue, Error)
Alex Gaynor67903a62016-06-02 10:37:13 -070086_openssl_assert = _make_assert(Error)
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050087
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070088
Paul Kehrereb633842016-10-06 11:22:01 +020089def _get_backend():
90 """
91 Importing the backend from cryptography has the side effect of activating
92 the osrandom engine. This mutates the global state of OpenSSL in the
93 process and causes issues for various programs that use subinterpreters or
94 embed Python. By putting the import in this function we can avoid
95 triggering this side effect unless _get_backend is called.
96 """
97 from cryptography.hazmat.backends.openssl.backend import backend
Alex Gaynor03737182020-07-23 20:40:46 -040098
Paul Kehrereb633842016-10-06 11:22:01 +020099 return backend
100
101
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500102def _untested_error(where):
103 """
104 An OpenSSL API failed somehow. Additionally, the failure which was
105 encountered isn't one that's exercised by the test suite so future behavior
106 of pyOpenSSL is now somewhat less predictable.
107 """
108 raise RuntimeError("Unknown %s failure" % (where,))
109
110
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500111def _new_mem_buf(buffer=None):
112 """
113 Allocate a new OpenSSL memory BIO.
114
115 Arrange for the garbage collector to clean it up automatically.
116
117 :param buffer: None or some bytes to use to put into the BIO so that they
118 can be read out.
119 """
120 if buffer is None:
121 bio = _lib.BIO_new(_lib.BIO_s_mem())
122 free = _lib.BIO_free
123 else:
124 data = _ffi.new("char[]", buffer)
125 bio = _lib.BIO_new_mem_buf(data, len(buffer))
Alex Gaynor5945ea82015-09-05 14:59:06 -0400126
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500127 # Keep the memory alive as long as the bio is alive!
128 def free(bio, ref=data):
129 return _lib.BIO_free(bio)
130
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700131 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500132
133 bio = _ffi.gc(bio, free)
134 return bio
135
136
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800137def _bio_to_string(bio):
138 """
139 Copy the contents of an OpenSSL BIO object into a Python byte string.
140 """
Alex Gaynor03737182020-07-23 20:40:46 -0400141 result_buffer = _ffi.new("char**")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500142 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
143 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800144
145
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800146def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500147 """
148 The the time value of an ASN1 time object.
149
Moriyoshi Koizumi80b25ef2017-06-22 00:54:20 +0900150 @param boundary: An ASN1_TIME pointer (or an object safely
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500151 castable to that type) which will have its value set.
152 @param when: A string representation of the desired time value.
153
154 @raise TypeError: If C{when} is not a L{bytes} string.
155 @raise ValueError: If C{when} does not represent a time in the required
156 format.
157 @raise RuntimeError: If the time value cannot be set for some other
158 (unspecified) reason.
159 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800160 if not isinstance(when, bytes):
161 raise TypeError("when must be a byte string")
162
Moriyoshi Koizumi80b25ef2017-06-22 00:54:20 +0900163 set_result = _lib.ASN1_TIME_set_string(boundary, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800164 if set_result == 0:
Moriyoshi Koizumi80b25ef2017-06-22 00:54:20 +0900165 raise ValueError("Invalid string")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800166
Alex Gaynor510293e2016-06-02 12:07:59 -0700167
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800168def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500169 """
170 Retrieve the time value of an ASN1 time object.
171
172 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
173 that type) from which the time value will be retrieved.
174
175 @return: The time value from C{timestamp} as a L{bytes} string in a certain
176 format. Or C{None} if the object contains no time value.
177 """
Alex Gaynor03737182020-07-23 20:40:46 -0400178 string_timestamp = _ffi.cast("ASN1_STRING*", timestamp)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500179 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800180 return None
Alex Gaynor5945ea82015-09-05 14:59:06 -0400181 elif (
182 _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
183 ):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500184 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800185 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500186 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
187 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
188 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500189 # This may happen:
190 # - if timestamp was not an ASN1_TIME
191 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
192 # - if a copy of the time data from timestamp cannot be made for
193 # the newly allocated ASN1_GENERALIZEDTIME
194 #
195 # These are difficult to test. cffi enforces the ASN1_TIME type.
196 # Memory allocation failures are a pain to trigger
197 # deterministically.
198 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800199 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500200 string_timestamp = _ffi.cast(
Alex Gaynor03737182020-07-23 20:40:46 -0400201 "ASN1_STRING*", generalized_timestamp[0]
202 )
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500203 string_data = _lib.ASN1_STRING_data(string_timestamp)
204 string_result = _ffi.string(string_data)
205 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800206 return string_result
207
208
Alex Gaynor4aa52c32017-11-20 09:04:08 -0500209class _X509NameInvalidator(object):
210 def __init__(self):
211 self._names = []
212
213 def add(self, name):
214 self._names.append(name)
215
216 def clear(self):
217 for name in self._names:
218 # Breaks the object, but also prevents UAF!
219 del name._name
220
221
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800222class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200223 """
224 A class representing an DSA or RSA public key or key pair.
225 """
Alex Gaynor03737182020-07-23 20:40:46 -0400226
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800227 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800228 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800229
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800230 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500231 pkey = _lib.EVP_PKEY_new()
232 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800233 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800234
Paul Kehrer72d968b2016-07-29 15:31:04 +0800235 def to_cryptography_key(self):
236 """
237 Export as a ``cryptography`` key.
238
239 :rtype: One of ``cryptography``'s `key interfaces`_.
240
241 .. _key interfaces: https://cryptography.io/en/latest/hazmat/\
242 primitives/asymmetric/rsa/#key-interfaces
243
244 .. versionadded:: 16.1.0
245 """
Paul Kehrereb633842016-10-06 11:22:01 +0200246 backend = _get_backend()
Paul Kehrer72d968b2016-07-29 15:31:04 +0800247 if self._only_public:
248 return backend._evp_pkey_to_public_key(self._pkey)
249 else:
250 return backend._evp_pkey_to_private_key(self._pkey)
251
252 @classmethod
253 def from_cryptography_key(cls, crypto_key):
254 """
255 Construct based on a ``cryptography`` *crypto_key*.
256
257 :param crypto_key: A ``cryptography`` key.
258 :type crypto_key: One of ``cryptography``'s `key interfaces`_.
259
260 :rtype: PKey
261
262 .. versionadded:: 16.1.0
263 """
264 pkey = cls()
Alex Gaynor03737182020-07-23 20:40:46 -0400265 if not isinstance(
266 crypto_key,
267 (
268 rsa.RSAPublicKey,
269 rsa.RSAPrivateKey,
270 dsa.DSAPublicKey,
271 dsa.DSAPrivateKey,
272 ),
273 ):
Paul Kehrer72d968b2016-07-29 15:31:04 +0800274 raise TypeError("Unsupported key type")
275
276 pkey._pkey = crypto_key._evp_pkey
277 if isinstance(crypto_key, (rsa.RSAPublicKey, dsa.DSAPublicKey)):
278 pkey._only_public = True
279 pkey._initialized = True
280 return pkey
281
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800282 def generate_key(self, type, bits):
283 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700284 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800285
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200286 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800287
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200288 :param type: The key type.
289 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
290 :param bits: The number of bits.
291 :type bits: :py:data:`int` ``>= 0``
292 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
293 of the appropriate type.
294 :raises ValueError: If the number of bits isn't an integer of
295 the appropriate size.
Dan Sully44e767a2016-06-04 18:05:27 -0700296 :return: ``None``
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800297 """
298 if not isinstance(type, int):
299 raise TypeError("type must be an integer")
300
301 if not isinstance(bits, int):
302 raise TypeError("bits must be an integer")
303
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800304 if type == TYPE_RSA:
305 if bits <= 0:
306 raise ValueError("Invalid number of bits")
307
David Benjamin179eb1d2018-06-05 17:56:07 -0400308 # TODO Check error return
309 exponent = _lib.BN_new()
310 exponent = _ffi.gc(exponent, _lib.BN_free)
311 _lib.BN_set_word(exponent, _lib.RSA_F4)
312
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500313 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800314
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500315 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400316 _openssl_assert(result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800317
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500318 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400319 _openssl_assert(result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800320
321 elif type == TYPE_DSA:
Paul Kehrera0860b92016-03-09 21:39:27 -0400322 dsa = _lib.DSA_new()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700323 _openssl_assert(dsa != _ffi.NULL)
Paul Kehrerafa5a662016-03-10 10:29:28 -0400324
325 dsa = _ffi.gc(dsa, _lib.DSA_free)
Paul Kehrera0860b92016-03-09 21:39:27 -0400326 res = _lib.DSA_generate_parameters_ex(
327 dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL
328 )
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700329 _openssl_assert(res == 1)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400330
331 _openssl_assert(_lib.DSA_generate_key(dsa) == 1)
332 _openssl_assert(_lib.EVP_PKEY_set1_DSA(self._pkey, dsa) == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800333 else:
334 raise Error("No such key type")
335
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800336 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800337
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800338 def check(self):
339 """
340 Check the consistency of an RSA private key.
341
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200342 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
343
Hynek Schlawack01c31672016-12-11 15:14:09 +0100344 :return: ``True`` if key is consistent.
345
346 :raise OpenSSL.crypto.Error: if the key is inconsistent.
347
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800348 :raise TypeError: if the key is of a type which cannot be checked.
349 Only RSA keys can currently be checked.
350 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800351 if self._only_public:
352 raise TypeError("public key only")
353
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100354 if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800355 raise TypeError("key type unsupported")
356
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500357 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
358 rsa = _ffi.gc(rsa, _lib.RSA_free)
359 result = _lib.RSA_check_key(rsa)
Mrmaxmeier8cd3b172020-03-11 22:03:59 +0100360 if result == 1:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800361 return True
362 _raise_current_error()
363
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800364 def type(self):
365 """
366 Returns the type of the key
367
368 :return: The type of the key.
369 """
Alex Gaynor0d2aec52017-05-31 04:26:27 -0400370 return _lib.EVP_PKEY_id(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800371
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800372 def bits(self):
373 """
374 Returns the number of bits of the key
375
376 :return: The number of bits of the key.
377 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500378 return _lib.EVP_PKEY_bits(self._pkey)
Alex Chanc6077062016-11-18 13:53:39 +0000379
380
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400381class _EllipticCurve(object):
382 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400383 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400384
385 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
386 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
387 instances each of which represents one curve supported by the system.
388 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400389 """
Alex Gaynor03737182020-07-23 20:40:46 -0400390
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400391 _curves = None
392
Alex Gaynor26f1a922019-11-18 00:37:39 -0500393 if not _PY2:
Felix Yan3db93f12020-10-15 03:41:20 +0800394 # This only necessary on Python 3. Moreover, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400395 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400396 """
397 Implement cooperation with the right-hand side argument of ``!=``.
398
399 Python 3 seems to have dropped this cooperation in this very narrow
400 circumstance.
401 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400402 if isinstance(other, _EllipticCurve):
403 return super(_EllipticCurve, self).__ne__(other)
404 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400405
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400406 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400407 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400408 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400409 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400410
411 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400412
413 :return: A :py:type:`set` of ``cls`` instances giving the names of the
414 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400415 """
Alex Chan84902a22017-04-20 11:50:47 +0100416 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
Alex Gaynor03737182020-07-23 20:40:46 -0400417 builtin_curves = _ffi.new("EC_builtin_curve[]", num_curves)
Alex Chan84902a22017-04-20 11:50:47 +0100418 # The return value on this call should be num_curves again. We
419 # could check it to make sure but if it *isn't* then.. what could
420 # we do? Abort the whole process, I suppose...? -exarkun
421 lib.EC_get_builtin_curves(builtin_curves, num_curves)
Alex Gaynor03737182020-07-23 20:40:46 -0400422 return set(cls.from_nid(lib, c.nid) for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400423
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400424 @classmethod
425 def _get_elliptic_curves(cls, lib):
426 """
427 Get, cache, and return the curves supported by OpenSSL.
428
429 :param lib: The OpenSSL library binding object.
430
431 :return: A :py:type:`set` of ``cls`` instances giving the names of the
432 elliptic curves the underlying library supports.
433 """
434 if cls._curves is None:
435 cls._curves = cls._load_elliptic_curves(lib)
436 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400437
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400438 @classmethod
439 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400440 """
441 Instantiate a new :py:class:`_EllipticCurve` associated with the given
442 OpenSSL NID.
443
444 :param lib: The OpenSSL library binding object.
445
446 :param nid: The OpenSSL NID the resulting curve object will represent.
447 This must be a curve NID (and not, for example, a hash NID) or
448 subsequent operations will fail in unpredictable ways.
449 :type nid: :py:class:`int`
450
451 :return: The curve object.
452 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400453 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
454
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400455 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400456 """
457 :param _lib: The :py:mod:`cryptography` binding instance used to
458 interface with OpenSSL.
459
460 :param _nid: The OpenSSL NID identifying the curve this object
461 represents.
462 :type _nid: :py:class:`int`
463
464 :param name: The OpenSSL short name identifying the curve this object
465 represents.
466 :type name: :py:class:`unicode`
467 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400468 self._lib = lib
469 self._nid = nid
470 self.name = name
471
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400472 def __repr__(self):
473 return "<Curve %r>" % (self.name,)
474
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400475 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400476 """
477 Create a new OpenSSL EC_KEY structure initialized to use this curve.
478
479 The structure is automatically garbage collected when the Python object
480 is garbage collected.
481 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400482 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
483 return _ffi.gc(key, _lib.EC_KEY_free)
484
485
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400486def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400487 """
488 Return a set of objects representing the elliptic curves supported in the
489 OpenSSL build in use.
490
491 The curve objects have a :py:class:`unicode` ``name`` attribute by which
492 they identify themselves.
493
494 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400495 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
496 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400497 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400498 return _EllipticCurve._get_elliptic_curves(_lib)
499
500
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400501def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400502 """
503 Return a single curve object selected by name.
504
505 See :py:func:`get_elliptic_curves` for information about curve objects.
506
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400507 :param name: The OpenSSL short name identifying the curve object to
508 retrieve.
509 :type name: :py:class:`unicode`
510
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400511 If the named curve is not supported then :py:class:`ValueError` is raised.
512 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400513 for curve in get_elliptic_curves():
514 if curve.name == name:
515 return curve
516 raise ValueError("unknown curve name", name)
517
518
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800519class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200520 """
521 An X.509 Distinguished Name.
522
523 :ivar countryName: The country of the entity.
524 :ivar C: Alias for :py:attr:`countryName`.
525
526 :ivar stateOrProvinceName: The state or province of the entity.
527 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
528
529 :ivar localityName: The locality of the entity.
530 :ivar L: Alias for :py:attr:`localityName`.
531
532 :ivar organizationName: The organization name of the entity.
533 :ivar O: Alias for :py:attr:`organizationName`.
534
535 :ivar organizationalUnitName: The organizational unit of the entity.
536 :ivar OU: Alias for :py:attr:`organizationalUnitName`
537
538 :ivar commonName: The common name of the entity.
539 :ivar CN: Alias for :py:attr:`commonName`.
540
541 :ivar emailAddress: The e-mail address of the entity.
542 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400543
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800544 def __init__(self, name):
545 """
546 Create a new X509Name, copying the given X509Name instance.
547
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200548 :param name: The name to copy.
549 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800550 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500551 name = _lib.X509_NAME_dup(name._name)
552 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800553
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800554 def __setattr__(self, name, value):
Alex Gaynor03737182020-07-23 20:40:46 -0400555 if name.startswith("_"):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800556 return super(X509Name, self).__setattr__(name, value)
557
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800558 # Note: we really do not want str subclasses here, so we do not use
559 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800560 if type(name) is not str:
Alex Gaynor03737182020-07-23 20:40:46 -0400561 raise TypeError(
562 "attribute name must be string, not '%.200s'"
563 % (type(value).__name__,)
564 )
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800565
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500566 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500567 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800568 try:
569 _raise_current_error()
570 except Error:
571 pass
572 raise AttributeError("No such attribute")
573
574 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500575 for i in range(_lib.X509_NAME_entry_count(self._name)):
576 ent = _lib.X509_NAME_get_entry(self._name, i)
577 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
578 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800579 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500580 ent = _lib.X509_NAME_delete_entry(self._name, i)
581 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800582 break
583
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500584 if isinstance(value, _text_type):
Alex Gaynor03737182020-07-23 20:40:46 -0400585 value = value.encode("utf-8")
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800586
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500587 add_result = _lib.X509_NAME_add_entry_by_NID(
Alex Gaynor03737182020-07-23 20:40:46 -0400588 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0
589 )
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800590 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500591 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800592
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800593 def __getattr__(self, name):
594 """
595 Find attribute. An X509Name object has the following attributes:
596 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400597 organization (alias O), organizationalUnit (alias OU), commonName
598 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800599 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500600 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500601 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800602 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
603 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
604 # push something onto the error queue. If we don't clean that up
605 # now, someone else will bump into it later and be quite confused.
606 # See lp#314814.
607 try:
608 _raise_current_error()
609 except Error:
610 pass
611 return super(X509Name, self).__getattr__(name)
612
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500613 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800614 if entry_index == -1:
615 return None
616
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500617 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
618 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800619
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500620 result_buffer = _ffi.new("unsigned char**")
621 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400622 _openssl_assert(data_length >= 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800623
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700624 try:
Alex Gaynor03737182020-07-23 20:40:46 -0400625 result = _ffi.buffer(result_buffer[0], data_length)[:].decode(
626 "utf-8"
627 )
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700628 finally:
629 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500630 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800631 return result
632
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500633 def _cmp(op):
634 def f(self, other):
635 if not isinstance(other, X509Name):
636 return NotImplemented
637 result = _lib.X509_NAME_cmp(self._name, other._name)
638 return op(result, 0)
Alex Gaynor03737182020-07-23 20:40:46 -0400639
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500640 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800641
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500642 __eq__ = _cmp(__eq__)
643 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800644
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500645 __lt__ = _cmp(__lt__)
646 __le__ = _cmp(__le__)
647
648 __gt__ = _cmp(__gt__)
649 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800650
651 def __repr__(self):
652 """
653 String representation of an X509Name
654 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400655 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500656 format_result = _lib.X509_NAME_oneline(
Alex Gaynor03737182020-07-23 20:40:46 -0400657 self._name, result_buffer, len(result_buffer)
658 )
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700659 _openssl_assert(format_result != _ffi.NULL)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800660
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500661 return "<X509Name object '%s'>" % (
Alex Gaynor03737182020-07-23 20:40:46 -0400662 _native(_ffi.string(result_buffer)),
663 )
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800664
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800665 def hash(self):
666 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200667 Return an integer representation of the first four bytes of the
668 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800669
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200670 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
671
672 :return: The (integer) hash of this name.
673 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800674 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500675 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800676
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800677 def der(self):
678 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200679 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800680
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200681 :return: The DER encoded form of this name.
682 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800683 """
Alex Gaynor03737182020-07-23 20:40:46 -0400684 result_buffer = _ffi.new("unsigned char**")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500685 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400686 _openssl_assert(encode_result >= 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800687
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500688 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
689 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800690 return string_result
691
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800692 def get_components(self):
693 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200694 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800695
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200696 :return: The components of this name.
697 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800698 """
699 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500700 for i in range(_lib.X509_NAME_entry_count(self._name)):
701 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800702
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500703 fname = _lib.X509_NAME_ENTRY_get_object(ent)
704 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800705
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500706 nid = _lib.OBJ_obj2nid(fname)
707 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800708
Romuald Brunet4183beb2019-01-21 19:38:33 +0100709 # ffi.string does not handle strings containing NULL bytes
710 # (which may have been generated by old, broken software)
Alex Gaynor03737182020-07-23 20:40:46 -0400711 value = _ffi.buffer(
712 _lib.ASN1_STRING_data(fval), _lib.ASN1_STRING_length(fval)
713 )[:]
Romuald Brunet4183beb2019-01-21 19:38:33 +0100714 result.append((_ffi.string(name), value))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800715
716 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200717
718
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800719class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200720 """
721 An X.509 v3 certificate extension.
722 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400723
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800724 def __init__(self, type_name, critical, value, subject=None, issuer=None):
725 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200726 Initializes an X509 extension.
727
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100728 :param type_name: The name of the type of extension_ to create.
Alex Gaynor6f719912015-09-20 09:21:29 -0400729 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800730
Alex Gaynor5945ea82015-09-05 14:59:06 -0400731 :param bool critical: A flag indicating whether this is a critical
732 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800733
734 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200735 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800736
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200737 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800738 :type subject: :py:class:`X509`
739
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200740 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800741 :type issuer: :py:class:`X509`
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100742
Alex Chan54005ce2017-03-21 08:08:17 +0000743 .. _extension: https://www.openssl.org/docs/manmaster/man5/
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100744 x509v3_config.html#STANDARD-EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800745 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500746 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800747
Alex Gaynor5945ea82015-09-05 14:59:06 -0400748 # A context is necessary for any extension which uses the r2i
749 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
750 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500751 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800752
753 # We have no configuration database - but perhaps we should (some
754 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500755 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800756
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800757 # Initialize the subject and issuer, if appropriate. ctx is a local,
758 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400759 # any references, so no need to mess with reference counts or
760 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800761 if issuer is not None:
762 if not isinstance(issuer, X509):
763 raise TypeError("issuer must be an X509 instance")
764 ctx.issuer_cert = issuer._x509
765 if subject is not None:
766 if not isinstance(subject, X509):
767 raise TypeError("subject must be an X509 instance")
768 ctx.subject_cert = subject._x509
769
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800770 if critical:
771 # There are other OpenSSL APIs which would let us pass in critical
772 # separately, but they're harder to use, and since value is already
773 # a pile of crappy junk smuggling a ton of utterly important
774 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400775 # with strings? (However, X509V3_EXT_i2d in particular seems like
776 # it would be a better API to invoke. I do not know where to get
777 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500778 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800779
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500780 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
781 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800782 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500783 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800784
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400785 @property
786 def _nid(self):
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400787 return _lib.OBJ_obj2nid(
788 _lib.X509_EXTENSION_get_object(self._extension)
789 )
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400790
791 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500792 _lib.GEN_EMAIL: "email",
793 _lib.GEN_DNS: "DNS",
794 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400795 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400796
797 def _subjectAltNameString(self):
Alex Gaynord61c46a2017-06-29 22:51:33 -0700798 names = _ffi.cast(
799 "GENERAL_NAMES*", _lib.X509V3_EXT_d2i(self._extension)
800 )
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400801
Paul Kehrerb7d79502015-05-04 07:43:51 -0500802 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400803 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500804 for i in range(_lib.sk_GENERAL_NAME_num(names)):
805 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400806 try:
807 label = self._prefixes[name.type]
808 except KeyError:
809 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500810 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500811 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400812 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500813 value = _native(
Alex Gaynor03737182020-07-23 20:40:46 -0400814 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:]
815 )
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500816 parts.append(label + ":" + value)
817 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400818
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800819 def __str__(self):
820 """
821 :return: a nice text representation of the extension
822 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500823 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400824 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800825
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400826 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500827 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400828 _openssl_assert(print_result != 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800829
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500830 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800831
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800832 def get_critical(self):
833 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200834 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800835
836 :return: The critical field.
837 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500838 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800839
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800840 def get_short_name(self):
841 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200842 Returns the short type name of this X.509 extension.
843
844 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800845
846 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200847 :rtype: :py:data:`bytes`
848
849 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800850 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500851 obj = _lib.X509_EXTENSION_get_object(self._extension)
852 nid = _lib.OBJ_obj2nid(obj)
853 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800854
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800855 def get_data(self):
856 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200857 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800858
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200859 :return: The ASN.1 encoded data of this X509 extension.
860 :rtype: :py:data:`bytes`
861
862 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800863 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500864 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
Alex Gaynor03737182020-07-23 20:40:46 -0400865 string_result = _ffi.cast("ASN1_STRING*", octet_result)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500866 char_result = _lib.ASN1_STRING_data(string_result)
867 result_length = _lib.ASN1_STRING_length(string_result)
868 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800869
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200870
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800871class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200872 """
873 An X.509 certificate signing requests.
874 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400875
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800876 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500877 req = _lib.X509_REQ_new()
878 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Alex Gaynor5af32d02016-09-24 01:52:21 -0400879 # Default to version 0.
880 self.set_version(0)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800881
Paul Kehrer41c10242017-06-29 18:24:17 -0500882 def to_cryptography(self):
883 """
884 Export as a ``cryptography`` certificate signing request.
885
886 :rtype: ``cryptography.x509.CertificateSigningRequest``
887
888 .. versionadded:: 17.1.0
889 """
890 from cryptography.hazmat.backends.openssl.x509 import (
Alex Gaynor03737182020-07-23 20:40:46 -0400891 _CertificateSigningRequest,
Paul Kehrer41c10242017-06-29 18:24:17 -0500892 )
Alex Gaynor03737182020-07-23 20:40:46 -0400893
Paul Kehrer41c10242017-06-29 18:24:17 -0500894 backend = _get_backend()
895 return _CertificateSigningRequest(backend, self._req)
896
897 @classmethod
898 def from_cryptography(cls, crypto_req):
899 """
900 Construct based on a ``cryptography`` *crypto_req*.
901
902 :param crypto_req: A ``cryptography`` X.509 certificate signing request
903 :type crypto_req: ``cryptography.x509.CertificateSigningRequest``
904
Gaurav Malhotra4121e252019-01-22 00:09:19 +0530905 :rtype: X509Req
Paul Kehrer41c10242017-06-29 18:24:17 -0500906
907 .. versionadded:: 17.1.0
908 """
909 if not isinstance(crypto_req, x509.CertificateSigningRequest):
910 raise TypeError("Must be a certificate signing request")
911
912 req = cls()
913 req._req = crypto_req._x509_req
914 return req
915
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800916 def set_pubkey(self, pkey):
917 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200918 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800919
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200920 :param pkey: The public key to use.
921 :type pkey: :py:class:`PKey`
922
Dan Sully44e767a2016-06-04 18:05:27 -0700923 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800924 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500925 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400926 _openssl_assert(set_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800927
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800928 def get_pubkey(self):
929 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200930 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800931
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200932 :return: The public key.
933 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800934 """
935 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500936 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700937 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500938 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800939 pkey._only_public = True
940 return pkey
941
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800942 def set_version(self, version):
943 """
944 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
945 request.
946
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200947 :param int version: The version number.
Dan Sully44e767a2016-06-04 18:05:27 -0700948 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800949 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500950 set_result = _lib.X509_REQ_set_version(self._req, version)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400951 _openssl_assert(set_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800952
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800953 def get_version(self):
954 """
955 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
956 request.
957
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200958 :return: The value of the version subfield.
959 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800960 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500961 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800962
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800963 def get_subject(self):
964 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200965 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800966
Cory Benfield881dc8d2015-12-09 08:25:14 +0000967 This creates a new :class:`X509Name` that wraps the underlying subject
968 name field on the certificate signing request. Modifying it will modify
969 the underlying signing request, and will have the effect of modifying
970 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200971
972 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000973 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800974 """
975 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500976 name._name = _lib.X509_REQ_get_subject_name(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700977 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800978
979 # The name is owned by the X509Req structure. As long as the X509Name
980 # Python object is alive, keep the X509Req Python object alive.
981 name._owner = self
982
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800983 return name
984
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800985 def add_extensions(self, extensions):
986 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200987 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800988
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200989 :param extensions: The X.509 extensions to add.
990 :type extensions: iterable of :py:class:`X509Extension`
Dan Sully44e767a2016-06-04 18:05:27 -0700991 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800992 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500993 stack = _lib.sk_X509_EXTENSION_new_null()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700994 _openssl_assert(stack != _ffi.NULL)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800995
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500996 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800997
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800998 for ext in extensions:
999 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -08001000 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001001
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001002 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001003 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001004
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001005 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001006 _openssl_assert(add_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001007
Stephen Holsappleadfd39d2014-01-28 17:58:31 -08001008 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -08001009 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001010 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -08001011
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001012 :return: The X.509 extensions in this request.
1013 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
1014
1015 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -08001016 """
1017 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -05001018 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -05001019 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -08001020 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -05001021 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -08001022 exts.append(ext)
1023 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -08001024
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001025 def sign(self, pkey, digest):
1026 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001027 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001028
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001029 :param pkey: The key pair to sign with.
1030 :type pkey: :py:class:`PKey`
1031 :param digest: The name of the message digest to use for the signature,
Alex Gaynor239e2d32016-09-11 12:36:35 -04001032 e.g. :py:data:`b"sha256"`.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001033 :type digest: :py:class:`bytes`
Dan Sully44e767a2016-06-04 18:05:27 -07001034 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001035 """
1036 if pkey._only_public:
1037 raise ValueError("Key has only public part")
1038
1039 if not pkey._initialized:
1040 raise ValueError("Key is uninitialized")
1041
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001042 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001043 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001044 raise ValueError("No such digest method")
1045
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001046 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001047 _openssl_assert(sign_result > 0)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -08001048
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001049 def verify(self, pkey):
1050 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +02001051 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001052
Hynek Schlawack01c31672016-12-11 15:14:09 +01001053 :param PKey key: A public key.
1054
1055 :return: ``True`` if the signature is correct.
1056 :rtype: bool
1057
1058 :raises OpenSSL.crypto.Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001059 problem verifying the signature.
1060 """
1061 if not isinstance(pkey, PKey):
1062 raise TypeError("pkey must be a PKey instance")
1063
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001064 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001065 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001066 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -08001067
1068 return result
1069
1070
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001071class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001072 """
1073 An X.509 certificate.
1074 """
Alex Gaynor03737182020-07-23 20:40:46 -04001075
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001076 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001077 x509 = _lib.X509_new()
Hynek Schlawack8a2dd772016-07-31 13:46:20 +02001078 _openssl_assert(x509 != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001079 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001080
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001081 self._issuer_invalidator = _X509NameInvalidator()
1082 self._subject_invalidator = _X509NameInvalidator()
1083
1084 @classmethod
1085 def _from_raw_x509_ptr(cls, x509):
1086 cert = cls.__new__(cls)
1087 cert._x509 = _ffi.gc(x509, _lib.X509_free)
1088 cert._issuer_invalidator = _X509NameInvalidator()
1089 cert._subject_invalidator = _X509NameInvalidator()
1090 return cert
1091
Alex Gaynor9939ba12017-06-25 16:28:24 -04001092 def to_cryptography(self):
1093 """
1094 Export as a ``cryptography`` certificate.
1095
1096 :rtype: ``cryptography.x509.Certificate``
1097
1098 .. versionadded:: 17.1.0
1099 """
1100 from cryptography.hazmat.backends.openssl.x509 import _Certificate
Alex Gaynor03737182020-07-23 20:40:46 -04001101
Alex Gaynor9939ba12017-06-25 16:28:24 -04001102 backend = _get_backend()
1103 return _Certificate(backend, self._x509)
1104
1105 @classmethod
1106 def from_cryptography(cls, crypto_cert):
1107 """
1108 Construct based on a ``cryptography`` *crypto_cert*.
1109
1110 :param crypto_key: A ``cryptography`` X.509 certificate.
1111 :type crypto_key: ``cryptography.x509.Certificate``
1112
Gaurav Malhotra4121e252019-01-22 00:09:19 +05301113 :rtype: X509
Alex Gaynor9939ba12017-06-25 16:28:24 -04001114
1115 .. versionadded:: 17.1.0
1116 """
1117 if not isinstance(crypto_cert, x509.Certificate):
1118 raise TypeError("Must be a certificate")
1119
1120 cert = cls()
1121 cert._x509 = crypto_cert._x509
1122 return cert
1123
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001124 def set_version(self, version):
1125 """
Cyril Stoller6f25ced2018-08-27 13:37:51 +02001126 Set the version number of the certificate. Note that the
1127 version value is zero-based, eg. a value of 0 is V1.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001128
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001129 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001130 :type version: :py:class:`int`
1131
Dan Sully44e767a2016-06-04 18:05:27 -07001132 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001133 """
1134 if not isinstance(version, int):
1135 raise TypeError("version must be an integer")
1136
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001137 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001138
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001139 def get_version(self):
1140 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001141 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001142
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001143 :return: The version number of the certificate.
1144 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001145 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001146 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001147
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001148 def get_pubkey(self):
1149 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001150 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001151
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001152 :return: The public key.
1153 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001154 """
1155 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001156 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1157 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001158 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001159 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001160 pkey._only_public = True
1161 return pkey
1162
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001163 def set_pubkey(self, pkey):
1164 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001165 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001166
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001167 :param pkey: The public key.
1168 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001169
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001170 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001171 """
1172 if not isinstance(pkey, PKey):
1173 raise TypeError("pkey must be a PKey instance")
1174
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001175 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Alex Gaynor7778e792016-07-03 23:38:48 -04001176 _openssl_assert(set_result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001177
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001178 def sign(self, pkey, digest):
1179 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001180 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001181
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001182 :param pkey: The key to sign with.
1183 :type pkey: :py:class:`PKey`
1184
1185 :param digest: The name of the message digest to use.
1186 :type digest: :py:class:`bytes`
1187
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001188 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001189 """
1190 if not isinstance(pkey, PKey):
1191 raise TypeError("pkey must be a PKey instance")
1192
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001193 if pkey._only_public:
1194 raise ValueError("Key only has public part")
1195
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001196 if not pkey._initialized:
1197 raise ValueError("Key is uninitialized")
1198
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001199 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001200 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001201 raise ValueError("No such digest method")
1202
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001203 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -04001204 _openssl_assert(sign_result > 0)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001205
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001206 def get_signature_algorithm(self):
1207 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001208 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001209
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001210 :return: The name of the algorithm.
1211 :rtype: :py:class:`bytes`
1212
1213 :raises ValueError: If the signature algorithm is undefined.
1214
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001215 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001216 """
Alex Gaynor39ea5312016-06-02 09:12:10 -07001217 algor = _lib.X509_get0_tbs_sigalg(self._x509)
1218 nid = _lib.OBJ_obj2nid(algor.algorithm)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001219 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001220 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001221 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001222
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001223 def digest(self, digest_name):
1224 """
1225 Return the digest of the X509 object.
1226
1227 :param digest_name: The name of the digest algorithm to use.
1228 :type digest_name: :py:class:`bytes`
1229
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001230 :return: The digest of the object, formatted as
1231 :py:const:`b":"`-delimited hex pairs.
1232 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001233 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001234 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001235 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001236 raise ValueError("No such digest method")
1237
Paul Kehrer9f9113a2016-09-20 20:10:25 -05001238 result_buffer = _ffi.new("unsigned char[]", _lib.EVP_MAX_MD_SIZE)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001239 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001240 result_length[0] = len(result_buffer)
1241
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001242 digest_result = _lib.X509_digest(
Alex Gaynor03737182020-07-23 20:40:46 -04001243 self._x509, digest, result_buffer, result_length
1244 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04001245 _openssl_assert(digest_result == 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001246
Alex Gaynor03737182020-07-23 20:40:46 -04001247 return b":".join(
1248 [
1249 b16encode(ch).upper()
1250 for ch in _ffi.buffer(result_buffer, result_length[0])
1251 ]
1252 )
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001253
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001254 def subject_name_hash(self):
1255 """
1256 Return the hash of the X509 subject.
1257
1258 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001259 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001260 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001261 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001262
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001263 def set_serial_number(self, serial):
1264 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001265 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001266
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001267 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001268 :type serial: :py:class:`int`
1269
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001270 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001271 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001272 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001273 raise TypeError("serial must be an integer")
1274
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001275 hex_serial = hex(serial)[2:]
1276 if not isinstance(hex_serial, bytes):
Alex Gaynor03737182020-07-23 20:40:46 -04001277 hex_serial = hex_serial.encode("ascii")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001278
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001279 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001280
1281 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001282 # it. If bignum is still NULL after this call, then the return value
1283 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001284 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001285
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001286 if bignum_serial[0] == _ffi.NULL:
1287 set_result = _lib.ASN1_INTEGER_set(
Alex Gaynor03737182020-07-23 20:40:46 -04001288 _lib.X509_get_serialNumber(self._x509), small_serial
1289 )
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001290 if set_result:
1291 # TODO Not tested
1292 _raise_current_error()
1293 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001294 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1295 _lib.BN_free(bignum_serial[0])
1296 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001297 # TODO Not tested
1298 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001299 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1300 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Alex Gaynor37726112016-07-04 09:51:32 -04001301 _openssl_assert(set_result == 1)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001302
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001303 def get_serial_number(self):
1304 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001305 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001306
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001307 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001308 :rtype: int
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001309 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001310 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1311 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001312 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001313 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001314 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001315 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001316 serial = int(hexstring_serial, 16)
1317 return serial
1318 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001319 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001320 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001321 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001322
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001323 def gmtime_adj_notAfter(self, amount):
1324 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001325 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001326
Dan Sully44e767a2016-06-04 18:05:27 -07001327 :param int amount: The number of seconds by which to adjust the
1328 timestamp.
1329 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001330 """
1331 if not isinstance(amount, int):
1332 raise TypeError("amount must be an integer")
1333
Rosen Penev43a23a32020-08-13 12:07:12 -07001334 notAfter = _lib.X509_getm_notAfter(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001335 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001336
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001337 def gmtime_adj_notBefore(self, amount):
1338 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001339 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001340
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001341 :param amount: The number of seconds by which to adjust the timestamp.
Dan Sully44e767a2016-06-04 18:05:27 -07001342 :return: ``None``
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001343 """
1344 if not isinstance(amount, int):
1345 raise TypeError("amount must be an integer")
1346
Rosen Penev43a23a32020-08-13 12:07:12 -07001347 notBefore = _lib.X509_getm_notBefore(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001348 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001349
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001350 def has_expired(self):
1351 """
1352 Check whether the certificate has expired.
1353
Dan Sully44e767a2016-06-04 18:05:27 -07001354 :return: ``True`` if the certificate has expired, ``False`` otherwise.
1355 :rtype: bool
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001356 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001357 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001358 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001359
Paul Kehrerfde45c92016-01-21 12:57:37 -06001360 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001361
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001362 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001363 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001364
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001365 def get_notBefore(self):
1366 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001367 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001368
Paul Kehrerce98ee62017-06-21 06:59:58 -10001369 The timestamp is formatted as an ASN.1 TIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001370
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001371 YYYYMMDDhhmmssZ
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001372
Dan Sully44e767a2016-06-04 18:05:27 -07001373 :return: A timestamp string, or ``None`` if there is none.
1374 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001375 """
Rosen Penev43a23a32020-08-13 12:07:12 -07001376 return self._get_boundary_time(_lib.X509_getm_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001377
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001378 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001379 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001380
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001381 def set_notBefore(self, when):
1382 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001383 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001384
Paul Kehrerce98ee62017-06-21 06:59:58 -10001385 The timestamp is formatted as an ASN.1 TIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001386
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001387 YYYYMMDDhhmmssZ
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001388
Dan Sully44e767a2016-06-04 18:05:27 -07001389 :param bytes when: A timestamp string.
1390 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001391 """
Rosen Penev43a23a32020-08-13 12:07:12 -07001392 return self._set_boundary_time(_lib.X509_getm_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001393
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001394 def get_notAfter(self):
1395 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001396 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001397
Paul Kehrerce98ee62017-06-21 06:59:58 -10001398 The timestamp is formatted as an ASN.1 TIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001399
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001400 YYYYMMDDhhmmssZ
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001401
Dan Sully44e767a2016-06-04 18:05:27 -07001402 :return: A timestamp string, or ``None`` if there is none.
1403 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001404 """
Rosen Penev43a23a32020-08-13 12:07:12 -07001405 return self._get_boundary_time(_lib.X509_getm_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001406
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001407 def set_notAfter(self, when):
1408 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001409 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001410
Paul Kehrerce98ee62017-06-21 06:59:58 -10001411 The timestamp is formatted as an ASN.1 TIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001412
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001413 YYYYMMDDhhmmssZ
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001414
Dan Sully44e767a2016-06-04 18:05:27 -07001415 :param bytes when: A timestamp string.
1416 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001417 """
Rosen Penev43a23a32020-08-13 12:07:12 -07001418 return self._set_boundary_time(_lib.X509_getm_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001419
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001420 def _get_name(self, which):
1421 name = X509Name.__new__(X509Name)
1422 name._name = which(self._x509)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001423 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001424
1425 # The name is owned by the X509 structure. As long as the X509Name
1426 # Python object is alive, keep the X509 Python object alive.
1427 name._owner = self
1428
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001429 return name
1430
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001431 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001432 if not isinstance(name, X509Name):
1433 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001434 set_result = which(self._x509, name._name)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001435 _openssl_assert(set_result == 1)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001436
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001437 def get_issuer(self):
1438 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001439 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001440
Cory Benfielde6bcce82015-12-09 08:40:03 +00001441 This creates a new :class:`X509Name` that wraps the underlying issuer
1442 name field on the certificate. Modifying it will modify the underlying
1443 certificate, and will have the effect of modifying any other
1444 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001445
1446 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001447 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001448 """
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001449 name = self._get_name(_lib.X509_get_issuer_name)
1450 self._issuer_invalidator.add(name)
1451 return name
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001452
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001453 def set_issuer(self, issuer):
1454 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001455 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001456
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001457 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001458 :type issuer: :py:class:`X509Name`
1459
Dan Sully44e767a2016-06-04 18:05:27 -07001460 :return: ``None``
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001461 """
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001462 self._set_name(_lib.X509_set_issuer_name, issuer)
1463 self._issuer_invalidator.clear()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001464
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001465 def get_subject(self):
1466 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001467 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001468
Cory Benfielde6bcce82015-12-09 08:40:03 +00001469 This creates a new :class:`X509Name` that wraps the underlying subject
1470 name field on the certificate. Modifying it will modify the underlying
1471 certificate, and will have the effect of modifying any other
1472 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001473
1474 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001475 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001476 """
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001477 name = self._get_name(_lib.X509_get_subject_name)
1478 self._subject_invalidator.add(name)
1479 return name
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001480
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001481 def set_subject(self, subject):
1482 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001483 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001484
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001485 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001486 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001487
Dan Sully44e767a2016-06-04 18:05:27 -07001488 :return: ``None``
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001489 """
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001490 self._set_name(_lib.X509_set_subject_name, subject)
1491 self._subject_invalidator.clear()
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001492
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001493 def get_extension_count(self):
1494 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001495 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001496
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001497 :return: The number of extensions.
1498 :rtype: :py:class:`int`
1499
1500 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001501 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001502 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001503
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001504 def add_extensions(self, extensions):
1505 """
1506 Add extensions to the certificate.
1507
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001508 :param extensions: The extensions to add.
1509 :type extensions: An iterable of :py:class:`X509Extension` objects.
Dan Sully44e767a2016-06-04 18:05:27 -07001510 :return: ``None``
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001511 """
1512 for ext in extensions:
1513 if not isinstance(ext, X509Extension):
1514 raise ValueError("One of the elements is not an X509Extension")
1515
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001516 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001517 if not add_result:
1518 _raise_current_error()
1519
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001520 def get_extension(self, index):
1521 """
1522 Get a specific extension of the certificate by index.
1523
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001524 Extensions on a certificate are kept in order. The index
1525 parameter selects which extension will be returned.
1526
1527 :param int index: The index of the extension to retrieve.
1528 :return: The extension at the specified index.
1529 :rtype: :py:class:`X509Extension`
1530 :raises IndexError: If the extension index was out of bounds.
1531
1532 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001533 """
1534 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001535 ext._extension = _lib.X509_get_ext(self._x509, index)
1536 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001537 raise IndexError("extension index out of bounds")
1538
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001539 extension = _lib.X509_EXTENSION_dup(ext._extension)
1540 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001541 return ext
1542
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001543
Dan Sully44e767a2016-06-04 18:05:27 -07001544class X509StoreFlags(object):
1545 """
1546 Flags for X509 verification, used to change the behavior of
1547 :class:`X509Store`.
1548
1549 See `OpenSSL Verification Flags`_ for details.
1550
1551 .. _OpenSSL Verification Flags:
Alex Chan54005ce2017-03-21 08:08:17 +00001552 https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_flags.html
Dan Sully44e767a2016-06-04 18:05:27 -07001553 """
Alex Gaynor03737182020-07-23 20:40:46 -04001554
Dan Sully44e767a2016-06-04 18:05:27 -07001555 CRL_CHECK = _lib.X509_V_FLAG_CRL_CHECK
1556 CRL_CHECK_ALL = _lib.X509_V_FLAG_CRL_CHECK_ALL
1557 IGNORE_CRITICAL = _lib.X509_V_FLAG_IGNORE_CRITICAL
1558 X509_STRICT = _lib.X509_V_FLAG_X509_STRICT
1559 ALLOW_PROXY_CERTS = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS
1560 POLICY_CHECK = _lib.X509_V_FLAG_POLICY_CHECK
1561 EXPLICIT_POLICY = _lib.X509_V_FLAG_EXPLICIT_POLICY
1562 INHIBIT_MAP = _lib.X509_V_FLAG_INHIBIT_MAP
1563 NOTIFY_POLICY = _lib.X509_V_FLAG_NOTIFY_POLICY
1564 CHECK_SS_SIGNATURE = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE
1565 CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK
1566
1567
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001568class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001569 """
Dan Sully44e767a2016-06-04 18:05:27 -07001570 An X.509 store.
1571
1572 An X.509 store is used to describe a context in which to verify a
1573 certificate. A description of a context may include a set of certificates
1574 to trust, a set of certificate revocation lists, verification flags and
1575 more.
1576
1577 An X.509 store, being only a description, cannot be used by itself to
1578 verify a certificate. To carry out the actual verification process, see
1579 :class:`X509StoreContext`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001580 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001581
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001582 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001583 store = _lib.X509_STORE_new()
1584 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001585
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001586 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001587 """
Dan Sully44e767a2016-06-04 18:05:27 -07001588 Adds a trusted certificate to this store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001589
Dan Sully44e767a2016-06-04 18:05:27 -07001590 Adding a certificate with this method adds this certificate as a
1591 *trusted* certificate.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001592
1593 :param X509 cert: The certificate to add to this store.
Hynek Schlawack01c31672016-12-11 15:14:09 +01001594
Dan Sully44e767a2016-06-04 18:05:27 -07001595 :raises TypeError: If the certificate is not an :class:`X509`.
Hynek Schlawack01c31672016-12-11 15:14:09 +01001596
1597 :raises OpenSSL.crypto.Error: If OpenSSL was unhappy with your
1598 certificate.
1599
Dan Sully44e767a2016-06-04 18:05:27 -07001600 :return: ``None`` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001601 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001602 if not isinstance(cert, X509):
1603 raise TypeError()
1604
Paul Kehrer0e6c5532018-08-23 10:52:15 -05001605 # As of OpenSSL 1.1.0i adding the same cert to the store more than
1606 # once doesn't cause an error. Accordingly, this code now silences
1607 # the error for OpenSSL < 1.1.0i as well.
1608 if _lib.X509_STORE_add_cert(self._store, cert._x509) == 0:
1609 code = _lib.ERR_peek_error()
1610 err_reason = _lib.ERR_GET_REASON(code)
1611 _openssl_assert(
1612 err_reason == _lib.X509_R_CERT_ALREADY_IN_HASH_TABLE
1613 )
1614 _lib.ERR_clear_error()
Dan Sully44e767a2016-06-04 18:05:27 -07001615
1616 def add_crl(self, crl):
1617 """
1618 Add a certificate revocation list to this store.
1619
1620 The certificate revocation lists added to a store will only be used if
1621 the associated flags are configured to check certificate revocation
1622 lists.
1623
1624 .. versionadded:: 16.1.0
1625
1626 :param CRL crl: The certificate revocation list to add to this store.
1627 :return: ``None`` if the certificate revocation list was added
1628 successfully.
1629 """
1630 _openssl_assert(_lib.X509_STORE_add_crl(self._store, crl._crl) != 0)
1631
1632 def set_flags(self, flags):
1633 """
1634 Set verification flags to this store.
1635
1636 Verification flags can be combined by oring them together.
1637
1638 .. note::
1639
1640 Setting a verification flag sometimes requires clients to add
1641 additional information to the store, otherwise a suitable error will
1642 be raised.
1643
1644 For example, in setting flags to enable CRL checking a
1645 suitable CRL must be added to the store otherwise an error will be
1646 raised.
1647
1648 .. versionadded:: 16.1.0
1649
1650 :param int flags: The verification flags to set on this store.
1651 See :class:`X509StoreFlags` for available constants.
1652 :return: ``None`` if the verification flags were successfully set.
1653 """
1654 _openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0)
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001655
Thomas Sileoe15e60a2016-11-22 18:13:30 +01001656 def set_time(self, vfy_time):
1657 """
1658 Set the time against which the certificates are verified.
1659
1660 Normally the current time is used.
1661
1662 .. note::
1663
1664 For example, you can determine if a certificate was valid at a given
1665 time.
1666
Hynek Schlawackf6c96af2017-04-20 12:34:58 +02001667 .. versionadded:: 17.0.0
Thomas Sileoe15e60a2016-11-22 18:13:30 +01001668
1669 :param datetime vfy_time: The verification time to set on this store.
1670 :return: ``None`` if the verification time was successfully set.
1671 """
1672 param = _lib.X509_VERIFY_PARAM_new()
1673 param = _ffi.gc(param, _lib.X509_VERIFY_PARAM_free)
1674
Alex Gaynor03737182020-07-23 20:40:46 -04001675 _lib.X509_VERIFY_PARAM_set_time(param, int(vfy_time.strftime("%s")))
Thomas Sileoe15e60a2016-11-22 18:13:30 +01001676 _openssl_assert(_lib.X509_STORE_set1_param(self._store, param) != 0)
1677
Sándor Oroszi43c97762020-09-11 17:17:31 +02001678 def load_locations(self, cafile, capath=None):
1679 """
1680 Let X509Store know where we can find trusted certificates for the
1681 certificate chain. Note that the certificates have to be in PEM
1682 format.
1683
1684 If *capath* is passed, it must be a directory prepared using the
1685 ``c_rehash`` tool included with OpenSSL. Either, but not both, of
1686 *cafile* or *capath* may be ``None``.
1687
1688 .. note::
1689
1690 Both *cafile* and *capath* may be set simultaneously.
1691
1692 Call this method multiple times to add more than one location.
1693 For example, CA certificates, and certificate revocation list bundles
1694 may be passed in *cafile* in subsequent calls to this method.
1695
1696 .. versionadded:: 20.0
1697
1698 :param cafile: In which file we can find the certificates (``bytes`` or
1699 ``unicode``).
1700 :param capath: In which directory we can find the certificates
1701 (``bytes`` or ``unicode``).
1702
1703 :return: ``None`` if the locations were set successfully.
1704
1705 :raises OpenSSL.crypto.Error: If both *cafile* and *capath* is ``None``
1706 or the locations could not be set for any reason.
1707
1708 """
1709 if cafile is None:
1710 cafile = _ffi.NULL
1711 else:
1712 cafile = _path_string(cafile)
1713
1714 if capath is None:
1715 capath = _ffi.NULL
1716 else:
1717 capath = _path_string(capath)
1718
1719 load_result = _lib.X509_STORE_load_locations(
1720 self._store, cafile, capath
1721 )
1722 if not load_result:
1723 _raise_current_error()
1724
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001725
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001726class X509StoreContextError(Exception):
1727 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001728 An exception raised when an error occurred while verifying a certificate
1729 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001730
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001731 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001732 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001733 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001734
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001735 def __init__(self, message, certificate):
1736 super(X509StoreContextError, self).__init__(message)
1737 self.certificate = certificate
1738
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001739
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001740class X509StoreContext(object):
1741 """
1742 An X.509 store context.
1743
Dan Sully44e767a2016-06-04 18:05:27 -07001744 An X.509 store context is used to carry out the actual verification process
1745 of a certificate in a described context. For describing such a context, see
1746 :class:`X509Store`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001747
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001748 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1749 instance. It is dynamically allocated and automatically garbage
1750 collected.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001751 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001752 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Sándor Oroszi83ef2302020-10-12 15:42:23 +02001753 :ivar _chain: See the ``chain`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001754 :param X509Store store: The certificates which will be trusted for the
1755 purposes of any verifications.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001756 :param X509 certificate: The certificate to be verified.
Sándor Oroszi83ef2302020-10-12 15:42:23 +02001757 :param chain: List of untrusted certificates that may be used for building
1758 the certificate chain. May be ``None``.
1759 :type chain: :class:`list` of :class:`X509`
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001760 """
1761
Sándor Oroszi83ef2302020-10-12 15:42:23 +02001762 def __init__(self, store, certificate, chain=None):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001763 store_ctx = _lib.X509_STORE_CTX_new()
1764 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1765 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001766 self._cert = certificate
Sándor Oroszi83ef2302020-10-12 15:42:23 +02001767 self._chain = self._build_certificate_stack(chain)
Stephen Holsapple46a09252015-02-12 14:45:43 -08001768 # Make the store context available for use after instantiating this
1769 # class by initializing it now. Per testing, subsequent calls to
Dan Sully44e767a2016-06-04 18:05:27 -07001770 # :meth:`_init` have no adverse affect.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001771 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001772
Sándor Oroszi83ef2302020-10-12 15:42:23 +02001773 @staticmethod
1774 def _build_certificate_stack(certificates):
1775 def cleanup(s):
1776 # Equivalent to sk_X509_pop_free, but we don't
1777 # currently have a CFFI binding for that available
1778 for i in range(_lib.sk_X509_num(s)):
1779 x = _lib.sk_X509_value(s, i)
1780 _lib.X509_free(x)
1781 _lib.sk_X509_free(s)
1782
1783 if certificates is None or len(certificates) == 0:
1784 return _ffi.NULL
1785
1786 stack = _lib.sk_X509_new_null()
1787 _openssl_assert(stack != _ffi.NULL)
1788 stack = _ffi.gc(stack, cleanup)
1789
1790 for cert in certificates:
1791 if not isinstance(cert, X509):
1792 raise TypeError("One of the elements is not an X509 instance")
1793
1794 _openssl_assert(_lib.X509_up_ref(cert._x509) > 0)
1795 if _lib.sk_X509_push(stack, cert._x509) <= 0:
1796 _lib.X509_free(cert._x509)
1797 _raise_current_error()
1798
1799 return stack
1800
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001801 def _init(self):
1802 """
1803 Set up the store context for a subsequent verification operation.
Jeremy Cline58193f12017-09-13 21:14:53 -04001804
1805 Calling this method more than once without first calling
1806 :meth:`_cleanup` will leak memory.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001807 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001808 ret = _lib.X509_STORE_CTX_init(
Shane Harvey33c54992020-08-05 16:48:51 -07001809 self._store_ctx, self._store._store, self._cert._x509, self._chain
Alex Gaynor5945ea82015-09-05 14:59:06 -04001810 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001811 if ret <= 0:
1812 _raise_current_error()
1813
1814 def _cleanup(self):
1815 """
1816 Internally cleans up the store context.
1817
Dan Sully44e767a2016-06-04 18:05:27 -07001818 The store context can then be reused with a new call to :meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001819 """
1820 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1821
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001822 def _exception_from_context(self):
1823 """
1824 Convert an OpenSSL native context error failure into a Python
1825 exception.
1826
Alex Gaynor5945ea82015-09-05 14:59:06 -04001827 When a call to native OpenSSL X509_verify_cert fails, additional
1828 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001829 """
1830 errors = [
1831 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1832 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
Alex Gaynor03737182020-07-23 20:40:46 -04001833 _native(
1834 _ffi.string(
1835 _lib.X509_verify_cert_error_string(
1836 _lib.X509_STORE_CTX_get_error(self._store_ctx)
1837 )
1838 )
1839 ),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001840 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001841 # A context error should always be associated with a certificate, so we
1842 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001843 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001844 _cert = _lib.X509_dup(_x509)
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001845 pycert = X509._from_raw_x509_ptr(_cert)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001846 return X509StoreContextError(errors, pycert)
1847
Stephen Holsapple46a09252015-02-12 14:45:43 -08001848 def set_store(self, store):
1849 """
Dan Sully44e767a2016-06-04 18:05:27 -07001850 Set the context's X.509 store.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001851
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001852 .. versionadded:: 0.15
1853
Dan Sully44e767a2016-06-04 18:05:27 -07001854 :param X509Store store: The store description which will be used for
1855 the purposes of any *future* verifications.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001856 """
1857 self._store = store
1858
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001859 def verify_certificate(self):
1860 """
1861 Verify a certificate in a context.
1862
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001863 .. versionadded:: 0.15
1864
Alex Gaynorca87ff62015-09-04 23:31:03 -04001865 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001866 certificate in the context. Sets ``certificate`` attribute to
1867 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001868 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001869 # Always re-initialize the store context in case
Dan Sully44e767a2016-06-04 18:05:27 -07001870 # :meth:`verify_certificate` is called multiple times.
Jeremy Cline58193f12017-09-13 21:14:53 -04001871 #
1872 # :meth:`_init` is called in :meth:`__init__` so _cleanup is called
1873 # before _init to ensure memory is not leaked.
1874 self._cleanup()
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001875 self._init()
1876 ret = _lib.X509_verify_cert(self._store_ctx)
1877 self._cleanup()
1878 if ret <= 0:
1879 raise self._exception_from_context()
1880
Shane Harvey33c54992020-08-05 16:48:51 -07001881 def get_verified_chain(self):
1882 """
1883 Verify a certificate in a context and return the complete validated
1884 chain.
1885
1886 :raises X509StoreContextError: If an error occurred when validating a
1887 certificate in the context. Sets ``certificate`` attribute to
1888 indicate which certificate caused the error.
1889
1890 .. versionadded:: 20.0
1891 """
1892 # Always re-initialize the store context in case
1893 # :meth:`verify_certificate` is called multiple times.
1894 #
1895 # :meth:`_init` is called in :meth:`__init__` so _cleanup is called
1896 # before _init to ensure memory is not leaked.
1897 self._cleanup()
1898 self._init()
1899 ret = _lib.X509_verify_cert(self._store_ctx)
1900 if ret <= 0:
1901 self._cleanup()
1902 raise self._exception_from_context()
1903
1904 # Note: X509_STORE_CTX_get1_chain returns a deep copy of the chain.
1905 cert_stack = _lib.X509_STORE_CTX_get1_chain(self._store_ctx)
1906 _openssl_assert(cert_stack != _ffi.NULL)
1907
1908 result = []
1909 for i in range(_lib.sk_X509_num(cert_stack)):
1910 cert = _lib.sk_X509_value(cert_stack, i)
1911 _openssl_assert(cert != _ffi.NULL)
1912 pycert = X509._from_raw_x509_ptr(cert)
1913 result.append(pycert)
1914
1915 # Free the stack but not the members which are freed by the X509 class.
1916 _lib.sk_X509_free(cert_stack)
1917 self._cleanup()
1918 return result
1919
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001920
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001921def load_certificate(type, buffer):
1922 """
Alex Chand072cae2018-02-15 09:57:59 +00001923 Load a certificate (X509) from the string *buffer* encoded with the
1924 type *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001925
1926 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1927
Dan Sully44e767a2016-06-04 18:05:27 -07001928 :param bytes buffer: The buffer the certificate is stored in
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001929
1930 :return: The X509 object
1931 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001932 if isinstance(buffer, _text_type):
1933 buffer = buffer.encode("ascii")
1934
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001935 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001936
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001937 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001938 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001939 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001940 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001941 else:
Alex Gaynor03737182020-07-23 20:40:46 -04001942 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001943
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001944 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001945 _raise_current_error()
1946
Alex Gaynor4aa52c32017-11-20 09:04:08 -05001947 return X509._from_raw_x509_ptr(x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001948
1949
1950def dump_certificate(type, cert):
1951 """
Alex Chand072cae2018-02-15 09:57:59 +00001952 Dump the certificate *cert* into a buffer string encoded with the type
1953 *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001954
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001955 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1956 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001957 :param cert: The certificate to dump
1958 :return: The buffer with the dumped certificate in
1959 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001960 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001961
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001962 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001963 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001964 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001965 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001966 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001967 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001968 else:
1969 raise ValueError(
1970 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
Alex Gaynor03737182020-07-23 20:40:46 -04001971 "FILETYPE_TEXT"
1972 )
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001973
Adrián Chaves98c57be2020-03-31 16:14:50 +02001974 _openssl_assert(result_code == 1)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001975 return _bio_to_string(bio)
1976
1977
Cory Benfield6492f7c2015-10-27 16:57:58 +09001978def dump_publickey(type, pkey):
1979 """
Cory Benfield11c10192015-10-27 17:23:03 +09001980 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001981
Cory Benfield9c590b92015-10-28 14:55:05 +09001982 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001983 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001984 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001985 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001986 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001987 """
1988 bio = _new_mem_buf()
1989 if type == FILETYPE_PEM:
1990 write_bio = _lib.PEM_write_bio_PUBKEY
1991 elif type == FILETYPE_ASN1:
1992 write_bio = _lib.i2d_PUBKEY_bio
1993 else:
1994 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1995
1996 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001997 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001998 _raise_current_error()
1999
2000 return _bio_to_string(bio)
2001
2002
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002003def dump_privatekey(type, pkey, cipher=None, passphrase=None):
2004 """
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02002005 Dump the private key *pkey* into a buffer string encoded with the type
2006 *type*. Optionally (if *type* is :const:`FILETYPE_PEM`) encrypting it
2007 using *cipher* and *passphrase*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002008
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02002009 :param type: The file type (one of :const:`FILETYPE_PEM`,
2010 :const:`FILETYPE_ASN1`, or :const:`FILETYPE_TEXT`)
2011 :param PKey pkey: The PKey to dump
2012 :param cipher: (optional) if encrypted PEM format, the cipher to use
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002013 :param passphrase: (optional) if encrypted PEM format, this can be either
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02002014 the passphrase to use, or a callback for providing the passphrase.
2015
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002016 :return: The buffer with the dumped key in
Dan Sully44e767a2016-06-04 18:05:27 -07002017 :rtype: bytes
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002018 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002019 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002020
Paul Kehrercded9932017-06-29 18:43:42 -05002021 if not isinstance(pkey, PKey):
2022 raise TypeError("pkey must be a PKey")
2023
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002024 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002025 if passphrase is None:
2026 raise TypeError(
2027 "if a value is given for cipher "
Alex Gaynor03737182020-07-23 20:40:46 -04002028 "one must also be given for passphrase"
2029 )
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002030 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002031 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002032 raise ValueError("Invalid cipher name")
2033 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002034 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002035
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002036 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002037 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002038 result_code = _lib.PEM_write_bio_PrivateKey(
Alex Gaynor03737182020-07-23 20:40:46 -04002039 bio,
2040 pkey._pkey,
2041 cipher_obj,
2042 _ffi.NULL,
2043 0,
2044 helper.callback,
2045 helper.callback_args,
2046 )
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002047 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002048 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002049 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002050 elif type == FILETYPE_TEXT:
Paul Kehrercded9932017-06-29 18:43:42 -05002051 if _lib.EVP_PKEY_id(pkey._pkey) != _lib.EVP_PKEY_RSA:
2052 raise TypeError("Only RSA keys are supported for FILETYPE_TEXT")
2053
Alex Gaynor03737182020-07-23 20:40:46 -04002054 rsa = _ffi.gc(_lib.EVP_PKEY_get1_RSA(pkey._pkey), _lib.RSA_free)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002055 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002056 else:
2057 raise ValueError(
2058 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
Alex Gaynor03737182020-07-23 20:40:46 -04002059 "FILETYPE_TEXT"
2060 )
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002061
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02002062 _openssl_assert(result_code != 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002063
2064 return _bio_to_string(bio)
2065
2066
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002067class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002068 """
2069 A certificate revocation.
2070 """
Alex Gaynor03737182020-07-23 20:40:46 -04002071
Cyril Stoller37e60222018-08-27 13:38:10 +02002072 # https://www.openssl.org/docs/manmaster/man5/x509v3_config.html#CRL-distribution-points
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002073 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
2074 # OCSP_crl_reason_str. We use the latter, just like the command line
2075 # program.
2076 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002077 b"unspecified",
2078 b"keyCompromise",
2079 b"CACompromise",
2080 b"affiliationChanged",
2081 b"superseded",
2082 b"cessationOfOperation",
2083 b"certificateHold",
2084 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04002085 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002086
2087 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002088 revoked = _lib.X509_REVOKED_new()
2089 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002090
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002091 def set_serial(self, hex_str):
2092 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002093 Set the serial number.
2094
2095 The serial number is formatted as a hexadecimal number encoded in
2096 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002097
Dan Sully44e767a2016-06-04 18:05:27 -07002098 :param bytes hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002099
Dan Sully44e767a2016-06-04 18:05:27 -07002100 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002101 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002102 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
2103 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08002104 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002105 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002106 if not bn_result:
2107 raise ValueError("bad hex string")
2108
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002109 asn1_serial = _ffi.gc(
2110 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
Alex Gaynor03737182020-07-23 20:40:46 -04002111 _lib.ASN1_INTEGER_free,
2112 )
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002113 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002114
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002115 def get_serial(self):
2116 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002117 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002118
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002119 The serial number is formatted as a hexadecimal number encoded in
2120 ASCII.
2121
2122 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07002123 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002124 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08002125 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002126
Alex Gaynor67903a62016-06-02 10:37:13 -07002127 asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked)
2128 _openssl_assert(asn1_int != _ffi.NULL)
2129 result = _lib.i2a_ASN1_INTEGER(bio, asn1_int)
2130 _openssl_assert(result >= 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002131 return _bio_to_string(bio)
2132
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002133 def _delete_reason(self):
Alex Gaynor67903a62016-06-02 10:37:13 -07002134 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
2135 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04002136 obj = _lib.X509_EXTENSION_get_object(ext)
2137 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002138 _lib.X509_EXTENSION_free(ext)
Alex Gaynor67903a62016-06-02 10:37:13 -07002139 _lib.X509_REVOKED_delete_ext(self._revoked, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002140 break
2141
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002142 def set_reason(self, reason):
2143 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002144 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002145
Dan Sully44e767a2016-06-04 18:05:27 -07002146 If :data:`reason` is ``None``, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002147
2148 :param reason: The reason string.
Dan Sully44e767a2016-06-04 18:05:27 -07002149 :type reason: :class:`bytes` or :class:`NoneType`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002150
Dan Sully44e767a2016-06-04 18:05:27 -07002151 :return: ``None``
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002152
2153 .. seealso::
2154
Dan Sully44e767a2016-06-04 18:05:27 -07002155 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002156 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002157 """
2158 if reason is None:
2159 self._delete_reason()
2160 elif not isinstance(reason, bytes):
2161 raise TypeError("reason must be None or a byte string")
2162 else:
Alex Gaynor03737182020-07-23 20:40:46 -04002163 reason = reason.lower().replace(b" ", b"")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002164 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
2165
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002166 new_reason_ext = _lib.ASN1_ENUMERATED_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07002167 _openssl_assert(new_reason_ext != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002168 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002169
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002170 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002171 _openssl_assert(set_result != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002172
2173 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002174 add_result = _lib.X509_REVOKED_add1_ext_i2d(
Alex Gaynor03737182020-07-23 20:40:46 -04002175 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0
2176 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04002177 _openssl_assert(add_result == 1)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002178
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002179 def get_reason(self):
2180 """
Alex Gaynor80262fb2016-04-22 07:53:42 -04002181 Get the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002182
Dan Sully44e767a2016-06-04 18:05:27 -07002183 :return: The reason, or ``None`` if there is none.
2184 :rtype: bytes or NoneType
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002185
2186 .. seealso::
2187
Dan Sully44e767a2016-06-04 18:05:27 -07002188 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002189 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002190 """
Alex Gaynor67903a62016-06-02 10:37:13 -07002191 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
2192 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04002193 obj = _lib.X509_EXTENSION_get_object(ext)
2194 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08002195 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002196
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002197 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002198 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002199 print_result = _lib.M_ASN1_OCTET_STRING_print(
Paul Kehrere8f91cc2016-03-09 21:26:29 -04002200 bio, _lib.X509_EXTENSION_get_data(ext)
Alex Gaynor5945ea82015-09-05 14:59:06 -04002201 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04002202 _openssl_assert(print_result != 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002203
2204 return _bio_to_string(bio)
2205
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002206 def all_reasons(self):
2207 """
2208 Return a list of all the supported reason strings.
2209
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002210 This list is a copy; modifying it does not change the supported reason
2211 strings.
2212
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002213 :return: A list of reason strings.
Dan Sully44e767a2016-06-04 18:05:27 -07002214 :rtype: :class:`list` of :class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002215 """
2216 return self._crl_reasons[:]
2217
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002218 def set_rev_date(self, when):
2219 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002220 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002221
Dan Sully44e767a2016-06-04 18:05:27 -07002222 :param bytes when: The timestamp of the revocation,
Paul Kehrerce98ee62017-06-21 06:59:58 -10002223 as ASN.1 TIME.
Dan Sully44e767a2016-06-04 18:05:27 -07002224 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002225 """
Alex Gaynor67903a62016-06-02 10:37:13 -07002226 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
2227 return _set_asn1_time(dt, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002228
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002229 def get_rev_date(self):
2230 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02002231 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002232
Paul Kehrerce98ee62017-06-21 06:59:58 -10002233 :return: The timestamp of the revocation, as ASN.1 TIME.
Dan Sully44e767a2016-06-04 18:05:27 -07002234 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002235 """
Alex Gaynor67903a62016-06-02 10:37:13 -07002236 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
2237 return _get_asn1_time(dt)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002238
2239
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002240class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002241 """
2242 A certificate revocation list.
2243 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002244
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002245 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002246 crl = _lib.X509_CRL_new()
2247 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002248
Paul Kehrer41c10242017-06-29 18:24:17 -05002249 def to_cryptography(self):
2250 """
2251 Export as a ``cryptography`` CRL.
2252
2253 :rtype: ``cryptography.x509.CertificateRevocationList``
2254
2255 .. versionadded:: 17.1.0
2256 """
2257 from cryptography.hazmat.backends.openssl.x509 import (
Alex Gaynor03737182020-07-23 20:40:46 -04002258 _CertificateRevocationList,
Paul Kehrer41c10242017-06-29 18:24:17 -05002259 )
Alex Gaynor03737182020-07-23 20:40:46 -04002260
Paul Kehrer41c10242017-06-29 18:24:17 -05002261 backend = _get_backend()
2262 return _CertificateRevocationList(backend, self._crl)
2263
2264 @classmethod
2265 def from_cryptography(cls, crypto_crl):
2266 """
2267 Construct based on a ``cryptography`` *crypto_crl*.
2268
2269 :param crypto_crl: A ``cryptography`` certificate revocation list
2270 :type crypto_crl: ``cryptography.x509.CertificateRevocationList``
2271
2272 :rtype: CRL
2273
2274 .. versionadded:: 17.1.0
2275 """
2276 if not isinstance(crypto_crl, x509.CertificateRevocationList):
2277 raise TypeError("Must be a certificate revocation list")
2278
2279 crl = cls()
2280 crl._crl = crypto_crl._x509_crl
2281 return crl
2282
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002283 def get_revoked(self):
2284 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002285 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002286
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002287 These revocations will be provided by value, not by reference.
2288 That means it's okay to mutate them: it won't affect this CRL.
2289
2290 :return: The revocations in this CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07002291 :rtype: :class:`tuple` of :class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002292 """
2293 results = []
Alex Gaynor67903a62016-06-02 10:37:13 -07002294 revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002295 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
2296 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Paul Kehrer2fe23b02016-03-09 22:02:15 -04002297 revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002298 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002299 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002300 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002301 if results:
2302 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002303
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002304 def add_revoked(self, revoked):
2305 """
2306 Add a revoked (by value not reference) to the CRL structure
2307
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02002308 This revocation will be added by value, not by reference. That
2309 means it's okay to mutate it after adding: it won't affect
2310 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002311
Dan Sully44e767a2016-06-04 18:05:27 -07002312 :param Revoked revoked: The new revocation.
2313 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002314 """
Paul Kehrer8dddb1a2016-03-09 21:48:04 -04002315 copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002316 _openssl_assert(copy != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002317
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002318 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Alex Gaynor09a386e2016-07-03 09:32:44 -04002319 _openssl_assert(add_result != 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002320
Dan Sully44e767a2016-06-04 18:05:27 -07002321 def get_issuer(self):
2322 """
2323 Get the CRL's issuer.
2324
2325 .. versionadded:: 16.1.0
2326
2327 :rtype: X509Name
2328 """
2329 _issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl))
2330 _openssl_assert(_issuer != _ffi.NULL)
2331 _issuer = _ffi.gc(_issuer, _lib.X509_NAME_free)
2332 issuer = X509Name.__new__(X509Name)
2333 issuer._name = _issuer
2334 return issuer
2335
2336 def set_version(self, version):
2337 """
2338 Set the CRL version.
2339
2340 .. versionadded:: 16.1.0
2341
2342 :param int version: The version of the CRL.
2343 :return: ``None``
2344 """
2345 _openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0)
2346
2347 def _set_boundary_time(self, which, when):
2348 return _set_asn1_time(which(self._crl), when)
2349
2350 def set_lastUpdate(self, when):
2351 """
2352 Set when the CRL was last updated.
2353
Paul Kehrerce98ee62017-06-21 06:59:58 -10002354 The timestamp is formatted as an ASN.1 TIME::
Dan Sully44e767a2016-06-04 18:05:27 -07002355
2356 YYYYMMDDhhmmssZ
Dan Sully44e767a2016-06-04 18:05:27 -07002357
2358 .. versionadded:: 16.1.0
2359
2360 :param bytes when: A timestamp string.
2361 :return: ``None``
2362 """
2363 return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when)
2364
2365 def set_nextUpdate(self, when):
2366 """
Felix Yan3db93f12020-10-15 03:41:20 +08002367 Set when the CRL will next be updated.
Dan Sully44e767a2016-06-04 18:05:27 -07002368
Paul Kehrerce98ee62017-06-21 06:59:58 -10002369 The timestamp is formatted as an ASN.1 TIME::
Dan Sully44e767a2016-06-04 18:05:27 -07002370
2371 YYYYMMDDhhmmssZ
Dan Sully44e767a2016-06-04 18:05:27 -07002372
2373 .. versionadded:: 16.1.0
2374
2375 :param bytes when: A timestamp string.
2376 :return: ``None``
2377 """
2378 return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when)
2379
2380 def sign(self, issuer_cert, issuer_key, digest):
2381 """
2382 Sign the CRL.
2383
2384 Signing a CRL enables clients to associate the CRL itself with an
2385 issuer. Before a CRL is meaningful to other OpenSSL functions, it must
2386 be signed by an issuer.
2387
2388 This method implicitly sets the issuer's name based on the issuer
2389 certificate and private key used to sign the CRL.
2390
2391 .. versionadded:: 16.1.0
2392
2393 :param X509 issuer_cert: The issuer's certificate.
2394 :param PKey issuer_key: The issuer's private key.
2395 :param bytes digest: The digest method to sign the CRL with.
2396 """
2397 digest_obj = _lib.EVP_get_digestbyname(digest)
2398 _openssl_assert(digest_obj != _ffi.NULL)
2399 _lib.X509_CRL_set_issuer_name(
Alex Gaynor03737182020-07-23 20:40:46 -04002400 self._crl, _lib.X509_get_subject_name(issuer_cert._x509)
2401 )
Dan Sully44e767a2016-06-04 18:05:27 -07002402 _lib.X509_CRL_sort(self._crl)
2403 result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj)
2404 _openssl_assert(result != 0)
2405
Alex Gaynor03737182020-07-23 20:40:46 -04002406 def export(
2407 self, cert, key, type=FILETYPE_PEM, days=100, digest=_UNSPECIFIED
2408 ):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002409 """
Dan Sully44e767a2016-06-04 18:05:27 -07002410 Export the CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002411
Dan Sully44e767a2016-06-04 18:05:27 -07002412 :param X509 cert: The certificate used to sign the CRL.
2413 :param PKey key: The key used to sign the CRL.
2414 :param int type: The export format, either :data:`FILETYPE_PEM`,
2415 :data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`.
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002416 :param int days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002417 :param bytes digest: The name of the message digest to use (eg
Wayne Werner80dcf382019-01-30 15:03:16 -06002418 ``b"sha256"``).
Dan Sully44e767a2016-06-04 18:05:27 -07002419 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002420 """
Dan Sully44e767a2016-06-04 18:05:27 -07002421
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002422 if not isinstance(cert, X509):
2423 raise TypeError("cert must be an X509 instance")
2424 if not isinstance(key, PKey):
2425 raise TypeError("key must be a PKey instance")
2426 if not isinstance(type, int):
2427 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002428
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002429 if digest is _UNSPECIFIED:
Alex Gaynor173e4ba2017-06-30 08:01:12 -07002430 raise TypeError("digest must be provided")
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002431
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002432 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002433 if digest_obj == _ffi.NULL:
2434 raise ValueError("No such digest method")
2435
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002436 bio = _lib.BIO_new(_lib.BIO_s_mem())
Alex Gaynoradd5b072016-06-04 21:04:00 -07002437 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002438
Alex Gaynora738ed52015-09-05 11:17:10 -04002439 # A scratch time object to give different values to different CRL
2440 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002441 sometime = _lib.ASN1_TIME_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07002442 _openssl_assert(sometime != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002443
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002444 _lib.X509_gmtime_adj(sometime, 0)
2445 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002446
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002447 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2448 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002449
Alex Gaynor5945ea82015-09-05 14:59:06 -04002450 _lib.X509_CRL_set_issuer_name(
2451 self._crl, _lib.X509_get_subject_name(cert._x509)
2452 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002453
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002454 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002455 if not sign_result:
2456 _raise_current_error()
2457
Dominic Chenf05b2122015-10-13 16:32:35 +00002458 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002459
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002460
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002461class PKCS7(object):
2462 def type_is_signed(self):
2463 """
2464 Check if this NID_pkcs7_signed object
2465
2466 :return: True if the PKCS7 is of type signed
2467 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002468 return bool(_lib.PKCS7_type_is_signed(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002469
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002470 def type_is_enveloped(self):
2471 """
2472 Check if this NID_pkcs7_enveloped object
2473
2474 :returns: True if the PKCS7 is of type enveloped
2475 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002476 return bool(_lib.PKCS7_type_is_enveloped(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002477
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002478 def type_is_signedAndEnveloped(self):
2479 """
2480 Check if this NID_pkcs7_signedAndEnveloped object
2481
2482 :returns: True if the PKCS7 is of type signedAndEnveloped
2483 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002484 return bool(_lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002485
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002486 def type_is_data(self):
2487 """
2488 Check if this NID_pkcs7_data object
2489
2490 :return: True if the PKCS7 is of type data
2491 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002492 return bool(_lib.PKCS7_type_is_data(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002493
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002494 def get_type_name(self):
2495 """
2496 Returns the type name of the PKCS7 structure
2497
2498 :return: A string with the typename
2499 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002500 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2501 string_type = _lib.OBJ_nid2sn(nid)
2502 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002503
Alex Chanc6077062016-11-18 13:53:39 +00002504
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002505class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002506 """
2507 A PKCS #12 archive.
2508 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002509
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002510 def __init__(self):
2511 self._pkey = None
2512 self._cert = None
2513 self._cacerts = None
2514 self._friendlyname = None
2515
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002516 def get_certificate(self):
2517 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002518 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002519
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002520 :return: The certificate, or :py:const:`None` if there is none.
2521 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002522 """
2523 return self._cert
2524
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002525 def set_certificate(self, cert):
2526 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002527 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002528
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002529 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002530 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002531
Dan Sully44e767a2016-06-04 18:05:27 -07002532 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002533 """
2534 if not isinstance(cert, X509):
2535 raise TypeError("cert must be an X509 instance")
2536 self._cert = cert
2537
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002538 def get_privatekey(self):
2539 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002540 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002541
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002542 :return: The private key, or :py:const:`None` if there is none.
2543 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002544 """
2545 return self._pkey
2546
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002547 def set_privatekey(self, pkey):
2548 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002549 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002550
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002551 :param pkey: The new private key, or :py:const:`None` to unset it.
2552 :type pkey: :py:class:`PKey` or :py:const:`None`
2553
Dan Sully44e767a2016-06-04 18:05:27 -07002554 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002555 """
2556 if not isinstance(pkey, PKey):
2557 raise TypeError("pkey must be a PKey instance")
2558 self._pkey = pkey
2559
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002560 def get_ca_certificates(self):
2561 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002562 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002563
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002564 :return: A tuple with the CA certificates in the chain, or
2565 :py:const:`None` if there are none.
2566 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002567 """
2568 if self._cacerts is not None:
2569 return tuple(self._cacerts)
2570
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002571 def set_ca_certificates(self, cacerts):
2572 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002573 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002574
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002575 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2576 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002577 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002578
Dan Sully44e767a2016-06-04 18:05:27 -07002579 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002580 """
2581 if cacerts is None:
2582 self._cacerts = None
2583 else:
2584 cacerts = list(cacerts)
2585 for cert in cacerts:
2586 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002587 raise TypeError(
2588 "iterable must only contain X509 instances"
2589 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002590 self._cacerts = cacerts
2591
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002592 def set_friendlyname(self, name):
2593 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002594 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002595
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002596 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002597 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002598
Dan Sully44e767a2016-06-04 18:05:27 -07002599 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002600 """
2601 if name is None:
2602 self._friendlyname = None
2603 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002604 raise TypeError(
2605 "name must be a byte string or None (not %r)" % (name,)
2606 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002607 self._friendlyname = name
2608
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002609 def get_friendlyname(self):
2610 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002611 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002612
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002613 :returns: The friendly name, or :py:const:`None` if there is none.
2614 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002615 """
2616 return self._friendlyname
2617
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002618 def export(self, passphrase=None, iter=2048, maciter=1):
2619 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002620 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002621
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002622 For more information, see the :c:func:`PKCS12_create` man page.
2623
2624 :param passphrase: The passphrase used to encrypt the structure. Unlike
2625 some other passphrase arguments, this *must* be a string, not a
2626 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002627 :type passphrase: :py:data:`bytes`
2628
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002629 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002630 :type iter: :py:data:`int`
2631
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002632 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002633 :type maciter: :py:data:`int`
2634
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002635 :return: The string representation of the PKCS #12 structure.
2636 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002637 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002638 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002639
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002640 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002641 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002642 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002643 cacerts = _lib.sk_X509_new_null()
2644 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002645 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002646 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002647
2648 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002649 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002650
2651 friendlyname = self._friendlyname
2652 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002653 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002654
2655 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002656 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002657 else:
2658 pkey = self._pkey._pkey
2659
2660 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002661 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002662 else:
2663 cert = self._cert._x509
2664
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002665 pkcs12 = _lib.PKCS12_create(
Alex Gaynor03737182020-07-23 20:40:46 -04002666 passphrase,
2667 friendlyname,
2668 pkey,
2669 cert,
2670 cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002671 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2672 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Alex Gaynor03737182020-07-23 20:40:46 -04002673 iter,
2674 maciter,
2675 0,
2676 )
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002677 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002678 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002679 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002680
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002681 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002682 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002683 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002684
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002685
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002686class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002687 """
2688 A Netscape SPKI object.
2689 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002690
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002691 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002692 spki = _lib.NETSCAPE_SPKI_new()
2693 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002694
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002695 def sign(self, pkey, digest):
2696 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002697 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002698
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002699 :param pkey: The private key to sign with.
2700 :type pkey: :py:class:`PKey`
2701
2702 :param digest: The message digest to use.
2703 :type digest: :py:class:`bytes`
2704
Dan Sully44e767a2016-06-04 18:05:27 -07002705 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002706 """
2707 if pkey._only_public:
2708 raise ValueError("Key has only public part")
2709
2710 if not pkey._initialized:
2711 raise ValueError("Key is uninitialized")
2712
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002713 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002714 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002715 raise ValueError("No such digest method")
2716
Alex Gaynor5945ea82015-09-05 14:59:06 -04002717 sign_result = _lib.NETSCAPE_SPKI_sign(
2718 self._spki, pkey._pkey, digest_obj
2719 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04002720 _openssl_assert(sign_result > 0)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002721
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002722 def verify(self, key):
2723 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002724 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002725
Hynek Schlawack01c31672016-12-11 15:14:09 +01002726 :param PKey key: The public key that signature is supposedly from.
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002727
Hynek Schlawack01c31672016-12-11 15:14:09 +01002728 :return: ``True`` if the signature is correct.
2729 :rtype: bool
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002730
Hynek Schlawack01c31672016-12-11 15:14:09 +01002731 :raises OpenSSL.crypto.Error: If the signature is invalid, or there was
2732 a problem verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002733 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002734 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002735 if answer <= 0:
2736 _raise_current_error()
2737 return True
2738
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002739 def b64_encode(self):
2740 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002741 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002742
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002743 :return: The base64 encoded string.
2744 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002745 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002746 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2747 result = _ffi.string(encoded)
Paul Kehrer0dcacf72016-03-17 19:25:39 -04002748 _lib.OPENSSL_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002749 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002750
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002751 def get_pubkey(self):
2752 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002753 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002754
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002755 :return: The public key.
2756 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002757 """
2758 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002759 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002760 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002761 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002762 pkey._only_public = True
2763 return pkey
2764
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002765 def set_pubkey(self, pkey):
2766 """
2767 Set the public key of the certificate
2768
2769 :param pkey: The public key
Dan Sully44e767a2016-06-04 18:05:27 -07002770 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002771 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002772 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -04002773 _openssl_assert(set_result == 1)
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002774
2775
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002776class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002777 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002778 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002779 raise ValueError(
2780 "only FILETYPE_PEM key format supports encryption"
2781 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002782 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002783 self._more_args = more_args
2784 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002785 self._problems = []
2786
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002787 @property
2788 def callback(self):
2789 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002790 return _ffi.NULL
Huw Jonescdd66962020-10-13 05:14:19 +01002791 elif isinstance(self._passphrase, bytes) or callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002792 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002793 else:
Hynek Schlawack33675f92016-11-18 14:55:06 +01002794 raise TypeError(
2795 "Last argument must be a byte string or a callable."
2796 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002797
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002798 @property
2799 def callback_args(self):
2800 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002801 return _ffi.NULL
Huw Jonescdd66962020-10-13 05:14:19 +01002802 elif isinstance(self._passphrase, bytes) or callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002803 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002804 else:
Hynek Schlawack33675f92016-11-18 14:55:06 +01002805 raise TypeError(
2806 "Last argument must be a byte string or a callable."
2807 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002808
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002809 def raise_if_problem(self, exceptionType=Error):
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002810 if self._problems:
Greg Bowser36eb2de2017-01-24 11:38:55 -05002811
2812 # Flush the OpenSSL error queue
2813 try:
2814 _exception_from_error_queue(exceptionType)
2815 except exceptionType:
2816 pass
2817
2818 raise self._problems.pop(0)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002819
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002820 def _read_passphrase(self, buf, size, rwflag, userdata):
2821 try:
Huw Jonescdd66962020-10-13 05:14:19 +01002822 if callable(self._passphrase):
2823 if self._more_args:
2824 result = self._passphrase(size, rwflag, userdata)
2825 else:
2826 result = self._passphrase(rwflag)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002827 else:
Huw Jonescdd66962020-10-13 05:14:19 +01002828 result = self._passphrase
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002829 if not isinstance(result, bytes):
Huw Jonescdd66962020-10-13 05:14:19 +01002830 raise ValueError("Bytes expected")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002831 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002832 if self._truncate:
2833 result = result[:size]
2834 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002835 raise ValueError(
2836 "passphrase returned by callback is too long"
2837 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002838 for i in range(len(result)):
Alex Gaynor03737182020-07-23 20:40:46 -04002839 buf[i] = result[i : i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002840 return len(result)
2841 except Exception as e:
2842 self._problems.append(e)
2843 return 0
2844
2845
Cory Benfield6492f7c2015-10-27 16:57:58 +09002846def load_publickey(type, buffer):
2847 """
Cory Benfield11c10192015-10-27 17:23:03 +09002848 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002849
Cory Benfield9c590b92015-10-28 14:55:05 +09002850 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002851 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002852 :param buffer: The buffer the key is stored in.
2853 :type buffer: A Python string object, either unicode or bytestring.
2854 :return: The PKey object.
2855 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002856 """
2857 if isinstance(buffer, _text_type):
2858 buffer = buffer.encode("ascii")
2859
2860 bio = _new_mem_buf(buffer)
2861
2862 if type == FILETYPE_PEM:
2863 evp_pkey = _lib.PEM_read_bio_PUBKEY(
Alex Gaynor03737182020-07-23 20:40:46 -04002864 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL
2865 )
Cory Benfield6492f7c2015-10-27 16:57:58 +09002866 elif type == FILETYPE_ASN1:
2867 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2868 else:
2869 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2870
2871 if evp_pkey == _ffi.NULL:
2872 _raise_current_error()
2873
2874 pkey = PKey.__new__(PKey)
2875 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Paul Kehrer32fc4e62016-06-03 15:21:44 -07002876 pkey._only_public = True
Cory Benfield6492f7c2015-10-27 16:57:58 +09002877 return pkey
2878
2879
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002880def load_privatekey(type, buffer, passphrase=None):
2881 """
Alex Chand072cae2018-02-15 09:57:59 +00002882 Load a private key (PKey) from the string *buffer* encoded with the type
2883 *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002884
2885 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2886 :param buffer: The buffer the key is stored in
2887 :param passphrase: (optional) if encrypted PEM format, this can be
2888 either the passphrase to use, or a callback for
2889 providing the passphrase.
2890
2891 :return: The PKey object
2892 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002893 if isinstance(buffer, _text_type):
2894 buffer = buffer.encode("ascii")
2895
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002896 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002897
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002898 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002899 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002900 evp_pkey = _lib.PEM_read_bio_PrivateKey(
Alex Gaynor03737182020-07-23 20:40:46 -04002901 bio, _ffi.NULL, helper.callback, helper.callback_args
2902 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002903 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002904 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002905 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002906 else:
2907 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2908
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002909 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002910 _raise_current_error()
2911
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002912 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002913 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002914 return pkey
2915
2916
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002917def dump_certificate_request(type, req):
2918 """
Alex Chand072cae2018-02-15 09:57:59 +00002919 Dump the certificate request *req* into a buffer string encoded with the
2920 type *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002921
2922 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2923 :param req: The certificate request to dump
2924 :return: The buffer with the dumped certificate request in
2925 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002926 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002927
2928 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002929 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002930 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002931 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002932 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002933 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002934 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002935 raise ValueError(
2936 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2937 "FILETYPE_TEXT"
2938 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002939
Alex Gaynor09a386e2016-07-03 09:32:44 -04002940 _openssl_assert(result_code != 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002941
2942 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002943
2944
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002945def load_certificate_request(type, buffer):
2946 """
Alex Chand072cae2018-02-15 09:57:59 +00002947 Load a certificate request (X509Req) from the string *buffer* encoded with
2948 the type *type*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002949
2950 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2951 :param buffer: The buffer the certificate request is stored in
2952 :return: The X509Req object
2953 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002954 if isinstance(buffer, _text_type):
2955 buffer = buffer.encode("ascii")
2956
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002957 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002958
2959 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002960 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002961 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002962 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002963 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002964 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002965
Alex Gaynoradd5b072016-06-04 21:04:00 -07002966 _openssl_assert(req != _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002967
2968 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002969 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002970 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002971
2972
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002973def sign(pkey, data, digest):
2974 """
Alex Chand072cae2018-02-15 09:57:59 +00002975 Sign a data string using the given key and message digest.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002976
Alex Chand072cae2018-02-15 09:57:59 +00002977 :param pkey: PKey to sign with
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002978 :param data: data to be signed
2979 :param digest: message digest to use
2980 :return: signature
Alex Chand072cae2018-02-15 09:57:59 +00002981
2982 .. versionadded:: 0.11
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002983 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002984 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002985
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002986 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002987 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002988 raise ValueError("No such digest method")
2989
Alex Gaynor67903a62016-06-02 10:37:13 -07002990 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002991 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002992
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002993 _lib.EVP_SignInit(md_ctx, digest_obj)
2994 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002995
Paul Kehrer59d26252017-07-20 10:45:54 +02002996 length = _lib.EVP_PKEY_size(pkey._pkey)
2997 _openssl_assert(length > 0)
2998 signature_buffer = _ffi.new("unsigned char[]", length)
2999 signature_length = _ffi.new("unsigned int *")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003000 final_result = _lib.EVP_SignFinal(
Alex Gaynor03737182020-07-23 20:40:46 -04003001 md_ctx, signature_buffer, signature_length, pkey._pkey
3002 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04003003 _openssl_assert(final_result == 1)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003004
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003005 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003006
3007
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003008def verify(cert, signature, data, digest):
3009 """
Alex Chand072cae2018-02-15 09:57:59 +00003010 Verify the signature for a data string.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003011
Alex Chand072cae2018-02-15 09:57:59 +00003012 :param cert: signing certificate (X509 object) corresponding to the
3013 private key which generated the signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003014 :param signature: signature returned by sign function
3015 :param data: data to be verified
3016 :param digest: message digest to use
Dan Sully44e767a2016-06-04 18:05:27 -07003017 :return: ``None`` if the signature is correct, raise exception otherwise.
Alex Chand072cae2018-02-15 09:57:59 +00003018
3019 .. versionadded:: 0.11
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003020 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04003021 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00003022
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05003023 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003024 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003025 raise ValueError("No such digest method")
3026
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003027 pkey = _lib.X509_get_pubkey(cert._x509)
Alex Gaynoradd5b072016-06-04 21:04:00 -07003028 _openssl_assert(pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003029 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003030
Alex Gaynor67903a62016-06-02 10:37:13 -07003031 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07003032 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003033
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003034 _lib.EVP_VerifyInit(md_ctx, digest_obj)
3035 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04003036 verify_result = _lib.EVP_VerifyFinal(
3037 md_ctx, signature, len(signature), pkey
3038 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08003039
3040 if verify_result != 1:
3041 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003042
3043
Dominic Chenf05b2122015-10-13 16:32:35 +00003044def dump_crl(type, crl):
3045 """
3046 Dump a certificate revocation list to a buffer.
3047
3048 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
3049 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02003050 :param CRL crl: The CRL to dump.
3051
Dominic Chenf05b2122015-10-13 16:32:35 +00003052 :return: The buffer with the CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07003053 :rtype: bytes
Dominic Chenf05b2122015-10-13 16:32:35 +00003054 """
3055 bio = _new_mem_buf()
3056
3057 if type == FILETYPE_PEM:
3058 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
3059 elif type == FILETYPE_ASN1:
3060 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
3061 elif type == FILETYPE_TEXT:
3062 ret = _lib.X509_CRL_print(bio, crl._crl)
3063 else:
3064 raise ValueError(
3065 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
Alex Gaynor03737182020-07-23 20:40:46 -04003066 "FILETYPE_TEXT"
3067 )
Dominic Chenf05b2122015-10-13 16:32:35 +00003068
Adrián Chaves98c57be2020-03-31 16:14:50 +02003069 _openssl_assert(ret == 1)
Dominic Chenf05b2122015-10-13 16:32:35 +00003070 return _bio_to_string(bio)
3071
3072
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003073def load_crl(type, buffer):
3074 """
Alex Chand072cae2018-02-15 09:57:59 +00003075 Load Certificate Revocation List (CRL) data from a string *buffer*.
3076 *buffer* encoded with the type *type*.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003077
3078 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
3079 :param buffer: The buffer the CRL is stored in
3080
3081 :return: The PKey object
3082 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05003083 if isinstance(buffer, _text_type):
3084 buffer = buffer.encode("ascii")
3085
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08003086 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003087
3088 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003089 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003090 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003091 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003092 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003093 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
3094
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003095 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003096 _raise_current_error()
3097
3098 result = CRL.__new__(CRL)
Jeremy Cline9e15eca2017-09-07 20:11:08 -04003099 result._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08003100 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003101
3102
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003103def load_pkcs7_data(type, buffer):
3104 """
Alex Chand072cae2018-02-15 09:57:59 +00003105 Load pkcs7 data from the string *buffer* encoded with the type
3106 *type*.
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003107
3108 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
3109 :param buffer: The buffer with the pkcs7 data.
3110 :return: The PKCS7 object
3111 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05003112 if isinstance(buffer, _text_type):
3113 buffer = buffer.encode("ascii")
3114
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08003115 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003116
3117 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003118 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003119 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07003120 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003121 else:
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003122 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
3123
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003124 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08003125 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003126
3127 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003128 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08003129 return pypkcs7
3130
3131
Alex Gaynorbb971ae2020-08-05 01:14:16 -04003132load_pkcs7_data = utils.deprecated(
3133 load_pkcs7_data,
3134 __name__,
3135 (
3136 "PKCS#7 support in pyOpenSSL is deprecated. You should use the APIs "
3137 "in cryptography."
3138 ),
3139 DeprecationWarning,
3140)
3141
3142
Stephen Holsapple38482622014-04-05 20:29:34 -07003143def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003144 """
Alex Chand072cae2018-02-15 09:57:59 +00003145 Load pkcs12 data from the string *buffer*. If the pkcs12 structure is
3146 encrypted, a *passphrase* must be included. The MAC is always
3147 checked and thus required.
3148
3149 See also the man page for the C function :py:func:`PKCS12_parse`.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003150
3151 :param buffer: The buffer the certificate is stored in
3152 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
3153 :returns: The PKCS12 object
3154 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04003155 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00003156
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05003157 if isinstance(buffer, _text_type):
3158 buffer = buffer.encode("ascii")
3159
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08003160 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003161
Stephen Holsapple38482622014-04-05 20:29:34 -07003162 # Use null passphrase if passphrase is None or empty string. With PKCS#12
3163 # password based encryption no password and a zero length password are two
3164 # different things, but OpenSSL implementation will try both to figure out
3165 # which one works.
3166 if not passphrase:
3167 passphrase = _ffi.NULL
3168
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003169 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
3170 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003171 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003172 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003173
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003174 pkey = _ffi.new("EVP_PKEY**")
3175 cert = _ffi.new("X509**")
3176 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003177
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003178 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003179 if not parse_result:
3180 _raise_current_error()
3181
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003182 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08003183
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003184 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
3185 # queue for no particular reason. This error isn't interesting to anyone
3186 # outside this function. It's not even interesting to us. Get rid of it.
3187 try:
3188 _raise_current_error()
3189 except Error:
3190 pass
3191
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003192 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003193 pykey = None
3194 else:
3195 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003196 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003197
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003198 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003199 pycert = None
3200 friendlyname = None
3201 else:
Paul Kehrere7381862017-11-30 20:55:25 +08003202 pycert = X509._from_raw_x509_ptr(cert[0])
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003203
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003204 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04003205 friendlyname_buffer = _lib.X509_alias_get0(
3206 cert[0], friendlyname_length
3207 )
3208 friendlyname = _ffi.buffer(
3209 friendlyname_buffer, friendlyname_length[0]
3210 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003211 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003212 friendlyname = None
3213
3214 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05003215 for i in range(_lib.sk_X509_num(cacerts)):
Paul Kehrere7381862017-11-30 20:55:25 +08003216 x509 = _lib.sk_X509_value(cacerts, i)
3217 pycacert = X509._from_raw_x509_ptr(x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08003218 pycacerts.append(pycacert)
3219 if not pycacerts:
3220 pycacerts = None
3221
3222 pkcs12 = PKCS12.__new__(PKCS12)
3223 pkcs12._pkey = pykey
3224 pkcs12._cert = pycert
3225 pkcs12._cacerts = pycacerts
3226 pkcs12._friendlyname = friendlyname
3227 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05003228
3229
Alex Gaynorbb971ae2020-08-05 01:14:16 -04003230load_pkcs12 = utils.deprecated(
3231 load_pkcs12,
3232 __name__,
3233 (
3234 "PKCS#12 support in pyOpenSSL is deprecated. You should use the APIs "
3235 "in cryptography."
3236 ),
3237 DeprecationWarning,
3238)
3239
3240
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05003241# There are no direct unit tests for this initialization. It is tested
3242# indirectly since it is necessary for functions like dump_privatekey when
3243# using encryption.
3244#
3245# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
3246# and some other similar tests may fail without this (though they may not if
3247# the Python runtime has already done some initialization of the underlying
3248# OpenSSL library (and is linked against the same one that cryptography is
3249# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05003250_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05003251
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05003252# This is similar but exercised mainly by exception_from_error_queue. It calls
3253# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
3254_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02003255
3256
D.S. Ljungmark349e1362014-05-31 18:40:38 +02003257# Set the default string mask to match OpenSSL upstream (since 2005) and
3258# RFC5280 recommendations.
Alex Gaynor03737182020-07-23 20:40:46 -04003259_lib.ASN1_STRING_set_default_mask_asc(b"utf8only")