Line data Source code
1 : /* t-convert.c - Tests for mpi print and scna functions
2 : * Copyright (C) 2013 g10 Code GmbH
3 : *
4 : * This file is part of Libgcrypt.
5 : *
6 : * Libgcrypt is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * Libgcrypt is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #ifdef HAVE_CONFIG_H
21 : # include <config.h>
22 : #endif
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <assert.h>
27 : #include <stdarg.h>
28 :
29 : #include "../src/gcrypt-int.h"
30 :
31 : #define PGM "t-convert"
32 :
33 : #define DIM(v) (sizeof(v)/sizeof((v)[0]))
34 : #define DIMof(type,member) DIM(((type *)0)->member)
35 :
36 : static const char *wherestr;
37 : static int verbose;
38 : static int debug;
39 : static int error_count;
40 :
41 :
42 : #define xmalloc(a) gcry_xmalloc ((a))
43 : #define xcalloc(a,b) gcry_xcalloc ((a),(b))
44 : #define xfree(a) gcry_free ((a))
45 : #define pass() do { ; } while (0)
46 :
47 : static void
48 1 : show (const char *format, ...)
49 : {
50 : va_list arg_ptr;
51 :
52 1 : if (!verbose)
53 2 : return;
54 0 : fprintf (stderr, "%s: ", PGM);
55 0 : va_start (arg_ptr, format);
56 0 : vfprintf (stderr, format, arg_ptr);
57 0 : va_end (arg_ptr);
58 : }
59 :
60 : static void
61 0 : showhex (const char *prefix, const void *buffer, size_t buflen)
62 : {
63 : const unsigned char *s;
64 :
65 0 : if (!verbose)
66 0 : return;
67 0 : fprintf (stderr, "%s: %s ", PGM, prefix);
68 0 : for (s= buffer; buflen; buflen--, s++)
69 0 : fprintf (stderr, "%02x", *s);
70 0 : putc ('\n', stderr);
71 : }
72 :
73 :
74 : /* Allocate a bit string consisting of '0' and '1' from the MPI A. Do
75 : not return any leading zero bits. Caller needs to gcry_free the
76 : result. */
77 : static char *
78 0 : mpi2bitstr_nlz (gcry_mpi_t a)
79 : {
80 : char *p, *buf;
81 0 : size_t length = gcry_mpi_get_nbits (a);
82 :
83 0 : if (!length)
84 : {
85 0 : buf = p = xmalloc (3);
86 0 : *p++ = ' ';
87 0 : *p++ = '0';
88 : }
89 : else
90 : {
91 0 : buf = p = xmalloc (length + 1 + 1);
92 0 : *p++ = gcry_mpi_is_neg (a)? '-':' ';
93 0 : while (length-- > 1)
94 0 : *p++ = gcry_mpi_test_bit (a, length) ? '1':'0';
95 0 : *p++ = gcry_mpi_test_bit (a, 0) ? '1':'0';
96 : }
97 0 : *p = 0;
98 0 : return buf;
99 : }
100 :
101 :
102 : static void
103 0 : showmpi (const char *prefix, gcry_mpi_t a)
104 : {
105 : char *bitstr;
106 :
107 0 : if (!verbose)
108 0 : return;
109 0 : bitstr = mpi2bitstr_nlz (a);
110 0 : fprintf (stderr, "%s: %s%s\n", PGM, prefix, bitstr);
111 0 : xfree (bitstr);
112 : }
113 :
114 :
115 : static void
116 0 : fail (const char *format, ...)
117 : {
118 : va_list arg_ptr;
119 :
120 0 : fflush (stdout);
121 0 : fprintf (stderr, "%s: ", PGM);
122 0 : if (wherestr)
123 0 : fprintf (stderr, "%s: ", wherestr);
124 0 : va_start (arg_ptr, format);
125 0 : vfprintf (stderr, format, arg_ptr);
126 0 : va_end (arg_ptr);
127 0 : error_count++;
128 0 : }
129 :
130 : static void
131 0 : die (const char *format, ...)
132 : {
133 : va_list arg_ptr;
134 :
135 0 : fflush (stdout);
136 0 : fprintf (stderr, "%s: ", PGM);
137 0 : if (wherestr)
138 0 : fprintf (stderr, "%s: ", wherestr);
139 0 : va_start (arg_ptr, format);
140 0 : vfprintf (stderr, format, arg_ptr);
141 0 : va_end (arg_ptr);
142 0 : exit (1);
143 : }
144 :
145 :
146 : /* Check that mpi_print does not return a negative zero. */
147 : static void
148 1 : negative_zero (void)
149 : {
150 : gpg_error_t err;
151 : gcry_mpi_t a;
152 : char *buf;
153 1 : void *bufaddr = &buf;
154 1 : struct { const char *name; enum gcry_mpi_format format; } fmts[] =
155 : {
156 : { "STD", GCRYMPI_FMT_STD },
157 : { "PGP", GCRYMPI_FMT_PGP },
158 : { "SSH", GCRYMPI_FMT_SSH },
159 : { "HEX", GCRYMPI_FMT_HEX },
160 : { "USG", GCRYMPI_FMT_USG },
161 : { NULL, 0 }
162 : };
163 : int i;
164 :
165 1 : if (debug)
166 0 : show ("negative zero printing\n");
167 :
168 1 : a = gcry_mpi_new (0);
169 6 : for (i=0; fmts[i].name; i++)
170 : {
171 5 : err = gcry_mpi_aprint (fmts[i].format, bufaddr, NULL, a);
172 5 : if (err)
173 0 : fail ("error printing a zero as %s: %s\n",
174 : fmts[i].name,gpg_strerror (err) );
175 : else
176 5 : gcry_free (buf);
177 : }
178 :
179 : /* With the current version of libgcrypt the next two statements
180 : should set a to -0. */
181 1 : gcry_mpi_sub_ui (a, a, 1);
182 1 : gcry_mpi_add_ui (a, a, 1);
183 :
184 6 : for (i=0; fmts[i].name; i++)
185 : {
186 5 : err = gcry_mpi_aprint (fmts[i].format, bufaddr, NULL, a);
187 5 : if (err)
188 0 : fail ("error printing a negative zero as %s: %s\n",
189 : fmts[i].name,gpg_strerror (err) );
190 : else
191 5 : gcry_free (buf);
192 : }
193 :
194 1 : gcry_mpi_release (a);
195 1 : }
196 :
197 :
198 : static void
199 1 : check_formats (void)
200 : {
201 : static struct {
202 : int value;
203 : struct {
204 : const char *hex;
205 : size_t stdlen;
206 : const char *std;
207 : size_t sshlen;
208 : const char *ssh;
209 : size_t usglen;
210 : const char *usg;
211 : size_t pgplen;
212 : const char *pgp;
213 : } a;
214 : } data[] = {
215 : { 0, { "00",
216 : 0, "",
217 : 4, "\x00\x00\x00\x00",
218 : 0, "",
219 : 2, "\x00\x00"}
220 : },
221 : { 1, { "01",
222 : 1, "\x01",
223 : 5, "\x00\x00\x00\x01\x01",
224 : 1, "\x01",
225 : 3, "\x00\x01\x01" }
226 : },
227 : { 2, { "02",
228 : 1, "\x02",
229 : 5, "\x00\x00\x00\x01\x02",
230 : 1, "\x02",
231 : 3, "\x00\x02\x02" }
232 : },
233 : { 127, { "7F",
234 : 1, "\x7f",
235 : 5, "\x00\x00\x00\x01\x7f",
236 : 1, "\x7f",
237 : 3, "\x00\x07\x7f" }
238 : },
239 : { 128, { "0080",
240 : 2, "\x00\x80",
241 : 6, "\x00\x00\x00\x02\x00\x80",
242 : 1, "\x80",
243 : 3, "\x00\x08\x80" }
244 : },
245 : { 129, { "0081",
246 : 2, "\x00\x81",
247 : 6, "\x00\x00\x00\x02\x00\x81",
248 : 1, "\x81",
249 : 3, "\x00\x08\x81" }
250 : },
251 : { 255, { "00FF",
252 : 2, "\x00\xff",
253 : 6, "\x00\x00\x00\x02\x00\xff",
254 : 1, "\xff",
255 : 3, "\x00\x08\xff" }
256 : },
257 : { 256, { "0100",
258 : 2, "\x01\x00",
259 : 6, "\x00\x00\x00\x02\x01\x00",
260 : 2, "\x01\x00",
261 : 4, "\x00\x09\x01\x00" }
262 : },
263 : { 257, { "0101",
264 : 2, "\x01\x01",
265 : 6, "\x00\x00\x00\x02\x01\x01",
266 : 2, "\x01\x01",
267 : 4, "\x00\x09\x01\x01" }
268 : },
269 : { -1, { "-01",
270 : 1, "\xff",
271 : 5, "\x00\x00\x00\x01\xff",
272 : 1,"\x01" }
273 : },
274 : { -2, { "-02",
275 : 1, "\xfe",
276 : 5, "\x00\x00\x00\x01\xfe",
277 : 1, "\x02" }
278 : },
279 : { -127, { "-7F",
280 : 1, "\x81",
281 : 5, "\x00\x00\x00\x01\x81",
282 : 1, "\x7f" }
283 : },
284 : { -128, { "-0080",
285 : 1, "\x80",
286 : 5, "\x00\x00\x00\x01\x80",
287 : 1, "\x80" }
288 : },
289 : { -129, { "-0081",
290 : 2, "\xff\x7f",
291 : 6, "\x00\x00\x00\x02\xff\x7f",
292 : 1, "\x81" }
293 : },
294 : { -255, { "-00FF",
295 : 2, "\xff\x01",
296 : 6, "\x00\x00\x00\x02\xff\x01",
297 : 1, "\xff" }
298 : },
299 : { -256, { "-0100",
300 : 2, "\xff\x00",
301 : 6, "\x00\x00\x00\x02\xff\x00",
302 : 2, "\x01\x00" }
303 : },
304 : { -257, { "-0101",
305 : 2, "\xfe\xff",
306 : 6, "\x00\x00\x00\x02\xfe\xff",
307 : 2, "\x01\x01" }
308 : },
309 : { 65535, { "00FFFF",
310 : 3, "\x00\xff\xff",
311 : 7, "\x00\x00\x00\x03\x00\xff\xff",
312 : 2, "\xff\xff",
313 : 4, "\x00\x10\xff\xff" }
314 : },
315 : { 65536, { "010000",
316 : 3, "\x01\00\x00",
317 : 7, "\x00\x00\x00\x03\x01\x00\x00",
318 : 3, "\x01\x00\x00",
319 : 5, "\x00\x11\x01\x00\x00 "}
320 : },
321 : { 65537, { "010001",
322 : 3, "\x01\00\x01",
323 : 7, "\x00\x00\x00\x03\x01\x00\x01",
324 : 3, "\x01\x00\x01",
325 : 5, "\x00\x11\x01\x00\x01" }
326 : },
327 : { -65537, { "-010001",
328 : 3, "\xfe\xff\xff",
329 : 7, "\x00\x00\x00\x03\xfe\xff\xff",
330 : 3, "\x01\x00\x01" }
331 : },
332 : { -65536, { "-010000",
333 : 3, "\xff\x00\x00",
334 : 7, "\x00\x00\x00\x03\xff\x00\x00",
335 : 3, "\x01\x00\x00" }
336 : },
337 : { -65535, { "-00FFFF",
338 : 3, "\xff\x00\x01",
339 : 7, "\x00\x00\x00\x03\xff\x00\x01",
340 : 2, "\xff\xff" }
341 : }
342 : };
343 : gpg_error_t err;
344 : gcry_mpi_t a, b;
345 : char *buf;
346 1 : void *bufaddr = &buf;
347 : int idx;
348 : size_t buflen;
349 :
350 1 : a = gcry_mpi_new (0);
351 24 : for (idx=0; idx < DIM(data); idx++)
352 : {
353 23 : if (debug)
354 0 : show ("print test %d\n", data[idx].value);
355 :
356 23 : if (data[idx].value < 0)
357 : {
358 11 : gcry_mpi_set_ui (a, -data[idx].value);
359 11 : gcry_mpi_neg (a, a);
360 : }
361 : else
362 12 : gcry_mpi_set_ui (a, data[idx].value);
363 :
364 23 : err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
365 23 : if (err)
366 0 : fail ("error printing value %d as %s: %s\n",
367 : data[idx].value, "HEX", gpg_strerror (err));
368 : else
369 : {
370 23 : if (strcmp (buf, data[idx].a.hex))
371 : {
372 0 : fail ("error printing value %d as %s: %s\n",
373 : data[idx].value, "HEX", "wrong result");
374 0 : show ("expected: '%s'\n", data[idx].a.hex);
375 0 : show (" got: '%s'\n", buf);
376 : }
377 23 : gcry_free (buf);
378 : }
379 :
380 23 : err = gcry_mpi_aprint (GCRYMPI_FMT_STD, bufaddr, &buflen, a);
381 23 : if (err)
382 0 : fail ("error printing value %d as %s: %s\n",
383 : data[idx].value, "STD", gpg_strerror (err));
384 : else
385 : {
386 23 : if (buflen != data[idx].a.stdlen
387 23 : || memcmp (buf, data[idx].a.std, data[idx].a.stdlen))
388 : {
389 0 : fail ("error printing value %d as %s: %s\n",
390 : data[idx].value, "STD", "wrong result");
391 0 : showhex ("expected:", data[idx].a.std, data[idx].a.stdlen);
392 0 : showhex (" got:", buf, buflen);
393 : }
394 23 : gcry_free (buf);
395 : }
396 :
397 23 : err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, bufaddr, &buflen, a);
398 23 : if (err)
399 0 : fail ("error printing value %d as %s: %s\n",
400 : data[idx].value, "SSH", gpg_strerror (err));
401 : else
402 : {
403 23 : if (buflen != data[idx].a.sshlen
404 23 : || memcmp (buf, data[idx].a.ssh, data[idx].a.sshlen))
405 : {
406 0 : fail ("error printing value %d as %s: %s\n",
407 : data[idx].value, "SSH", "wrong result");
408 0 : showhex ("expected:", data[idx].a.ssh, data[idx].a.sshlen);
409 0 : showhex (" got:", buf, buflen);
410 : }
411 23 : gcry_free (buf);
412 : }
413 :
414 23 : err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufaddr, &buflen, a);
415 23 : if (err)
416 0 : fail ("error printing value %d as %s: %s\n",
417 : data[idx].value, "USG", gpg_strerror (err));
418 : else
419 : {
420 23 : if (buflen != data[idx].a.usglen
421 23 : || memcmp (buf, data[idx].a.usg, data[idx].a.usglen))
422 : {
423 0 : fail ("error printing value %d as %s: %s\n",
424 : data[idx].value, "USG", "wrong result");
425 0 : showhex ("expected:", data[idx].a.usg, data[idx].a.usglen);
426 0 : showhex (" got:", buf, buflen);
427 : }
428 23 : gcry_free (buf);
429 : }
430 :
431 23 : err = gcry_mpi_aprint (GCRYMPI_FMT_PGP, bufaddr, &buflen, a);
432 23 : if (gcry_mpi_is_neg (a))
433 : {
434 11 : if (gpg_err_code (err) != GPG_ERR_INV_ARG)
435 0 : fail ("error printing value %d as %s: %s\n",
436 : data[idx].value, "PGP", "Expected error not returned");
437 : }
438 12 : else if (err)
439 0 : fail ("error printing value %d as %s: %s\n",
440 : data[idx].value, "PGP", gpg_strerror (err));
441 : else
442 : {
443 12 : if (buflen != data[idx].a.pgplen
444 12 : || memcmp (buf, data[idx].a.pgp, data[idx].a.pgplen))
445 : {
446 0 : fail ("error printing value %d as %s: %s\n",
447 : data[idx].value, "PGP", "wrong result");
448 0 : showhex ("expected:", data[idx].a.pgp, data[idx].a.pgplen);
449 0 : showhex (" got:", buf, buflen);
450 : }
451 12 : gcry_free (buf);
452 : }
453 : }
454 :
455 :
456 : /* Now for the other direction. */
457 24 : for (idx=0; idx < DIM(data); idx++)
458 : {
459 23 : if (debug)
460 0 : show ("scan test %d\n", data[idx].value);
461 :
462 23 : if (data[idx].value < 0)
463 : {
464 11 : gcry_mpi_set_ui (a, -data[idx].value);
465 11 : gcry_mpi_neg (a, a);
466 : }
467 : else
468 12 : gcry_mpi_set_ui (a, data[idx].value);
469 :
470 23 : err = gcry_mpi_scan (&b, GCRYMPI_FMT_HEX, data[idx].a.hex, 0, &buflen);
471 23 : if (err)
472 0 : fail ("error scanning value %d from %s: %s\n",
473 : data[idx].value, "HEX", gpg_strerror (err));
474 : else
475 : {
476 23 : if (gcry_mpi_cmp (a, b))
477 : {
478 0 : fail ("error scanning value %d from %s: %s\n",
479 : data[idx].value, "HEX", "wrong result");
480 0 : showmpi ("expected:", a);
481 0 : showmpi (" got:", b);
482 : }
483 23 : gcry_mpi_release (b);
484 : }
485 :
486 46 : err = gcry_mpi_scan (&b, GCRYMPI_FMT_STD,
487 23 : data[idx].a.std, data[idx].a.stdlen, &buflen);
488 23 : if (err)
489 0 : fail ("error scanning value %d as %s: %s\n",
490 : data[idx].value, "STD", gpg_strerror (err));
491 : else
492 : {
493 23 : if (gcry_mpi_cmp (a, b) || data[idx].a.stdlen != buflen)
494 : {
495 0 : fail ("error scanning value %d from %s: %s (%u)\n",
496 : data[idx].value, "STD", "wrong result", buflen);
497 0 : showmpi ("expected:", a);
498 0 : showmpi (" got:", b);
499 : }
500 23 : gcry_mpi_release (b);
501 : }
502 :
503 46 : err = gcry_mpi_scan (&b, GCRYMPI_FMT_SSH,
504 23 : data[idx].a.ssh, data[idx].a.sshlen, &buflen);
505 23 : if (err)
506 0 : fail ("error scanning value %d as %s: %s\n",
507 : data[idx].value, "SSH", gpg_strerror (err));
508 : else
509 : {
510 23 : if (gcry_mpi_cmp (a, b) || data[idx].a.sshlen != buflen)
511 : {
512 0 : fail ("error scanning value %d from %s: %s (%u)\n",
513 : data[idx].value, "SSH", "wrong result", buflen);
514 0 : showmpi ("expected:", a);
515 0 : showmpi (" got:", b);
516 : }
517 23 : gcry_mpi_release (b);
518 : }
519 :
520 46 : err = gcry_mpi_scan (&b, GCRYMPI_FMT_USG,
521 23 : data[idx].a.usg, data[idx].a.usglen, &buflen);
522 23 : if (err)
523 0 : fail ("error scanning value %d as %s: %s\n",
524 : data[idx].value, "USG", gpg_strerror (err));
525 : else
526 : {
527 23 : if (gcry_mpi_is_neg (a))
528 11 : gcry_mpi_neg (b, b);
529 23 : if (gcry_mpi_cmp (a, b) || data[idx].a.usglen != buflen)
530 : {
531 0 : fail ("error scanning value %d from %s: %s (%u)\n",
532 : data[idx].value, "USG", "wrong result", buflen);
533 0 : showmpi ("expected:", a);
534 0 : showmpi (" got:", b);
535 : }
536 23 : gcry_mpi_release (b);
537 : }
538 :
539 : /* Negative values are not supported by PGP, thus we don't have
540 : an samples. */
541 23 : if (!gcry_mpi_is_neg (a))
542 : {
543 24 : err = gcry_mpi_scan (&b, GCRYMPI_FMT_PGP,
544 12 : data[idx].a.pgp, data[idx].a.pgplen, &buflen);
545 12 : if (err)
546 0 : fail ("error scanning value %d as %s: %s\n",
547 : data[idx].value, "PGP", gpg_strerror (err));
548 : else
549 : {
550 12 : if (gcry_mpi_cmp (a, b) || data[idx].a.pgplen != buflen)
551 : {
552 0 : fail ("error scanning value %d from %s: %s (%u)\n",
553 : data[idx].value, "PGP", "wrong result", buflen);
554 0 : showmpi ("expected:", a);
555 0 : showmpi (" got:", b);
556 : }
557 12 : gcry_mpi_release (b);
558 : }
559 : }
560 : }
561 :
562 1 : gcry_mpi_release (a);
563 1 : }
564 :
565 :
566 : int
567 1 : main (int argc, char **argv)
568 : {
569 1 : if (argc > 1 && !strcmp (argv[1], "--verbose"))
570 0 : verbose = 1;
571 1 : else if (argc > 1 && !strcmp (argv[1], "--debug"))
572 0 : verbose = debug = 1;
573 :
574 1 : if (!gcry_check_version (GCRYPT_VERSION))
575 0 : die ("version mismatch\n");
576 :
577 1 : gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
578 1 : gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
579 1 : if (debug)
580 0 : gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
581 1 : gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
582 :
583 1 : negative_zero ();
584 1 : check_formats ();
585 :
586 1 : show ("All tests completed. Errors: %d\n", error_count);
587 1 : return error_count ? 1 : 0;
588 : }
|