Annotation of embedaddon/axTLS/crypto/crypto_misc.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>