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