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>