]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto_misc.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / net / https / 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 "os_port.h"
40 #include <lwip/def.h>
41 #include "sockets.h"
42 #include "crypto_misc.h"
43 #include "config.h"
44
45 #include <time.h>
46 #ifdef CONFIG_WIN32_USE_CRYPTO_LIB
47 #include "wincrypt.h"
48 #endif
49
50 #ifndef WIN32
51 static int rng_fd = -1;
52 #elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
53 static HCRYPTPROV gCryptProv;
54 #endif
55
56 #if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
57 /* change to processor registers as appropriate */
58 #define ENTROPY_POOL_SIZE 32
59 #define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec)
60 #define ENTROPY_COUNTER2 rand()
61 static uint8_t entropy_pool[ENTROPY_POOL_SIZE];
62 #endif
63
64 const char * const unsupported_str = "Error: Feature not supported\n";
65
66 #ifndef CONFIG_SSL_SKELETON_MODE
67 /** 
68  * Retrieve a file and put it into memory
69  * @return The size of the file, or -1 on failure.
70  */
71 int get_file(const char *filename, uint8_t **buf)
72 {
73     int total_bytes = 0;
74     int bytes_read = 0; 
75     int filesize;
76     FILE *stream = fopen(filename, "rb");
77
78     if (stream == NULL)
79     {
80 #ifdef CONFIG_SSL_FULL_MODE         
81         printf("file '%s' does not exist\n", filename); TTY_FLUSH();
82 #endif
83         return -1;
84     }
85
86     /* Win CE doesn't support stat() */
87     fseek(stream, 0, SEEK_END);
88     filesize = ftell(stream);
89     *buf = (uint8_t *)malloc(filesize);
90     fseek(stream, 0, SEEK_SET);
91
92     do
93     {
94         bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
95         total_bytes += bytes_read;
96     } while (total_bytes < filesize && bytes_read > 0);
97     
98     fclose(stream);
99     return filesize;
100 }
101 #endif
102
103 /**
104  * Initialise the Random Number Generator engine.
105  * - On Win32 use the platform SDK's crypto engine.
106  * - On Linux use /dev/urandom
107  * - If none of these work then use a custom RNG.
108  */
109 EXP_FUNC void STDCALL RNG_initialize()
110 {
111 #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
112     rng_fd = ax_open("/dev/urandom", O_RDONLY);
113 #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
114     if (!CryptAcquireContext(&gCryptProv, 
115                       NULL, NULL, PROV_RSA_FULL, 0))
116     {
117         if (GetLastError() == NTE_BAD_KEYSET &&
118                 !CryptAcquireContext(&gCryptProv, 
119                        NULL, 
120                        NULL, 
121                        PROV_RSA_FULL, 
122                        CRYPT_NEWKEYSET))
123         {
124             printf("CryptoLib: %x\n", unsupported_str, GetLastError());
125             exit(1);
126         }
127     }
128 #else
129     /* start of with a stack to copy across */
130     int i;
131     memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE);
132     srand((unsigned int)&i); 
133 #endif
134 }
135
136 /**
137  * If no /dev/urandom, then initialise the RNG with something interesting.
138  */
139 EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size)
140 {
141 #if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB)
142     int i;
143
144     for (i = 0; i < ENTROPY_POOL_SIZE && i < size; i++)
145         entropy_pool[i] ^= seed_buf[i];
146 #endif
147 }
148
149 /**
150  * Terminate the RNG engine.
151  */
152 EXP_FUNC void STDCALL RNG_terminate(void)
153 {
154 #ifndef WIN32
155     //close(rng_fd);
156 #elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
157     CryptReleaseContext(gCryptProv, 0);
158 #endif
159 }
160
161 /**
162  * Set a series of bytes with a random number. Individual bytes can be 0
163  */
164 EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
165 {   
166 #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
167     /* use the Linux default */
168     read(rng_fd, rand_data, num_rand_bytes);    /* read from /dev/urandom */
169 #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
170     /* use Microsoft Crypto Libraries */
171     CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
172 #else   /* nothing else to use, so use a custom RNG */
173     /* The method we use when we've got nothing better. Use RC4, time 
174        and a couple of random seeds to generate a random sequence */
175     RC4_CTX rng_ctx;
176     struct timeval tv;
177     MD5_CTX rng_digest_ctx;
178     uint8_t digest[MD5_SIZE];
179     uint64_t *ep;
180     int i;
181
182     /* A proper implementation would use counters etc for entropy */
183     // XXX XXX XX X need to seed this properly
184     gettimeofday(&tv, NULL);    
185     ep = (uint64_t *)entropy_pool;
186     
187     ep[0] ^= ENTROPY_COUNTER1;
188     ep[1] ^= ENTROPY_COUNTER2; 
189     
190
191     /* use a digested version of the entropy pool as a key */
192     MD5_Init(&rng_digest_ctx);
193     MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE);
194     MD5_Final(digest, &rng_digest_ctx);
195
196     /* come up with the random sequence */
197     RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */
198     memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ?
199                 num_rand_bytes : ENTROPY_POOL_SIZE);
200     RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);
201
202     /* move things along */
203     for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--)
204         entropy_pool[i] = entropy_pool[i-MD5_SIZE];
205
206     /* insert the digest at the start of the entropy pool */
207     memcpy(entropy_pool, digest, MD5_SIZE);
208 #endif
209 }
210
211 /**
212  * Set a series of bytes with a random number. Individual bytes are not zero.
213  */
214 void get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
215 {
216     int i;
217     get_random(num_rand_bytes, rand_data);
218
219     for (i = 0; i < num_rand_bytes; i++)
220     {
221         while (rand_data[i] == 0)  /* can't be 0 */
222             rand_data[i] = (uint8_t)(rand());
223     }
224 }
225
226 /**
227  * Some useful diagnostic routines
228  */
229 #if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
230 int hex_finish;
231 int hex_index;
232
233 static void print_hex_init(int finish)
234 {
235     hex_finish = finish;
236     hex_index = 0;
237 }
238
239 static void print_hex(uint8_t hex)
240 {
241     static int column;
242
243     if (hex_index == 0)
244     {
245         column = 0;
246     }
247
248     printf("%02x ", hex);
249     if (++column == 8)
250     {
251         printf(": ");
252     }
253     else if (column >= 16)
254     {
255         printf("\r\n");
256         column = 0;
257     }
258
259     if (++hex_index >= hex_finish && column > 0)
260     {
261         printf("\r\n");
262     }
263 }
264
265 /**
266  * Spit out a blob of data for diagnostics. The data is is a nice column format
267  * for easy reading.
268  *
269  * @param format   [in]    The string (with possible embedded format characters)
270  * @param size     [in]    The number of numbers to print
271  * @param data     [in]    The start of data to use
272  * @param ...      [in]    Any additional arguments
273  */
274 EXP_FUNC void STDCALL print_blob(const char *format, 
275         const uint8_t *data, int size, ...)
276 {
277     int i;
278     char tmp[80];
279     va_list(ap);
280
281     va_start(ap, size);
282     sprintf(tmp, "%s\n", format);
283     vprintf(tmp, ap);
284     print_hex_init(size);
285     for (i = 0; i < size; i++)
286     {
287         print_hex(data[i]);
288     }
289
290     va_end(ap);
291     TTY_FLUSH();
292 }
293 #elif defined(WIN32)
294 /* VC6.0 doesn't handle variadic macros */
295 EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,
296         int size, ...) {}
297 #endif
298
299 #if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
300 /* base64 to binary lookup table */
301 static const uint8_t map[128] =
302 {
303     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
304     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
305     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
306     255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
307     52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
308     255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
309     7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
310     19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
311     255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
312     37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
313     49,  50,  51, 255, 255, 255, 255, 255
314 };
315
316 EXP_FUNC int STDCALL base64_decode(const char *in, int len,
317                     uint8_t *out, int *outlen)
318 {
319     int g, t, x, y, z;
320     uint8_t c;
321     int ret = -1;
322
323     g = 3;
324     for (x = y = z = t = 0; x < len; x++)
325     {
326         if ((c = map[in[x]&0x7F]) == 0xff)
327             continue;
328
329         if (c == 254)   /* this is the end... */
330         {
331             c = 0;
332
333             if (--g < 0)
334                 goto error;
335         }
336         else if (g != 3) /* only allow = at end */
337             goto error;
338
339         t = (t<<6) | c;
340
341         if (++y == 4)
342         {
343             out[z++] = (uint8_t)((t>>16)&255);
344
345             if (g > 1)
346                 out[z++] = (uint8_t)((t>>8)&255);
347
348             if (g > 2)
349                 out[z++] = (uint8_t)(t&255);
350
351             y = t = 0;
352         }
353
354         /* check that we don't go past the output buffer */
355         if (z > *outlen) 
356             goto error;
357     }
358
359     if (y != 0)
360         goto error;
361
362     *outlen = z;
363     ret = 0;
364
365 error:
366 #ifdef CONFIG_SSL_FULL_MODE
367     if (ret < 0)
368         printf("Error: Invalid base64\n"); TTY_FLUSH();
369 #endif
370     TTY_FLUSH();
371     return ret;
372
373 }
374 #endif
375