blob: 1c134ad487edb9282c90c3d77b431e336e91e7cc [file] [log] [blame]
Laurens Van Houtven7d2c74e2014-06-23 13:49:58 +02001C bindings
2==========
3
4C bindings are bindings to C libraries, using cffi_ whenever possible.
5
6.. _cffi:: http://cffi.readthedocs.org
7
8Bindings live in :py:mod:`cryptography.hazmat.bindings`.
Laurens Van Houtvenefa5cfb2014-06-23 13:51:35 +02009
10Adding constant, types, functions...
11------------------------------------
12
13You can create bindings for any name that exists in some version of
14the library you're binding against. However, the project also has to
15keep supporting older versions of the library. In order to acchieve
16this, binding modules have ``CUSTOMIZATIONS`` and
17``CONDITIONAL_NAMES`` constants.
18
19Let's say you want to enable quantum transmogrification. The upstream
20library implements this as the following API::
21
22 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT;
23 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT;
24 typedef ... QM_TRANSMOGRIFICATION_CTX;
25 int QM_transmogrify(QM_TRANSMOGRIFICATION_CTX *, int);
26
27To start, create a new constant that defines if the *actual* library
28has the feature you want, and add it to ``TYPES``::
29
30 static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION;
31
32This should start with ``Cryptography_``, since we're adding it in
33this library. This prevents namespace collisions.
34
35Then, define the actual features (constants, types, functions...) you
36want to expose. If it's a constant, just add it to ``TYPES``::
37
38 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT;
39 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT;
40
41If it's a struct, add it to ``TYPES`` as well. The following is an
42opaque struct::
43
44 typedef ... QM_TRANSMOGRIFICATION_CTX;
45
46... but you can also make some or all items in the struct accessible::
47
48 typedef struct {
49 /* Fundamental constant k for your particular universe */
50 BIGNUM *k;
51 ...;
52 } QM_TRANSMOGRIFICATION_CTX;
53
54Confusingly, functions that aren't always available on all supported
55versions of the library, should be defined in ``MACROS`` and *not* in
56``FUNCTIONS``. Fortunately, you just have to copy the signature::
57
58 int QM_transmogrify(QM_TRANSMOGRIFICATION_CTX *, int);
59
60Then, we define the ``CUSTOMIZATIONS`` entry. To do that, we have to
61come up with a C preprocessor expression that decides whether or not a
62feature exists in the library. For example::
63
64 #ifdef QM_transmogrify
65
66Then, we set the flag that signifies the feature exists::
67
68 static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION = 1;
69
70Otherwise, we set that flag to 0::
71
72 #else
73 static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION = 0;
74
75Then, in that ``#else`` block, we define a number of fallbacks. For an
76integer constant, just define it as 0::
77
78 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT = 0;
79 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT = 0;
80
81For a function, it's a bit trickier. You have to define a function
82pointer of the appropriate type to be NULL::
83
84 int (*QM_transmogrify)(QM_TRANSMOGRIFICATION_CTX *, int) = NULL;
85
86(That is, copy the signature, put a ``*`` in front of the function
87name and wrap it in parens, and then put ``= NULL`` at the end).
88
89Note how types don't need to be conditionally defined, as long as all
90the necessarily typedefs are in place.
91
92Finally, add an entry to ``CONDITIONAL_NAMES`` with all of the things
93you want to conditionally export::
94
95 CONDITIONAL_NAMES = {
96 ...
97 "Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION": [
98 "QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT",
99 "QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT",
100 "QM_transmogrify"
101 ]
102 }
103
104Caveats
105~~~~~~~
106
107Sometimes, a set of loosely related features are added in the same
108version, and it's impractical to create ``#ifdef`` statements for each
109one. In that case, it may make sense to either check for a particular
110version. For example, to check for OpenSSL 1.0.0 or newer:
111
112 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
113
114Sometimes, the version of a libray on a particular platform will have
115features that you thought it wouldn't, based on its version.
116Occasionally, packagers appear to ship arbitrary VCS checkouts. As a
117result, sometimes you may have to add separate ``#ifdef`` statements
118for particular features. This kind of issue is typically only caught
119by running the tests on a wide variety of systems, which is the job of
120our continuous integration infrastructure.