1/*	$OpenBSD: bn_print.c,v 1.5 2023/07/27 06:41:39 tb Exp $ */
2
3/*
4 * Copyright (c) 2023 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 <stdio.h>
21#include <string.h>
22
23#include <openssl/asn1.h>
24#include <openssl/bio.h>
25#include <openssl/bn.h>
26
27#include "bn_local.h"
28
29#define BATIHDIDIDI "mana mana"
30#define BUF_MEM_LEN 1024
31
32static const char *pk = "040d305e1b159d03d0a17935b73a3c927aca151ccd62f39c"
33			"265c073de554faa3d6cc12eaf4145fe88e19ab2f2e48e6ac"
34			"184378acd037c3bdb2cd2ce647e21ae663b83d2e2f78c44f"
35			"dbf40fa4684c55726b951d4e18429578cc373c91e29b652b"
36			"29";
37
38const struct print_test {
39	const char *desc;
40	const char *want;
41} bn_print_tests[] = {
42	{
43		.desc = "zero",
44		.want = "    mana mana 0\n",
45	},
46	{
47		.desc = "minus one",
48		.want = "    mana mana 1 (0x1)\n",
49	},
50	{
51		.desc = "minus one",
52		.want = "    mana mana -1 (-0x1)\n",
53	},
54#ifdef _LP64
55	{
56		.desc = "largest word",
57		.want = "    mana mana 18446744073709551615 "
58			"(0xffffffffffffffff)\n",
59	},
60	{
61		.desc = "smallest word",
62		.want = "    mana mana -18446744073709551615 "
63			"(-0xffffffffffffffff)\n",
64	},
65	{
66		.desc = "largest negative non-word",
67		.want = "    mana mana (Negative)\n"
68			"        01:00:00:00:00:00:00:00:00\n",
69	},
70	{
71		.desc = "smallest positive non-word",
72		.want = "    mana mana\n"
73			"        01:00:00:00:00:00:00:00:00\n",
74	},
75#else
76	{
77		.desc = "largest word",
78		.want = "    mana mana 4294967295 (0xffffffff)\n",
79	},
80	{
81		.desc = "smallest word",
82		.want = "    mana mana -4294967295 (-0xffffffff)\n",
83	},
84	{
85		.desc = "largest negative non-word",
86		.want = "    mana mana (Negative)\n"
87			"        01:00:00:00:00\n",
88	},
89	{
90		.desc = "smallest positive non-word",
91		.want = "    mana mana\n"
92			"        01:00:00:00:00\n",
93	},
94#endif
95	{
96		.desc = "some pubkey",
97		.want = "    mana mana\n"
98			"        04:0d:30:5e:1b:15:9d:03:d0:a1:79:35:b7:3a:3c:\n"
99			"        92:7a:ca:15:1c:cd:62:f3:9c:26:5c:07:3d:e5:54:\n"
100			"        fa:a3:d6:cc:12:ea:f4:14:5f:e8:8e:19:ab:2f:2e:\n"
101			"        48:e6:ac:18:43:78:ac:d0:37:c3:bd:b2:cd:2c:e6:\n"
102			"        47:e2:1a:e6:63:b8:3d:2e:2f:78:c4:4f:db:f4:0f:\n"
103			"        a4:68:4c:55:72:6b:95:1d:4e:18:42:95:78:cc:37:\n"
104			"        3c:91:e2:9b:65:2b:29\n",
105	},
106	{
107		.desc = "negated pubkey",
108		.want = "    mana mana (Negative)\n"
109			"        04:0d:30:5e:1b:15:9d:03:d0:a1:79:35:b7:3a:3c:\n"
110			"        92:7a:ca:15:1c:cd:62:f3:9c:26:5c:07:3d:e5:54:\n"
111			"        fa:a3:d6:cc:12:ea:f4:14:5f:e8:8e:19:ab:2f:2e:\n"
112			"        48:e6:ac:18:43:78:ac:d0:37:c3:bd:b2:cd:2c:e6:\n"
113			"        47:e2:1a:e6:63:b8:3d:2e:2f:78:c4:4f:db:f4:0f:\n"
114			"        a4:68:4c:55:72:6b:95:1d:4e:18:42:95:78:cc:37:\n"
115			"        3c:91:e2:9b:65:2b:29\n",
116	},
117	{
118		.desc = "shifted negated pubkey",
119		.want = "    mana mana (Negative)\n"
120			"        04:0d:30:5e:1b:15:9d:03:d0:a1:79:35:b7:3a:3c:\n"
121			"        92:7a:ca:15:1c:cd:62:f3:9c:26:5c:07:3d:e5:54:\n"
122			"        fa:a3:d6:cc:12:ea:f4:14:5f:e8:8e:19:ab:2f:2e:\n"
123			"        48:e6:ac:18:43:78:ac:d0:37:c3:bd:b2:cd:2c:e6:\n"
124			"        47:e2:1a:e6:63:b8:3d:2e:2f:78:c4:4f:db:f4:0f:\n"
125			"        a4:68:4c:55:72:6b:95:1d:4e:18:42:95:78:cc:37\n",
126	},
127	{
128		.desc = "shifted pubkey",
129		.want = "    mana mana\n"
130			"        04:0d:30:5e:1b:15:9d:03:d0:a1:79:35:b7:3a:3c:\n"
131			"        92:7a:ca:15:1c:cd:62:f3:9c:26:5c:07:3d:e5:54:\n"
132			"        fa:a3:d6:cc:12:ea:f4:14:5f:e8:8e:19:ab:2f:2e:\n"
133			"        48:e6:ac:18:43:78:ac:d0:37:c3:bd:b2:cd:2c:e6:\n"
134			"        47:e2:1a:e6:63:b8:3d:2e:2f:78:c4:4f:db:f4:0f:\n"
135			"        a4:68:4c:55:72:6b:95:1d:4e:18:42:95:78:cc:37\n",
136	},
137	{
138		.desc = "high bit of first nibble is set",
139		.want = "    mana mana\n"
140			"        00:80:00:00:00:00:00:00:00:00\n",
141	},
142	{
143		/* XXX - this is incorrect and should be fixed. */
144		.desc = "high bit of first nibble is set for negative number",
145		.want = "    mana mana (Negative)\n"
146			"        00:80:00:00:00:00:00:00:00:00\n",
147	},
148};
149
150#define N_TESTCASES	(sizeof(bn_print_tests) / sizeof(bn_print_tests[0]))
151
152static int
153bn_print_testcase(const BIGNUM *bn, const struct print_test *test)
154{
155	BIO *bio;
156	char *got;
157	size_t want_len;
158	long got_len;
159	int failed = 1;
160
161	if ((bio = BIO_new(BIO_s_mem())) == NULL)
162		errx(1, "BIO_new");
163
164	if (!bn_printf(bio, bn, 4, "%s", BATIHDIDIDI))
165		errx(1, "bn_printf");
166
167	if ((got_len = BIO_get_mem_data(bio, &got)) < 0)
168		errx(1, "BIO_get_mem_data");
169
170	if ((want_len = strlen(test->want)) != (size_t)got_len) {
171		fprintf(stderr, "%s: want: %zu, got %ld\n",
172		    test->desc, want_len, got_len);
173		goto err;
174	}
175
176	if (strncmp(got, test->want, want_len) != 0) {
177		fprintf(stderr, "%s: strings differ\n", test->desc);
178		fprintf(stderr, "want: \"%s\"\ngot : \"%*s\"\n",
179		    test->want, (int)got_len, got);
180		goto err;
181	}
182
183	failed = 0;
184 err:
185	BIO_free(bio);
186
187	return failed;
188}
189
190int
191main(void)
192{
193	const struct print_test *test;
194	size_t testcase = 0;
195	BIGNUM *bn;
196	int failed = 0;
197
198	/* zero */
199	if ((bn = BN_new()) == NULL)
200		errx(1, "BN_new");
201	if (testcase >= N_TESTCASES)
202		errx(1, "Too many tests");
203	test = &bn_print_tests[testcase++];
204	failed |= bn_print_testcase(bn, test);
205
206	/* one */
207	if (!BN_set_word(bn, 1))
208		errx(1, "BIO_set_word");
209	if (testcase >= N_TESTCASES)
210		errx(1, "Too many tests");
211	test = &bn_print_tests[testcase++];
212	failed |= bn_print_testcase(bn, test);
213
214	/* minus one */
215	BN_set_negative(bn, 1);
216	if (testcase >= N_TESTCASES)
217		errx(1, "Too many tests");
218	test = &bn_print_tests[testcase++];
219	failed |= bn_print_testcase(bn, test);
220
221	/* largest word */
222	if (!BN_set_word(bn, ~0))
223		errx(1, "BN_set_word");
224	if (testcase >= N_TESTCASES)
225		errx(1, "Too many tests");
226	test = &bn_print_tests[testcase++];
227	failed |= bn_print_testcase(bn, test);
228
229	/* smallest word */
230	BN_set_negative(bn, 1);
231	if (testcase >= N_TESTCASES)
232		errx(1, "Too many tests");
233	test = &bn_print_tests[testcase++];
234	failed |= bn_print_testcase(bn, test);
235
236	/* largest negative non-word */
237	if (!BN_sub_word(bn, 1))
238		errx(1, "ASN1_bn_print");
239	if (testcase >= N_TESTCASES)
240		errx(1, "Too many tests");
241	test = &bn_print_tests[testcase++];
242	failed |= bn_print_testcase(bn, test);
243
244	/* smallest positive non-word */
245	BN_set_negative(bn, 0);
246	if (testcase >= N_TESTCASES)
247		errx(1, "Too many tests");
248	test = &bn_print_tests[testcase++];
249	failed |= bn_print_testcase(bn, test);
250
251	/* some pubkey */
252	if (BN_hex2bn(&bn, pk) == 0)
253		errx(1, "BN_hex2bn");
254	if (testcase >= N_TESTCASES)
255		errx(1, "Too many tests");
256	test = &bn_print_tests[testcase++];
257	failed |= bn_print_testcase(bn, test);
258
259	/* negated pubkey */
260	BN_set_negative(bn, 1);
261	if (testcase >= N_TESTCASES)
262		errx(1, "Too many tests");
263	test = &bn_print_tests[testcase++];
264	failed |= bn_print_testcase(bn, test);
265
266	/* shifted negated pubkey */
267	if (!BN_rshift(bn, bn, 7 * 8))
268		errx(1, "BN_rshift");
269	if (testcase >= N_TESTCASES)
270		errx(1, "Too many tests");
271	test = &bn_print_tests[testcase++];
272	failed |= bn_print_testcase(bn, test);
273
274	/* shifted pubkey */
275	BN_set_negative(bn, 0);
276	if (testcase >= N_TESTCASES)
277		errx(1, "Too many tests");
278	test = &bn_print_tests[testcase++];
279	failed |= bn_print_testcase(bn, test);
280
281	/* high bit of first nibble is set. */
282	BN_zero(bn);
283	if (!BN_set_bit(bn, 71))
284		errx(1, "BN_set_bit");
285	if (testcase >= N_TESTCASES)
286		errx(1, "Too many tests");
287	test = &bn_print_tests[testcase++];
288	failed |= bn_print_testcase(bn, test);
289
290	/* high bit of first nibble is set for negative number. */
291	BN_set_negative(bn, 1);
292	if (testcase >= N_TESTCASES)
293		errx(1, "Too many tests");
294	test = &bn_print_tests[testcase++];
295	failed |= bn_print_testcase(bn, test);
296
297	if (testcase != N_TESTCASES) {
298		warnx("Not all tests run");
299		failed |= 1;
300	}
301
302	BN_free(bn);
303
304	return failed;
305}
306