Annotation of embedaddon/strongswan/src/charon-nm/nm/nm_creds.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2008 Martin Willi
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include "nm_creds.h"
                     17: 
                     18: #include <sys/types.h>
                     19: #include <sys/stat.h>
                     20: #include <unistd.h>
                     21: 
                     22: #include <daemon.h>
                     23: #include <threading/rwlock.h>
                     24: #include <credentials/certificates/x509.h>
                     25: 
                     26: typedef struct private_nm_creds_t private_nm_creds_t;
                     27: 
                     28: /**
                     29:  * private data of nm_creds
                     30:  */
                     31: struct private_nm_creds_t {
                     32: 
                     33:        /**
                     34:         * public functions
                     35:         */
                     36:        nm_creds_t public;
                     37: 
                     38:        /**
                     39:         * List of trusted certificates, certificate_t*
                     40:         */
                     41:        linked_list_t *certs;
                     42: 
                     43:        /**
                     44:         * User name
                     45:         */
                     46:        identification_t *user;
                     47: 
                     48:        /**
                     49:         * User password
                     50:         */
                     51:        char *pass;
                     52: 
                     53:        /**
                     54:         * Private key decryption password / smartcard pin
                     55:         */
                     56:        char *keypass;
                     57: 
                     58:        /**
                     59:         * private key ID of smartcard key
                     60:         */
                     61:        chunk_t keyid;
                     62: 
                     63:        /**
                     64:         * users certificate
                     65:         */
                     66:        certificate_t *usercert;
                     67: 
                     68:        /**
                     69:         * users private key
                     70:         */
                     71:        private_key_t *key;
                     72: 
                     73:        /**
                     74:         * read/write lock
                     75:         */
                     76:        rwlock_t *lock;
                     77: };
                     78: 
                     79: /**
                     80:  * Enumerator for user certificate
                     81:  */
                     82: static enumerator_t *create_usercert_enumerator(private_nm_creds_t *this,
                     83:                                                        certificate_type_t cert, key_type_t key)
                     84: {
                     85:        public_key_t *public;
                     86: 
                     87:        if (cert != CERT_ANY && cert != this->usercert->get_type(this->usercert))
                     88:        {
                     89:                return NULL;
                     90:        }
                     91:        if (key != KEY_ANY)
                     92:        {
                     93:                public = this->usercert->get_public_key(this->usercert);
                     94:                if (!public)
                     95:                {
                     96:                        return NULL;
                     97:                }
                     98:                if (public->get_type(public) != key)
                     99:                {
                    100:                        public->destroy(public);
                    101:                        return NULL;
                    102:                }
                    103:                public->destroy(public);
                    104:        }
                    105:        this->lock->read_lock(this->lock);
                    106:        return enumerator_create_cleaner(
                    107:                                                                enumerator_create_single(this->usercert, NULL),
                    108:                                                                (void*)this->lock->unlock, this->lock);
                    109: }
                    110: 
                    111: /**
                    112:  * CA certificate enumerator data
                    113:  */
                    114: typedef struct {
                    115:        /** ref to credential credential store */
                    116:        private_nm_creds_t *this;
                    117:        /** type of key we are looking for */
                    118:        key_type_t key;
                    119:        /** CA certificate ID */
                    120:        identification_t *id;
                    121: } cert_data_t;
                    122: 
                    123: CALLBACK(cert_data_destroy, void,
                    124:        cert_data_t *data)
                    125: {
                    126:        data->this->lock->unlock(data->this->lock);
                    127:        free(data);
                    128: }
                    129: 
                    130: CALLBACK(cert_filter, bool,
                    131:        cert_data_t *data, enumerator_t *orig, va_list args)
                    132: {
                    133:        certificate_t *cert, **out;
                    134:        public_key_t *public;
                    135: 
                    136:        VA_ARGS_VGET(args, out);
                    137: 
                    138:        while (orig->enumerate(orig, &cert))
                    139:        {
                    140:                public = cert->get_public_key(cert);
                    141:                if (!public)
                    142:                {
                    143:                        continue;
                    144:                }
                    145:                if (data->key != KEY_ANY && public->get_type(public) != data->key)
                    146:                {
                    147:                        public->destroy(public);
                    148:                        continue;
                    149:                }
                    150:                if (data->id && data->id->get_type(data->id) == ID_KEY_ID &&
                    151:                        public->has_fingerprint(public, data->id->get_encoding(data->id)))
                    152:                {
                    153:                        public->destroy(public);
                    154:                        *out = cert;
                    155:                        return TRUE;
                    156:                }
                    157:                public->destroy(public);
                    158:                if (data->id && !cert->has_subject(cert, data->id))
                    159:                {
                    160:                        continue;
                    161:                }
                    162:                *out = cert;
                    163:                return TRUE;
                    164:        }
                    165:        return FALSE;
                    166: }
                    167: 
                    168: /**
                    169:  * Create enumerator for trusted certificates
                    170:  */
                    171: static enumerator_t *create_trusted_cert_enumerator(private_nm_creds_t *this,
                    172:                                                                                key_type_t key, identification_t *id)
                    173: {
                    174:        cert_data_t *data;
                    175: 
                    176:        INIT(data,
                    177:                .this = this,
                    178:                .id = id,
                    179:                .key = key,
                    180:        );
                    181: 
                    182:        this->lock->read_lock(this->lock);
                    183:        return enumerator_create_filter(
                    184:                                        this->certs->create_enumerator(this->certs),
                    185:                                        cert_filter, data, cert_data_destroy);
                    186: }
                    187: 
                    188: METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
                    189:        private_nm_creds_t *this, certificate_type_t cert, key_type_t key,
                    190:        identification_t *id, bool trusted)
                    191: {
                    192:        if (id && this->usercert &&
                    193:                id->equals(id, this->usercert->get_subject(this->usercert)))
                    194:        {
                    195:                return create_usercert_enumerator(this, cert, key);
                    196:        }
                    197:        if (cert == CERT_X509 || cert == CERT_ANY)
                    198:        {
                    199:                return create_trusted_cert_enumerator(this, key, id);
                    200:        }
                    201:        return NULL;
                    202: }
                    203: 
                    204: METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
                    205:        private_nm_creds_t *this, key_type_t type, identification_t *id)
                    206: {
                    207:        if (this->key == NULL)
                    208:        {
                    209:                return NULL;
                    210:        }
                    211:        if (type != KEY_ANY && type != this->key->get_type(this->key))
                    212:        {
                    213:                return NULL;
                    214:        }
                    215:        if (id && id->get_type(id) != ID_ANY)
                    216:        {
                    217:                if (id->get_type(id) != ID_KEY_ID ||
                    218:                        !this->key->has_fingerprint(this->key, id->get_encoding(id)))
                    219:                {
                    220:                        return NULL;
                    221:                }
                    222:        }
                    223:        this->lock->read_lock(this->lock);
                    224:        return enumerator_create_cleaner(enumerator_create_single(this->key, NULL),
                    225:                                                                         (void*)this->lock->unlock, this->lock);
                    226: }
                    227: 
                    228: /**
                    229:  * shared key enumerator implementation
                    230:  */
                    231: typedef struct {
                    232:        enumerator_t public;
                    233:        private_nm_creds_t *this;
                    234:        shared_key_t *key;
                    235:        bool done;
                    236: } shared_enumerator_t;
                    237: 
                    238: METHOD(enumerator_t, shared_enumerate, bool,
                    239:        shared_enumerator_t *this, va_list args)
                    240: {
                    241:        shared_key_t **key;
                    242:        id_match_t *me, *other;
                    243: 
                    244:        VA_ARGS_VGET(args, key, me, other);
                    245: 
                    246:        if (this->done)
                    247:        {
                    248:                return FALSE;
                    249:        }
                    250:        *key = this->key;
                    251:        if (me)
                    252:        {
                    253:                *me = ID_MATCH_PERFECT;
                    254:        }
                    255:        if (other)
                    256:        {
                    257:                *other = ID_MATCH_ANY;
                    258:        }
                    259:        this->done = TRUE;
                    260:        return TRUE;
                    261: }
                    262: 
                    263: METHOD(enumerator_t, shared_destroy, void,
                    264:        shared_enumerator_t *this)
                    265: {
                    266:        this->key->destroy(this->key);
                    267:        this->this->lock->unlock(this->this->lock);
                    268:        free(this);
                    269: }
                    270: 
                    271: METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
                    272:        private_nm_creds_t *this, shared_key_type_t type, identification_t *me,
                    273:        identification_t *other)
                    274: {
                    275:        shared_enumerator_t *enumerator;
                    276:        chunk_t key;
                    277: 
                    278:        this->lock->read_lock(this->lock);
                    279: 
                    280:        switch (type)
                    281:        {
                    282:                case SHARED_EAP:
                    283:                case SHARED_IKE:
                    284:                        if (!this->pass || !this->user)
                    285:                        {
                    286:                                goto no_secret;
                    287:                        }
                    288:                        if (me && !me->matches(me, this->user))
                    289:                        {
                    290:                                goto no_secret;
                    291:                        }
                    292:                        key = chunk_create(this->pass, strlen(this->pass));
                    293:                        break;
                    294:                case SHARED_PRIVATE_KEY_PASS:
                    295:                        if (!this->keypass)
                    296:                        {
                    297:                                goto no_secret;
                    298:                        }
                    299:                        key = chunk_create(this->keypass, strlen(this->keypass));
                    300:                        break;
                    301:                case SHARED_PIN:
                    302:                        if (!this->keypass || !me ||
                    303:                                !chunk_equals(me->get_encoding(me), this->keyid))
                    304:                        {
                    305:                                goto no_secret;
                    306:                        }
                    307:                        key = chunk_create(this->keypass, strlen(this->keypass));
                    308:                        break;
                    309:                default:
                    310:                        goto no_secret;
                    311:        }
                    312: 
                    313:        INIT(enumerator,
                    314:                .public = {
                    315:                        .enumerate = enumerator_enumerate_default,
                    316:                        .venumerate = _shared_enumerate,
                    317:                        .destroy = _shared_destroy,
                    318:                },
                    319:                .this = this,
                    320:        );
                    321:        enumerator->key = shared_key_create(type, chunk_clone(key));
                    322:        return &enumerator->public;
                    323: 
                    324: no_secret:
                    325:        this->lock->unlock(this->lock);
                    326:        return NULL;
                    327: }
                    328: 
                    329: METHOD(nm_creds_t, add_certificate, void,
                    330:        private_nm_creds_t *this, certificate_t *cert)
                    331: {
                    332:        this->lock->write_lock(this->lock);
                    333:        this->certs->insert_last(this->certs, cert);
                    334:        this->lock->unlock(this->lock);
                    335: }
                    336: 
                    337: /**
                    338:  * Load a certificate file
                    339:  */
                    340: static void load_ca_file(private_nm_creds_t *this, char *file)
                    341: {
                    342:        certificate_t *cert;
                    343: 
                    344:        /* We add the CA constraint, as many CAs miss it */
                    345:        cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
                    346:                                                          BUILD_FROM_FILE, file, BUILD_END);
                    347:        if (!cert)
                    348:        {
                    349:                DBG1(DBG_CFG, "loading CA certificate '%s' failed", file);
                    350:        }
                    351:        else
                    352:        {
                    353:                DBG2(DBG_CFG, "loaded CA certificate '%Y'", cert->get_subject(cert));
                    354:                x509_t *x509 = (x509_t*)cert;
                    355:                if (!(x509->get_flags(x509) & X509_SELF_SIGNED))
                    356:                {
                    357:                        DBG1(DBG_CFG, "%Y is not self signed", cert->get_subject(cert));
                    358:                }
                    359:                this->certs->insert_last(this->certs, cert);
                    360:        }
                    361: }
                    362: 
                    363: METHOD(nm_creds_t, load_ca_dir, void,
                    364:        private_nm_creds_t *this, char *dir)
                    365: {
                    366:        enumerator_t *enumerator;
                    367:        char *rel, *abs;
                    368:        struct stat st;
                    369: 
                    370:        enumerator = enumerator_create_directory(dir);
                    371:        if (enumerator)
                    372:        {
                    373:                while (enumerator->enumerate(enumerator, &rel, &abs, &st))
                    374:                {
                    375:                        /* skip '.', '..' and hidden files */
                    376:                        if (rel[0] != '.')
                    377:                        {
                    378:                                if (S_ISDIR(st.st_mode))
                    379:                                {
                    380:                                        load_ca_dir(this, abs);
                    381:                                }
                    382:                                else if (S_ISREG(st.st_mode))
                    383:                                {
                    384:                                        load_ca_file(this, abs);
                    385:                                }
                    386:                        }
                    387:                }
                    388:                enumerator->destroy(enumerator);
                    389:        }
                    390: }
                    391: 
                    392: METHOD(nm_creds_t, set_username_password, void,
                    393:        private_nm_creds_t *this, identification_t *id, char *password)
                    394: {
                    395:        this->lock->write_lock(this->lock);
                    396:        DESTROY_IF(this->user);
                    397:        this->user = id->clone(id);
                    398:        free(this->pass);
                    399:        this->pass = strdupnull(password);
                    400:        this->lock->unlock(this->lock);
                    401: }
                    402: 
                    403: METHOD(nm_creds_t, set_key_password, void,
                    404:        private_nm_creds_t *this, char *password)
                    405: {
                    406:        this->lock->write_lock(this->lock);
                    407:        free(this->keypass);
                    408:        this->keypass = strdupnull(password);
                    409:        this->lock->unlock(this->lock);
                    410: }
                    411: 
                    412: METHOD(nm_creds_t, set_pin, void,
                    413:        private_nm_creds_t *this, chunk_t keyid, char *pin)
                    414: {
                    415:        this->lock->write_lock(this->lock);
                    416:        free(this->keypass);
                    417:        free(this->keyid.ptr);
                    418:        this->keypass = strdupnull(pin);
                    419:        this->keyid = chunk_clone(keyid);
                    420:        this->lock->unlock(this->lock);
                    421: }
                    422: 
                    423: METHOD(nm_creds_t, set_cert_and_key, void,
                    424:        private_nm_creds_t *this, certificate_t *cert, private_key_t *key)
                    425: {
                    426:        this->lock->write_lock(this->lock);
                    427:        DESTROY_IF(this->key);
                    428:        DESTROY_IF(this->usercert);
                    429:        this->key = key;
                    430:        this->usercert = cert;
                    431:        this->lock->unlock(this->lock);
                    432: }
                    433: 
                    434: METHOD(nm_creds_t, clear, void,
                    435:        private_nm_creds_t *this)
                    436: {
                    437:        certificate_t *cert;
                    438: 
                    439:        while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS)
                    440:        {
                    441:                cert->destroy(cert);
                    442:        }
                    443:        DESTROY_IF(this->user);
                    444:        free(this->pass);
                    445:        free(this->keypass);
                    446:        free(this->keyid.ptr);
                    447:        DESTROY_IF(this->usercert);
                    448:        DESTROY_IF(this->key);
                    449:        this->key = NULL;
                    450:        this->usercert = NULL;
                    451:        this->pass = NULL;
                    452:        this->user = NULL;
                    453:        this->keypass = NULL;
                    454:        this->keyid = chunk_empty;
                    455: }
                    456: 
                    457: METHOD(nm_creds_t, destroy, void,
                    458:        private_nm_creds_t *this)
                    459: {
                    460:        clear(this);
                    461:        this->certs->destroy(this->certs);
                    462:        this->lock->destroy(this->lock);
                    463:        free(this);
                    464: }
                    465: 
                    466: /*
                    467:  * see header file
                    468:  */
                    469: nm_creds_t *nm_creds_create()
                    470: {
                    471:        private_nm_creds_t *this;
                    472: 
                    473:        INIT(this,
                    474:                .public = {
                    475:                        .set = {
                    476:                                .create_private_enumerator = _create_private_enumerator,
                    477:                                .create_cert_enumerator = _create_cert_enumerator,
                    478:                                .create_shared_enumerator = _create_shared_enumerator,
                    479:                                .create_cdp_enumerator = (void*)return_null,
                    480:                                .cache_cert = (void*)nop,
                    481:                        },
                    482:                        .add_certificate = _add_certificate,
                    483:                        .load_ca_dir = _load_ca_dir,
                    484:                        .set_username_password = _set_username_password,
                    485:                        .set_key_password = _set_key_password,
                    486:                        .set_pin = _set_pin,
                    487:                        .set_cert_and_key = _set_cert_and_key,
                    488:                        .clear = _clear,
                    489:                        .destroy = _destroy,
                    490:                },
                    491:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    492:                .certs = linked_list_create(),
                    493:        );
                    494:        return &this->public;
                    495: }
                    496: 

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