Annotation of embedaddon/axTLS/ssl/loader.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 2007, Cameron Rich
        !             3:  * 
        !             4:  * All rights reserved.
        !             5:  * 
        !             6:  * Redistribution and use in source and binary forms, with or without 
        !             7:  * modification, are permitted provided that the following conditions are met:
        !             8:  *
        !             9:  * * Redistributions of source code must retain the above copyright notice, 
        !            10:  *   this list of conditions and the following disclaimer.
        !            11:  * * Redistributions in binary form must reproduce the above copyright notice, 
        !            12:  *   this list of conditions and the following disclaimer in the documentation 
        !            13:  *   and/or other materials provided with the distribution.
        !            14:  * * Neither the name of the axTLS project nor the names of its contributors 
        !            15:  *   may be used to endorse or promote products derived from this software 
        !            16:  *   without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
        !            19:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
        !            20:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
        !            21:  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
        !            22:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
        !            23:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
        !            24:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
        !            25:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
        !            26:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
        !            27:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
        !            28:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            29:  */
        !            30: 
        !            31: /**
        !            32:  * Load certificates/keys into memory. These can be in many different formats.
        !            33:  * PEM support and other formats can be processed here.
        !            34:  *
        !            35:  * The PEM private keys may be optionally encrypted with AES128 or AES256. 
        !            36:  * The encrypted PEM keys were generated with something like:
        !            37:  *
        !            38:  * openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512
        !            39:  */
        !            40: 
        !            41: #include <stdlib.h>
        !            42: #include <string.h>
        !            43: #include <stdio.h>
        !            44: #include "os_port.h"
        !            45: #include "ssl.h"
        !            46: 
        !            47: static int do_obj(SSL_CTX *ssl_ctx, int obj_type, 
        !            48:                     SSLObjLoader *ssl_obj, const char *password);
        !            49: #ifdef CONFIG_SSL_HAS_PEM
        !            50: static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, 
        !            51:                         SSLObjLoader *ssl_obj, const char *password);
        !            52: #endif
        !            53: 
        !            54: /*
        !            55:  * Load a file into memory that is in binary DER (or ascii PEM) format.
        !            56:  */
        !            57: EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, 
        !            58:                             const char *filename, const char *password)
        !            59: {
        !            60: #ifndef CONFIG_SSL_SKELETON_MODE
        !            61:     static const char * const begin = "-----BEGIN";
        !            62:     int ret = SSL_OK;
        !            63:     SSLObjLoader *ssl_obj = NULL;
        !            64: 
        !            65:     if (filename == NULL)
        !            66:     {
        !            67:         ret = SSL_ERROR_INVALID_KEY;
        !            68:         goto error;
        !            69:     }
        !            70: 
        !            71:     ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
        !            72:     ssl_obj->len = get_file(filename, &ssl_obj->buf); 
        !            73:     if (ssl_obj->len <= 0)
        !            74:     {
        !            75:         ret = SSL_ERROR_INVALID_KEY;
        !            76:         goto error;
        !            77:     }
        !            78: 
        !            79:     /* is the file a PEM file? */
        !            80:     if (strstr((char *)ssl_obj->buf, begin) != NULL)
        !            81:     {
        !            82: #ifdef CONFIG_SSL_HAS_PEM
        !            83:         ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password);
        !            84: #else
        !            85:         printf(unsupported_str);
        !            86:         ret = SSL_ERROR_NOT_SUPPORTED;
        !            87: #endif
        !            88:     }
        !            89:     else
        !            90:         ret = do_obj(ssl_ctx, obj_type, ssl_obj, password);
        !            91: 
        !            92: error:
        !            93:     ssl_obj_free(ssl_obj);
        !            94:     return ret;
        !            95: #else
        !            96:     printf(unsupported_str);
        !            97:     return SSL_ERROR_NOT_SUPPORTED;
        !            98: #endif /* CONFIG_SSL_SKELETON_MODE */
        !            99: }
        !           100: 
        !           101: /*
        !           102:  * Transfer binary data into the object loader.
        !           103:  */
        !           104: EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type, 
        !           105:         const uint8_t *data, int len, const char *password)
        !           106: {
        !           107:     int ret;
        !           108:     SSLObjLoader *ssl_obj;
        !           109: 
        !           110:     ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
        !           111:     ssl_obj->buf = (uint8_t *)malloc(len);
        !           112:     memcpy(ssl_obj->buf, data, len);
        !           113:     ssl_obj->len = len;
        !           114:     ret = do_obj(ssl_ctx, mem_type, ssl_obj, password);
        !           115:     ssl_obj_free(ssl_obj);
        !           116:     return ret;
        !           117: }
        !           118: 
        !           119: /*
        !           120:  * Actually work out what we are doing 
        !           121:  */
        !           122: static int do_obj(SSL_CTX *ssl_ctx, int obj_type, 
        !           123:                     SSLObjLoader *ssl_obj, const char *password)
        !           124: {
        !           125:     int ret = SSL_OK;
        !           126: 
        !           127:     switch (obj_type)
        !           128:     {
        !           129:         case SSL_OBJ_RSA_KEY:
        !           130:             ret = add_private_key(ssl_ctx, ssl_obj);
        !           131:             break;
        !           132: 
        !           133:         case SSL_OBJ_X509_CERT:
        !           134:             ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len);
        !           135:             break;
        !           136: 
        !           137: #ifdef CONFIG_SSL_CERT_VERIFICATION
        !           138:         case SSL_OBJ_X509_CACERT:
        !           139:             add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len);
        !           140:             break;
        !           141: #endif
        !           142: 
        !           143: #ifdef CONFIG_SSL_USE_PKCS12
        !           144:         case SSL_OBJ_PKCS8:
        !           145:             ret = pkcs8_decode(ssl_ctx, ssl_obj, password);
        !           146:             break;
        !           147: 
        !           148:         case SSL_OBJ_PKCS12:
        !           149:             ret = pkcs12_decode(ssl_ctx, ssl_obj, password);
        !           150:             break;
        !           151: #endif
        !           152:         default:
        !           153:             printf(unsupported_str);
        !           154:             ret = SSL_ERROR_NOT_SUPPORTED;
        !           155:             break;
        !           156:     }
        !           157: 
        !           158:     return ret;
        !           159: }
        !           160: 
        !           161: /*
        !           162:  * Clean up our mess.
        !           163:  */
        !           164: void ssl_obj_free(SSLObjLoader *ssl_obj)
        !           165: {
        !           166:     if (ssl_obj)
        !           167:     {
        !           168:         free(ssl_obj->buf);
        !           169:         free(ssl_obj);
        !           170:     }
        !           171: }
        !           172: 
        !           173: /*
        !           174:  * Support for PEM encoded keys/certificates.
        !           175:  */
        !           176: #ifdef CONFIG_SSL_HAS_PEM
        !           177: 
        !           178: #define NUM_PEM_TYPES               4
        !           179: #define IV_SIZE                     16
        !           180: #define IS_RSA_PRIVATE_KEY          0
        !           181: #define IS_ENCRYPTED_PRIVATE_KEY    1
        !           182: #define IS_PRIVATE_KEY              2
        !           183: #define IS_CERTIFICATE              3
        !           184: 
        !           185: static const char * const begins[NUM_PEM_TYPES] =
        !           186: {
        !           187:     "-----BEGIN RSA PRIVATE KEY-----",
        !           188:     "-----BEGIN ENCRYPTED PRIVATE KEY-----",
        !           189:     "-----BEGIN PRIVATE KEY-----",
        !           190:     "-----BEGIN CERTIFICATE-----",
        !           191: };
        !           192: 
        !           193: static const char * const ends[NUM_PEM_TYPES] =
        !           194: {
        !           195:     "-----END RSA PRIVATE KEY-----",
        !           196:     "-----END ENCRYPTED PRIVATE KEY-----",
        !           197:     "-----END PRIVATE KEY-----",
        !           198:     "-----END CERTIFICATE-----",
        !           199: };
        !           200: 
        !           201: static const char * const aes_str[2] =
        !           202: {
        !           203:     "DEK-Info: AES-128-CBC,",
        !           204:     "DEK-Info: AES-256-CBC," 
        !           205: };
        !           206: 
        !           207: /**
        !           208:  * Take a base64 blob of data and decrypt it (using AES) into its 
        !           209:  * proper ASN.1 form.
        !           210:  */
        !           211: static int pem_decrypt(const char *where, const char *end,
        !           212:                         const char *password, SSLObjLoader *ssl_obj)
        !           213: {
        !           214:     int ret = -1;
        !           215:     int is_aes_256 = 0;
        !           216:     char *start = NULL;
        !           217:     uint8_t iv[IV_SIZE];
        !           218:     int i, pem_size;
        !           219:     MD5_CTX md5_ctx;
        !           220:     AES_CTX aes_ctx;
        !           221:     uint8_t key[32];        /* AES256 size */
        !           222: 
        !           223:     if (password == NULL || strlen(password) == 0)
        !           224:     {
        !           225: #ifdef CONFIG_SSL_FULL_MODE
        !           226:         printf("Error: Need a password for this PEM file\n"); TTY_FLUSH();
        !           227: #endif
        !           228:         goto error;
        !           229:     }
        !           230: 
        !           231:     if ((start = strstr((const char *)where, aes_str[0])))         /* AES128? */
        !           232:     {
        !           233:         start += strlen(aes_str[0]);
        !           234:     }
        !           235:     else if ((start = strstr((const char *)where, aes_str[1])))    /* AES256? */
        !           236:     {
        !           237:         is_aes_256 = 1;
        !           238:         start += strlen(aes_str[1]);
        !           239:     }
        !           240:     else 
        !           241:     {
        !           242: #ifdef CONFIG_SSL_FULL_MODE
        !           243:         printf("Error: Unsupported password cipher\n"); TTY_FLUSH();
        !           244: #endif
        !           245:         goto error;
        !           246:     }
        !           247: 
        !           248:     /* convert from hex to binary - assumes uppercase hex */
        !           249:     for (i = 0; i < IV_SIZE; i++)
        !           250:     {
        !           251:         char c = *start++ - '0';
        !           252:         iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4;
        !           253:         c = *start++ - '0';
        !           254:         iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c);
        !           255:     }
        !           256: 
        !           257:     while (*start == '\r' || *start == '\n')
        !           258:         start++;
        !           259: 
        !           260:     /* turn base64 into binary */
        !           261:     pem_size = (int)(end-start);
        !           262:     if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0)
        !           263:         goto error;
        !           264: 
        !           265:     /* work out the key */
        !           266:     MD5_Init(&md5_ctx);
        !           267:     MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
        !           268:     MD5_Update(&md5_ctx, iv, SALT_SIZE);
        !           269:     MD5_Final(key, &md5_ctx);
        !           270: 
        !           271:     if (is_aes_256)
        !           272:     {
        !           273:         MD5_Init(&md5_ctx);
        !           274:         MD5_Update(&md5_ctx, key, MD5_SIZE);
        !           275:         MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
        !           276:         MD5_Update(&md5_ctx, iv, SALT_SIZE);
        !           277:         MD5_Final(&key[MD5_SIZE], &md5_ctx);
        !           278:     }
        !           279: 
        !           280:     /* decrypt using the key/iv */
        !           281:     AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128);
        !           282:     AES_convert_key(&aes_ctx);
        !           283:     AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len);
        !           284:     ret = 0;
        !           285: 
        !           286: error:
        !           287:     return ret; 
        !           288: }
        !           289: 
        !           290: /**
        !           291:  * Take a base64 blob of data and turn it into its proper ASN.1 form.
        !           292:  */
        !           293: static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where, 
        !           294:                     int remain, const char *password)
        !           295: {
        !           296:     int ret = SSL_ERROR_BAD_CERTIFICATE;
        !           297:     SSLObjLoader *ssl_obj = NULL;
        !           298: 
        !           299:     while (remain > 0)
        !           300:     {
        !           301:         int i, pem_size, obj_type;
        !           302:         char *start = NULL, *end = NULL;
        !           303: 
        !           304:         for (i = 0; i < NUM_PEM_TYPES; i++)
        !           305:         {
        !           306:             if ((start = strstr(where, begins[i])) &&
        !           307:                     (end = strstr(where, ends[i])))
        !           308:             {
        !           309:                 remain -= (int)(end-where);
        !           310:                 start += strlen(begins[i]);
        !           311:                 pem_size = (int)(end-start);
        !           312: 
        !           313:                 ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
        !           314: 
        !           315:                 /* 4/3 bigger than what we need but so what */
        !           316:                 ssl_obj->buf = (uint8_t *)calloc(1, pem_size);
        !           317:                 ssl_obj->len = pem_size;
        !           318: 
        !           319:                 if (i == IS_RSA_PRIVATE_KEY && 
        !           320:                             strstr(start, "Proc-Type:") && 
        !           321:                             strstr(start, "4,ENCRYPTED"))
        !           322:                 {
        !           323:                     /* check for encrypted PEM file */
        !           324:                     if (pem_decrypt(start, end, password, ssl_obj) < 0)
        !           325:                     {
        !           326:                         ret = SSL_ERROR_BAD_CERTIFICATE;
        !           327:                         goto error;
        !           328:                     }
        !           329:                 }
        !           330:                 else 
        !           331:                 {
        !           332:                     ssl_obj->len = pem_size;
        !           333:                     if (base64_decode(start, pem_size, 
        !           334:                                 ssl_obj->buf, &ssl_obj->len) != 0)
        !           335:                     {
        !           336:                         ret = SSL_ERROR_BAD_CERTIFICATE;
        !           337:                         goto error;
        !           338:                     }
        !           339:                 }
        !           340: 
        !           341:                 switch (i)
        !           342:                 {
        !           343:                     case IS_RSA_PRIVATE_KEY:
        !           344:                         obj_type = SSL_OBJ_RSA_KEY;
        !           345:                         break;
        !           346: 
        !           347:                     case IS_ENCRYPTED_PRIVATE_KEY:
        !           348:                     case IS_PRIVATE_KEY:
        !           349:                         obj_type = SSL_OBJ_PKCS8;
        !           350:                         break;
        !           351: 
        !           352:                     case IS_CERTIFICATE:
        !           353:                         obj_type = is_cacert ?
        !           354:                                         SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT;
        !           355:                         break;
        !           356: 
        !           357:                     default:
        !           358:                         ret = SSL_ERROR_BAD_CERTIFICATE;
        !           359:                         goto error;
        !           360:                 }
        !           361: 
        !           362:                 /* In a format we can now understand - so process it */
        !           363:                 if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password)))
        !           364:                     goto error;
        !           365: 
        !           366:                 end += strlen(ends[i]);
        !           367:                 remain -= strlen(ends[i]);
        !           368:                 while (remain > 0 && (*end == '\r' || *end == '\n'))
        !           369:                 {
        !           370:                     end++;
        !           371:                     remain--;
        !           372:                 }
        !           373: 
        !           374:                 where = end;
        !           375:                 break;
        !           376:             }
        !           377:         }
        !           378: 
        !           379:         ssl_obj_free(ssl_obj);
        !           380:         ssl_obj = NULL;
        !           381:         if (start == NULL)
        !           382:            break;
        !           383:     }
        !           384: error:
        !           385:     ssl_obj_free(ssl_obj);
        !           386:     return ret;
        !           387: }
        !           388: 
        !           389: /*
        !           390:  * Load a file into memory that is in ASCII PEM format.
        !           391:  */
        !           392: static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, 
        !           393:                         SSLObjLoader *ssl_obj, const char *password)
        !           394: {
        !           395:     char *start;
        !           396: 
        !           397:     /* add a null terminator */
        !           398:     ssl_obj->len++;
        !           399:     ssl_obj->buf = (uint8_t *)realloc(ssl_obj->buf, ssl_obj->len);
        !           400:     ssl_obj->buf[ssl_obj->len-1] = 0;
        !           401:     start = (char *)ssl_obj->buf;
        !           402:     return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT,
        !           403:                                 start, ssl_obj->len, password);
        !           404: }
        !           405: #endif /* CONFIG_SSL_HAS_PEM */
        !           406: 
        !           407: /**
        !           408:  * Load the key/certificates in memory depending on compile-time and user
        !           409:  * options. 
        !           410:  */
        !           411: int load_key_certs(SSL_CTX *ssl_ctx)
        !           412: {
        !           413:     int ret = SSL_OK;
        !           414:     uint32_t options = ssl_ctx->options;
        !           415: #ifdef CONFIG_SSL_GENERATE_X509_CERT 
        !           416:     uint8_t *cert_data = NULL;
        !           417:     int cert_size;
        !           418:     static const char *dn[] = 
        !           419:     {
        !           420:         CONFIG_SSL_X509_COMMON_NAME,
        !           421:         CONFIG_SSL_X509_ORGANIZATION_NAME,
        !           422:         CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME
        !           423:     };
        !           424: #endif
        !           425: 
        !           426:     /* do the private key first */
        !           427:     if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0)
        !           428:     {
        !           429:         if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, 
        !           430:                                 CONFIG_SSL_PRIVATE_KEY_LOCATION,
        !           431:                                 CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0)
        !           432:             goto error;
        !           433:     }
        !           434:     else if (!(options & SSL_NO_DEFAULT_KEY))
        !           435:     {
        !           436: #if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
        !           437:         static const    /* saves a few more bytes */
        !           438: #include "private_key.h"
        !           439: 
        !           440:         ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key,
        !           441:                 default_private_key_len, NULL); 
        !           442: #endif
        !           443:     }
        !           444: 
        !           445:     /* now load the certificate */
        !           446: #ifdef CONFIG_SSL_GENERATE_X509_CERT 
        !           447:     if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0)
        !           448:     {
        !           449:         ret = cert_size;
        !           450:         goto error;
        !           451:     }
        !           452: 
        !           453:     ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL);
        !           454:     free(cert_data);
        !           455: #else
        !           456:     if (strlen(CONFIG_SSL_X509_CERT_LOCATION))
        !           457:     {
        !           458:         if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, 
        !           459:                                 CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0)
        !           460:             goto error;
        !           461:     }
        !           462:     else if (!(options & SSL_NO_DEFAULT_KEY))
        !           463:     {
        !           464: #if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
        !           465:         static const    /* saves a few bytes and RAM */
        !           466: #include "cert.h"
        !           467:         ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, 
        !           468:                     default_certificate, default_certificate_len, NULL);
        !           469: #endif
        !           470:     }
        !           471: #endif
        !           472: 
        !           473: error:
        !           474: #ifdef CONFIG_SSL_FULL_MODE
        !           475:     if (ret)
        !           476:     {
        !           477:         printf("Error: Certificate or key not loaded\n"); TTY_FLUSH();
        !           478:     }
        !           479: #endif
        !           480: 
        !           481:     return ret;
        !           482: 
        !           483: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>