Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs12/pkcs12_decode.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2013 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include "pkcs12_decode.h"
                     17: 
                     18: #include <utils/debug.h>
                     19: #include <asn1/oid.h>
                     20: #include <asn1/asn1.h>
                     21: #include <asn1/asn1_parser.h>
                     22: #include <credentials/sets/mem_cred.h>
                     23: 
                     24: typedef struct private_pkcs12_t private_pkcs12_t;
                     25: 
                     26: /**
                     27:  * Private data of a pkcs12_t object
                     28:  */
                     29: struct private_pkcs12_t {
                     30: 
                     31:        /**
                     32:         * Public interface
                     33:         */
                     34:        pkcs12_t public;
                     35: 
                     36:        /**
                     37:         * Contained credentials
                     38:         */
                     39:        mem_cred_t *creds;
                     40: };
                     41: 
                     42: METHOD(container_t, get_type, container_type_t,
                     43:        private_pkcs12_t *this)
                     44: {
                     45:        return CONTAINER_PKCS12;
                     46: }
                     47: 
                     48: METHOD(container_t, get_data, bool,
                     49:        private_pkcs12_t *this, chunk_t *data)
                     50: {
                     51:        /* we could return the content of the outer-most PKCS#7 container (authSafe)
                     52:         * don't really see the point though */
                     53:        return FALSE;
                     54: }
                     55: 
                     56: METHOD(container_t, get_encoding, bool,
                     57:        private_pkcs12_t *this, chunk_t *encoding)
                     58: {
                     59:        /* similar to get_data() we don't have any use for it at the moment */
                     60:        return FALSE;
                     61: }
                     62: 
                     63: METHOD(pkcs12_t, create_cert_enumerator, enumerator_t*,
                     64:        private_pkcs12_t *this)
                     65: {
                     66:        return this->creds->set.create_cert_enumerator(&this->creds->set, CERT_ANY,
                     67:                                                                                                   KEY_ANY, NULL, FALSE);
                     68: }
                     69: 
                     70: METHOD(pkcs12_t, create_key_enumerator, enumerator_t*,
                     71:        private_pkcs12_t *this)
                     72: {
                     73:        return this->creds->set.create_private_enumerator(&this->creds->set,
                     74:                                                                                                          KEY_ANY, NULL);
                     75: }
                     76: 
                     77: METHOD(container_t, destroy, void,
                     78:        private_pkcs12_t *this)
                     79: {
                     80:        this->creds->destroy(this->creds);
                     81:        free(this);
                     82: }
                     83: 
                     84: static private_pkcs12_t *pkcs12_create()
                     85: {
                     86:        private_pkcs12_t *this;
                     87: 
                     88:        INIT(this,
                     89:                .public = {
                     90:                        .container = {
                     91:                                .get_type = _get_type,
                     92:                                .create_signature_enumerator = (void*)enumerator_create_empty,
                     93:                                .get_data = _get_data,
                     94:                                .get_encoding = _get_encoding,
                     95:                                .destroy = _destroy,
                     96:                        },
                     97:                        .create_cert_enumerator = _create_cert_enumerator,
                     98:                        .create_key_enumerator = _create_key_enumerator,
                     99:                },
                    100:                .creds = mem_cred_create(),
                    101:        );
                    102:        return this;
                    103: }
                    104: 
                    105: /**
                    106:  * ASN.1 definition of an CertBag structure
                    107:  */
                    108: static const asn1Object_t certBagObjects[] = {
                    109:        { 0, "CertBag",                 ASN1_SEQUENCE,          ASN1_BODY                       }, /* 0 */
                    110:        { 1,   "certId",                ASN1_OID,                       ASN1_BODY                       }, /* 1 */
                    111:        { 1,   "certValue",             ASN1_CONTEXT_C_0,       ASN1_BODY                       }, /* 2 */
                    112:        { 0, "exit",                    ASN1_EOC,                       ASN1_EXIT                       }
                    113: };
                    114: #define CERT_BAG_ID    1
                    115: #define CERT_BAG_VALUE         2
                    116: 
                    117: /**
                    118:  * Parse a CertBag structure and extract certificate
                    119:  */
                    120: static bool add_certificate(private_pkcs12_t *this, int level0, chunk_t blob)
                    121: {
                    122:        asn1_parser_t *parser;
                    123:        chunk_t object;
                    124:        int objectID;
                    125:        int oid = OID_UNKNOWN;
                    126:        bool success = FALSE;
                    127: 
                    128:        parser = asn1_parser_create(certBagObjects, blob);
                    129:        parser->set_top_level(parser, level0);
                    130: 
                    131:        while (parser->iterate(parser, &objectID, &object))
                    132:        {
                    133:                switch (objectID)
                    134:                {
                    135:                        case CERT_BAG_ID:
                    136:                                oid = asn1_known_oid(object);
                    137:                                break;
                    138:                        case CERT_BAG_VALUE:
                    139:                        {
                    140:                                if (oid == OID_X509_CERTIFICATE &&
                    141:                                        asn1_parse_simple_object(&object, ASN1_OCTET_STRING,
                    142:                                                                parser->get_level(parser)+1, "x509Certificate"))
                    143:                                {
                    144:                                        certificate_t *cert;
                    145: 
                    146:                                        DBG2(DBG_ASN, "-- > parsing certificate from PKCS#12");
                    147:                                        cert = lib->creds->create(lib->creds,
                    148:                                                                                          CRED_CERTIFICATE, CERT_X509,
                    149:                                                                                          BUILD_BLOB_ASN1_DER, object,
                    150:                                                                                          BUILD_END);
                    151:                                        if (cert)
                    152:                                        {
                    153:                                                this->creds->add_cert(this->creds, FALSE, cert);
                    154:                                                DBG2(DBG_ASN, "-- < --");
                    155:                                        }
                    156:                                        else
                    157:                                        {
                    158:                                                DBG2(DBG_ASN, "-- < failed parsing certificate from "
                    159:                                                         "PKCS#12");
                    160:                                        }
                    161:                                }
                    162:                                break;
                    163:                        }
                    164:                }
                    165:        }
                    166:        success = parser->success(parser);
                    167:        parser->destroy(parser);
                    168:        return success;
                    169: }
                    170: 
                    171: /**
                    172:  * ASN.1 definition of an AuthenticatedSafe structure
                    173:  */
                    174: static const asn1Object_t safeContentsObjects[] = {
                    175:        { 0, "SafeContents",    ASN1_SEQUENCE,          ASN1_LOOP                       }, /* 0 */
                    176:        { 1,   "SafeBag",               ASN1_SEQUENCE,          ASN1_BODY                       }, /* 1 */
                    177:        { 2,     "bagId",               ASN1_OID,                       ASN1_BODY                       }, /* 2 */
                    178:        { 2,     "bagValue",    ASN1_CONTEXT_C_0,       ASN1_BODY                       }, /* 3 */
                    179:        { 2,     "bagAttr",             ASN1_SET,                       ASN1_OPT|ASN1_RAW       }, /* 4 */
                    180:        { 2,     "end opt",             ASN1_EOC,                       ASN1_END                        }, /* 5 */
                    181:        { 0, "end loop",                ASN1_EOC,                       ASN1_END                        }, /* 6 */
                    182:        { 0, "exit",                    ASN1_EOC,                       ASN1_EXIT                       }
                    183: };
                    184: #define SAFE_BAG_ID    2
                    185: #define SAFE_BAG_VALUE         3
                    186: 
                    187: /**
                    188:  * Parse a SafeContents structure and extract credentials
                    189:  */
                    190: static bool parse_safe_contents(private_pkcs12_t *this, int level0,
                    191:                                                                chunk_t blob)
                    192: {
                    193:        asn1_parser_t *parser;
                    194:        chunk_t object;
                    195:        int objectID;
                    196:        int oid = OID_UNKNOWN;
                    197:        bool success = FALSE;
                    198: 
                    199:        parser = asn1_parser_create(safeContentsObjects, blob);
                    200:        parser->set_top_level(parser, level0);
                    201: 
                    202:        while (parser->iterate(parser, &objectID, &object))
                    203:        {
                    204:                switch (objectID)
                    205:                {
                    206:                        case SAFE_BAG_ID:
                    207:                                oid = asn1_known_oid(object);
                    208:                                break;
                    209:                        case SAFE_BAG_VALUE:
                    210:                        {
                    211:                                switch (oid)
                    212:                                {
                    213:                                        case OID_P12_CERT_BAG:
                    214:                                        {
                    215:                                                add_certificate(this, parser->get_level(parser)+1,
                    216:                                                                                object);
                    217:                                                break;
                    218:                                        }
                    219:                                        case OID_P12_KEY_BAG:
                    220:                                        case OID_P12_PKCS8_KEY_BAG:
                    221:                                        {
                    222:                                                private_key_t *key;
                    223: 
                    224:                                                DBG2(DBG_ASN, "-- > parsing private key from PKCS#12");
                    225:                                                key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
                    226:                                                                                KEY_ANY, BUILD_BLOB_ASN1_DER, object,
                    227:                                                                                BUILD_END);
                    228:                                                if (key)
                    229:                                                {
                    230:                                                        this->creds->add_key(this->creds, key);
                    231:                                                        DBG2(DBG_ASN, "-- < --");
                    232:                                                }
                    233:                                                else
                    234:                                                {
                    235:                                                        DBG2(DBG_ASN, "-- < failed parsing private key "
                    236:                                                                 "from PKCS#12");
                    237:                                                }
                    238:                                        }
                    239:                                        default:
                    240:                                                break;
                    241:                                }
                    242:                                break;
                    243:                        }
                    244:                }
                    245:        }
                    246:        success = parser->success(parser);
                    247:        parser->destroy(parser);
                    248:        return success;
                    249: }
                    250: 
                    251: /**
                    252:  * ASN.1 definition of an AuthenticatedSafe structure
                    253:  */
                    254: static const asn1Object_t authenticatedSafeObjects[] = {
                    255:        { 0, "AuthenticatedSafe",       ASN1_SEQUENCE,  ASN1_LOOP       }, /* 0 */
                    256:        { 1,   "ContentInfo",           ASN1_SEQUENCE,  ASN1_OBJ        }, /* 1 */
                    257:        { 0, "end loop",                        ASN1_EOC,               ASN1_END        }, /* 2 */
                    258:        { 0, "exit",                            ASN1_EOC,               ASN1_EXIT       }
                    259: };
                    260: #define AUTHENTICATED_SAFE_DATA        1
                    261: 
                    262: /**
                    263:  * Parse an AuthenticatedSafe structure
                    264:  */
                    265: static bool parse_authenticated_safe(private_pkcs12_t *this, chunk_t blob)
                    266: {
                    267:        asn1_parser_t *parser;
                    268:        chunk_t object;
                    269:        int objectID;
                    270:        bool success = FALSE;
                    271: 
                    272:        parser = asn1_parser_create(authenticatedSafeObjects, blob);
                    273: 
                    274:        while (parser->iterate(parser, &objectID, &object))
                    275:        {
                    276:                switch (objectID)
                    277:                {
                    278:                        case AUTHENTICATED_SAFE_DATA:
                    279:                        {
                    280:                                container_t *container;
                    281:                                chunk_t data;
                    282: 
                    283:                                container = lib->creds->create(lib->creds, CRED_CONTAINER,
                    284:                                                                                CONTAINER_PKCS7, BUILD_BLOB_ASN1_DER,
                    285:                                                                                object, BUILD_END);
                    286:                                if (!container)
                    287:                                {
                    288:                                        goto end;
                    289:                                }
                    290:                                switch (container->get_type(container))
                    291:                                {
                    292:                                        case CONTAINER_PKCS7_DATA:
                    293:                                        case CONTAINER_PKCS7_ENCRYPTED_DATA:
                    294:                                        case CONTAINER_PKCS7_ENVELOPED_DATA:
                    295:                                                if (container->get_data(container, &data))
                    296:                                                {
                    297:                                                        break;
                    298:                                                }
                    299:                                                /* fall-through */
                    300:                                        default:
                    301:                                                container->destroy(container);
                    302:                                                goto end;
                    303:                                }
                    304:                                container->destroy(container);
                    305: 
                    306:                                if (!parse_safe_contents(this, parser->get_level(parser)+1,
                    307:                                                                                 data))
                    308:                                {
                    309:                                        chunk_free(&data);
                    310:                                        goto end;
                    311:                                }
                    312:                                chunk_free(&data);
                    313:                                break;
                    314:                        }
                    315:                }
                    316:        }
                    317:        success = parser->success(parser);
                    318: end:
                    319:        parser->destroy(parser);
                    320:        return success;
                    321: }
                    322: 
                    323: /**
                    324:  * Verify the given MAC with available passwords.
                    325:  */
                    326: static bool verify_mac(hash_algorithm_t hash, chunk_t salt,
                    327:                                           uint64_t iterations, chunk_t data, chunk_t mac)
                    328: {
                    329:        integrity_algorithm_t integ;
                    330:        enumerator_t *enumerator;
                    331:        shared_key_t *shared;
                    332:        signer_t *signer;
                    333:        chunk_t key, calculated;
                    334:        bool success = FALSE;
                    335: 
                    336:        integ = hasher_algorithm_to_integrity(hash, mac.len);
                    337:        signer = lib->crypto->create_signer(lib->crypto, integ);
                    338:        if (!signer)
                    339:        {
                    340:                return FALSE;
                    341:        }
                    342:        key = chunk_alloca(signer->get_key_size(signer));
                    343:        calculated = chunk_alloca(signer->get_block_size(signer));
                    344: 
                    345:        enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
                    346:                                                                                SHARED_PRIVATE_KEY_PASS, NULL, NULL);
                    347:        while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
                    348:        {
                    349:                if (!pkcs12_derive_key(hash, shared->get_key(shared), salt, iterations,
                    350:                                                           PKCS12_KEY_MAC, key))
                    351:                {
                    352:                        break;
                    353:                }
                    354:                if (!signer->set_key(signer, key) ||
                    355:                        !signer->get_signature(signer, data, calculated.ptr))
                    356:                {
                    357:                        break;
                    358:                }
                    359:                if (chunk_equals_const(mac, calculated))
                    360:                {
                    361:                        success = TRUE;
                    362:                        break;
                    363:                }
                    364:        }
                    365:        enumerator->destroy(enumerator);
                    366:        signer->destroy(signer);
                    367:        return success;
                    368: }
                    369: 
                    370: /**
                    371:  * ASN.1 definition of digestInfo
                    372:  */
                    373: static const asn1Object_t digestInfoObjects[] = {
                    374:        { 0, "digestInfo",                      ASN1_SEQUENCE,          ASN1_OBJ        }, /*  0 */
                    375:        { 1,   "digestAlgorithm",       ASN1_EOC,                       ASN1_RAW        }, /*  1 */
                    376:        { 1,   "digest",                        ASN1_OCTET_STRING,      ASN1_BODY       }, /*  2 */
                    377:        { 0, "exit",                            ASN1_EOC,                       ASN1_EXIT       }
                    378: };
                    379: #define DIGEST_INFO_ALGORITHM          1
                    380: #define DIGEST_INFO_DIGEST                     2
                    381: 
                    382: /**
                    383:  * Parse a digestInfo structure
                    384:  */
                    385: static bool parse_digest_info(chunk_t blob, int level0, hash_algorithm_t *hash,
                    386:                                                          chunk_t *digest)
                    387: {
                    388:        asn1_parser_t *parser;
                    389:        chunk_t object;
                    390:        int objectID;
                    391:        bool success;
                    392: 
                    393:        parser = asn1_parser_create(digestInfoObjects, blob);
                    394:        parser->set_top_level(parser, level0);
                    395: 
                    396:        while (parser->iterate(parser, &objectID, &object))
                    397:        {
                    398:                switch (objectID)
                    399: 
                    400:                {
                    401:                        case DIGEST_INFO_ALGORITHM:
                    402:                        {
                    403:                                int oid = asn1_parse_algorithmIdentifier(object,
                    404:                                                                         parser->get_level(parser)+1, NULL);
                    405: 
                    406:                                *hash = hasher_algorithm_from_oid(oid);
                    407:                                break;
                    408:                        }
                    409:                        case DIGEST_INFO_DIGEST:
                    410:                        {
                    411:                                *digest = object;
                    412:                                break;
                    413:                        }
                    414:                        default:
                    415:                                break;
                    416:                }
                    417:        }
                    418:        success = parser->success(parser);
                    419:        parser->destroy(parser);
                    420:        return success;
                    421: }
                    422: 
                    423: /**
                    424:  * ASN.1 definition of a PFX structure
                    425:  */
                    426: static const asn1Object_t PFXObjects[] = {
                    427:        { 0, "PFX",                             ASN1_SEQUENCE,          ASN1_NONE                       }, /* 0 */
                    428:        { 1,   "version",               ASN1_INTEGER,           ASN1_BODY                       }, /* 1 */
                    429:        { 1,   "authSafe",              ASN1_SEQUENCE,          ASN1_OBJ                        }, /* 2 */
                    430:        { 1,   "macData",               ASN1_SEQUENCE,          ASN1_OPT|ASN1_BODY      }, /* 3 */
                    431:        { 2,     "mac",                 ASN1_SEQUENCE,          ASN1_RAW                        }, /* 4 */
                    432:        { 2,     "macSalt",             ASN1_OCTET_STRING,      ASN1_BODY                       }, /* 5 */
                    433:        { 2,     "iterations",  ASN1_INTEGER,           ASN1_DEF|ASN1_BODY      }, /* 6 */
                    434:        { 1,   "end opt",               ASN1_EOC,                       ASN1_END                        }, /* 7 */
                    435:        { 0, "exit",                    ASN1_EOC,                       ASN1_EXIT                       }
                    436: };
                    437: #define PFX_AUTH_SAFE  2
                    438: #define PFX_MAC                        4
                    439: #define PFX_SALT               5
                    440: #define PFX_ITERATIONS 6
                    441: 
                    442: /**
                    443:  * Parse an ASN.1 encoded PFX structure
                    444:  */
                    445: static bool parse_PFX(private_pkcs12_t *this, chunk_t blob)
                    446: {
                    447:        asn1_parser_t *parser;
                    448:        int objectID;
                    449:        chunk_t object, auth_safe, digest = chunk_empty, salt = chunk_empty,
                    450:                        data = chunk_empty;
                    451:        hash_algorithm_t hash = HASH_UNKNOWN;
                    452:        container_t *container = NULL;
                    453:        uint64_t iterations = 0;
                    454:        bool success = FALSE;
                    455: 
                    456:        parser = asn1_parser_create(PFXObjects, blob);
                    457: 
                    458:        while (parser->iterate(parser, &objectID, &object))
                    459:        {
                    460:                switch (objectID)
                    461:                {
                    462:                        case PFX_AUTH_SAFE:
                    463:                        {
                    464:                                auth_safe = object;
                    465:                                break;
                    466:                        }
                    467:                        case PFX_MAC:
                    468:                        {
                    469:                                if (!parse_digest_info(object, parser->get_level(parser)+1,
                    470:                                                                           &hash, &digest))
                    471:                                {
                    472:                                        goto end_parse;
                    473:                                }
                    474:                                break;
                    475:                        }
                    476:                        case PFX_SALT:
                    477:                        {
                    478:                                salt = object;
                    479:                                break;
                    480:                        }
                    481:                        case PFX_ITERATIONS:
                    482:                        {
                    483:                                iterations = object.len ? asn1_parse_integer_uint64(object) : 1;
                    484:                                break;
                    485:                        }
                    486:                }
                    487:        }
                    488:        success = parser->success(parser);
                    489: 
                    490: end_parse:
                    491:        parser->destroy(parser);
                    492:        if (!success)
                    493:        {
                    494:                return FALSE;
                    495:        }
                    496: 
                    497:        success = FALSE;
                    498:        DBG2(DBG_ASN, "-- > --");
                    499:        container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
                    500:                                                                   BUILD_BLOB_ASN1_DER, auth_safe, BUILD_END);
                    501:        if (container && container->get_data(container, &data))
                    502:        {
                    503:                if (hash != HASH_UNKNOWN)
                    504:                {
                    505:                        if (container->get_type(container) != CONTAINER_PKCS7_DATA)
                    506:                        {
                    507:                                goto end;
                    508:                        }
                    509:                        if (!verify_mac(hash, salt, iterations, data, digest))
                    510:                        {
                    511:                                DBG1(DBG_ASN, "  MAC verification of PKCS#12 container failed");
                    512:                                goto end;
                    513:                        }
                    514:                }
                    515:                else
                    516:                {
                    517:                        enumerator_t *enumerator;
                    518:                        auth_cfg_t *auth;
                    519: 
                    520:                        if (container->get_type(container) != CONTAINER_PKCS7_SIGNED_DATA)
                    521:                        {
                    522:                                goto end;
                    523:                        }
                    524:                        enumerator = container->create_signature_enumerator(container);
                    525:                        if (!enumerator->enumerate(enumerator, &auth))
                    526:                        {
                    527:                                DBG1(DBG_ASN, "  signature verification of PKCS#12 container "
                    528:                                         "failed");
                    529:                                enumerator->destroy(enumerator);
                    530:                                goto end;
                    531:                        }
                    532:                        enumerator->destroy(enumerator);
                    533:                }
                    534:                success = parse_authenticated_safe(this, data);
                    535:        }
                    536: end:
                    537:        DBG2(DBG_ASN, "-- < --");
                    538:        DESTROY_IF(container);
                    539:        chunk_free(&data);
                    540:        return success;
                    541: }
                    542: 
                    543: /**
                    544:  * See header.
                    545:  */
                    546: pkcs12_t *pkcs12_decode(container_type_t type, va_list args)
                    547: {
                    548:        private_pkcs12_t *this;
                    549:        chunk_t blob = chunk_empty;
                    550: 
                    551:        while (TRUE)
                    552:        {
                    553:                switch (va_arg(args, builder_part_t))
                    554:                {
                    555:                        case BUILD_BLOB_ASN1_DER:
                    556:                                blob = va_arg(args, chunk_t);
                    557:                                continue;
                    558:                        case BUILD_END:
                    559:                                break;
                    560:                        default:
                    561:                                return NULL;
                    562:                }
                    563:                break;
                    564:        }
                    565:        if (blob.len)
                    566:        {
                    567:                if (blob.len >= 2 &&
                    568:                        blob.ptr[0] == ASN1_SEQUENCE && blob.ptr[1] == 0x80)
                    569:                {       /* looks like infinite length BER encoding, but we can't handle it.
                    570:                         */
                    571:                        return NULL;
                    572:                }
                    573:                this = pkcs12_create();
                    574:                if (parse_PFX(this, blob))
                    575:                {
                    576:                        return &this->public;
                    577:                }
                    578:                destroy(this);
                    579:        }
                    580:        return NULL;
                    581: }

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