Add axTLS sourcecode
[project/luci.git] / libs / nixio / axTLS / crypto / crypto_misc.c
1 /*
2  * Copyright (c) 2007, Cameron Rich
3  * 
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright notice, 
10  *   this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright notice, 
12  *   this list of conditions and the following disclaimer in the documentation 
13  *   and/or other materials provided with the distribution.
14  * * Neither the name of the axTLS project nor the names of its contributors 
15  *   may be used to endorse or promote products derived from this software 
16  *   without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * Some misc. routines to help things out
33  */
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include "crypto_misc.h"
40 #ifdef CONFIG_WIN32_USE_CRYPTO_LIB
41 #include "wincrypt.h"
42 #endif
43
44 #ifndef WIN32
45 static int rng_fd = -1;
46 #elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
47 static HCRYPTPROV gCryptProv;
48 #endif
49
50 #if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
51 static uint64_t rng_num;
52 #endif
53
54 static int rng_ref_count;
55 const char * const unsupported_str = "Error: Feature not supported\n";
56
57 #ifndef CONFIG_SSL_SKELETON_MODE
58 /** 
59  * Retrieve a file and put it into memory
60  * @return The size of the file, or -1 on failure.
61  */
62 int get_file(const char *filename, uint8_t **buf)
63 {
64     int total_bytes = 0;
65     int bytes_read = 0; 
66     int filesize;
67     FILE *stream = fopen(filename, "rb");
68
69     if (stream == NULL)
70     {
71 #ifdef CONFIG_SSL_FULL_MODE         
72         printf("file '%s' does not exist\n", filename); TTY_FLUSH();
73 #endif
74         return -1;
75     }
76
77     /* Win CE doesn't support stat() */
78     fseek(stream, 0, SEEK_END);
79     filesize = ftell(stream);
80     *buf = (uint8_t *)malloc(filesize);
81     fseek(stream, 0, SEEK_SET);
82
83     do
84     {
85         bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
86         total_bytes += bytes_read;
87     } while (total_bytes < filesize && bytes_read > 0);
88     
89     fclose(stream);
90     return filesize;
91 }
92 #endif
93
94 /**
95  * Initialise the Random Number Generator engine.
96  * - On Win32 use the platform SDK's crypto engine.
97  * - On Linux use /dev/urandom
98  * - If none of these work then use a custom RNG.
99  */
100 EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size)
101 {
102     if (rng_ref_count == 0)
103     {
104 #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
105         rng_fd = ax_open("/dev/urandom", O_RDONLY);
106 #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
107         if (!CryptAcquireContext(&gCryptProv, 
108                           NULL, NULL, PROV_RSA_FULL, 0))
109         {
110             if (GetLastError() == NTE_BAD_KEYSET &&
111                     !CryptAcquireContext(&gCryptProv, 
112                            NULL, 
113                            NULL, 
114                            PROV_RSA_FULL, 
115                            CRYPT_NEWKEYSET))
116             {
117                 printf("CryptoLib: %x\n", unsupported_str, GetLastError());
118                 exit(1);
119             }
120         }
121 #else   
122         /* help seed with the user's private key - this is a number that 
123            should be hard to find, due to the fact that it relies on knowing 
124            the private key */
125         int i;  
126
127         for (i = 0; i < size/(int)sizeof(uint64_t); i++)
128             rng_num ^= *((uint64_t *)&seed_buf[i*sizeof(uint64_t)]);
129
130         srand((long)&seed_buf);  /* use the stack ptr as another rnd seed */
131 #endif
132     }
133
134     rng_ref_count++;
135 }
136
137 /**
138  * Terminate the RNG engine.
139  */
140 EXP_FUNC void STDCALL RNG_terminate(void)
141 {
142     if (--rng_ref_count == 0)
143     {
144 #ifndef WIN32
145         close(rng_fd);
146 #elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
147         CryptReleaseContext(gCryptProv, 0);
148 #endif
149     }
150 }
151
152 /**
153  * Set a series of bytes with a random number. Individual bytes can be 0
154  */
155 EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
156 {   
157 #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
158     /* use the Linux default */
159     read(rng_fd, rand_data, num_rand_bytes);    /* read from /dev/urandom */
160 #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
161     /* use Microsoft Crypto Libraries */
162     CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
163 #else   /* nothing else to use, so use a custom RNG */
164     /* The method we use when we've got nothing better. Use RC4, time 
165        and a couple of random seeds to generate a random sequence */
166     RC4_CTX rng_ctx;
167     struct timeval tv;
168     uint64_t big_num1, big_num2;
169
170     gettimeofday(&tv, NULL);    /* yes I know we shouldn't do this */
171
172     /* all numbers by themselves are pretty simple, but combined should 
173      * be a challenge */
174     big_num1 = (uint64_t)tv.tv_sec*(tv.tv_usec+1); 
175     big_num2 = (uint64_t)rand()*big_num1;
176     big_num1 ^= rng_num;
177
178     memcpy(rand_data, &big_num1, sizeof(uint64_t));
179     if (num_rand_bytes > sizeof(uint64_t))
180         memcpy(&rand_data[8], &big_num2, sizeof(uint64_t));
181
182     if (num_rand_bytes > 16)
183     {
184         /* clear rest of data */
185         memset(&rand_data[16], 0, num_rand_bytes-16); 
186     }
187
188     RC4_setup(&rng_ctx, rand_data, 16); /* use as a key */
189     RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);
190     
191     /* use last 8 bytes for next time */
192     memcpy(&rng_num, &rand_data[num_rand_bytes-8], sizeof(uint64_t));    
193 #endif
194 }
195
196 /**
197  * Set a series of bytes with a random number. Individual bytes are not zero.
198  */
199 void get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
200 {
201     int i;
202     get_random(num_rand_bytes, rand_data);
203
204     for (i = 0; i < num_rand_bytes; i++)
205     {
206         while (rand_data[i] == 0)  /* can't be 0 */
207             rand_data[i] = (uint8_t)(rand());
208     }
209 }
210
211 /**
212  * Some useful diagnostic routines
213  */
214 #if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
215 int hex_finish;
216 int hex_index;
217
218 static void print_hex_init(int finish)
219 {
220     hex_finish = finish;
221     hex_index = 0;
222 }
223
224 static void print_hex(uint8_t hex)
225 {
226     static int column;
227
228     if (hex_index == 0)
229     {
230         column = 0;
231     }
232
233     printf("%02x ", hex);
234     if (++column == 8)
235     {
236         printf(": ");
237     }
238     else if (column >= 16)
239     {
240         printf("\n");
241         column = 0;
242     }
243
244     if (++hex_index >= hex_finish && column > 0)
245     {
246         printf("\n");
247     }
248 }
249
250 /**
251  * Spit out a blob of data for diagnostics. The data is is a nice column format
252  * for easy reading.
253  *
254  * @param format   [in]    The string (with possible embedded format characters)
255  * @param size     [in]    The number of numbers to print
256  * @param data     [in]    The start of data to use
257  * @param ...      [in]    Any additional arguments
258  */
259 EXP_FUNC void STDCALL print_blob(const char *format, 
260         const uint8_t *data, int size, ...)
261 {
262     int i;
263     char tmp[80];
264     va_list(ap);
265
266     va_start(ap, size);
267     sprintf(tmp, "%s\n", format);
268     vprintf(tmp, ap);
269     print_hex_init(size);
270     for (i = 0; i < size; i++)
271     {
272         print_hex(data[i]);
273     }
274
275     va_end(ap);
276     TTY_FLUSH();
277 }
278 #elif defined(WIN32)
279 /* VC6.0 doesn't handle variadic macros */
280 EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,
281         int size, ...) {}
282 #endif
283
284 #if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
285 /* base64 to binary lookup table */
286 static const uint8_t map[128] =
287 {
288     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
289     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
290     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
291     255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
292     52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
293     255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
294     7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
295     19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
296     255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
297     37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
298     49,  50,  51, 255, 255, 255, 255, 255
299 };
300
301 EXP_FUNC int STDCALL base64_decode(const char *in, int len,
302                     uint8_t *out, int *outlen)
303 {
304     int g, t, x, y, z;
305     uint8_t c;
306     int ret = -1;
307
308     g = 3;
309     for (x = y = z = t = 0; x < len; x++)
310     {
311         if ((c = map[in[x]&0x7F]) == 0xff)
312             continue;
313
314         if (c == 254)   /* this is the end... */
315         {
316             c = 0;
317
318             if (--g < 0)
319                 goto error;
320         }
321         else if (g != 3) /* only allow = at end */
322             goto error;
323
324         t = (t<<6) | c;
325
326         if (++y == 4)
327         {
328             out[z++] = (uint8_t)((t>>16)&255);
329
330             if (g > 1)
331                 out[z++] = (uint8_t)((t>>8)&255);
332
333             if (g > 2)
334                 out[z++] = (uint8_t)(t&255);
335
336             y = t = 0;
337         }
338     }
339
340     if (y != 0)
341         goto error;
342
343     if (outlen)
344         *outlen = z;
345     ret = 0;
346
347 error:
348 #ifdef CONFIG_SSL_FULL_MODE
349     if (ret < 0)
350         printf("Error: Invalid base64\n"); TTY_FLUSH();
351 #endif
352     TTY_FLUSH();
353     return ret;
354
355 }
356 #endif
357