Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_pkcs12.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: #define _GNU_SOURCE /* for asprintf() */
                     17: #include <stdio.h>
                     18: #include <openssl/pkcs12.h>
                     19: 
                     20: #include "openssl_pkcs12.h"
                     21: #include "openssl_util.h"
                     22: 
                     23: #include <library.h>
                     24: #include <credentials/sets/mem_cred.h>
                     25: 
                     26: typedef struct private_pkcs12_t private_pkcs12_t;
                     27: 
                     28: /**
                     29:  * Private data of a pkcs12_t object.
                     30:  */
                     31: struct private_pkcs12_t {
                     32: 
                     33:        /**
                     34:         * Public pkcs12_t interface.
                     35:         */
                     36:        pkcs12_t public;
                     37: 
                     38:        /**
                     39:         * OpenSSL PKCS#12 structure
                     40:         */
                     41:        PKCS12 *p12;
                     42: 
                     43:        /**
                     44:         * Credentials contained in container
                     45:         */
                     46:        mem_cred_t *creds;
                     47: };
                     48: 
                     49: /**
                     50:  * Decode certificate and add it to our credential set
                     51:  */
                     52: static bool add_cert(private_pkcs12_t *this, X509 *x509)
                     53: {
                     54:        certificate_t *cert = NULL;
                     55:        chunk_t encoding;
                     56: 
                     57:        if (!x509)
                     58:        {       /* no certificate is ok */
                     59:                return TRUE;
                     60:        }
                     61:        encoding = openssl_i2chunk(X509, x509);
                     62:        if (encoding.ptr)
                     63:        {
                     64:                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
                     65:                                                                  BUILD_BLOB_ASN1_DER, encoding,
                     66:                                                                  BUILD_END);
                     67:                if (cert)
                     68:                {
                     69:                        this->creds->add_cert(this->creds, FALSE, cert);
                     70:                }
                     71:        }
                     72:        chunk_free(&encoding);
                     73:        X509_free(x509);
                     74:        return cert != NULL;
                     75: }
                     76: 
                     77: /**
                     78:  * Add CA certificates to our credential set
                     79:  */
                     80: static bool add_cas(private_pkcs12_t *this, STACK_OF(X509) *cas)
                     81: {
                     82:        bool success = TRUE;
                     83:        int i;
                     84: 
                     85:        if (!cas)
                     86:        {       /* no CAs is ok */
                     87:                return TRUE;
                     88:        }
                     89:        for (i = 0; i < sk_X509_num(cas); i++)
                     90:        {
                     91:                if (!add_cert(this, sk_X509_value(cas, i)))
                     92:                {       /* continue to free all X509 objects */
                     93:                        success = FALSE;
                     94:                }
                     95:        }
                     96:        sk_X509_free(cas);
                     97:        return success;
                     98: }
                     99: 
                    100: /**
                    101:  * Decode private key and add it to our credential set
                    102:  */
                    103: static bool add_key(private_pkcs12_t *this, EVP_PKEY *private)
                    104: {
                    105:        private_key_t *key = NULL;
                    106:        chunk_t encoding;
                    107:        key_type_t type;
                    108: 
                    109:        if (!private)
                    110:        {       /* no private key is ok */
                    111:                return TRUE;
                    112:        }
                    113:        switch (EVP_PKEY_base_id(private))
                    114:        {
                    115:                case EVP_PKEY_RSA:
                    116:                        type = KEY_RSA;
                    117:                        break;
                    118:                case EVP_PKEY_EC:
                    119:                        type = KEY_ECDSA;
                    120:                        break;
                    121:                default:
                    122:                        EVP_PKEY_free(private);
                    123:                        return FALSE;
                    124:        }
                    125:        encoding = openssl_i2chunk(PrivateKey, private);
                    126:        if (encoding.ptr)
                    127:        {
                    128:                key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
                    129:                                                                 BUILD_BLOB_ASN1_DER, encoding,
                    130:                                                                 BUILD_END);
                    131:                if (key)
                    132:                {
                    133:                        this->creds->add_key(this->creds, key);
                    134:                }
                    135:        }
                    136:        chunk_clear(&encoding);
                    137:        EVP_PKEY_free(private);
                    138:        return key != NULL;
                    139: }
                    140: 
                    141: /**
                    142:  * Decrypt PKCS#12 file and unpack credentials
                    143:  */
                    144: static bool decrypt_and_unpack(private_pkcs12_t *this)
                    145: {
                    146:        enumerator_t *enumerator;
                    147:        shared_key_t *shared;
                    148:        STACK_OF(X509) *cas = NULL;
                    149:        EVP_PKEY *private;
                    150:        X509 *cert;
                    151:        chunk_t key;
                    152:        char *password;
                    153:        bool success = FALSE;
                    154: 
                    155:        enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
                    156:                                                                                SHARED_PRIVATE_KEY_PASS, NULL, NULL);
                    157:        while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
                    158:        {
                    159:                key = shared->get_key(shared);
                    160:                if (!key.ptr || asprintf(&password, "%.*s", (int)key.len, key.ptr) < 0)
                    161:                {
                    162:                        password = NULL;
                    163:                }
                    164:                if (PKCS12_parse(this->p12, password, &private, &cert, &cas))
                    165:                {
                    166:                        success = add_key(this, private);
                    167:                        success &= add_cert(this, cert);
                    168:                        success &= add_cas(this, cas);
                    169:                        free(password);
                    170:                        break;
                    171:                }
                    172:                free(password);
                    173:        }
                    174:        enumerator->destroy(enumerator);
                    175:        return success;
                    176: }
                    177: 
                    178: METHOD(container_t, get_type, container_type_t,
                    179:        private_pkcs12_t *this)
                    180: {
                    181:        return CONTAINER_PKCS12;
                    182: }
                    183: 
                    184: METHOD(pkcs12_t, create_cert_enumerator, enumerator_t*,
                    185:        private_pkcs12_t *this)
                    186: {
                    187:        return this->creds->set.create_cert_enumerator(&this->creds->set, CERT_ANY,
                    188:                                                                                                   KEY_ANY, NULL, FALSE);
                    189: }
                    190: 
                    191: METHOD(pkcs12_t, create_key_enumerator, enumerator_t*,
                    192:        private_pkcs12_t *this)
                    193: {
                    194:        return this->creds->set.create_private_enumerator(&this->creds->set,
                    195:                                                                                                          KEY_ANY, NULL);
                    196: }
                    197: 
                    198: METHOD(container_t, destroy, void,
                    199:        private_pkcs12_t *this)
                    200: {
                    201:        if (this->p12)
                    202:        {
                    203:                PKCS12_free(this->p12);
                    204:        }
                    205:        this->creds->destroy(this->creds);
                    206:        free(this);
                    207: }
                    208: 
                    209: /**
                    210:  * Parse a PKCS#12 container
                    211:  */
                    212: static pkcs12_t *parse(chunk_t blob)
                    213: {
                    214:        private_pkcs12_t *this;
                    215:        BIO *bio;
                    216: 
                    217:        INIT(this,
                    218:                .public = {
                    219:                        .container = {
                    220:                                .get_type = _get_type,
                    221:                                .create_signature_enumerator = (void*)enumerator_create_empty,
                    222:                                .get_data = (void*)return_false,
                    223:                                .get_encoding = (void*)return_false,
                    224:                                .destroy = _destroy,
                    225:                        },
                    226:                        .create_cert_enumerator = _create_cert_enumerator,
                    227:                        .create_key_enumerator = _create_key_enumerator,
                    228:                },
                    229:                .creds = mem_cred_create(),
                    230:        );
                    231: 
                    232:        bio = BIO_new_mem_buf(blob.ptr, blob.len);
                    233:        this->p12 = d2i_PKCS12_bio(bio, NULL);
                    234:        BIO_free(bio);
                    235: 
                    236:        if (!this->p12 || !decrypt_and_unpack(this))
                    237:        {
                    238:                destroy(this);
                    239:                return NULL;
                    240:        }
                    241:        return &this->public;
                    242: }
                    243: 
                    244: /*
                    245:  * Defined in header
                    246:  */
                    247: pkcs12_t *openssl_pkcs12_load(container_type_t type, va_list args)
                    248: {
                    249:        chunk_t blob = chunk_empty;
                    250: 
                    251:        while (TRUE)
                    252:        {
                    253:                switch (va_arg(args, builder_part_t))
                    254:                {
                    255:                        case BUILD_BLOB_ASN1_DER:
                    256:                                blob = va_arg(args, chunk_t);
                    257:                                continue;
                    258:                        case BUILD_END:
                    259:                                break;
                    260:                        default:
                    261:                                return NULL;
                    262:                }
                    263:                break;
                    264:        }
                    265:        return blob.len ? parse(blob) : NULL;
                    266: }

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