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.
Fork of mbed-os 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 13:15:52 by
