1/*	$OpenBSD: bn_unit.c,v 1.7 2023/06/21 07:15:38 jsing Exp $ */
2
3/*
4 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
5 *
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
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <err.h>
20#include <limits.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include <openssl/bn.h>
26
27static int
28test_bn_print_wrapper(char *a, size_t size, const char *descr,
29    int (*to_bn)(BIGNUM **, const char *))
30{
31	int ret;
32
33	ret = to_bn(NULL, a);
34	if (ret != 0 && (ret < 0 || (size_t)ret != size - 1)) {
35		fprintf(stderr, "unexpected %s() return"
36		    "want 0 or %zu, got %d\n", descr, size - 1, ret);
37		return 1;
38	}
39
40	return 0;
41}
42
43static int
44test_bn_print_null_derefs(void)
45{
46	size_t size = INT_MAX / 4 + 4;
47	size_t datalimit = (size + 500 * 1024) / 1024;
48	char *a;
49	char digit;
50	int failed = 0;
51
52	if ((a = malloc(size)) == NULL) {
53		warn("malloc(%zu) failed (make sure data limit is >= %zu KiB)",
54		    size, datalimit);
55		return 0;
56	}
57
58	/* Fill with a random digit since coverity doesn't like us using '0'. */
59	digit = '0' + arc4random_uniform(10);
60
61	memset(a, digit, size - 1);
62	a[size - 1] = '\0';
63
64	failed |= test_bn_print_wrapper(a, size, "BN_dec2bn", BN_dec2bn);
65	failed |= test_bn_print_wrapper(a, size, "BN_hex2bn", BN_hex2bn);
66
67	free(a);
68
69	return failed;
70}
71
72static int
73test_bn_num_bits(void)
74{
75	BIGNUM *bn;
76	int i, num_bits;
77	int failed = 0;
78
79	if ((bn = BN_new()) == NULL)
80		errx(1, "BN_new");
81
82	if ((num_bits = BN_num_bits(bn)) != 0) {
83		warnx("BN_num_bits(0): got %d, want 0", num_bits);
84		failed |= 1;
85	}
86
87	if (!BN_set_word(bn, 1))
88		errx(1, "BN_set_word");
89
90	for (i = 0; i <= 5 * BN_BITS2; i++) {
91		if ((num_bits = BN_num_bits(bn)) != i + 1) {
92			warnx("BN_num_bits(1 << %d): got %d, want %d",
93			    i, num_bits, i + 1);
94			failed |= 1;
95		}
96		if (!BN_lshift1(bn, bn))
97			errx(1, "BN_lshift1");
98	}
99
100	if (BN_hex2bn(&bn, "0000000000000000010000000000000000") != 34)
101		errx(1, "BN_hex2bn");
102
103	if ((num_bits = BN_num_bits(bn)) != 65) {
104		warnx("BN_num_bits(1 << 64) padded: got %d, want %d",
105		    num_bits, 65);
106		failed |= 1;
107	}
108
109	BN_free(bn);
110
111	return failed;
112}
113
114static int
115test_bn_num_bits_word(void)
116{
117	BN_ULONG w = 1;
118	int i, num_bits;
119	int failed = 0;
120
121	if ((num_bits = BN_num_bits_word(0)) != 0) {
122		warnx("BN_num_bits_word(0): want 0, got %d", num_bits);
123		failed |= 1;
124	}
125
126	for (i = 0; i < BN_BITS2; i++) {
127		if ((num_bits = BN_num_bits_word(w << i)) != i + 1) {
128			warnx("BN_num_bits_word(0x%llx): want %d, got %d",
129			    (unsigned long long)(w << i), i + 1, num_bits);
130			failed |= 1;
131		}
132	}
133
134	return failed;
135}
136
137#define BN_FLG_ALL_KNOWN \
138    (BN_FLG_STATIC_DATA | BN_FLG_CONSTTIME | BN_FLG_MALLOCED)
139
140static int
141bn_check_expected_flags(const BIGNUM *bn, int expected, const char *fn,
142    const char *descr)
143{
144	int flags, got;
145	int ret = 1;
146
147	flags = BN_get_flags(bn, BN_FLG_ALL_KNOWN);
148
149	if ((got = flags & expected) != expected) {
150		fprintf(stderr, "%s: %s: expected flags: want %x, got %x\n",
151		    fn, descr, expected, got);
152		ret = 0;
153	}
154
155	if ((got = flags & ~expected) != 0) {
156		fprintf(stderr, "%s: %s: unexpected flags: want %x, got %x\n",
157		    fn, descr, 0, got);
158		ret = 0;
159	}
160
161	return ret;
162}
163
164static int
165test_bn_copy_copies_flags(void)
166{
167	BIGNUM *dst, *src;
168	int failed = 0;
169
170	if ((dst = BN_new()) == NULL)
171		errx(1, "%s: src = BN_new()", __func__);
172
173	if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED,
174	    __func__, "dst after BN_new"))
175		failed |= 1;
176
177	if (BN_copy(dst, BN_value_one()) == NULL)
178		errx(1, "%s: bn_copy()", __func__);
179
180	if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED,
181	    __func__, "dst after bn_copy"))
182		failed |= 1;
183
184	if ((src = BN_new()) == NULL)
185		errx(1, "%s: src = BN_new()", __func__);
186
187	BN_set_flags(src, BN_FLG_CONSTTIME);
188
189	if (!bn_check_expected_flags(src, BN_FLG_MALLOCED | BN_FLG_CONSTTIME,
190	    __func__, "src after BN_set_flags"))
191		failed |= 1;
192
193	if (!BN_set_word(src, 57))
194		errx(1, "%s: BN_set_word(src, 57)", __func__);
195
196	if (BN_copy(dst, src) == NULL)
197		errx(1, "%s: BN_copy(dst, src)", __func__);
198
199	if (BN_cmp(src, dst) != 0) {
200		fprintf(stderr, "copy not equal to original\n");
201		failed |= 1;
202	}
203
204	if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED | BN_FLG_CONSTTIME,
205	    __func__, "dst after BN_copy(dst, src)"))
206		failed |= 1;
207
208	BN_free(dst);
209	BN_free(src);
210
211	return failed;
212}
213
214static int
215test_bn_copy_consttime_is_sticky(void)
216{
217	BIGNUM *src, *dst;
218	int failed = 0;
219
220	if ((src = BN_new()) == NULL)
221		errx(1, "%s: src = BN_new()", __func__);
222
223	if (!bn_check_expected_flags(src, BN_FLG_MALLOCED,
224	    __func__, "src after BN_new"))
225		failed |= 1;
226
227	if ((dst = BN_new()) == NULL)
228		errx(1, "%s: dst = BN_new()", __func__);
229
230	if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED,
231	    __func__, "dst after BN_new"))
232		failed |= 1;
233
234	BN_set_flags(dst, BN_FLG_CONSTTIME);
235
236	if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED | BN_FLG_CONSTTIME,
237	    __func__, "src after BN_new"))
238		failed |= 1;
239
240	if (BN_copy(dst, BN_value_one()) == NULL)
241		errx(1, "%s: bn_copy()", __func__);
242
243	if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED | BN_FLG_CONSTTIME,
244	    __func__, "dst after bn_copy"))
245		failed |= 1;
246
247	BN_free(dst);
248	BN_free(src);
249
250	return failed;
251}
252
253static int
254test_bn_dup_consttime_is_sticky(void)
255{
256	BIGNUM *src, *dst;
257	int failed = 0;
258
259	if (!bn_check_expected_flags(BN_value_one(), BN_FLG_STATIC_DATA,
260	    __func__, "flags on BN_value_one()"))
261		failed |= 1;
262
263	if ((dst = BN_dup(BN_value_one())) == NULL)
264		errx(1, "%s: dst = BN_dup(BN_value_one())", __func__);
265
266	if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED,
267	    __func__, "dst after BN_dup(BN_value_one())"))
268		failed |= 1;
269
270	BN_free(dst);
271
272	if ((src = BN_new()) == NULL)
273		errx(1, "%s: src = BN_new()", __func__);
274
275	BN_set_flags(src, BN_FLG_CONSTTIME);
276
277	if (!bn_check_expected_flags(src, BN_FLG_MALLOCED | BN_FLG_CONSTTIME,
278	    __func__, "src after BN_new"))
279		failed |= 1;
280
281	if ((dst = BN_dup(src)) == NULL)
282		errx(1, "%s: dst = BN_dup(src)", __func__);
283
284	if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED | BN_FLG_CONSTTIME,
285	    __func__, "dst after bn_copy"))
286		failed |= 1;
287
288	BN_free(dst);
289	BN_free(src);
290
291	return failed;
292}
293
294int
295main(void)
296{
297	int failed = 0;
298
299	failed |= test_bn_print_null_derefs();
300	failed |= test_bn_num_bits();
301	failed |= test_bn_num_bits_word();
302	failed |= test_bn_copy_copies_flags();
303	failed |= test_bn_copy_consttime_is_sticky();
304	failed |= test_bn_dup_consttime_is_sticky();
305
306	return failed;
307}
308