Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_pkcs7.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2012 Martin Willi
                      3:  * Copyright (C) 2012 revosec AG
                      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 <openssl/opensslv.h>
                     17: #include <openssl/opensslconf.h>
                     18: 
                     19: #if OPENSSL_VERSION_NUMBER >= 0x0090807fL
                     20: #ifndef OPENSSL_NO_CMS
                     21: 
                     22: #include "openssl_pkcs7.h"
                     23: #include "openssl_util.h"
                     24: 
                     25: #include <library.h>
                     26: #include <utils/debug.h>
                     27: #include <asn1/oid.h>
                     28: #include <credentials/sets/mem_cred.h>
                     29: 
                     30: #include <openssl/cms.h>
                     31: 
                     32: #if OPENSSL_VERSION_NUMBER < 0x10100000L
                     33: #define X509_ATTRIBUTE_get0_object(attr) ({ (attr)->object; })
                     34: #endif
                     35: 
                     36: typedef struct private_openssl_pkcs7_t private_openssl_pkcs7_t;
                     37: 
                     38: /**
                     39:  * Private data of an openssl_pkcs7_t object.
                     40:  */
                     41: struct private_openssl_pkcs7_t {
                     42: 
                     43:        /**
                     44:         * Public pkcs7_t interface.
                     45:         */
                     46:        pkcs7_t public;
                     47: 
                     48:        /**
                     49:         * Type of this container
                     50:         */
                     51:        container_type_t type;
                     52: 
                     53:        /**
                     54:         * OpenSSL CMS structure
                     55:         */
                     56:        CMS_ContentInfo *cms;
                     57: };
                     58: 
                     59: /**
                     60:  * OpenSSL does not allow us to read the signature to verify it with our own
                     61:  * crypto API. We define the internal CMS_SignerInfo structure here to get it.
                     62:  */
                     63: struct CMS_SignerInfo_st {
                     64:        long version;
                     65:        void *sid;
                     66:        X509_ALGOR *digestAlgorithm;
                     67:        STACK_OF(X509_ATTRIBUTE) *signedAttrs;
                     68:        X509_ALGOR *signatureAlgorithm;
                     69:        ASN1_OCTET_STRING *signature;
                     70:        /* and more... */
                     71: };
                     72: 
                     73: /**
                     74:  * And we also need access to the wrappend CMS_KeyTransRecipientInfo to
                     75:  * read the encrypted key
                     76:  */
                     77: struct CMS_KeyTransRecipientInfo_st {
                     78:        long version;
                     79:        void *rid;
                     80:        X509_ALGOR *keyEncryptionAlgorithm;
                     81:        ASN1_OCTET_STRING *encryptedKey;
                     82: };
                     83: 
                     84: struct CMS_RecipientInfo_st {
                     85:        int type;
                     86:        struct CMS_KeyTransRecipientInfo_st *ktri;
                     87:        /* and more in union... */
                     88: };
                     89: 
                     90: struct CMS_EncryptedContentInfo_st {
                     91:        ASN1_OBJECT *contentType;
                     92:        X509_ALGOR *contentEncryptionAlgorithm;
                     93:        ASN1_OCTET_STRING *encryptedContent;
                     94:        /* and more... */
                     95: };
                     96: 
                     97: struct CMS_EnvelopedData_st {
                     98:        long version;
                     99:        void *originatorInfo;
                    100:        STACK_OF(CMS_RecipientInfo) *recipientInfos;
                    101:        struct CMS_EncryptedContentInfo_st *encryptedContentInfo;
                    102:        /* and more... */
                    103: };
                    104: 
                    105: struct CMS_ContentInfo_st {
                    106:        ASN1_OBJECT *contentType;
                    107:        struct CMS_EnvelopedData_st *envelopedData;
                    108:        /* and more in union... */
                    109: };
                    110: 
                    111: /**
                    112:  * We can't include asn1.h, declare function prototypes directly
                    113:  */
                    114: chunk_t asn1_wrap(int, const char *mode, ...);
                    115: int asn1_unwrap(chunk_t*, chunk_t*);
                    116: 
                    117: /**
                    118:  * Enumerator over certificates
                    119:  */
                    120: typedef struct {
                    121:        /** implements enumerator_t */
                    122:        enumerator_t public;
                    123:        /** Stack of X509 certificates */
                    124:        STACK_OF(X509) *certs;
                    125:        /** current enumerator position in certificates */
                    126:        int i;
                    127:        /** currently enumerating certificate_t */
                    128:        certificate_t *cert;
                    129: } cert_enumerator_t;
                    130: 
                    131: METHOD(enumerator_t, cert_destroy, void,
                    132:        cert_enumerator_t *this)
                    133: {
                    134:        DESTROY_IF(this->cert);
                    135:        free(this);
                    136: }
                    137: 
                    138: METHOD(enumerator_t, cert_enumerate, bool,
                    139:        cert_enumerator_t *this, va_list args)
                    140: {
                    141:        certificate_t **out;
                    142: 
                    143:        VA_ARGS_VGET(args, out);
                    144: 
                    145:        if (!this->certs)
                    146:        {
                    147:                return FALSE;
                    148:        }
                    149:        while (this->i < sk_X509_num(this->certs))
                    150:        {
                    151:                chunk_t encoding;
                    152:                X509 *x509;
                    153: 
                    154:                /* clean up previous round */
                    155:                DESTROY_IF(this->cert);
                    156:                this->cert = NULL;
                    157: 
                    158:                x509 = sk_X509_value(this->certs, this->i++);
                    159:                encoding = openssl_i2chunk(X509, x509);
                    160:                this->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
                    161:                                                                                BUILD_BLOB_ASN1_DER, encoding,
                    162:                                                                                BUILD_END);
                    163:                free(encoding.ptr);
                    164:                if (!this->cert)
                    165:                {
                    166:                        continue;
                    167:                }
                    168:                *out = this->cert;
                    169:                return TRUE;
                    170:        }
                    171:        return FALSE;
                    172: }
                    173: 
                    174: METHOD(pkcs7_t, create_cert_enumerator, enumerator_t*,
                    175:        private_openssl_pkcs7_t *this)
                    176: {
                    177:        cert_enumerator_t *enumerator;
                    178: 
                    179:        if (this->type == CONTAINER_PKCS7_SIGNED_DATA)
                    180:        {
                    181:                INIT(enumerator,
                    182:                        .public = {
                    183:                                .enumerate = enumerator_enumerate_default,
                    184:                                .venumerate = _cert_enumerate,
                    185:                                .destroy = _cert_destroy,
                    186:                        },
                    187:                        .certs = CMS_get1_certs(this->cms),
                    188:                );
                    189:                return &enumerator->public;
                    190:        }
                    191:        return enumerator_create_empty();
                    192: }
                    193: 
                    194: /**
                    195:  * Enumerator for signatures
                    196:  */
                    197: typedef struct {
                    198:        /** implements enumerator_t */
                    199:        enumerator_t public;
                    200:        /** Stack of signerinfos */
                    201:        STACK_OF(CMS_SignerInfo) *signers;
                    202:        /** current enumerator position in signers */
                    203:        int i;
                    204:        /** currently enumerating auth config */
                    205:        auth_cfg_t *auth;
                    206:        /** full CMS */
                    207:        CMS_ContentInfo *cms;
                    208:        /** credential set containing wrapped certificates */
                    209:        mem_cred_t *creds;
                    210: } signature_enumerator_t;
                    211: 
                    212: /**
                    213:  * Verify signerInfo signature
                    214:  */
                    215: static auth_cfg_t *verify_signature(CMS_SignerInfo *si, int hash_oid)
                    216: {
                    217:        enumerator_t *enumerator;
                    218:        public_key_t *key;
                    219:        certificate_t *cert;
                    220:        auth_cfg_t *auth, *found = NULL;
                    221:        identification_t *issuer, *serial;
                    222:        chunk_t attrs = chunk_empty, sig, attr;
                    223:        X509_NAME *name;
                    224:        ASN1_INTEGER *snr;
                    225:        int i;
                    226: 
                    227:        if (CMS_SignerInfo_get0_signer_id(si, NULL, &name, &snr) != 1)
                    228:        {
                    229:                return NULL;
                    230:        }
                    231:        issuer = openssl_x509_name2id(name);
                    232:        if (!issuer)
                    233:        {
                    234:                return NULL;
                    235:        }
                    236:        serial = identification_create_from_encoding(
                    237:                                                                        ID_KEY_ID, openssl_asn1_str2chunk(snr));
                    238: 
                    239:        /* reconstruct DER encoded attributes to verify signature */
                    240:        for (i = 0; i < CMS_signed_get_attr_count(si); i++)
                    241:        {
                    242:                attr = openssl_i2chunk(X509_ATTRIBUTE, CMS_signed_get_attr(si, i));
                    243:                attrs = chunk_cat("mm", attrs, attr);
                    244:        }
                    245:        /* wrap in a ASN1_SET */
                    246:        attrs = asn1_wrap(0x31, "m", attrs);
                    247: 
                    248:        /* TODO: find a better way to access and verify the signature */
                    249:        sig = openssl_asn1_str2chunk(si->signature);
                    250:        enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
                    251:                                                                                                                KEY_RSA, serial, FALSE);
                    252:        while (enumerator->enumerate(enumerator, &cert, &auth))
                    253:        {
                    254:                if (issuer->equals(issuer, cert->get_issuer(cert)))
                    255:                {
                    256:                        key = cert->get_public_key(cert);
                    257:                        if (key)
                    258:                        {
                    259:                                if (key->verify(key, signature_scheme_from_oid(hash_oid), NULL,
                    260:                                                                attrs, sig))
                    261:                                {
                    262:                                        found = auth->clone(auth);
                    263:                                        key->destroy(key);
                    264:                                        break;
                    265:                                }
                    266:                                key->destroy(key);
                    267:                        }
                    268:                }
                    269:        }
                    270:        enumerator->destroy(enumerator);
                    271:        issuer->destroy(issuer);
                    272:        serial->destroy(serial);
                    273:        free(attrs.ptr);
                    274: 
                    275:        return found;
                    276: }
                    277: 
                    278: /**
                    279:  * Verify the message digest in the signerInfo attributes
                    280:  */
                    281: static bool verify_digest(CMS_ContentInfo *cms, CMS_SignerInfo *si, int hash_oid)
                    282: {
                    283:        ASN1_OCTET_STRING *os, **osp;
                    284:        hash_algorithm_t hash_alg;
                    285:        chunk_t digest, content, hash;
                    286:        hasher_t *hasher;
                    287: 
                    288:        os = CMS_signed_get0_data_by_OBJ(si,
                    289:                                OBJ_nid2obj(NID_pkcs9_messageDigest), -3, V_ASN1_OCTET_STRING);
                    290:        if (!os)
                    291:        {
                    292:                return FALSE;
                    293:        }
                    294:        digest = openssl_asn1_str2chunk(os);
                    295:        osp = CMS_get0_content(cms);
                    296:        if (!osp)
                    297:        {
                    298:                return FALSE;
                    299:        }
                    300:        content = openssl_asn1_str2chunk(*osp);
                    301: 
                    302:        hash_alg = hasher_algorithm_from_oid(hash_oid);
                    303:        hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
                    304:        if (!hasher)
                    305:        {
                    306:                DBG1(DBG_LIB, "hash algorithm %N not supported",
                    307:                         hash_algorithm_names, hash_alg);
                    308:                return FALSE;
                    309:        }
                    310:        if (!hasher->allocate_hash(hasher, content, &hash))
                    311:        {
                    312:                hasher->destroy(hasher);
                    313:                return FALSE;
                    314:        }
                    315:        hasher->destroy(hasher);
                    316: 
                    317:        if (!chunk_equals_const(digest, hash))
                    318:        {
                    319:                free(hash.ptr);
                    320:                DBG1(DBG_LIB, "invalid messageDigest");
                    321:                return FALSE;
                    322:        }
                    323:        free(hash.ptr);
                    324:        return TRUE;
                    325: }
                    326: 
                    327: METHOD(enumerator_t, signature_enumerate, bool,
                    328:        signature_enumerator_t *this, va_list args)
                    329: {
                    330:        auth_cfg_t **out;
                    331: 
                    332:        VA_ARGS_VGET(args, out);
                    333: 
                    334:        if (!this->signers)
                    335:        {
                    336:                return FALSE;
                    337:        }
                    338:        while (this->i < sk_CMS_SignerInfo_num(this->signers))
                    339:        {
                    340:                CMS_SignerInfo *si;
                    341:                X509_ALGOR *digest, *sig;
                    342:                int hash_oid;
                    343: 
                    344:                /* clean up previous round */
                    345:                DESTROY_IF(this->auth);
                    346:                this->auth = NULL;
                    347: 
                    348:                si = sk_CMS_SignerInfo_value(this->signers, this->i++);
                    349: 
                    350:                CMS_SignerInfo_get0_algs(si, NULL, NULL, &digest, &sig);
                    351:                hash_oid = openssl_asn1_known_oid(digest->algorithm);
                    352:                if (openssl_asn1_known_oid(sig->algorithm) != OID_RSA_ENCRYPTION)
                    353:                {
                    354:                        DBG1(DBG_LIB, "only RSA digest encryption supported");
                    355:                        continue;
                    356:                }
                    357:                this->auth = verify_signature(si, hash_oid);
                    358:                if (!this->auth)
                    359:                {
                    360:                        DBG1(DBG_LIB, "unable to verify pkcs7 attributes signature");
                    361:                        continue;
                    362:                }
                    363:                if (!verify_digest(this->cms, si, hash_oid))
                    364:                {
                    365:                        continue;
                    366:                }
                    367:                *out = this->auth;
                    368:                return TRUE;
                    369:        }
                    370:        return FALSE;
                    371: }
                    372: 
                    373: METHOD(enumerator_t, signature_destroy, void,
                    374:        signature_enumerator_t *this)
                    375: {
                    376:        lib->credmgr->remove_local_set(lib->credmgr, &this->creds->set);
                    377:        this->creds->destroy(this->creds);
                    378:        DESTROY_IF(this->auth);
                    379:        free(this);
                    380: }
                    381: 
                    382: METHOD(container_t, create_signature_enumerator, enumerator_t*,
                    383:        private_openssl_pkcs7_t *this)
                    384: {
                    385:        signature_enumerator_t *enumerator;
                    386: 
                    387:        if (this->type == CONTAINER_PKCS7_SIGNED_DATA)
                    388:        {
                    389:                enumerator_t *certs;
                    390:                certificate_t *cert;
                    391: 
                    392:                INIT(enumerator,
                    393:                        .public = {
                    394:                                .enumerate = enumerator_enumerate_default,
                    395:                                .venumerate = _signature_enumerate,
                    396:                                .destroy = _signature_destroy,
                    397:                        },
                    398:                        .cms = this->cms,
                    399:                        .signers = CMS_get0_SignerInfos(this->cms),
                    400:                        .creds = mem_cred_create(),
                    401:                );
                    402: 
                    403:                /* make available wrapped certs during signature checking */
                    404:                certs = create_cert_enumerator(this);
                    405:                while (certs->enumerate(certs, &cert))
                    406:                {
                    407:                        enumerator->creds->add_cert(enumerator->creds, FALSE,
                    408:                                                                                cert->get_ref(cert));
                    409:                }
                    410:                certs->destroy(certs);
                    411: 
                    412:                lib->credmgr->add_local_set(lib->credmgr, &enumerator->creds->set,
                    413:                                                                        FALSE);
                    414: 
                    415:                return &enumerator->public;
                    416:        }
                    417:        return enumerator_create_empty();
                    418: }
                    419: 
                    420: 
                    421: METHOD(container_t, get_type, container_type_t,
                    422:        private_openssl_pkcs7_t *this)
                    423: {
                    424:        return this->type;
                    425: }
                    426: 
                    427: METHOD(pkcs7_t, get_attribute, bool,
                    428:        private_openssl_pkcs7_t *this, int oid,
                    429:        enumerator_t *enumerator, chunk_t *value)
                    430: {
                    431:        signature_enumerator_t *e;
                    432:        CMS_SignerInfo *si;
                    433:        X509_ATTRIBUTE *attr;
                    434:        ASN1_TYPE *type;
                    435:        chunk_t chunk, wrapped;
                    436:        int i;
                    437: 
                    438:        e = (signature_enumerator_t*)enumerator;
                    439:        if (e->i <= 0)
                    440:        {
                    441:                return FALSE;
                    442:        }
                    443: 
                    444:        /* "i" gets incremented after enumerate(), hence read from previous */
                    445:        si = sk_CMS_SignerInfo_value(e->signers, e->i - 1);
                    446:        for (i = 0; i < CMS_signed_get_attr_count(si); i++)
                    447:        {
                    448:                attr = CMS_signed_get_attr(si, i);
                    449:                if (X509_ATTRIBUTE_count(attr) == 1 &&
                    450:                        openssl_asn1_known_oid(X509_ATTRIBUTE_get0_object(attr)) == oid)
                    451:                {
                    452:                        /* get first value in SET */
                    453:                        type = X509_ATTRIBUTE_get0_type(attr, 0);
                    454:                        chunk = wrapped = openssl_i2chunk(ASN1_TYPE, type);
                    455:                        if (asn1_unwrap(&chunk, &chunk) != 0x100 /* ASN1_INVALID */)
                    456:                        {
                    457:                                *value = chunk_clone(chunk);
                    458:                                free(wrapped.ptr);
                    459:                                return TRUE;
                    460:                        }
                    461:                        free(wrapped.ptr);
                    462:                }
                    463:        }
                    464:        return FALSE;
                    465: }
                    466: 
                    467: /**
                    468:  * Find a private key for issuerAndSerialNumber
                    469:  */
                    470: static private_key_t *find_private(identification_t *issuer,
                    471:                                                                   identification_t *serial)
                    472: {
                    473:        enumerator_t *enumerator;
                    474:        certificate_t *cert;
                    475:        public_key_t *public;
                    476:        private_key_t *private = NULL;
                    477:        identification_t *id;
                    478:        chunk_t fp;
                    479: 
                    480:        enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
                    481:                                                                                        CERT_X509, KEY_RSA, serial, FALSE);
                    482:        while (enumerator->enumerate(enumerator, &cert))
                    483:        {
                    484:                if (issuer->equals(issuer, cert->get_issuer(cert)))
                    485:                {
                    486:                        public = cert->get_public_key(cert);
                    487:                        if (public)
                    488:                        {
                    489:                                if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &fp))
                    490:                                {
                    491:                                        id = identification_create_from_encoding(ID_KEY_ID, fp);
                    492:                                        private = lib->credmgr->get_private(lib->credmgr,
                    493:                                                                                                                KEY_ANY, id, NULL);
                    494:                                        id->destroy(id);
                    495:                                }
                    496:                                public->destroy(public);
                    497:                        }
                    498:                }
                    499:                if (private)
                    500:                {
                    501:                        break;
                    502:                }
                    503:        }
                    504:        enumerator->destroy(enumerator);
                    505:        return private;
                    506: }
                    507: 
                    508: /**
                    509:  * Decrypt enveloped-data with a decrypted symmetric key
                    510:  */
                    511: static bool decrypt_symmetric(private_openssl_pkcs7_t *this, chunk_t key,
                    512:                                                          chunk_t encrypted, chunk_t *plain)
                    513: {
                    514:        encryption_algorithm_t encr;
                    515:        X509_ALGOR *alg;
                    516:        crypter_t *crypter;
                    517:        chunk_t iv;
                    518:        size_t key_size;
                    519: 
                    520:        /* read encryption algorithm from internal structures; TODO fixup */
                    521:        alg = this->cms->envelopedData->encryptedContentInfo->
                    522:                                                                                                contentEncryptionAlgorithm;
                    523:        encr = encryption_algorithm_from_oid(openssl_asn1_known_oid(alg->algorithm),
                    524:                                                                                 &key_size);
                    525:        if (alg->parameter->type != V_ASN1_OCTET_STRING)
                    526:        {
                    527:                return FALSE;
                    528:        }
                    529:        iv = openssl_asn1_str2chunk(alg->parameter->value.octet_string);
                    530: 
                    531:        crypter = lib->crypto->create_crypter(lib->crypto, encr, key_size / 8);
                    532:        if (!crypter)
                    533:        {
                    534:                DBG1(DBG_LIB, "crypter %N-%d not available",
                    535:                         encryption_algorithm_names, alg, key_size);
                    536:                return FALSE;
                    537:        }
                    538:        if (key.len != crypter->get_key_size(crypter))
                    539:        {
                    540:                DBG1(DBG_LIB, "symmetric key length is wrong");
                    541:                crypter->destroy(crypter);
                    542:                return FALSE;
                    543:        }
                    544:        if (iv.len != crypter->get_iv_size(crypter))
                    545:        {
                    546:                DBG1(DBG_LIB, "IV length is wrong");
                    547:                crypter->destroy(crypter);
                    548:                return FALSE;
                    549:        }
                    550:        if (!crypter->set_key(crypter, key) ||
                    551:                !crypter->decrypt(crypter, encrypted, iv, plain))
                    552:        {
                    553:                crypter->destroy(crypter);
                    554:                return FALSE;
                    555:        }
                    556:        crypter->destroy(crypter);
                    557:        return TRUE;
                    558: }
                    559: 
                    560: /**
                    561:  * Remove enveloped-data PKCS#7 padding from plain data
                    562:  */
                    563: static bool remove_padding(chunk_t *data)
                    564: {
                    565:        u_char *pos;
                    566:        u_char pattern;
                    567:        size_t padding;
                    568: 
                    569:        if (!data->len)
                    570:        {
                    571:                return FALSE;
                    572:        }
                    573:        pos = data->ptr + data->len - 1;
                    574:        padding = pattern = *pos;
                    575: 
                    576:        if (padding > data->len)
                    577:        {
                    578:                DBG1(DBG_LIB, "padding greater than data length");
                    579:                return FALSE;
                    580:        }
                    581:        data->len -= padding;
                    582: 
                    583:        while (padding-- > 0)
                    584:        {
                    585:                if (*pos-- != pattern)
                    586:                {
                    587:                        DBG1(DBG_LIB, "wrong padding pattern");
                    588:                        return FALSE;
                    589:                }
                    590:        }
                    591:        return TRUE;
                    592: }
                    593: 
                    594: /**
                    595:  * Decrypt PKCS#7 enveloped-data
                    596:  */
                    597: static bool decrypt(private_openssl_pkcs7_t *this,
                    598:                                        chunk_t encrypted, chunk_t *plain)
                    599: {
                    600:        STACK_OF(CMS_RecipientInfo) *ris;
                    601:        CMS_RecipientInfo *ri;
                    602:        chunk_t chunk, key = chunk_empty;
                    603:        int i;
                    604: 
                    605:        ris = CMS_get0_RecipientInfos(this->cms);
                    606:        for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
                    607:        {
                    608:                ri = sk_CMS_RecipientInfo_value(ris, i);
                    609:                if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_TRANS)
                    610:                {
                    611:                        identification_t *serial, *issuer;
                    612:                        private_key_t *private;
                    613:                        X509_ALGOR *alg;
                    614:                        X509_NAME *name;
                    615:                        ASN1_INTEGER *sn;
                    616:                        u_char zero = 0;
                    617:                        int oid;
                    618: 
                    619:                        if (CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg) == 1 &&
                    620:                                CMS_RecipientInfo_ktri_get0_signer_id(ri, NULL, &name, &sn) == 1)
                    621:                        {
                    622:                                oid = openssl_asn1_known_oid(alg->algorithm);
                    623:                                if (oid != OID_RSA_ENCRYPTION)
                    624:                                {
                    625:                                        DBG1(DBG_LIB, "only RSA encryption supported in PKCS#7");
                    626:                                        continue;
                    627:                                }
                    628:                                issuer = openssl_x509_name2id(name);
                    629:                                if (!issuer)
                    630:                                {
                    631:                                        continue;
                    632:                                }
                    633:                                chunk = openssl_asn1_str2chunk(sn);
                    634:                                if (chunk.len && chunk.ptr[0] & 0x80)
                    635:                                {       /* if MSB is set, append a zero to make it non-negative */
                    636:                                        chunk = chunk_cata("cc", chunk_from_thing(zero), chunk);
                    637:                                }
                    638:                                serial = identification_create_from_encoding(ID_KEY_ID, chunk);
                    639:                                private = find_private(issuer, serial);
                    640:                                issuer->destroy(issuer);
                    641:                                serial->destroy(serial);
                    642: 
                    643:                                if (private)
                    644:                                {
                    645:                                        /* get encryptedKey from internal structure; TODO fixup */
                    646:                                        chunk = openssl_asn1_str2chunk(ri->ktri->encryptedKey);
                    647:                                        if (private->decrypt(private, ENCRYPT_RSA_PKCS1,
                    648:                                                                                 chunk, &key))
                    649:                                        {
                    650:                                                private->destroy(private);
                    651:                                                break;
                    652:                                        }
                    653:                                        private->destroy(private);
                    654:                                }
                    655:                        }
                    656:                }
                    657:        }
                    658:        if (!key.len)
                    659:        {
                    660:                DBG1(DBG_LIB, "no private key found to decrypt PKCS#7");
                    661:                return FALSE;
                    662:        }
                    663:        if (!decrypt_symmetric(this, key, encrypted, plain))
                    664:        {
                    665:                chunk_clear(&key);
                    666:                return FALSE;
                    667:        }
                    668:        chunk_clear(&key);
                    669:        if (!remove_padding(plain))
                    670:        {
                    671:                free(plain->ptr);
                    672:                return FALSE;
                    673:        }
                    674:        return TRUE;
                    675: }
                    676: 
                    677: METHOD(container_t, get_data, bool,
                    678:        private_openssl_pkcs7_t *this, chunk_t *data)
                    679: {
                    680:        ASN1_OCTET_STRING **os;
                    681:        chunk_t chunk;
                    682: 
                    683:        os = CMS_get0_content(this->cms);
                    684:        if (os)
                    685:        {
                    686:                chunk = openssl_asn1_str2chunk(*os);
                    687:                switch (this->type)
                    688:                {
                    689:                        case CONTAINER_PKCS7_DATA:
                    690:                        case CONTAINER_PKCS7_SIGNED_DATA:
                    691:                                *data = chunk_clone(chunk);
                    692:                                return TRUE;
                    693:                        case CONTAINER_PKCS7_ENVELOPED_DATA:
                    694:                                return decrypt(this, chunk, data);
                    695:                        default:
                    696:                                break;
                    697:                }
                    698:        }
                    699:        return FALSE;
                    700: }
                    701: 
                    702: METHOD(container_t, get_encoding, bool,
                    703:        private_openssl_pkcs7_t *this, chunk_t *data)
                    704: {
                    705:        return FALSE;
                    706: }
                    707: 
                    708: METHOD(container_t, destroy, void,
                    709:        private_openssl_pkcs7_t *this)
                    710: {
                    711:        CMS_ContentInfo_free(this->cms);
                    712:        free(this);
                    713: }
                    714: 
                    715: /**
                    716:  * Generic constructor
                    717:  */
                    718: static private_openssl_pkcs7_t* create_empty()
                    719: {
                    720:        private_openssl_pkcs7_t *this;
                    721: 
                    722:        INIT(this,
                    723:                .public = {
                    724:                        .container = {
                    725:                                .get_type = _get_type,
                    726:                                .create_signature_enumerator = _create_signature_enumerator,
                    727:                                .get_data = _get_data,
                    728:                                .get_encoding = _get_encoding,
                    729:                                .destroy = _destroy,
                    730:                        },
                    731:                        .get_attribute = _get_attribute,
                    732:                        .create_cert_enumerator = _create_cert_enumerator,
                    733:                },
                    734:        );
                    735: 
                    736:        return this;
                    737: }
                    738: 
                    739: /**
                    740:  * Parse a PKCS#7 container
                    741:  */
                    742: static bool parse(private_openssl_pkcs7_t *this, chunk_t blob)
                    743: {
                    744:        BIO *bio;
                    745: 
                    746:        bio = BIO_new_mem_buf(blob.ptr, blob.len);
                    747:        this->cms = d2i_CMS_bio(bio, NULL);
                    748:        BIO_free(bio);
                    749: 
                    750:        if (!this->cms)
                    751:        {
                    752:                return FALSE;
                    753:        }
                    754:        switch (openssl_asn1_known_oid((ASN1_OBJECT*)CMS_get0_type(this->cms)))
                    755:        {
                    756:                case OID_PKCS7_DATA:
                    757:                        this->type = CONTAINER_PKCS7_DATA;
                    758:                        break;
                    759:                case OID_PKCS7_SIGNED_DATA:
                    760:                        this->type = CONTAINER_PKCS7_SIGNED_DATA;
                    761:                        break;
                    762:                case OID_PKCS7_ENVELOPED_DATA:
                    763:                        this->type = CONTAINER_PKCS7_ENVELOPED_DATA;
                    764:                        break;
                    765:                default:
                    766:                        return FALSE;
                    767:        }
                    768: 
                    769:        return TRUE;
                    770: }
                    771: 
                    772: /**
                    773:  * See header
                    774:  */
                    775: pkcs7_t *openssl_pkcs7_load(container_type_t type, va_list args)
                    776: {
                    777:        chunk_t blob = chunk_empty;
                    778:        private_openssl_pkcs7_t *this;
                    779: 
                    780:        while (TRUE)
                    781:        {
                    782:                switch (va_arg(args, builder_part_t))
                    783:                {
                    784:                        case BUILD_BLOB_ASN1_DER:
                    785:                                blob = va_arg(args, chunk_t);
                    786:                                continue;
                    787:                        case BUILD_END:
                    788:                                break;
                    789:                        default:
                    790:                                return NULL;
                    791:                }
                    792:                break;
                    793:        }
                    794:        if (blob.len)
                    795:        {
                    796:                this = create_empty();
                    797:                if (parse(this, blob))
                    798:                {
                    799:                        return &this->public;
                    800:                }
                    801:                destroy(this);
                    802:        }
                    803:        return NULL;
                    804: }
                    805: 
                    806: #endif /* OPENSSL_NO_CMS */
                    807: #endif /* OPENSSL_VERSION_NUMBER */

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