Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_pkcs7.c, revision 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>