blob: a4fe63a6d04fe11875c2416df2d43d93cb8cea4d [file] [log] [blame]
Jean-Paul Calderonecbb68cc2015-04-11 12:41:30 -04001import sys
2
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -05003from six import PY3, binary_type, text_type
4
Jean-Paul Calderonee36b31a2014-01-08 16:55:06 -05005from cryptography.hazmat.bindings.openssl.binding import Binding
6binding = Binding()
7ffi = binding.ffi
8lib = binding.lib
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -05009
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070010
11
12def text(charp):
Jean-Paul Calderone130cd0e2015-03-15 15:49:33 -040013 """
14 Get a native string type representing of the given CFFI ``char*`` object.
15
16 :param charp: A C-style string represented using CFFI.
17
18 :return: :class:`str`
19 """
Jean-Paul Calderone6d862182015-04-11 07:24:52 -040020 if not charp:
21 return ""
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070022 return native(ffi.string(charp))
23
24
25
26def exception_from_error_queue(exception_type):
27 """
28 Convert an OpenSSL library failure into a Python exception.
29
30 When a call to the native OpenSSL library fails, this is usually signalled
31 by the return value, and an error code is stored in an error queue
32 associated with the current thread. The err library provides functions to
33 obtain these error codes and textual error messages.
34 """
Jean-Paul Calderonede075462014-01-18 10:34:12 -050035
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050036 errors = []
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070037
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050038 while True:
39 error = lib.ERR_get_error()
40 if error == 0:
41 break
42 errors.append((
Jean-Paul Calderonede075462014-01-18 10:34:12 -050043 text(lib.ERR_lib_error_string(error)),
44 text(lib.ERR_func_error_string(error)),
45 text(lib.ERR_reason_error_string(error))))
Jean-Paul Calderonec86bb7d2013-12-29 10:25:59 -050046
Stephen Holsapple0d9815f2014-08-27 19:36:53 -070047 raise exception_type(errors)
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050048
49
50
51def native(s):
52 """
53 Convert :py:class:`bytes` or :py:class:`unicode` to the native
Jean-Paul Calderoneaca50f42014-01-11 14:43:37 -050054 :py:class:`str` type, using UTF-8 encoding if conversion is necessary.
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050055
56 :raise UnicodeError: The input string is not UTF-8 decodeable.
57
58 :raise TypeError: The input is neither :py:class:`bytes` nor
59 :py:class:`unicode`.
60 """
61 if not isinstance(s, (binary_type, text_type)):
62 raise TypeError("%r is neither bytes nor unicode" % s)
63 if PY3:
64 if isinstance(s, binary_type):
65 return s.decode("utf-8")
66 else:
67 if isinstance(s, text_type):
68 return s.encode("utf-8")
69 return s
70
71
72
Jean-Paul Calderonecbb68cc2015-04-11 12:41:30 -040073def path_string(s):
74 """
75 Convert a Python string to a :py:class:`bytes` string identifying the same
76 path and which can be passed into an OpenSSL API accepting a filename.
77
78 :param s: An instance of :py:class:`bytes` or :py:class:`unicode`.
79
80 :return: An instance of :py:class:`bytes`.
81 """
82 if isinstance(s, binary_type):
83 return s
84 elif isinstance(s, text_type):
85 return s.encode(sys.getfilesystemencoding())
86 else:
87 raise TypeError("Path must be represented as bytes or unicode string")
88
89
Jean-Paul Calderone4f0467a2014-01-11 11:58:41 -050090if PY3:
91 def byte_string(s):
92 return s.encode("charmap")
93else:
94 def byte_string(s):
95 return s
Jean-Paul Calderone00f84eb2015-04-13 12:47:21 -040096
97
98# A marker object to observe whether some optional arguments are passed any
99# value or not.
100UNSPECIFIED = object()