Finish FIPS random test driver.
[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 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   unsigned char key[16];
135   unsigned char seed[16];
136   unsigned char dt[16];
137   void *context;
138   gpg_error_t err;
139   unsigned char buffer[16];
140
141   if (argc)
142     { argc--; argv++; }
143
144   while (argc && last_argc != argc )
145     {
146       last_argc = argc;
147       if (!strcmp (*argv, "--"))
148         {
149           argc--; argv++;
150           break;
151         }
152       else if (!strcmp (*argv, "--verbose"))
153         {
154           verbose = 2;
155           argc--; argv++;
156         }
157       else if (!strcmp (*argv, "--binary"))
158         {
159           binary = 1;
160           argc--; argv++;
161         }
162       else if (!strcmp (*argv, "--loop"))
163         {
164           loop = 1;
165           argc--; argv++;
166         }
167       else if (!strcmp (*argv, "--progress"))
168         {
169           progress = 1;
170           argc--; argv++;
171         }
172     }          
173   
174   if (!argc)
175     {
176       memcpy (key,  "1234567890123456", 16);
177       memcpy (seed, "abcdefghijklmnop", 16);
178       memcpy (dt,   "XXXXXXXXXXXXXXXX", 16);
179     }
180   else if (argc == 3)
181     {
182       if (    hex2bin (argv[0], key, 16) < 0
183            || hex2bin (argv[1], seed, 16) < 0
184            || hex2bin (argv[2], dt, 16) < 0 )
185         die ("args are not 32 hex digits each\n");
186     }
187   else
188     die ("invalid usage\n");
189
190 #ifndef HAVE_W32_SYSTEM
191   if (loop)
192     signal (SIGPIPE, SIG_IGN);
193 #endif
194
195   gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
196   gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
197   if (!gcry_check_version ("1.4.3"))
198     die ("version mismatch\n");
199   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
200   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
201
202   err = init_external_test (&context, 0, key, 16, seed, 16, dt, 16);
203   if (err)
204     die ("init external test failed: %s\n", gpg_strerror (err));
205
206   do 
207     {
208       err = run_external_test (context, buffer, sizeof buffer);
209       if (err)
210         die ("run external test failed: %s\n", gpg_strerror (err));
211       if (binary)
212         {
213           if (fwrite (buffer, 16, 1, stdout) != 1)
214             {
215 #ifndef HAVE_W32_SYSTEM
216               if (loop && errno == EPIPE)
217                 break;
218 #endif
219               die ("writing output failed: %s\n", strerror (errno));
220             }
221           fflush (stdout);
222         }
223       else
224         {
225           print_buffer (buffer, sizeof buffer);
226           putchar ('\n');
227         }
228       if (progress)
229         {
230           putc ('.', stderr);
231           fflush (stderr);
232         }
233     }
234   while (loop);
235
236   if (progress)
237     putc ('\n', stderr);
238
239   deinit_external_test (context);
240
241   return 0;
242 }
243