1*24882d0aStb /* $OpenBSD: bn_mod_exp.c,v 1.40 2023/10/19 13:38:12 tb Exp $ */
22cac8f3aStb
32cac8f3aStb /*
42cac8f3aStb * Copyright (c) 2022,2023 Theo Buehler <tb@openbsd.org>
52cac8f3aStb *
62cac8f3aStb * Permission to use, copy, modify, and distribute this software for any
72cac8f3aStb * purpose with or without fee is hereby granted, provided that the above
82cac8f3aStb * copyright notice and this permission notice appear in all copies.
92cac8f3aStb *
102cac8f3aStb * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112cac8f3aStb * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122cac8f3aStb * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132cac8f3aStb * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142cac8f3aStb * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152cac8f3aStb * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162cac8f3aStb * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172cac8f3aStb */
182cac8f3aStb
192cac8f3aStb #include <err.h>
2058a53292Stb #include <stdio.h>
2158a53292Stb #include <string.h>
222cac8f3aStb
232cac8f3aStb #include <openssl/bn.h>
242cac8f3aStb #include <openssl/err.h>
252cac8f3aStb
262cac8f3aStb #include "bn_local.h"
272cac8f3aStb
28a3971f08Stb #define N_MOD_EXP_TESTS 100
29a3971f08Stb #define N_MOD_EXP2_TESTS 50
3036cb5e34Stb
312cac8f3aStb #define INIT_MOD_EXP_FN(f) { .name = #f, .mod_exp_fn = (f), }
322cac8f3aStb #define INIT_MOD_EXP_MONT_FN(f) { .name = #f, .mod_exp_mont_fn = (f), }
332cac8f3aStb
343baba9acStb static int
bn_mod_exp2_mont_first(BIGNUM * r,const BIGNUM * a,const BIGNUM * p,const BIGNUM * m,BN_CTX * ctx,BN_MONT_CTX * mctx)353baba9acStb bn_mod_exp2_mont_first(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
363baba9acStb const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *mctx)
373baba9acStb {
383baba9acStb const BIGNUM *one = BN_value_one();
393baba9acStb
403baba9acStb return BN_mod_exp2_mont(r, a, p, one, one, m, ctx, mctx);
413baba9acStb }
423baba9acStb
433baba9acStb static int
bn_mod_exp2_mont_second(BIGNUM * r,const BIGNUM * a,const BIGNUM * p,const BIGNUM * m,BN_CTX * ctx,BN_MONT_CTX * mctx)443baba9acStb bn_mod_exp2_mont_second(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
453baba9acStb const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *mctx)
463baba9acStb {
473baba9acStb const BIGNUM *one = BN_value_one();
483baba9acStb
493baba9acStb return BN_mod_exp2_mont(r, one, one, a, p, m, ctx, mctx);
503baba9acStb }
513baba9acStb
52f5f16a4eStb static const struct mod_exp_test {
532cac8f3aStb const char *name;
542cac8f3aStb int (*mod_exp_fn)(BIGNUM *, const BIGNUM *, const BIGNUM *,
552cac8f3aStb const BIGNUM *, BN_CTX *);
562cac8f3aStb int (*mod_exp_mont_fn)(BIGNUM *, const BIGNUM *, const BIGNUM *,
572cac8f3aStb const BIGNUM *, BN_CTX *, BN_MONT_CTX *);
58f5f16a4eStb } mod_exp_fn[] = {
592cac8f3aStb INIT_MOD_EXP_FN(BN_mod_exp),
602cac8f3aStb INIT_MOD_EXP_FN(BN_mod_exp_ct),
612cac8f3aStb INIT_MOD_EXP_FN(BN_mod_exp_nonct),
622cac8f3aStb INIT_MOD_EXP_FN(BN_mod_exp_recp),
632cac8f3aStb INIT_MOD_EXP_FN(BN_mod_exp_simple),
642cac8f3aStb INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont),
652cac8f3aStb INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_ct),
662cac8f3aStb INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_consttime),
672cac8f3aStb INIT_MOD_EXP_MONT_FN(BN_mod_exp_mont_nonct),
683baba9acStb INIT_MOD_EXP_MONT_FN(bn_mod_exp2_mont_first),
693baba9acStb INIT_MOD_EXP_MONT_FN(bn_mod_exp2_mont_second),
702cac8f3aStb };
712cac8f3aStb
72f5f16a4eStb #define N_MOD_EXP_FN (sizeof(mod_exp_fn) / sizeof(mod_exp_fn[0]))
732cac8f3aStb
742cac8f3aStb static void
bn_print(const char * name,const BIGNUM * bn)7558a53292Stb bn_print(const char *name, const BIGNUM *bn)
762cac8f3aStb {
7758a53292Stb size_t len;
7858a53292Stb int pad = 0;
7958a53292Stb
80a0987236Stb if ((len = strlen(name)) < 7)
8158a53292Stb pad = 6 - len;
8258a53292Stb
8358a53292Stb fprintf(stderr, "%s: %*s", name, pad, "");
8458a53292Stb BN_print_fp(stderr, bn);
852cac8f3aStb fprintf(stderr, "\n");
862cac8f3aStb }
872cac8f3aStb
8858a53292Stb static void
print_zero_test_failure(const BIGNUM * got,const BIGNUM * a,const BIGNUM * m,const char * name)89b5847372Stb print_zero_test_failure(const BIGNUM *got, const BIGNUM *a, const BIGNUM *m,
90b5847372Stb const char *name)
9158a53292Stb {
9258a53292Stb fprintf(stderr, "%s() zero test failed:\n", name);
9358a53292Stb
9458a53292Stb bn_print("a", a);
95b5847372Stb bn_print("m", m);
9658a53292Stb bn_print("got", got);
9758a53292Stb }
9858a53292Stb
992cac8f3aStb static int
bn_mod_exp_zero_test(const struct mod_exp_test * test,BN_CTX * ctx,int neg_modulus,int random_base)100b5847372Stb bn_mod_exp_zero_test(const struct mod_exp_test *test, BN_CTX *ctx,
101b5847372Stb int neg_modulus, int random_base)
1022cac8f3aStb {
103b5847372Stb BIGNUM *a, *m, *p, *got;
1049cd3ae5cStb int mod_exp_ret;
1052cac8f3aStb int failed = 1;
1062cac8f3aStb
1072cac8f3aStb BN_CTX_start(ctx);
1082cac8f3aStb
1092cac8f3aStb if ((a = BN_CTX_get(ctx)) == NULL)
1102cac8f3aStb errx(1, "BN_CTX_get");
111b5847372Stb if ((m = BN_CTX_get(ctx)) == NULL)
112b5847372Stb errx(1, "BN_CTX_get");
1132cac8f3aStb if ((p = BN_CTX_get(ctx)) == NULL)
1142cac8f3aStb errx(1, "BN_CTX_get");
1152cac8f3aStb if ((got = BN_CTX_get(ctx)) == NULL)
1162cac8f3aStb errx(1, "BN_CTX_get");
1172cac8f3aStb
118b5847372Stb if (!BN_one(m))
119b5847372Stb errx(1, "BN_one");
120b5847372Stb if (neg_modulus)
121b5847372Stb BN_set_negative(m, 1);
1222cac8f3aStb BN_zero(a);
1232cac8f3aStb BN_zero(p);
1242cac8f3aStb
125b5847372Stb if (random_base) {
1262cac8f3aStb if (!BN_rand(a, 1024, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY))
1272cac8f3aStb errx(1, "BN_rand");
1282cac8f3aStb }
1292cac8f3aStb
1302cac8f3aStb if (test->mod_exp_fn != NULL) {
131b5847372Stb mod_exp_ret = test->mod_exp_fn(got, a, p, m, ctx);
1322cac8f3aStb } else {
133b5847372Stb mod_exp_ret = test->mod_exp_mont_fn(got, a, p, m, ctx, NULL);
1349cd3ae5cStb }
1359cd3ae5cStb
1369cd3ae5cStb if (!mod_exp_ret) {
1372cac8f3aStb fprintf(stderr, "%s failed\n", test->name);
1382cac8f3aStb ERR_print_errors_fp(stderr);
1392cac8f3aStb goto err;
1402cac8f3aStb }
1412cac8f3aStb
1422cac8f3aStb if (!BN_is_zero(got)) {
143b5847372Stb print_zero_test_failure(got, a, m, test->name);
1442cac8f3aStb goto err;
1452cac8f3aStb }
1462cac8f3aStb
1472cac8f3aStb failed = 0;
1482cac8f3aStb
1492cac8f3aStb err:
1502cac8f3aStb BN_CTX_end(ctx);
1512cac8f3aStb
1522cac8f3aStb return failed;
1532cac8f3aStb }
1542cac8f3aStb
1552cac8f3aStb static int
bn_mod_exp_zero_word_test(BN_CTX * ctx,int neg_modulus)156b5847372Stb bn_mod_exp_zero_word_test(BN_CTX *ctx, int neg_modulus)
1572cac8f3aStb {
1582cac8f3aStb const char *name = "BN_mod_exp_mont_word";
159b5847372Stb BIGNUM *m, *p, *got;
1602cac8f3aStb int failed = 1;
1612cac8f3aStb
1622cac8f3aStb BN_CTX_start(ctx);
1632cac8f3aStb
164b5847372Stb if ((m = BN_CTX_get(ctx)) == NULL)
165b5847372Stb errx(1, "BN_CTX_get");
1662cac8f3aStb if ((p = BN_CTX_get(ctx)) == NULL)
1672cac8f3aStb errx(1, "BN_CTX_get");
1682cac8f3aStb if ((got = BN_CTX_get(ctx)) == NULL)
1692cac8f3aStb errx(1, "BN_CTX_get");
1702cac8f3aStb
171b5847372Stb if (!BN_one(m))
172b5847372Stb errx(1, "BN_one");
173b5847372Stb if (neg_modulus)
174b5847372Stb BN_set_negative(m, neg_modulus);
1752cac8f3aStb BN_zero(p);
1762cac8f3aStb
177b5847372Stb if (!BN_mod_exp_mont_word(got, 1, p, m, ctx, NULL)) {
1782cac8f3aStb fprintf(stderr, "%s failed\n", name);
1792cac8f3aStb ERR_print_errors_fp(stderr);
1802cac8f3aStb goto err;
1812cac8f3aStb }
1822cac8f3aStb
1832cac8f3aStb if (!BN_is_zero(got)) {
184b5847372Stb print_zero_test_failure(got, p, m, name);
1852cac8f3aStb goto err;
1862cac8f3aStb }
1872cac8f3aStb
1882cac8f3aStb failed = 0;
1892cac8f3aStb
1902cac8f3aStb err:
1912cac8f3aStb BN_CTX_end(ctx);
1922cac8f3aStb
1932cac8f3aStb return failed;
1942cac8f3aStb }
1952cac8f3aStb
1962cac8f3aStb static int
test_bn_mod_exp_zero(void)19717db9b10Stb test_bn_mod_exp_zero(void)
1982cac8f3aStb {
1992cac8f3aStb BN_CTX *ctx;
200b5847372Stb size_t i, j;
2012cac8f3aStb int failed = 0;
2022cac8f3aStb
2032cac8f3aStb if ((ctx = BN_CTX_new()) == NULL)
2042cac8f3aStb errx(1, "BN_CTX_new");
2052cac8f3aStb
206b5847372Stb for (i = 0; i < N_MOD_EXP_FN; i++) {
207b5847372Stb for (j = 0; j < 4; j++) {
208b5847372Stb int neg_modulus = (j >> 0) & 1;
209b5847372Stb int random_base = (j >> 1) & 1;
2102cac8f3aStb
211b5847372Stb failed |= bn_mod_exp_zero_test(&mod_exp_fn[i], ctx,
212b5847372Stb neg_modulus, random_base);
213b5847372Stb }
214b5847372Stb }
2152cac8f3aStb
216b5847372Stb failed |= bn_mod_exp_zero_word_test(ctx, 0);
217b5847372Stb failed |= bn_mod_exp_zero_word_test(ctx, 1);
2182cac8f3aStb
2192cac8f3aStb BN_CTX_free(ctx);
2202cac8f3aStb
2212cac8f3aStb return failed;
2222cac8f3aStb }
2232cac8f3aStb
2242cac8f3aStb static int
generate_bn(BIGNUM * bn,int avg_bits,int deviate,int force_odd)2252cac8f3aStb generate_bn(BIGNUM *bn, int avg_bits, int deviate, int force_odd)
2262cac8f3aStb {
2272cac8f3aStb int bits;
2282cac8f3aStb
229e0bdcda1Stb if (bn == NULL)
230e0bdcda1Stb return 1;
231e0bdcda1Stb
2322cac8f3aStb if (avg_bits <= 0 || deviate <= 0 || deviate >= avg_bits)
2332cac8f3aStb return 0;
2342cac8f3aStb
2352cac8f3aStb bits = avg_bits + arc4random_uniform(deviate) - deviate;
2362cac8f3aStb
2372cac8f3aStb return BN_rand(bn, bits, 0, force_odd);
2382cac8f3aStb }
2392cac8f3aStb
2402cac8f3aStb static int
generate_test_quintuple(int reduce,BIGNUM * a,BIGNUM * p,BIGNUM * b,BIGNUM * q,BIGNUM * m,BN_CTX * ctx)241e0bdcda1Stb generate_test_quintuple(int reduce, BIGNUM *a, BIGNUM *p, BIGNUM *b, BIGNUM *q,
242e0bdcda1Stb BIGNUM *m, BN_CTX *ctx)
243f34e85acStb {
244f34e85acStb BIGNUM *mmodified;
245f34e85acStb BN_ULONG multiple;
246f34e85acStb int avg = 2 * BN_BITS, deviate = BN_BITS / 2;
247f34e85acStb int ret = 0;
248f34e85acStb
249c0423487Stb if (!generate_bn(a, avg, deviate, 0))
250f34e85acStb return 0;
251f34e85acStb
252c0423487Stb if (!generate_bn(p, avg, deviate, 0))
253f34e85acStb return 0;
254f34e85acStb
255c0423487Stb if (!generate_bn(b, avg, deviate, 0))
256f34e85acStb return 0;
257f34e85acStb
258c0423487Stb if (!generate_bn(q, avg, deviate, 0))
259f34e85acStb return 0;
260f34e85acStb
261f34e85acStb if (!generate_bn(m, avg, deviate, 1))
262f34e85acStb return 0;
263f34e85acStb
264f34e85acStb if (reduce) {
265c0423487Stb if (!BN_mod(a, a, m, ctx))
266f34e85acStb return 0;
267f34e85acStb
268e0bdcda1Stb if (b == NULL)
269e0bdcda1Stb return 1;
270e0bdcda1Stb
271c0423487Stb return BN_mod(b, b, m, ctx);
272f34e85acStb }
273f34e85acStb
274f34e85acStb /*
275f34e85acStb * Add a random multiple of m to a to test unreduced exponentiation.
276f34e85acStb */
277f34e85acStb
278f34e85acStb BN_CTX_start(ctx);
279f34e85acStb
280f34e85acStb if ((mmodified = BN_CTX_get(ctx)) == NULL)
281f34e85acStb goto err;
282f34e85acStb
2838e84e241Stb if (!bn_copy(mmodified, m))
284f34e85acStb goto err;
285f34e85acStb
286f34e85acStb multiple = arc4random_uniform(16) + 2;
287f34e85acStb
288f34e85acStb if (!BN_mul_word(mmodified, multiple))
289f34e85acStb goto err;
290f34e85acStb
291c0423487Stb if (!BN_add(a, a, mmodified))
292f34e85acStb goto err;
293f34e85acStb
294e0bdcda1Stb if (b == NULL)
295e0bdcda1Stb goto done;
296e0bdcda1Stb
297c0423487Stb if (!BN_add(b, b, mmodified))
298f34e85acStb goto err;
299f34e85acStb
300e0bdcda1Stb done:
301f34e85acStb ret = 1;
302e0bdcda1Stb
303f34e85acStb err:
304f34e85acStb BN_CTX_end(ctx);
305f34e85acStb
306f34e85acStb return ret;
307f34e85acStb }
308f34e85acStb
309e0bdcda1Stb static int
generate_test_triple(int reduce,BIGNUM * a,BIGNUM * p,BIGNUM * m,BN_CTX * ctx)310e0bdcda1Stb generate_test_triple(int reduce, BIGNUM *a, BIGNUM *p, BIGNUM *m, BN_CTX *ctx)
311e0bdcda1Stb {
312e0bdcda1Stb return generate_test_quintuple(reduce, a, p, NULL, NULL, m, ctx);
313e0bdcda1Stb }
314e0bdcda1Stb
3152cac8f3aStb static void
dump_results(const BIGNUM * a,const BIGNUM * p,const BIGNUM * b,const BIGNUM * q,const BIGNUM * m,const BIGNUM * want,const BIGNUM * got,const char * name)3167d8f44b3Stb dump_results(const BIGNUM *a, const BIGNUM *p, const BIGNUM *b, const BIGNUM *q,
3177d8f44b3Stb const BIGNUM *m, const BIGNUM *want, const BIGNUM *got, const char *name)
3182cac8f3aStb {
31958a53292Stb fprintf(stderr, "BN_mod_exp_simple() and %s() disagree:\n", name);
3202cac8f3aStb
32158a53292Stb bn_print("want", want);
32258a53292Stb bn_print("got", got);
3232cac8f3aStb
32458a53292Stb bn_print("a", a);
32558a53292Stb bn_print("p", p);
3267d8f44b3Stb
3277d8f44b3Stb if (b != NULL) {
32858a53292Stb bn_print("b", b);
32958a53292Stb bn_print("q", q);
3307d8f44b3Stb }
3317d8f44b3Stb
33258a53292Stb bn_print("m", m);
3337d8f44b3Stb
33458a53292Stb fprintf(stderr, "\n");
3352cac8f3aStb }
3362cac8f3aStb
3372cac8f3aStb static int
test_mod_exp(const BIGNUM * want,const BIGNUM * a,const BIGNUM * p,const BIGNUM * m,BN_CTX * ctx,const struct mod_exp_test * test)3382cac8f3aStb test_mod_exp(const BIGNUM *want, const BIGNUM *a, const BIGNUM *p,
3392cac8f3aStb const BIGNUM *m, BN_CTX *ctx, const struct mod_exp_test *test)
3402cac8f3aStb {
3412cac8f3aStb BIGNUM *got;
3424dc4dc58Stb int mod_exp_ret;
3432cac8f3aStb int ret = 0;
3442cac8f3aStb
3452cac8f3aStb BN_CTX_start(ctx);
3462cac8f3aStb
3472cac8f3aStb if ((got = BN_CTX_get(ctx)) == NULL)
3482cac8f3aStb goto err;
3492cac8f3aStb
3502cac8f3aStb if (test->mod_exp_fn != NULL)
3514dc4dc58Stb mod_exp_ret = test->mod_exp_fn(got, a, p, m, ctx);
3522cac8f3aStb else
3534dc4dc58Stb mod_exp_ret = test->mod_exp_mont_fn(got, a, p, m, ctx, NULL);
3542cac8f3aStb
3554dc4dc58Stb if (!mod_exp_ret)
3562cac8f3aStb errx(1, "%s() failed", test->name);
3572cac8f3aStb
3582cac8f3aStb if (BN_cmp(want, got) != 0) {
3597d8f44b3Stb dump_results(a, p, NULL, NULL, m, want, got, test->name);
3602cac8f3aStb goto err;
3612cac8f3aStb }
3622cac8f3aStb
3632cac8f3aStb ret = 1;
3642cac8f3aStb
3652cac8f3aStb err:
3662cac8f3aStb BN_CTX_end(ctx);
3672cac8f3aStb
3682cac8f3aStb return ret;
3692cac8f3aStb }
3702cac8f3aStb
3712cac8f3aStb static int
bn_mod_exp_test(int reduce,BIGNUM * want,BIGNUM * a,BIGNUM * p,BIGNUM * m,BN_CTX * ctx)3722cac8f3aStb bn_mod_exp_test(int reduce, BIGNUM *want, BIGNUM *a, BIGNUM *p, BIGNUM *m,
3732cac8f3aStb BN_CTX *ctx)
3742cac8f3aStb {
3752cac8f3aStb size_t i, j;
3762cac8f3aStb int failed = 0;
3772cac8f3aStb
3782cac8f3aStb if (!generate_test_triple(reduce, a, p, m, ctx))
3792cac8f3aStb errx(1, "generate_test_triple");
3802cac8f3aStb
3814141cafdStb for (i = 0; i < 8 && !failed; i++) {
382c0423487Stb BN_set_negative(a, (i >> 0) & 1);
3832cac8f3aStb BN_set_negative(p, (i >> 1) & 1);
384a3971f08Stb BN_set_negative(m, (i >> 2) & 1);
3852cac8f3aStb
3862cac8f3aStb if ((BN_mod_exp_simple(want, a, p, m, ctx)) <= 0)
3872cac8f3aStb errx(1, "BN_mod_exp_simple");
3882cac8f3aStb
3892cac8f3aStb for (j = 0; j < N_MOD_EXP_FN; j++) {
3902cac8f3aStb const struct mod_exp_test *test = &mod_exp_fn[j];
3912cac8f3aStb
3922cac8f3aStb if (!test_mod_exp(want, a, p, m, ctx, test))
3932cac8f3aStb failed |= 1;
3942cac8f3aStb }
3952cac8f3aStb }
3962cac8f3aStb
3972cac8f3aStb return failed;
3982cac8f3aStb }
3992cac8f3aStb
4002cac8f3aStb static int
test_bn_mod_exp(void)40117db9b10Stb test_bn_mod_exp(void)
4022cac8f3aStb {
4032cac8f3aStb BIGNUM *a, *p, *m, *want;
4042cac8f3aStb BN_CTX *ctx;
4052cac8f3aStb int i;
4062cac8f3aStb int reduce;
4072cac8f3aStb int failed = 0;
4082cac8f3aStb
4092cac8f3aStb if ((ctx = BN_CTX_new()) == NULL)
4102cac8f3aStb errx(1, "BN_CTX_new");
4112cac8f3aStb
4122cac8f3aStb BN_CTX_start(ctx);
4132cac8f3aStb
4142cac8f3aStb if ((a = BN_CTX_get(ctx)) == NULL)
4152cac8f3aStb errx(1, "a = BN_CTX_get()");
4162cac8f3aStb if ((p = BN_CTX_get(ctx)) == NULL)
4172cac8f3aStb errx(1, "p = BN_CTX_get()");
4182cac8f3aStb if ((m = BN_CTX_get(ctx)) == NULL)
4192cac8f3aStb errx(1, "m = BN_CTX_get()");
4202cac8f3aStb if ((want = BN_CTX_get(ctx)) == NULL)
4212cac8f3aStb errx(1, "want = BN_CTX_get()");
4222cac8f3aStb
4232cac8f3aStb reduce = 0;
4244141cafdStb for (i = 0; i < N_MOD_EXP_TESTS && !failed; i++)
4252cac8f3aStb failed |= bn_mod_exp_test(reduce, want, a, p, m, ctx);
4262cac8f3aStb
4272cac8f3aStb reduce = 1;
4284141cafdStb for (i = 0; i < N_MOD_EXP_TESTS && !failed; i++)
4292cac8f3aStb failed |= bn_mod_exp_test(reduce, want, a, p, m, ctx);
4302cac8f3aStb
4312cac8f3aStb BN_CTX_end(ctx);
4322cac8f3aStb BN_CTX_free(ctx);
4332cac8f3aStb
4342cac8f3aStb return failed;
4352cac8f3aStb }
4362cac8f3aStb
437f34e85acStb static int
bn_mod_exp2_simple(BIGNUM * out,const BIGNUM * a,const BIGNUM * p,const BIGNUM * b,const BIGNUM * q,const BIGNUM * m,BN_CTX * ctx)438c0423487Stb bn_mod_exp2_simple(BIGNUM *out, const BIGNUM *a, const BIGNUM *p,
439c0423487Stb const BIGNUM *b, const BIGNUM *q, const BIGNUM *m, BN_CTX *ctx)
440f34e85acStb {
441f34e85acStb BIGNUM *fact1, *fact2;
442f34e85acStb int ret = 0;
443f34e85acStb
444f34e85acStb BN_CTX_start(ctx);
445f34e85acStb
446f34e85acStb if ((fact1 = BN_CTX_get(ctx)) == NULL)
447f34e85acStb goto err;
448f34e85acStb if ((fact2 = BN_CTX_get(ctx)) == NULL)
449f34e85acStb goto err;
450f34e85acStb
451c0423487Stb if (!BN_mod_exp_simple(fact1, a, p, m, ctx))
452f34e85acStb goto err;
453c0423487Stb if (!BN_mod_exp_simple(fact2, b, q, m, ctx))
454f34e85acStb goto err;
455f34e85acStb if (!BN_mod_mul(out, fact1, fact2, m, ctx))
456f34e85acStb goto err;
457f34e85acStb
458f34e85acStb ret = 1;
459f34e85acStb err:
460f34e85acStb BN_CTX_end(ctx);
461f34e85acStb
462f34e85acStb return ret;
463f34e85acStb }
464f34e85acStb
465f34e85acStb static int
bn_mod_exp2_test(int reduce,BIGNUM * want,BIGNUM * got,BIGNUM * a,BIGNUM * p,BIGNUM * b,BIGNUM * q,BIGNUM * m,BN_CTX * ctx)466c0423487Stb bn_mod_exp2_test(int reduce, BIGNUM *want, BIGNUM *got, BIGNUM *a, BIGNUM *p,
467c0423487Stb BIGNUM *b, BIGNUM *q, BIGNUM *m, BN_CTX *ctx)
468f34e85acStb {
469f34e85acStb size_t i;
470f34e85acStb int failed = 0;
471f34e85acStb
472c0423487Stb if (!generate_test_quintuple(reduce, a, p, b, q, m, ctx))
473f34e85acStb errx(1, "generate_test_quintuple");
474f34e85acStb
4754141cafdStb for (i = 0; i < 32 && !failed; i++) {
476c0423487Stb BN_set_negative(a, (i >> 0) & 1);
477c0423487Stb BN_set_negative(p, (i >> 1) & 1);
478c0423487Stb BN_set_negative(b, (i >> 2) & 1);
479c0423487Stb BN_set_negative(q, (i >> 3) & 1);
480a3971f08Stb BN_set_negative(m, (i >> 4) & 1);
481f34e85acStb
482c0423487Stb if (!bn_mod_exp2_simple(want, a, p, b, q, m, ctx))
483f34e85acStb errx(1, "BN_mod_exp_simple");
484f34e85acStb
485c0423487Stb if (!BN_mod_exp2_mont(got, a, p, b, q, m, ctx, NULL))
486f34e85acStb errx(1, "BN_mod_exp2_mont");
487f34e85acStb
488f34e85acStb if (BN_cmp(want, got) != 0) {
4897d8f44b3Stb dump_results(a, p, b, q, m, want, got, "BN_mod_exp2_mont");
490f34e85acStb failed |= 1;
491f34e85acStb }
492f34e85acStb }
493f34e85acStb
494f34e85acStb return failed;
495f34e85acStb }
4969cd3ae5cStb
497f34e85acStb static int
test_bn_mod_exp2(void)49817db9b10Stb test_bn_mod_exp2(void)
499f34e85acStb {
500c0423487Stb BIGNUM *a, *p, *b, *q, *m, *want, *got;
501f34e85acStb BN_CTX *ctx;
502f34e85acStb int i;
503f34e85acStb int reduce;
504f34e85acStb int failed = 0;
505f34e85acStb
506f34e85acStb if ((ctx = BN_CTX_new()) == NULL)
507f34e85acStb errx(1, "BN_CTX_new");
508f34e85acStb
509f34e85acStb BN_CTX_start(ctx);
510f34e85acStb
511c0423487Stb if ((a = BN_CTX_get(ctx)) == NULL)
512c0423487Stb errx(1, "a = BN_CTX_get()");
513c0423487Stb if ((p = BN_CTX_get(ctx)) == NULL)
514c0423487Stb errx(1, "p = BN_CTX_get()");
515c0423487Stb if ((b = BN_CTX_get(ctx)) == NULL)
516c0423487Stb errx(1, "b = BN_CTX_get()");
517c0423487Stb if ((q = BN_CTX_get(ctx)) == NULL)
518c0423487Stb errx(1, "q = BN_CTX_get()");
519f34e85acStb if ((m = BN_CTX_get(ctx)) == NULL)
520f34e85acStb errx(1, "m = BN_CTX_get()");
521f34e85acStb if ((want = BN_CTX_get(ctx)) == NULL)
522f34e85acStb errx(1, "want = BN_CTX_get()");
523f34e85acStb if ((got = BN_CTX_get(ctx)) == NULL)
524f1a5dec3Stb errx(1, "got = BN_CTX_get()");
525f34e85acStb
526f34e85acStb reduce = 0;
5274141cafdStb for (i = 0; i < N_MOD_EXP_TESTS && !failed; i++)
528c0423487Stb failed |= bn_mod_exp2_test(reduce, want, got, a, p, b, q, m, ctx);
529f34e85acStb
530f34e85acStb reduce = 1;
5314141cafdStb for (i = 0; i < N_MOD_EXP_TESTS && !failed; i++)
532c0423487Stb failed |= bn_mod_exp2_test(reduce, want, got, a, p, b, q, m, ctx);
533f34e85acStb
534f34e85acStb BN_CTX_end(ctx);
535f34e85acStb BN_CTX_free(ctx);
536f34e85acStb
537f34e85acStb return failed;
538f34e85acStb }
539f34e85acStb
54039f402e9Stb /*
54139f402e9Stb * Small test for a crash reported by Guido Vranken, fixed in bn_exp2.c r1.13.
54239f402e9Stb * https://github.com/openssl/openssl/issues/17648
54339f402e9Stb */
54439f402e9Stb
54539f402e9Stb static int
test_bn_mod_exp2_mont_crash(void)54639f402e9Stb test_bn_mod_exp2_mont_crash(void)
54739f402e9Stb {
54839f402e9Stb BIGNUM *m;
54939f402e9Stb int failed = 0;
55039f402e9Stb
55139f402e9Stb if ((m = BN_new()) == NULL)
55239f402e9Stb errx(1, "BN_new");
55339f402e9Stb
55439f402e9Stb if (BN_mod_exp2_mont(NULL, NULL, NULL, NULL, NULL, m, NULL, NULL)) {
55539f402e9Stb fprintf(stderr, "BN_mod_exp2_mont succeeded\n");
55639f402e9Stb failed |= 1;
55739f402e9Stb }
55839f402e9Stb
55939f402e9Stb BN_free(m);
56039f402e9Stb
56139f402e9Stb return failed;
56239f402e9Stb }
56339f402e9Stb
564*24882d0aStb const struct aliasing_test_case {
565*24882d0aStb BN_ULONG a;
566*24882d0aStb BN_ULONG p;
567*24882d0aStb BN_ULONG m;
568*24882d0aStb } aliasing_test_cases[] = {
569*24882d0aStb {
570*24882d0aStb .a = 1031,
571*24882d0aStb .p = 1033,
572*24882d0aStb .m = 1039,
573*24882d0aStb },
574*24882d0aStb {
575*24882d0aStb .a = 3,
576*24882d0aStb .p = 4,
577*24882d0aStb .m = 5,
578*24882d0aStb },
579*24882d0aStb {
580*24882d0aStb .a = 97,
581*24882d0aStb .p = 17,
582*24882d0aStb .m = 11,
583*24882d0aStb },
584*24882d0aStb {
585*24882d0aStb .a = 999961,
586*24882d0aStb .p = 999979,
587*24882d0aStb .m = 999983,
588*24882d0aStb },
589*24882d0aStb };
590*24882d0aStb
591*24882d0aStb #define N_ALIASING_TEST_CASES \
592*24882d0aStb (sizeof(aliasing_test_cases) / sizeof(aliasing_test_cases[0]))
593*24882d0aStb
594*24882d0aStb static void
test_bn_mod_exp_aliasing_setup(BIGNUM * want,BIGNUM * a,BIGNUM * p,BIGNUM * m,BN_CTX * ctx,const struct aliasing_test_case * tc)595*24882d0aStb test_bn_mod_exp_aliasing_setup(BIGNUM *want, BIGNUM *a, BIGNUM *p, BIGNUM *m,
596*24882d0aStb BN_CTX *ctx, const struct aliasing_test_case *tc)
597*24882d0aStb {
598*24882d0aStb if (!BN_set_word(a, tc->a))
599*24882d0aStb errx(1, "BN_set_word");
600*24882d0aStb if (!BN_set_word(p, tc->p))
601*24882d0aStb errx(1, "BN_set_word");
602*24882d0aStb if (!BN_set_word(m, tc->m))
603*24882d0aStb errx(1, "BN_set_word");
604*24882d0aStb
605*24882d0aStb if (!BN_mod_exp_simple(want, a, p, m, ctx))
606*24882d0aStb errx(1, "BN_mod_exp");
607*24882d0aStb }
608*24882d0aStb
6097849ca55Stb static int
test_mod_exp_aliased(const char * alias,int want_ret,BIGNUM * got,const BIGNUM * want,const BIGNUM * a,const BIGNUM * p,const BIGNUM * m,BN_CTX * ctx,const struct mod_exp_test * test)6107849ca55Stb test_mod_exp_aliased(const char *alias, int want_ret, BIGNUM *got,
6117849ca55Stb const BIGNUM *want, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
6127849ca55Stb BN_CTX *ctx, const struct mod_exp_test *test)
6137849ca55Stb {
6147849ca55Stb int mod_exp_ret;
6157849ca55Stb int ret = 0;
6167849ca55Stb
6177849ca55Stb BN_CTX_start(ctx);
6187849ca55Stb
6197849ca55Stb if (test->mod_exp_fn != NULL)
6207849ca55Stb mod_exp_ret = test->mod_exp_fn(got, a, p, m, ctx);
6217849ca55Stb else
6227849ca55Stb mod_exp_ret = test->mod_exp_mont_fn(got, a, p, m, ctx, NULL);
6237849ca55Stb
624*24882d0aStb if (mod_exp_ret != want_ret) {
625*24882d0aStb warnx("%s() %s aliased with result failed", test->name, alias);
626*24882d0aStb goto err;
627*24882d0aStb }
6287849ca55Stb
6297849ca55Stb if (!mod_exp_ret)
6307849ca55Stb goto done;
6317849ca55Stb
6327849ca55Stb if (BN_cmp(want, got) != 0) {
6337849ca55Stb dump_results(a, p, NULL, NULL, m, want, got, test->name);
6347849ca55Stb goto err;
6357849ca55Stb }
6367849ca55Stb
6377849ca55Stb done:
6387849ca55Stb ret = 1;
6397849ca55Stb
6407849ca55Stb err:
6417849ca55Stb BN_CTX_end(ctx);
6427849ca55Stb
6437849ca55Stb return ret;
6447849ca55Stb }
6457849ca55Stb
646*24882d0aStb static int
test_bn_mod_exp_aliasing_test(const struct mod_exp_test * test,BIGNUM * a,BIGNUM * p,BIGNUM * m,BIGNUM * want,BIGNUM * got,BN_CTX * ctx)647*24882d0aStb test_bn_mod_exp_aliasing_test(const struct mod_exp_test *test,
648*24882d0aStb BIGNUM *a, BIGNUM *p, BIGNUM *m, BIGNUM *want, BIGNUM *got, BN_CTX *ctx)
6497849ca55Stb {
650*24882d0aStb int modulus_alias_works = test->mod_exp_fn != BN_mod_exp_simple;
651*24882d0aStb size_t i;
652*24882d0aStb int failed = 0;
6537849ca55Stb
654*24882d0aStb for (i = 0; i < N_ALIASING_TEST_CASES; i++) {
655*24882d0aStb const struct aliasing_test_case *tc = &aliasing_test_cases[i];
656*24882d0aStb
657*24882d0aStb test_bn_mod_exp_aliasing_setup(want, a, p, m, ctx, tc);
658*24882d0aStb if (!test_mod_exp_aliased("nothing", 1, got, want, a, p, m, ctx,
659*24882d0aStb test))
660*24882d0aStb failed |= 1;
661*24882d0aStb test_bn_mod_exp_aliasing_setup(want, a, p, m, ctx, tc);
662*24882d0aStb if (!test_mod_exp_aliased("a", 1, a, want, a, p, m, ctx, test))
663*24882d0aStb failed |= 1;
664*24882d0aStb test_bn_mod_exp_aliasing_setup(want, a, p, m, ctx, tc);
665*24882d0aStb if (!test_mod_exp_aliased("p", 1, p, want, a, p, m, ctx, test))
666*24882d0aStb failed |= 1;
667*24882d0aStb test_bn_mod_exp_aliasing_setup(want, a, p, m, ctx, tc);
668*24882d0aStb if (!test_mod_exp_aliased("m", modulus_alias_works, m, want,
669*24882d0aStb a, p, m, ctx, test))
670*24882d0aStb failed |= 1;
671*24882d0aStb }
672*24882d0aStb
673*24882d0aStb return failed;
6747849ca55Stb }
6757849ca55Stb
6767849ca55Stb static int
test_bn_mod_exp_aliasing(void)6777849ca55Stb test_bn_mod_exp_aliasing(void)
6787849ca55Stb {
6797849ca55Stb BN_CTX *ctx;
6807849ca55Stb BIGNUM *a, *p, *m, *want, *got;
6817849ca55Stb size_t i;
6827849ca55Stb int failed = 0;
6837849ca55Stb
6847849ca55Stb if ((ctx = BN_CTX_new()) == NULL)
6857849ca55Stb errx(1, "BN_CTX_new");
6867849ca55Stb
6877849ca55Stb BN_CTX_start(ctx);
6887849ca55Stb
6897849ca55Stb if ((a = BN_CTX_get(ctx)) == NULL)
6907849ca55Stb errx(1, "a = BN_CTX_get()");
6917849ca55Stb if ((p = BN_CTX_get(ctx)) == NULL)
6927849ca55Stb errx(1, "p = BN_CTX_get()");
6937849ca55Stb if ((m = BN_CTX_get(ctx)) == NULL)
6947849ca55Stb errx(1, "m = BN_CTX_get()");
6957849ca55Stb if ((want = BN_CTX_get(ctx)) == NULL)
6967849ca55Stb errx(1, "want = BN_CTX_get()");
6977849ca55Stb if ((got = BN_CTX_get(ctx)) == NULL)
6987849ca55Stb errx(1, "got = BN_CTX_get()");
6997849ca55Stb
7007849ca55Stb for (i = 0; i < N_MOD_EXP_FN; i++) {
7017849ca55Stb const struct mod_exp_test *test = &mod_exp_fn[i];
702*24882d0aStb failed |= test_bn_mod_exp_aliasing_test(test, a, p, m,
703*24882d0aStb want, got, ctx);
7047849ca55Stb }
7057849ca55Stb
7067849ca55Stb BN_CTX_end(ctx);
7077849ca55Stb BN_CTX_free(ctx);
7087849ca55Stb
7097849ca55Stb return failed;
7107849ca55Stb }
7117849ca55Stb
7122cac8f3aStb int
main(void)7132cac8f3aStb main(void)
7142cac8f3aStb {
7152cac8f3aStb int failed = 0;
7162cac8f3aStb
71717db9b10Stb failed |= test_bn_mod_exp_zero();
71817db9b10Stb failed |= test_bn_mod_exp();
71917db9b10Stb failed |= test_bn_mod_exp2();
72039f402e9Stb failed |= test_bn_mod_exp2_mont_crash();
7217849ca55Stb failed |= test_bn_mod_exp_aliasing();
7222cac8f3aStb
7232cac8f3aStb return failed;
7242cac8f3aStb }
725