blob: dbcd62f5b737ecaba647381bfe2bd6339cca4f59 [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
Laurens Van Houtven4e006142014-06-23 14:05:10 +02006.. _cffi: http://cffi.readthedocs.org
Laurens Van Houtven7d2c74e2014-06-23 13:49:58 +02007
8Bindings live in :py:mod:`cryptography.hazmat.bindings`.
Laurens Van Houtvenefa5cfb2014-06-23 13:51:35 +02009
Laurens Van Houtven220a98d2014-06-23 14:08:27 +020010Style guide
11-----------
12
13Don't name parameters:
14
15.. code-block:: c
16
17 /* Good */
18 long f(long);
19 /* Bad */
20 long f(long x);
21
22...unless they're inside a struct:
23
24.. code-block:: c
25
26 struct my_struct {
27 char *name;
28 int number;
29 ...;
30 };
31
32Include ``void`` if the function takes no arguments:
33
34.. code-block:: c
35
36 /* Good */
37 long f(void);
38 /* Bad */
39 long f();
40
41Wrap lines at 80 characters like so:
42
43.. code-block:: c
44
45 /* Pretend this went to 80 characters */
46 long f(long, long,
47 int *)
48
49Include a space after commas between parameters:
50
51.. code-block:: c
52
53 /* Good */
54 long f(int, char *)
55 /* Bad */
56 long f(int,char *)
57
58Use C-style ``/* */`` comments instead of C++-style ``//``:
59
60.. code-block:: c
61
62 // Bad
63 /* Good */
64
65Values set by ``#define`` should be assigned the appropriate type. If you see
66this:
67
68.. code-block:: c
69
70 #define SOME_INTEGER_LITERAL 0x0;
71 #define SOME_UNSIGNED_INTEGER_LITERAL 0x0001U;
72 #define SOME_STRING_LITERAL "hello";
73
74...it should be added to the bindings like so:
75
76.. code-block:: c
77
78 static const int SOME_INTEGER_LITERAL;
79 static const unsigned int SOME_UNSIGNED_INTEGER_LITERAL;
80 static const char *const SOME_STRING_LITERAL;
81
Laurens Van Houtvenefa5cfb2014-06-23 13:51:35 +020082Adding constant, types, functions...
83------------------------------------
84
85You can create bindings for any name that exists in some version of
86the library you're binding against. However, the project also has to
87keep supporting older versions of the library. In order to acchieve
88this, binding modules have ``CUSTOMIZATIONS`` and
89``CONDITIONAL_NAMES`` constants.
90
91Let's say you want to enable quantum transmogrification. The upstream
92library implements this as the following API::
93
94 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT;
95 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT;
96 typedef ... QM_TRANSMOGRIFICATION_CTX;
97 int QM_transmogrify(QM_TRANSMOGRIFICATION_CTX *, int);
98
99To start, create a new constant that defines if the *actual* library
100has the feature you want, and add it to ``TYPES``::
101
102 static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION;
103
104This should start with ``Cryptography_``, since we're adding it in
105this library. This prevents namespace collisions.
106
107Then, define the actual features (constants, types, functions...) you
108want to expose. If it's a constant, just add it to ``TYPES``::
109
110 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT;
111 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT;
112
113If it's a struct, add it to ``TYPES`` as well. The following is an
114opaque struct::
115
116 typedef ... QM_TRANSMOGRIFICATION_CTX;
117
118... but you can also make some or all items in the struct accessible::
119
120 typedef struct {
121 /* Fundamental constant k for your particular universe */
122 BIGNUM *k;
123 ...;
124 } QM_TRANSMOGRIFICATION_CTX;
125
126Confusingly, functions that aren't always available on all supported
127versions of the library, should be defined in ``MACROS`` and *not* in
128``FUNCTIONS``. Fortunately, you just have to copy the signature::
129
130 int QM_transmogrify(QM_TRANSMOGRIFICATION_CTX *, int);
131
132Then, we define the ``CUSTOMIZATIONS`` entry. To do that, we have to
133come up with a C preprocessor expression that decides whether or not a
134feature exists in the library. For example::
135
136 #ifdef QM_transmogrify
137
138Then, we set the flag that signifies the feature exists::
139
140 static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION = 1;
141
142Otherwise, we set that flag to 0::
143
144 #else
145 static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION = 0;
146
147Then, in that ``#else`` block, we define a number of fallbacks. For an
148integer constant, just define it as 0::
149
150 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT = 0;
151 static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT = 0;
152
153For a function, it's a bit trickier. You have to define a function
154pointer of the appropriate type to be NULL::
155
156 int (*QM_transmogrify)(QM_TRANSMOGRIFICATION_CTX *, int) = NULL;
157
Laurens Van Houtven1dc0b142014-06-23 13:55:21 +0200158(To do that, copy the signature, put a ``*`` in front of the function
Laurens Van Houtvenefa5cfb2014-06-23 13:51:35 +0200159name and wrap it in parens, and then put ``= NULL`` at the end).
160
161Note how types don't need to be conditionally defined, as long as all
162the necessarily typedefs are in place.
163
164Finally, add an entry to ``CONDITIONAL_NAMES`` with all of the things
165you want to conditionally export::
166
167 CONDITIONAL_NAMES = {
168 ...
169 "Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION": [
170 "QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT",
171 "QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT",
172 "QM_transmogrify"
173 ]
174 }
175
176Caveats
177~~~~~~~
178
179Sometimes, a set of loosely related features are added in the same
180version, and it's impractical to create ``#ifdef`` statements for each
181one. In that case, it may make sense to either check for a particular
Laurens Van Houtven1c07ddf2014-06-23 13:55:27 +0200182version. For example, to check for OpenSSL 1.0.0 or newer::
Laurens Van Houtvenefa5cfb2014-06-23 13:51:35 +0200183
184 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
185
Laurens Van Houtven260e8872014-06-23 16:22:32 +0200186Sometimes, the version of a library on a particular platform will have
Laurens Van Houtvenefa5cfb2014-06-23 13:51:35 +0200187features that you thought it wouldn't, based on its version.
188Occasionally, packagers appear to ship arbitrary VCS checkouts. As a
189result, sometimes you may have to add separate ``#ifdef`` statements
190for particular features. This kind of issue is typically only caught
191by running the tests on a wide variety of systems, which is the job of
192our continuous integration infrastructure.