Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.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_hasher.h"
                     17: 
                     18: #include <unistd.h>
                     19: 
                     20: #include <utils/debug.h>
                     21: #include <threading/mutex.h>
                     22: 
                     23: #include "pkcs11_manager.h"
                     24: 
                     25: typedef struct private_pkcs11_hasher_t private_pkcs11_hasher_t;
                     26: 
                     27: /**
                     28:  * Private data of an pkcs11_hasher_t object.
                     29:  */
                     30: struct private_pkcs11_hasher_t {
                     31: 
                     32:        /**
                     33:         * Public pkcs11_hasher_t interface.
                     34:         */
                     35:        pkcs11_hasher_t public;
                     36: 
                     37:        /**
                     38:         * PKCS#11 library
                     39:         */
                     40:        pkcs11_library_t *lib;
                     41: 
                     42:        /**
                     43:         * Mechanism for this hasher
                     44:         */
                     45:        CK_MECHANISM_PTR mech;
                     46: 
                     47:        /**
                     48:         * Token session
                     49:         */
                     50:        CK_SESSION_HANDLE session;
                     51: 
                     52:        /**
                     53:         * size of the hash
                     54:         */
                     55:        size_t size;
                     56: 
                     57:        /**
                     58:         * Mutex to lock the tokens hashing engine
                     59:         */
                     60:        mutex_t *mutex;
                     61: 
                     62:        /**
                     63:         * do we have an initialized state?
                     64:         */
                     65:        bool have_state;
                     66: 
                     67:        /**
                     68:         * state buffer
                     69:         */
                     70:        CK_BYTE_PTR state;
                     71: 
                     72:        /**
                     73:         * Length of the state buffer
                     74:         */
                     75:        CK_ULONG state_len;
                     76: };
                     77: 
                     78: METHOD(hasher_t, get_hash_size, size_t,
                     79:        private_pkcs11_hasher_t *this)
                     80: {
                     81:        return this->size;
                     82: }
                     83: 
                     84: /**
                     85:  * Save the Operation state to host memory
                     86:  */
                     87: static bool save_state(private_pkcs11_hasher_t *this)
                     88: {
                     89:        CK_RV rv;
                     90: 
                     91:        while (TRUE)
                     92:        {
                     93:                if (!this->state)
                     94:                {
                     95:                        rv = this->lib->f->C_GetOperationState(this->session, NULL,
                     96:                                                                                                   &this->state_len);
                     97:                        if (rv != CKR_OK)
                     98:                        {
                     99:                                break;
                    100:                        }
                    101:                        this->state = malloc(this->state_len);
                    102:                }
                    103:                rv = this->lib->f->C_GetOperationState(this->session, this->state,
                    104:                                                                                           &this->state_len);
                    105:                switch (rv)
                    106:                {
                    107:                        case CKR_BUFFER_TOO_SMALL:
                    108:                                free(this->state);
                    109:                                this->state = NULL;
                    110:                                continue;
                    111:                        case CKR_OK:
                    112:                                this->have_state = TRUE;
                    113:                                return TRUE;
                    114:                        default:
                    115:                                break;
                    116:                }
                    117:                break;
                    118:        }
                    119:        DBG1(DBG_CFG, "C_GetOperationState() failed: %N", ck_rv_names, rv);
                    120:        return FALSE;
                    121: }
                    122: 
                    123: /**
                    124:  * Load the Operation state from host memory
                    125:  */
                    126: static bool load_state(private_pkcs11_hasher_t *this)
                    127: {
                    128:        CK_RV rv;
                    129: 
                    130:        rv = this->lib->f->C_SetOperationState(this->session, this->state,
                    131:                                                this->state_len, CK_INVALID_HANDLE, CK_INVALID_HANDLE);
                    132:        if (rv != CKR_OK)
                    133:        {
                    134:                DBG1(DBG_CFG, "C_SetOperationState() failed: %N", ck_rv_names, rv);
                    135:                return FALSE;
                    136:        }
                    137:        this->have_state = FALSE;
                    138:        return TRUE;
                    139: }
                    140: 
                    141: METHOD(hasher_t, reset, bool,
                    142:        private_pkcs11_hasher_t *this)
                    143: {
                    144:        this->have_state = FALSE;
                    145:        return TRUE;
                    146: }
                    147: 
                    148: METHOD(hasher_t, get_hash, bool,
                    149:        private_pkcs11_hasher_t *this, chunk_t chunk, uint8_t *hash)
                    150: {
                    151:        CK_RV rv;
                    152:        CK_ULONG len;
                    153: 
                    154:        this->mutex->lock(this->mutex);
                    155:        if (this->have_state)
                    156:        {
                    157:                if (!load_state(this))
                    158:                {
                    159:                        this->mutex->unlock(this->mutex);
                    160:                        return FALSE;
                    161:                }
                    162:        }
                    163:        else
                    164:        {
                    165:                rv = this->lib->f->C_DigestInit(this->session, this->mech);
                    166:                if (rv != CKR_OK)
                    167:                {
                    168:                        DBG1(DBG_CFG, "C_DigestInit() failed: %N", ck_rv_names, rv);
                    169:                        this->mutex->unlock(this->mutex);
                    170:                        return FALSE;
                    171:                }
                    172:        }
                    173:        if (chunk.len)
                    174:        {
                    175:                rv = this->lib->f->C_DigestUpdate(this->session, chunk.ptr, chunk.len);
                    176:                if (rv != CKR_OK)
                    177:                {
                    178:                        DBG1(DBG_CFG, "C_DigestUpdate() failed: %N", ck_rv_names, rv);
                    179:                        this->mutex->unlock(this->mutex);
                    180:                        return FALSE;
                    181:                }
                    182:        }
                    183:        if (hash)
                    184:        {
                    185:                len = this->size;
                    186:                rv = this->lib->f->C_DigestFinal(this->session,
                    187:                                                                hash, &len);
                    188:                if (rv != CKR_OK)
                    189:                {
                    190:                        DBG1(DBG_CFG, "C_DigestFinal() failed: %N", ck_rv_names, rv);
                    191:                        this->mutex->unlock(this->mutex);
                    192:                        return FALSE;
                    193:                }
                    194:        }
                    195:        else
                    196:        {
                    197:                if (!save_state(this))
                    198:                {
                    199:                        this->mutex->unlock(this->mutex);
                    200:                        return FALSE;
                    201:                }
                    202:        }
                    203:        this->mutex->unlock(this->mutex);
                    204:        return TRUE;
                    205: }
                    206: 
                    207: METHOD(hasher_t, allocate_hash, bool,
                    208:        private_pkcs11_hasher_t *this, chunk_t chunk, chunk_t *hash)
                    209: {
                    210:        if (hash)
                    211:        {
                    212:                *hash = chunk_alloc(this->size);
                    213:                return get_hash(this, chunk, hash->ptr);
                    214:        }
                    215:        return get_hash(this, chunk, NULL);
                    216: }
                    217: 
                    218: METHOD(hasher_t, destroy, void,
                    219:        private_pkcs11_hasher_t *this)
                    220: {
                    221:        this->lib->f->C_CloseSession(this->session);
                    222:        this->mutex->destroy(this->mutex);
                    223:        free(this);
                    224: }
                    225: 
                    226: /**
                    227:  * Get the Cryptoki mechanism for a hash algorithm
                    228:  */
                    229: static CK_MECHANISM_PTR algo_to_mechanism(hash_algorithm_t algo, size_t *size)
                    230: {
                    231:        static struct {
                    232:                hash_algorithm_t algo;
                    233:                CK_MECHANISM mechanism;
                    234:                size_t size;
                    235:        } mappings[] = {
                    236:                {HASH_MD2,              {CKM_MD2,               NULL, 0},       HASH_SIZE_MD2},
                    237:                {HASH_MD5,              {CKM_MD5,               NULL, 0},       HASH_SIZE_MD5},
                    238:                {HASH_SHA1,             {CKM_SHA_1,             NULL, 0},       HASH_SIZE_SHA1},
                    239:                {HASH_SHA256,   {CKM_SHA256,    NULL, 0},       HASH_SIZE_SHA256},
                    240:                {HASH_SHA384,   {CKM_SHA384,    NULL, 0},       HASH_SIZE_SHA384},
                    241:                {HASH_SHA512,   {CKM_SHA512,    NULL, 0},       HASH_SIZE_SHA512},
                    242:        };
                    243:        int i;
                    244: 
                    245:        for (i = 0; i < countof(mappings); i++)
                    246:        {
                    247:                if (mappings[i].algo == algo)
                    248:                {
                    249:                        *size = mappings[i].size;
                    250:                        return &mappings[i].mechanism;
                    251:                }
                    252:        }
                    253:        return NULL;
                    254: }
                    255: 
                    256: /**
                    257:  * Find a token we can use for a hash algorithm
                    258:  */
                    259: static pkcs11_library_t* find_token(hash_algorithm_t algo,
                    260:                        CK_SESSION_HANDLE *session, CK_MECHANISM_PTR *mout, size_t *size)
                    261: {
                    262:        enumerator_t *tokens, *mechs;
                    263:        pkcs11_manager_t *manager;
                    264:        pkcs11_library_t *current, *found = NULL;
                    265:        CK_MECHANISM_TYPE type;
                    266:        CK_MECHANISM_PTR mech;
                    267:        CK_SLOT_ID slot;
                    268: 
                    269:        mech = algo_to_mechanism(algo, size);
                    270:        if (!mech)
                    271:        {
                    272:                return NULL;
                    273:        }
                    274:        manager = lib->get(lib, "pkcs11-manager");
                    275:        if (!manager)
                    276:        {
                    277:                return NULL;
                    278:        }
                    279:        tokens = manager->create_token_enumerator(manager);
                    280:        while (tokens->enumerate(tokens, &current, &slot))
                    281:        {
                    282:                mechs = current->create_mechanism_enumerator(current, slot);
                    283:                while (mechs->enumerate(mechs, &type, NULL))
                    284:                {
                    285:                        if (type == mech->mechanism)
                    286:                        {
                    287:                                if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
                    288:                                                                                          NULL, NULL, session) == CKR_OK)
                    289:                                {
                    290:                                        found = current;
                    291:                                        *mout = mech;
                    292:                                        break;
                    293:                                }
                    294:                        }
                    295:                }
                    296:                mechs->destroy(mechs);
                    297:                if (found)
                    298:                {
                    299:                        break;
                    300:                }
                    301:        }
                    302:        tokens->destroy(tokens);
                    303:        return found;
                    304: }
                    305: 
                    306: /**
                    307:  * See header
                    308:  */
                    309: pkcs11_hasher_t *pkcs11_hasher_create(hash_algorithm_t algo)
                    310: {
                    311:        private_pkcs11_hasher_t *this;
                    312: 
                    313:        INIT(this,
                    314:                .public = {
                    315:                        .hasher = {
                    316:                                .get_hash_size = _get_hash_size,
                    317:                                .reset = _reset,
                    318:                                .get_hash = _get_hash,
                    319:                                .allocate_hash = _allocate_hash,
                    320:                                .destroy = _destroy,
                    321:                        },
                    322:                },
                    323:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                    324:        );
                    325: 
                    326:        this->lib = find_token(algo, &this->session, &this->mech, &this->size);
                    327:        if (!this->lib)
                    328:        {
                    329:                this->mutex->destroy(this->mutex);
                    330:                free(this);
                    331:                return NULL;
                    332:        }
                    333: 
                    334:        return &this->public;
                    335: }

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