Annotation of embedaddon/axTLS/crypto/crypto_misc.c, revision 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>