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.
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 00111 ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); 00112 ssl_obj->buf = (uint8_t *)malloc(len); 00113 memcpy(ssl_obj->buf, data, len); 00114 ssl_obj->len = len; 00115 ret = do_obj(ssl_ctx, mem_type, ssl_obj, password); 00116 ssl_obj_free(ssl_obj); 00117 return ret; 00118 } 00119 00120 /* 00121 * Actually work out what we are doing 00122 */ 00123 static int do_obj(SSL_CTX *ssl_ctx, int obj_type, 00124 SSLObjLoader *ssl_obj, const char *password) 00125 { 00126 int ret = SSL_OK; 00127 00128 switch (obj_type) 00129 { 00130 case SSL_OBJ_RSA_KEY: 00131 ret = add_private_key(ssl_ctx, ssl_obj); 00132 break; 00133 00134 case SSL_OBJ_X509_CERT: 00135 ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len); 00136 break; 00137 00138 #ifdef CONFIG_SSL_CERT_VERIFICATION 00139 case SSL_OBJ_X509_CACERT: 00140 add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len); 00141 break; 00142 #endif 00143 00144 #ifdef CONFIG_SSL_USE_PKCS12 00145 case SSL_OBJ_PKCS8: 00146 ret = pkcs8_decode(ssl_ctx, ssl_obj, password); 00147 break; 00148 00149 case SSL_OBJ_PKCS12: 00150 ret = pkcs12_decode(ssl_ctx, ssl_obj, password); 00151 break; 00152 #endif 00153 default: 00154 printf(unsupported_str); 00155 ret = SSL_ERROR_NOT_SUPPORTED; 00156 break; 00157 } 00158 00159 return ret; 00160 } 00161 00162 /* 00163 * Clean up our mess. 00164 */ 00165 void ssl_obj_free(SSLObjLoader *ssl_obj) 00166 { 00167 if (ssl_obj) 00168 { 00169 free(ssl_obj->buf); 00170 free(ssl_obj); 00171 } 00172 } 00173 00174 /* 00175 * Support for PEM encoded keys/certificates. 00176 */ 00177 #ifdef CONFIG_SSL_HAS_PEM 00178 00179 #define NUM_PEM_TYPES 4 00180 #define IV_SIZE 16 00181 #define IS_RSA_PRIVATE_KEY 0 00182 #define IS_ENCRYPTED_PRIVATE_KEY 1 00183 #define IS_PRIVATE_KEY 2 00184 #define IS_CERTIFICATE 3 00185 00186 static const char * const begins[NUM_PEM_TYPES] = 00187 { 00188 "-----BEGIN RSA PRIVATE KEY-----", 00189 "-----BEGIN ENCRYPTED PRIVATE KEY-----", 00190 "-----BEGIN PRIVATE KEY-----", 00191 "-----BEGIN CERTIFICATE-----", 00192 }; 00193 00194 static const char * const ends[NUM_PEM_TYPES] = 00195 { 00196 "-----END RSA PRIVATE KEY-----", 00197 "-----END ENCRYPTED PRIVATE KEY-----", 00198 "-----END PRIVATE KEY-----", 00199 "-----END CERTIFICATE-----", 00200 }; 00201 00202 static const char * const aes_str[2] = 00203 { 00204 "DEK-Info: AES-128-CBC,", 00205 "DEK-Info: AES-256-CBC," 00206 }; 00207 00208 /** 00209 * Take a base64 blob of data and decrypt it (using AES) into its 00210 * proper ASN.1 form. 00211 */ 00212 static int pem_decrypt(const char *where, const char *end, 00213 const char *password, SSLObjLoader *ssl_obj) 00214 { 00215 int ret = -1; 00216 int is_aes_256 = 0; 00217 char *start = NULL; 00218 uint8_t iv[IV_SIZE]; 00219 int i, pem_size; 00220 MD5_CTX md5_ctx; 00221 AES_CTX aes_ctx; 00222 uint8_t key[32]; /* AES256 size */ 00223 00224 if (password == NULL || strlen(password) == 0) 00225 { 00226 #ifdef CONFIG_SSL_FULL_MODE 00227 printf("Error: Need a password for this PEM file\n"); TTY_FLUSH(); 00228 #endif 00229 goto error; 00230 } 00231 00232 if ((start = strstr((const char *)where, aes_str[0]))) /* AES128? */ 00233 { 00234 start += strlen(aes_str[0]); 00235 } 00236 else if ((start = strstr((const char *)where, aes_str[1]))) /* AES256? */ 00237 { 00238 is_aes_256 = 1; 00239 start += strlen(aes_str[1]); 00240 } 00241 else 00242 { 00243 #ifdef CONFIG_SSL_FULL_MODE 00244 printf("Error: Unsupported password cipher\n"); TTY_FLUSH(); 00245 #endif 00246 goto error; 00247 } 00248 00249 /* convert from hex to binary - assumes uppercase hex */ 00250 for (i = 0; i < IV_SIZE; i++) 00251 { 00252 char c = *start++ - '0'; 00253 iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4; 00254 c = *start++ - '0'; 00255 iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c); 00256 } 00257 00258 while (*start == '\r' || *start == '\n') 00259 start++; 00260 00261 /* turn base64 into binary */ 00262 pem_size = (int)(end-start); 00263 if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0) 00264 goto error; 00265 00266 /* work out the key */ 00267 MD5_Init(&md5_ctx); 00268 MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); 00269 MD5_Update(&md5_ctx, iv, SALT_SIZE); 00270 MD5_Final(key, &md5_ctx); 00271 00272 if (is_aes_256) 00273 { 00274 MD5_Init(&md5_ctx); 00275 MD5_Update(&md5_ctx, key, MD5_SIZE); 00276 MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password)); 00277 MD5_Update(&md5_ctx, iv, SALT_SIZE); 00278 MD5_Final(&key[MD5_SIZE], &md5_ctx); 00279 } 00280 00281 /* decrypt using the key/iv */ 00282 AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128); 00283 AES_convert_key(&aes_ctx); 00284 AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len); 00285 ret = 0; 00286 00287 error: 00288 return ret; 00289 } 00290 00291 /** 00292 * Take a base64 blob of data and turn it into its proper ASN.1 form. 00293 */ 00294 static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where, 00295 int remain, const char *password) 00296 { 00297 int ret = SSL_ERROR_BAD_CERTIFICATE; 00298 SSLObjLoader *ssl_obj = NULL; 00299 00300 while (remain > 0) 00301 { 00302 int i, pem_size, obj_type; 00303 char *start = NULL, *end = NULL; 00304 00305 for (i = 0; i < NUM_PEM_TYPES; i++) 00306 { 00307 if ((start = strstr(where, begins[i])) && 00308 (end = strstr(where, ends[i]))) 00309 { 00310 remain -= (int)(end-where); 00311 start += strlen(begins[i]); 00312 pem_size = (int)(end-start); 00313 00314 ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader)); 00315 00316 /* 4/3 bigger than what we need but so what */ 00317 ssl_obj->buf = (uint8_t *)calloc(1, pem_size); 00318 ssl_obj->len = pem_size; 00319 00320 if (i == IS_RSA_PRIVATE_KEY && 00321 strstr(start, "Proc-Type:") && 00322 strstr(start, "4,ENCRYPTED")) 00323 { 00324 /* check for encrypted PEM file */ 00325 if (pem_decrypt(start, end, password, ssl_obj) < 0) 00326 { 00327 ret = SSL_ERROR_BAD_CERTIFICATE; 00328 goto error; 00329 } 00330 } 00331 else 00332 { 00333 ssl_obj->len = pem_size; 00334 if (base64_decode(start, pem_size, 00335 ssl_obj->buf, &ssl_obj->len) != 0) 00336 { 00337 ret = SSL_ERROR_BAD_CERTIFICATE; 00338 goto error; 00339 } 00340 } 00341 00342 switch (i) 00343 { 00344 case IS_RSA_PRIVATE_KEY: 00345 obj_type = SSL_OBJ_RSA_KEY; 00346 break; 00347 00348 case IS_ENCRYPTED_PRIVATE_KEY: 00349 case IS_PRIVATE_KEY: 00350 obj_type = SSL_OBJ_PKCS8; 00351 break; 00352 00353 case IS_CERTIFICATE: 00354 obj_type = is_cacert ? 00355 SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT; 00356 break; 00357 00358 default: 00359 ret = SSL_ERROR_BAD_CERTIFICATE; 00360 goto error; 00361 } 00362 00363 /* In a format we can now understand - so process it */ 00364 if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password))) 00365 goto error; 00366 00367 end += strlen(ends[i]); 00368 remain -= strlen(ends[i]); 00369 while (remain > 0 && (*end == '\r' || *end == '\n')) 00370 { 00371 end++; 00372 remain--; 00373 } 00374 00375 where = end; 00376 break; 00377 } 00378 } 00379 00380 ssl_obj_free(ssl_obj); 00381 ssl_obj = NULL; 00382 if (start == NULL) 00383 break; 00384 } 00385 error: 00386 ssl_obj_free(ssl_obj); 00387 return ret; 00388 } 00389 00390 /* 00391 * Load a file into memory that is in ASCII PEM format. 00392 */ 00393 static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, 00394 SSLObjLoader *ssl_obj, const char *password) 00395 { 00396 char *start; 00397 00398 /* add a null terminator */ 00399 ssl_obj->len++; 00400 ssl_obj->buf = (uint8_t *)realloc(ssl_obj->buf, ssl_obj->len); 00401 ssl_obj->buf[ssl_obj->len-1] = 0; 00402 start = (char *)ssl_obj->buf; 00403 return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT, 00404 start, ssl_obj->len, password); 00405 } 00406 #endif /* CONFIG_SSL_HAS_PEM */ 00407 00408 /** 00409 * Load the key/certificates in memory depending on compile-time and user 00410 * options. 00411 */ 00412 int load_key_certs(SSL_CTX *ssl_ctx) 00413 { 00414 printf("loading key certs\r\n"); 00415 int ret = SSL_OK; 00416 uint32_t options = ssl_ctx->options; 00417 #ifdef CONFIG_SSL_GENERATE_X509_CERT 00418 uint8_t *cert_data = NULL; 00419 int cert_size; 00420 static const char *dn[] = 00421 { 00422 CONFIG_SSL_X509_COMMON_NAME, 00423 CONFIG_SSL_X509_ORGANIZATION_NAME, 00424 CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME 00425 }; 00426 #endif 00427 00428 /* do the private key first */ 00429 if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0) 00430 { 00431 if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, 00432 CONFIG_SSL_PRIVATE_KEY_LOCATION, 00433 CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0) 00434 goto error; 00435 } 00436 else if (!(options & SSL_NO_DEFAULT_KEY)) 00437 { 00438 #if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) 00439 static const /* saves a few more bytes */ 00440 #include "private_key.h" 00441 ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key, 00442 default_private_key_len, NULL); 00443 #endif 00444 } 00445 00446 /* now load the certificate */ 00447 #ifdef CONFIG_SSL_GENERATE_X509_CERT 00448 if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0) 00449 { 00450 ret = cert_size; 00451 goto error; 00452 } 00453 00454 ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL); 00455 free(cert_data); 00456 #else 00457 if (strlen(CONFIG_SSL_X509_CERT_LOCATION)) 00458 { 00459 if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, 00460 CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0) 00461 goto error; 00462 } 00463 else if (!(options & SSL_NO_DEFAULT_KEY)) 00464 { 00465 #if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) 00466 static const /* saves a few bytes and RAM */ 00467 #include "cert.h" 00468 ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, 00469 default_certificate, default_certificate_len, NULL); 00470 #endif 00471 } 00472 #endif 00473 00474 error: 00475 #ifdef CONFIG_SSL_FULL_MODE 00476 if (ret) 00477 { 00478 printf("Error: Certificate or key not loaded\n"); TTY_FLUSH(); 00479 } 00480 #endif 00481 00482 return ret; 00483 00484 }
Generated on Tue Jul 12 2022 18:48:00 by
1.7.2