Add ossl_inline
[openssl.git] / test / constant_time_test.c
1 /* crypto/constant_time_test.c */
2 /*-
3  * Utilities for constant-time cryptography.
4  *
5  * Author: Emilia Kasper (emilia@openssl.org)
6  * Based on previous work by Bodo Moeller, Emilia Kasper, Adam Langley
7  * (Google).
8  * ====================================================================
9  * Copyright (c) 2014 The OpenSSL Project.  All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *    "This product includes cryptographic software written by
22  *     Eric Young (eay@cryptsoft.com)"
23  *    The word 'cryptographic' can be left out if the rouines from the library
24  *    being used are not cryptographic related :-).
25  * 4. If you include any Windows specific code (or a derivative thereof) from
26  *    the apps directory (application code) you must include an acknowledgement:
27  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
28  *
29  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  * The licence and distribution terms for any publically available version or
42  * derivative of this code cannot be changed.  i.e. this code cannot simply be
43  * copied and put under another distribution licence
44  * [including the GNU Public Licence.]
45  */
46
47 #include "internal/constant_time_locl.h"
48 #include "e_os.h"
49
50 #include <limits.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53
54 static const unsigned int CONSTTIME_TRUE = (unsigned)(~0);
55 static const unsigned int CONSTTIME_FALSE = 0;
56 static const unsigned char CONSTTIME_TRUE_8 = 0xff;
57 static const unsigned char CONSTTIME_FALSE_8 = 0;
58
59 static int test_binary_op(unsigned int (*op) (unsigned int a, unsigned int b),
60                           const char *op_name, unsigned int a, unsigned int b,
61                           int is_true)
62 {
63     unsigned c = op(a, b);
64     if (is_true && c != CONSTTIME_TRUE) {
65         fprintf(stderr, "Test failed for %s(%du, %du): expected %du "
66                 "(TRUE), got %du\n", op_name, a, b, CONSTTIME_TRUE, c);
67         return 1;
68     } else if (!is_true && c != CONSTTIME_FALSE) {
69         fprintf(stderr, "Test failed for  %s(%du, %du): expected %du "
70                 "(FALSE), got %du\n", op_name, a, b, CONSTTIME_FALSE, c);
71         return 1;
72     }
73     return 0;
74 }
75
76 static int test_binary_op_8(unsigned
77                             char (*op) (unsigned int a, unsigned int b),
78                             const char *op_name, unsigned int a,
79                             unsigned int b, int is_true)
80 {
81     unsigned char c = op(a, b);
82     if (is_true && c != CONSTTIME_TRUE_8) {
83         fprintf(stderr, "Test failed for %s(%du, %du): expected %u "
84                 "(TRUE), got %u\n", op_name, a, b, CONSTTIME_TRUE_8, c);
85         return 1;
86     } else if (!is_true && c != CONSTTIME_FALSE_8) {
87         fprintf(stderr, "Test failed for  %s(%du, %du): expected %u "
88                 "(FALSE), got %u\n", op_name, a, b, CONSTTIME_FALSE_8, c);
89         return 1;
90     }
91     return 0;
92 }
93
94 static int test_is_zero(unsigned int a)
95 {
96     unsigned int c = constant_time_is_zero(a);
97     if (a == 0 && c != CONSTTIME_TRUE) {
98         fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
99                 "expected %du (TRUE), got %du\n", a, CONSTTIME_TRUE, c);
100         return 1;
101     } else if (a != 0 && c != CONSTTIME_FALSE) {
102         fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
103                 "expected %du (FALSE), got %du\n", a, CONSTTIME_FALSE, c);
104         return 1;
105     }
106     return 0;
107 }
108
109 static int test_is_zero_8(unsigned int a)
110 {
111     unsigned char c = constant_time_is_zero_8(a);
112     if (a == 0 && c != CONSTTIME_TRUE_8) {
113         fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
114                 "expected %u (TRUE), got %u\n", a, CONSTTIME_TRUE_8, c);
115         return 1;
116     } else if (a != 0 && c != CONSTTIME_FALSE) {
117         fprintf(stderr, "Test failed for constant_time_is_zero(%du): "
118                 "expected %u (FALSE), got %u\n", a, CONSTTIME_FALSE_8, c);
119         return 1;
120     }
121     return 0;
122 }
123
124 static int test_select(unsigned int a, unsigned int b)
125 {
126     unsigned int selected = constant_time_select(CONSTTIME_TRUE, a, b);
127     if (selected != a) {
128         fprintf(stderr, "Test failed for constant_time_select(%du, %du,"
129                 "%du): expected %du(first value), got %du\n",
130                 CONSTTIME_TRUE, a, b, a, selected);
131         return 1;
132     }
133     selected = constant_time_select(CONSTTIME_FALSE, a, b);
134     if (selected != b) {
135         fprintf(stderr, "Test failed for constant_time_select(%du, %du,"
136                 "%du): expected %du(second value), got %du\n",
137                 CONSTTIME_FALSE, a, b, b, selected);
138         return 1;
139     }
140     return 0;
141 }
142
143 static int test_select_8(unsigned char a, unsigned char b)
144 {
145     unsigned char selected = constant_time_select_8(CONSTTIME_TRUE_8, a, b);
146     if (selected != a) {
147         fprintf(stderr, "Test failed for constant_time_select(%u, %u,"
148                 "%u): expected %u(first value), got %u\n",
149                 CONSTTIME_TRUE, a, b, a, selected);
150         return 1;
151     }
152     selected = constant_time_select_8(CONSTTIME_FALSE_8, a, b);
153     if (selected != b) {
154         fprintf(stderr, "Test failed for constant_time_select(%u, %u,"
155                 "%u): expected %u(second value), got %u\n",
156                 CONSTTIME_FALSE, a, b, b, selected);
157         return 1;
158     }
159     return 0;
160 }
161
162 static int test_select_int(int a, int b)
163 {
164     int selected = constant_time_select_int(CONSTTIME_TRUE, a, b);
165     if (selected != a) {
166         fprintf(stderr, "Test failed for constant_time_select(%du, %d,"
167                 "%d): expected %d(first value), got %d\n",
168                 CONSTTIME_TRUE, a, b, a, selected);
169         return 1;
170     }
171     selected = constant_time_select_int(CONSTTIME_FALSE, a, b);
172     if (selected != b) {
173         fprintf(stderr, "Test failed for constant_time_select(%du, %d,"
174                 "%d): expected %d(second value), got %d\n",
175                 CONSTTIME_FALSE, a, b, b, selected);
176         return 1;
177     }
178     return 0;
179 }
180
181 static int test_eq_int(int a, int b)
182 {
183     unsigned int equal = constant_time_eq_int(a, b);
184     if (a == b && equal != CONSTTIME_TRUE) {
185         fprintf(stderr, "Test failed for constant_time_eq_int(%d, %d): "
186                 "expected %du(TRUE), got %du\n", a, b, CONSTTIME_TRUE, equal);
187         return 1;
188     } else if (a != b && equal != CONSTTIME_FALSE) {
189         fprintf(stderr, "Test failed for constant_time_eq_int(%d, %d): "
190                 "expected %du(FALSE), got %du\n",
191                 a, b, CONSTTIME_FALSE, equal);
192         return 1;
193     }
194     return 0;
195 }
196
197 static int test_eq_int_8(int a, int b)
198 {
199     unsigned char equal = constant_time_eq_int_8(a, b);
200     if (a == b && equal != CONSTTIME_TRUE_8) {
201         fprintf(stderr, "Test failed for constant_time_eq_int_8(%d, %d): "
202                 "expected %u(TRUE), got %u\n", a, b, CONSTTIME_TRUE_8, equal);
203         return 1;
204     } else if (a != b && equal != CONSTTIME_FALSE_8) {
205         fprintf(stderr, "Test failed for constant_time_eq_int_8(%d, %d): "
206                 "expected %u(FALSE), got %u\n",
207                 a, b, CONSTTIME_FALSE_8, equal);
208         return 1;
209     }
210     return 0;
211 }
212
213 static unsigned int test_values[] =
214     { 0, 1, 1024, 12345, 32000, UINT_MAX / 2 - 1,
215     UINT_MAX / 2, UINT_MAX / 2 + 1, UINT_MAX - 1,
216     UINT_MAX
217 };
218
219 static unsigned char test_values_8[] =
220     { 0, 1, 2, 20, 32, 127, 128, 129, 255 };
221
222 static int signed_test_values[] = { 0, 1, -1, 1024, -1024, 12345, -12345,
223     32000, -32000, INT_MAX, INT_MIN, INT_MAX - 1,
224     INT_MIN + 1
225 };
226
227 int main(int argc, char *argv[])
228 {
229     unsigned int a, b, i, j;
230     int c, d;
231     unsigned char e, f;
232     int num_failed = 0, num_all = 0;
233     fprintf(stdout, "Testing constant time operations...\n");
234
235     for (i = 0; i < OSSL_NELEM(test_values); ++i) {
236         a = test_values[i];
237         num_failed += test_is_zero(a);
238         num_failed += test_is_zero_8(a);
239         num_all += 2;
240         for (j = 0; j < OSSL_NELEM(test_values); ++j) {
241             b = test_values[j];
242             num_failed += test_binary_op(&constant_time_lt,
243                                          "constant_time_lt", a, b, a < b);
244             num_failed += test_binary_op_8(&constant_time_lt_8,
245                                            "constant_time_lt_8", a, b, a < b);
246             num_failed += test_binary_op(&constant_time_lt,
247                                          "constant_time_lt_8", b, a, b < a);
248             num_failed += test_binary_op_8(&constant_time_lt_8,
249                                            "constant_time_lt_8", b, a, b < a);
250             num_failed += test_binary_op(&constant_time_ge,
251                                          "constant_time_ge", a, b, a >= b);
252             num_failed += test_binary_op_8(&constant_time_ge_8,
253                                            "constant_time_ge_8", a, b,
254                                            a >= b);
255             num_failed +=
256                 test_binary_op(&constant_time_ge, "constant_time_ge", b, a,
257                                b >= a);
258             num_failed +=
259                 test_binary_op_8(&constant_time_ge_8, "constant_time_ge_8", b,
260                                  a, b >= a);
261             num_failed +=
262                 test_binary_op(&constant_time_eq, "constant_time_eq", a, b,
263                                a == b);
264             num_failed +=
265                 test_binary_op_8(&constant_time_eq_8, "constant_time_eq_8", a,
266                                  b, a == b);
267             num_failed +=
268                 test_binary_op(&constant_time_eq, "constant_time_eq", b, a,
269                                b == a);
270             num_failed +=
271                 test_binary_op_8(&constant_time_eq_8, "constant_time_eq_8", b,
272                                  a, b == a);
273             num_failed += test_select(a, b);
274             num_all += 13;
275         }
276     }
277
278     for (i = 0; i < OSSL_NELEM(signed_test_values); ++i) {
279         c = signed_test_values[i];
280         for (j = 0; j < OSSL_NELEM(signed_test_values); ++j) {
281             d = signed_test_values[j];
282             num_failed += test_select_int(c, d);
283             num_failed += test_eq_int(c, d);
284             num_failed += test_eq_int_8(c, d);
285             num_all += 3;
286         }
287     }
288
289     for (i = 0; i < sizeof(test_values_8); ++i) {
290         e = test_values_8[i];
291         for (j = 0; j < sizeof(test_values_8); ++j) {
292             f = test_values_8[j];
293             num_failed += test_select_8(e, f);
294             num_all += 1;
295         }
296     }
297
298     if (!num_failed) {
299         fprintf(stdout, "success (ran %d tests)\n", num_all);
300         return EXIT_SUCCESS;
301     } else {
302         fprintf(stdout, "%d of %d tests failed!\n", num_failed, num_all);
303         return EXIT_FAILURE;
304     }
305 }