ecc: fix memory leak.
[libgcrypt.git] / tests / fipsrngdrv.c
1 /* fipsrngdrv.c  -  A driver to test the FIPS RNG.
2    Copyright (C) 2008 Free Software Foundation, Inc.
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 <stdarg.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #ifndef HAVE_W32_SYSTEM
30 # include <signal.h>
31 #endif
32
33 #include <gcrypt.h>
34
35 #define PGM "fipsrngdrv"
36
37 #define my_isascii(c) (!((c) & 0x80))
38 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
39 #define hexdigitp(a) (digitp (a)                     \
40                       || (*(a) >= 'A' && *(a) <= 'F')  \
41                       || (*(a) >= 'a' && *(a) <= 'f'))
42 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
43                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
44 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
45
46
47 static void
48 die (const char *format, ...)
49 {
50   va_list arg_ptr;
51
52   va_start (arg_ptr, format);
53   fputs (PGM ": ", stderr);
54   vfprintf (stderr, format, arg_ptr);
55   va_end (arg_ptr);
56   exit (1);
57 }
58
59
60 /* Convert STRING consisting of hex characters into its binary
61    representation and store that at BUFFER.  BUFFER needs to be of
62    LENGTH bytes.  The function checks that the STRING will convert
63    exactly to LENGTH bytes. The string is delimited by either end of
64    string or a white space character.  The function returns -1 on
65    error or the length of the parsed string.  */
66 static int
67 hex2bin (const char *string, void *buffer, size_t length)
68 {
69   int i;
70   const char *s = string;
71
72   for (i=0; i < length; )
73     {
74       if (!hexdigitp (s) || !hexdigitp (s+1))
75         return -1;           /* Invalid hex digits. */
76       ((unsigned char*)buffer)[i++] = xtoi_2 (s);
77       s += 2;
78     }
79   if (*s && (!my_isascii (*s) || !isspace (*s)) )
80     return -1;             /* Not followed by Nul or white space.  */
81   if (i != length)
82     return -1;             /* Not of expected length.  */
83   if (*s)
84     s++; /* Skip the delimiter. */
85   return s - string;
86 }
87
88
89
90
91 static gcry_error_t
92 init_external_test (void **r_context,
93                     unsigned int flags,
94                     const void *key, size_t keylen,
95                     const void *seed, size_t seedlen,
96                     const void *dt, size_t dtlen)
97 {
98   return gcry_control (58,
99                        r_context, flags,
100                        key, keylen,
101                        seed, seedlen,
102                        dt, dtlen);
103 }
104
105 static gcry_error_t
106 run_external_test (void *context, void *buffer, size_t buflen)
107 {
108   return gcry_control (59, context, buffer, buflen);
109 }
110
111 static void
112 deinit_external_test (void *context)
113 {
114   gcry_control (60, context);
115 }
116
117
118 static void
119 print_buffer (const unsigned char *buffer, size_t length)
120 {
121   while (length--)
122     printf ("%02X", *buffer++);
123 }
124
125
126 int
127 main (int argc, char **argv)
128 {
129   int last_argc = -1;
130   int verbose = 0;
131   int binary = 0;
132   int loop = 0;
133   int progress = 0;
134   int no_fips = 0;
135   unsigned char key[16];
136   unsigned char seed[16];
137   unsigned char dt[16];
138   void *context;
139   gpg_error_t err;
140   unsigned char buffer[16];
141
142   if (argc)
143     { argc--; argv++; }
144
145   while (argc && last_argc != argc )
146     {
147       last_argc = argc;
148       if (!strcmp (*argv, "--"))
149         {
150           argc--; argv++;
151           break;
152         }
153       else if (!strcmp (*argv, "--help"))
154         {
155           fputs ("usage: " PGM
156                  " [--verbose] [--binary] [--loop] [--progress] KEY V DT\n",
157                  stdout);
158           exit (0);
159         }
160       else if (!strcmp (*argv, "--verbose"))
161         {
162           verbose++;
163           argc--; argv++;
164         }
165       else if (!strcmp (*argv, "--no-fips"))
166         {
167           no_fips++;
168           argc--; argv++;
169         }
170       else if (!strcmp (*argv, "--binary"))
171         {
172           binary = 1;
173           argc--; argv++;
174         }
175       else if (!strcmp (*argv, "--loop"))
176         {
177           loop = 1;
178           argc--; argv++;
179         }
180       else if (!strcmp (*argv, "--progress"))
181         {
182           progress = 1;
183           argc--; argv++;
184         }
185     }
186
187   if (!argc)
188     {
189       memcpy (key,  "1234567890123456", 16);
190       memcpy (seed, "abcdefghijklmnop", 16);
191       memcpy (dt,   "XXXXXXXXXXXXXXXX", 16);
192     }
193   else if (argc == 3)
194     {
195       if (    hex2bin (argv[0], key, 16) < 0
196            || hex2bin (argv[1], seed, 16) < 0
197            || hex2bin (argv[2], dt, 16) < 0 )
198         die ("args are not 32 hex digits each\n");
199     }
200   else
201     die ("invalid usage (try --help)\n");
202
203 #ifndef HAVE_W32_SYSTEM
204   if (loop)
205     signal (SIGPIPE, SIG_IGN);
206 #endif
207
208   if (verbose)
209     fputs (PGM ": started\n", stderr);
210
211   gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
212   if (!no_fips)
213     gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
214   if (!gcry_check_version ("1.4.3"))
215     die ("version mismatch\n");
216   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
217   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
218
219   /* The flag value 1 disables the dup check, so that the RNG returns
220      all generated data.  */
221   err = init_external_test (&context, 1, key, 16, seed, 16, dt, 16);
222   if (err)
223     die ("init external test failed: %s\n", gpg_strerror (err));
224
225   do
226     {
227       int writerr = 0;
228
229       err = run_external_test (context, buffer, sizeof buffer);
230       if (err)
231         die ("run external test failed: %s\n", gpg_strerror (err));
232       if (binary)
233         {
234           if (fwrite (buffer, 16, 1, stdout) != 1)
235             writerr = 1;
236           else
237             fflush (stdout);
238         }
239       else
240         {
241           print_buffer (buffer, sizeof buffer);
242           if (putchar ('\n') == EOF)
243             writerr = 1;
244         }
245       if (writerr)
246         {
247 #ifndef HAVE_W32_SYSTEM
248           if (loop && errno == EPIPE)
249             break;
250 #endif
251           die ("writing output failed: %s\n", strerror (errno));
252         }
253
254       if (progress)
255         {
256           putc ('.', stderr);
257           fflush (stderr);
258         }
259     }
260   while (loop);
261
262   if (progress)
263     putc ('\n', stderr);
264
265   deinit_external_test (context);
266
267   if (verbose)
268     fputs (PGM ": ready\n", stderr);
269
270   return 0;
271 }