Ashley Mills / axTLS
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers loader.c Source File

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 }