]> git.gir.st - tmk_keyboard.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/net/https/axTLS/crypto/crypto_misc.c
Merge commit 'fdc38ef3f92af7adeeb4de49550d8838c8a39b5c'
[tmk_keyboard.git] / tmk_core / 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
Imprint / Impressum