This is a fork of the mbed port of axTLS
Dependents: TLS_axTLS-Example HTTPSClientExample
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
Generated on Wed Jul 13 2022 19:30:07 by 1.7.2