Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2011-2016 Tobias Brunner
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             4:  *
        !             5:  * Copyright (C) 2010 Martin Willi
        !             6:  * Copyright (C) 2010 revosec AG
        !             7:  *
        !             8:  * This program is free software; you can redistribute it and/or modify it
        !             9:  * under the terms of the GNU General Public License as published by the
        !            10:  * Free Software Foundation; either version 2 of the License, or (at your
        !            11:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            12:  *
        !            13:  * This program is distributed in the hope that it will be useful, but
        !            14:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            15:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            16:  * for more details.
        !            17:  */
        !            18: /*
        !            19:  * Copyright (C) 2016 EDF S.A.
        !            20:  *
        !            21:  * Permission is hereby granted, free of charge, to any person obtaining a copy
        !            22:  * of this software and associated documentation files (the "Software"), to deal
        !            23:  * in the Software without restriction, including without limitation the rights
        !            24:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        !            25:  * copies of the Software, and to permit persons to whom the Software is
        !            26:  * furnished to do so, subject to the following conditions:
        !            27:  *
        !            28:  * The above copyright notice and this permission notice shall be included in
        !            29:  * all copies or substantial portions of the Software.
        !            30:  *
        !            31:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        !            32:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            33:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        !            34:  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            35:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        !            36:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
        !            37:  * THE SOFTWARE.
        !            38:  */
        !            39: 
        !            40: #include "pkcs11_private_key.h"
        !            41: 
        !            42: #include "pkcs11_library.h"
        !            43: #include "pkcs11_manager.h"
        !            44: #include "pkcs11_public_key.h"
        !            45: 
        !            46: #include <utils/debug.h>
        !            47: #include <asn1/asn1.h>
        !            48: 
        !            49: typedef struct private_pkcs11_private_key_t private_pkcs11_private_key_t;
        !            50: 
        !            51: /**
        !            52:  * Private data of an pkcs11_private_key_t object.
        !            53:  */
        !            54: struct private_pkcs11_private_key_t {
        !            55: 
        !            56:        /**
        !            57:         * Public pkcs11_private_key_t interface.
        !            58:         */
        !            59:        pkcs11_private_key_t public;
        !            60: 
        !            61:        /**
        !            62:         * PKCS#11 module
        !            63:         */
        !            64:        pkcs11_library_t *lib;
        !            65: 
        !            66:        /**
        !            67:         * Slot the token is in
        !            68:         */
        !            69:        CK_SLOT_ID slot;
        !            70: 
        !            71:        /**
        !            72:         * Token session
        !            73:         */
        !            74:        CK_SESSION_HANDLE session;
        !            75: 
        !            76:        /**
        !            77:         * Key object on the token
        !            78:         */
        !            79:        CK_OBJECT_HANDLE object;
        !            80: 
        !            81:        /**
        !            82:         * Key requires reauthentication for each signature/decryption
        !            83:         */
        !            84:        CK_BBOOL reauth;
        !            85: 
        !            86:        /**
        !            87:         * Keyid of the key we use
        !            88:         */
        !            89:        identification_t *keyid;
        !            90: 
        !            91:        /**
        !            92:         * Associated public key
        !            93:         */
        !            94:        public_key_t *pubkey;
        !            95: 
        !            96:        /**
        !            97:         * References to this key
        !            98:         */
        !            99:        refcount_t ref;
        !           100: 
        !           101:        /**
        !           102:         * Type of this private key
        !           103:         */
        !           104:        key_type_t type;
        !           105: };
        !           106: 
        !           107: 
        !           108: METHOD(private_key_t, get_type, key_type_t,
        !           109:        private_pkcs11_private_key_t *this)
        !           110: {
        !           111:        return this->type;
        !           112: }
        !           113: 
        !           114: METHOD(private_key_t, get_keysize, int,
        !           115:        private_pkcs11_private_key_t *this)
        !           116: {
        !           117:        return this->pubkey->get_keysize(this->pubkey);
        !           118: }
        !           119: 
        !           120: /**
        !           121:  * See header.
        !           122:  */
        !           123: CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme,
        !           124:                                                                                                 key_type_t type, size_t keylen,
        !           125:                                                                                                 hash_algorithm_t *hash)
        !           126: {
        !           127:        static struct {
        !           128:                signature_scheme_t scheme;
        !           129:                CK_MECHANISM mechanism;
        !           130:                key_type_t type;
        !           131:                size_t keylen;
        !           132:                hash_algorithm_t hash;
        !           133:        } mappings[] = {
        !           134:                {SIGN_RSA_EMSA_PKCS1_NULL,              {CKM_RSA_PKCS,                  NULL, 0},
        !           135:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
        !           136:                {SIGN_RSA_EMSA_PKCS1_SHA2_256,  {CKM_SHA256_RSA_PKCS,   NULL, 0},
        !           137:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
        !           138:                {SIGN_RSA_EMSA_PKCS1_SHA2_384,  {CKM_SHA384_RSA_PKCS,   NULL, 0},
        !           139:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
        !           140:                {SIGN_RSA_EMSA_PKCS1_SHA2_512,  {CKM_SHA512_RSA_PKCS,   NULL, 0},
        !           141:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
        !           142:                {SIGN_RSA_EMSA_PKCS1_SHA1,              {CKM_SHA1_RSA_PKCS,             NULL, 0},
        !           143:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
        !           144:                {SIGN_RSA_EMSA_PKCS1_MD5,               {CKM_MD5_RSA_PKCS,              NULL, 0},
        !           145:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
        !           146:                {SIGN_ECDSA_WITH_NULL,                  {CKM_ECDSA,                             NULL, 0},
        !           147:                 KEY_ECDSA, 0,                                                                     HASH_UNKNOWN},
        !           148:                {SIGN_ECDSA_WITH_SHA1_DER,              {CKM_ECDSA_SHA1,                NULL, 0},
        !           149:                 KEY_ECDSA, 0,                                                                     HASH_UNKNOWN},
        !           150:                {SIGN_ECDSA_WITH_SHA256_DER,    {CKM_ECDSA,                             NULL, 0},
        !           151:                 KEY_ECDSA, 0,                                                                          HASH_SHA256},
        !           152:                {SIGN_ECDSA_WITH_SHA384_DER,    {CKM_ECDSA,                             NULL, 0},
        !           153:                 KEY_ECDSA, 0,                                                                          HASH_SHA384},
        !           154:                {SIGN_ECDSA_WITH_SHA512_DER,    {CKM_ECDSA,                             NULL, 0},
        !           155:                 KEY_ECDSA, 0,                                                                          HASH_SHA512},
        !           156:                {SIGN_ECDSA_256,                                {CKM_ECDSA,                             NULL, 0},
        !           157:                 KEY_ECDSA, 256,                                                                        HASH_SHA256},
        !           158:                {SIGN_ECDSA_384,                                {CKM_ECDSA,                             NULL, 0},
        !           159:                 KEY_ECDSA, 384,                                                                        HASH_SHA384},
        !           160:                {SIGN_ECDSA_521,                                {CKM_ECDSA,                             NULL, 0},
        !           161:                 KEY_ECDSA, 521,                                                                        HASH_SHA512},
        !           162:        };
        !           163:        int i;
        !           164: 
        !           165:        for (i = 0; i < countof(mappings); i++)
        !           166:        {
        !           167:                if (mappings[i].scheme == scheme)
        !           168:                {
        !           169:                        size_t len = mappings[i].keylen;
        !           170:                        if (mappings[i].type != type || (len && keylen != len))
        !           171:                        {
        !           172:                                return NULL;
        !           173:                        }
        !           174:                        if (hash)
        !           175:                        {
        !           176:                                *hash = mappings[i].hash;
        !           177:                        }
        !           178:                        return &mappings[i].mechanism;
        !           179:                }
        !           180:        }
        !           181:        return NULL;
        !           182: }
        !           183: 
        !           184: /**
        !           185:  * See header.
        !           186:  */
        !           187: CK_MECHANISM_PTR pkcs11_encryption_scheme_to_mech(encryption_scheme_t scheme)
        !           188: {
        !           189:        static struct {
        !           190:                encryption_scheme_t scheme;
        !           191:                CK_MECHANISM mechanism;
        !           192:        } mappings[] = {
        !           193:                {ENCRYPT_RSA_PKCS1,                     {CKM_RSA_PKCS,                          NULL, 0}},
        !           194:                {ENCRYPT_RSA_OAEP_SHA1,         {CKM_RSA_PKCS_OAEP,                     NULL, 0}},
        !           195:        };
        !           196:        int i;
        !           197: 
        !           198:        for (i = 0; i < countof(mappings); i++)
        !           199:        {
        !           200:                if (mappings[i].scheme == scheme)
        !           201:                {
        !           202:                        return &mappings[i].mechanism;
        !           203:                }
        !           204:        }
        !           205:        return NULL;
        !           206: }
        !           207: 
        !           208: /**
        !           209:  * Reauthenticate to do a signature
        !           210:  */
        !           211: static bool reauth(private_pkcs11_private_key_t *this,
        !           212:                                   CK_SESSION_HANDLE session)
        !           213: {
        !           214:        enumerator_t *enumerator;
        !           215:        shared_key_t *shared;
        !           216:        chunk_t pin;
        !           217:        CK_RV rv;
        !           218:        bool found = FALSE, success = FALSE;
        !           219: 
        !           220:        enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
        !           221:                                                                                                SHARED_PIN, this->keyid, NULL);
        !           222:        while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
        !           223:        {
        !           224:                found = TRUE;
        !           225:                pin = shared->get_key(shared);
        !           226:                rv = this->lib->f->C_Login(session, CKU_CONTEXT_SPECIFIC,
        !           227:                                                                   pin.ptr, pin.len);
        !           228:                if (rv == CKR_OK)
        !           229:                {
        !           230:                        success = TRUE;
        !           231:                        break;
        !           232:                }
        !           233:                DBG1(DBG_CFG, "reauthentication login failed: %N", ck_rv_names, rv);
        !           234:        }
        !           235:        enumerator->destroy(enumerator);
        !           236: 
        !           237:        if (!found)
        !           238:        {
        !           239:                DBG1(DBG_CFG, "private key requires reauthentication, but no PIN found");
        !           240:                return FALSE;
        !           241:        }
        !           242:        return success;
        !           243: }
        !           244: 
        !           245: METHOD(private_key_t, sign, bool,
        !           246:        private_pkcs11_private_key_t *this, signature_scheme_t scheme, void *params,
        !           247:        chunk_t data, chunk_t *signature)
        !           248: {
        !           249:        CK_MECHANISM_PTR mechanism;
        !           250:        CK_SESSION_HANDLE session;
        !           251:        CK_BYTE_PTR buf;
        !           252:        CK_ULONG len;
        !           253:        CK_RV rv;
        !           254:        hash_algorithm_t hash_alg;
        !           255:        chunk_t hash = chunk_empty;
        !           256: 
        !           257:        mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type,
        !           258:                                                                                                get_keysize(this), &hash_alg);
        !           259:        if (!mechanism)
        !           260:        {
        !           261:                DBG1(DBG_LIB, "signature scheme %N not supported",
        !           262:                         signature_scheme_names, scheme);
        !           263:                return FALSE;
        !           264:        }
        !           265:        rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
        !           266:                                                                         &session);
        !           267:        if (rv != CKR_OK)
        !           268:        {
        !           269:                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
        !           270:                return FALSE;
        !           271:        }
        !           272:        rv = this->lib->f->C_SignInit(session, mechanism, this->object);
        !           273:        if (this->reauth && !reauth(this, session))
        !           274:        {
        !           275:                this->lib->f->C_CloseSession(session);
        !           276:                return FALSE;
        !           277:        }
        !           278:        if (rv != CKR_OK)
        !           279:        {
        !           280:                this->lib->f->C_CloseSession(session);
        !           281:                DBG1(DBG_LIB, "C_SignInit() failed: %N", ck_rv_names, rv);
        !           282:                return FALSE;
        !           283:        }
        !           284:        if (hash_alg != HASH_UNKNOWN)
        !           285:        {
        !           286:                hasher_t *hasher;
        !           287: 
        !           288:                hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
        !           289:                if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
        !           290:                {
        !           291:                        DESTROY_IF(hasher);
        !           292:                        this->lib->f->C_CloseSession(session);
        !           293:                        return FALSE;
        !           294:                }
        !           295:                hasher->destroy(hasher);
        !           296:                data = hash;
        !           297:        }
        !           298:        len = (get_keysize(this) + 7) / 8;
        !           299:        if (this->type == KEY_ECDSA)
        !           300:        {       /* signature is twice the length of the base point order */
        !           301:                len *= 2;
        !           302:        }
        !           303:        buf = malloc(len);
        !           304:        rv = this->lib->f->C_Sign(session, data.ptr, data.len, buf, &len);
        !           305:        this->lib->f->C_CloseSession(session);
        !           306:        chunk_free(&hash);
        !           307:        if (rv != CKR_OK)
        !           308:        {
        !           309:                DBG1(DBG_LIB, "C_Sign() failed: %N", ck_rv_names, rv);
        !           310:                free(buf);
        !           311:                return FALSE;
        !           312:        }
        !           313:        switch (scheme)
        !           314:        {
        !           315:                case SIGN_ECDSA_WITH_SHA1_DER:
        !           316:                case SIGN_ECDSA_WITH_SHA256_DER:
        !           317:                case SIGN_ECDSA_WITH_SHA384_DER:
        !           318:                case SIGN_ECDSA_WITH_SHA512_DER:
        !           319:                {
        !           320:                        chunk_t r, s;
        !           321: 
        !           322:                        /* return an ASN.1 encoded sequence of integers r and s, removing
        !           323:                         * any zero-padding */
        !           324:                        len /= 2;
        !           325:                        r = chunk_skip_zero(chunk_create(buf, len));
        !           326:                        s = chunk_skip_zero(chunk_create(buf+len, len));
        !           327:                        *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
        !           328:                                                                   asn1_integer("c", r), asn1_integer("c", s));
        !           329:                        free(buf);
        !           330:                        break;
        !           331:                }
        !           332:                default:
        !           333:                        *signature = chunk_create(buf, len);
        !           334:                        break;
        !           335:        }
        !           336:        return TRUE;
        !           337: }
        !           338: 
        !           339: METHOD(private_key_t, decrypt, bool,
        !           340:        private_pkcs11_private_key_t *this, encryption_scheme_t scheme,
        !           341:        chunk_t crypt, chunk_t *plain)
        !           342: {
        !           343:        CK_MECHANISM_PTR mechanism;
        !           344:        CK_SESSION_HANDLE session;
        !           345:        CK_BYTE_PTR buf;
        !           346:        CK_ULONG len;
        !           347:        CK_RV rv;
        !           348: 
        !           349:        mechanism = pkcs11_encryption_scheme_to_mech(scheme);
        !           350:        if (!mechanism)
        !           351:        {
        !           352:                DBG1(DBG_LIB, "encryption scheme %N not supported",
        !           353:                         encryption_scheme_names, scheme);
        !           354:                return FALSE;
        !           355:        }
        !           356:        rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
        !           357:                                                                         &session);
        !           358:        if (rv != CKR_OK)
        !           359:        {
        !           360:                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
        !           361:                return FALSE;
        !           362:        }
        !           363:        rv = this->lib->f->C_DecryptInit(session, mechanism, this->object);
        !           364:        if (this->reauth && !reauth(this, session))
        !           365:        {
        !           366:                this->lib->f->C_CloseSession(session);
        !           367:                return FALSE;
        !           368:        }
        !           369:        if (rv != CKR_OK)
        !           370:        {
        !           371:                this->lib->f->C_CloseSession(session);
        !           372:                DBG1(DBG_LIB, "C_DecryptInit() failed: %N", ck_rv_names, rv);
        !           373:                return FALSE;
        !           374:        }
        !           375:        len = (get_keysize(this) + 7) / 8;
        !           376:        buf = malloc(len);
        !           377:        rv = this->lib->f->C_Decrypt(session, crypt.ptr, crypt.len, buf, &len);
        !           378:        this->lib->f->C_CloseSession(session);
        !           379:        if (rv != CKR_OK)
        !           380:        {
        !           381:                DBG1(DBG_LIB, "C_Decrypt() failed: %N", ck_rv_names, rv);
        !           382:                free(buf);
        !           383:                return FALSE;
        !           384:        }
        !           385:        *plain = chunk_create(buf, len);
        !           386:        return TRUE;
        !           387: }
        !           388: 
        !           389: METHOD(private_key_t, get_public_key, public_key_t*,
        !           390:        private_pkcs11_private_key_t *this)
        !           391: {
        !           392:        return this->pubkey->get_ref(this->pubkey);
        !           393: }
        !           394: 
        !           395: METHOD(private_key_t, get_fingerprint, bool,
        !           396:        private_pkcs11_private_key_t *this, cred_encoding_type_t type,
        !           397:        chunk_t *fingerprint)
        !           398: {
        !           399:        return this->pubkey->get_fingerprint(this->pubkey, type, fingerprint);
        !           400: }
        !           401: 
        !           402: METHOD(private_key_t, get_encoding, bool,
        !           403:        private_pkcs11_private_key_t *this, cred_encoding_type_t type,
        !           404:        chunk_t *encoding)
        !           405: {
        !           406:        return FALSE;
        !           407: }
        !           408: 
        !           409: METHOD(private_key_t, get_ref, private_key_t*,
        !           410:        private_pkcs11_private_key_t *this)
        !           411: {
        !           412:        ref_get(&this->ref);
        !           413:        return &this->public.key;
        !           414: }
        !           415: 
        !           416: METHOD(private_key_t, destroy, void,
        !           417:        private_pkcs11_private_key_t *this)
        !           418: {
        !           419:        if (ref_put(&this->ref))
        !           420:        {
        !           421:                if (this->pubkey)
        !           422:                {
        !           423:                        this->pubkey->destroy(this->pubkey);
        !           424:                }
        !           425:                this->keyid->destroy(this->keyid);
        !           426:                this->lib->f->C_CloseSession(this->session);
        !           427:                free(this);
        !           428:        }
        !           429: }
        !           430: 
        !           431: /**
        !           432:  * Find the PKCS#11 library by its friendly name
        !           433:  */
        !           434: static pkcs11_library_t* find_lib(char *module)
        !           435: {
        !           436:        pkcs11_manager_t *manager;
        !           437:        enumerator_t *enumerator;
        !           438:        pkcs11_library_t *p11, *found = NULL;
        !           439:        CK_SLOT_ID slot;
        !           440: 
        !           441:        manager = lib->get(lib, "pkcs11-manager");
        !           442:        if (!manager)
        !           443:        {
        !           444:                return NULL;
        !           445:        }
        !           446:        enumerator = manager->create_token_enumerator(manager);
        !           447:        while (enumerator->enumerate(enumerator, &p11, &slot))
        !           448:        {
        !           449:                if (streq(module, p11->get_name(p11)))
        !           450:                {
        !           451:                        found = p11;
        !           452:                        break;
        !           453:                }
        !           454:        }
        !           455:        enumerator->destroy(enumerator);
        !           456:        return found;
        !           457: }
        !           458: 
        !           459: /**
        !           460:  * Find the PKCS#11 lib having a keyid, and optionally a slot
        !           461:  */
        !           462: static pkcs11_library_t* find_lib_by_keyid(chunk_t keyid, int *slot,
        !           463:                                                                                   CK_OBJECT_CLASS class)
        !           464: {
        !           465:        pkcs11_manager_t *manager;
        !           466:        enumerator_t *enumerator;
        !           467:        pkcs11_library_t *p11, *found = NULL;
        !           468:        CK_SLOT_ID current;
        !           469: 
        !           470:        manager = lib->get(lib, "pkcs11-manager");
        !           471:        if (!manager)
        !           472:        {
        !           473:                return NULL;
        !           474:        }
        !           475:        enumerator = manager->create_token_enumerator(manager);
        !           476:        while (enumerator->enumerate(enumerator, &p11, &current))
        !           477:        {
        !           478:                if (*slot == -1 || *slot == current)
        !           479:                {
        !           480:                        /* look for a pubkey/cert, it is usually readable without login */
        !           481:                        CK_ATTRIBUTE tmpl[] = {
        !           482:                                {CKA_CLASS, &class, sizeof(class)},
        !           483:                                {CKA_ID, keyid.ptr, keyid.len},
        !           484:                        };
        !           485:                        CK_OBJECT_HANDLE object;
        !           486:                        CK_SESSION_HANDLE session;
        !           487:                        CK_RV rv;
        !           488:                        enumerator_t *keys;
        !           489: 
        !           490:                        rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
        !           491:                                                                           &session);
        !           492:                        if (rv != CKR_OK)
        !           493:                        {
        !           494:                                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
        !           495:                                         ck_rv_names, rv);
        !           496:                                continue;
        !           497:                        }
        !           498:                        keys = p11->create_object_enumerator(p11, session,
        !           499:                                                                                                 tmpl, countof(tmpl), NULL, 0);
        !           500:                        if (keys->enumerate(keys, &object))
        !           501:                        {
        !           502:                                DBG1(DBG_CFG, "found key on PKCS#11 token '%s':%d",
        !           503:                                         p11->get_name(p11), current);
        !           504:                                found = p11;
        !           505:                                *slot = current;
        !           506:                        }
        !           507:                        keys->destroy(keys);
        !           508:                        p11->f->C_CloseSession(session);
        !           509:                        if (found)
        !           510:                        {
        !           511:                                break;
        !           512:                        }
        !           513:                }
        !           514:        }
        !           515:        enumerator->destroy(enumerator);
        !           516:        return found;
        !           517: }
        !           518: 
        !           519: /**
        !           520:  * Find the PKCS#11 lib and CKA_ID of the certificate object of a given
        !           521:  * subjectKeyIdentifier and optional slot
        !           522:  */
        !           523: static pkcs11_library_t* find_lib_and_keyid_by_skid(chunk_t keyid_chunk,
        !           524:                                                                                                        chunk_t *ckaid, int *slot)
        !           525: {
        !           526:        CK_OBJECT_CLASS class = CKO_CERTIFICATE;
        !           527:        CK_CERTIFICATE_TYPE type = CKC_X_509;
        !           528:        CK_ATTRIBUTE tmpl[] = {
        !           529:                {CKA_CLASS, &class, sizeof(class)},
        !           530:                {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
        !           531:        };
        !           532:        CK_ATTRIBUTE attr[] = {
        !           533:                {CKA_VALUE, NULL, 0},
        !           534:                {CKA_ID, NULL, 0},
        !           535:        };
        !           536:        CK_OBJECT_HANDLE object;
        !           537:        CK_SESSION_HANDLE session;
        !           538:        CK_RV rv;
        !           539:        pkcs11_manager_t *manager;
        !           540:        enumerator_t *enumerator, *certs;
        !           541:        identification_t *keyid;
        !           542:        pkcs11_library_t *p11, *found = NULL;
        !           543:        CK_SLOT_ID current;
        !           544:        linked_list_t *raw;
        !           545:        certificate_t *cert;
        !           546:        struct {
        !           547:                chunk_t value;
        !           548:                chunk_t ckaid;
        !           549:        } *entry;
        !           550: 
        !           551:        manager = lib->get(lib, "pkcs11-manager");
        !           552:        if (!manager)
        !           553:        {
        !           554:                return NULL;
        !           555:        }
        !           556: 
        !           557:        keyid = identification_create_from_encoding(ID_KEY_ID, keyid_chunk);
        !           558:        /* store result in a temporary list, avoid recursive operation */
        !           559:        raw = linked_list_create();
        !           560: 
        !           561:        enumerator = manager->create_token_enumerator(manager);
        !           562:        while (enumerator->enumerate(enumerator, &p11, &current))
        !           563:        {
        !           564:                if (*slot != -1 && *slot != current)
        !           565:                {
        !           566:                        continue;
        !           567:                }
        !           568:                rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
        !           569:                                                                   &session);
        !           570:                if (rv != CKR_OK)
        !           571:                {
        !           572:                        DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
        !           573:                                 ck_rv_names, rv);
        !           574:                        continue;
        !           575:                }
        !           576:                certs = p11->create_object_enumerator(p11, session, tmpl, countof(tmpl),
        !           577:                                                                                          attr, countof(attr));
        !           578:                while (certs->enumerate(certs, &object))
        !           579:                {
        !           580:                        INIT(entry,
        !           581:                                .value = chunk_clone(
        !           582:                                                        chunk_create(attr[0].pValue, attr[0].ulValueLen)),
        !           583:                                .ckaid = chunk_clone(
        !           584:                                                        chunk_create(attr[1].pValue, attr[1].ulValueLen)),
        !           585:                        );
        !           586:                        raw->insert_last(raw, entry);
        !           587:                }
        !           588:                certs->destroy(certs);
        !           589: 
        !           590:                while (raw->remove_first(raw, (void**)&entry) == SUCCESS)
        !           591:                {
        !           592:                        if (!found)
        !           593:                        {
        !           594:                                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
        !           595:                                                                                  CERT_X509, BUILD_BLOB_ASN1_DER,
        !           596:                                                                                  entry->value, BUILD_END);
        !           597:                                if (cert)
        !           598:                                {
        !           599:                                        if (cert->has_subject(cert, keyid))
        !           600:                                        {
        !           601:                                                DBG1(DBG_CFG, "found cert with keyid '%#B' on PKCS#11 "
        !           602:                                                         "token '%s':%d", &keyid_chunk, p11->get_name(p11),
        !           603:                                                         current);
        !           604:                                                found = p11;
        !           605:                                                *ckaid = chunk_clone(entry->ckaid);
        !           606:                                                *slot = current;
        !           607:                                        }
        !           608:                                        cert->destroy(cert);
        !           609:                                }
        !           610:                                else
        !           611:                                {
        !           612:                                        DBG1(DBG_CFG, "parsing cert with CKA_ID '%#B' on PKCS#11 "
        !           613:                                                 "token '%s':%d failed", &entry->ckaid,
        !           614:                                                 p11->get_name(p11), current);
        !           615:                                }
        !           616:                        }
        !           617:                        chunk_free(&entry->value);
        !           618:                        chunk_free(&entry->ckaid);
        !           619:                        free(entry);
        !           620:                }
        !           621:                p11->f->C_CloseSession(session);
        !           622:                if (found)
        !           623:                {
        !           624:                        break;
        !           625:                }
        !           626:        }
        !           627:        enumerator->destroy(enumerator);
        !           628:        keyid->destroy(keyid);
        !           629:        raw->destroy(raw);
        !           630:        return found;
        !           631: }
        !           632: 
        !           633: /**
        !           634:  * Find the key on the token
        !           635:  */
        !           636: static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid)
        !           637: {
        !           638:        CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
        !           639:        CK_ATTRIBUTE tmpl[] = {
        !           640:                {CKA_CLASS, &class, sizeof(class)},
        !           641:                {CKA_ID, keyid.ptr, keyid.len},
        !           642:        };
        !           643:        CK_OBJECT_HANDLE object;
        !           644:        CK_KEY_TYPE type;
        !           645:        CK_BBOOL reauth = FALSE;
        !           646:        CK_ATTRIBUTE attr[] = {
        !           647:                {CKA_KEY_TYPE, &type, sizeof(type)},
        !           648:                {CKA_ALWAYS_AUTHENTICATE, &reauth, sizeof(reauth)},
        !           649:        };
        !           650:        enumerator_t *enumerator;
        !           651:        int count = countof(attr);
        !           652:        bool found = FALSE;
        !           653: 
        !           654:        /* do not use CKA_ALWAYS_AUTHENTICATE if not supported */
        !           655:        if (!(this->lib->get_features(this->lib) & PKCS11_ALWAYS_AUTH_KEYS))
        !           656:        {
        !           657:                count--;
        !           658:        }
        !           659:        enumerator = this->lib->create_object_enumerator(this->lib,
        !           660:                                                        this->session, tmpl, countof(tmpl), attr, count);
        !           661:        if (enumerator->enumerate(enumerator, &object))
        !           662:        {
        !           663:                this->type = KEY_RSA;
        !           664:                switch (type)
        !           665:                {
        !           666:                        case CKK_ECDSA:
        !           667:                                this->type = KEY_ECDSA;
        !           668:                                /* fall-through */
        !           669:                        case CKK_RSA:
        !           670:                                this->reauth = reauth;
        !           671:                                this->object = object;
        !           672:                                found = TRUE;
        !           673:                                break;
        !           674:                        default:
        !           675:                                DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
        !           676:                                break;
        !           677:                }
        !           678:        }
        !           679:        enumerator->destroy(enumerator);
        !           680:        return found;
        !           681: }
        !           682: 
        !           683: /**
        !           684:  * Find a PIN and try to log in
        !           685:  */
        !           686: static bool login(private_pkcs11_private_key_t *this, int slot)
        !           687: {
        !           688:        enumerator_t *enumerator;
        !           689:        shared_key_t *shared;
        !           690:        chunk_t pin;
        !           691:        CK_RV rv;
        !           692:        CK_SESSION_INFO info;
        !           693:        bool found = FALSE, success = FALSE;
        !           694: 
        !           695:        rv = this->lib->f->C_GetSessionInfo(this->session, &info);
        !           696:        if (rv != CKR_OK)
        !           697:        {
        !           698:                DBG1(DBG_CFG, "C_GetSessionInfo failed: %N", ck_rv_names, rv);
        !           699:                return FALSE;
        !           700:        }
        !           701:        if (info.state != CKS_RO_PUBLIC_SESSION &&
        !           702:                info.state != CKS_RW_PUBLIC_SESSION)
        !           703:        {       /* already logged in with another session, skip */
        !           704:                return TRUE;
        !           705:        }
        !           706: 
        !           707:        enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
        !           708:                                                                                                SHARED_PIN, this->keyid, NULL);
        !           709:        while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
        !           710:        {
        !           711:                found = TRUE;
        !           712:                pin = shared->get_key(shared);
        !           713:                rv = this->lib->f->C_Login(this->session, CKU_USER, pin.ptr, pin.len);
        !           714:                if (rv == CKR_OK)
        !           715:                {
        !           716:                        success = TRUE;
        !           717:                        break;
        !           718:                }
        !           719:                DBG1(DBG_CFG, "login to '%s':%d failed: %N",
        !           720:                         this->lib->get_name(this->lib), slot, ck_rv_names, rv);
        !           721:        }
        !           722:        enumerator->destroy(enumerator);
        !           723: 
        !           724:        if (!found)
        !           725:        {
        !           726:                DBG1(DBG_CFG, "no PIN found for PKCS#11 key %Y", this->keyid);
        !           727:                return FALSE;
        !           728:        }
        !           729:        return success;
        !           730: }
        !           731: 
        !           732: /**
        !           733:  * Get a public key from a certificate with a given key ID.
        !           734:  */
        !           735: static public_key_t* find_pubkey_in_certs(private_pkcs11_private_key_t *this,
        !           736:                                                                                  chunk_t keyid)
        !           737: {
        !           738:        CK_OBJECT_CLASS class = CKO_CERTIFICATE;
        !           739:        CK_CERTIFICATE_TYPE type = CKC_X_509;
        !           740:        CK_ATTRIBUTE tmpl[] = {
        !           741:                {CKA_CLASS, &class, sizeof(class)},
        !           742:                {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
        !           743:                {CKA_ID, keyid.ptr, keyid.len},
        !           744:        };
        !           745:        CK_OBJECT_HANDLE object;
        !           746:        CK_ATTRIBUTE attr[] = {
        !           747:                {CKA_VALUE, NULL, 0},
        !           748:        };
        !           749:        enumerator_t *enumerator;
        !           750:        chunk_t data = chunk_empty;
        !           751:        public_key_t *key = NULL;
        !           752:        certificate_t *cert;
        !           753: 
        !           754:        enumerator = this->lib->create_object_enumerator(this->lib, this->session,
        !           755:                                                                        tmpl, countof(tmpl), attr, countof(attr));
        !           756:        if (enumerator->enumerate(enumerator, &object))
        !           757:        {
        !           758:                data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen));
        !           759:        }
        !           760:        enumerator->destroy(enumerator);
        !           761: 
        !           762:        if (data.ptr)
        !           763:        {
        !           764:                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
        !           765:                                                                  BUILD_BLOB_ASN1_DER, data, BUILD_END);
        !           766:                free(data.ptr);
        !           767:                if (cert)
        !           768:                {
        !           769:                        key = cert->get_public_key(cert);
        !           770:                        cert->destroy(cert);
        !           771:                }
        !           772:        }
        !           773:        return key;
        !           774: }
        !           775: 
        !           776: /**
        !           777:  * See header.
        !           778:  */
        !           779: pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args)
        !           780: {
        !           781:        private_pkcs11_private_key_t *this;
        !           782:        char *module = NULL;
        !           783:        chunk_t keyid = chunk_empty, ckaid = chunk_empty;
        !           784:        int slot = -1;
        !           785:        CK_RV rv;
        !           786: 
        !           787:        while (TRUE)
        !           788:        {
        !           789:                switch (va_arg(args, builder_part_t))
        !           790:                {
        !           791:                        case BUILD_PKCS11_KEYID:
        !           792:                                keyid = va_arg(args, chunk_t);
        !           793:                                continue;
        !           794:                        case BUILD_PKCS11_SLOT:
        !           795:                                slot = va_arg(args, int);
        !           796:                                continue;
        !           797:                        case BUILD_PKCS11_MODULE:
        !           798:                                module = va_arg(args, char*);
        !           799:                                continue;
        !           800:                        case BUILD_END:
        !           801:                                break;
        !           802:                        default:
        !           803:                                return NULL;
        !           804:                }
        !           805:                break;
        !           806:        }
        !           807:        if (!keyid.len)
        !           808:        {
        !           809:                return NULL;
        !           810:        }
        !           811: 
        !           812:        INIT(this,
        !           813:                .public = {
        !           814:                        .key = {
        !           815:                                .get_type = _get_type,
        !           816:                                .sign = _sign,
        !           817:                                .decrypt = _decrypt,
        !           818:                                .get_keysize = _get_keysize,
        !           819:                                .get_public_key = _get_public_key,
        !           820:                                .equals = private_key_equals,
        !           821:                                .belongs_to = private_key_belongs_to,
        !           822:                                .get_fingerprint = _get_fingerprint,
        !           823:                                .has_fingerprint = private_key_has_fingerprint,
        !           824:                                .get_encoding = _get_encoding,
        !           825:                                .get_ref = _get_ref,
        !           826:                                .destroy = _destroy,
        !           827:                        },
        !           828:                },
        !           829:                .ref = 1,
        !           830:        );
        !           831: 
        !           832:        if (module && slot != -1)
        !           833:        {
        !           834:                this->lib = find_lib(module);
        !           835:                if (!this->lib)
        !           836:                {
        !           837:                        DBG1(DBG_CFG, "PKCS#11 module '%s' not found", module);
        !           838:                        free(this);
        !           839:                        return NULL;
        !           840:                }
        !           841:        }
        !           842:        else
        !           843:        {
        !           844:                this->lib = find_lib_by_keyid(keyid, &slot, CKO_PUBLIC_KEY);
        !           845:                if (!this->lib)
        !           846:                {
        !           847:                        this->lib = find_lib_by_keyid(keyid, &slot, CKO_CERTIFICATE);
        !           848:                }
        !           849:                if (!this->lib)
        !           850:                {
        !           851:                        this->lib = find_lib_and_keyid_by_skid(keyid, &ckaid, &slot);
        !           852:                }
        !           853:                if (!this->lib)
        !           854:                {
        !           855:                        DBG1(DBG_CFG, "no PKCS#11 module found having a keyid %#B", &keyid);
        !           856:                        free(this);
        !           857:                        return NULL;
        !           858:                }
        !           859:        }
        !           860: 
        !           861:        rv = this->lib->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
        !           862:                                                                         NULL, NULL, &this->session);
        !           863:        if (rv != CKR_OK)
        !           864:        {
        !           865:                DBG1(DBG_CFG, "opening private key session on '%s':%d failed: %N",
        !           866:                         module, slot, ck_rv_names, rv);
        !           867:                free(this);
        !           868:                return NULL;
        !           869:        }
        !           870: 
        !           871:        this->slot = slot;
        !           872:        this->keyid = identification_create_from_encoding(ID_KEY_ID, keyid);
        !           873: 
        !           874:        if (!login(this, slot))
        !           875:        {
        !           876:                destroy(this);
        !           877:                return NULL;
        !           878:        }
        !           879: 
        !           880:        if (ckaid.ptr)
        !           881:        {
        !           882:                DBG1(DBG_CFG, "using CKA_ID '%#B' for key with keyid '%#B'",
        !           883:                         &ckaid, &keyid);
        !           884:                keyid = ckaid;
        !           885:        }
        !           886: 
        !           887:        if (!find_key(this, keyid))
        !           888:        {
        !           889:                DBG1(DBG_CFG, "did not find the key with %s '%#B'",
        !           890:                         ckaid.ptr ? "CKA_ID" : "keyid", &keyid);
        !           891:                destroy(this);
        !           892:                return NULL;
        !           893:        }
        !           894: 
        !           895:        this->pubkey = pkcs11_public_key_connect(this->lib, slot, this->type, keyid);
        !           896:        if (!this->pubkey)
        !           897:        {
        !           898:                this->pubkey = find_pubkey_in_certs(this, keyid);
        !           899:                if (!this->pubkey)
        !           900:                {
        !           901:                        DBG1(DBG_CFG, "no public key or certificate found for private key "
        !           902:                                 "(%s '%#B') on '%s':%d", ckaid.ptr ? "CKA_ID" : "keyid",
        !           903:                                 &keyid, module, slot);
        !           904:                        destroy(this);
        !           905:                        return NULL;
        !           906:                }
        !           907:        }
        !           908:        return &this->public;
        !           909: }

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