Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pem/pem_builder.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (C) 2013 Tobias Brunner
                      3:  * Copyright (C) 2009 Martin Willi
                      4:  * Copyright (C) 2001-2008 Andreas Steffen
                      5:  * HSR Hochschule fuer Technik Rapperswil
                      6:  *
                      7:  * This program is free software; you can redistribute it and/or modify it
                      8:  * under the terms of the GNU General Public License as published by the
                      9:  * Free Software Foundation; either version 2 of the License, or (at your
                     10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     11:  *
                     12:  * This program is distributed in the hope that it will be useful, but
                     13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     15:  * for more details.
                     16:  */
                     17: 
                     18: #include "pem_builder.h"
                     19: 
                     20: #include <stdio.h>
                     21: #include <stdlib.h>
                     22: #include <unistd.h>
                     23: #include <errno.h>
                     24: #include <string.h>
                     25: #include <stddef.h>
                     26: #include <fcntl.h>
                     27: #include <sys/types.h>
                     28: #include <sys/stat.h>
                     29: 
                     30: #include <utils/debug.h>
                     31: #include <library.h>
                     32: #include <utils/lexparser.h>
                     33: #include <asn1/asn1.h>
                     34: #include <crypto/hashers/hasher.h>
                     35: #include <crypto/crypters/crypter.h>
                     36: #include <credentials/certificates/x509.h>
                     37: 
                     38: #define PKCS5_SALT_LEN 8       /* bytes */
                     39: 
                     40: /**
                     41:  * check the presence of a pattern in a character string, skip if found
                     42:  */
                     43: static bool present(char* pattern, chunk_t* ch)
                     44: {
                     45:        u_int len = strlen(pattern);
                     46: 
                     47:        if (ch->len >= len && strneq(ch->ptr, pattern, len))
                     48:        {
                     49:                *ch = chunk_skip(*ch, len);
                     50:                return TRUE;
                     51:        }
                     52:        return FALSE;
                     53: }
                     54: 
                     55: /**
                     56:  * find a boundary of the form -----tag name-----
                     57:  */
                     58: static bool find_boundary(char* tag, chunk_t *line)
                     59: {
                     60:        chunk_t name = chunk_empty;
                     61: 
                     62:        if (!present("-----", line) ||
                     63:                !present(tag, line) ||
                     64:                !line->len || *line->ptr != ' ')
                     65:        {
                     66:                return FALSE;
                     67:        }
                     68:        *line = chunk_skip(*line, 1);
                     69: 
                     70:        /* extract name */
                     71:        name.ptr = line->ptr;
                     72:        while (line->len > 0)
                     73:        {
                     74:                if (present("-----", line))
                     75:                {
                     76:                        DBG2(DBG_ASN, "  -----%s %.*s-----", tag, (int)name.len, name.ptr);
                     77:                        return TRUE;
                     78:                }
                     79:                line->ptr++;  line->len--;  name.len++;
                     80:        }
                     81:        return FALSE;
                     82: }
                     83: 
                     84: /*
                     85:  * decrypts a passphrase protected encrypted data block
                     86:  */
                     87: static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
                     88:                                                        size_t key_size, chunk_t iv, chunk_t passphrase)
                     89: {
                     90:        hasher_t *hasher;
                     91:        crypter_t *crypter;
                     92:        chunk_t salt = { iv.ptr, PKCS5_SALT_LEN };
                     93:        chunk_t hash;
                     94:        chunk_t decrypted;
                     95:        chunk_t key = {alloca(key_size), key_size};
                     96:        uint8_t padding, *last_padding_pos, *first_padding_pos;
                     97: 
                     98:        /* build key from passphrase and IV */
                     99:        hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
                    100:        if (hasher == NULL)
                    101:        {
                    102:                DBG1(DBG_ASN, "  MD5 hash algorithm not available");
                    103:                return NOT_SUPPORTED;
                    104:        }
                    105:        hash.len = hasher->get_hash_size(hasher);
                    106:        hash.ptr = alloca(hash.len);
                    107:        if (!hasher->get_hash(hasher, passphrase, NULL) ||
                    108:                !hasher->get_hash(hasher, salt, hash.ptr))
                    109:        {
                    110:                return FAILED;
                    111:        }
                    112:        memcpy(key.ptr, hash.ptr, hash.len);
                    113: 
                    114:        if (key.len > hash.len)
                    115:        {
                    116:                if (!hasher->get_hash(hasher, hash, NULL) ||
                    117:                        !hasher->get_hash(hasher, passphrase, NULL) ||
                    118:                        !hasher->get_hash(hasher, salt, hash.ptr))
                    119:                {
                    120:                        return FAILED;
                    121:                }
                    122:                memcpy(key.ptr + hash.len, hash.ptr, key.len - hash.len);
                    123:        }
                    124:        hasher->destroy(hasher);
                    125: 
                    126:        /* decrypt blob */
                    127:        crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size);
                    128:        if (crypter == NULL)
                    129:        {
                    130:                DBG1(DBG_ASN, "  %N encryption algorithm not available",
                    131:                         encryption_algorithm_names, alg);
                    132:                return NOT_SUPPORTED;
                    133:        }
                    134: 
                    135:        if (iv.len != crypter->get_iv_size(crypter) ||
                    136:                blob->len % crypter->get_block_size(crypter))
                    137:        {
                    138:                crypter->destroy(crypter);
                    139:                DBG1(DBG_ASN, "  data size is not multiple of block size");
                    140:                return PARSE_ERROR;
                    141:        }
                    142:        if (!crypter->set_key(crypter, key) ||
                    143:                !crypter->decrypt(crypter, *blob, iv, &decrypted))
                    144:        {
                    145:                crypter->destroy(crypter);
                    146:                return FAILED;
                    147:        }
                    148:        crypter->destroy(crypter);
                    149:        memcpy(blob->ptr, decrypted.ptr, blob->len);
                    150:        chunk_free(&decrypted);
                    151: 
                    152:        /* determine amount of padding */
                    153:        last_padding_pos = blob->ptr + blob->len - 1;
                    154:        padding = *last_padding_pos;
                    155:        if (padding > blob->len)
                    156:        {
                    157:                first_padding_pos = blob->ptr;
                    158:        }
                    159:        else
                    160:        {
                    161:                first_padding_pos = last_padding_pos - padding;
                    162:        }
                    163:        /* check the padding pattern */
                    164:        while (--last_padding_pos > first_padding_pos)
                    165:        {
                    166:                if (*last_padding_pos != padding)
                    167:                {
                    168:                        DBG1(DBG_ASN, "  invalid passphrase");
                    169:                        return INVALID_ARG;
                    170:                }
                    171:        }
                    172:        /* remove padding */
                    173:        blob->len -= padding;
                    174:        return SUCCESS;
                    175: }
                    176: 
                    177: /**
                    178:  * Converts a PEM encoded file into its binary form (RFC 1421, RFC 934)
                    179:  */
                    180: static status_t pem_to_bin(chunk_t *blob, bool *pgp)
                    181: {
                    182:        typedef enum {
                    183:                PEM_PRE    = 0,
                    184:                PEM_MSG    = 1,
                    185:                PEM_HEADER = 2,
                    186:                PEM_BODY   = 3,
                    187:                PEM_POST   = 4,
                    188:                PEM_ABORT  = 5
                    189:        } state_t;
                    190: 
                    191:        encryption_algorithm_t alg = ENCR_UNDEFINED;
                    192:        size_t key_size = 0;
                    193:        bool encrypted = FALSE;
                    194:        state_t state  = PEM_PRE;
                    195:        chunk_t src    = *blob;
                    196:        chunk_t dst    = *blob;
                    197:        chunk_t line   = chunk_empty;
                    198:        chunk_t iv     = chunk_empty;
                    199:        u_char iv_buf[HASH_SIZE_MD5];
                    200:        status_t status = NOT_FOUND;
                    201:        enumerator_t *enumerator;
                    202:        shared_key_t *shared;
                    203: 
                    204:        dst.len = 0;
                    205:        iv.ptr = iv_buf;
                    206:        iv.len = 0;
                    207: 
                    208:        while (fetchline(&src, &line))
                    209:        {
                    210:                if (state == PEM_PRE)
                    211:                {
                    212:                        if (find_boundary("BEGIN", &line))
                    213:                        {
                    214:                                state = PEM_MSG;
                    215:                        }
                    216:                        continue;
                    217:                }
                    218:                else
                    219:                {
                    220:                        if (find_boundary("END", &line))
                    221:                        {
                    222:                                state = PEM_POST;
                    223:                                break;
                    224:                        }
                    225:                        if (state == PEM_MSG)
                    226:                        {
                    227:                                state = PEM_HEADER;
                    228:                                if (memchr(line.ptr, ':', line.len) == NULL)
                    229:                                {
                    230:                                        state = PEM_BODY;
                    231:                                }
                    232:                        }
                    233:                        if (state == PEM_HEADER)
                    234:                        {
                    235:                                err_t ugh = NULL;
                    236:                                chunk_t name  = chunk_empty;
                    237:                                chunk_t value = chunk_empty;
                    238: 
                    239:                                /* an empty line separates HEADER and BODY */
                    240:                                if (line.len == 0)
                    241:                                {
                    242:                                        state = PEM_BODY;
                    243:                                        continue;
                    244:                                }
                    245: 
                    246:                                /* we are looking for a parameter: value pair */
                    247:                                DBG2(DBG_ASN, "  %.*s", (int)line.len, line.ptr);
                    248:                                ugh = extract_parameter_value(&name, &value, &line);
                    249:                                if (ugh != NULL)
                    250:                                {
                    251:                                        continue;
                    252:                                }
                    253:                                if (match("Proc-Type", &name) && value.len && *value.ptr == '4')
                    254:                                {
                    255:                                        encrypted = TRUE;
                    256:                                }
                    257:                                else if (match("DEK-Info", &name))
                    258:                                {
                    259:                                        chunk_t dek;
                    260: 
                    261:                                        if (!extract_token(&dek, ',', &value))
                    262:                                        {
                    263:                                                dek = value;
                    264:                                        }
                    265:                                        if (match("DES-EDE3-CBC", &dek))
                    266:                                        {
                    267:                                                alg = ENCR_3DES;
                    268:                                                key_size = 24;
                    269:                                        }
                    270:                                        else if (match("AES-128-CBC", &dek))
                    271:                                        {
                    272:                                                alg = ENCR_AES_CBC;
                    273:                                                key_size = 16;
                    274:                                        }
                    275:                                        else if (match("AES-192-CBC", &dek))
                    276:                                        {
                    277:                                                alg = ENCR_AES_CBC;
                    278:                                                key_size = 24;
                    279:                                        }
                    280:                                        else if (match("AES-256-CBC", &dek))
                    281:                                        {
                    282:                                                alg = ENCR_AES_CBC;
                    283:                                                key_size = 32;
                    284:                                        }
                    285:                                        else
                    286:                                        {
                    287:                                                DBG1(DBG_ASN, "  encryption algorithm '%.*s'"
                    288:                                                         " not supported", (int)dek.len, dek.ptr);
                    289:                                                return NOT_SUPPORTED;
                    290:                                        }
                    291:                                        if (!eat_whitespace(&value) || value.len > 2*sizeof(iv_buf))
                    292:                                        {
                    293:                                                return PARSE_ERROR;
                    294:                                        }
                    295:                                        iv = chunk_from_hex(value, iv_buf);
                    296:                                }
                    297:                        }
                    298:                        else /* state is PEM_BODY */
                    299:                        {
                    300:                                chunk_t data;
                    301: 
                    302:                                /* remove any trailing whitespace */
                    303:                                if (!extract_token(&data ,' ', &line))
                    304:                                {
                    305:                                        data = line;
                    306:                                }
                    307: 
                    308:                                /* check for PGP armor checksum */
                    309:                                if (data.len && *data.ptr == '=')
                    310:                                {
                    311:                                        *pgp = TRUE;
                    312:                                        data.ptr++;
                    313:                                        data.len--;
                    314:                                        DBG2(DBG_ASN, "  armor checksum: %.*s", (int)data.len,
                    315:                                                 data.ptr);
                    316:                                        continue;
                    317:                                }
                    318: 
                    319:                                if (blob->len - dst.len < data.len / 4 * 3)
                    320:                                {
                    321:                                        state = PEM_ABORT;
                    322:                                }
                    323:                                data = chunk_from_base64(data, dst.ptr);
                    324: 
                    325:                                dst.ptr += data.len;
                    326:                                dst.len += data.len;
                    327:                        }
                    328:                }
                    329:        }
                    330:        /* set length to size of binary blob */
                    331:        blob->len = dst.len;
                    332: 
1.1.1.2 ! misho     333:        if (state != PEM_POST || !blob->len)
1.1       misho     334:        {
                    335:                DBG1(DBG_LIB, "  file coded in unknown format, discarded");
                    336:                return PARSE_ERROR;
                    337:        }
                    338:        if (!encrypted)
                    339:        {
                    340:                return SUCCESS;
                    341:        }
                    342: 
                    343:        enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
                    344:                                                                                        SHARED_PRIVATE_KEY_PASS, NULL, NULL);
                    345:        while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
                    346:        {
                    347:                chunk_t passphrase, chunk;
                    348: 
                    349:                passphrase = shared->get_key(shared);
                    350:                chunk = chunk_clone(*blob);
                    351:                status = pem_decrypt(&chunk, alg, key_size, iv, passphrase);
                    352:                if (status == SUCCESS)
                    353:                {
                    354:                        memcpy(blob->ptr, chunk.ptr, chunk.len);
                    355:                        blob->len = chunk.len;
                    356:                }
                    357:                free(chunk.ptr);
                    358:                if (status != INVALID_ARG)
                    359:                {       /* try again only if passphrase invalid */
                    360:                        break;
                    361:                }
                    362:        }
                    363:        enumerator->destroy(enumerator);
                    364:        return status;
                    365: }
                    366: 
                    367: /**
                    368:  * Check if a blob looks like an ASN1 SEQUENCE or SET with BER indefinite length
                    369:  */
                    370: static bool is_ber_indefinite_length(chunk_t blob)
                    371: {
                    372:        if (blob.len >= 4)
                    373:        {
                    374:                switch (blob.ptr[0])
                    375:                {
                    376:                        case ASN1_SEQUENCE:
                    377:                        case ASN1_SET:
                    378:                                /* BER indefinite length uses 0x80, and is terminated with
                    379:                                 * end-of-content using 0x00,0x00 */
                    380:                                return blob.ptr[1] == 0x80 &&
                    381:                                           blob.ptr[blob.len - 2] == 0 &&
                    382:                                           blob.ptr[blob.len - 1] == 0;
                    383:                        default:
                    384:                                break;
                    385:                }
                    386:        }
                    387:        return FALSE;
                    388: }
                    389: 
                    390: /**
                    391:  * load the credential from a blob
                    392:  */
                    393: static void *load_from_blob(chunk_t blob, credential_type_t type, int subtype,
                    394:                                                        identification_t *subject, x509_flag_t flags)
                    395: {
                    396:        void *cred = NULL;
                    397:        bool pgp = FALSE;
                    398: 
                    399:        blob = chunk_clone(blob);
                    400:        if (!is_ber_indefinite_length(blob) && !is_asn1(blob))
                    401:        {
                    402:                if (pem_to_bin(&blob, &pgp) != SUCCESS)
                    403:                {
                    404:                        chunk_clear(&blob);
                    405:                        return NULL;
                    406:                }
                    407:                if (pgp && type == CRED_PRIVATE_KEY)
                    408:                {
                    409:                        /* PGP encoded keys are parsed with a KEY_ANY key type, as it
                    410:                         * can contain any type of key. However, ipsec.secrets uses
                    411:                         * RSA for PGP keys, which is actually wrong. */
                    412:                        subtype = KEY_ANY;
                    413:                }
                    414:        }
                    415:        /* if CERT_ANY is given, ASN1 encoded blob is handled as X509 */
                    416:        if (type == CRED_CERTIFICATE && subtype == CERT_ANY)
                    417:        {
                    418:                subtype = pgp ? CERT_GPG : CERT_X509;
                    419:        }
                    420:        if (type == CRED_CERTIFICATE && subtype == CERT_TRUSTED_PUBKEY && subject)
                    421:        {
                    422:                cred = lib->creds->create(lib->creds, type, subtype,
                    423:                                                          BUILD_BLOB_ASN1_DER, blob, BUILD_SUBJECT, subject,
                    424:                                                          BUILD_END);
                    425:        }
                    426:        else
                    427:        {
                    428:                cred = lib->creds->create(lib->creds, type, subtype,
                    429:                                                          pgp ? BUILD_BLOB_PGP : BUILD_BLOB_ASN1_DER, blob,
                    430:                                                          flags ? BUILD_X509_FLAG : BUILD_END,
                    431:                                                          flags, BUILD_END);
                    432:        }
                    433:        chunk_clear(&blob);
                    434:        return cred;
                    435: }
                    436: 
                    437: /**
                    438:  * load the credential from a file
                    439:  */
                    440: static void *load_from_file(char *file, credential_type_t type, int subtype,
                    441:                                                        identification_t *subject, x509_flag_t flags)
                    442: {
                    443:        void *cred;
                    444:        chunk_t *chunk;
                    445: 
                    446:        chunk = chunk_map(file, FALSE);
                    447:        if (!chunk)
                    448:        {
                    449:                DBG1(DBG_LIB, "  opening '%s' failed: %s", file, strerror(errno));
                    450:                return NULL;
                    451:        }
                    452:        cred = load_from_blob(*chunk, type, subtype, subject, flags);
                    453:        chunk_unmap(chunk);
                    454:        return cred;
                    455: }
                    456: 
                    457: /**
                    458:  * Load all kind of PEM encoded credentials.
                    459:  */
                    460: static void *pem_load(credential_type_t type, int subtype, va_list args)
                    461: {
                    462:        char *file = NULL;
                    463:        chunk_t pem = chunk_empty;
                    464:        identification_t *subject = NULL;
                    465:        int flags = 0;
                    466: 
                    467:        while (TRUE)
                    468:        {
                    469:                switch (va_arg(args, builder_part_t))
                    470:                {
                    471:                        case BUILD_FROM_FILE:
                    472:                                file = va_arg(args, char*);
                    473:                                continue;
                    474:                        case BUILD_BLOB:
                    475:                        case BUILD_BLOB_PEM:
                    476:                                pem = va_arg(args, chunk_t);
                    477:                                continue;
                    478:                        case BUILD_SUBJECT:
                    479:                                subject = va_arg(args, identification_t*);
                    480:                                continue;
                    481:                        case BUILD_X509_FLAG:
                    482:                                flags = va_arg(args, int);
                    483:                                continue;
                    484:                        case BUILD_END:
                    485:                                break;
                    486:                        default:
                    487:                                return NULL;
                    488:                }
                    489:                break;
                    490:        }
                    491: 
                    492:        if (pem.len)
                    493:        {
                    494:                return load_from_blob(pem, type, subtype, subject, flags);
                    495:        }
                    496:        if (file)
                    497:        {
                    498:                return load_from_file(file, type, subtype, subject, flags);
                    499:        }
                    500:        return NULL;
                    501: }
                    502: 
                    503: /**
                    504:  * Private key PEM loader.
                    505:  */
                    506: private_key_t *pem_private_key_load(key_type_t type, va_list args)
                    507: {
                    508:        return pem_load(CRED_PRIVATE_KEY, type, args);
                    509: }
                    510: 
                    511: /**
                    512:  * Public key PEM loader.
                    513:  */
                    514: public_key_t *pem_public_key_load(key_type_t type, va_list args)
                    515: {
                    516:        return pem_load(CRED_PUBLIC_KEY, type, args);
                    517: }
                    518: 
                    519: /**
                    520:  * Certificate PEM loader.
                    521:  */
                    522: certificate_t *pem_certificate_load(certificate_type_t type, va_list args)
                    523: {
                    524:        return pem_load(CRED_CERTIFICATE, type, args);
                    525: }
                    526: 
                    527: /**
                    528:  * Container PEM loader.
                    529:  */
                    530: container_t *pem_container_load(container_type_t type, va_list args)
                    531: {
                    532:        return pem_load(CRED_CONTAINER, type, args);
                    533: }

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