Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2010 Martin Willi
                      3:  * Copyright (C) 2010 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 "pkcs11_manager.h"
                     17: 
                     18: #include <utils/debug.h>
                     19: #include <collections/linked_list.h>
                     20: #include <threading/thread.h>
                     21: 
                     22: #include "pkcs11_library.h"
                     23: 
                     24: #include <processing/jobs/callback_job.h>
                     25: 
                     26: typedef struct private_pkcs11_manager_t private_pkcs11_manager_t;
                     27: 
                     28: /**
                     29:  * Private data of an pkcs11_manager_t object.
                     30:  */
                     31: struct private_pkcs11_manager_t {
                     32: 
                     33:        /**
                     34:         * Public pkcs11_manager_t interface.
                     35:         */
                     36:        pkcs11_manager_t public;
                     37: 
                     38:        /**
                     39:         * List of loaded libraries, as lib_entry_t
                     40:         */
                     41:        linked_list_t *libs;
                     42: 
                     43:        /**
                     44:         * Slot event callback function
                     45:         */
                     46:        pkcs11_manager_token_event_t cb;
                     47: 
                     48:        /**
                     49:         * Slot event user data
                     50:         */
                     51:        void *data;
                     52: };
                     53: 
                     54: /**
                     55:  * Entry for a loaded library
                     56:  */
                     57: typedef struct {
                     58:        /* back reference to this */
                     59:        private_pkcs11_manager_t *this;
                     60:        /* associated library path */
                     61:        char *path;
                     62:        /* loaded library */
                     63:        pkcs11_library_t *lib;
                     64: } lib_entry_t;
                     65: 
                     66: /**
                     67:  * Destroy a lib_entry_t
                     68:  */
                     69: static void lib_entry_destroy(lib_entry_t *entry)
                     70: {
                     71:        entry->lib->destroy(entry->lib);
                     72:        free(entry);
                     73: }
                     74: 
                     75: /**
                     76:  * Print supported mechanisms of a token in a slot
                     77:  */
                     78: static void print_mechs(lib_entry_t *entry, CK_SLOT_ID slot)
                     79: {
                     80:        enumerator_t *enumerator;
                     81:        CK_MECHANISM_TYPE type;
                     82:        CK_MECHANISM_INFO info;
                     83: 
                     84:        enumerator = entry->lib->create_mechanism_enumerator(entry->lib, slot);
                     85:        while (enumerator->enumerate(enumerator, &type, &info))
                     86:        {
                     87:                DBG2(DBG_CFG, "      %N %lu-%lu [ %s%s%s%s%s%s%s%s%s%s%s%s%s]",
                     88:                        ck_mech_names, type,
                     89:                        info.ulMinKeySize, info.ulMaxKeySize,
                     90:                        info.flags & CKF_HW ? "HW " : "",
                     91:                        info.flags & CKF_ENCRYPT ? "ENCR " : "",
                     92:                        info.flags & CKF_DECRYPT ? "DECR " : "",
                     93:                        info.flags & CKF_DIGEST ? "DGST " : "",
                     94:                        info.flags & CKF_SIGN ? "SIGN " : "",
                     95:                        info.flags & CKF_SIGN_RECOVER ? "SIGN_RCVR " : "",
                     96:                        info.flags & CKF_VERIFY ? "VRFY " : "",
                     97:                        info.flags & CKF_VERIFY_RECOVER ? "VRFY_RCVR " : "",
                     98:                        info.flags & CKF_GENERATE ? "GEN " : "",
                     99:                        info.flags & CKF_GENERATE_KEY_PAIR ? "GEN_KEY_PAIR " : "",
                    100:                        info.flags & CKF_WRAP ? "WRAP " : "",
                    101:                        info.flags & CKF_UNWRAP ? "UNWRAP " : "",
                    102:                        info.flags & CKF_DERIVE ? "DERIVE " : "");
                    103:        }
                    104:        enumerator->destroy(enumerator);
                    105: }
                    106: 
                    107: /**
                    108:  * Handle a token
                    109:  */
                    110: static void handle_token(lib_entry_t *entry, CK_SLOT_ID slot)
                    111: {
                    112:        CK_TOKEN_INFO info;
                    113:        CK_RV rv;
                    114: 
                    115:        rv = entry->lib->f->C_GetTokenInfo(slot, &info);
                    116:        if (rv != CKR_OK)
                    117:        {
                    118:                DBG1(DBG_CFG, "C_GetTokenInfo failed: %N", ck_rv_names, rv);
                    119:                return;
                    120:        }
                    121:        pkcs11_library_trim(info.label, sizeof(info.label));
                    122:        pkcs11_library_trim(info.manufacturerID, sizeof(info.manufacturerID));
                    123:        pkcs11_library_trim(info.model, sizeof(info.model));
                    124:        DBG1(DBG_CFG, "    %s (%s: %s)",
                    125:                 info.label, info.manufacturerID, info.model);
                    126: 
                    127:        print_mechs(entry, slot);
                    128: }
                    129: 
                    130: /**
                    131:  * Handle slot changes
                    132:  */
                    133: static void handle_slot(lib_entry_t *entry, CK_SLOT_ID slot, bool hot)
                    134: {
                    135:        CK_SLOT_INFO info;
                    136:        CK_RV rv;
                    137: 
                    138:        rv = entry->lib->f->C_GetSlotInfo(slot, &info);
                    139:        if (rv != CKR_OK)
                    140:        {
                    141:                DBG1(DBG_CFG, "C_GetSlotInfo failed: %N", ck_rv_names, rv);
                    142:                return;
                    143:        }
                    144: 
                    145:        pkcs11_library_trim(info.slotDescription, sizeof(info.slotDescription));
                    146:        if (info.flags & CKF_TOKEN_PRESENT)
                    147:        {
                    148:                DBG1(DBG_CFG, "  found token in slot '%s':%lu (%s)",
                    149:                         entry->lib->get_name(entry->lib), slot, info.slotDescription);
                    150:                handle_token(entry, slot);
                    151:                if (hot)
                    152:                {
                    153:                        entry->this->cb(entry->this->data, entry->lib, slot, TRUE);
                    154:                }
                    155:        }
                    156:        else
                    157:        {
                    158:                DBG1(DBG_CFG, "token removed from slot '%s':%lu (%s)",
                    159:                         entry->lib->get_name(entry->lib), slot, info.slotDescription);
                    160:                if (hot)
                    161:                {
                    162:                        entry->this->cb(entry->this->data, entry->lib, slot, FALSE);
                    163:                }
                    164:        }
                    165: }
                    166: 
                    167: CALLBACK(dispatch_slot_events, job_requeue_t,
                    168:        lib_entry_t *entry)
                    169: {
                    170:        CK_SLOT_ID slot;
                    171:        CK_RV rv;
                    172: 
                    173:        rv = entry->lib->f->C_WaitForSlotEvent(0, &slot, NULL);
                    174:        if (rv == CKR_FUNCTION_NOT_SUPPORTED || rv == CKR_NO_EVENT)
                    175:        {
                    176:                DBG1(DBG_CFG, "module '%s' does not support hot-plugging, cancelled",
                    177:                         entry->lib->get_name(entry->lib));
                    178:                return JOB_REQUEUE_NONE;
                    179:        }
                    180:        if (rv == CKR_CRYPTOKI_NOT_INITIALIZED)
                    181:        {       /* C_Finalize called, abort */
                    182:                return JOB_REQUEUE_NONE;
                    183:        }
                    184:        if (rv != CKR_OK)
                    185:        {
                    186:                DBG1(DBG_CFG, "error in C_WaitForSlotEvent: %N", ck_rv_names, rv);
                    187:        }
                    188:        handle_slot(entry, slot, TRUE);
                    189: 
                    190:        return JOB_REQUEUE_DIRECT;
                    191: }
                    192: 
                    193: CALLBACK(cancel_events, bool,
                    194:        lib_entry_t *entry)
                    195: {
                    196:        /* it's possible other threads still use the API after this call, but we
                    197:         * have no other way to return from C_WaitForSlotEvent() if we can't cancel
                    198:         * the thread because libraries hold locks they don't release */
                    199:        entry->lib->f->C_Finalize(NULL);
                    200:        return TRUE;
                    201: }
                    202: 
                    203: /**
                    204:  * Get the slot list of a library
                    205:  */
                    206: static CK_SLOT_ID_PTR get_slot_list(pkcs11_library_t *p11, CK_ULONG *out)
                    207: {
                    208:        CK_SLOT_ID_PTR slots;
                    209:        CK_ULONG count;
                    210:        CK_RV rv;
                    211: 
                    212:        rv = p11->f->C_GetSlotList(TRUE, NULL, &count);
                    213:        if (rv != CKR_OK)
                    214:        {
                    215:                DBG1(DBG_CFG, "C_GetSlotList() failed: %N", ck_rv_names, rv);
                    216:                return NULL;
                    217:        }
                    218:        if (count == 0)
                    219:        {
                    220:                return NULL;
                    221:        }
                    222:        slots = malloc(sizeof(CK_SLOT_ID) * count);
                    223:        rv = p11->f->C_GetSlotList(TRUE, slots, &count);
                    224:        if (rv != CKR_OK)
                    225:        {
                    226:                DBG1(DBG_CFG, "C_GetSlotList() failed: %N", ck_rv_names, rv);
                    227:                free(slots);
                    228:                return NULL;
                    229:        }
                    230:        *out = count;
                    231:        return slots;
                    232: }
                    233: 
                    234: /**
                    235:  * Query the slots for tokens
                    236:  */
                    237: static void query_slots(lib_entry_t *entry)
                    238: {
                    239:        CK_ULONG count;
                    240:        CK_SLOT_ID_PTR slots;
                    241:        int i;
                    242: 
                    243:        slots = get_slot_list(entry->lib, &count);
                    244:        if (slots)
                    245:        {
                    246:                for (i = 0; i < count; i++)
                    247:                {
                    248:                        handle_slot(entry, slots[i], FALSE);
                    249:                }
                    250:                free(slots);
                    251:        }
                    252: }
                    253: 
                    254: /**
                    255:  * Token enumerator
                    256:  */
                    257: typedef struct {
                    258:        /* implements enumerator */
                    259:        enumerator_t public;
                    260:        /* inner enumerator over PKCS#11 libraries */
                    261:        enumerator_t *inner;
                    262:        /* active library entry */
                    263:        lib_entry_t *entry;
                    264:        /* slot list with tokens */
                    265:        CK_SLOT_ID_PTR slots;
                    266:        /* number of slots */
                    267:        CK_ULONG count;
                    268:        /* current slot */
                    269:        int current;
                    270: } token_enumerator_t;
                    271: 
                    272: METHOD(enumerator_t, enumerate_token, bool,
                    273:        token_enumerator_t *this, va_list args)
                    274: {
                    275:        pkcs11_library_t **out;
                    276:        CK_SLOT_ID *slot;
                    277: 
                    278:        VA_ARGS_VGET(args, out, slot);
                    279: 
                    280:        if (this->current >= this->count)
                    281:        {
                    282:                free(this->slots);
                    283:                this->slots = NULL;
                    284:                this->current = 0;
                    285:        }
                    286:        while (!this->slots)
                    287:        {
                    288:                if (!this->inner->enumerate(this->inner, &this->entry))
                    289:                {
                    290:                        return FALSE;
                    291:                }
                    292:                this->slots = get_slot_list(this->entry->lib, &this->count);
                    293:        }
                    294:        *out = this->entry->lib;
                    295:        *slot = this->slots[this->current++];
                    296:        return TRUE;
                    297: }
                    298: 
                    299: METHOD(enumerator_t, destroy_token, void,
                    300:        token_enumerator_t *this)
                    301: {
                    302:        this->inner->destroy(this->inner);
                    303:        free(this->slots);
                    304:        free(this);
                    305: }
                    306: 
                    307: METHOD(pkcs11_manager_t, create_token_enumerator, enumerator_t*,
                    308:        private_pkcs11_manager_t *this)
                    309: {
                    310:        token_enumerator_t *enumerator;
                    311: 
                    312:        INIT(enumerator,
                    313:                .public = {
                    314:                        .enumerate = enumerator_enumerate_default,
                    315:                        .venumerate = _enumerate_token,
                    316:                        .destroy = _destroy_token,
                    317:                },
                    318:                .inner = this->libs->create_enumerator(this->libs),
                    319:        );
                    320:        return &enumerator->public;
                    321: }
                    322: 
                    323: METHOD(pkcs11_manager_t, destroy, void,
                    324:        private_pkcs11_manager_t *this)
                    325: {
                    326:        this->libs->destroy_function(this->libs, (void*)lib_entry_destroy);
                    327:        free(this);
                    328: }
                    329: 
                    330: /**
                    331:  * See header
                    332:  */
                    333: pkcs11_manager_t *pkcs11_manager_create(pkcs11_manager_token_event_t cb,
                    334:                                                                                void *data)
                    335: {
                    336:        private_pkcs11_manager_t *this;
                    337:        enumerator_t *enumerator;
                    338:        lib_entry_t *entry;
                    339:        char *module;
                    340: 
                    341:        INIT(this,
                    342:                .public = {
                    343:                        .create_token_enumerator = _create_token_enumerator,
                    344:                        .destroy = _destroy,
                    345:                },
                    346:                .libs = linked_list_create(),
                    347:                .cb = cb,
                    348:                .data = data,
                    349:        );
                    350: 
                    351:        enumerator = lib->settings->create_section_enumerator(lib->settings,
                    352:                                                                                "%s.plugins.pkcs11.modules", lib->ns);
                    353:        while (enumerator->enumerate(enumerator, &module))
                    354:        {
                    355:                INIT(entry,
                    356:                        .this = this,
                    357:                );
                    358: 
                    359:                entry->path = lib->settings->get_str(lib->settings,
                    360:                                "%s.plugins.pkcs11.modules.%s.path", NULL, lib->ns, module);
                    361:                if (!entry->path)
                    362:                {
                    363:                        DBG1(DBG_CFG, "PKCS11 module '%s' lacks library path", module);
                    364:                        free(entry);
                    365:                        continue;
                    366:                }
                    367:                entry->lib = pkcs11_library_create(module, entry->path,
                    368:                                                lib->settings->get_bool(lib->settings,
                    369:                                                        "%s.plugins.pkcs11.modules.%s.os_locking",
                    370:                                                        FALSE, lib->ns, module));
                    371:                if (!entry->lib)
                    372:                {
                    373:                        free(entry);
                    374:                        continue;
                    375:                }
                    376:                this->libs->insert_last(this->libs, entry);
                    377:        }
                    378:        enumerator->destroy(enumerator);
                    379: 
                    380:        enumerator = this->libs->create_enumerator(this->libs);
                    381:        while (enumerator->enumerate(enumerator, &entry))
                    382:        {
                    383:                query_slots(entry);
                    384:                lib->processor->queue_job(lib->processor,
                    385:                        (job_t*)callback_job_create_with_prio(dispatch_slot_events,
                    386:                                                entry, NULL, cancel_events, JOB_PRIO_CRITICAL));
                    387:        }
                    388:        enumerator->destroy(enumerator);
                    389: 
                    390:        return &this->public;
                    391: }
                    392: 

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