]>
Commit | Line | Data |
---|---|---|
37916462 P |
1 | #include "../testutil.h" |
2 | #include "output.h" | |
3 | #include "tu_local.h" | |
4 | ||
5 | #include <string.h> | |
6 | #include <ctype.h> | |
7 | #include "../../e_os.h" | |
8 | ||
9 | /* The size of memory buffers to display on failure */ | |
10 | #define MEM_BUFFER_SIZE (2000) | |
11 | #define MAX_STRING_WIDTH (80) | |
12 | #define BN_OUTPUT_SIZE (8) | |
13 | ||
14 | /* Output a diff header */ | |
15 | static void test_diff_header(const char *left, const char *right) | |
16 | { | |
17 | test_printf_stderr("%*s# --- %s\n", subtest_level(), "", left); | |
18 | test_printf_stderr("%*s# +++ %s\n", subtest_level(), "", right); | |
19 | } | |
20 | ||
21 | /* Formatted string output routines */ | |
22 | static void test_string_null_empty(const char *m, char c) | |
23 | { | |
24 | if (m == NULL) | |
25 | test_printf_stderr("%*s# % 4s %c NULL\n", subtest_level(), "", "", c); | |
26 | else | |
27 | test_printf_stderr("%*s# % 4u:%c ''\n", subtest_level(), "", 0u, c); | |
28 | } | |
29 | ||
30 | static void test_fail_string_common(const char *prefix, const char *file, | |
31 | int line, const char *type, | |
32 | const char *left, const char *right, | |
33 | const char *op, const char *m1, size_t l1, | |
34 | const char *m2, size_t l2) | |
35 | { | |
36 | const int indent = subtest_level(); | |
37 | const size_t width = (MAX_STRING_WIDTH - indent - 12) / 16 * 16; | |
38 | char b1[MAX_STRING_WIDTH + 1], b2[MAX_STRING_WIDTH + 1]; | |
39 | char bdiff[MAX_STRING_WIDTH + 1]; | |
40 | size_t n1, n2, i; | |
41 | unsigned int cnt = 0, diff; | |
42 | ||
43 | test_fail_message_prefix(prefix, file, line, type, left, right, op); | |
44 | if (m1 == NULL) | |
45 | l1 = 0; | |
46 | if (m2 == NULL) | |
47 | l2 = 0; | |
48 | if (l1 == 0 && l2 == 0) { | |
49 | if ((m1 == NULL) == (m2 == NULL)) { | |
50 | test_string_null_empty(m1, ' '); | |
51 | } else { | |
52 | test_diff_header(left, right); | |
53 | test_string_null_empty(m1, '-'); | |
54 | test_string_null_empty(m2, '+'); | |
55 | } | |
56 | goto fin; | |
57 | } | |
58 | ||
59 | if (l1 != l2 || strcmp(m1, m2) != 0) | |
60 | test_diff_header(left, right); | |
61 | ||
62 | while (l1 > 0 || l2 > 0) { | |
63 | n1 = n2 = 0; | |
64 | if (l1 > 0) { | |
65 | b1[n1 = l1 > width ? width : l1] = 0; | |
66 | for (i = 0; i < n1; i++) | |
67 | b1[i] = isprint(m1[i]) ? m1[i] : '.'; | |
68 | } | |
69 | if (l2 > 0) { | |
70 | b2[n2 = l2 > width ? width : l2] = 0; | |
71 | for (i = 0; i < n2; i++) | |
72 | b2[i] = isprint(m2[i]) ? m2[i] : '.'; | |
73 | } | |
74 | diff = 0; | |
75 | i = 0; | |
76 | if (n1 > 0 && n2 > 0) { | |
77 | const size_t j = n1 < n2 ? n1 : n2; | |
78 | ||
79 | for (; i < j; i++) | |
80 | if (m1[i] == m2[i]) { | |
81 | bdiff[i] = ' '; | |
82 | } else { | |
83 | bdiff[i] = '^'; | |
84 | diff = 1; | |
85 | } | |
86 | bdiff[i] = '\0'; | |
87 | } | |
88 | if (n1 == n2 && !diff) { | |
89 | test_printf_stderr("%*s# % 4u: '%s'\n", indent, "", cnt, | |
90 | n2 > n1 ? b2 : b1); | |
91 | } else { | |
92 | if (cnt == 0 && (m1 == NULL || *m1 == '\0')) | |
93 | test_string_null_empty(m1, '-'); | |
94 | else if (n1 > 0) | |
95 | test_printf_stderr("%*s# % 4u:- '%s'\n", indent, "", cnt, b1); | |
96 | if (cnt == 0 && (m2 == NULL || *m2 == '\0')) | |
97 | test_string_null_empty(m2, '+'); | |
98 | else if (n2 > 0) | |
99 | test_printf_stderr("%*s# % 4u:+ '%s'\n", indent, "", cnt, b2); | |
100 | if (diff && i > 0) | |
101 | test_printf_stderr("%*s# % 4s %s\n", indent, "", "", bdiff); | |
102 | } | |
103 | m1 += n1; | |
104 | m2 += n2; | |
105 | l1 -= n1; | |
106 | l2 -= n2; | |
107 | cnt += width; | |
108 | } | |
109 | fin: | |
110 | test_flush_stderr(); | |
111 | } | |
112 | ||
113 | /* | |
114 | * Wrapper routines so that the underlying code can be shared. | |
115 | * The first is the call from inside the test utilities when a conditional | |
116 | * fails. The second is the user's call to dump a string. | |
117 | */ | |
118 | void test_fail_string_message(const char *prefix, const char *file, | |
119 | int line, const char *type, | |
120 | const char *left, const char *right, | |
121 | const char *op, const char *m1, size_t l1, | |
122 | const char *m2, size_t l2) | |
123 | { | |
124 | test_fail_string_common(prefix, file, line, type, left, right, op, | |
125 | m1, l1, m2, l2); | |
126 | test_printf_stderr("\n"); | |
127 | } | |
128 | ||
129 | void test_output_string(const char *name, const char *m, size_t l) | |
130 | { | |
131 | test_fail_string_common("string", NULL, 0, NULL, NULL, NULL, name, | |
132 | m, l, m, l); | |
133 | } | |
134 | ||
135 | /* BIGNUM formatted output routines */ | |
136 | ||
137 | /* | |
138 | * A basic memory byte to hex digit converter with allowance for spacing | |
139 | * every so often. | |
140 | */ | |
141 | static void hex_convert_memory(const unsigned char *m, size_t n, char *b, | |
142 | size_t width) | |
143 | { | |
144 | size_t i; | |
145 | ||
146 | for (i = 0; i < n; i++) { | |
147 | const unsigned char c = *m++; | |
148 | ||
149 | *b++ = "0123456789abcdef"[c >> 4]; | |
150 | *b++ = "0123456789abcdef"[c & 15]; | |
151 | if (i % width == width - 1 && i != n - 1) | |
152 | *b++ = ' '; | |
153 | } | |
154 | *b = '\0'; | |
155 | } | |
156 | ||
157 | /* | |
158 | * Constants to define the number of bytes to display per line and the number | |
159 | * of characters these take. | |
160 | */ | |
161 | static const int bn_bytes = (MAX_STRING_WIDTH - 9) / (BN_OUTPUT_SIZE * 2 + 1) | |
162 | * BN_OUTPUT_SIZE; | |
163 | static const int bn_chars = (MAX_STRING_WIDTH - 9) / (BN_OUTPUT_SIZE * 2 + 1) | |
164 | * (BN_OUTPUT_SIZE * 2 + 1) - 1; | |
165 | ||
166 | /* | |
167 | * Output the header line for the bignum | |
168 | */ | |
169 | static void test_bignum_header_line(void) | |
170 | { | |
171 | test_printf_stderr("%*s# %*s\n", subtest_level(), "", bn_chars + 6, | |
172 | "bit position"); | |
173 | } | |
174 | ||
175 | static const char *test_bignum_zero_null(const BIGNUM *bn) | |
176 | { | |
177 | if (bn != NULL) | |
178 | return BN_is_negative(bn) ? "-0" : "0"; | |
179 | return "NULL"; | |
180 | } | |
181 | ||
182 | /* | |
183 | * Print a bignum zero taking care to include the correct sign. | |
184 | * This routine correctly deals with a NULL bignum pointer as input. | |
185 | */ | |
186 | static void test_bignum_zero_print(const BIGNUM *bn, char sep) | |
187 | { | |
188 | const char *v = test_bignum_zero_null(bn); | |
189 | const char *suf = bn != NULL ? ": 0" : ""; | |
190 | ||
191 | test_printf_stderr("%*s# %c%*s%s\n", subtest_level(), "", sep, bn_chars, | |
192 | v, suf); | |
193 | } | |
194 | ||
195 | /* | |
196 | * Convert a section of memory from inside a bignum into a displayable | |
197 | * string with appropriate visual aid spaces inserted. | |
198 | */ | |
199 | static int convert_bn_memory(const unsigned char *in, size_t bytes, | |
200 | char *out, int *lz, const BIGNUM *bn) | |
201 | { | |
202 | int n = bytes * 2, i; | |
203 | char *p = out, *q = NULL; | |
204 | ||
205 | if (bn != NULL && !BN_is_zero(bn)) { | |
206 | hex_convert_memory(in, bytes, out, BN_OUTPUT_SIZE); | |
207 | if (*lz) { | |
208 | for (; *p == '0' || *p == ' '; p++) | |
209 | if (*p == '0') { | |
210 | q = p; | |
211 | *p = ' '; | |
212 | n--; | |
213 | } | |
214 | if (*p == '\0') { | |
215 | /* | |
216 | * in[bytes] is defined because we're converting a non-zero | |
217 | * number and we've not seen a non-zero yet. | |
218 | */ | |
219 | if ((in[bytes] & 0xf0) != 0 && BN_is_negative(bn)) { | |
220 | *lz = 0; | |
221 | *q = '-'; | |
222 | n++; | |
223 | } | |
224 | } else { | |
225 | *lz = 0; | |
226 | if (BN_is_negative(bn)) { | |
227 | /* | |
228 | * This is valid because we always convert more digits than | |
229 | * the number holds. | |
230 | */ | |
231 | *q = '-'; | |
232 | n++; | |
233 | } | |
234 | } | |
235 | } | |
236 | return n; | |
237 | } | |
238 | ||
239 | for (i = 0; i < n; i++) { | |
240 | *p++ = ' '; | |
241 | if (i % (2 * BN_OUTPUT_SIZE) == 2 * BN_OUTPUT_SIZE - 1 && i != n - 1) | |
242 | *p++ = ' '; | |
243 | } | |
244 | *p = '\0'; | |
245 | if (bn == NULL) | |
246 | q = "NULL"; | |
247 | else | |
248 | q = BN_is_negative(bn) ? "-0" : "0"; | |
249 | strcpy(p - strlen(q), q); | |
250 | return 0; | |
251 | } | |
252 | ||
253 | /* | |
254 | * Common code to display either one or two bignums, including the diff | |
255 | * pointers for changes (only when there are two). | |
256 | */ | |
257 | static void test_fail_bignum_common(const char *prefix, const char *file, | |
258 | int line, const char *type, | |
259 | const char *left, const char *right, | |
260 | const char *op, | |
261 | const BIGNUM *bn1, const BIGNUM *bn2) | |
262 | { | |
263 | const int indent = subtest_level(); | |
264 | const size_t bytes = bn_bytes; | |
265 | char b1[MAX_STRING_WIDTH + 1], b2[MAX_STRING_WIDTH + 1]; | |
266 | char *p, bdiff[MAX_STRING_WIDTH + 1]; | |
267 | size_t l1, l2, n1, n2, i, len; | |
268 | unsigned int cnt, diff, real_diff; | |
269 | unsigned char *m1 = NULL, *m2 = NULL; | |
270 | int lz1 = 1, lz2 = 1; | |
271 | unsigned char buffer[MEM_BUFFER_SIZE * 2], *bufp = buffer; | |
272 | ||
273 | test_fail_message_prefix(prefix, file, line, type, left, right, op); | |
274 | l1 = bn1 == NULL ? 0 : (BN_num_bytes(bn1) + (BN_is_negative(bn1) ? 1 : 0)); | |
275 | l2 = bn2 == NULL ? 0 : (BN_num_bytes(bn2) + (BN_is_negative(bn2) ? 1 : 0)); | |
276 | if (l1 == 0 && l2 == 0) { | |
277 | if ((bn1 == NULL) == (bn2 == NULL)) { | |
278 | test_bignum_header_line(); | |
279 | test_bignum_zero_print(bn1, ' '); | |
280 | } else { | |
281 | test_diff_header(left, right); | |
282 | test_bignum_header_line(); | |
283 | test_bignum_zero_print(bn1, '-'); | |
284 | test_bignum_zero_print(bn2, '+'); | |
285 | } | |
286 | goto fin; | |
287 | } | |
288 | ||
289 | if (l1 != l2 || bn1 == NULL || bn2 == NULL || BN_cmp(bn1, bn2) != 0) | |
290 | test_diff_header(left, right); | |
291 | test_bignum_header_line(); | |
292 | ||
293 | len = ((l1 > l2 ? l1 : l2) + bytes - 1) / bytes * bytes; | |
294 | ||
295 | if (len > MEM_BUFFER_SIZE && (bufp = OPENSSL_malloc(len * 2)) == NULL) { | |
296 | bufp = buffer; | |
297 | len = MEM_BUFFER_SIZE; | |
298 | test_printf_stderr("%*s# WARNING: these BIGNUMs have been truncated", | |
299 | indent, ""); | |
300 | } | |
301 | ||
302 | if (bn1 != NULL) { | |
303 | m1 = bufp; | |
304 | BN_bn2binpad(bn1, m1, len); | |
305 | } | |
306 | if (bn2 != NULL) { | |
307 | m2 = bufp + len; | |
308 | BN_bn2binpad(bn2, m2, len); | |
309 | } | |
310 | ||
311 | while (len > 0) { | |
312 | cnt = 8 * (len - bytes); | |
313 | n1 = convert_bn_memory(m1, bytes, b1, &lz1, bn1); | |
314 | n2 = convert_bn_memory(m2, bytes, b2, &lz2, bn2); | |
315 | ||
316 | diff = real_diff = 0; | |
317 | i = 0; | |
318 | p = bdiff; | |
319 | for (i=0; b1[i] != '\0'; i++) | |
320 | if (b1[i] == b2[i] || b1[i] == ' ' || b2[i] == ' ') { | |
321 | *p++ = ' '; | |
322 | diff |= b1[i] != b2[i]; | |
323 | } else { | |
324 | *p++ = '^'; | |
325 | real_diff = diff = 1; | |
326 | } | |
327 | *p++ = '\0'; | |
328 | if (!diff) { | |
329 | test_printf_stderr("%*s# %s:% 5d\n", indent, "", | |
330 | n2 > n1 ? b2 : b1, cnt); | |
331 | } else { | |
332 | if (cnt == 0 && bn1 == NULL) | |
333 | test_printf_stderr("%*s# -%s\n", indent, "", b1); | |
334 | else if (cnt == 0 || n1 > 0) | |
335 | test_printf_stderr("%*s# -%s:% 5d\n", indent, "", b1, cnt); | |
336 | if (cnt == 0 && bn2 == NULL) | |
337 | test_printf_stderr("%*s# +%s\n", indent, "", b2); | |
338 | else if (cnt == 0 || n2 > 0) | |
339 | test_printf_stderr("%*s# +%s:% 5d\n", indent, "", b2, cnt); | |
340 | if (real_diff && (cnt == 0 || (n1 > 0 && n2 > 0)) | |
341 | && bn1 != NULL && bn2 != NULL) | |
342 | test_printf_stderr("%*s# %s\n", indent, "", bdiff); | |
343 | } | |
344 | if (m1 != NULL) | |
345 | m1 += bytes; | |
346 | if (m2 != NULL) | |
347 | m2 += bytes; | |
348 | len -= bytes; | |
349 | } | |
350 | fin: | |
351 | test_flush_stderr(); | |
352 | if (bufp != buffer) | |
353 | OPENSSL_free(bufp); | |
354 | } | |
355 | ||
356 | /* | |
357 | * Wrapper routines so that the underlying code can be shared. | |
358 | * The first two are calls from inside the test utilities when a conditional | |
359 | * fails. The third is the user's call to dump a bignum. | |
360 | */ | |
361 | void test_fail_bignum_message(const char *prefix, const char *file, | |
362 | int line, const char *type, | |
363 | const char *left, const char *right, | |
364 | const char *op, | |
365 | const BIGNUM *bn1, const BIGNUM *bn2) | |
366 | { | |
367 | test_fail_bignum_common(prefix, file, line, type, left, right, op, bn1, bn2); | |
368 | test_printf_stderr("\n"); | |
369 | } | |
370 | ||
371 | void test_fail_bignum_mono_message(const char *prefix, const char *file, | |
372 | int line, const char *type, | |
373 | const char *left, const char *right, | |
374 | const char *op, const BIGNUM *bn) | |
375 | { | |
376 | test_fail_bignum_common(prefix, file, line, type, left, right, op, bn, bn); | |
377 | test_printf_stderr("\n"); | |
378 | } | |
379 | ||
380 | void test_output_bignum(const char *name, const BIGNUM *bn) | |
381 | { | |
382 | if (bn == NULL || BN_is_zero(bn)) { | |
383 | test_printf_stderr("%*s# bignum: '%s' = %s\n", subtest_level(), "", | |
384 | name, test_bignum_zero_null(bn)); | |
385 | } else if (BN_num_bytes(bn) <= BN_OUTPUT_SIZE) { | |
386 | unsigned char buf[BN_OUTPUT_SIZE]; | |
387 | char out[2 * sizeof(buf) + 1]; | |
388 | char *p = out; | |
389 | int n = BN_bn2bin(bn, buf); | |
390 | ||
391 | hex_convert_memory(buf, n, p, BN_OUTPUT_SIZE); | |
392 | while (*p == '0' && *++p != '\0') | |
393 | ; | |
394 | test_printf_stderr("%*s# bignum: '%s' = %s0x%s\n", subtest_level(), "", | |
395 | name, BN_is_negative(bn) ? "-" : "", p); | |
396 | } else { | |
397 | test_fail_bignum_common("bignum", NULL, 0, NULL, NULL, NULL, name, | |
398 | bn, bn); | |
399 | } | |
400 | } | |
401 | ||
402 | /* Memory output routines */ | |
403 | ||
404 | /* | |
405 | * Handle zero length blocks of memory or NULL pointers to memory | |
406 | */ | |
407 | static void test_memory_null_empty(const unsigned char *m, int indent, char c) | |
408 | { | |
409 | if (m == NULL) | |
410 | test_printf_stderr("%*s# % 4s %c%s\n", indent, "", "", c, "NULL"); | |
411 | else | |
412 | test_printf_stderr("%*s# %04x %c%s\n", indent, "", 0u, c, "empty"); | |
413 | } | |
414 | ||
415 | /* | |
416 | * Common code to display one or two blocks of memory. | |
417 | */ | |
418 | static void test_fail_memory_common(const char *prefix, const char *file, | |
419 | int line, const char *type, | |
420 | const char *left, const char *right, | |
421 | const char *op, | |
422 | const unsigned char *m1, size_t l1, | |
423 | const unsigned char *m2, size_t l2) | |
424 | { | |
425 | const int indent = subtest_level(); | |
426 | const size_t bytes = (MAX_STRING_WIDTH - 9) / 17 * 8; | |
427 | char b1[MAX_STRING_WIDTH + 1], b2[MAX_STRING_WIDTH + 1]; | |
428 | char *p, bdiff[MAX_STRING_WIDTH + 1]; | |
429 | size_t n1, n2, i; | |
430 | unsigned int cnt = 0, diff; | |
431 | ||
432 | test_fail_message_prefix(prefix, file, line, type, left, right, op); | |
433 | if (m1 == NULL) | |
434 | l1 = 0; | |
435 | if (m2 == NULL) | |
436 | l2 = 0; | |
437 | if (l1 == 0 && l2 == 0) { | |
438 | if ((m1 == NULL) == (m2 == NULL)) { | |
439 | test_memory_null_empty(m1, indent, ' '); | |
440 | } else { | |
441 | test_diff_header(left, right); | |
442 | test_memory_null_empty(m1, indent, '-'); | |
443 | test_memory_null_empty(m2, indent, '+'); | |
444 | } | |
445 | goto fin; | |
446 | } | |
447 | ||
448 | if (l1 != l2 || (m1 != m2 && memcmp(m1, m2, l1) != 0)) | |
449 | test_diff_header(left, right); | |
450 | ||
451 | while (l1 > 0 || l2 > 0) { | |
452 | n1 = n2 = 0; | |
453 | if (l1 > 0) { | |
454 | n1 = l1 > bytes ? bytes : l1; | |
455 | hex_convert_memory(m1, n1, b1, 8); | |
456 | } | |
457 | if (l2 > 0) { | |
458 | n2 = l2 > bytes ? bytes : l2; | |
459 | hex_convert_memory(m2, n2, b2, 8); | |
460 | } | |
461 | ||
462 | diff = 0; | |
463 | i = 0; | |
464 | p = bdiff; | |
465 | if (n1 > 0 && n2 > 0) { | |
466 | const size_t j = n1 < n2 ? n1 : n2; | |
467 | ||
468 | for (; i < j; i++) { | |
469 | if (m1[i] == m2[i]) { | |
470 | *p++ = ' '; | |
471 | *p++ = ' '; | |
472 | } else { | |
473 | *p++ = '^'; | |
474 | *p++ = '^'; | |
475 | diff = 1; | |
476 | } | |
477 | if (i % 8 == 7 && i != j - 1) | |
478 | *p++ = ' '; | |
479 | } | |
480 | *p++ = '\0'; | |
481 | } | |
482 | ||
483 | if (n1 == n2 && !diff) { | |
484 | test_printf_stderr("%*s# %04x: %s\n", indent, "", cnt, b1); | |
485 | } else { | |
486 | if (cnt == 0 && (m1 == NULL || l1 == 0)) | |
487 | test_memory_null_empty(m1, indent, '-'); | |
488 | else if (n1 > 0) | |
489 | test_printf_stderr("%*s# %04x:-%s\n", indent, "", cnt, b1); | |
490 | if (cnt == 0 && (m2 == NULL || l2 == 0)) | |
491 | test_memory_null_empty(m2, indent, '+'); | |
492 | else if (n2 > 0) | |
493 | test_printf_stderr("%*s# %04x:+%s\n", indent, "", cnt, b2); | |
494 | if (diff && i > 0) | |
495 | test_printf_stderr("%*s# % 4s %s\n", indent, "", "", bdiff); | |
496 | } | |
497 | m1 += n1; | |
498 | m2 += n2; | |
499 | l1 -= n1; | |
500 | l2 -= n2; | |
501 | cnt += bytes; | |
502 | } | |
503 | fin: | |
504 | test_flush_stderr(); | |
505 | } | |
506 | ||
507 | /* | |
508 | * Wrapper routines so that the underlying code can be shared. | |
509 | * The first is the call from inside the test utilities when a conditional | |
510 | * fails. The second is the user's call to dump memory. | |
511 | */ | |
512 | void test_fail_memory_message(const char *prefix, const char *file, | |
513 | int line, const char *type, | |
514 | const char *left, const char *right, | |
515 | const char *op, | |
516 | const unsigned char *m1, size_t l1, | |
517 | const unsigned char *m2, size_t l2) | |
518 | { | |
519 | test_fail_memory_common(prefix, file, line, type, left, right, op, | |
520 | m1, l1, m2, l2); | |
521 | test_printf_stderr("\n"); | |
522 | } | |
523 | ||
524 | void test_output_memory(const char *name, const unsigned char *m, size_t l) | |
525 | { | |
526 | test_fail_memory_common("memory", NULL, 0, NULL, NULL, NULL, name, | |
527 | m, l, m, l); | |
528 | } |