blob: 52fcdaf96d45d98dfea49b5b645cebc06e3c92ce [file] [log] [blame]
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001import datetime
Paul Kehrer8d887e12015-10-24 09:09:55 -05002
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05003from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05004from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05005from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
Jean-Paul Calderone60432792015-04-13 12:26:07 -04006from warnings import warn as _warn
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05007
8from six import (
9 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -040010 text_type as _text_type,
11 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080012
Paul Kehrer72d968b2016-07-29 15:31:04 +080013from cryptography.hazmat.primitives.asymmetric import dsa, rsa
14
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050015from OpenSSL._util import (
16 ffi as _ffi,
17 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050018 exception_from_error_queue as _exception_from_error_queue,
19 byte_string as _byte_string,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040020 native as _native,
21 UNSPECIFIED as _UNSPECIFIED,
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -040022 text_to_bytes_and_warn as _text_to_bytes_and_warn,
Alex Gaynor67903a62016-06-02 10:37:13 -070023 make_assert as _make_assert,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040024)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080025
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050026FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
27FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080028
29# TODO This was an API mistake. OpenSSL has no such constant.
30FILETYPE_TEXT = 2 ** 16 - 1
31
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050032TYPE_RSA = _lib.EVP_PKEY_RSA
33TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080034
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080035
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050036class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050037 """
38 An error occurred in an `OpenSSL.crypto` API.
39 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050040
41
42_raise_current_error = partial(_exception_from_error_queue, Error)
Alex Gaynor67903a62016-06-02 10:37:13 -070043_openssl_assert = _make_assert(Error)
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050044
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070045
Paul Kehrereb633842016-10-06 11:22:01 +020046def _get_backend():
47 """
48 Importing the backend from cryptography has the side effect of activating
49 the osrandom engine. This mutates the global state of OpenSSL in the
50 process and causes issues for various programs that use subinterpreters or
51 embed Python. By putting the import in this function we can avoid
52 triggering this side effect unless _get_backend is called.
53 """
54 from cryptography.hazmat.backends.openssl.backend import backend
55 return backend
56
57
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050058def _untested_error(where):
59 """
60 An OpenSSL API failed somehow. Additionally, the failure which was
61 encountered isn't one that's exercised by the test suite so future behavior
62 of pyOpenSSL is now somewhat less predictable.
63 """
64 raise RuntimeError("Unknown %s failure" % (where,))
65
66
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050067def _new_mem_buf(buffer=None):
68 """
69 Allocate a new OpenSSL memory BIO.
70
71 Arrange for the garbage collector to clean it up automatically.
72
73 :param buffer: None or some bytes to use to put into the BIO so that they
74 can be read out.
75 """
76 if buffer is None:
77 bio = _lib.BIO_new(_lib.BIO_s_mem())
78 free = _lib.BIO_free
79 else:
80 data = _ffi.new("char[]", buffer)
81 bio = _lib.BIO_new_mem_buf(data, len(buffer))
Alex Gaynor5945ea82015-09-05 14:59:06 -040082
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050083 # Keep the memory alive as long as the bio is alive!
84 def free(bio, ref=data):
85 return _lib.BIO_free(bio)
86
Alex Gaynorfb8a2a12016-06-04 18:26:26 -070087 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050088
89 bio = _ffi.gc(bio, free)
90 return bio
91
92
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080093def _bio_to_string(bio):
94 """
95 Copy the contents of an OpenSSL BIO object into a Python byte string.
96 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050097 result_buffer = _ffi.new('char**')
98 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
99 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800100
101
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800102def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500103 """
104 The the time value of an ASN1 time object.
105
106 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
107 castable to that type) which will have its value set.
108 @param when: A string representation of the desired time value.
109
110 @raise TypeError: If C{when} is not a L{bytes} string.
111 @raise ValueError: If C{when} does not represent a time in the required
112 format.
113 @raise RuntimeError: If the time value cannot be set for some other
114 (unspecified) reason.
115 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800116 if not isinstance(when, bytes):
117 raise TypeError("when must be a byte string")
118
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500119 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
120 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800121 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500122 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
123 _lib.ASN1_STRING_set(dummy, when, len(when))
124 check_result = _lib.ASN1_GENERALIZEDTIME_check(
125 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800126 if not check_result:
127 raise ValueError("Invalid string")
128 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500129 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800130
Alex Gaynor510293e2016-06-02 12:07:59 -0700131
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800132def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500133 """
134 Retrieve the time value of an ASN1 time object.
135
136 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
137 that type) from which the time value will be retrieved.
138
139 @return: The time value from C{timestamp} as a L{bytes} string in a certain
140 format. Or C{None} if the object contains no time value.
141 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500142 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
143 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800144 return None
Alex Gaynor5945ea82015-09-05 14:59:06 -0400145 elif (
146 _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME
147 ):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500148 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800149 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500150 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
151 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
152 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500153 # This may happen:
154 # - if timestamp was not an ASN1_TIME
155 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
156 # - if a copy of the time data from timestamp cannot be made for
157 # the newly allocated ASN1_GENERALIZEDTIME
158 #
159 # These are difficult to test. cffi enforces the ASN1_TIME type.
160 # Memory allocation failures are a pain to trigger
161 # deterministically.
162 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800163 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500164 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800165 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500166 string_data = _lib.ASN1_STRING_data(string_timestamp)
167 string_result = _ffi.string(string_data)
168 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800169 return string_result
170
171
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800172class PKey(object):
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200173 """
174 A class representing an DSA or RSA public key or key pair.
175 """
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800176 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800177 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800178
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800179 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500180 pkey = _lib.EVP_PKEY_new()
181 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800182 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800183
Paul Kehrer72d968b2016-07-29 15:31:04 +0800184 def to_cryptography_key(self):
185 """
186 Export as a ``cryptography`` key.
187
188 :rtype: One of ``cryptography``'s `key interfaces`_.
189
190 .. _key interfaces: https://cryptography.io/en/latest/hazmat/\
191 primitives/asymmetric/rsa/#key-interfaces
192
193 .. versionadded:: 16.1.0
194 """
Paul Kehrereb633842016-10-06 11:22:01 +0200195 backend = _get_backend()
Paul Kehrer72d968b2016-07-29 15:31:04 +0800196 if self._only_public:
197 return backend._evp_pkey_to_public_key(self._pkey)
198 else:
199 return backend._evp_pkey_to_private_key(self._pkey)
200
201 @classmethod
202 def from_cryptography_key(cls, crypto_key):
203 """
204 Construct based on a ``cryptography`` *crypto_key*.
205
206 :param crypto_key: A ``cryptography`` key.
207 :type crypto_key: One of ``cryptography``'s `key interfaces`_.
208
209 :rtype: PKey
210
211 .. versionadded:: 16.1.0
212 """
213 pkey = cls()
214 if not isinstance(crypto_key, (rsa.RSAPublicKey, rsa.RSAPrivateKey,
215 dsa.DSAPublicKey, dsa.DSAPrivateKey)):
216 raise TypeError("Unsupported key type")
217
218 pkey._pkey = crypto_key._evp_pkey
219 if isinstance(crypto_key, (rsa.RSAPublicKey, dsa.DSAPublicKey)):
220 pkey._only_public = True
221 pkey._initialized = True
222 return pkey
223
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800224 def generate_key(self, type, bits):
225 """
Laurens Van Houtven90c09142015-04-23 10:52:49 -0700226 Generate a key pair of the given type, with the given number of bits.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800227
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200228 This generates a key "into" the this object.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800229
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200230 :param type: The key type.
231 :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`
232 :param bits: The number of bits.
233 :type bits: :py:data:`int` ``>= 0``
234 :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't
235 of the appropriate type.
236 :raises ValueError: If the number of bits isn't an integer of
237 the appropriate size.
Dan Sully44e767a2016-06-04 18:05:27 -0700238 :return: ``None``
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800239 """
240 if not isinstance(type, int):
241 raise TypeError("type must be an integer")
242
243 if not isinstance(bits, int):
244 raise TypeError("bits must be an integer")
245
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800246 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500247 exponent = _lib.BN_new()
248 exponent = _ffi.gc(exponent, _lib.BN_free)
249 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800250
251 if type == TYPE_RSA:
252 if bits <= 0:
253 raise ValueError("Invalid number of bits")
254
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500255 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800256
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500257 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400258 _openssl_assert(result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800259
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500260 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400261 _openssl_assert(result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800262
263 elif type == TYPE_DSA:
Paul Kehrera0860b92016-03-09 21:39:27 -0400264 dsa = _lib.DSA_new()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700265 _openssl_assert(dsa != _ffi.NULL)
Paul Kehrerafa5a662016-03-10 10:29:28 -0400266
267 dsa = _ffi.gc(dsa, _lib.DSA_free)
Paul Kehrera0860b92016-03-09 21:39:27 -0400268 res = _lib.DSA_generate_parameters_ex(
269 dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL
270 )
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700271 _openssl_assert(res == 1)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400272
273 _openssl_assert(_lib.DSA_generate_key(dsa) == 1)
274 _openssl_assert(_lib.EVP_PKEY_set1_DSA(self._pkey, dsa) == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800275 else:
276 raise Error("No such key type")
277
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800278 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800279
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800280 def check(self):
281 """
282 Check the consistency of an RSA private key.
283
Laurens Van Houtven6e7dd432014-06-17 16:10:57 +0200284 This is the Python equivalent of OpenSSL's ``RSA_check_key``.
285
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800286 :return: True if key is consistent.
287 :raise Error: if the key is inconsistent.
288 :raise TypeError: if the key is of a type which cannot be checked.
289 Only RSA keys can currently be checked.
290 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800291 if self._only_public:
292 raise TypeError("public key only")
293
Hynek Schlawack2a91ba32016-01-31 14:18:54 +0100294 if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800295 raise TypeError("key type unsupported")
296
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500297 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
298 rsa = _ffi.gc(rsa, _lib.RSA_free)
299 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800300 if result:
301 return True
302 _raise_current_error()
303
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800304 def type(self):
305 """
306 Returns the type of the key
307
308 :return: The type of the key.
309 """
Alex Gaynorc84567b2016-03-16 07:45:09 -0400310 return _lib.Cryptography_EVP_PKEY_id(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800311
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800312 def bits(self):
313 """
314 Returns the number of bits of the key
315
316 :return: The number of bits of the key.
317 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500318 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800319PKeyType = PKey
320
321
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400322class _EllipticCurve(object):
323 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400324 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400325
326 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
327 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
328 instances each of which represents one curve supported by the system.
329 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400330 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400331 _curves = None
332
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400333 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400334 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400335 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400336 """
337 Implement cooperation with the right-hand side argument of ``!=``.
338
339 Python 3 seems to have dropped this cooperation in this very narrow
340 circumstance.
341 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400342 if isinstance(other, _EllipticCurve):
343 return super(_EllipticCurve, self).__ne__(other)
344 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400345
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400346 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400347 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400348 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400349 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400350
351 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400352
353 :return: A :py:type:`set` of ``cls`` instances giving the names of the
354 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400355 """
356 if lib.Cryptography_HAS_EC:
357 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
358 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
Alex Gaynor5945ea82015-09-05 14:59:06 -0400359 # The return value on this call should be num_curves again. We
360 # could check it to make sure but if it *isn't* then.. what could
361 # we do? Abort the whole process, I suppose...? -exarkun
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400362 lib.EC_get_builtin_curves(builtin_curves, num_curves)
363 return set(
364 cls.from_nid(lib, c.nid)
365 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400366 return set()
367
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400368 @classmethod
369 def _get_elliptic_curves(cls, lib):
370 """
371 Get, cache, and return the curves supported by OpenSSL.
372
373 :param lib: The OpenSSL library binding object.
374
375 :return: A :py:type:`set` of ``cls`` instances giving the names of the
376 elliptic curves the underlying library supports.
377 """
378 if cls._curves is None:
379 cls._curves = cls._load_elliptic_curves(lib)
380 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400381
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400382 @classmethod
383 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400384 """
385 Instantiate a new :py:class:`_EllipticCurve` associated with the given
386 OpenSSL NID.
387
388 :param lib: The OpenSSL library binding object.
389
390 :param nid: The OpenSSL NID the resulting curve object will represent.
391 This must be a curve NID (and not, for example, a hash NID) or
392 subsequent operations will fail in unpredictable ways.
393 :type nid: :py:class:`int`
394
395 :return: The curve object.
396 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400397 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
398
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400399 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400400 """
401 :param _lib: The :py:mod:`cryptography` binding instance used to
402 interface with OpenSSL.
403
404 :param _nid: The OpenSSL NID identifying the curve this object
405 represents.
406 :type _nid: :py:class:`int`
407
408 :param name: The OpenSSL short name identifying the curve this object
409 represents.
410 :type name: :py:class:`unicode`
411 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400412 self._lib = lib
413 self._nid = nid
414 self.name = name
415
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400416 def __repr__(self):
417 return "<Curve %r>" % (self.name,)
418
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400419 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400420 """
421 Create a new OpenSSL EC_KEY structure initialized to use this curve.
422
423 The structure is automatically garbage collected when the Python object
424 is garbage collected.
425 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400426 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
427 return _ffi.gc(key, _lib.EC_KEY_free)
428
429
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400430def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400431 """
432 Return a set of objects representing the elliptic curves supported in the
433 OpenSSL build in use.
434
435 The curve objects have a :py:class:`unicode` ``name`` attribute by which
436 they identify themselves.
437
438 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400439 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
440 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400441 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400442 return _EllipticCurve._get_elliptic_curves(_lib)
443
444
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400445def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400446 """
447 Return a single curve object selected by name.
448
449 See :py:func:`get_elliptic_curves` for information about curve objects.
450
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400451 :param name: The OpenSSL short name identifying the curve object to
452 retrieve.
453 :type name: :py:class:`unicode`
454
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400455 If the named curve is not supported then :py:class:`ValueError` is raised.
456 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400457 for curve in get_elliptic_curves():
458 if curve.name == name:
459 return curve
460 raise ValueError("unknown curve name", name)
461
462
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800463class X509Name(object):
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200464 """
465 An X.509 Distinguished Name.
466
467 :ivar countryName: The country of the entity.
468 :ivar C: Alias for :py:attr:`countryName`.
469
470 :ivar stateOrProvinceName: The state or province of the entity.
471 :ivar ST: Alias for :py:attr:`stateOrProvinceName`.
472
473 :ivar localityName: The locality of the entity.
474 :ivar L: Alias for :py:attr:`localityName`.
475
476 :ivar organizationName: The organization name of the entity.
477 :ivar O: Alias for :py:attr:`organizationName`.
478
479 :ivar organizationalUnitName: The organizational unit of the entity.
480 :ivar OU: Alias for :py:attr:`organizationalUnitName`
481
482 :ivar commonName: The common name of the entity.
483 :ivar CN: Alias for :py:attr:`commonName`.
484
485 :ivar emailAddress: The e-mail address of the entity.
486 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400487
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800488 def __init__(self, name):
489 """
490 Create a new X509Name, copying the given X509Name instance.
491
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200492 :param name: The name to copy.
493 :type name: :py:class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800494 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500495 name = _lib.X509_NAME_dup(name._name)
496 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800497
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800498 def __setattr__(self, name, value):
499 if name.startswith('_'):
500 return super(X509Name, self).__setattr__(name, value)
501
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800502 # Note: we really do not want str subclasses here, so we do not use
503 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800504 if type(name) is not str:
505 raise TypeError("attribute name must be string, not '%.200s'" % (
Alex Gaynora738ed52015-09-05 11:17:10 -0400506 type(value).__name__,))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800507
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500508 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500509 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800510 try:
511 _raise_current_error()
512 except Error:
513 pass
514 raise AttributeError("No such attribute")
515
516 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500517 for i in range(_lib.X509_NAME_entry_count(self._name)):
518 ent = _lib.X509_NAME_get_entry(self._name, i)
519 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
520 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800521 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500522 ent = _lib.X509_NAME_delete_entry(self._name, i)
523 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800524 break
525
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500526 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800527 value = value.encode('utf-8')
528
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500529 add_result = _lib.X509_NAME_add_entry_by_NID(
530 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800531 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500532 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800533
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800534 def __getattr__(self, name):
535 """
536 Find attribute. An X509Name object has the following attributes:
537 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
Alex Gaynor5945ea82015-09-05 14:59:06 -0400538 organization (alias O), organizationalUnit (alias OU), commonName
539 (alias CN) and more...
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800540 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500541 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500542 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800543 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
544 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
545 # push something onto the error queue. If we don't clean that up
546 # now, someone else will bump into it later and be quite confused.
547 # See lp#314814.
548 try:
549 _raise_current_error()
550 except Error:
551 pass
552 return super(X509Name, self).__getattr__(name)
553
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500554 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800555 if entry_index == -1:
556 return None
557
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500558 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
559 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800560
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500561 result_buffer = _ffi.new("unsigned char**")
562 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400563 _openssl_assert(data_length >= 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800564
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700565 try:
Alex Gaynor5945ea82015-09-05 14:59:06 -0400566 result = _ffi.buffer(
567 result_buffer[0], data_length
568 )[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700569 finally:
570 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500571 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800572 return result
573
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500574 def _cmp(op):
575 def f(self, other):
576 if not isinstance(other, X509Name):
577 return NotImplemented
578 result = _lib.X509_NAME_cmp(self._name, other._name)
579 return op(result, 0)
580 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800581
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500582 __eq__ = _cmp(__eq__)
583 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800584
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500585 __lt__ = _cmp(__lt__)
586 __le__ = _cmp(__le__)
587
588 __gt__ = _cmp(__gt__)
589 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800590
591 def __repr__(self):
592 """
593 String representation of an X509Name
594 """
Alex Gaynor962ac212015-09-04 08:06:42 -0400595 result_buffer = _ffi.new("char[]", 512)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500596 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800597 self._name, result_buffer, len(result_buffer))
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700598 _openssl_assert(format_result != _ffi.NULL)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800599
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500600 return "<X509Name object '%s'>" % (
601 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800602
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800603 def hash(self):
604 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200605 Return an integer representation of the first four bytes of the
606 MD5 digest of the DER representation of the name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800607
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200608 This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.
609
610 :return: The (integer) hash of this name.
611 :rtype: :py:class:`int`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800612 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500613 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800614
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800615 def der(self):
616 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200617 Return the DER encoding of this name.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800618
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200619 :return: The DER encoded form of this name.
620 :rtype: :py:class:`bytes`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800621 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500622 result_buffer = _ffi.new('unsigned char**')
623 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400624 _openssl_assert(encode_result >= 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800625
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500626 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
627 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800628 return string_result
629
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800630 def get_components(self):
631 """
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200632 Returns the components of this name, as a sequence of 2-tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800633
Laurens Van Houtven196195b2014-06-17 17:06:34 +0200634 :return: The components of this name.
635 :rtype: :py:class:`list` of ``name, value`` tuples.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800636 """
637 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500638 for i in range(_lib.X509_NAME_entry_count(self._name)):
639 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800640
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500641 fname = _lib.X509_NAME_ENTRY_get_object(ent)
642 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800643
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500644 nid = _lib.OBJ_obj2nid(fname)
645 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800646
647 result.append((
Alex Gaynora738ed52015-09-05 11:17:10 -0400648 _ffi.string(name),
649 _ffi.string(
650 _lib.ASN1_STRING_data(fval),
651 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800652
653 return result
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200654
655
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800656X509NameType = X509Name
657
658
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800659class X509Extension(object):
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200660 """
661 An X.509 v3 certificate extension.
662 """
Alex Gaynor5945ea82015-09-05 14:59:06 -0400663
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800664 def __init__(self, type_name, critical, value, subject=None, issuer=None):
665 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200666 Initializes an X509 extension.
667
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100668 :param type_name: The name of the type of extension_ to create.
Alex Gaynor6f719912015-09-20 09:21:29 -0400669 :type type_name: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800670
Alex Gaynor5945ea82015-09-05 14:59:06 -0400671 :param bool critical: A flag indicating whether this is a critical
672 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800673
674 :param value: The value of the extension.
Maximilian Hils0de43752015-09-18 15:26:54 +0200675 :type value: :py:data:`bytes`
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800676
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200677 :param subject: Optional X509 certificate to use as subject.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800678 :type subject: :py:class:`X509`
679
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200680 :param issuer: Optional X509 certificate to use as issuer.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800681 :type issuer: :py:class:`X509`
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100682
Hynek Schlawackc3b38e52016-10-15 14:56:14 +0200683 .. _extension: https://www.openssl.org/docs/manmaster/apps/
Hynek Schlawack8d4f9762016-03-19 08:15:03 +0100684 x509v3_config.html#STANDARD-EXTENSIONS
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800685 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500686 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800687
Alex Gaynor5945ea82015-09-05 14:59:06 -0400688 # A context is necessary for any extension which uses the r2i
689 # conversion method. That is, X509V3_EXT_nconf may segfault if passed
690 # a NULL ctx. Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500691 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800692
693 # We have no configuration database - but perhaps we should (some
694 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500695 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800696
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800697 # Initialize the subject and issuer, if appropriate. ctx is a local,
698 # and as far as I can tell none of the X509V3_* APIs invoked here steal
Alex Gaynora738ed52015-09-05 11:17:10 -0400699 # any references, so no need to mess with reference counts or
700 # duplicates.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800701 if issuer is not None:
702 if not isinstance(issuer, X509):
703 raise TypeError("issuer must be an X509 instance")
704 ctx.issuer_cert = issuer._x509
705 if subject is not None:
706 if not isinstance(subject, X509):
707 raise TypeError("subject must be an X509 instance")
708 ctx.subject_cert = subject._x509
709
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800710 if critical:
711 # There are other OpenSSL APIs which would let us pass in critical
712 # separately, but they're harder to use, and since value is already
713 # a pile of crappy junk smuggling a ton of utterly important
714 # structured data, what's the point of trying to avoid nasty stuff
Alex Gaynor5945ea82015-09-05 14:59:06 -0400715 # with strings? (However, X509V3_EXT_i2d in particular seems like
716 # it would be a better API to invoke. I do not know where to get
717 # the ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500718 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800719
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500720 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
721 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800722 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500723 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800724
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400725 @property
726 def _nid(self):
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400727 return _lib.OBJ_obj2nid(
728 _lib.X509_EXTENSION_get_object(self._extension)
729 )
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400730
731 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500732 _lib.GEN_EMAIL: "email",
733 _lib.GEN_DNS: "DNS",
734 _lib.GEN_URI: "URI",
Alex Gaynora738ed52015-09-05 11:17:10 -0400735 }
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400736
737 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500738 method = _lib.X509V3_EXT_get(self._extension)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700739 _openssl_assert(method != _ffi.NULL)
Paul Kehrere8f91cc2016-03-09 21:26:29 -0400740 ext_data = _lib.X509_EXTENSION_get_data(self._extension)
741 payload = ext_data.data
742 length = ext_data.length
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400743
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500744 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400745 payloadptr[0] = payload
746
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500747 if method.it != _ffi.NULL:
748 ptr = _lib.ASN1_ITEM_ptr(method.it)
749 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
750 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400751 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500752 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400753 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500754 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400755
Paul Kehrerb7d79502015-05-04 07:43:51 -0500756 names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400757 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500758 for i in range(_lib.sk_GENERAL_NAME_num(names)):
759 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400760 try:
761 label = self._prefixes[name.type]
762 except KeyError:
763 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500764 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500765 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400766 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500767 value = _native(
768 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
769 parts.append(label + ":" + value)
770 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400771
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800772 def __str__(self):
773 """
774 :return: a nice text representation of the extension
775 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500776 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400777 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800778
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400779 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500780 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400781 _openssl_assert(print_result != 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800782
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500783 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800784
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800785 def get_critical(self):
786 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200787 Returns the critical field of this X.509 extension.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800788
789 :return: The critical field.
790 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500791 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800792
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800793 def get_short_name(self):
794 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200795 Returns the short type name of this X.509 extension.
796
797 The result is a byte string such as :py:const:`b"basicConstraints"`.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800798
799 :return: The short type name.
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200800 :rtype: :py:data:`bytes`
801
802 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800803 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500804 obj = _lib.X509_EXTENSION_get_object(self._extension)
805 nid = _lib.OBJ_obj2nid(obj)
806 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800807
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800808 def get_data(self):
809 """
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200810 Returns the data of the X509 extension, encoded as ASN.1.
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800811
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200812 :return: The ASN.1 encoded data of this X509 extension.
813 :rtype: :py:data:`bytes`
814
815 .. versionadded:: 0.12
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800816 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500817 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
818 string_result = _ffi.cast('ASN1_STRING*', octet_result)
819 char_result = _lib.ASN1_STRING_data(string_result)
820 result_length = _lib.ASN1_STRING_length(string_result)
821 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800822
Laurens Van Houtven2650de52014-06-18 13:47:47 +0200823
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800824X509ExtensionType = X509Extension
825
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800826
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800827class X509Req(object):
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200828 """
829 An X.509 certificate signing requests.
830 """
Alex Gaynora738ed52015-09-05 11:17:10 -0400831
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800832 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500833 req = _lib.X509_REQ_new()
834 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Alex Gaynor5af32d02016-09-24 01:52:21 -0400835 # Default to version 0.
836 self.set_version(0)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800837
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800838 def set_pubkey(self, pkey):
839 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200840 Set the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800841
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200842 :param pkey: The public key to use.
843 :type pkey: :py:class:`PKey`
844
Dan Sully44e767a2016-06-04 18:05:27 -0700845 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800846 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500847 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400848 _openssl_assert(set_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800849
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850 def get_pubkey(self):
851 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200852 Get the public key of the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800853
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200854 :return: The public key.
855 :rtype: :py:class:`PKey`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800856 """
857 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500858 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700859 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500860 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800861 pkey._only_public = True
862 return pkey
863
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800864 def set_version(self, version):
865 """
866 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
867 request.
868
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200869 :param int version: The version number.
Dan Sully44e767a2016-06-04 18:05:27 -0700870 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800871 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500872 set_result = _lib.X509_REQ_set_version(self._req, version)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -0400873 _openssl_assert(set_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800874
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800875 def get_version(self):
876 """
877 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
878 request.
879
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200880 :return: The value of the version subfield.
881 :rtype: :py:class:`int`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800882 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500883 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800884
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800885 def get_subject(self):
886 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200887 Return the subject of this certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800888
Cory Benfield881dc8d2015-12-09 08:25:14 +0000889 This creates a new :class:`X509Name` that wraps the underlying subject
890 name field on the certificate signing request. Modifying it will modify
891 the underlying signing request, and will have the effect of modifying
892 any other :class:`X509Name` that refers to this subject.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200893
894 :return: The subject of this certificate signing request.
Cory Benfield881dc8d2015-12-09 08:25:14 +0000895 :rtype: :class:`X509Name`
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800896 """
897 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500898 name._name = _lib.X509_REQ_get_subject_name(self._req)
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700899 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800900
901 # The name is owned by the X509Req structure. As long as the X509Name
902 # Python object is alive, keep the X509Req Python object alive.
903 name._owner = self
904
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800905 return name
906
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800907 def add_extensions(self, extensions):
908 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200909 Add extensions to the certificate signing request.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800910
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200911 :param extensions: The X.509 extensions to add.
912 :type extensions: iterable of :py:class:`X509Extension`
Dan Sully44e767a2016-06-04 18:05:27 -0700913 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800914 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500915 stack = _lib.sk_X509_EXTENSION_new_null()
Alex Gaynorfb8a2a12016-06-04 18:26:26 -0700916 _openssl_assert(stack != _ffi.NULL)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800917
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500918 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800919
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800920 for ext in extensions:
921 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800922 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800923
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800924 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500925 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800926
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500927 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400928 _openssl_assert(add_result == 1)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800929
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800930 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800931 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200932 Get X.509 extensions in the certificate signing request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800933
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200934 :return: The X.509 extensions in this request.
935 :rtype: :py:class:`list` of :py:class:`X509Extension` objects.
936
937 .. versionadded:: 0.15
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800938 """
939 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500940 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500941 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800942 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500943 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800944 exts.append(ext)
945 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800946
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800947 def sign(self, pkey, digest):
948 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -0700949 Sign the certificate signing request with this key and digest type.
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800950
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200951 :param pkey: The key pair to sign with.
952 :type pkey: :py:class:`PKey`
953 :param digest: The name of the message digest to use for the signature,
Alex Gaynor239e2d32016-09-11 12:36:35 -0400954 e.g. :py:data:`b"sha256"`.
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200955 :type digest: :py:class:`bytes`
Dan Sully44e767a2016-06-04 18:05:27 -0700956 :return: ``None``
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800957 """
958 if pkey._only_public:
959 raise ValueError("Key has only public part")
960
961 if not pkey._initialized:
962 raise ValueError("Key is uninitialized")
963
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500964 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500965 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800966 raise ValueError("No such digest method")
967
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500968 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Alex Gaynor09a386e2016-07-03 09:32:44 -0400969 _openssl_assert(sign_result > 0)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800970
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800971 def verify(self, pkey):
972 """
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200973 Verifies the signature on this certificate signing request.
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800974
Laurens Van Houtven3e83d242014-06-18 14:29:47 +0200975 :param key: A public key.
976 :type key: :py:class:`PKey`
977 :return: :py:data:`True` if the signature is correct.
978 :rtype: :py:class:`bool`
979 :raises Error: If the signature is invalid or there is a
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800980 problem verifying the signature.
981 """
982 if not isinstance(pkey, PKey):
983 raise TypeError("pkey must be a PKey instance")
984
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500985 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800986 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500987 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800988
989 return result
990
991
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800992X509ReqType = X509Req
993
994
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800995class X509(object):
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +0200996 """
997 An X.509 certificate.
998 """
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800999 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001000 x509 = _lib.X509_new()
Hynek Schlawack8a2dd772016-07-31 13:46:20 +02001001 _openssl_assert(x509 != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001002 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001003
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001004 def set_version(self, version):
1005 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001006 Set the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001007
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001008 :param version: The version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001009 :type version: :py:class:`int`
1010
Dan Sully44e767a2016-06-04 18:05:27 -07001011 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001012 """
1013 if not isinstance(version, int):
1014 raise TypeError("version must be an integer")
1015
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001016 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001017
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001018 def get_version(self):
1019 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001020 Return the version number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001021
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001022 :return: The version number of the certificate.
1023 :rtype: :py:class:`int`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001024 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001025 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001026
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001027 def get_pubkey(self):
1028 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001029 Get the public key of the certificate.
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001030
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001031 :return: The public key.
1032 :rtype: :py:class:`PKey`
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001033 """
1034 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001035 pkey._pkey = _lib.X509_get_pubkey(self._x509)
1036 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001037 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001038 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001039 pkey._only_public = True
1040 return pkey
1041
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001042 def set_pubkey(self, pkey):
1043 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001044 Set the public key of the certificate.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001045
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001046 :param pkey: The public key.
1047 :type pkey: :py:class:`PKey`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001048
Laurens Van Houtven33fcf122015-04-23 10:50:08 -07001049 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001050 """
1051 if not isinstance(pkey, PKey):
1052 raise TypeError("pkey must be a PKey instance")
1053
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001054 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Alex Gaynor7778e792016-07-03 23:38:48 -04001055 _openssl_assert(set_result == 1)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001056
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001057 def sign(self, pkey, digest):
1058 """
Laurens Van Houtven6f2e4262015-04-23 10:48:32 -07001059 Sign the certificate with this key and digest type.
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001060
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001061 :param pkey: The key to sign with.
1062 :type pkey: :py:class:`PKey`
1063
1064 :param digest: The name of the message digest to use.
1065 :type digest: :py:class:`bytes`
1066
Laurens Van Houtvena367fe82015-04-23 10:49:12 -07001067 :return: :py:data:`None`
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001068 """
1069 if not isinstance(pkey, PKey):
1070 raise TypeError("pkey must be a PKey instance")
1071
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -08001072 if pkey._only_public:
1073 raise ValueError("Key only has public part")
1074
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -08001075 if not pkey._initialized:
1076 raise ValueError("Key is uninitialized")
1077
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001078 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001079 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001080 raise ValueError("No such digest method")
1081
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001082 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Alex Gaynor5bb2bd12016-07-03 10:48:32 -04001083 _openssl_assert(sign_result > 0)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001084
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001085 def get_signature_algorithm(self):
1086 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001087 Return the signature algorithm used in the certificate.
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001088
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001089 :return: The name of the algorithm.
1090 :rtype: :py:class:`bytes`
1091
1092 :raises ValueError: If the signature algorithm is undefined.
1093
Laurens Van Houtven0dd87402015-04-23 10:47:18 -07001094 .. versionadded:: 0.13
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001095 """
Alex Gaynor39ea5312016-06-02 09:12:10 -07001096 algor = _lib.X509_get0_tbs_sigalg(self._x509)
1097 nid = _lib.OBJ_obj2nid(algor.algorithm)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001098 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001099 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001100 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001101
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001102 def digest(self, digest_name):
1103 """
1104 Return the digest of the X509 object.
1105
1106 :param digest_name: The name of the digest algorithm to use.
1107 :type digest_name: :py:class:`bytes`
1108
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001109 :return: The digest of the object, formatted as
1110 :py:const:`b":"`-delimited hex pairs.
1111 :rtype: :py:class:`bytes`
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001112 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001113 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001114 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001115 raise ValueError("No such digest method")
1116
Paul Kehrer9f9113a2016-09-20 20:10:25 -05001117 result_buffer = _ffi.new("unsigned char[]", _lib.EVP_MAX_MD_SIZE)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001118 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001119 result_length[0] = len(result_buffer)
1120
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001121 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001122 self._x509, digest, result_buffer, result_length)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001123 _openssl_assert(digest_result == 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001124
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001125 return b":".join([
Alex Gaynora738ed52015-09-05 11:17:10 -04001126 b16encode(ch).upper() for ch
1127 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001128
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001129 def subject_name_hash(self):
1130 """
1131 Return the hash of the X509 subject.
1132
1133 :return: The hash of the subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001134 :rtype: :py:class:`bytes`
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001135 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001136 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001137
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001138 def set_serial_number(self, serial):
1139 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001140 Set the serial number of the certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001141
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001142 :param serial: The new serial number.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001143 :type serial: :py:class:`int`
1144
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001145 :return: :py:data`None`
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001146 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001147 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001148 raise TypeError("serial must be an integer")
1149
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001150 hex_serial = hex(serial)[2:]
1151 if not isinstance(hex_serial, bytes):
1152 hex_serial = hex_serial.encode('ascii')
1153
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001154 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001155
1156 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
Alex Gaynor5945ea82015-09-05 14:59:06 -04001157 # it. If bignum is still NULL after this call, then the return value
1158 # is actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001159 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001160
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001161 if bignum_serial[0] == _ffi.NULL:
1162 set_result = _lib.ASN1_INTEGER_set(
1163 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001164 if set_result:
1165 # TODO Not tested
1166 _raise_current_error()
1167 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001168 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1169 _lib.BN_free(bignum_serial[0])
1170 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001171 # TODO Not tested
1172 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001173 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1174 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Alex Gaynor37726112016-07-04 09:51:32 -04001175 _openssl_assert(set_result == 1)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001176
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001177 def get_serial_number(self):
1178 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001179 Return the serial number of this certificate.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001180
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001181 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001182 :rtype: int
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001183 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001184 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1185 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001186 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001187 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001188 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001189 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001190 serial = int(hexstring_serial, 16)
1191 return serial
1192 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001193 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001194 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001195 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001196
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001197 def gmtime_adj_notAfter(self, amount):
1198 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001199 Adjust the time stamp on which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001200
Dan Sully44e767a2016-06-04 18:05:27 -07001201 :param int amount: The number of seconds by which to adjust the
1202 timestamp.
1203 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001204 """
1205 if not isinstance(amount, int):
1206 raise TypeError("amount must be an integer")
1207
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001208 notAfter = _lib.X509_get_notAfter(self._x509)
1209 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001210
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001211 def gmtime_adj_notBefore(self, amount):
1212 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001213 Adjust the timestamp on which the certificate starts being valid.
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001214
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001215 :param amount: The number of seconds by which to adjust the timestamp.
Dan Sully44e767a2016-06-04 18:05:27 -07001216 :return: ``None``
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001217 """
1218 if not isinstance(amount, int):
1219 raise TypeError("amount must be an integer")
1220
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001221 notBefore = _lib.X509_get_notBefore(self._x509)
1222 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001223
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001224 def has_expired(self):
1225 """
1226 Check whether the certificate has expired.
1227
Dan Sully44e767a2016-06-04 18:05:27 -07001228 :return: ``True`` if the certificate has expired, ``False`` otherwise.
1229 :rtype: bool
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001230 """
Paul Kehrer8d887e12015-10-24 09:09:55 -05001231 time_string = _native(self.get_notAfter())
Paul Kehrerfde45c92016-01-21 12:57:37 -06001232 not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ")
Paul Kehrer5d5d28d2015-10-21 18:55:22 -05001233
Paul Kehrerfde45c92016-01-21 12:57:37 -06001234 return not_after < datetime.datetime.utcnow()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001235
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001236 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001237 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001238
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001239 def get_notBefore(self):
1240 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001241 Get the timestamp at which the certificate starts being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001242
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001243 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001244
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001245 YYYYMMDDhhmmssZ
1246 YYYYMMDDhhmmss+hhmm
1247 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001248
Dan Sully44e767a2016-06-04 18:05:27 -07001249 :return: A timestamp string, or ``None`` if there is none.
1250 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001251 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001252 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001253
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001254 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001255 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001256
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001257 def set_notBefore(self, when):
1258 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001259 Set the timestamp at which the certificate starts being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001260
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001261 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001262
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001263 YYYYMMDDhhmmssZ
1264 YYYYMMDDhhmmss+hhmm
1265 YYYYMMDDhhmmss-hhmm
1266
Dan Sully44e767a2016-06-04 18:05:27 -07001267 :param bytes when: A timestamp string.
1268 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001269 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001270 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001271
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001272 def get_notAfter(self):
1273 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001274 Get the timestamp at which the certificate stops being valid.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001275
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001276 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001277
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001278 YYYYMMDDhhmmssZ
1279 YYYYMMDDhhmmss+hhmm
1280 YYYYMMDDhhmmss-hhmm
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001281
Dan Sully44e767a2016-06-04 18:05:27 -07001282 :return: A timestamp string, or ``None`` if there is none.
1283 :rtype: bytes or NoneType
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001284 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001285 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001286
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001287 def set_notAfter(self, when):
1288 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001289 Set the timestamp at which the certificate stops being valid.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001290
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001291 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001292
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001293 YYYYMMDDhhmmssZ
1294 YYYYMMDDhhmmss+hhmm
1295 YYYYMMDDhhmmss-hhmm
1296
Dan Sully44e767a2016-06-04 18:05:27 -07001297 :param bytes when: A timestamp string.
1298 :return: ``None``
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001299 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001300 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001301
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001302 def _get_name(self, which):
1303 name = X509Name.__new__(X509Name)
1304 name._name = which(self._x509)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001305 _openssl_assert(name._name != _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001306
1307 # The name is owned by the X509 structure. As long as the X509Name
1308 # Python object is alive, keep the X509 Python object alive.
1309 name._owner = self
1310
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001311 return name
1312
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001313 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001314 if not isinstance(name, X509Name):
1315 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001316 set_result = which(self._x509, name._name)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001317 _openssl_assert(set_result == 1)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001318
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001319 def get_issuer(self):
1320 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001321 Return the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001322
Cory Benfielde6bcce82015-12-09 08:40:03 +00001323 This creates a new :class:`X509Name` that wraps the underlying issuer
1324 name field on the certificate. Modifying it will modify the underlying
1325 certificate, and will have the effect of modifying any other
1326 :class:`X509Name` that refers to this issuer.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001327
1328 :return: The issuer of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001329 :rtype: :class:`X509Name`
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001330 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001331 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001332
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001333 def set_issuer(self, issuer):
1334 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001335 Set the issuer of this certificate.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001336
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001337 :param issuer: The issuer.
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001338 :type issuer: :py:class:`X509Name`
1339
Dan Sully44e767a2016-06-04 18:05:27 -07001340 :return: ``None``
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001341 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001342 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001343
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001344 def get_subject(self):
1345 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001346 Return the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001347
Cory Benfielde6bcce82015-12-09 08:40:03 +00001348 This creates a new :class:`X509Name` that wraps the underlying subject
1349 name field on the certificate. Modifying it will modify the underlying
1350 certificate, and will have the effect of modifying any other
1351 :class:`X509Name` that refers to this subject.
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001352
1353 :return: The subject of this certificate.
Cory Benfielde6bcce82015-12-09 08:40:03 +00001354 :rtype: :class:`X509Name`
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001355 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001356 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001357
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001358 def set_subject(self, subject):
1359 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001360 Set the subject of this certificate.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001361
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001362 :param subject: The subject.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001363 :type subject: :py:class:`X509Name`
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001364
Dan Sully44e767a2016-06-04 18:05:27 -07001365 :return: ``None``
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001366 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001367 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001368
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001369 def get_extension_count(self):
1370 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001371 Get the number of extensions on this certificate.
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001372
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001373 :return: The number of extensions.
1374 :rtype: :py:class:`int`
1375
1376 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001377 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001378 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001379
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001380 def add_extensions(self, extensions):
1381 """
1382 Add extensions to the certificate.
1383
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001384 :param extensions: The extensions to add.
1385 :type extensions: An iterable of :py:class:`X509Extension` objects.
Dan Sully44e767a2016-06-04 18:05:27 -07001386 :return: ``None``
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001387 """
1388 for ext in extensions:
1389 if not isinstance(ext, X509Extension):
1390 raise ValueError("One of the elements is not an X509Extension")
1391
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001392 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001393 if not add_result:
1394 _raise_current_error()
1395
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001396 def get_extension(self, index):
1397 """
1398 Get a specific extension of the certificate by index.
1399
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02001400 Extensions on a certificate are kept in order. The index
1401 parameter selects which extension will be returned.
1402
1403 :param int index: The index of the extension to retrieve.
1404 :return: The extension at the specified index.
1405 :rtype: :py:class:`X509Extension`
1406 :raises IndexError: If the extension index was out of bounds.
1407
1408 .. versionadded:: 0.12
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001409 """
1410 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001411 ext._extension = _lib.X509_get_ext(self._x509, index)
1412 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001413 raise IndexError("extension index out of bounds")
1414
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001415 extension = _lib.X509_EXTENSION_dup(ext._extension)
1416 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001417 return ext
1418
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001419
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001420X509Type = X509
1421
1422
Dan Sully44e767a2016-06-04 18:05:27 -07001423class X509StoreFlags(object):
1424 """
1425 Flags for X509 verification, used to change the behavior of
1426 :class:`X509Store`.
1427
1428 See `OpenSSL Verification Flags`_ for details.
1429
1430 .. _OpenSSL Verification Flags:
1431 https://www.openssl.org/docs/manmaster/crypto/X509_VERIFY_PARAM_set_flags.html
1432 """
1433 CRL_CHECK = _lib.X509_V_FLAG_CRL_CHECK
1434 CRL_CHECK_ALL = _lib.X509_V_FLAG_CRL_CHECK_ALL
1435 IGNORE_CRITICAL = _lib.X509_V_FLAG_IGNORE_CRITICAL
1436 X509_STRICT = _lib.X509_V_FLAG_X509_STRICT
1437 ALLOW_PROXY_CERTS = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS
1438 POLICY_CHECK = _lib.X509_V_FLAG_POLICY_CHECK
1439 EXPLICIT_POLICY = _lib.X509_V_FLAG_EXPLICIT_POLICY
1440 INHIBIT_MAP = _lib.X509_V_FLAG_INHIBIT_MAP
1441 NOTIFY_POLICY = _lib.X509_V_FLAG_NOTIFY_POLICY
1442 CHECK_SS_SIGNATURE = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE
1443 CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK
1444
1445
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001446class X509Store(object):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001447 """
Dan Sully44e767a2016-06-04 18:05:27 -07001448 An X.509 store.
1449
1450 An X.509 store is used to describe a context in which to verify a
1451 certificate. A description of a context may include a set of certificates
1452 to trust, a set of certificate revocation lists, verification flags and
1453 more.
1454
1455 An X.509 store, being only a description, cannot be used by itself to
1456 verify a certificate. To carry out the actual verification process, see
1457 :class:`X509StoreContext`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001458 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001459
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001460 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001461 store = _lib.X509_STORE_new()
1462 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001463
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001464 def add_cert(self, cert):
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001465 """
Dan Sully44e767a2016-06-04 18:05:27 -07001466 Adds a trusted certificate to this store.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001467
Dan Sully44e767a2016-06-04 18:05:27 -07001468 Adding a certificate with this method adds this certificate as a
1469 *trusted* certificate.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001470
1471 :param X509 cert: The certificate to add to this store.
Dan Sully44e767a2016-06-04 18:05:27 -07001472 :raises TypeError: If the certificate is not an :class:`X509`.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001473 :raises Error: If OpenSSL was unhappy with your certificate.
Dan Sully44e767a2016-06-04 18:05:27 -07001474 :return: ``None`` if the certificate was added successfully.
Laurens Van Houtvenef5c83d2014-06-17 15:32:27 +02001475 """
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001476 if not isinstance(cert, X509):
1477 raise TypeError()
1478
Dan Sully44e767a2016-06-04 18:05:27 -07001479 _openssl_assert(_lib.X509_STORE_add_cert(self._store, cert._x509) != 0)
1480
1481 def add_crl(self, crl):
1482 """
1483 Add a certificate revocation list to this store.
1484
1485 The certificate revocation lists added to a store will only be used if
1486 the associated flags are configured to check certificate revocation
1487 lists.
1488
1489 .. versionadded:: 16.1.0
1490
1491 :param CRL crl: The certificate revocation list to add to this store.
1492 :return: ``None`` if the certificate revocation list was added
1493 successfully.
1494 """
1495 _openssl_assert(_lib.X509_STORE_add_crl(self._store, crl._crl) != 0)
1496
1497 def set_flags(self, flags):
1498 """
1499 Set verification flags to this store.
1500
1501 Verification flags can be combined by oring them together.
1502
1503 .. note::
1504
1505 Setting a verification flag sometimes requires clients to add
1506 additional information to the store, otherwise a suitable error will
1507 be raised.
1508
1509 For example, in setting flags to enable CRL checking a
1510 suitable CRL must be added to the store otherwise an error will be
1511 raised.
1512
1513 .. versionadded:: 16.1.0
1514
1515 :param int flags: The verification flags to set on this store.
1516 See :class:`X509StoreFlags` for available constants.
1517 :return: ``None`` if the verification flags were successfully set.
1518 """
1519 _openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0)
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001520
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001521
1522X509StoreType = X509Store
1523
1524
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001525class X509StoreContextError(Exception):
1526 """
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001527 An exception raised when an error occurred while verifying a certificate
1528 using `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001529
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001530 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001531 :type certificate: :class:`X509`
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001532 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001533
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001534 def __init__(self, message, certificate):
1535 super(X509StoreContextError, self).__init__(message)
1536 self.certificate = certificate
1537
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001538
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001539class X509StoreContext(object):
1540 """
1541 An X.509 store context.
1542
Dan Sully44e767a2016-06-04 18:05:27 -07001543 An X.509 store context is used to carry out the actual verification process
1544 of a certificate in a described context. For describing such a context, see
1545 :class:`X509Store`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001546
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001547 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1548 instance. It is dynamically allocated and automatically garbage
1549 collected.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001550 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001551 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001552 :param X509Store store: The certificates which will be trusted for the
1553 purposes of any verifications.
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001554 :param X509 certificate: The certificate to be verified.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001555 """
1556
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001557 def __init__(self, store, certificate):
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001558 store_ctx = _lib.X509_STORE_CTX_new()
1559 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1560 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001561 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001562 # Make the store context available for use after instantiating this
1563 # class by initializing it now. Per testing, subsequent calls to
Dan Sully44e767a2016-06-04 18:05:27 -07001564 # :meth:`_init` have no adverse affect.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001565 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001566
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001567 def _init(self):
1568 """
1569 Set up the store context for a subsequent verification operation.
1570 """
Alex Gaynor5945ea82015-09-05 14:59:06 -04001571 ret = _lib.X509_STORE_CTX_init(
1572 self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL
1573 )
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001574 if ret <= 0:
1575 _raise_current_error()
1576
1577 def _cleanup(self):
1578 """
1579 Internally cleans up the store context.
1580
Dan Sully44e767a2016-06-04 18:05:27 -07001581 The store context can then be reused with a new call to :meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001582 """
1583 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1584
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001585 def _exception_from_context(self):
1586 """
1587 Convert an OpenSSL native context error failure into a Python
1588 exception.
1589
Alex Gaynor5945ea82015-09-05 14:59:06 -04001590 When a call to native OpenSSL X509_verify_cert fails, additional
1591 information about the failure can be obtained from the store context.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001592 """
1593 errors = [
1594 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1595 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1596 _native(_ffi.string(_lib.X509_verify_cert_error_string(
Alex Gaynor5945ea82015-09-05 14:59:06 -04001597 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001598 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001599 # A context error should always be associated with a certificate, so we
1600 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001601 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001602 _cert = _lib.X509_dup(_x509)
1603 pycert = X509.__new__(X509)
1604 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001605 return X509StoreContextError(errors, pycert)
1606
Stephen Holsapple46a09252015-02-12 14:45:43 -08001607 def set_store(self, store):
1608 """
Dan Sully44e767a2016-06-04 18:05:27 -07001609 Set the context's X.509 store.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001610
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001611 .. versionadded:: 0.15
1612
Dan Sully44e767a2016-06-04 18:05:27 -07001613 :param X509Store store: The store description which will be used for
1614 the purposes of any *future* verifications.
Stephen Holsapple46a09252015-02-12 14:45:43 -08001615 """
1616 self._store = store
1617
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001618 def verify_certificate(self):
1619 """
1620 Verify a certificate in a context.
1621
Stephen Holsapple8ad4a192015-06-09 22:51:43 -07001622 .. versionadded:: 0.15
1623
Alex Gaynorca87ff62015-09-04 23:31:03 -04001624 :raises X509StoreContextError: If an error occurred when validating a
Alex Gaynor5945ea82015-09-05 14:59:06 -04001625 certificate in the context. Sets ``certificate`` attribute to
1626 indicate which certificate caused the error.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001627 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001628 # Always re-initialize the store context in case
Dan Sully44e767a2016-06-04 18:05:27 -07001629 # :meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001630 self._init()
1631 ret = _lib.X509_verify_cert(self._store_ctx)
1632 self._cleanup()
1633 if ret <= 0:
1634 raise self._exception_from_context()
1635
1636
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001637def load_certificate(type, buffer):
1638 """
1639 Load a certificate from a buffer
1640
1641 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
1642
Dan Sully44e767a2016-06-04 18:05:27 -07001643 :param bytes buffer: The buffer the certificate is stored in
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001644
1645 :return: The X509 object
1646 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001647 if isinstance(buffer, _text_type):
1648 buffer = buffer.encode("ascii")
1649
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001650 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001651
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001652 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001653 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001654 elif type == FILETYPE_ASN1:
Alex Gaynor962ac212015-09-04 08:06:42 -04001655 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001656 else:
1657 raise ValueError(
1658 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001659
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001660 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001661 _raise_current_error()
1662
1663 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001664 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001665 return cert
1666
1667
1668def dump_certificate(type, cert):
1669 """
1670 Dump a certificate to a buffer
1671
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001672 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1673 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001674 :param cert: The certificate to dump
1675 :return: The buffer with the dumped certificate in
1676 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001677 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001678
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001679 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001680 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001681 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001682 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001683 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001684 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001685 else:
1686 raise ValueError(
1687 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1688 "FILETYPE_TEXT")
1689
Alex Gaynorc7a9eb52015-09-05 16:57:49 -04001690 assert result_code == 1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001691 return _bio_to_string(bio)
1692
1693
Cory Benfield6492f7c2015-10-27 16:57:58 +09001694def dump_publickey(type, pkey):
1695 """
Cory Benfield11c10192015-10-27 17:23:03 +09001696 Dump a public key to a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09001697
Cory Benfield9c590b92015-10-28 14:55:05 +09001698 :param type: The file type (one of :data:`FILETYPE_PEM` or
Cory Benfielde813cec2015-10-28 08:57:08 +09001699 :data:`FILETYPE_ASN1`).
Cory Benfield2b6bb802015-10-28 22:19:31 +09001700 :param PKey pkey: The public key to dump
Cory Benfield6492f7c2015-10-27 16:57:58 +09001701 :return: The buffer with the dumped key in it.
Cory Benfield11c10192015-10-27 17:23:03 +09001702 :rtype: bytes
Cory Benfield6492f7c2015-10-27 16:57:58 +09001703 """
1704 bio = _new_mem_buf()
1705 if type == FILETYPE_PEM:
1706 write_bio = _lib.PEM_write_bio_PUBKEY
1707 elif type == FILETYPE_ASN1:
1708 write_bio = _lib.i2d_PUBKEY_bio
1709 else:
1710 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1711
1712 result_code = write_bio(bio, pkey._pkey)
Cory Benfield1e9c7ab2015-10-28 08:58:31 +09001713 if result_code != 1: # pragma: no cover
Cory Benfield6492f7c2015-10-27 16:57:58 +09001714 _raise_current_error()
1715
1716 return _bio_to_string(bio)
1717
1718
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001719def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1720 """
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001721 Dump the private key *pkey* into a buffer string encoded with the type
1722 *type*. Optionally (if *type* is :const:`FILETYPE_PEM`) encrypting it
1723 using *cipher* and *passphrase*.
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001724
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001725 :param type: The file type (one of :const:`FILETYPE_PEM`,
1726 :const:`FILETYPE_ASN1`, or :const:`FILETYPE_TEXT`)
1727 :param PKey pkey: The PKey to dump
1728 :param cipher: (optional) if encrypted PEM format, the cipher to use
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001729 :param passphrase: (optional) if encrypted PEM format, this can be either
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001730 the passphrase to use, or a callback for providing the passphrase.
1731
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001732 :return: The buffer with the dumped key in
Dan Sully44e767a2016-06-04 18:05:27 -07001733 :rtype: bytes
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001734 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001735 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001736
1737 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001738 if passphrase is None:
1739 raise TypeError(
1740 "if a value is given for cipher "
1741 "one must also be given for passphrase")
1742 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001743 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001744 raise ValueError("Invalid cipher name")
1745 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001746 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001747
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001748 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001749 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001750 result_code = _lib.PEM_write_bio_PrivateKey(
1751 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001752 helper.callback, helper.callback_args)
1753 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001754 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001755 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001756 elif type == FILETYPE_TEXT:
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001757 rsa = _ffi.gc(
1758 _lib.EVP_PKEY_get1_RSA(pkey._pkey),
1759 _lib.RSA_free
1760 )
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001761 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001762 else:
1763 raise ValueError(
1764 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1765 "FILETYPE_TEXT")
1766
Hynek Schlawack11e43ad2016-07-03 14:40:20 +02001767 _openssl_assert(result_code != 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001768
1769 return _bio_to_string(bio)
1770
1771
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001772class Revoked(object):
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001773 """
1774 A certificate revocation.
1775 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001776 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1777 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1778 # OCSP_crl_reason_str. We use the latter, just like the command line
1779 # program.
1780 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001781 b"unspecified",
1782 b"keyCompromise",
1783 b"CACompromise",
1784 b"affiliationChanged",
1785 b"superseded",
1786 b"cessationOfOperation",
1787 b"certificateHold",
1788 # b"removeFromCRL",
Alex Gaynorca87ff62015-09-04 23:31:03 -04001789 ]
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001790
1791 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001792 revoked = _lib.X509_REVOKED_new()
1793 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001794
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001795 def set_serial(self, hex_str):
1796 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001797 Set the serial number.
1798
1799 The serial number is formatted as a hexadecimal number encoded in
1800 ASCII.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001801
Dan Sully44e767a2016-06-04 18:05:27 -07001802 :param bytes hex_str: The new serial number.
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001803
Dan Sully44e767a2016-06-04 18:05:27 -07001804 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001805 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001806 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1807 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001808 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001809 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001810 if not bn_result:
1811 raise ValueError("bad hex string")
1812
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001813 asn1_serial = _ffi.gc(
1814 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1815 _lib.ASN1_INTEGER_free)
1816 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001817
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001818 def get_serial(self):
1819 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001820 Get the serial number.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001821
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001822 The serial number is formatted as a hexadecimal number encoded in
1823 ASCII.
1824
1825 :return: The serial number.
Dan Sully44e767a2016-06-04 18:05:27 -07001826 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001827 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001828 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001829
Alex Gaynor67903a62016-06-02 10:37:13 -07001830 asn1_int = _lib.X509_REVOKED_get0_serialNumber(self._revoked)
1831 _openssl_assert(asn1_int != _ffi.NULL)
1832 result = _lib.i2a_ASN1_INTEGER(bio, asn1_int)
1833 _openssl_assert(result >= 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001834 return _bio_to_string(bio)
1835
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001836 def _delete_reason(self):
Alex Gaynor67903a62016-06-02 10:37:13 -07001837 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1838 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001839 obj = _lib.X509_EXTENSION_get_object(ext)
1840 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001841 _lib.X509_EXTENSION_free(ext)
Alex Gaynor67903a62016-06-02 10:37:13 -07001842 _lib.X509_REVOKED_delete_ext(self._revoked, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001843 break
1844
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001845 def set_reason(self, reason):
1846 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001847 Set the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001848
Dan Sully44e767a2016-06-04 18:05:27 -07001849 If :data:`reason` is ``None``, delete the reason instead.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001850
1851 :param reason: The reason string.
Dan Sully44e767a2016-06-04 18:05:27 -07001852 :type reason: :class:`bytes` or :class:`NoneType`
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001853
Dan Sully44e767a2016-06-04 18:05:27 -07001854 :return: ``None``
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001855
1856 .. seealso::
1857
Dan Sully44e767a2016-06-04 18:05:27 -07001858 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001859 reasons which you might pass to this method.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001860 """
1861 if reason is None:
1862 self._delete_reason()
1863 elif not isinstance(reason, bytes):
1864 raise TypeError("reason must be None or a byte string")
1865 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001866 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001867 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1868
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001869 new_reason_ext = _lib.ASN1_ENUMERATED_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07001870 _openssl_assert(new_reason_ext != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001871 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001872
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001873 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001874 _openssl_assert(set_result != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001875
1876 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001877 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1878 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001879 _openssl_assert(add_result == 1)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001880
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001881 def get_reason(self):
1882 """
Alex Gaynor80262fb2016-04-22 07:53:42 -04001883 Get the reason of this revocation.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001884
Dan Sully44e767a2016-06-04 18:05:27 -07001885 :return: The reason, or ``None`` if there is none.
1886 :rtype: bytes or NoneType
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001887
1888 .. seealso::
1889
Dan Sully44e767a2016-06-04 18:05:27 -07001890 :meth:`all_reasons`, which gives you a list of all supported
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001891 reasons this method might return.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001892 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001893 for i in range(_lib.X509_REVOKED_get_ext_count(self._revoked)):
1894 ext = _lib.X509_REVOKED_get_ext(self._revoked, i)
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001895 obj = _lib.X509_EXTENSION_get_object(ext)
1896 if _lib.OBJ_obj2nid(obj) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001897 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001898
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001899 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001900 if not print_result:
Alex Gaynor5945ea82015-09-05 14:59:06 -04001901 print_result = _lib.M_ASN1_OCTET_STRING_print(
Paul Kehrere8f91cc2016-03-09 21:26:29 -04001902 bio, _lib.X509_EXTENSION_get_data(ext)
Alex Gaynor5945ea82015-09-05 14:59:06 -04001903 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04001904 _openssl_assert(print_result != 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001905
1906 return _bio_to_string(bio)
1907
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001908 def all_reasons(self):
1909 """
1910 Return a list of all the supported reason strings.
1911
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001912 This list is a copy; modifying it does not change the supported reason
1913 strings.
1914
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001915 :return: A list of reason strings.
Dan Sully44e767a2016-06-04 18:05:27 -07001916 :rtype: :class:`list` of :class:`bytes`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001917 """
1918 return self._crl_reasons[:]
1919
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001920 def set_rev_date(self, when):
1921 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001922 Set the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001923
Dan Sully44e767a2016-06-04 18:05:27 -07001924 :param bytes when: The timestamp of the revocation,
1925 as ASN.1 GENERALIZEDTIME.
1926 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001927 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001928 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1929 return _set_asn1_time(dt, when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001930
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001931 def get_rev_date(self):
1932 """
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001933 Get the revocation timestamp.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001934
Laurens Van Houtvend92f55c2014-06-19 17:08:41 +02001935 :return: The timestamp of the revocation, as ASN.1 GENERALIZEDTIME.
Dan Sully44e767a2016-06-04 18:05:27 -07001936 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001937 """
Alex Gaynor67903a62016-06-02 10:37:13 -07001938 dt = _lib.X509_REVOKED_get0_revocationDate(self._revoked)
1939 return _get_asn1_time(dt)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001940
1941
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001942class CRL(object):
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001943 """
1944 A certificate revocation list.
1945 """
Alex Gaynora738ed52015-09-05 11:17:10 -04001946
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001947 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001948 crl = _lib.X509_CRL_new()
1949 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001950
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001951 def get_revoked(self):
1952 """
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001953 Return the revocations in this certificate revocation list.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001954
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001955 These revocations will be provided by value, not by reference.
1956 That means it's okay to mutate them: it won't affect this CRL.
1957
1958 :return: The revocations in this CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07001959 :rtype: :class:`tuple` of :class:`Revocation`
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001960 """
1961 results = []
Alex Gaynor67903a62016-06-02 10:37:13 -07001962 revoked_stack = _lib.X509_CRL_get_REVOKED(self._crl)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001963 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1964 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Paul Kehrer2fe23b02016-03-09 22:02:15 -04001965 revoked_copy = _lib.Cryptography_X509_REVOKED_dup(revoked)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001966 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001967 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001968 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001969 if results:
1970 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001971
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001972 def add_revoked(self, revoked):
1973 """
1974 Add a revoked (by value not reference) to the CRL structure
1975
Laurens Van Houtvencb32e852014-06-19 17:36:28 +02001976 This revocation will be added by value, not by reference. That
1977 means it's okay to mutate it after adding: it won't affect
1978 this CRL.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001979
Dan Sully44e767a2016-06-04 18:05:27 -07001980 :param Revoked revoked: The new revocation.
1981 :return: ``None``
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001982 """
Paul Kehrer8dddb1a2016-03-09 21:48:04 -04001983 copy = _lib.Cryptography_X509_REVOKED_dup(revoked._revoked)
Alex Gaynoradd5b072016-06-04 21:04:00 -07001984 _openssl_assert(copy != _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001985
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001986 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Alex Gaynor09a386e2016-07-03 09:32:44 -04001987 _openssl_assert(add_result != 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001988
Dan Sully44e767a2016-06-04 18:05:27 -07001989 def get_issuer(self):
1990 """
1991 Get the CRL's issuer.
1992
1993 .. versionadded:: 16.1.0
1994
1995 :rtype: X509Name
1996 """
1997 _issuer = _lib.X509_NAME_dup(_lib.X509_CRL_get_issuer(self._crl))
1998 _openssl_assert(_issuer != _ffi.NULL)
1999 _issuer = _ffi.gc(_issuer, _lib.X509_NAME_free)
2000 issuer = X509Name.__new__(X509Name)
2001 issuer._name = _issuer
2002 return issuer
2003
2004 def set_version(self, version):
2005 """
2006 Set the CRL version.
2007
2008 .. versionadded:: 16.1.0
2009
2010 :param int version: The version of the CRL.
2011 :return: ``None``
2012 """
2013 _openssl_assert(_lib.X509_CRL_set_version(self._crl, version) != 0)
2014
2015 def _set_boundary_time(self, which, when):
2016 return _set_asn1_time(which(self._crl), when)
2017
2018 def set_lastUpdate(self, when):
2019 """
2020 Set when the CRL was last updated.
2021
2022 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2023
2024 YYYYMMDDhhmmssZ
2025 YYYYMMDDhhmmss+hhmm
2026 YYYYMMDDhhmmss-hhmm
2027
2028 .. versionadded:: 16.1.0
2029
2030 :param bytes when: A timestamp string.
2031 :return: ``None``
2032 """
2033 return self._set_boundary_time(_lib.X509_CRL_get_lastUpdate, when)
2034
2035 def set_nextUpdate(self, when):
2036 """
2037 Set when the CRL will next be udpated.
2038
2039 The timestamp is formatted as an ASN.1 GENERALIZEDTIME::
2040
2041 YYYYMMDDhhmmssZ
2042 YYYYMMDDhhmmss+hhmm
2043 YYYYMMDDhhmmss-hhmm
2044
2045 .. versionadded:: 16.1.0
2046
2047 :param bytes when: A timestamp string.
2048 :return: ``None``
2049 """
2050 return self._set_boundary_time(_lib.X509_CRL_get_nextUpdate, when)
2051
2052 def sign(self, issuer_cert, issuer_key, digest):
2053 """
2054 Sign the CRL.
2055
2056 Signing a CRL enables clients to associate the CRL itself with an
2057 issuer. Before a CRL is meaningful to other OpenSSL functions, it must
2058 be signed by an issuer.
2059
2060 This method implicitly sets the issuer's name based on the issuer
2061 certificate and private key used to sign the CRL.
2062
2063 .. versionadded:: 16.1.0
2064
2065 :param X509 issuer_cert: The issuer's certificate.
2066 :param PKey issuer_key: The issuer's private key.
2067 :param bytes digest: The digest method to sign the CRL with.
2068 """
2069 digest_obj = _lib.EVP_get_digestbyname(digest)
2070 _openssl_assert(digest_obj != _ffi.NULL)
2071 _lib.X509_CRL_set_issuer_name(
2072 self._crl, _lib.X509_get_subject_name(issuer_cert._x509))
2073 _lib.X509_CRL_sort(self._crl)
2074 result = _lib.X509_CRL_sign(self._crl, issuer_key._pkey, digest_obj)
2075 _openssl_assert(result != 0)
2076
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002077 def export(self, cert, key, type=FILETYPE_PEM, days=100,
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002078 digest=_UNSPECIFIED):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002079 """
Dan Sully44e767a2016-06-04 18:05:27 -07002080 Export the CRL as a string.
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002081
Dan Sully44e767a2016-06-04 18:05:27 -07002082 :param X509 cert: The certificate used to sign the CRL.
2083 :param PKey key: The key used to sign the CRL.
2084 :param int type: The export format, either :data:`FILETYPE_PEM`,
2085 :data:`FILETYPE_ASN1`, or :data:`FILETYPE_TEXT`.
Jean-Paul Calderonedf514012015-04-13 21:45:18 -04002086 :param int days: The number of days until the next update of this CRL.
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002087 :param bytes digest: The name of the message digest to use (eg
Alex Gaynor239e2d32016-09-11 12:36:35 -04002088 ``b"sha2566"``).
Dan Sully44e767a2016-06-04 18:05:27 -07002089 :rtype: bytes
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002090 """
Dan Sully44e767a2016-06-04 18:05:27 -07002091
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002092 if not isinstance(cert, X509):
2093 raise TypeError("cert must be an X509 instance")
2094 if not isinstance(key, PKey):
2095 raise TypeError("key must be a PKey instance")
2096 if not isinstance(type, int):
2097 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002098
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -04002099 if digest is _UNSPECIFIED:
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002100 _warn(
2101 "The default message digest (md5) is deprecated. "
2102 "Pass the name of a message digest explicitly.",
2103 category=DeprecationWarning,
2104 stacklevel=2,
2105 )
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002106 digest = b"md5"
Jean-Paul Calderone60432792015-04-13 12:26:07 -04002107
Jean-Paul Calderonecce22d02015-04-13 13:56:09 -04002108 digest_obj = _lib.EVP_get_digestbyname(digest)
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002109 if digest_obj == _ffi.NULL:
2110 raise ValueError("No such digest method")
2111
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002112 bio = _lib.BIO_new(_lib.BIO_s_mem())
Alex Gaynoradd5b072016-06-04 21:04:00 -07002113 _openssl_assert(bio != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002114
Alex Gaynora738ed52015-09-05 11:17:10 -04002115 # A scratch time object to give different values to different CRL
2116 # fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002117 sometime = _lib.ASN1_TIME_new()
Alex Gaynoradd5b072016-06-04 21:04:00 -07002118 _openssl_assert(sometime != _ffi.NULL)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002119
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002120 _lib.X509_gmtime_adj(sometime, 0)
2121 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002122
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002123 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
2124 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002125
Alex Gaynor5945ea82015-09-05 14:59:06 -04002126 _lib.X509_CRL_set_issuer_name(
2127 self._crl, _lib.X509_get_subject_name(cert._x509)
2128 )
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002129
Bulat Gaifullin2923dc02014-09-21 22:36:48 +04002130 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002131 if not sign_result:
2132 _raise_current_error()
2133
Dominic Chenf05b2122015-10-13 16:32:35 +00002134 return dump_crl(type, self)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002135
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08002136
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002137CRLType = CRL
2138
2139
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002140class PKCS7(object):
2141 def type_is_signed(self):
2142 """
2143 Check if this NID_pkcs7_signed object
2144
2145 :return: True if the PKCS7 is of type signed
2146 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002147 return bool(_lib.PKCS7_type_is_signed(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002148
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002149 def type_is_enveloped(self):
2150 """
2151 Check if this NID_pkcs7_enveloped object
2152
2153 :returns: True if the PKCS7 is of type enveloped
2154 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002155 return bool(_lib.PKCS7_type_is_enveloped(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002156
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002157 def type_is_signedAndEnveloped(self):
2158 """
2159 Check if this NID_pkcs7_signedAndEnveloped object
2160
2161 :returns: True if the PKCS7 is of type signedAndEnveloped
2162 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002163 return bool(_lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002164
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002165 def type_is_data(self):
2166 """
2167 Check if this NID_pkcs7_data object
2168
2169 :return: True if the PKCS7 is of type data
2170 """
Alex Gaynor3aeead92016-07-31 11:31:59 -04002171 return bool(_lib.PKCS7_type_is_data(self._pkcs7))
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002172
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002173 def get_type_name(self):
2174 """
2175 Returns the type name of the PKCS7 structure
2176
2177 :return: A string with the typename
2178 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002179 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
2180 string_type = _lib.OBJ_nid2sn(nid)
2181 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002182
2183PKCS7Type = PKCS7
2184
2185
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002186class PKCS12(object):
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002187 """
2188 A PKCS #12 archive.
2189 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002190
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002191 def __init__(self):
2192 self._pkey = None
2193 self._cert = None
2194 self._cacerts = None
2195 self._friendlyname = None
2196
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002197 def get_certificate(self):
2198 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002199 Get the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002200
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002201 :return: The certificate, or :py:const:`None` if there is none.
2202 :rtype: :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002203 """
2204 return self._cert
2205
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002206 def set_certificate(self, cert):
2207 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002208 Set the certificate in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002209
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002210 :param cert: The new certificate, or :py:const:`None` to unset it.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002211 :type cert: :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002212
Dan Sully44e767a2016-06-04 18:05:27 -07002213 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002214 """
2215 if not isinstance(cert, X509):
2216 raise TypeError("cert must be an X509 instance")
2217 self._cert = cert
2218
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002219 def get_privatekey(self):
2220 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002221 Get the private key in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002222
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002223 :return: The private key, or :py:const:`None` if there is none.
2224 :rtype: :py:class:`PKey`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002225 """
2226 return self._pkey
2227
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002228 def set_privatekey(self, pkey):
2229 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002230 Set the certificate portion of the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002231
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002232 :param pkey: The new private key, or :py:const:`None` to unset it.
2233 :type pkey: :py:class:`PKey` or :py:const:`None`
2234
Dan Sully44e767a2016-06-04 18:05:27 -07002235 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002236 """
2237 if not isinstance(pkey, PKey):
2238 raise TypeError("pkey must be a PKey instance")
2239 self._pkey = pkey
2240
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002241 def get_ca_certificates(self):
2242 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002243 Get the CA certificates in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002244
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002245 :return: A tuple with the CA certificates in the chain, or
2246 :py:const:`None` if there are none.
2247 :rtype: :py:class:`tuple` of :py:class:`X509` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002248 """
2249 if self._cacerts is not None:
2250 return tuple(self._cacerts)
2251
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002252 def set_ca_certificates(self, cacerts):
2253 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002254 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002255
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002256 :param cacerts: The new CA certificates, or :py:const:`None` to unset
2257 them.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002258 :type cacerts: An iterable of :py:class:`X509` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002259
Dan Sully44e767a2016-06-04 18:05:27 -07002260 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002261 """
2262 if cacerts is None:
2263 self._cacerts = None
2264 else:
2265 cacerts = list(cacerts)
2266 for cert in cacerts:
2267 if not isinstance(cert, X509):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002268 raise TypeError(
2269 "iterable must only contain X509 instances"
2270 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002271 self._cacerts = cacerts
2272
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002273 def set_friendlyname(self, name):
2274 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002275 Set the friendly name in the PKCS #12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002276
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002277 :param name: The new friendly name, or :py:const:`None` to unset.
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002278 :type name: :py:class:`bytes` or :py:const:`None`
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002279
Dan Sully44e767a2016-06-04 18:05:27 -07002280 :return: ``None``
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002281 """
2282 if name is None:
2283 self._friendlyname = None
2284 elif not isinstance(name, bytes):
Alex Gaynor5945ea82015-09-05 14:59:06 -04002285 raise TypeError(
2286 "name must be a byte string or None (not %r)" % (name,)
2287 )
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002288 self._friendlyname = name
2289
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002290 def get_friendlyname(self):
2291 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002292 Get the friendly name in the PKCS# 12 structure.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002293
Laurens Van Houtvena7904582014-06-19 12:33:04 +02002294 :returns: The friendly name, or :py:const:`None` if there is none.
2295 :rtype: :py:class:`bytes` or :py:const:`None`
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002296 """
2297 return self._friendlyname
2298
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002299 def export(self, passphrase=None, iter=2048, maciter=1):
2300 """
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002301 Dump a PKCS12 object as a string.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002302
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002303 For more information, see the :c:func:`PKCS12_create` man page.
2304
2305 :param passphrase: The passphrase used to encrypt the structure. Unlike
2306 some other passphrase arguments, this *must* be a string, not a
2307 callback.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002308 :type passphrase: :py:data:`bytes`
2309
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002310 :param iter: Number of times to repeat the encryption step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002311 :type iter: :py:data:`int`
2312
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002313 :param maciter: Number of times to repeat the MAC step.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002314 :type maciter: :py:data:`int`
2315
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002316 :return: The string representation of the PKCS #12 structure.
2317 :rtype:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002318 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002319 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002320
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002321 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002322 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002323 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002324 cacerts = _lib.sk_X509_new_null()
2325 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002326 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002327 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002328
2329 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002330 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002331
2332 friendlyname = self._friendlyname
2333 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002334 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002335
2336 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002337 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002338 else:
2339 pkey = self._pkey._pkey
2340
2341 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002342 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002343 else:
2344 cert = self._cert._x509
2345
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002346 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002347 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002348 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2349 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002350 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002351 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002352 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002353 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002354
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002355 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002356 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002357 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002358
Laurens Van Houtvenbb503a32014-06-19 12:28:08 +02002359
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002360PKCS12Type = PKCS12
2361
2362
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002363class NetscapeSPKI(object):
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002364 """
2365 A Netscape SPKI object.
2366 """
Alex Gaynora738ed52015-09-05 11:17:10 -04002367
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002368 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002369 spki = _lib.NETSCAPE_SPKI_new()
2370 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002371
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002372 def sign(self, pkey, digest):
2373 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002374 Sign the certificate request with this key and digest type.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002375
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002376 :param pkey: The private key to sign with.
2377 :type pkey: :py:class:`PKey`
2378
2379 :param digest: The message digest to use.
2380 :type digest: :py:class:`bytes`
2381
Dan Sully44e767a2016-06-04 18:05:27 -07002382 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002383 """
2384 if pkey._only_public:
2385 raise ValueError("Key has only public part")
2386
2387 if not pkey._initialized:
2388 raise ValueError("Key is uninitialized")
2389
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002390 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002391 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002392 raise ValueError("No such digest method")
2393
Alex Gaynor5945ea82015-09-05 14:59:06 -04002394 sign_result = _lib.NETSCAPE_SPKI_sign(
2395 self._spki, pkey._pkey, digest_obj
2396 )
Alex Gaynor09a386e2016-07-03 09:32:44 -04002397 _openssl_assert(sign_result > 0)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002398
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002399 def verify(self, key):
2400 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002401 Verifies a signature on a certificate request.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002402
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002403 :param key: The public key that signature is supposedly from.
2404 :type pkey: :py:class:`PKey`
2405
2406 :return: :py:const:`True` if the signature is correct.
2407 :rtype: :py:class:`bool`
2408
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002409 :raises Error: If the signature is invalid, or there was a problem
2410 verifying the signature.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002411 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002412 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002413 if answer <= 0:
2414 _raise_current_error()
2415 return True
2416
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002417 def b64_encode(self):
2418 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002419 Generate a base64 encoded representation of this SPKI object.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002420
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002421 :return: The base64 encoded string.
2422 :rtype: :py:class:`bytes`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002423 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002424 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2425 result = _ffi.string(encoded)
Paul Kehrer0dcacf72016-03-17 19:25:39 -04002426 _lib.OPENSSL_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002427 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002428
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002429 def get_pubkey(self):
2430 """
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002431 Get the public key of this certificate.
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002432
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002433 :return: The public key.
2434 :rtype: :py:class:`PKey`
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002435 """
2436 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002437 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002438 _openssl_assert(pkey._pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002439 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002440 pkey._only_public = True
2441 return pkey
2442
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002443 def set_pubkey(self, pkey):
2444 """
2445 Set the public key of the certificate
2446
2447 :param pkey: The public key
Dan Sully44e767a2016-06-04 18:05:27 -07002448 :return: ``None``
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002449 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002450 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -04002451 _openssl_assert(set_result == 1)
Laurens Van Houtven59152b52014-06-19 16:42:30 +02002452
2453
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002454NetscapeSPKIType = NetscapeSPKI
2455
2456
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002457class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002458 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002459 if type != FILETYPE_PEM and passphrase is not None:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002460 raise ValueError(
2461 "only FILETYPE_PEM key format supports encryption"
2462 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002463 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002464 self._more_args = more_args
2465 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002466 self._problems = []
2467
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002468 @property
2469 def callback(self):
2470 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002471 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002472 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002473 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002474 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002475 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002476 else:
2477 raise TypeError("Last argument must be string or callable")
2478
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002479 @property
2480 def callback_args(self):
2481 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002482 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002483 elif isinstance(self._passphrase, bytes):
2484 return self._passphrase
2485 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002486 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002487 else:
2488 raise TypeError("Last argument must be string or callable")
2489
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002490 def raise_if_problem(self, exceptionType=Error):
2491 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002492 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002493 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002494 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002495 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002496 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002497 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002498
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002499 def _read_passphrase(self, buf, size, rwflag, userdata):
2500 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002501 if self._more_args:
2502 result = self._passphrase(size, rwflag, userdata)
2503 else:
2504 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002505 if not isinstance(result, bytes):
2506 raise ValueError("String expected")
2507 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002508 if self._truncate:
2509 result = result[:size]
2510 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002511 raise ValueError(
2512 "passphrase returned by callback is too long"
2513 )
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002514 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002515 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002516 return len(result)
2517 except Exception as e:
2518 self._problems.append(e)
2519 return 0
2520
2521
Cory Benfield6492f7c2015-10-27 16:57:58 +09002522def load_publickey(type, buffer):
2523 """
Cory Benfield11c10192015-10-27 17:23:03 +09002524 Load a public key from a buffer.
Cory Benfield6492f7c2015-10-27 16:57:58 +09002525
Cory Benfield9c590b92015-10-28 14:55:05 +09002526 :param type: The file type (one of :data:`FILETYPE_PEM`,
Cory Benfielde813cec2015-10-28 08:57:08 +09002527 :data:`FILETYPE_ASN1`).
Cory Benfieldc9c30a22015-10-28 17:39:20 +09002528 :param buffer: The buffer the key is stored in.
2529 :type buffer: A Python string object, either unicode or bytestring.
2530 :return: The PKey object.
2531 :rtype: :class:`PKey`
Cory Benfield6492f7c2015-10-27 16:57:58 +09002532 """
2533 if isinstance(buffer, _text_type):
2534 buffer = buffer.encode("ascii")
2535
2536 bio = _new_mem_buf(buffer)
2537
2538 if type == FILETYPE_PEM:
2539 evp_pkey = _lib.PEM_read_bio_PUBKEY(
2540 bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
2541 elif type == FILETYPE_ASN1:
2542 evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL)
2543 else:
2544 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2545
2546 if evp_pkey == _ffi.NULL:
2547 _raise_current_error()
2548
2549 pkey = PKey.__new__(PKey)
2550 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Paul Kehrer32fc4e62016-06-03 15:21:44 -07002551 pkey._only_public = True
Cory Benfield6492f7c2015-10-27 16:57:58 +09002552 return pkey
2553
2554
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002555def load_privatekey(type, buffer, passphrase=None):
2556 """
2557 Load a private key from a buffer
2558
2559 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2560 :param buffer: The buffer the key is stored in
2561 :param passphrase: (optional) if encrypted PEM format, this can be
2562 either the passphrase to use, or a callback for
2563 providing the passphrase.
2564
2565 :return: The PKey object
2566 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002567 if isinstance(buffer, _text_type):
2568 buffer = buffer.encode("ascii")
2569
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002570 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002571
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002572 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002573 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002574 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2575 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002576 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002577 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002578 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002579 else:
2580 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2581
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002582 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002583 _raise_current_error()
2584
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002585 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002586 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002587 return pkey
2588
2589
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002590def dump_certificate_request(type, req):
2591 """
2592 Dump a certificate request to a buffer
2593
2594 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2595 :param req: The certificate request to dump
2596 :return: The buffer with the dumped certificate request in
2597 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002598 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002599
2600 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002601 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002602 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002603 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002604 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002605 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002606 else:
Alex Gaynor5945ea82015-09-05 14:59:06 -04002607 raise ValueError(
2608 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2609 "FILETYPE_TEXT"
2610 )
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002611
Alex Gaynor09a386e2016-07-03 09:32:44 -04002612 _openssl_assert(result_code != 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002613
2614 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002615
2616
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002617def load_certificate_request(type, buffer):
2618 """
2619 Load a certificate request from a buffer
2620
2621 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2622 :param buffer: The buffer the certificate request is stored in
2623 :return: The X509Req object
2624 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002625 if isinstance(buffer, _text_type):
2626 buffer = buffer.encode("ascii")
2627
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002628 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002629
2630 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002631 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002632 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002633 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002634 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002635 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002636
Alex Gaynoradd5b072016-06-04 21:04:00 -07002637 _openssl_assert(req != _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002638
2639 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002640 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002641 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002642
2643
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002644def sign(pkey, data, digest):
2645 """
2646 Sign data with a digest
2647
2648 :param pkey: Pkey to sign with
2649 :param data: data to be signed
2650 :param digest: message digest to use
2651 :return: signature
2652 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002653 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002654
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002655 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002656 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002657 raise ValueError("No such digest method")
2658
Alex Gaynor67903a62016-06-02 10:37:13 -07002659 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002660 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002661
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002662 _lib.EVP_SignInit(md_ctx, digest_obj)
2663 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002664
Colleen Murphye09399b2016-03-01 17:40:49 -08002665 pkey_length = (PKey.bits(pkey) + 7) // 8
2666 signature_buffer = _ffi.new("unsigned char[]", pkey_length)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002667 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002668 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002669 md_ctx, signature_buffer, signature_length, pkey._pkey)
Alex Gaynor09a386e2016-07-03 09:32:44 -04002670 _openssl_assert(final_result == 1)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002671
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002672 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002673
2674
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002675def verify(cert, signature, data, digest):
2676 """
Laurens Van Houtvenc3baa7b2014-06-18 22:06:56 +02002677 Verify a signature.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002678
2679 :param cert: signing certificate (X509 object)
2680 :param signature: signature returned by sign function
2681 :param data: data to be verified
2682 :param digest: message digest to use
Dan Sully44e767a2016-06-04 18:05:27 -07002683 :return: ``None`` if the signature is correct, raise exception otherwise.
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002684 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002685 data = _text_to_bytes_and_warn("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002686
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002687 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002688 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002689 raise ValueError("No such digest method")
2690
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002691 pkey = _lib.X509_get_pubkey(cert._x509)
Alex Gaynoradd5b072016-06-04 21:04:00 -07002692 _openssl_assert(pkey != _ffi.NULL)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002693 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002694
Alex Gaynor67903a62016-06-02 10:37:13 -07002695 md_ctx = _lib.Cryptography_EVP_MD_CTX_new()
Alex Gaynor1f9d4de2016-06-02 11:01:52 -07002696 md_ctx = _ffi.gc(md_ctx, _lib.Cryptography_EVP_MD_CTX_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002697
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002698 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2699 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
Alex Gaynor5945ea82015-09-05 14:59:06 -04002700 verify_result = _lib.EVP_VerifyFinal(
2701 md_ctx, signature, len(signature), pkey
2702 )
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002703
2704 if verify_result != 1:
2705 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002706
2707
Dominic Chenf05b2122015-10-13 16:32:35 +00002708def dump_crl(type, crl):
2709 """
2710 Dump a certificate revocation list to a buffer.
2711
2712 :param type: The file type (one of ``FILETYPE_PEM``, ``FILETYPE_ASN1``, or
2713 ``FILETYPE_TEXT``).
Hynek Schlawack0a3cd6d2015-10-21 16:39:22 +02002714 :param CRL crl: The CRL to dump.
2715
Dominic Chenf05b2122015-10-13 16:32:35 +00002716 :return: The buffer with the CRL.
Dan Sully44e767a2016-06-04 18:05:27 -07002717 :rtype: bytes
Dominic Chenf05b2122015-10-13 16:32:35 +00002718 """
2719 bio = _new_mem_buf()
2720
2721 if type == FILETYPE_PEM:
2722 ret = _lib.PEM_write_bio_X509_CRL(bio, crl._crl)
2723 elif type == FILETYPE_ASN1:
2724 ret = _lib.i2d_X509_CRL_bio(bio, crl._crl)
2725 elif type == FILETYPE_TEXT:
2726 ret = _lib.X509_CRL_print(bio, crl._crl)
2727 else:
2728 raise ValueError(
2729 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
2730 "FILETYPE_TEXT")
2731
2732 assert ret == 1
2733 return _bio_to_string(bio)
2734
2735
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002736def load_crl(type, buffer):
2737 """
2738 Load a certificate revocation list from a buffer
2739
2740 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2741 :param buffer: The buffer the CRL is stored in
2742
2743 :return: The PKey object
2744 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002745 if isinstance(buffer, _text_type):
2746 buffer = buffer.encode("ascii")
2747
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002748 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002749
2750 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002751 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002752 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002753 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002754 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002755 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2756
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002757 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002758 _raise_current_error()
2759
2760 result = CRL.__new__(CRL)
2761 result._crl = crl
2762 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002763
2764
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002765def load_pkcs7_data(type, buffer):
2766 """
2767 Load pkcs7 data from a buffer
2768
2769 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2770 :param buffer: The buffer with the pkcs7 data.
2771 :return: The PKCS7 object
2772 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002773 if isinstance(buffer, _text_type):
2774 buffer = buffer.encode("ascii")
2775
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002776 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002777
2778 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002779 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002780 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002781 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002782 else:
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002783 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2784
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002785 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002786 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002787
2788 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002789 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002790 return pypkcs7
2791
2792
Stephen Holsapple38482622014-04-05 20:29:34 -07002793def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002794 """
2795 Load a PKCS12 object from a buffer
2796
2797 :param buffer: The buffer the certificate is stored in
2798 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2799 :returns: The PKCS12 object
2800 """
Jean-Paul Calderone39a8d592015-04-13 20:49:50 -04002801 passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002802
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002803 if isinstance(buffer, _text_type):
2804 buffer = buffer.encode("ascii")
2805
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002806 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002807
Stephen Holsapple38482622014-04-05 20:29:34 -07002808 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2809 # password based encryption no password and a zero length password are two
2810 # different things, but OpenSSL implementation will try both to figure out
2811 # which one works.
2812 if not passphrase:
2813 passphrase = _ffi.NULL
2814
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002815 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2816 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002817 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002818 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002819
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002820 pkey = _ffi.new("EVP_PKEY**")
2821 cert = _ffi.new("X509**")
2822 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002823
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002824 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002825 if not parse_result:
2826 _raise_current_error()
2827
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002828 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002829
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002830 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2831 # queue for no particular reason. This error isn't interesting to anyone
2832 # outside this function. It's not even interesting to us. Get rid of it.
2833 try:
2834 _raise_current_error()
2835 except Error:
2836 pass
2837
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002838 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002839 pykey = None
2840 else:
2841 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002842 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002843
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002844 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002845 pycert = None
2846 friendlyname = None
2847 else:
2848 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002849 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002850
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002851 friendlyname_length = _ffi.new("int*")
Alex Gaynor5945ea82015-09-05 14:59:06 -04002852 friendlyname_buffer = _lib.X509_alias_get0(
2853 cert[0], friendlyname_length
2854 )
2855 friendlyname = _ffi.buffer(
2856 friendlyname_buffer, friendlyname_length[0]
2857 )[:]
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002858 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002859 friendlyname = None
2860
2861 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002862 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002863 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002864 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002865 pycacerts.append(pycacert)
2866 if not pycacerts:
2867 pycacerts = None
2868
2869 pkcs12 = PKCS12.__new__(PKCS12)
2870 pkcs12._pkey = pykey
2871 pkcs12._cert = pycert
2872 pkcs12._cacerts = pycacerts
2873 pkcs12._friendlyname = friendlyname
2874 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002875
2876
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002877# There are no direct unit tests for this initialization. It is tested
2878# indirectly since it is necessary for functions like dump_privatekey when
2879# using encryption.
2880#
2881# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2882# and some other similar tests may fail without this (though they may not if
2883# the Python runtime has already done some initialization of the underlying
2884# OpenSSL library (and is linked against the same one that cryptography is
2885# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002886_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002887
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002888# This is similar but exercised mainly by exception_from_error_queue. It calls
2889# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2890_lib.SSL_load_error_strings()
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002891
2892
D.S. Ljungmark349e1362014-05-31 18:40:38 +02002893# Set the default string mask to match OpenSSL upstream (since 2005) and
2894# RFC5280 recommendations.
2895_lib.ASN1_STRING_set_default_mask_asc(b'utf8only')