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
32 static const char *pk = "040d305e1b159d03d0a17935b73a3c927aca151ccd62f39c"
33 "265c073de554faa3d6cc12eaf4145fe88e19ab2f2e48e6ac"
34 "184378acd037c3bdb2cd2ce647e21ae663b83d2e2f78c44f"
35 "dbf40fa4684c55726b951d4e18429578cc373c91e29b652b"
36 "29";
37
38 const 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
152 static int
bn_print_testcase(const BIGNUM * bn,const struct print_test * test)153 bn_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
190 int
main(void)191 main(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