blob: 6013ca3f950a7e3c4fffa9235f4dac671c7d4a50 [file] [log] [blame]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001from time import time
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002from base64 import b16encode
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05003from functools import partial
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05004from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
5
6from six import (
7 integer_types as _integer_types,
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -04008 text_type as _text_type,
9 PY3 as _PY3)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080010
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050011from OpenSSL._util import (
12 ffi as _ffi,
13 lib as _lib,
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050014 exception_from_error_queue as _exception_from_error_queue,
15 byte_string as _byte_string,
Jean-Paul Calderone6462b072015-03-29 07:03:11 -040016 native as _native,
17 warn_text as _warn_text)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080018
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050019FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
20FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080021
22# TODO This was an API mistake. OpenSSL has no such constant.
23FILETYPE_TEXT = 2 ** 16 - 1
24
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050025TYPE_RSA = _lib.EVP_PKEY_RSA
26TYPE_DSA = _lib.EVP_PKEY_DSA
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -080027
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080028
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070029
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050030class Error(Exception):
Jean-Paul Calderone511cde02013-12-29 10:31:13 -050031 """
32 An error occurred in an `OpenSSL.crypto` API.
33 """
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050034
35
36_raise_current_error = partial(_exception_from_error_queue, Error)
37
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070038
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050039
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -050040def _untested_error(where):
41 """
42 An OpenSSL API failed somehow. Additionally, the failure which was
43 encountered isn't one that's exercised by the test suite so future behavior
44 of pyOpenSSL is now somewhat less predictable.
45 """
46 raise RuntimeError("Unknown %s failure" % (where,))
47
48
49
50def _new_mem_buf(buffer=None):
51 """
52 Allocate a new OpenSSL memory BIO.
53
54 Arrange for the garbage collector to clean it up automatically.
55
56 :param buffer: None or some bytes to use to put into the BIO so that they
57 can be read out.
58 """
59 if buffer is None:
60 bio = _lib.BIO_new(_lib.BIO_s_mem())
61 free = _lib.BIO_free
62 else:
63 data = _ffi.new("char[]", buffer)
64 bio = _lib.BIO_new_mem_buf(data, len(buffer))
65 # Keep the memory alive as long as the bio is alive!
66 def free(bio, ref=data):
67 return _lib.BIO_free(bio)
68
69 if bio == _ffi.NULL:
70 # TODO: This is untested.
71 _raise_current_error()
72
73 bio = _ffi.gc(bio, free)
74 return bio
75
76
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050077
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080078def _bio_to_string(bio):
79 """
80 Copy the contents of an OpenSSL BIO object into a Python byte string.
81 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -050082 result_buffer = _ffi.new('char**')
83 buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)
84 return _ffi.buffer(result_buffer[0], buffer_length)[:]
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -080085
86
87
Jean-Paul Calderone57122982013-02-21 08:47:05 -080088def _set_asn1_time(boundary, when):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -050089 """
90 The the time value of an ASN1 time object.
91
92 @param boundary: An ASN1_GENERALIZEDTIME pointer (or an object safely
93 castable to that type) which will have its value set.
94 @param when: A string representation of the desired time value.
95
96 @raise TypeError: If C{when} is not a L{bytes} string.
97 @raise ValueError: If C{when} does not represent a time in the required
98 format.
99 @raise RuntimeError: If the time value cannot be set for some other
100 (unspecified) reason.
101 """
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800102 if not isinstance(when, bytes):
103 raise TypeError("when must be a byte string")
104
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500105 set_result = _lib.ASN1_GENERALIZEDTIME_set_string(
106 _ffi.cast('ASN1_GENERALIZEDTIME*', boundary), when)
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800107 if set_result == 0:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500108 dummy = _ffi.gc(_lib.ASN1_STRING_new(), _lib.ASN1_STRING_free)
109 _lib.ASN1_STRING_set(dummy, when, len(when))
110 check_result = _lib.ASN1_GENERALIZEDTIME_check(
111 _ffi.cast('ASN1_GENERALIZEDTIME*', dummy))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800112 if not check_result:
113 raise ValueError("Invalid string")
114 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500115 _untested_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800116
117
118
119def _get_asn1_time(timestamp):
Jean-Paul Calderonee728e872013-12-29 10:37:15 -0500120 """
121 Retrieve the time value of an ASN1 time object.
122
123 @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to
124 that type) from which the time value will be retrieved.
125
126 @return: The time value from C{timestamp} as a L{bytes} string in a certain
127 format. Or C{None} if the object contains no time value.
128 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500129 string_timestamp = _ffi.cast('ASN1_STRING*', timestamp)
130 if _lib.ASN1_STRING_length(string_timestamp) == 0:
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800131 return None
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500132 elif _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME:
133 return _ffi.string(_lib.ASN1_STRING_data(string_timestamp))
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800134 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500135 generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")
136 _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)
137 if generalized_timestamp[0] == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500138 # This may happen:
139 # - if timestamp was not an ASN1_TIME
140 # - if allocating memory for the ASN1_GENERALIZEDTIME failed
141 # - if a copy of the time data from timestamp cannot be made for
142 # the newly allocated ASN1_GENERALIZEDTIME
143 #
144 # These are difficult to test. cffi enforces the ASN1_TIME type.
145 # Memory allocation failures are a pain to trigger
146 # deterministically.
147 _untested_error("ASN1_TIME_to_generalizedtime")
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800148 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500149 string_timestamp = _ffi.cast(
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800150 "ASN1_STRING*", generalized_timestamp[0])
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500151 string_data = _lib.ASN1_STRING_data(string_timestamp)
152 string_result = _ffi.string(string_data)
153 _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])
Jean-Paul Calderone57122982013-02-21 08:47:05 -0800154 return string_result
155
156
157
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800158class PKey(object):
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800159 _only_public = False
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800160 _initialized = True
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800161
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800162 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500163 pkey = _lib.EVP_PKEY_new()
164 self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800165 self._initialized = False
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800166
167
168 def generate_key(self, type, bits):
169 """
170 Generate a key of a given type, with a given number of a bits
171
172 :param type: The key type (TYPE_RSA or TYPE_DSA)
173 :param bits: The number of bits
174
175 :return: None
176 """
177 if not isinstance(type, int):
178 raise TypeError("type must be an integer")
179
180 if not isinstance(bits, int):
181 raise TypeError("bits must be an integer")
182
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800183 # TODO Check error return
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500184 exponent = _lib.BN_new()
185 exponent = _ffi.gc(exponent, _lib.BN_free)
186 _lib.BN_set_word(exponent, _lib.RSA_F4)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800187
188 if type == TYPE_RSA:
189 if bits <= 0:
190 raise ValueError("Invalid number of bits")
191
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500192 rsa = _lib.RSA_new()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800193
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500194 result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500195 if result == 0:
196 # TODO: The test for this case is commented out. Different
197 # builds of OpenSSL appear to have different failure modes that
198 # make it hard to test. Visual inspection of the OpenSSL
199 # source reveals that a return value of 0 signals an error.
200 # Manual testing on a particular build of OpenSSL suggests that
201 # this is probably the appropriate way to handle those errors.
202 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800203
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500204 result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800205 if not result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500206 # TODO: It appears as though this can fail if an engine is in
207 # use which does not support RSA.
208 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800209
210 elif type == TYPE_DSA:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500211 dsa = _lib.DSA_generate_parameters(
212 bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL)
213 if dsa == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500214 # TODO: This is untested.
215 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500216 if not _lib.DSA_generate_key(dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500217 # TODO: This is untested.
218 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500219 if not _lib.EVP_PKEY_assign_DSA(self._pkey, dsa):
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500220 # TODO: This is untested.
221 _raise_current_error()
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800222 else:
223 raise Error("No such key type")
224
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800225 self._initialized = True
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800226
227
228 def check(self):
229 """
230 Check the consistency of an RSA private key.
231
232 :return: True if key is consistent.
233 :raise Error: if the key is inconsistent.
234 :raise TypeError: if the key is of a type which cannot be checked.
235 Only RSA keys can currently be checked.
236 """
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800237 if self._only_public:
238 raise TypeError("public key only")
239
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500240 if _lib.EVP_PKEY_type(self._pkey.type) != _lib.EVP_PKEY_RSA:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800241 raise TypeError("key type unsupported")
242
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500243 rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)
244 rsa = _ffi.gc(rsa, _lib.RSA_free)
245 result = _lib.RSA_check_key(rsa)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800246 if result:
247 return True
248 _raise_current_error()
249
250
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800251 def type(self):
252 """
253 Returns the type of the key
254
255 :return: The type of the key.
256 """
257 return self._pkey.type
258
259
260 def bits(self):
261 """
262 Returns the number of bits of the key
263
264 :return: The number of bits of the key.
265 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500266 return _lib.EVP_PKEY_bits(self._pkey)
Jean-Paul Calderonec86fcaf2013-02-20 12:38:33 -0800267PKeyType = PKey
268
269
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800270
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400271class _EllipticCurve(object):
272 """
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400273 A representation of a supported elliptic curve.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400274
275 @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
276 Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
277 instances each of which represents one curve supported by the system.
278 @type _curves: :py:type:`NoneType` or :py:type:`set`
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400279 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400280 _curves = None
281
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400282 if _PY3:
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400283 # This only necessary on Python 3. Morever, it is broken on Python 2.
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400284 def __ne__(self, other):
Jean-Paul Calderonea5381052014-05-01 09:32:46 -0400285 """
286 Implement cooperation with the right-hand side argument of ``!=``.
287
288 Python 3 seems to have dropped this cooperation in this very narrow
289 circumstance.
290 """
Jean-Paul Calderonef22abcd2014-05-01 09:31:19 -0400291 if isinstance(other, _EllipticCurve):
292 return super(_EllipticCurve, self).__ne__(other)
293 return NotImplemented
Jean-Paul Calderone40da72d2014-05-01 09:25:17 -0400294
295
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400296 @classmethod
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400297 def _load_elliptic_curves(cls, lib):
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400298 """
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400299 Get the curves supported by OpenSSL.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400300
301 :param lib: The OpenSSL library binding object.
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400302
303 :return: A :py:type:`set` of ``cls`` instances giving the names of the
304 elliptic curves the underlying library supports.
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400305 """
306 if lib.Cryptography_HAS_EC:
307 num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
308 builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
309 # The return value on this call should be num_curves again. We could
310 # check it to make sure but if it *isn't* then.. what could we do?
311 # Abort the whole process, I suppose...? -exarkun
312 lib.EC_get_builtin_curves(builtin_curves, num_curves)
313 return set(
314 cls.from_nid(lib, c.nid)
315 for c in builtin_curves)
Jean-Paul Calderone73945e32014-04-30 18:18:01 -0400316 return set()
317
318
319 @classmethod
320 def _get_elliptic_curves(cls, lib):
321 """
322 Get, cache, and return the curves supported by OpenSSL.
323
324 :param lib: The OpenSSL library binding object.
325
326 :return: A :py:type:`set` of ``cls`` instances giving the names of the
327 elliptic curves the underlying library supports.
328 """
329 if cls._curves is None:
330 cls._curves = cls._load_elliptic_curves(lib)
331 return cls._curves
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400332
333
334 @classmethod
335 def from_nid(cls, lib, nid):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400336 """
337 Instantiate a new :py:class:`_EllipticCurve` associated with the given
338 OpenSSL NID.
339
340 :param lib: The OpenSSL library binding object.
341
342 :param nid: The OpenSSL NID the resulting curve object will represent.
343 This must be a curve NID (and not, for example, a hash NID) or
344 subsequent operations will fail in unpredictable ways.
345 :type nid: :py:class:`int`
346
347 :return: The curve object.
348 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400349 return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
350
351
352 def __init__(self, lib, nid, name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400353 """
354 :param _lib: The :py:mod:`cryptography` binding instance used to
355 interface with OpenSSL.
356
357 :param _nid: The OpenSSL NID identifying the curve this object
358 represents.
359 :type _nid: :py:class:`int`
360
361 :param name: The OpenSSL short name identifying the curve this object
362 represents.
363 :type name: :py:class:`unicode`
364 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400365 self._lib = lib
366 self._nid = nid
367 self.name = name
368
369
370 def __repr__(self):
371 return "<Curve %r>" % (self.name,)
372
373
374 def _to_EC_KEY(self):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400375 """
376 Create a new OpenSSL EC_KEY structure initialized to use this curve.
377
378 The structure is automatically garbage collected when the Python object
379 is garbage collected.
380 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400381 key = self._lib.EC_KEY_new_by_curve_name(self._nid)
382 return _ffi.gc(key, _lib.EC_KEY_free)
383
384
385
386def get_elliptic_curves():
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400387 """
388 Return a set of objects representing the elliptic curves supported in the
389 OpenSSL build in use.
390
391 The curve objects have a :py:class:`unicode` ``name`` attribute by which
392 they identify themselves.
393
394 The curve objects are useful as values for the argument accepted by
Jean-Paul Calderone3b04e352014-04-19 09:29:10 -0400395 :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
396 used for ECDHE key exchange.
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400397 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400398 return _EllipticCurve._get_elliptic_curves(_lib)
399
400
401
402def get_elliptic_curve(name):
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400403 """
404 Return a single curve object selected by name.
405
406 See :py:func:`get_elliptic_curves` for information about curve objects.
407
Jean-Paul Calderoned5839e22014-04-19 09:26:44 -0400408 :param name: The OpenSSL short name identifying the curve object to
409 retrieve.
410 :type name: :py:class:`unicode`
411
Jean-Paul Calderoneaaf516d2014-04-19 09:10:45 -0400412 If the named curve is not supported then :py:class:`ValueError` is raised.
413 """
Jean-Paul Calderonec09fd582014-04-18 22:00:10 -0400414 for curve in get_elliptic_curves():
415 if curve.name == name:
416 return curve
417 raise ValueError("unknown curve name", name)
418
419
420
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800421class X509Name(object):
422 def __init__(self, name):
423 """
424 Create a new X509Name, copying the given X509Name instance.
425
426 :param name: An X509Name object to copy
427 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500428 name = _lib.X509_NAME_dup(name._name)
429 self._name = _ffi.gc(name, _lib.X509_NAME_free)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800430
431
432 def __setattr__(self, name, value):
433 if name.startswith('_'):
434 return super(X509Name, self).__setattr__(name, value)
435
Jean-Paul Calderoneff363be2013-03-03 10:21:23 -0800436 # Note: we really do not want str subclasses here, so we do not use
437 # isinstance.
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800438 if type(name) is not str:
439 raise TypeError("attribute name must be string, not '%.200s'" % (
440 type(value).__name__,))
441
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500442 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500443 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800444 try:
445 _raise_current_error()
446 except Error:
447 pass
448 raise AttributeError("No such attribute")
449
450 # If there's an old entry for this NID, remove it
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500451 for i in range(_lib.X509_NAME_entry_count(self._name)):
452 ent = _lib.X509_NAME_get_entry(self._name, i)
453 ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)
454 ent_nid = _lib.OBJ_obj2nid(ent_obj)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800455 if nid == ent_nid:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500456 ent = _lib.X509_NAME_delete_entry(self._name, i)
457 _lib.X509_NAME_ENTRY_free(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800458 break
459
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500460 if isinstance(value, _text_type):
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800461 value = value.encode('utf-8')
462
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500463 add_result = _lib.X509_NAME_add_entry_by_NID(
464 self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800465 if not add_result:
Jean-Paul Calderone5300d6a2013-12-29 16:36:50 -0500466 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800467
468
469 def __getattr__(self, name):
470 """
471 Find attribute. An X509Name object has the following attributes:
472 countryName (alias C), stateOrProvince (alias ST), locality (alias L),
473 organization (alias O), organizationalUnit (alias OU), commonName (alias
474 CN) and more...
475 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500476 nid = _lib.OBJ_txt2nid(_byte_string(name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500477 if nid == _lib.NID_undef:
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800478 # This is a bit weird. OBJ_txt2nid indicated failure, but it seems
479 # a lower level function, a2d_ASN1_OBJECT, also feels the need to
480 # push something onto the error queue. If we don't clean that up
481 # now, someone else will bump into it later and be quite confused.
482 # See lp#314814.
483 try:
484 _raise_current_error()
485 except Error:
486 pass
487 return super(X509Name, self).__getattr__(name)
488
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500489 entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800490 if entry_index == -1:
491 return None
492
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500493 entry = _lib.X509_NAME_get_entry(self._name, entry_index)
494 data = _lib.X509_NAME_ENTRY_get_data(entry)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800495
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500496 result_buffer = _ffi.new("unsigned char**")
497 data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800498 if data_length < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500499 # TODO: This is untested.
500 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800501
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700502 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500503 result = _ffi.buffer(result_buffer[0], data_length)[:].decode('utf-8')
Jean-Paul Calderoned899af02013-03-19 22:10:37 -0700504 finally:
505 # XXX untested
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500506 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800507 return result
508
509
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500510 def _cmp(op):
511 def f(self, other):
512 if not isinstance(other, X509Name):
513 return NotImplemented
514 result = _lib.X509_NAME_cmp(self._name, other._name)
515 return op(result, 0)
516 return f
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800517
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500518 __eq__ = _cmp(__eq__)
519 __ne__ = _cmp(__ne__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800520
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500521 __lt__ = _cmp(__lt__)
522 __le__ = _cmp(__le__)
523
524 __gt__ = _cmp(__gt__)
525 __ge__ = _cmp(__ge__)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800526
527 def __repr__(self):
528 """
529 String representation of an X509Name
530 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500531 result_buffer = _ffi.new("char[]", 512);
532 format_result = _lib.X509_NAME_oneline(
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800533 self._name, result_buffer, len(result_buffer))
534
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500535 if format_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500536 # TODO: This is untested.
537 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800538
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500539 return "<X509Name object '%s'>" % (
540 _native(_ffi.string(result_buffer)),)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800541
542
543 def hash(self):
544 """
545 Return the hash value of this name
546
547 :return: None
548 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500549 return _lib.X509_NAME_hash(self._name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800550
551
552 def der(self):
553 """
554 Return the DER encoding of this name
555
556 :return: A :py:class:`bytes` instance giving the DER encoded form of
557 this name.
558 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500559 result_buffer = _ffi.new('unsigned char**')
560 encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800561 if encode_result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500562 # TODO: This is untested.
563 _raise_current_error()
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800564
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500565 string_result = _ffi.buffer(result_buffer[0], encode_result)[:]
566 _lib.OPENSSL_free(result_buffer[0])
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800567 return string_result
568
569
570 def get_components(self):
571 """
572 Returns the split-up components of this name.
573
574 :return: List of tuples (name, value).
575 """
576 result = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500577 for i in range(_lib.X509_NAME_entry_count(self._name)):
578 ent = _lib.X509_NAME_get_entry(self._name, i)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800579
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500580 fname = _lib.X509_NAME_ENTRY_get_object(ent)
581 fval = _lib.X509_NAME_ENTRY_get_data(ent)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800582
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500583 nid = _lib.OBJ_obj2nid(fname)
584 name = _lib.OBJ_nid2sn(nid)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800585
586 result.append((
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500587 _ffi.string(name),
588 _ffi.string(
589 _lib.ASN1_STRING_data(fval),
590 _lib.ASN1_STRING_length(fval))))
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800591
592 return result
593X509NameType = X509Name
594
595
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800596class X509Extension(object):
597 def __init__(self, type_name, critical, value, subject=None, issuer=None):
598 """
599 :param typename: The name of the extension to create.
600 :type typename: :py:data:`str`
601
602 :param critical: A flag indicating whether this is a critical extension.
603
604 :param value: The value of the extension.
605 :type value: :py:data:`str`
606
607 :param subject: Optional X509 cert to use as subject.
608 :type subject: :py:class:`X509`
609
610 :param issuer: Optional X509 cert to use as issuer.
611 :type issuer: :py:class:`X509`
612
613 :return: The X509Extension object
614 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500615 ctx = _ffi.new("X509V3_CTX*")
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800616
617 # A context is necessary for any extension which uses the r2i conversion
618 # method. That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
619 # Start off by initializing most of the fields to NULL.
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500620 _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800621
622 # We have no configuration database - but perhaps we should (some
623 # extensions may require it).
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500624 _lib.X509V3_set_ctx_nodb(ctx)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800625
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800626 # Initialize the subject and issuer, if appropriate. ctx is a local,
627 # and as far as I can tell none of the X509V3_* APIs invoked here steal
628 # any references, so no need to mess with reference counts or duplicates.
629 if issuer is not None:
630 if not isinstance(issuer, X509):
631 raise TypeError("issuer must be an X509 instance")
632 ctx.issuer_cert = issuer._x509
633 if subject is not None:
634 if not isinstance(subject, X509):
635 raise TypeError("subject must be an X509 instance")
636 ctx.subject_cert = subject._x509
637
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800638 if critical:
639 # There are other OpenSSL APIs which would let us pass in critical
640 # separately, but they're harder to use, and since value is already
641 # a pile of crappy junk smuggling a ton of utterly important
642 # structured data, what's the point of trying to avoid nasty stuff
643 # with strings? (However, X509V3_EXT_i2d in particular seems like it
644 # would be a better API to invoke. I do not know where to get the
645 # ext_struc it desires for its last parameter, though.)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500646 value = b"critical," + value
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800647
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500648 extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
649 if extension == _ffi.NULL:
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800650 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500651 self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800652
653
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400654 @property
655 def _nid(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500656 return _lib.OBJ_obj2nid(self._extension.object)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400657
658 _prefixes = {
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500659 _lib.GEN_EMAIL: "email",
660 _lib.GEN_DNS: "DNS",
661 _lib.GEN_URI: "URI",
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400662 }
663
664 def _subjectAltNameString(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500665 method = _lib.X509V3_EXT_get(self._extension)
666 if method == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500667 # TODO: This is untested.
668 _raise_current_error()
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400669 payload = self._extension.value.data
670 length = self._extension.value.length
671
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500672 payloadptr = _ffi.new("unsigned char**")
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400673 payloadptr[0] = payload
674
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500675 if method.it != _ffi.NULL:
676 ptr = _lib.ASN1_ITEM_ptr(method.it)
677 data = _lib.ASN1_item_d2i(_ffi.NULL, payloadptr, length, ptr)
678 names = _ffi.cast("GENERAL_NAMES*", data)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400679 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500680 names = _ffi.cast(
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400681 "GENERAL_NAMES*",
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500682 method.d2i(_ffi.NULL, payloadptr, length))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400683
684 parts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500685 for i in range(_lib.sk_GENERAL_NAME_num(names)):
686 name = _lib.sk_GENERAL_NAME_value(names, i)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400687 try:
688 label = self._prefixes[name.type]
689 except KeyError:
690 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500691 _lib.GENERAL_NAME_print(bio, name)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500692 parts.append(_native(_bio_to_string(bio)))
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400693 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500694 value = _native(
695 _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[:])
696 parts.append(label + ":" + value)
697 return ", ".join(parts)
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400698
699
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800700 def __str__(self):
701 """
702 :return: a nice text representation of the extension
703 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500704 if _lib.NID_subject_alt_name == self._nid:
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400705 return self._subjectAltNameString()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800706
Jean-Paul Calderoneed0c57b2013-10-06 08:31:40 -0400707 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500708 print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800709 if not print_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500710 # TODO: This is untested.
711 _raise_current_error()
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800712
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500713 return _native(_bio_to_string(bio))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800714
715
716 def get_critical(self):
717 """
718 Returns the critical field of the X509Extension
719
720 :return: The critical field.
721 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500722 return _lib.X509_EXTENSION_get_critical(self._extension)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800723
724
725 def get_short_name(self):
726 """
727 Returns the short version of the type name of the X509Extension
728
729 :return: The short type name.
730 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500731 obj = _lib.X509_EXTENSION_get_object(self._extension)
732 nid = _lib.OBJ_obj2nid(obj)
733 return _ffi.string(_lib.OBJ_nid2sn(nid))
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -0800734
735
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800736 def get_data(self):
737 """
738 Returns the data of the X509Extension
739
740 :return: A :py:data:`str` giving the X509Extension's ASN.1 encoded data.
741 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500742 octet_result = _lib.X509_EXTENSION_get_data(self._extension)
743 string_result = _ffi.cast('ASN1_STRING*', octet_result)
744 char_result = _lib.ASN1_STRING_data(string_result)
745 result_length = _lib.ASN1_STRING_length(string_result)
746 return _ffi.buffer(char_result, result_length)[:]
Jean-Paul Calderoned418a9c2013-02-20 16:24:55 -0800747
748X509ExtensionType = X509Extension
749
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -0800750
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800751class X509Req(object):
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800752 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500753 req = _lib.X509_REQ_new()
754 self._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800755
756
757 def set_pubkey(self, pkey):
758 """
759 Set the public key of the certificate request
760
761 :param pkey: The public key to use
762 :return: None
763 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500764 set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800765 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500766 # TODO: This is untested.
767 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800768
769
770 def get_pubkey(self):
771 """
772 Get the public key from the certificate request
773
774 :return: The public key
775 """
776 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500777 pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)
778 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500779 # TODO: This is untested.
780 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500781 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800782 pkey._only_public = True
783 return pkey
784
785
786 def set_version(self, version):
787 """
788 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate
789 request.
790
791 :param version: The version number
792 :return: None
793 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500794 set_result = _lib.X509_REQ_set_version(self._req, version)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800795 if not set_result:
796 _raise_current_error()
797
798
799 def get_version(self):
800 """
801 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate
802 request.
803
804 :return: an integer giving the value of the version subfield
805 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500806 return _lib.X509_REQ_get_version(self._req)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800807
808
809 def get_subject(self):
810 """
811 Create an X509Name object for the subject of the certificate request
812
813 :return: An X509Name object
814 """
815 name = X509Name.__new__(X509Name)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500816 name._name = _lib.X509_REQ_get_subject_name(self._req)
817 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500818 # TODO: This is untested.
819 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800820
821 # The name is owned by the X509Req structure. As long as the X509Name
822 # Python object is alive, keep the X509Req Python object alive.
823 name._owner = self
824
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800825 return name
826
827
828 def add_extensions(self, extensions):
829 """
830 Add extensions to the request.
831
832 :param extensions: a sequence of X509Extension objects
833 :return: None
834 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500835 stack = _lib.sk_X509_EXTENSION_new_null()
836 if stack == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500837 # TODO: This is untested.
838 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800839
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500840 stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -0800841
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800842 for ext in extensions:
843 if not isinstance(ext, X509Extension):
Jean-Paul Calderonec2154b72013-02-20 14:29:37 -0800844 raise ValueError("One of the elements is not an X509Extension")
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800845
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -0800846 # TODO push can fail (here and elsewhere)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500847 _lib.sk_X509_EXTENSION_push(stack, ext._extension)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800848
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500849 add_result = _lib.X509_REQ_add_extensions(self._req, stack)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800850 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500851 # TODO: This is untested.
852 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800853
854
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800855 def get_extensions(self):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800856 """
857 Get extensions to the request.
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800858
Jean-Paul Calderoneda3e6c62014-03-02 08:06:11 -0500859 :return: A :py:class:`list` of :py:class:`X509Extension` objects.
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800860 """
861 exts = []
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500862 native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
Jean-Paul Calderoneb7a79b42014-03-02 08:06:47 -0500863 for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800864 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone9479d732014-03-02 08:04:54 -0500865 ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
Stephen Holsapple7fbdf642014-03-01 20:05:47 -0800866 exts.append(ext)
867 return exts
Stephen Holsappleadfd39d2014-01-28 17:58:31 -0800868
869
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800870 def sign(self, pkey, digest):
871 """
872 Sign the certificate request using the supplied key and digest
873
874 :param pkey: The key to sign with
875 :param digest: The message digest to use
876 :return: None
877 """
878 if pkey._only_public:
879 raise ValueError("Key has only public part")
880
881 if not pkey._initialized:
882 raise ValueError("Key is uninitialized")
883
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500884 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500885 if digest_obj == _ffi.NULL:
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800886 raise ValueError("No such digest method")
887
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500888 sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800889 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -0500890 # TODO: This is untested.
891 _raise_current_error()
Jean-Paul Calderone4328d472013-02-20 14:28:46 -0800892
893
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800894 def verify(self, pkey):
895 """
896 Verifies a certificate request using the supplied public key
897
898 :param key: a public key
899 :return: True if the signature is correct.
900
901 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
902 problem verifying the signature.
903 """
904 if not isinstance(pkey, PKey):
905 raise TypeError("pkey must be a PKey instance")
906
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500907 result = _lib.X509_REQ_verify(self._req, pkey._pkey)
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800908 if result <= 0:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -0500909 _raise_current_error()
Jean-Paul Calderone5565f0f2013-03-06 11:10:20 -0800910
911 return result
912
913
Jean-Paul Calderone066f0572013-02-20 13:43:44 -0800914X509ReqType = X509Req
915
916
917
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800918class X509(object):
919 def __init__(self):
920 # TODO Allocation failure? And why not __new__ instead of __init__?
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500921 x509 = _lib.X509_new()
922 self._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800923
924
925 def set_version(self, version):
926 """
927 Set version number of the certificate
928
929 :param version: The version number
930 :type version: :py:class:`int`
931
932 :return: None
933 """
934 if not isinstance(version, int):
935 raise TypeError("version must be an integer")
936
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500937 _lib.X509_set_version(self._x509, version)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800938
939
940 def get_version(self):
941 """
942 Return version number of the certificate
943
944 :return: Version number as a Python integer
945 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500946 return _lib.X509_get_version(self._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -0800947
948
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800949 def get_pubkey(self):
950 """
951 Get the public key of the certificate
952
953 :return: The public key
954 """
955 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500956 pkey._pkey = _lib.X509_get_pubkey(self._x509)
957 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800958 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500959 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800960 pkey._only_public = True
961 return pkey
962
963
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800964 def set_pubkey(self, pkey):
965 """
966 Set the public key of the certificate
967
968 :param pkey: The public key
969
970 :return: None
971 """
972 if not isinstance(pkey, PKey):
973 raise TypeError("pkey must be a PKey instance")
974
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500975 set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800976 if not set_result:
977 _raise_current_error()
978
979
980 def sign(self, pkey, digest):
981 """
982 Sign the certificate using the supplied key and digest
983
984 :param pkey: The key to sign with
985 :param digest: The message digest to use
986 :return: None
987 """
988 if not isinstance(pkey, PKey):
989 raise TypeError("pkey must be a PKey instance")
990
Jean-Paul Calderoneedafced2013-02-19 11:48:38 -0800991 if pkey._only_public:
992 raise ValueError("Key only has public part")
993
Jean-Paul Calderone09e3bdc2013-02-19 12:15:28 -0800994 if not pkey._initialized:
995 raise ValueError("Key is uninitialized")
996
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -0500997 evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -0500998 if evp_md == _ffi.NULL:
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -0800999 raise ValueError("No such digest method")
1000
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001001 sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)
Jean-Paul Calderone3e29ccf2013-02-19 11:32:46 -08001002 if not sign_result:
1003 _raise_current_error()
1004
1005
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001006 def get_signature_algorithm(self):
1007 """
1008 Retrieve the signature algorithm used in the certificate
1009
1010 :return: A byte string giving the name of the signature algorithm used in
1011 the certificate.
1012 :raise ValueError: If the signature algorithm is undefined.
1013 """
1014 alg = self._x509.cert_info.signature.algorithm
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001015 nid = _lib.OBJ_obj2nid(alg)
1016 if nid == _lib.NID_undef:
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001017 raise ValueError("Undefined signature algorithm")
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001018 return _ffi.string(_lib.OBJ_nid2ln(nid))
Jean-Paul Calderonee4aa3fa2013-02-19 12:12:53 -08001019
1020
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001021 def digest(self, digest_name):
1022 """
1023 Return the digest of the X509 object.
1024
1025 :param digest_name: The name of the digest algorithm to use.
1026 :type digest_name: :py:class:`bytes`
1027
1028 :return: The digest of the object
1029 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001030 digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001031 if digest == _ffi.NULL:
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001032 raise ValueError("No such digest method")
1033
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001034 result_buffer = _ffi.new("char[]", _lib.EVP_MAX_MD_SIZE)
1035 result_length = _ffi.new("unsigned int[]", 1)
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001036 result_length[0] = len(result_buffer)
1037
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001038 digest_result = _lib.X509_digest(
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001039 self._x509, digest, result_buffer, result_length)
1040
1041 if not digest_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001042 # TODO: This is untested.
1043 _raise_current_error()
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001044
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001045 return b":".join([
1046 b16encode(ch).upper() for ch
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001047 in _ffi.buffer(result_buffer, result_length[0])])
Jean-Paul Calderoneb4078722013-02-19 12:01:55 -08001048
1049
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001050 def subject_name_hash(self):
1051 """
1052 Return the hash of the X509 subject.
1053
1054 :return: The hash of the subject.
1055 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001056 return _lib.X509_subject_name_hash(self._x509)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001057
1058
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001059 def set_serial_number(self, serial):
1060 """
1061 Set serial number of the certificate
1062
1063 :param serial: The serial number
1064 :type serial: :py:class:`int`
1065
1066 :return: None
1067 """
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001068 if not isinstance(serial, _integer_types):
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001069 raise TypeError("serial must be an integer")
1070
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001071 hex_serial = hex(serial)[2:]
1072 if not isinstance(hex_serial, bytes):
1073 hex_serial = hex_serial.encode('ascii')
1074
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001075 bignum_serial = _ffi.new("BIGNUM**")
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001076
1077 # BN_hex2bn stores the result in &bignum. Unless it doesn't feel like
1078 # it. If bignum is still NULL after this call, then the return value is
1079 # actually the result. I hope. -exarkun
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001080 small_serial = _lib.BN_hex2bn(bignum_serial, hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001081
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001082 if bignum_serial[0] == _ffi.NULL:
1083 set_result = _lib.ASN1_INTEGER_set(
1084 _lib.X509_get_serialNumber(self._x509), small_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001085 if set_result:
1086 # TODO Not tested
1087 _raise_current_error()
1088 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001089 asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)
1090 _lib.BN_free(bignum_serial[0])
1091 if asn1_serial == _ffi.NULL:
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001092 # TODO Not tested
1093 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001094 asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)
1095 set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001096 if not set_result:
1097 # TODO Not tested
1098 _raise_current_error()
1099
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001100
1101 def get_serial_number(self):
1102 """
1103 Return serial number of the certificate
1104
1105 :return: Serial number as a Python integer
1106 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001107 asn1_serial = _lib.X509_get_serialNumber(self._x509)
1108 bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001109 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001110 hex_serial = _lib.BN_bn2hex(bignum_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001111 try:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001112 hexstring_serial = _ffi.string(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001113 serial = int(hexstring_serial, 16)
1114 return serial
1115 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001116 _lib.OPENSSL_free(hex_serial)
Jean-Paul Calderone78133852013-02-19 10:41:46 -08001117 finally:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001118 _lib.BN_free(bignum_serial)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001119
1120
1121 def gmtime_adj_notAfter(self, amount):
1122 """
1123 Adjust the time stamp for when the certificate stops being valid
1124
1125 :param amount: The number of seconds by which to adjust the ending
1126 validity time.
1127 :type amount: :py:class:`int`
1128
1129 :return: None
1130 """
1131 if not isinstance(amount, int):
1132 raise TypeError("amount must be an integer")
1133
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001134 notAfter = _lib.X509_get_notAfter(self._x509)
1135 _lib.X509_gmtime_adj(notAfter, amount)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001136
1137
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001138 def gmtime_adj_notBefore(self, amount):
1139 """
1140 Change the timestamp for when the certificate starts being valid to the current
1141 time plus an offset.
1142
1143 :param amount: The number of seconds by which to adjust the starting validity
1144 time.
1145 :return: None
1146 """
1147 if not isinstance(amount, int):
1148 raise TypeError("amount must be an integer")
1149
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001150 notBefore = _lib.X509_get_notBefore(self._x509)
1151 _lib.X509_gmtime_adj(notBefore, amount)
Jean-Paul Calderone662afe52013-02-20 08:41:11 -08001152
1153
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001154 def has_expired(self):
1155 """
1156 Check whether the certificate has expired.
1157
1158 :return: True if the certificate has expired, false otherwise
1159 """
1160 now = int(time())
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001161 notAfter = _lib.X509_get_notAfter(self._x509)
1162 return _lib.ASN1_UTCTIME_cmp_time_t(
1163 _ffi.cast('ASN1_UTCTIME*', notAfter), now) < 0
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001164
1165
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001166 def _get_boundary_time(self, which):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001167 return _get_asn1_time(which(self._x509))
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001168
1169
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001170 def get_notBefore(self):
1171 """
1172 Retrieve the time stamp for when the certificate starts being valid
1173
1174 :return: A string giving the timestamp, in the format::
1175
1176 YYYYMMDDhhmmssZ
1177 YYYYMMDDhhmmss+hhmm
1178 YYYYMMDDhhmmss-hhmm
1179
1180 or None if there is no value set.
1181 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001182 return self._get_boundary_time(_lib.X509_get_notBefore)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001183
1184
1185 def _set_boundary_time(self, which, when):
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001186 return _set_asn1_time(which(self._x509), when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001187
1188
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001189 def set_notBefore(self, when):
1190 """
1191 Set the time stamp for when the certificate starts being valid
1192
1193 :param when: A string giving the timestamp, in the format:
1194
1195 YYYYMMDDhhmmssZ
1196 YYYYMMDDhhmmss+hhmm
1197 YYYYMMDDhhmmss-hhmm
1198 :type when: :py:class:`bytes`
1199
1200 :return: None
1201 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001202 return self._set_boundary_time(_lib.X509_get_notBefore, when)
Jean-Paul Calderoned7d81272013-02-19 13:16:03 -08001203
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001204
1205 def get_notAfter(self):
1206 """
1207 Retrieve the time stamp for when the certificate stops being valid
1208
1209 :return: A string giving the timestamp, in the format::
1210
1211 YYYYMMDDhhmmssZ
1212 YYYYMMDDhhmmss+hhmm
1213 YYYYMMDDhhmmss-hhmm
1214
1215 or None if there is no value set.
1216 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001217 return self._get_boundary_time(_lib.X509_get_notAfter)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001218
1219
1220 def set_notAfter(self, when):
1221 """
1222 Set the time stamp for when the certificate stops being valid
1223
1224 :param when: A string giving the timestamp, in the format:
1225
1226 YYYYMMDDhhmmssZ
1227 YYYYMMDDhhmmss+hhmm
1228 YYYYMMDDhhmmss-hhmm
1229 :type when: :py:class:`bytes`
1230
1231 :return: None
1232 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001233 return self._set_boundary_time(_lib.X509_get_notAfter, when)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001234
1235
1236 def _get_name(self, which):
1237 name = X509Name.__new__(X509Name)
1238 name._name = which(self._x509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001239 if name._name == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001240 # TODO: This is untested.
1241 _raise_current_error()
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001242
1243 # The name is owned by the X509 structure. As long as the X509Name
1244 # Python object is alive, keep the X509 Python object alive.
1245 name._owner = self
1246
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001247 return name
1248
1249
1250 def _set_name(self, which, name):
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001251 if not isinstance(name, X509Name):
1252 raise TypeError("name must be an X509Name")
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001253 set_result = which(self._x509, name._name)
1254 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001255 # TODO: This is untested.
1256 _raise_current_error()
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001257
1258
1259 def get_issuer(self):
1260 """
1261 Create an X509Name object for the issuer of the certificate
1262
1263 :return: An X509Name object
1264 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001265 return self._get_name(_lib.X509_get_issuer_name)
Jean-Paul Calderonec2bd4e92013-02-20 08:12:36 -08001266
1267
1268 def set_issuer(self, issuer):
1269 """
1270 Set the issuer of the certificate
1271
1272 :param issuer: The issuer name
1273 :type issuer: :py:class:`X509Name`
1274
1275 :return: None
1276 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001277 return self._set_name(_lib.X509_set_issuer_name, issuer)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001278
1279
1280 def get_subject(self):
1281 """
1282 Create an X509Name object for the subject of the certificate
1283
1284 :return: An X509Name object
1285 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001286 return self._get_name(_lib.X509_get_subject_name)
Jean-Paul Calderonea9de1952013-02-19 16:58:42 -08001287
1288
1289 def set_subject(self, subject):
1290 """
1291 Set the subject of the certificate
1292
1293 :param subject: The subject name
1294 :type subject: :py:class:`X509Name`
1295 :return: None
1296 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001297 return self._set_name(_lib.X509_set_subject_name, subject)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001298
1299
1300 def get_extension_count(self):
1301 """
1302 Get the number of extensions on the certificate.
1303
1304 :return: The number of extensions as an integer.
1305 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001306 return _lib.X509_get_ext_count(self._x509)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001307
1308
1309 def add_extensions(self, extensions):
1310 """
1311 Add extensions to the certificate.
1312
1313 :param extensions: a sequence of X509Extension objects
1314 :return: None
1315 """
1316 for ext in extensions:
1317 if not isinstance(ext, X509Extension):
1318 raise ValueError("One of the elements is not an X509Extension")
1319
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001320 add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001321 if not add_result:
1322 _raise_current_error()
1323
1324
1325 def get_extension(self, index):
1326 """
1327 Get a specific extension of the certificate by index.
1328
1329 :param index: The index of the extension to retrieve.
1330 :return: The X509Extension object at the specified index.
1331 """
1332 ext = X509Extension.__new__(X509Extension)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001333 ext._extension = _lib.X509_get_ext(self._x509, index)
1334 if ext._extension == _ffi.NULL:
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001335 raise IndexError("extension index out of bounds")
1336
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001337 extension = _lib.X509_EXTENSION_dup(ext._extension)
1338 ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Jean-Paul Calderone83d22eb2013-02-20 12:19:43 -08001339 return ext
1340
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001341X509Type = X509
1342
1343
1344
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001345class X509Store(object):
1346 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001347 store = _lib.X509_STORE_new()
1348 self._store = _ffi.gc(store, _lib.X509_STORE_free)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001349
1350
1351 def add_cert(self, cert):
1352 if not isinstance(cert, X509):
1353 raise TypeError()
1354
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001355 result = _lib.X509_STORE_add_cert(self._store, cert._x509)
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001356 if not result:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05001357 _raise_current_error()
Jean-Paul Calderonee6f32b82013-03-06 10:27:57 -08001358
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001359
1360X509StoreType = X509Store
1361
1362
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001363class X509StoreContextError(Exception):
1364 """
1365 An error occurred while verifying a certificate using
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001366 `OpenSSL.X509StoreContext.verify_certificate`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001367
Jean-Paul Calderonefeb17432015-03-15 15:49:45 -04001368 :ivar certificate: The certificate which caused verificate failure.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001369 :type cert: :class:`X509`
1370
1371 """
1372 def __init__(self, message, certificate):
1373 super(X509StoreContextError, self).__init__(message)
1374 self.certificate = certificate
1375
Jean-Paul Calderonea63714c2013-03-05 17:02:26 -08001376
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001377class X509StoreContext(object):
1378 """
1379 An X.509 store context.
1380
Jean-Paul Calderone13a81682015-01-18 15:49:15 -05001381 An :py:class:`X509StoreContext` is used to define some of the criteria for
1382 certificate verification. The information encapsulated in this object
1383 includes, but is not limited to, a set of trusted certificates,
1384 verification parameters, and revoked certificates.
1385
1386 Of these, only the set of trusted certificates is currently exposed.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001387
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001388 :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
1389 instance. It is dynamically allocated and automatically garbage
1390 collected.
1391
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001392 :ivar _store: See the ``store`` ``__init__`` parameter.
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001393
Jean-Paul Calderone64b6b842015-03-15 16:08:02 -04001394 :ivar _cert: See the ``certificate`` ``__init__`` parameter.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001395 """
1396
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001397 def __init__(self, store, certificate):
1398 """
1399 :param X509Store store: The certificates which will be trusted for the
1400 purposes of any verifications.
1401
1402 :param X509 certificate: The certificate to be verified.
1403 """
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001404 store_ctx = _lib.X509_STORE_CTX_new()
1405 self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
1406 self._store = store
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001407 self._cert = certificate
Stephen Holsapple46a09252015-02-12 14:45:43 -08001408 # Make the store context available for use after instantiating this
1409 # class by initializing it now. Per testing, subsequent calls to
1410 # :py:meth:`_init` have no adverse affect.
1411 self._init()
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001412
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001413
1414 def _init(self):
1415 """
1416 Set up the store context for a subsequent verification operation.
1417 """
1418 ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
1419 if ret <= 0:
1420 _raise_current_error()
1421
Jean-Paul Calderoneb7b7fb92015-01-18 15:37:10 -05001422
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001423 def _cleanup(self):
1424 """
1425 Internally cleans up the store context.
1426
1427 The store context can then be reused with a new call to
Stephen Holsapple46a09252015-02-12 14:45:43 -08001428 :py:meth:`_init`.
Stephen Holsapple0d9815f2014-08-27 19:36:53 -07001429 """
1430 _lib.X509_STORE_CTX_cleanup(self._store_ctx)
1431
1432
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001433 def _exception_from_context(self):
1434 """
1435 Convert an OpenSSL native context error failure into a Python
1436 exception.
1437
1438 When a call to native OpenSSL X509_verify_cert fails, additonal information
1439 about the failure can be obtained from the store context.
1440 """
1441 errors = [
1442 _lib.X509_STORE_CTX_get_error(self._store_ctx),
1443 _lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
1444 _native(_ffi.string(_lib.X509_verify_cert_error_string(
1445 _lib.X509_STORE_CTX_get_error(self._store_ctx)))),
1446 ]
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001447 # A context error should always be associated with a certificate, so we
1448 # expect this call to never return :class:`None`.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001449 _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
Stephen Holsapple1f713eb2015-02-09 19:19:44 -08001450 _cert = _lib.X509_dup(_x509)
1451 pycert = X509.__new__(X509)
1452 pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001453 return X509StoreContextError(errors, pycert)
1454
1455
Stephen Holsapple46a09252015-02-12 14:45:43 -08001456 def set_store(self, store):
1457 """
1458 Set the context's trust store.
1459
1460 :param X509Store store: The certificates which will be trusted for the
1461 purposes of any *future* verifications.
1462 """
1463 self._store = store
1464
1465
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001466 def verify_certificate(self):
1467 """
1468 Verify a certificate in a context.
1469
1470 :param store_ctx: The :py:class:`X509StoreContext` to verify.
1471 :raises: Error
1472 """
Stephen Holsapple46a09252015-02-12 14:45:43 -08001473 # Always re-initialize the store context in case
1474 # :py:meth:`verify_certificate` is called multiple times.
Stephen Holsapple08ffaa62015-01-30 17:18:40 -08001475 self._init()
1476 ret = _lib.X509_verify_cert(self._store_ctx)
1477 self._cleanup()
1478 if ret <= 0:
1479 raise self._exception_from_context()
1480
1481
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001482
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001483def load_certificate(type, buffer):
1484 """
1485 Load a certificate from a buffer
1486
1487 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08001488
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001489 :param buffer: The buffer the certificate is stored in
1490 :type buffer: :py:class:`bytes`
1491
1492 :return: The X509 object
1493 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05001494 if isinstance(buffer, _text_type):
1495 buffer = buffer.encode("ascii")
1496
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001497 bio = _new_mem_buf(buffer)
1498
1499 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001500 x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001501 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001502 x509 = _lib.d2i_X509_bio(bio, _ffi.NULL);
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001503 else:
1504 raise ValueError(
1505 "type argument must be FILETYPE_PEM or FILETYPE_ASN1")
1506
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001507 if x509 == _ffi.NULL:
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001508 _raise_current_error()
1509
1510 cert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001511 cert._x509 = _ffi.gc(x509, _lib.X509_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001512 return cert
1513
1514
1515def dump_certificate(type, cert):
1516 """
1517 Dump a certificate to a buffer
1518
Jean-Paul Calderonea12e7d22013-04-03 08:17:34 -04001519 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1520 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001521 :param cert: The certificate to dump
1522 :return: The buffer with the dumped certificate in
1523 """
Jean-Paul Calderone0c73aff2013-03-02 07:45:12 -08001524 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001525
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001526 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001527 result_code = _lib.PEM_write_bio_X509(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001528 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001529 result_code = _lib.i2d_X509_bio(bio, cert._x509)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001530 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001531 result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001532 else:
1533 raise ValueError(
1534 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1535 "FILETYPE_TEXT")
1536
1537 return _bio_to_string(bio)
1538
1539
1540
1541def dump_privatekey(type, pkey, cipher=None, passphrase=None):
1542 """
1543 Dump a private key to a buffer
1544
Jean-Paul Calderonee66fde22013-04-03 08:35:08 -04001545 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or
1546 FILETYPE_TEXT)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001547 :param pkey: The PKey to dump
1548 :param cipher: (optional) if encrypted PEM format, the cipher to
1549 use
1550 :param passphrase: (optional) if encrypted PEM format, this can be either
1551 the passphrase to use, or a callback for providing the
1552 passphrase.
1553 :return: The buffer with the dumped key in
1554 :rtype: :py:data:`str`
1555 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08001556 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001557
1558 if cipher is not None:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001559 if passphrase is None:
1560 raise TypeError(
1561 "if a value is given for cipher "
1562 "one must also be given for passphrase")
1563 cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001564 if cipher_obj == _ffi.NULL:
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08001565 raise ValueError("Invalid cipher name")
1566 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001567 cipher_obj = _ffi.NULL
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001568
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001569 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001570 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001571 result_code = _lib.PEM_write_bio_PrivateKey(
1572 bio, pkey._pkey, cipher_obj, _ffi.NULL, 0,
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08001573 helper.callback, helper.callback_args)
1574 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001575 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001576 result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001577 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001578 rsa = _lib.EVP_PKEY_get1_RSA(pkey._pkey)
1579 result_code = _lib.RSA_print(bio, rsa, 0)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08001580 # TODO RSA_free(rsa)?
1581 else:
1582 raise ValueError(
1583 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or "
1584 "FILETYPE_TEXT")
1585
1586 if result_code == 0:
1587 _raise_current_error()
1588
1589 return _bio_to_string(bio)
1590
1591
1592
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001593def _X509_REVOKED_dup(original):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001594 copy = _lib.X509_REVOKED_new()
1595 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001596 # TODO: This is untested.
1597 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001598
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001599 if original.serialNumber != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001600 _lib.ASN1_INTEGER_free(copy.serialNumber)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001601 copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001602
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001603 if original.revocationDate != _ffi.NULL:
Jonathan Giannuzzib5b93222014-03-20 15:54:29 +01001604 _lib.ASN1_TIME_free(copy.revocationDate)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001605 copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001606
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001607 if original.extensions != _ffi.NULL:
1608 extension_stack = _lib.sk_X509_EXTENSION_new_null()
1609 for i in range(_lib.sk_X509_EXTENSION_num(original.extensions)):
1610 original_ext = _lib.sk_X509_EXTENSION_value(original.extensions, i)
1611 copy_ext = _lib.X509_EXTENSION_dup(original_ext)
1612 _lib.sk_X509_EXTENSION_push(extension_stack, copy_ext)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001613 copy.extensions = extension_stack
1614
1615 copy.sequence = original.sequence
1616 return copy
1617
1618
1619
1620class Revoked(object):
1621 # http://www.openssl.org/docs/apps/x509v3_config.html#CRL_distribution_points_
1622 # which differs from crl_reasons of crypto/x509v3/v3_enum.c that matches
1623 # OCSP_crl_reason_str. We use the latter, just like the command line
1624 # program.
1625 _crl_reasons = [
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001626 b"unspecified",
1627 b"keyCompromise",
1628 b"CACompromise",
1629 b"affiliationChanged",
1630 b"superseded",
1631 b"cessationOfOperation",
1632 b"certificateHold",
1633 # b"removeFromCRL",
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001634 ]
1635
1636 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001637 revoked = _lib.X509_REVOKED_new()
1638 self._revoked = _ffi.gc(revoked, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001639
1640
1641 def set_serial(self, hex_str):
1642 """
1643 Set the serial number of a revoked Revoked structure
1644
1645 :param hex_str: The new serial number.
1646 :type hex_str: :py:data:`str`
1647 :return: None
1648 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001649 bignum_serial = _ffi.gc(_lib.BN_new(), _lib.BN_free)
1650 bignum_ptr = _ffi.new("BIGNUM**")
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001651 bignum_ptr[0] = bignum_serial
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001652 bn_result = _lib.BN_hex2bn(bignum_ptr, hex_str)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001653 if not bn_result:
1654 raise ValueError("bad hex string")
1655
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001656 asn1_serial = _ffi.gc(
1657 _lib.BN_to_ASN1_INTEGER(bignum_serial, _ffi.NULL),
1658 _lib.ASN1_INTEGER_free)
1659 _lib.X509_REVOKED_set_serialNumber(self._revoked, asn1_serial)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001660
1661
1662 def get_serial(self):
1663 """
1664 Return the serial number of a Revoked structure
1665
1666 :return: The serial number as a string
1667 """
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001668 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001669
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001670 result = _lib.i2a_ASN1_INTEGER(bio, self._revoked.serialNumber)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001671 if result < 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001672 # TODO: This is untested.
1673 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001674
1675 return _bio_to_string(bio)
1676
1677
1678 def _delete_reason(self):
1679 stack = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001680 for i in range(_lib.sk_X509_EXTENSION_num(stack)):
1681 ext = _lib.sk_X509_EXTENSION_value(stack, i)
1682 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
1683 _lib.X509_EXTENSION_free(ext)
1684 _lib.sk_X509_EXTENSION_delete(stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001685 break
1686
1687
1688 def set_reason(self, reason):
1689 """
1690 Set the reason of a Revoked object.
1691
1692 If :py:data:`reason` is :py:data:`None`, delete the reason instead.
1693
1694 :param reason: The reason string.
1695 :type reason: :py:class:`str` or :py:class:`NoneType`
1696 :return: None
1697 """
1698 if reason is None:
1699 self._delete_reason()
1700 elif not isinstance(reason, bytes):
1701 raise TypeError("reason must be None or a byte string")
1702 else:
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05001703 reason = reason.lower().replace(b' ', b'')
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001704 reason_code = [r.lower() for r in self._crl_reasons].index(reason)
1705
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001706 new_reason_ext = _lib.ASN1_ENUMERATED_new()
1707 if new_reason_ext == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001708 # TODO: This is untested.
1709 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001710 new_reason_ext = _ffi.gc(new_reason_ext, _lib.ASN1_ENUMERATED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001711
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001712 set_result = _lib.ASN1_ENUMERATED_set(new_reason_ext, reason_code)
1713 if set_result == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001714 # TODO: This is untested.
1715 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001716
1717 self._delete_reason()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001718 add_result = _lib.X509_REVOKED_add1_ext_i2d(
1719 self._revoked, _lib.NID_crl_reason, new_reason_ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001720
1721 if not add_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001722 # TODO: This is untested.
1723 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001724
1725
1726 def get_reason(self):
1727 """
1728 Return the reason of a Revoked object.
1729
1730 :return: The reason as a string
1731 """
1732 extensions = self._revoked.extensions
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001733 for i in range(_lib.sk_X509_EXTENSION_num(extensions)):
1734 ext = _lib.sk_X509_EXTENSION_value(extensions, i)
1735 if _lib.OBJ_obj2nid(ext.object) == _lib.NID_crl_reason:
Jean-Paul Calderonefd371362013-03-01 20:53:58 -08001736 bio = _new_mem_buf()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001737
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001738 print_result = _lib.X509V3_EXT_print(bio, ext, 0, 0)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001739 if not print_result:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001740 print_result = _lib.M_ASN1_OCTET_STRING_print(bio, ext.value)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001741 if print_result == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001742 # TODO: This is untested.
1743 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001744
1745 return _bio_to_string(bio)
1746
1747
1748 def all_reasons(self):
1749 """
1750 Return a list of all the supported reason strings.
1751
1752 :return: A list of reason strings.
1753 """
1754 return self._crl_reasons[:]
1755
1756
1757 def set_rev_date(self, when):
1758 """
1759 Set the revocation timestamp
1760
1761 :param when: A string giving the timestamp, in the format:
1762
1763 YYYYMMDDhhmmssZ
1764 YYYYMMDDhhmmss+hhmm
1765 YYYYMMDDhhmmss-hhmm
1766
1767 :return: None
1768 """
1769 return _set_asn1_time(self._revoked.revocationDate, when)
1770
1771
1772 def get_rev_date(self):
1773 """
1774 Retrieve the revocation date
1775
1776 :return: A string giving the timestamp, in the format:
1777
1778 YYYYMMDDhhmmssZ
1779 YYYYMMDDhhmmss+hhmm
1780 YYYYMMDDhhmmss-hhmm
1781 """
1782 return _get_asn1_time(self._revoked.revocationDate)
1783
1784
1785
1786class CRL(object):
1787 def __init__(self):
1788 """
1789 Create a new empty CRL object.
1790 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001791 crl = _lib.X509_CRL_new()
1792 self._crl = _ffi.gc(crl, _lib.X509_CRL_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001793
1794
1795 def get_revoked(self):
1796 """
1797 Return revoked portion of the CRL structure (by value not reference).
1798
1799 :return: A tuple of Revoked objects.
1800 """
1801 results = []
1802 revoked_stack = self._crl.crl.revoked
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001803 for i in range(_lib.sk_X509_REVOKED_num(revoked_stack)):
1804 revoked = _lib.sk_X509_REVOKED_value(revoked_stack, i)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001805 revoked_copy = _X509_REVOKED_dup(revoked)
1806 pyrev = Revoked.__new__(Revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001807 pyrev._revoked = _ffi.gc(revoked_copy, _lib.X509_REVOKED_free)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001808 results.append(pyrev)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001809 if results:
1810 return tuple(results)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001811
1812
1813 def add_revoked(self, revoked):
1814 """
1815 Add a revoked (by value not reference) to the CRL structure
1816
1817 :param revoked: The new revoked.
1818 :type revoked: :class:`X509`
1819
1820 :return: None
1821 """
1822 copy = _X509_REVOKED_dup(revoked._revoked)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001823 if copy == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001824 # TODO: This is untested.
1825 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001826
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001827 add_result = _lib.X509_CRL_add0_revoked(self._crl, copy)
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001828 if add_result == 0:
1829 # TODO: This is untested.
1830 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001831
1832
1833 def export(self, cert, key, type=FILETYPE_PEM, days=100):
1834 """
1835 export a CRL as a string
1836
1837 :param cert: Used to sign CRL.
1838 :type cert: :class:`X509`
1839
1840 :param key: Used to sign CRL.
1841 :type key: :class:`PKey`
1842
1843 :param type: The export format, either :py:data:`FILETYPE_PEM`, :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
1844
1845 :param days: The number of days until the next update of this CRL.
1846 :type days: :py:data:`int`
1847
1848 :return: :py:data:`str`
1849 """
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001850 if not isinstance(cert, X509):
1851 raise TypeError("cert must be an X509 instance")
1852 if not isinstance(key, PKey):
1853 raise TypeError("key must be a PKey instance")
1854 if not isinstance(type, int):
1855 raise TypeError("type must be an integer")
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001856
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001857 bio = _lib.BIO_new(_lib.BIO_s_mem())
1858 if bio == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001859 # TODO: This is untested.
1860 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001861
1862 # A scratch time object to give different values to different CRL fields
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001863 sometime = _lib.ASN1_TIME_new()
1864 if sometime == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001865 # TODO: This is untested.
1866 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001867
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001868 _lib.X509_gmtime_adj(sometime, 0)
1869 _lib.X509_CRL_set_lastUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001870
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001871 _lib.X509_gmtime_adj(sometime, days * 24 * 60 * 60)
1872 _lib.X509_CRL_set_nextUpdate(self._crl, sometime)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001873
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001874 _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001875
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001876 sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, _lib.EVP_md5())
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001877 if not sign_result:
1878 _raise_current_error()
1879
1880 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001881 ret = _lib.PEM_write_bio_X509_CRL(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001882 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001883 ret = _lib.i2d_X509_CRL_bio(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001884 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001885 ret = _lib.X509_CRL_print(bio, self._crl)
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001886 else:
1887 raise ValueError(
1888 "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
1889
1890 if not ret:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05001891 # TODO: This is untested.
1892 _raise_current_error()
Jean-Paul Calderone85b74eb2013-02-21 09:15:01 -08001893
1894 return _bio_to_string(bio)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08001895CRLType = CRL
1896
1897
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08001898
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001899class PKCS7(object):
1900 def type_is_signed(self):
1901 """
1902 Check if this NID_pkcs7_signed object
1903
1904 :return: True if the PKCS7 is of type signed
1905 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001906 if _lib.PKCS7_type_is_signed(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001907 return True
1908 return False
1909
1910
1911 def type_is_enveloped(self):
1912 """
1913 Check if this NID_pkcs7_enveloped object
1914
1915 :returns: True if the PKCS7 is of type enveloped
1916 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001917 if _lib.PKCS7_type_is_enveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001918 return True
1919 return False
1920
1921
1922 def type_is_signedAndEnveloped(self):
1923 """
1924 Check if this NID_pkcs7_signedAndEnveloped object
1925
1926 :returns: True if the PKCS7 is of type signedAndEnveloped
1927 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001928 if _lib.PKCS7_type_is_signedAndEnveloped(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001929 return True
1930 return False
1931
1932
1933 def type_is_data(self):
1934 """
1935 Check if this NID_pkcs7_data object
1936
1937 :return: True if the PKCS7 is of type data
1938 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001939 if _lib.PKCS7_type_is_data(self._pkcs7):
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001940 return True
1941 return False
1942
1943
1944 def get_type_name(self):
1945 """
1946 Returns the type name of the PKCS7 structure
1947
1948 :return: A string with the typename
1949 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05001950 nid = _lib.OBJ_obj2nid(self._pkcs7.type)
1951 string_type = _lib.OBJ_nid2sn(nid)
1952 return _ffi.string(string_type)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08001953
1954PKCS7Type = PKCS7
1955
1956
1957
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08001958class PKCS12(object):
1959 def __init__(self):
1960 self._pkey = None
1961 self._cert = None
1962 self._cacerts = None
1963 self._friendlyname = None
1964
1965
1966 def get_certificate(self):
1967 """
1968 Return certificate portion of the PKCS12 structure
1969
1970 :return: X509 object containing the certificate
1971 """
1972 return self._cert
1973
1974
1975 def set_certificate(self, cert):
1976 """
1977 Replace the certificate portion of the PKCS12 structure
1978
1979 :param cert: The new certificate.
1980 :type cert: :py:class:`X509` or :py:data:`None`
1981 :return: None
1982 """
1983 if not isinstance(cert, X509):
1984 raise TypeError("cert must be an X509 instance")
1985 self._cert = cert
1986
1987
1988 def get_privatekey(self):
1989 """
1990 Return private key portion of the PKCS12 structure
1991
1992 :returns: PKey object containing the private key
1993 """
1994 return self._pkey
1995
1996
1997 def set_privatekey(self, pkey):
1998 """
1999 Replace or set the certificate portion of the PKCS12 structure
2000
2001 :param pkey: The new private key.
2002 :type pkey: :py:class:`PKey`
2003 :return: None
2004 """
2005 if not isinstance(pkey, PKey):
2006 raise TypeError("pkey must be a PKey instance")
2007 self._pkey = pkey
2008
2009
2010 def get_ca_certificates(self):
2011 """
2012 Return CA certificates within of the PKCS12 object
2013
2014 :return: A newly created tuple containing the CA certificates in the chain,
2015 if any are present, or None if no CA certificates are present.
2016 """
2017 if self._cacerts is not None:
2018 return tuple(self._cacerts)
2019
2020
2021 def set_ca_certificates(self, cacerts):
2022 """
Alex Gaynor3b0ee972014-11-15 09:17:33 -08002023 Replace or set the CA certificates within the PKCS12 object.
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002024
2025 :param cacerts: The new CA certificates.
2026 :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
2027 :return: None
2028 """
2029 if cacerts is None:
2030 self._cacerts = None
2031 else:
2032 cacerts = list(cacerts)
2033 for cert in cacerts:
2034 if not isinstance(cert, X509):
2035 raise TypeError("iterable must only contain X509 instances")
2036 self._cacerts = cacerts
2037
2038
2039 def set_friendlyname(self, name):
2040 """
2041 Replace or set the certificate portion of the PKCS12 structure
2042
2043 :param name: The new friendly name.
2044 :type name: :py:class:`bytes`
2045 :return: None
2046 """
2047 if name is None:
2048 self._friendlyname = None
2049 elif not isinstance(name, bytes):
2050 raise TypeError("name must be a byte string or None (not %r)" % (name,))
2051 self._friendlyname = name
2052
2053
2054 def get_friendlyname(self):
2055 """
2056 Return friendly name portion of the PKCS12 structure
2057
2058 :returns: String containing the friendlyname
2059 """
2060 return self._friendlyname
2061
2062
2063 def export(self, passphrase=None, iter=2048, maciter=1):
2064 """
2065 Dump a PKCS12 object as a string. See also "man PKCS12_create".
2066
2067 :param passphrase: used to encrypt the PKCS12
2068 :type passphrase: :py:data:`bytes`
2069
2070 :param iter: How many times to repeat the encryption
2071 :type iter: :py:data:`int`
2072
2073 :param maciter: How many times to repeat the MAC
2074 :type maciter: :py:data:`int`
2075
2076 :return: The string containing the PKCS12
2077 """
Jean-Paul Calderone6462b072015-03-29 07:03:11 -04002078 passphrase = _warn_text("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002079
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002080 if self._cacerts is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002081 cacerts = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002082 else:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002083 cacerts = _lib.sk_X509_new_null()
2084 cacerts = _ffi.gc(cacerts, _lib.sk_X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002085 for cert in self._cacerts:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002086 _lib.sk_X509_push(cacerts, cert._x509)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002087
2088 if passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002089 passphrase = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002090
2091 friendlyname = self._friendlyname
2092 if friendlyname is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002093 friendlyname = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002094
2095 if self._pkey is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002096 pkey = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002097 else:
2098 pkey = self._pkey._pkey
2099
2100 if self._cert is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002101 cert = _ffi.NULL
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002102 else:
2103 cert = self._cert._x509
2104
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002105 pkcs12 = _lib.PKCS12_create(
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002106 passphrase, friendlyname, pkey, cert, cacerts,
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002107 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
2108 _lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002109 iter, maciter, 0)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002110 if pkcs12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002111 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002112 pkcs12 = _ffi.gc(pkcs12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002113
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002114 bio = _new_mem_buf()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002115 _lib.i2d_PKCS12_bio(bio, pkcs12)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002116 return _bio_to_string(bio)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002117
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002118PKCS12Type = PKCS12
2119
2120
2121
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002122class NetscapeSPKI(object):
2123 def __init__(self):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002124 spki = _lib.NETSCAPE_SPKI_new()
2125 self._spki = _ffi.gc(spki, _lib.NETSCAPE_SPKI_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002126
2127
2128 def sign(self, pkey, digest):
2129 """
2130 Sign the certificate request using the supplied key and digest
2131
2132 :param pkey: The key to sign with
2133 :param digest: The message digest to use
2134 :return: None
2135 """
2136 if pkey._only_public:
2137 raise ValueError("Key has only public part")
2138
2139 if not pkey._initialized:
2140 raise ValueError("Key is uninitialized")
2141
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002142 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002143 if digest_obj == _ffi.NULL:
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002144 raise ValueError("No such digest method")
2145
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002146 sign_result = _lib.NETSCAPE_SPKI_sign(self._spki, pkey._pkey, digest_obj)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002147 if not sign_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002148 # TODO: This is untested.
2149 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002150
2151
2152 def verify(self, key):
2153 """
2154 Verifies a certificate request using the supplied public key
2155
2156 :param key: a public key
2157 :return: True if the signature is correct.
2158 :raise OpenSSL.crypto.Error: If the signature is invalid or there is a
2159 problem verifying the signature.
2160 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002161 answer = _lib.NETSCAPE_SPKI_verify(self._spki, key._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002162 if answer <= 0:
2163 _raise_current_error()
2164 return True
2165
2166
2167 def b64_encode(self):
2168 """
2169 Generate a base64 encoded string from an SPKI
2170
2171 :return: The base64 encoded string
2172 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002173 encoded = _lib.NETSCAPE_SPKI_b64_encode(self._spki)
2174 result = _ffi.string(encoded)
2175 _lib.CRYPTO_free(encoded)
Jean-Paul Calderone2c2e21d2013-03-02 16:50:35 -08002176 return result
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002177
2178
2179 def get_pubkey(self):
2180 """
2181 Get the public key of the certificate
2182
2183 :return: The public key
2184 """
2185 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002186 pkey._pkey = _lib.NETSCAPE_SPKI_get_pubkey(self._spki)
2187 if pkey._pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002188 # TODO: This is untested.
2189 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002190 pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002191 pkey._only_public = True
2192 return pkey
2193
2194
2195 def set_pubkey(self, pkey):
2196 """
2197 Set the public key of the certificate
2198
2199 :param pkey: The public key
2200 :return: None
2201 """
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002202 set_result = _lib.NETSCAPE_SPKI_set_pubkey(self._spki, pkey._pkey)
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002203 if not set_result:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002204 # TODO: This is untested.
2205 _raise_current_error()
Jean-Paul Calderone3b89f472013-02-21 09:32:25 -08002206NetscapeSPKIType = NetscapeSPKI
2207
2208
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002209class _PassphraseHelper(object):
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002210 def __init__(self, type, passphrase, more_args=False, truncate=False):
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002211 if type != FILETYPE_PEM and passphrase is not None:
2212 raise ValueError("only FILETYPE_PEM key format supports encryption")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002213 self._passphrase = passphrase
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002214 self._more_args = more_args
2215 self._truncate = truncate
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002216 self._problems = []
2217
2218
2219 @property
2220 def callback(self):
2221 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002222 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002223 elif isinstance(self._passphrase, bytes):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002224 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002225 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002226 return _ffi.callback("pem_password_cb", self._read_passphrase)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002227 else:
2228 raise TypeError("Last argument must be string or callable")
2229
2230
2231 @property
2232 def callback_args(self):
2233 if self._passphrase is None:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002234 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002235 elif isinstance(self._passphrase, bytes):
2236 return self._passphrase
2237 elif callable(self._passphrase):
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002238 return _ffi.NULL
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002239 else:
2240 raise TypeError("Last argument must be string or callable")
2241
2242
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002243 def raise_if_problem(self, exceptionType=Error):
2244 try:
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05002245 _exception_from_error_queue(exceptionType)
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002246 except exceptionType as e:
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002247 from_queue = e
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002248 if self._problems:
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002249 raise self._problems[0]
Jean-Paul Calderone9b4115f2014-01-10 14:06:04 -05002250 return from_queue
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002251
2252
2253 def _read_passphrase(self, buf, size, rwflag, userdata):
2254 try:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002255 if self._more_args:
2256 result = self._passphrase(size, rwflag, userdata)
2257 else:
2258 result = self._passphrase(rwflag)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002259 if not isinstance(result, bytes):
2260 raise ValueError("String expected")
2261 if len(result) > size:
Jean-Paul Calderone8a1bea52013-03-05 07:57:57 -08002262 if self._truncate:
2263 result = result[:size]
2264 else:
2265 raise ValueError("passphrase returned by callback is too long")
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002266 for i in range(len(result)):
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002267 buf[i] = result[i:i + 1]
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002268 return len(result)
2269 except Exception as e:
2270 self._problems.append(e)
2271 return 0
2272
2273
2274
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002275def load_privatekey(type, buffer, passphrase=None):
2276 """
2277 Load a private key from a buffer
2278
2279 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2280 :param buffer: The buffer the key is stored in
2281 :param passphrase: (optional) if encrypted PEM format, this can be
2282 either the passphrase to use, or a callback for
2283 providing the passphrase.
2284
2285 :return: The PKey object
2286 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002287 if isinstance(buffer, _text_type):
2288 buffer = buffer.encode("ascii")
2289
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002290 bio = _new_mem_buf(buffer)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002291
Jean-Paul Calderone23478b32013-02-20 13:31:38 -08002292 helper = _PassphraseHelper(type, passphrase)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002293 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002294 evp_pkey = _lib.PEM_read_bio_PrivateKey(
2295 bio, _ffi.NULL, helper.callback, helper.callback_args)
Jean-Paul Calderonee41f05c2013-02-20 13:28:16 -08002296 helper.raise_if_problem()
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002297 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002298 evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002299 else:
2300 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2301
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002302 if evp_pkey == _ffi.NULL:
Jean-Paul Calderone31393aa2013-02-20 13:22:21 -08002303 _raise_current_error()
2304
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002305 pkey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002306 pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002307 return pkey
2308
2309
2310
2311def dump_certificate_request(type, req):
2312 """
2313 Dump a certificate request to a buffer
2314
2315 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2316 :param req: The certificate request to dump
2317 :return: The buffer with the dumped certificate request in
2318 """
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002319 bio = _new_mem_buf()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002320
2321 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002322 result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002323 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002324 result_code = _lib.i2d_X509_REQ_bio(bio, req._req)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002325 elif type == FILETYPE_TEXT:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002326 result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002327 else:
Jean-Paul Calderonec9a395f2013-02-20 16:59:21 -08002328 raise ValueError("type argument must be FILETYPE_PEM, FILETYPE_ASN1, or FILETYPE_TEXT")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002329
2330 if result_code == 0:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002331 # TODO: This is untested.
2332 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002333
2334 return _bio_to_string(bio)
Jean-Paul Calderoneabfbab62013-02-09 21:25:02 -08002335
2336
2337
2338def load_certificate_request(type, buffer):
2339 """
2340 Load a certificate request from a buffer
2341
2342 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2343 :param buffer: The buffer the certificate request is stored in
2344 :return: The X509Req object
2345 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002346 if isinstance(buffer, _text_type):
2347 buffer = buffer.encode("ascii")
2348
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002349 bio = _new_mem_buf(buffer)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002350
2351 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002352 req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002353 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002354 req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002355 else:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002356 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002357
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002358 if req == _ffi.NULL:
Jean-Paul Calderone4a68b402013-12-29 16:54:58 -05002359 # TODO: This is untested.
2360 _raise_current_error()
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002361
2362 x509req = X509Req.__new__(X509Req)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002363 x509req._req = _ffi.gc(req, _lib.X509_REQ_free)
Jean-Paul Calderone066f0572013-02-20 13:43:44 -08002364 return x509req
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002365
2366
2367
2368def sign(pkey, data, digest):
2369 """
2370 Sign data with a digest
2371
2372 :param pkey: Pkey to sign with
2373 :param data: data to be signed
2374 :param digest: message digest to use
2375 :return: signature
2376 """
Jean-Paul Calderone6462b072015-03-29 07:03:11 -04002377 data = _warn_text("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002378
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002379 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002380 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002381 raise ValueError("No such digest method")
2382
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002383 md_ctx = _ffi.new("EVP_MD_CTX*")
2384 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002385
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002386 _lib.EVP_SignInit(md_ctx, digest_obj)
2387 _lib.EVP_SignUpdate(md_ctx, data, len(data))
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002388
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002389 signature_buffer = _ffi.new("unsigned char[]", 512)
2390 signature_length = _ffi.new("unsigned int*")
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002391 signature_length[0] = len(signature_buffer)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002392 final_result = _lib.EVP_SignFinal(
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002393 md_ctx, signature_buffer, signature_length, pkey._pkey)
2394
2395 if final_result != 1:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002396 # TODO: This is untested.
2397 _raise_current_error()
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002398
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002399 return _ffi.buffer(signature_buffer, signature_length[0])[:]
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002400
2401
2402
2403def verify(cert, signature, data, digest):
2404 """
2405 Verify a signature
2406
2407 :param cert: signing certificate (X509 object)
2408 :param signature: signature returned by sign function
2409 :param data: data to be verified
2410 :param digest: message digest to use
2411 :return: None if the signature is correct, raise exception otherwise
2412 """
Jean-Paul Calderone6462b072015-03-29 07:03:11 -04002413 data = _warn_text("data", data)
Abraham Martine82326c2015-02-04 10:18:10 +00002414
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05002415 digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002416 if digest_obj == _ffi.NULL:
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002417 raise ValueError("No such digest method")
2418
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002419 pkey = _lib.X509_get_pubkey(cert._x509)
2420 if pkey == _ffi.NULL:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002421 # TODO: This is untested.
2422 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002423 pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002424
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002425 md_ctx = _ffi.new("EVP_MD_CTX*")
2426 md_ctx = _ffi.gc(md_ctx, _lib.EVP_MD_CTX_cleanup)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002427
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002428 _lib.EVP_VerifyInit(md_ctx, digest_obj)
2429 _lib.EVP_VerifyUpdate(md_ctx, data, len(data))
2430 verify_result = _lib.EVP_VerifyFinal(md_ctx, signature, len(signature), pkey)
Jean-Paul Calderone8cf4f802013-02-20 16:45:02 -08002431
2432 if verify_result != 1:
2433 _raise_current_error()
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002434
2435
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002436def load_crl(type, buffer):
2437 """
2438 Load a certificate revocation list from a buffer
2439
2440 :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)
2441 :param buffer: The buffer the CRL is stored in
2442
2443 :return: The PKey object
2444 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002445 if isinstance(buffer, _text_type):
2446 buffer = buffer.encode("ascii")
2447
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002448 bio = _new_mem_buf(buffer)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002449
2450 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002451 crl = _lib.PEM_read_bio_X509_CRL(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002452 elif type == FILETYPE_ASN1:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002453 crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL)
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002454 else:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002455 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2456
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002457 if crl == _ffi.NULL:
Jean-Paul Calderone57122982013-02-21 08:47:05 -08002458 _raise_current_error()
2459
2460 result = CRL.__new__(CRL)
2461 result._crl = crl
2462 return result
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002463
2464
2465
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002466def load_pkcs7_data(type, buffer):
2467 """
2468 Load pkcs7 data from a buffer
2469
2470 :param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)
2471 :param buffer: The buffer with the pkcs7 data.
2472 :return: The PKCS7 object
2473 """
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002474 if isinstance(buffer, _text_type):
2475 buffer = buffer.encode("ascii")
2476
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002477 bio = _new_mem_buf(buffer)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002478
2479 if type == FILETYPE_PEM:
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002480 pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002481 elif type == FILETYPE_ASN1:
Alex Gaynor77acc362014-08-13 14:46:15 -07002482 pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002483 else:
Jean-Paul Calderonedba578b2013-12-29 17:00:04 -05002484 # TODO: This is untested.
2485 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002486 raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1")
2487
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002488 if pkcs7 == _ffi.NULL:
Jean-Paul Calderoneb0f64712013-03-03 10:15:39 -08002489 _raise_current_error()
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002490
2491 pypkcs7 = PKCS7.__new__(PKCS7)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002492 pypkcs7._pkcs7 = _ffi.gc(pkcs7, _lib.PKCS7_free)
Jean-Paul Calderone4e8be1c2013-02-21 18:31:12 -08002493 return pypkcs7
2494
2495
2496
Stephen Holsapple38482622014-04-05 20:29:34 -07002497def load_pkcs12(buffer, passphrase=None):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002498 """
2499 Load a PKCS12 object from a buffer
2500
2501 :param buffer: The buffer the certificate is stored in
2502 :param passphrase: (Optional) The password to decrypt the PKCS12 lump
2503 :returns: The PKCS12 object
2504 """
Jean-Paul Calderone6462b072015-03-29 07:03:11 -04002505 passphrase = _warn_text("passphrase", passphrase)
Abraham Martine82326c2015-02-04 10:18:10 +00002506
Jean-Paul Calderone6922a862014-01-18 10:38:28 -05002507 if isinstance(buffer, _text_type):
2508 buffer = buffer.encode("ascii")
2509
Jean-Paul Calderonef6745b32013-03-01 15:08:46 -08002510 bio = _new_mem_buf(buffer)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002511
Stephen Holsapple38482622014-04-05 20:29:34 -07002512 # Use null passphrase if passphrase is None or empty string. With PKCS#12
2513 # password based encryption no password and a zero length password are two
2514 # different things, but OpenSSL implementation will try both to figure out
2515 # which one works.
2516 if not passphrase:
2517 passphrase = _ffi.NULL
2518
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002519 p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
2520 if p12 == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002521 _raise_current_error()
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002522 p12 = _ffi.gc(p12, _lib.PKCS12_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002523
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002524 pkey = _ffi.new("EVP_PKEY**")
2525 cert = _ffi.new("X509**")
2526 cacerts = _ffi.new("Cryptography_STACK_OF_X509**")
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002527
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002528 parse_result = _lib.PKCS12_parse(p12, passphrase, pkey, cert, cacerts)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002529 if not parse_result:
2530 _raise_current_error()
2531
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002532 cacerts = _ffi.gc(cacerts[0], _lib.sk_X509_free)
Jean-Paul Calderoneef9a3dc2013-03-02 16:33:32 -08002533
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002534 # openssl 1.0.0 sometimes leaves an X509_check_private_key error in the
2535 # queue for no particular reason. This error isn't interesting to anyone
2536 # outside this function. It's not even interesting to us. Get rid of it.
2537 try:
2538 _raise_current_error()
2539 except Error:
2540 pass
2541
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002542 if pkey[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002543 pykey = None
2544 else:
2545 pykey = PKey.__new__(PKey)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002546 pykey._pkey = _ffi.gc(pkey[0], _lib.EVP_PKEY_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002547
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002548 if cert[0] == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002549 pycert = None
2550 friendlyname = None
2551 else:
2552 pycert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002553 pycert._x509 = _ffi.gc(cert[0], _lib.X509_free)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002554
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002555 friendlyname_length = _ffi.new("int*")
2556 friendlyname_buffer = _lib.X509_alias_get0(cert[0], friendlyname_length)
2557 friendlyname = _ffi.buffer(friendlyname_buffer, friendlyname_length[0])[:]
2558 if friendlyname_buffer == _ffi.NULL:
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002559 friendlyname = None
2560
2561 pycacerts = []
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002562 for i in range(_lib.sk_X509_num(cacerts)):
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002563 pycacert = X509.__new__(X509)
Jean-Paul Calderone6037d072013-12-28 18:04:00 -05002564 pycacert._x509 = _lib.sk_X509_value(cacerts, i)
Jean-Paul Calderonee5912ce2013-02-21 10:49:35 -08002565 pycacerts.append(pycacert)
2566 if not pycacerts:
2567 pycacerts = None
2568
2569 pkcs12 = PKCS12.__new__(PKCS12)
2570 pkcs12._pkey = pykey
2571 pkcs12._cert = pycert
2572 pkcs12._cacerts = pycacerts
2573 pkcs12._friendlyname = friendlyname
2574 return pkcs12
Jean-Paul Calderone6bb40892014-01-01 12:21:34 -05002575
2576
2577def _initialize_openssl_threads(get_ident, Lock):
2578 import _ssl
2579 return
2580
2581 locks = list(Lock() for n in range(_lib.CRYPTO_num_locks()))
2582
2583 def locking_function(mode, index, filename, line):
2584 if mode & _lib.CRYPTO_LOCK:
2585 locks[index].acquire()
2586 else:
2587 locks[index].release()
2588
2589 _lib.CRYPTO_set_id_callback(
2590 _ffi.callback("unsigned long (*)(void)", get_ident))
2591
2592 _lib.CRYPTO_set_locking_callback(
2593 _ffi.callback(
2594 "void (*)(int, int, const char*, int)", locking_function))
2595
2596
2597try:
2598 from thread import get_ident
2599 from threading import Lock
2600except ImportError:
2601 pass
2602else:
2603 _initialize_openssl_threads(get_ident, Lock)
2604 del get_ident, Lock
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002605
Jean-Paul Calderoneb64e2a22014-01-11 08:06:35 -05002606# There are no direct unit tests for this initialization. It is tested
2607# indirectly since it is necessary for functions like dump_privatekey when
2608# using encryption.
2609#
2610# Thus OpenSSL.test.test_crypto.FunctionTests.test_dump_privatekey_passphrase
2611# and some other similar tests may fail without this (though they may not if
2612# the Python runtime has already done some initialization of the underlying
2613# OpenSSL library (and is linked against the same one that cryptography is
2614# using)).
Jean-Paul Calderonee324fd62014-01-11 08:00:33 -05002615_lib.OpenSSL_add_all_algorithms()
Jean-Paul Calderone11ed8e82014-01-18 10:21:50 -05002616
Jean-Paul Calderonefab157b2014-01-18 11:21:38 -05002617# This is similar but exercised mainly by exception_from_error_queue. It calls
2618# both ERR_load_crypto_strings() and ERR_load_SSL_strings().
2619_lib.SSL_load_error_strings()