Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: MAX44000 PWM_Tone_Library nexpaq_mdk
Fork of LED_Demo by
loader.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 * Load certificates/keys into memory. These can be in many different formats. 00033 * PEM support and other formats can be processed here. 00034 * 00035 * The PEM private keys may be optionally encrypted with AES128 or AES256. 00036 * The encrypted PEM keys were generated with something like: 00037 * 00038 * openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512 00039 */ 00040 00041 #include <stdlib.h> 00042 #include <string.h> 00043 #include <stdio.h> 00044 #include "os_port.h" 00045 #include "ssl.h" 00046 #include "config.h" 00047 00048 static int do_obj(SSL_CTX *ssl_ctx, int obj_type, 00049 SSLObjLoader *ssl_obj, const char *password); 00050 #ifdef CONFIG_SSL_HAS_PEM 00051 static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, 00052 SSLObjLoader *ssl_obj, const char *password); 00053 #endif 00054 00055 /* 00056 * Load a file into memory that is in binary DER (or ascii PEM) format. 00057 */ 00058 EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, 00059 const char *filename, const char *password) 00060 { 00061 #ifndef CONFIG_SSL_SKELETON_MODE 00062 static const char * const begin = "-----BEGIN"; 00063 int ret = SSL_OK; 00064 SSLObjLoader *ssl_obj = NULL; 00065 00066 if (filename == NULL) 00067 { 00068 ret = SSL_ERROR_INVALID_KEY; 00069 goto error; 00070 } 00071 00072 ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); 00073 ssl_obj->len = get_file(filename, &ssl_obj->buf); 00074 if (ssl_obj->len <= 0) 00075 { 00076 ret = SSL_ERROR_INVALID_KEY; 00077 goto error; 00078 } 00079 00080 /* is the file a PEM file? */ 00081 if (strstr((char *)ssl_obj->buf, begin) != NULL) 00082 { 00083 #ifdef CONFIG_SSL_HAS_PEM 00084 ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password); 00085 #else 00086 printf(unsupported_str); 00087 ret = SSL_ERROR_NOT_SUPPORTED; 00088 #endif 00089 } 00090 else 00091 ret = do_obj(ssl_ctx, obj_type, ssl_obj, password); 00092 00093 error: 00094 ssl_obj_free(ssl_obj); 00095 return ret; 00096 #else 00097 printf(unsupported_str); 00098 return SSL_ERROR_NOT_SUPPORTED; 00099 #endif /* CONFIG_SSL_SKELETON_MODE */ 00100 } 00101 00102 /* 00103 * Transfer binary data into the object loader. 00104 */ 00105 EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type, 00106 const uint8_t *data, int len, const char *password) 00107 { 00108 int ret; 00109 SSLObjLoader ssl_obj; 00110 ssl_obj.buf = data; 00111 ssl_obj.len = len; 00112 ret = do_obj(ssl_ctx, mem_type, &ssl_obj, password); 00113 00114 return ret; 00115 } 00116 00117 /* 00118 * Actually work out what we are doing 00119 */ 00120 static int do_obj(SSL_CTX *ssl_ctx, int obj_type, 00121 SSLObjLoader *ssl_obj, const char *password) 00122 { 00123 int ret = SSL_OK; 00124 00125 switch (obj_type) 00126 { 00127 case SSL_OBJ_RSA_KEY: 00128 ret = add_private_key(ssl_ctx, ssl_obj); 00129 break; 00130 00131 case SSL_OBJ_X509_CERT: 00132 ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len); 00133 break; 00134 00135 #ifdef CONFIG_SSL_CERT_VERIFICATION 00136 case SSL_OBJ_X509_CACERT: 00137 add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len); 00138 break; 00139 #endif 00140 00141 #ifdef CONFIG_SSL_USE_PKCS12 00142 case SSL_OBJ_PKCS8: 00143 ret = pkcs8_decode(ssl_ctx, ssl_obj, password); 00144 break; 00145 00146 case SSL_OBJ_PKCS12: 00147 ret = pkcs12_decode(ssl_ctx, ssl_obj, password); 00148 break; 00149 #endif 00150 default: 00151 printf(unsupported_str); 00152 ret = SSL_ERROR_NOT_SUPPORTED; 00153 break; 00154 } 00155 00156 return ret; 00157 } 00158 00159 /* 00160 * Clean up our mess. 00161 */ 00162 void ssl_obj_free(SSLObjLoader *ssl_obj) 00163 { 00164 if (ssl_obj) 00165 { 00166 free(ssl_obj->buf); 00167 free(ssl_obj); 00168 } 00169 } 00170 00171 /* 00172 * Support for PEM encoded keys/certificates. 00173 */ 00174 #ifdef CONFIG_SSL_HAS_PEM 00175 00176 #define NUM_PEM_TYPES 4 00177 #define IV_SIZE 16 00178 #define IS_RSA_PRIVATE_KEY 0 00179 #define IS_ENCRYPTED_PRIVATE_KEY 1 00180 #define IS_PRIVATE_KEY 2 00181 #define IS_CERTIFICATE 3 00182 00183 static const char * const begins[NUM_PEM_TYPES] = 00184 { 00185 "-----BEGIN RSA PRIVATE KEY-----", 00186 "-----BEGIN ENCRYPTED PRIVATE KEY-----", 00187 "-----BEGIN PRIVATE KEY-----", 00188 "-----BEGIN CERTIFICATE-----", 00189 }; 00190 00191 static const char * const ends[NUM_PEM_TYPES] = 00192 { 00193 "-----END RSA PRIVATE KEY-----", 00194 "-----END ENCRYPTED PRIVATE KEY-----", 00195 "-----END PRIVATE KEY-----", 00196 "-----END CERTIFICATE-----", 00197 }; 00198 00199 static const char * const aes_str[2] = 00200 { 00201 "DEK-Info: AES-128-CBC,", 00202 "DEK-Info: AES-256-CBC," 00203 }; 00204 00205 /** 00206 * Take a base64 blob of data and decrypt it (using AES) into its 00207 * proper ASN.1 form. 00208 */ 00209 static int pem_decrypt(const char *where, const char *end, 00210 const char *password, SSLObjLoader *ssl_obj) 00211 { 00212 int ret = -1; 00213 int is_aes_256 = 0; 00214 char *start = NULL; 00215 uint8_t iv[IV_SIZE]; 00216 int i, pem_size; 00217 MD5_CTX md5_ctx; 00218 AES_CTX aes_ctx; 00219 uint8_t key[32]; /* AES256 size */ 00220 00221 if (password == NULL || strlen(password) == 0) 00222 { 00223 #ifdef CONFIG_SSL_FULL_MODE 00224 printf("Error: Need a password for this PEM file\n"); TTY_FLUSH(); 00225 #endif 00226 goto error; 00227 } 00228 00229 if ((start = strstr((const char *)where, aes_str[0]))) /* AES128? */ 00230 { 00231 start += strlen(aes_str[0]); 00232 } 00233 else if ((start = strstr((const char *)where, aes_str[1]))) /* AES256? */ 00234 { 00235 is_aes_256 = 1; 00236 start += strlen(aes_str[1]); 00237 } 00238 else 00239 { 00240 #ifdef CONFIG_SSL_FULL_MODE 00241 printf("Error: Unsupported password cipher\n"); TTY_FLUSH(); 00242 #endif 00243 goto error; 00244 } 00245 00246 /* convert from hex to binary - assumes uppercase hex */ 00247 for (i = 0; i < IV_SIZE; i++) 00248 { 00249 char c = *start++ - '0'; 00250 iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4; 00251 c = *start++ - '0'; 00252 iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c); 00253 } 00254 00255 while (*start == '\r' || *start == '\n') 00256 start++; 00257 00258 /* turn base64 into binary */ 00259 pem_size = (int)(end-start); 00260 if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0) 00261 goto error; 00262 00263 /* work out the key */ 00264 MD5_Init(&md5_ctx); 00265 MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); 00266 MD5_Update(&md5_ctx, iv, SALT_SIZE); 00267 MD5_Final(key, &md5_ctx); 00268 00269 if (is_aes_256) 00270 { 00271 MD5_Init(&md5_ctx); 00272 MD5_Update(&md5_ctx, key, MD5_SIZE); 00273 MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); 00274 MD5_Update(&md5_ctx, iv, SALT_SIZE); 00275 MD5_Final(&key[MD5_SIZE], &md5_ctx); 00276 } 00277 00278 /* decrypt using the key/iv */ 00279 AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128); 00280 AES_convert_key(&aes_ctx); 00281 AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len); 00282 ret = 0; 00283 00284 error: 00285 return ret; 00286 } 00287 00288 /** 00289 * Take a base64 blob of data and turn it into its proper ASN.1 form. 00290 */ 00291 static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where, 00292 int remain, const char *password) 00293 { 00294 int ret = SSL_ERROR_BAD_CERTIFICATE; 00295 SSLObjLoader *ssl_obj = NULL; 00296 00297 while (remain > 0) 00298 { 00299 int i, pem_size, obj_type; 00300 char *start = NULL, *end = NULL; 00301 00302 for (i = 0; i < NUM_PEM_TYPES; i++) 00303 { 00304 if ((start = strstr(where, begins[i])) && 00305 (end = strstr(where, ends[i]))) 00306 { 00307 remain -= (int)(end-where); 00308 start += strlen(begins[i]); 00309 pem_size = (int)(end-start); 00310 00311 ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); 00312 00313 /* 4/3 bigger than what we need but so what */ 00314 ssl_obj->buf = (uint8_t *)calloc(1, pem_size); 00315 ssl_obj->len = pem_size; 00316 00317 if (i == IS_RSA_PRIVATE_KEY && 00318 strstr(start, "Proc-Type:") && 00319 strstr(start, "4,ENCRYPTED")) 00320 { 00321 /* check for encrypted PEM file */ 00322 if (pem_decrypt(start, end, password, ssl_obj) < 0) 00323 { 00324 ret = SSL_ERROR_BAD_CERTIFICATE; 00325 goto error; 00326 } 00327 } 00328 else 00329 { 00330 ssl_obj->len = pem_size; 00331 if (base64_decode(start, pem_size, 00332 ssl_obj->buf, &ssl_obj->len) != 0) 00333 { 00334 ret = SSL_ERROR_BAD_CERTIFICATE; 00335 goto error; 00336 } 00337 } 00338 00339 switch (i) 00340 { 00341 case IS_RSA_PRIVATE_KEY: 00342 obj_type = SSL_OBJ_RSA_KEY; 00343 break; 00344 00345 case IS_ENCRYPTED_PRIVATE_KEY: 00346 case IS_PRIVATE_KEY: 00347 obj_type = SSL_OBJ_PKCS8; 00348 break; 00349 00350 case IS_CERTIFICATE: 00351 obj_type = is_cacert ? 00352 SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT; 00353 break; 00354 00355 default: 00356 ret = SSL_ERROR_BAD_CERTIFICATE; 00357 goto error; 00358 } 00359 00360 /* In a format we can now understand - so process it */ 00361 if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password))) 00362 goto error; 00363 00364 end += strlen(ends[i]); 00365 remain -= strlen(ends[i]); 00366 while (remain > 0 && (*end == '\r' || *end == '\n')) 00367 { 00368 end++; 00369 remain--; 00370 } 00371 00372 where = end; 00373 break; 00374 } 00375 } 00376 00377 ssl_obj_free(ssl_obj); 00378 ssl_obj = NULL; 00379 if (start == NULL) 00380 break; 00381 } 00382 error: 00383 ssl_obj_free(ssl_obj); 00384 return ret; 00385 } 00386 00387 /* 00388 * Load a file into memory that is in ASCII PEM format. 00389 */ 00390 static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, 00391 SSLObjLoader *ssl_obj, const char *password) 00392 { 00393 char *start; 00394 00395 /* add a null terminator */ 00396 ssl_obj->len++; 00397 ssl_obj->buf = (uint8_t *)realloc(ssl_obj->buf, ssl_obj->len); 00398 ssl_obj->buf[ssl_obj->len-1] = 0; 00399 start = (char *)ssl_obj->buf; 00400 return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT, 00401 start, ssl_obj->len, password); 00402 } 00403 #endif /* CONFIG_SSL_HAS_PEM */ 00404 00405 /** 00406 * Load the key/certificates in memory depending on compile-time and user 00407 * options. 00408 */ 00409 int load_key_certs(SSL_CTX *ssl_ctx) 00410 { 00411 int ret = SSL_OK; 00412 uint32_t options = ssl_ctx->options; 00413 #ifdef CONFIG_SSL_GENERATE_X509_CERT 00414 uint8_t *cert_data = NULL; 00415 int cert_size; 00416 static const char *dn[] = 00417 { 00418 CONFIG_SSL_X509_COMMON_NAME, 00419 CONFIG_SSL_X509_ORGANIZATION_NAME, 00420 CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME 00421 }; 00422 #endif 00423 00424 /* do the private key first */ 00425 if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0) 00426 { 00427 if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, 00428 CONFIG_SSL_PRIVATE_KEY_LOCATION, 00429 CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0) 00430 goto error; 00431 } 00432 else if (!(options & SSL_NO_DEFAULT_KEY)) 00433 { 00434 #if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) 00435 // static const /* saves a few more bytes */ 00436 //#include "private_key.h" 00437 // ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key, 00438 // default_private_key_len, NULL); 00439 #endif 00440 } 00441 00442 /* now load the certificate */ 00443 #ifdef CONFIG_SSL_GENERATE_X509_CERT 00444 if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0) 00445 { 00446 ret = cert_size; 00447 goto error; 00448 } 00449 00450 ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL); 00451 free(cert_data); 00452 #else 00453 if (strlen(CONFIG_SSL_X509_CERT_LOCATION)) 00454 { 00455 if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, 00456 CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0) 00457 goto error; 00458 } 00459 else if (!(options & SSL_NO_DEFAULT_KEY)) 00460 { 00461 #if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) 00462 static const /* saves a few bytes and RAM */ 00463 #include "cert.h" 00464 ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, 00465 default_certificate, default_certificate_len, NULL); 00466 #endif 00467 } 00468 #endif 00469 00470 error: 00471 #ifdef CONFIG_SSL_FULL_MODE 00472 if (ret) 00473 { 00474 printf("Error: Certificate or key not loaded\n"); TTY_FLUSH(); 00475 } 00476 #endif 00477 00478 return ret; 00479 00480 }
Generated on Tue Jul 12 2022 12:28:34 by
