diff options
author | tb <> | 2023-03-18 08:55:42 +0000 |
---|---|---|
committer | tb <> | 2023-03-18 08:55:42 +0000 |
commit | ac5a70a7aa4b4c24f3172ba564f529b08b329434 (patch) | |
tree | a92c4a5f00d8cf39fcfdf43c50fb46d5fff375c2 | |
parent | 84f3ea7b91c095ce2c1a6e4cf4d19aca2a480e3d (diff) | |
download | openbsd-ac5a70a7aa4b4c24f3172ba564f529b08b329434.tar.gz openbsd-ac5a70a7aa4b4c24f3172ba564f529b08b329434.tar.bz2 openbsd-ac5a70a7aa4b4c24f3172ba564f529b08b329434.zip |
Reimplement a variant of the bn_mod_exp tests from scratch
This exercises the same corner cases as bn_mod_exp and a few more.
With input from jsing
-rw-r--r-- | src/regress/lib/libcrypto/bn/bn_mod_exp_zero.c | 204 |
1 files changed, 202 insertions, 2 deletions
diff --git a/src/regress/lib/libcrypto/bn/bn_mod_exp_zero.c b/src/regress/lib/libcrypto/bn/bn_mod_exp_zero.c index 292983e86b..23cfffc5b6 100644 --- a/src/regress/lib/libcrypto/bn/bn_mod_exp_zero.c +++ b/src/regress/lib/libcrypto/bn/bn_mod_exp_zero.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* $OpenBSD: bn_mod_exp_zero.c,v 1.2 2023/03/15 00:41:04 tb Exp $ */ | 1 | /* $OpenBSD: bn_mod_exp_zero.c,v 1.3 2023/03/18 08:55:42 tb Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> | 4 | * Copyright (c) 2022,2023 Theo Buehler <tb@openbsd.org> |
5 | * | 5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any | 6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
@@ -176,12 +176,212 @@ run_bn_mod_exp_zero_tests(void) | |||
176 | return failed; | 176 | return failed; |
177 | } | 177 | } |
178 | 178 | ||
179 | #define N_MOD_EXP_TESTS 400 | ||
180 | |||
181 | static const struct mod_exp_test { | ||
182 | const char *name; | ||
183 | int (*mod_exp_fn)(BIGNUM *,const BIGNUM *, const BIGNUM *, | ||
184 | const BIGNUM *, BN_CTX *); | ||
185 | int (*mod_exp_mont_fn)(BIGNUM *,const BIGNUM *, const BIGNUM *, | ||
186 | const BIGNUM *, BN_CTX *, BN_MONT_CTX *); | ||
187 | } mod_exp_fn[] = { | ||
188 | INIT_MOD_EXP_FN(BN_mod_exp), | ||
189 | INIT_MOD_EXP_FN(BN_mod_exp_ct), | ||
190 | INIT_MOD_EXP_FN(BN_mod_exp_nonct), | ||
191 | INIT_MOD_EXP_FN(BN_mod_exp_recp), | ||
192 | INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont), | ||
193 | INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_ct), | ||
194 | INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_consttime), | ||
195 | INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_nonct), | ||
196 | }; | ||
197 | |||
198 | #define N_MOD_EXP_FN (sizeof(mod_exp_fn) / sizeof(mod_exp_fn[0])) | ||
199 | |||
200 | static int | ||
201 | generate_bn(BIGNUM *bn, int avg_bits, int deviate, int force_odd) | ||
202 | { | ||
203 | int bits; | ||
204 | |||
205 | if (avg_bits <= 0 || deviate <= 0 || deviate >= avg_bits) | ||
206 | return 0; | ||
207 | |||
208 | bits = avg_bits + arc4random_uniform(deviate) - deviate; | ||
209 | |||
210 | return BN_rand(bn, bits, 0, force_odd); | ||
211 | } | ||
212 | |||
213 | static int | ||
214 | generate_test_triple(int reduce, BIGNUM *a, BIGNUM *p, BIGNUM *m, BN_CTX *ctx) | ||
215 | { | ||
216 | BIGNUM *mmodified; | ||
217 | BN_ULONG multiple; | ||
218 | int avg = 2 * BN_BITS, deviate = BN_BITS / 2; | ||
219 | int ret = 0; | ||
220 | |||
221 | if (!generate_bn(a, avg, deviate, 0)) | ||
222 | return 0; | ||
223 | |||
224 | if (!generate_bn(p, avg, deviate, 0)) | ||
225 | return 0; | ||
226 | |||
227 | if (!generate_bn(m, avg, deviate, 1)) | ||
228 | return 0; | ||
229 | |||
230 | if (reduce) | ||
231 | return BN_mod(a, a, m, ctx); | ||
232 | |||
233 | /* | ||
234 | * Add a random multiple of m to a to test unreduced exponentiation. | ||
235 | */ | ||
236 | |||
237 | BN_CTX_start(ctx); | ||
238 | |||
239 | if ((mmodified = BN_CTX_get(ctx)) == NULL) | ||
240 | goto err; | ||
241 | |||
242 | if (BN_copy(mmodified, m) == NULL) | ||
243 | goto err; | ||
244 | |||
245 | multiple = arc4random_uniform(1023) + 2; | ||
246 | |||
247 | if (!BN_mul_word(mmodified, multiple)) | ||
248 | goto err; | ||
249 | |||
250 | if (!BN_add(a, a, mmodified)) | ||
251 | goto err; | ||
252 | |||
253 | ret = 1; | ||
254 | err: | ||
255 | BN_CTX_end(ctx); | ||
256 | |||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | static void | ||
261 | dump_results(const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, | ||
262 | const BIGNUM *got, const BIGNUM *want, const char *name) | ||
263 | { | ||
264 | printf("BN_mod_exp_simple() and %s() disagree", name); | ||
265 | |||
266 | printf("\nwant: "); | ||
267 | BN_print_fp(stdout, want); | ||
268 | printf("\ngot: "); | ||
269 | BN_print_fp(stdout, got); | ||
270 | |||
271 | printf("\na: "); | ||
272 | BN_print_fp(stdout, a); | ||
273 | printf("\nb: "); | ||
274 | BN_print_fp(stdout, p); | ||
275 | printf("\nm: "); | ||
276 | BN_print_fp(stdout, m); | ||
277 | printf("\n\n"); | ||
278 | } | ||
279 | |||
280 | static int | ||
281 | test_mod_exp(const BIGNUM *want, const BIGNUM *a, const BIGNUM *p, | ||
282 | const BIGNUM *m, BN_CTX *ctx, const struct mod_exp_test *test) | ||
283 | { | ||
284 | BIGNUM *got; | ||
285 | int ret = 0; | ||
286 | |||
287 | BN_CTX_start(ctx); | ||
288 | |||
289 | if ((got = BN_CTX_get(ctx)) == NULL) | ||
290 | goto err; | ||
291 | |||
292 | if (test->mod_exp_fn != NULL) | ||
293 | ret = test->mod_exp_fn(got, a, p, m, ctx); | ||
294 | else | ||
295 | ret = test->mod_exp_mont_fn(got, a, p, m, ctx, NULL); | ||
296 | |||
297 | if (!ret) | ||
298 | errx(1, "%s() failed", test->name); | ||
299 | |||
300 | if (BN_cmp(want, got) != 0) { | ||
301 | dump_results(a, p, m, want, got, test->name); | ||
302 | goto err; | ||
303 | } | ||
304 | |||
305 | ret = 1; | ||
306 | |||
307 | err: | ||
308 | BN_CTX_end(ctx); | ||
309 | |||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | static int | ||
314 | bn_mod_exp_test(int reduce, BIGNUM *want, BIGNUM *a, BIGNUM *p, BIGNUM *m, | ||
315 | BN_CTX *ctx) | ||
316 | { | ||
317 | size_t i, j; | ||
318 | int failed = 0; | ||
319 | |||
320 | if (!generate_test_triple(reduce, a, p, m, ctx)) | ||
321 | errx(1, "generate_test_triple"); | ||
322 | |||
323 | for (i = 0; i < 4; i++) { | ||
324 | BN_set_negative(a, i & 1); | ||
325 | BN_set_negative(p, (i >> 1) & 1); | ||
326 | |||
327 | if ((BN_mod_exp_simple(want, a, p, m, ctx)) <= 0) | ||
328 | errx(1, "BN_mod_exp_simple"); | ||
329 | |||
330 | for (j = 0; j < N_MOD_EXP_FN; j++) { | ||
331 | const struct mod_exp_test *test = &mod_exp_fn[j]; | ||
332 | |||
333 | if (!test_mod_exp(want, a, p, m, ctx, test)) | ||
334 | failed |= 1; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | return failed; | ||
339 | } | ||
340 | |||
341 | static int | ||
342 | run_bn_mod_exp_tests(void) | ||
343 | { | ||
344 | BIGNUM *a, *p, *m, *want; | ||
345 | BN_CTX *ctx; | ||
346 | int i; | ||
347 | int reduce; | ||
348 | int failed = 0; | ||
349 | |||
350 | if ((ctx = BN_CTX_new()) == NULL) | ||
351 | errx(1, "BN_CTX_new"); | ||
352 | |||
353 | BN_CTX_start(ctx); | ||
354 | |||
355 | if ((a = BN_CTX_get(ctx)) == NULL) | ||
356 | errx(1, "a = BN_CTX_get()"); | ||
357 | if ((p = BN_CTX_get(ctx)) == NULL) | ||
358 | errx(1, "p = BN_CTX_get()"); | ||
359 | if ((m = BN_CTX_get(ctx)) == NULL) | ||
360 | errx(1, "m = BN_CTX_get()"); | ||
361 | if ((want = BN_CTX_get(ctx)) == NULL) | ||
362 | errx(1, "want = BN_CTX_get()"); | ||
363 | |||
364 | reduce = 0; | ||
365 | for (i = 0; i < N_MOD_EXP_TESTS; i++) | ||
366 | failed |= bn_mod_exp_test(reduce, want, a, p, m, ctx); | ||
367 | |||
368 | reduce = 1; | ||
369 | for (i = 0; i < N_MOD_EXP_TESTS; i++) | ||
370 | failed |= bn_mod_exp_test(reduce, want, a, p, m, ctx); | ||
371 | |||
372 | BN_CTX_end(ctx); | ||
373 | BN_CTX_free(ctx); | ||
374 | |||
375 | return failed; | ||
376 | } | ||
377 | |||
179 | int | 378 | int |
180 | main(void) | 379 | main(void) |
181 | { | 380 | { |
182 | int failed = 0; | 381 | int failed = 0; |
183 | 382 | ||
184 | failed |= run_bn_mod_exp_zero_tests(); | 383 | failed |= run_bn_mod_exp_zero_tests(); |
384 | failed |= run_bn_mod_exp_tests(); | ||
185 | 385 | ||
186 | return failed; | 386 | return failed; |
187 | } | 387 | } |