This is a fork of the mbed port of axTLS

Dependents:   TLS_axTLS-Example HTTPSClientExample

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers crypto_misc.c Source File

crypto_misc.c

00001 /*
00002  * Copyright (c) 2007, Cameron Rich
00003  * 
00004  * All rights reserved.
00005  * 
00006  * Redistribution and use in source and binary forms, with or without 
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  * * Redistributions of source code must retain the above copyright notice, 
00010  *   this list of conditions and the following disclaimer.
00011  * * Redistributions in binary form must reproduce the above copyright notice, 
00012  *   this list of conditions and the following disclaimer in the documentation 
00013  *   and/or other materials provided with the distribution.
00014  * * Neither the name of the axTLS project nor the names of its contributors 
00015  *   may be used to endorse or promote products derived from this software 
00016  *   without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00021  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
00022  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00024  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00025  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00026  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00027  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 /**
00032  * Some misc. routines to help things out
00033  */
00034 
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <stdarg.h>
00038 #include <stdio.h>
00039 #include "os_port.h"
00040 #include <lwip/def.h>
00041 #include "sockets.h"
00042 #include "crypto_misc.h "
00043 #include "config.h"
00044 
00045 #include <time.h>
00046 #ifdef CONFIG_WIN32_USE_CRYPTO_LIB
00047 #include "wincrypt.h"
00048 #endif
00049 
00050 #ifndef WIN32
00051 //static int rng_fd = -1;
00052 #elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
00053 static HCRYPTPROV gCryptProv;
00054 #endif
00055 
00056 #if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
00057 /* change to processor registers as appropriate */
00058 #define ENTROPY_POOL_SIZE 32
00059 #define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec)
00060 #define ENTROPY_COUNTER2 rand()
00061 static uint8_t entropy_pool[ENTROPY_POOL_SIZE];
00062 #endif
00063 
00064 const char * const unsupported_str = "Error: Feature not supported\n";
00065 
00066 #ifndef CONFIG_SSL_SKELETON_MODE
00067 /** 
00068  * Retrieve a file and put it into memory
00069  * @return The size of the file, or -1 on failure.
00070  */
00071 int get_file(const char *filename, uint8_t **buf)
00072 {
00073     int total_bytes = 0;
00074     int bytes_read = 0; 
00075     int filesize;
00076     FILE *stream = fopen(filename, "rb");
00077 
00078     if (stream == NULL)
00079     {
00080 #ifdef CONFIG_SSL_FULL_MODE         
00081         printf("file '%s' does not exist\n", filename); TTY_FLUSH();
00082 #endif
00083         return -1;
00084     }
00085 
00086     /* Win CE doesn't support stat() */
00087     fseek(stream, 0, SEEK_END);
00088     filesize = ftell(stream);
00089     *buf = (uint8_t *)malloc(filesize);
00090     fseek(stream, 0, SEEK_SET);
00091 
00092     do
00093     {
00094         bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
00095         total_bytes += bytes_read;
00096     } while (total_bytes < filesize && bytes_read > 0);
00097     
00098     fclose(stream);
00099     return filesize;
00100 }
00101 #endif
00102 
00103 /**
00104  * Initialise the Random Number Generator engine.
00105  * - On Win32 use the platform SDK's crypto engine.
00106  * - On Linux use /dev/urandom
00107  * - If none of these work then use a custom RNG.
00108  */
00109 EXP_FUNC void STDCALL RNG_initialize()
00110 {
00111 #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
00112     rng_fd = ax_open("/dev/urandom", O_RDONLY);
00113 #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
00114     if (!CryptAcquireContext(&gCryptProv, 
00115                       NULL, NULL, PROV_RSA_FULL, 0))
00116     {
00117         if (GetLastError() == NTE_BAD_KEYSET &&
00118                 !CryptAcquireContext(&gCryptProv, 
00119                        NULL, 
00120                        NULL, 
00121                        PROV_RSA_FULL, 
00122                        CRYPT_NEWKEYSET))
00123         {
00124             printf("CryptoLib: %x\n", unsupported_str, GetLastError());
00125             exit(1);
00126         }
00127     }
00128 #else
00129     /* start of with a stack to copy across */
00130     int i;
00131     memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE);
00132     srand((unsigned int)&i); 
00133 #endif
00134 }
00135 
00136 /**
00137  * If no /dev/urandom, then initialise the RNG with something interesting.
00138  */
00139 EXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size)
00140 {
00141 #if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB)
00142     int i;
00143 
00144     for (i = 0; i < ENTROPY_POOL_SIZE && i < size; i++)
00145         entropy_pool[i] ^= seed_buf[i];
00146 #endif
00147 }
00148 
00149 /**
00150  * Terminate the RNG engine.
00151  */
00152 EXP_FUNC void STDCALL RNG_terminate(void)
00153 {
00154 #ifndef WIN32
00155     //close(rng_fd);
00156 #elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
00157     CryptReleaseContext(gCryptProv, 0);
00158 #endif
00159 }
00160 
00161 /**
00162  * Set a series of bytes with a random number. Individual bytes can be 0
00163  */
00164 EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
00165 {   
00166 #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
00167     /* use the Linux default */
00168     read(rng_fd, rand_data, num_rand_bytes);    /* read from /dev/urandom */
00169 #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
00170     /* use Microsoft Crypto Libraries */
00171     CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
00172 #else   /* nothing else to use, so use a custom RNG */
00173     /* The method we use when we've got nothing better. Use RC4, time 
00174        and a couple of random seeds to generate a random sequence */
00175     RC4_CTX rng_ctx;
00176     struct timeval tv;
00177     MD5_CTX rng_digest_ctx;
00178     uint8_t digest[MD5_SIZE];
00179     uint64_t *ep;
00180     int i;
00181 
00182     /* A proper implementation would use counters etc for entropy */
00183     // XXX XXX XX X need to seed this properly
00184     gettimeofday(&tv, NULL);    
00185     ep = (uint64_t *)entropy_pool;
00186     
00187     ep[0] ^= ENTROPY_COUNTER1;
00188     ep[1] ^= ENTROPY_COUNTER2; 
00189     
00190 
00191     /* use a digested version of the entropy pool as a key */
00192     MD5_Init(&rng_digest_ctx);
00193     MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE);
00194     MD5_Final(digest, &rng_digest_ctx);
00195 
00196     /* come up with the random sequence */
00197     RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */
00198     memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ?
00199                 num_rand_bytes : ENTROPY_POOL_SIZE);
00200     RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);
00201 
00202     /* move things along */
00203     for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--)
00204         entropy_pool[i] = entropy_pool[i-MD5_SIZE];
00205 
00206     /* insert the digest at the start of the entropy pool */
00207     memcpy(entropy_pool, digest, MD5_SIZE);
00208 #endif
00209 }
00210 
00211 /**
00212  * Set a series of bytes with a random number. Individual bytes are not zero.
00213  */
00214 void get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
00215 {
00216     int i;
00217     get_random(num_rand_bytes, rand_data);
00218 
00219     for (i = 0; i < num_rand_bytes; i++)
00220     {
00221         while (rand_data[i] == 0)  /* can't be 0 */
00222             rand_data[i] = (uint8_t)(rand());
00223     }
00224 }
00225 
00226 /**
00227  * Some useful diagnostic routines
00228  */
00229 #if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
00230 int hex_finish;
00231 int hex_index;
00232 
00233 static void print_hex_init(int finish)
00234 {
00235     hex_finish = finish;
00236     hex_index = 0;
00237 }
00238 
00239 static void print_hex(uint8_t hex)
00240 {
00241     static int column;
00242 
00243     if (hex_index == 0)
00244     {
00245         column = 0;
00246     }
00247 
00248     printf("%02x ", hex);
00249     if (++column == 8)
00250     {
00251         printf(": ");
00252     }
00253     else if (column >= 16)
00254     {
00255         printf("\r\n");
00256         column = 0;
00257     }
00258 
00259     if (++hex_index >= hex_finish && column > 0)
00260     {
00261         printf("\r\n");
00262     }
00263 }
00264 
00265 /**
00266  * Spit out a blob of data for diagnostics. The data is is a nice column format
00267  * for easy reading.
00268  *
00269  * @param format   [in]    The string (with possible embedded format characters)
00270  * @param size     [in]    The number of numbers to print
00271  * @param data     [in]    The start of data to use
00272  * @param ...      [in]    Any additional arguments
00273  */
00274 EXP_FUNC void STDCALL print_blob(const char *format, 
00275         const uint8_t *data, int size, ...)
00276 {
00277     int i;
00278     char tmp[80];
00279     va_list(ap);
00280 
00281     va_start(ap, size);
00282     sprintf(tmp, "%s\n", format);
00283     vprintf(tmp, ap);
00284     print_hex_init(size);
00285     for (i = 0; i < size; i++)
00286     {
00287         print_hex(data[i]);
00288     }
00289 
00290     va_end(ap);
00291     TTY_FLUSH();
00292 }
00293 #elif defined(WIN32)
00294 /* VC6.0 doesn't handle variadic macros */
00295 EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,
00296         int size, ...) {}
00297 #endif
00298 
00299 #if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
00300 /* base64 to binary lookup table */
00301 static const uint8_t map[128] =
00302 {
00303     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
00304     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
00305     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
00306     255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
00307     52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
00308     255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
00309     7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
00310     19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
00311     255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
00312     37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
00313     49,  50,  51, 255, 255, 255, 255, 255
00314 };
00315 
00316 EXP_FUNC int STDCALL base64_decode(const char *in, int len,
00317                     uint8_t *out, int *outlen)
00318 {
00319     int g, t, x, y, z;
00320     uint8_t c;
00321     int ret = -1;
00322 
00323     g = 3;
00324     for (x = y = z = t = 0; x < len; x++)
00325     {
00326         if ((c = map[in[x]&0x7F]) == 0xff)
00327             continue;
00328 
00329         if (c == 254)   /* this is the end... */
00330         {
00331             c = 0;
00332 
00333             if (--g < 0)
00334                 goto error;
00335         }
00336         else if (g != 3) /* only allow = at end */
00337             goto error;
00338 
00339         t = (t<<6) | c;
00340 
00341         if (++y == 4)
00342         {
00343             out[z++] = (uint8_t)((t>>16)&255);
00344 
00345             if (g > 1)
00346                 out[z++] = (uint8_t)((t>>8)&255);
00347 
00348             if (g > 2)
00349                 out[z++] = (uint8_t)(t&255);
00350 
00351             y = t = 0;
00352         }
00353 
00354         /* check that we don't go past the output buffer */
00355         if (z > *outlen) 
00356             goto error;
00357     }
00358 
00359     if (y != 0)
00360         goto error;
00361 
00362     *outlen = z;
00363     ret = 0;
00364 
00365 error:
00366 #ifdef CONFIG_SSL_FULL_MODE
00367     if (ret < 0)
00368         printf("Error: Invalid base64\n"); TTY_FLUSH();
00369 #endif
00370     TTY_FLUSH();
00371     return ret;
00372 
00373 }
00374 #endif
00375 
00376 
00377