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

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: /**
1.1.1.2 ! misho     121:  * Check if a token supports the given mechanism.
1.1       misho     122:  */
1.1.1.2 ! misho     123: static bool is_mechanism_supported(pkcs11_library_t *p11, CK_SLOT_ID slot,
        !           124:                                                                   const CK_MECHANISM_PTR mech)
        !           125: {
        !           126:        enumerator_t *mechs;
        !           127:        CK_MECHANISM_TYPE type;
        !           128: 
        !           129:        mechs = p11->create_mechanism_enumerator(p11, slot);
        !           130:        while (mechs->enumerate(mechs, &type, NULL))
        !           131:        {
        !           132:                if (type == mech->mechanism)
        !           133:                {
        !           134:                        mechs->destroy(mechs);
        !           135:                        return TRUE;
        !           136:                }
        !           137:        }
        !           138:        mechs->destroy(mechs);
        !           139:        return FALSE;
        !           140: }
        !           141: 
        !           142: /*
        !           143:  * Described in header
        !           144:  */
        !           145: CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *p11,
        !           146:                                                                                                 CK_SLOT_ID slot,
        !           147:                                                                                                 signature_scheme_t scheme,
1.1       misho     148:                                                                                                 key_type_t type, size_t keylen,
                    149:                                                                                                 hash_algorithm_t *hash)
                    150: {
                    151:        static struct {
                    152:                signature_scheme_t scheme;
                    153:                CK_MECHANISM mechanism;
                    154:                key_type_t type;
                    155:                size_t keylen;
                    156:                hash_algorithm_t hash;
                    157:        } mappings[] = {
                    158:                {SIGN_RSA_EMSA_PKCS1_NULL,              {CKM_RSA_PKCS,                  NULL, 0},
                    159:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
                    160:                {SIGN_RSA_EMSA_PKCS1_SHA2_256,  {CKM_SHA256_RSA_PKCS,   NULL, 0},
                    161:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
1.1.1.2 ! misho     162:                {SIGN_RSA_EMSA_PKCS1_SHA2_256,  {CKM_RSA_PKCS,                  NULL, 0},
        !           163:                 KEY_RSA, 0,                                                                            HASH_SHA256},
1.1       misho     164:                {SIGN_RSA_EMSA_PKCS1_SHA2_384,  {CKM_SHA384_RSA_PKCS,   NULL, 0},
                    165:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
1.1.1.2 ! misho     166:                {SIGN_RSA_EMSA_PKCS1_SHA2_384,  {CKM_RSA_PKCS,                  NULL, 0},
        !           167:                 KEY_RSA, 0,                                                                            HASH_SHA384},
1.1       misho     168:                {SIGN_RSA_EMSA_PKCS1_SHA2_512,  {CKM_SHA512_RSA_PKCS,   NULL, 0},
                    169:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
1.1.1.2 ! misho     170:                {SIGN_RSA_EMSA_PKCS1_SHA2_512,  {CKM_RSA_PKCS,                  NULL, 0},
        !           171:                 KEY_RSA, 0,                                                                            HASH_SHA512},
1.1       misho     172:                {SIGN_RSA_EMSA_PKCS1_SHA1,              {CKM_SHA1_RSA_PKCS,             NULL, 0},
                    173:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
1.1.1.2 ! misho     174:                {SIGN_RSA_EMSA_PKCS1_SHA1,              {CKM_RSA_PKCS,                  NULL, 0},
        !           175:                 KEY_RSA, 0,                                                                              HASH_SHA1},
1.1       misho     176:                {SIGN_RSA_EMSA_PKCS1_MD5,               {CKM_MD5_RSA_PKCS,              NULL, 0},
                    177:                 KEY_RSA, 0,                                                                       HASH_UNKNOWN},
                    178:                {SIGN_ECDSA_WITH_NULL,                  {CKM_ECDSA,                             NULL, 0},
                    179:                 KEY_ECDSA, 0,                                                                     HASH_UNKNOWN},
                    180:                {SIGN_ECDSA_WITH_SHA1_DER,              {CKM_ECDSA_SHA1,                NULL, 0},
                    181:                 KEY_ECDSA, 0,                                                                     HASH_UNKNOWN},
                    182:                {SIGN_ECDSA_WITH_SHA256_DER,    {CKM_ECDSA,                             NULL, 0},
                    183:                 KEY_ECDSA, 0,                                                                          HASH_SHA256},
                    184:                {SIGN_ECDSA_WITH_SHA384_DER,    {CKM_ECDSA,                             NULL, 0},
                    185:                 KEY_ECDSA, 0,                                                                          HASH_SHA384},
                    186:                {SIGN_ECDSA_WITH_SHA512_DER,    {CKM_ECDSA,                             NULL, 0},
                    187:                 KEY_ECDSA, 0,                                                                          HASH_SHA512},
                    188:                {SIGN_ECDSA_256,                                {CKM_ECDSA,                             NULL, 0},
                    189:                 KEY_ECDSA, 256,                                                                        HASH_SHA256},
                    190:                {SIGN_ECDSA_384,                                {CKM_ECDSA,                             NULL, 0},
                    191:                 KEY_ECDSA, 384,                                                                        HASH_SHA384},
                    192:                {SIGN_ECDSA_521,                                {CKM_ECDSA,                             NULL, 0},
                    193:                 KEY_ECDSA, 521,                                                                        HASH_SHA512},
                    194:        };
                    195:        int i;
                    196: 
                    197:        for (i = 0; i < countof(mappings); i++)
                    198:        {
                    199:                if (mappings[i].scheme == scheme)
                    200:                {
                    201:                        size_t len = mappings[i].keylen;
1.1.1.2 ! misho     202: 
        !           203:                        if (mappings[i].type != type || (len && keylen != len) ||
        !           204:                                !is_mechanism_supported(p11, slot, &mappings[i].mechanism))
1.1       misho     205:                        {
1.1.1.2 ! misho     206:                                continue;
1.1       misho     207:                        }
                    208:                        if (hash)
                    209:                        {
                    210:                                *hash = mappings[i].hash;
                    211:                        }
                    212:                        return &mappings[i].mechanism;
                    213:                }
                    214:        }
                    215:        return NULL;
                    216: }
                    217: 
                    218: /**
                    219:  * See header.
                    220:  */
                    221: CK_MECHANISM_PTR pkcs11_encryption_scheme_to_mech(encryption_scheme_t scheme)
                    222: {
                    223:        static struct {
                    224:                encryption_scheme_t scheme;
                    225:                CK_MECHANISM mechanism;
                    226:        } mappings[] = {
                    227:                {ENCRYPT_RSA_PKCS1,                     {CKM_RSA_PKCS,                          NULL, 0}},
                    228:                {ENCRYPT_RSA_OAEP_SHA1,         {CKM_RSA_PKCS_OAEP,                     NULL, 0}},
                    229:        };
                    230:        int i;
                    231: 
                    232:        for (i = 0; i < countof(mappings); i++)
                    233:        {
                    234:                if (mappings[i].scheme == scheme)
                    235:                {
                    236:                        return &mappings[i].mechanism;
                    237:                }
                    238:        }
                    239:        return NULL;
                    240: }
                    241: 
                    242: /**
                    243:  * Reauthenticate to do a signature
                    244:  */
                    245: static bool reauth(private_pkcs11_private_key_t *this,
                    246:                                   CK_SESSION_HANDLE session)
                    247: {
                    248:        enumerator_t *enumerator;
                    249:        shared_key_t *shared;
                    250:        chunk_t pin;
                    251:        CK_RV rv;
                    252:        bool found = FALSE, success = FALSE;
                    253: 
                    254:        enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
                    255:                                                                                                SHARED_PIN, this->keyid, NULL);
                    256:        while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
                    257:        {
                    258:                found = TRUE;
                    259:                pin = shared->get_key(shared);
                    260:                rv = this->lib->f->C_Login(session, CKU_CONTEXT_SPECIFIC,
                    261:                                                                   pin.ptr, pin.len);
                    262:                if (rv == CKR_OK)
                    263:                {
                    264:                        success = TRUE;
                    265:                        break;
                    266:                }
                    267:                DBG1(DBG_CFG, "reauthentication login failed: %N", ck_rv_names, rv);
                    268:        }
                    269:        enumerator->destroy(enumerator);
                    270: 
                    271:        if (!found)
                    272:        {
                    273:                DBG1(DBG_CFG, "private key requires reauthentication, but no PIN found");
                    274:                return FALSE;
                    275:        }
                    276:        return success;
                    277: }
                    278: 
                    279: METHOD(private_key_t, sign, bool,
                    280:        private_pkcs11_private_key_t *this, signature_scheme_t scheme, void *params,
                    281:        chunk_t data, chunk_t *signature)
                    282: {
                    283:        CK_MECHANISM_PTR mechanism;
                    284:        CK_SESSION_HANDLE session;
                    285:        CK_BYTE_PTR buf;
                    286:        CK_ULONG len;
                    287:        CK_RV rv;
                    288:        hash_algorithm_t hash_alg;
                    289:        chunk_t hash = chunk_empty;
                    290: 
1.1.1.2 ! misho     291:        mechanism = pkcs11_signature_scheme_to_mech(this->lib, this->slot, scheme,
        !           292:                                                                                                this->type, get_keysize(this),
        !           293:                                                                                                &hash_alg);
1.1       misho     294:        if (!mechanism)
                    295:        {
                    296:                DBG1(DBG_LIB, "signature scheme %N not supported",
                    297:                         signature_scheme_names, scheme);
                    298:                return FALSE;
                    299:        }
                    300:        rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
                    301:                                                                         &session);
                    302:        if (rv != CKR_OK)
                    303:        {
                    304:                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
                    305:                return FALSE;
                    306:        }
                    307:        rv = this->lib->f->C_SignInit(session, mechanism, this->object);
                    308:        if (this->reauth && !reauth(this, session))
                    309:        {
                    310:                this->lib->f->C_CloseSession(session);
                    311:                return FALSE;
                    312:        }
                    313:        if (rv != CKR_OK)
                    314:        {
                    315:                this->lib->f->C_CloseSession(session);
                    316:                DBG1(DBG_LIB, "C_SignInit() failed: %N", ck_rv_names, rv);
                    317:                return FALSE;
                    318:        }
                    319:        if (hash_alg != HASH_UNKNOWN)
                    320:        {
                    321:                hasher_t *hasher;
                    322: 
                    323:                hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
                    324:                if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
                    325:                {
                    326:                        DESTROY_IF(hasher);
                    327:                        this->lib->f->C_CloseSession(session);
                    328:                        return FALSE;
                    329:                }
                    330:                hasher->destroy(hasher);
1.1.1.2 ! misho     331:                switch (scheme)
        !           332:                {
        !           333:                        case SIGN_RSA_EMSA_PKCS1_SHA1:
        !           334:                        case SIGN_RSA_EMSA_PKCS1_SHA2_256:
        !           335:                        case SIGN_RSA_EMSA_PKCS1_SHA2_384:
        !           336:                        case SIGN_RSA_EMSA_PKCS1_SHA2_512:
        !           337:                                /* encode PKCS#1 digestInfo if the token does not support it */
        !           338:                                hash = asn1_wrap(ASN1_SEQUENCE, "mm",
        !           339:                                                                 asn1_algorithmIdentifier(
        !           340:                                                                        hasher_algorithm_to_oid(hash_alg)),
        !           341:                                                                 asn1_wrap(ASN1_OCTET_STRING, "m", hash));
        !           342:                                break;
        !           343:                        default:
        !           344:                                break;
        !           345:                }
1.1       misho     346:                data = hash;
                    347:        }
                    348:        len = (get_keysize(this) + 7) / 8;
                    349:        if (this->type == KEY_ECDSA)
                    350:        {       /* signature is twice the length of the base point order */
                    351:                len *= 2;
                    352:        }
                    353:        buf = malloc(len);
                    354:        rv = this->lib->f->C_Sign(session, data.ptr, data.len, buf, &len);
                    355:        this->lib->f->C_CloseSession(session);
                    356:        chunk_free(&hash);
                    357:        if (rv != CKR_OK)
                    358:        {
                    359:                DBG1(DBG_LIB, "C_Sign() failed: %N", ck_rv_names, rv);
                    360:                free(buf);
                    361:                return FALSE;
                    362:        }
                    363:        switch (scheme)
                    364:        {
                    365:                case SIGN_ECDSA_WITH_SHA1_DER:
                    366:                case SIGN_ECDSA_WITH_SHA256_DER:
                    367:                case SIGN_ECDSA_WITH_SHA384_DER:
                    368:                case SIGN_ECDSA_WITH_SHA512_DER:
                    369:                {
                    370:                        chunk_t r, s;
                    371: 
                    372:                        /* return an ASN.1 encoded sequence of integers r and s, removing
                    373:                         * any zero-padding */
                    374:                        len /= 2;
                    375:                        r = chunk_skip_zero(chunk_create(buf, len));
                    376:                        s = chunk_skip_zero(chunk_create(buf+len, len));
                    377:                        *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
                    378:                                                                   asn1_integer("c", r), asn1_integer("c", s));
                    379:                        free(buf);
                    380:                        break;
                    381:                }
                    382:                default:
                    383:                        *signature = chunk_create(buf, len);
                    384:                        break;
                    385:        }
                    386:        return TRUE;
                    387: }
                    388: 
                    389: METHOD(private_key_t, decrypt, bool,
                    390:        private_pkcs11_private_key_t *this, encryption_scheme_t scheme,
                    391:        chunk_t crypt, chunk_t *plain)
                    392: {
                    393:        CK_MECHANISM_PTR mechanism;
                    394:        CK_SESSION_HANDLE session;
                    395:        CK_BYTE_PTR buf;
                    396:        CK_ULONG len;
                    397:        CK_RV rv;
                    398: 
                    399:        mechanism = pkcs11_encryption_scheme_to_mech(scheme);
                    400:        if (!mechanism)
                    401:        {
                    402:                DBG1(DBG_LIB, "encryption scheme %N not supported",
                    403:                         encryption_scheme_names, scheme);
                    404:                return FALSE;
                    405:        }
                    406:        rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
                    407:                                                                         &session);
                    408:        if (rv != CKR_OK)
                    409:        {
                    410:                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
                    411:                return FALSE;
                    412:        }
                    413:        rv = this->lib->f->C_DecryptInit(session, mechanism, this->object);
                    414:        if (this->reauth && !reauth(this, session))
                    415:        {
                    416:                this->lib->f->C_CloseSession(session);
                    417:                return FALSE;
                    418:        }
                    419:        if (rv != CKR_OK)
                    420:        {
                    421:                this->lib->f->C_CloseSession(session);
                    422:                DBG1(DBG_LIB, "C_DecryptInit() failed: %N", ck_rv_names, rv);
                    423:                return FALSE;
                    424:        }
                    425:        len = (get_keysize(this) + 7) / 8;
                    426:        buf = malloc(len);
                    427:        rv = this->lib->f->C_Decrypt(session, crypt.ptr, crypt.len, buf, &len);
                    428:        this->lib->f->C_CloseSession(session);
                    429:        if (rv != CKR_OK)
                    430:        {
                    431:                DBG1(DBG_LIB, "C_Decrypt() failed: %N", ck_rv_names, rv);
                    432:                free(buf);
                    433:                return FALSE;
                    434:        }
                    435:        *plain = chunk_create(buf, len);
                    436:        return TRUE;
                    437: }
                    438: 
                    439: METHOD(private_key_t, get_public_key, public_key_t*,
                    440:        private_pkcs11_private_key_t *this)
                    441: {
                    442:        return this->pubkey->get_ref(this->pubkey);
                    443: }
                    444: 
                    445: METHOD(private_key_t, get_fingerprint, bool,
                    446:        private_pkcs11_private_key_t *this, cred_encoding_type_t type,
                    447:        chunk_t *fingerprint)
                    448: {
                    449:        return this->pubkey->get_fingerprint(this->pubkey, type, fingerprint);
                    450: }
                    451: 
                    452: METHOD(private_key_t, get_encoding, bool,
                    453:        private_pkcs11_private_key_t *this, cred_encoding_type_t type,
                    454:        chunk_t *encoding)
                    455: {
                    456:        return FALSE;
                    457: }
                    458: 
                    459: METHOD(private_key_t, get_ref, private_key_t*,
                    460:        private_pkcs11_private_key_t *this)
                    461: {
                    462:        ref_get(&this->ref);
                    463:        return &this->public.key;
                    464: }
                    465: 
                    466: METHOD(private_key_t, destroy, void,
                    467:        private_pkcs11_private_key_t *this)
                    468: {
                    469:        if (ref_put(&this->ref))
                    470:        {
                    471:                if (this->pubkey)
                    472:                {
                    473:                        this->pubkey->destroy(this->pubkey);
                    474:                }
                    475:                this->keyid->destroy(this->keyid);
                    476:                this->lib->f->C_CloseSession(this->session);
                    477:                free(this);
                    478:        }
                    479: }
                    480: 
                    481: /**
                    482:  * Find the PKCS#11 library by its friendly name
                    483:  */
                    484: static pkcs11_library_t* find_lib(char *module)
                    485: {
                    486:        pkcs11_manager_t *manager;
                    487:        enumerator_t *enumerator;
                    488:        pkcs11_library_t *p11, *found = NULL;
                    489:        CK_SLOT_ID slot;
                    490: 
                    491:        manager = lib->get(lib, "pkcs11-manager");
                    492:        if (!manager)
                    493:        {
                    494:                return NULL;
                    495:        }
                    496:        enumerator = manager->create_token_enumerator(manager);
                    497:        while (enumerator->enumerate(enumerator, &p11, &slot))
                    498:        {
                    499:                if (streq(module, p11->get_name(p11)))
                    500:                {
                    501:                        found = p11;
                    502:                        break;
                    503:                }
                    504:        }
                    505:        enumerator->destroy(enumerator);
                    506:        return found;
                    507: }
                    508: 
                    509: /**
                    510:  * Find the PKCS#11 lib having a keyid, and optionally a slot
                    511:  */
                    512: static pkcs11_library_t* find_lib_by_keyid(chunk_t keyid, int *slot,
                    513:                                                                                   CK_OBJECT_CLASS class)
                    514: {
                    515:        pkcs11_manager_t *manager;
                    516:        enumerator_t *enumerator;
                    517:        pkcs11_library_t *p11, *found = NULL;
                    518:        CK_SLOT_ID current;
                    519: 
                    520:        manager = lib->get(lib, "pkcs11-manager");
                    521:        if (!manager)
                    522:        {
                    523:                return NULL;
                    524:        }
                    525:        enumerator = manager->create_token_enumerator(manager);
                    526:        while (enumerator->enumerate(enumerator, &p11, &current))
                    527:        {
                    528:                if (*slot == -1 || *slot == current)
                    529:                {
                    530:                        /* look for a pubkey/cert, it is usually readable without login */
                    531:                        CK_ATTRIBUTE tmpl[] = {
                    532:                                {CKA_CLASS, &class, sizeof(class)},
                    533:                                {CKA_ID, keyid.ptr, keyid.len},
                    534:                        };
                    535:                        CK_OBJECT_HANDLE object;
                    536:                        CK_SESSION_HANDLE session;
                    537:                        CK_RV rv;
                    538:                        enumerator_t *keys;
                    539: 
                    540:                        rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
                    541:                                                                           &session);
                    542:                        if (rv != CKR_OK)
                    543:                        {
                    544:                                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
                    545:                                         ck_rv_names, rv);
                    546:                                continue;
                    547:                        }
                    548:                        keys = p11->create_object_enumerator(p11, session,
                    549:                                                                                                 tmpl, countof(tmpl), NULL, 0);
                    550:                        if (keys->enumerate(keys, &object))
                    551:                        {
                    552:                                DBG1(DBG_CFG, "found key on PKCS#11 token '%s':%d",
                    553:                                         p11->get_name(p11), current);
                    554:                                found = p11;
                    555:                                *slot = current;
                    556:                        }
                    557:                        keys->destroy(keys);
                    558:                        p11->f->C_CloseSession(session);
                    559:                        if (found)
                    560:                        {
                    561:                                break;
                    562:                        }
                    563:                }
                    564:        }
                    565:        enumerator->destroy(enumerator);
                    566:        return found;
                    567: }
                    568: 
                    569: /**
                    570:  * Find the PKCS#11 lib and CKA_ID of the certificate object of a given
                    571:  * subjectKeyIdentifier and optional slot
                    572:  */
                    573: static pkcs11_library_t* find_lib_and_keyid_by_skid(chunk_t keyid_chunk,
                    574:                                                                                                        chunk_t *ckaid, int *slot)
                    575: {
                    576:        CK_OBJECT_CLASS class = CKO_CERTIFICATE;
                    577:        CK_CERTIFICATE_TYPE type = CKC_X_509;
                    578:        CK_ATTRIBUTE tmpl[] = {
                    579:                {CKA_CLASS, &class, sizeof(class)},
                    580:                {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
                    581:        };
                    582:        CK_ATTRIBUTE attr[] = {
                    583:                {CKA_VALUE, NULL, 0},
                    584:                {CKA_ID, NULL, 0},
                    585:        };
                    586:        CK_OBJECT_HANDLE object;
                    587:        CK_SESSION_HANDLE session;
                    588:        CK_RV rv;
                    589:        pkcs11_manager_t *manager;
                    590:        enumerator_t *enumerator, *certs;
                    591:        identification_t *keyid;
                    592:        pkcs11_library_t *p11, *found = NULL;
                    593:        CK_SLOT_ID current;
                    594:        linked_list_t *raw;
                    595:        certificate_t *cert;
                    596:        struct {
                    597:                chunk_t value;
                    598:                chunk_t ckaid;
                    599:        } *entry;
                    600: 
                    601:        manager = lib->get(lib, "pkcs11-manager");
                    602:        if (!manager)
                    603:        {
                    604:                return NULL;
                    605:        }
                    606: 
                    607:        keyid = identification_create_from_encoding(ID_KEY_ID, keyid_chunk);
                    608:        /* store result in a temporary list, avoid recursive operation */
                    609:        raw = linked_list_create();
                    610: 
                    611:        enumerator = manager->create_token_enumerator(manager);
                    612:        while (enumerator->enumerate(enumerator, &p11, &current))
                    613:        {
                    614:                if (*slot != -1 && *slot != current)
                    615:                {
                    616:                        continue;
                    617:                }
                    618:                rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
                    619:                                                                   &session);
                    620:                if (rv != CKR_OK)
                    621:                {
                    622:                        DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
                    623:                                 ck_rv_names, rv);
                    624:                        continue;
                    625:                }
                    626:                certs = p11->create_object_enumerator(p11, session, tmpl, countof(tmpl),
                    627:                                                                                          attr, countof(attr));
                    628:                while (certs->enumerate(certs, &object))
                    629:                {
                    630:                        INIT(entry,
                    631:                                .value = chunk_clone(
                    632:                                                        chunk_create(attr[0].pValue, attr[0].ulValueLen)),
                    633:                                .ckaid = chunk_clone(
                    634:                                                        chunk_create(attr[1].pValue, attr[1].ulValueLen)),
                    635:                        );
                    636:                        raw->insert_last(raw, entry);
                    637:                }
                    638:                certs->destroy(certs);
                    639: 
                    640:                while (raw->remove_first(raw, (void**)&entry) == SUCCESS)
                    641:                {
                    642:                        if (!found)
                    643:                        {
                    644:                                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
                    645:                                                                                  CERT_X509, BUILD_BLOB_ASN1_DER,
                    646:                                                                                  entry->value, BUILD_END);
                    647:                                if (cert)
                    648:                                {
                    649:                                        if (cert->has_subject(cert, keyid))
                    650:                                        {
                    651:                                                DBG1(DBG_CFG, "found cert with keyid '%#B' on PKCS#11 "
                    652:                                                         "token '%s':%d", &keyid_chunk, p11->get_name(p11),
                    653:                                                         current);
                    654:                                                found = p11;
                    655:                                                *ckaid = chunk_clone(entry->ckaid);
                    656:                                                *slot = current;
                    657:                                        }
                    658:                                        cert->destroy(cert);
                    659:                                }
                    660:                                else
                    661:                                {
                    662:                                        DBG1(DBG_CFG, "parsing cert with CKA_ID '%#B' on PKCS#11 "
                    663:                                                 "token '%s':%d failed", &entry->ckaid,
                    664:                                                 p11->get_name(p11), current);
                    665:                                }
                    666:                        }
                    667:                        chunk_free(&entry->value);
                    668:                        chunk_free(&entry->ckaid);
                    669:                        free(entry);
                    670:                }
                    671:                p11->f->C_CloseSession(session);
                    672:                if (found)
                    673:                {
                    674:                        break;
                    675:                }
                    676:        }
                    677:        enumerator->destroy(enumerator);
                    678:        keyid->destroy(keyid);
                    679:        raw->destroy(raw);
                    680:        return found;
                    681: }
                    682: 
                    683: /**
                    684:  * Find the key on the token
                    685:  */
                    686: static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid)
                    687: {
                    688:        CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
                    689:        CK_ATTRIBUTE tmpl[] = {
                    690:                {CKA_CLASS, &class, sizeof(class)},
                    691:                {CKA_ID, keyid.ptr, keyid.len},
                    692:        };
                    693:        CK_OBJECT_HANDLE object;
                    694:        CK_KEY_TYPE type;
                    695:        CK_BBOOL reauth = FALSE;
                    696:        CK_ATTRIBUTE attr[] = {
                    697:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    698:                {CKA_ALWAYS_AUTHENTICATE, &reauth, sizeof(reauth)},
                    699:        };
                    700:        enumerator_t *enumerator;
                    701:        int count = countof(attr);
                    702:        bool found = FALSE;
                    703: 
                    704:        /* do not use CKA_ALWAYS_AUTHENTICATE if not supported */
                    705:        if (!(this->lib->get_features(this->lib) & PKCS11_ALWAYS_AUTH_KEYS))
                    706:        {
                    707:                count--;
                    708:        }
                    709:        enumerator = this->lib->create_object_enumerator(this->lib,
                    710:                                                        this->session, tmpl, countof(tmpl), attr, count);
                    711:        if (enumerator->enumerate(enumerator, &object))
                    712:        {
                    713:                this->type = KEY_RSA;
                    714:                switch (type)
                    715:                {
                    716:                        case CKK_ECDSA:
                    717:                                this->type = KEY_ECDSA;
                    718:                                /* fall-through */
                    719:                        case CKK_RSA:
                    720:                                this->reauth = reauth;
                    721:                                this->object = object;
                    722:                                found = TRUE;
                    723:                                break;
                    724:                        default:
                    725:                                DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
                    726:                                break;
                    727:                }
                    728:        }
                    729:        enumerator->destroy(enumerator);
                    730:        return found;
                    731: }
                    732: 
                    733: /**
                    734:  * Find a PIN and try to log in
                    735:  */
                    736: static bool login(private_pkcs11_private_key_t *this, int slot)
                    737: {
                    738:        enumerator_t *enumerator;
                    739:        shared_key_t *shared;
                    740:        chunk_t pin;
                    741:        CK_RV rv;
                    742:        CK_SESSION_INFO info;
                    743:        bool found = FALSE, success = FALSE;
                    744: 
                    745:        rv = this->lib->f->C_GetSessionInfo(this->session, &info);
                    746:        if (rv != CKR_OK)
                    747:        {
                    748:                DBG1(DBG_CFG, "C_GetSessionInfo failed: %N", ck_rv_names, rv);
                    749:                return FALSE;
                    750:        }
                    751:        if (info.state != CKS_RO_PUBLIC_SESSION &&
                    752:                info.state != CKS_RW_PUBLIC_SESSION)
                    753:        {       /* already logged in with another session, skip */
                    754:                return TRUE;
                    755:        }
                    756: 
                    757:        enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
                    758:                                                                                                SHARED_PIN, this->keyid, NULL);
                    759:        while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
                    760:        {
                    761:                found = TRUE;
                    762:                pin = shared->get_key(shared);
                    763:                rv = this->lib->f->C_Login(this->session, CKU_USER, pin.ptr, pin.len);
                    764:                if (rv == CKR_OK)
                    765:                {
                    766:                        success = TRUE;
                    767:                        break;
                    768:                }
                    769:                DBG1(DBG_CFG, "login to '%s':%d failed: %N",
                    770:                         this->lib->get_name(this->lib), slot, ck_rv_names, rv);
                    771:        }
                    772:        enumerator->destroy(enumerator);
                    773: 
                    774:        if (!found)
                    775:        {
                    776:                DBG1(DBG_CFG, "no PIN found for PKCS#11 key %Y", this->keyid);
                    777:                return FALSE;
                    778:        }
                    779:        return success;
                    780: }
                    781: 
                    782: /**
                    783:  * Get a public key from a certificate with a given key ID.
                    784:  */
                    785: static public_key_t* find_pubkey_in_certs(private_pkcs11_private_key_t *this,
                    786:                                                                                  chunk_t keyid)
                    787: {
                    788:        CK_OBJECT_CLASS class = CKO_CERTIFICATE;
                    789:        CK_CERTIFICATE_TYPE type = CKC_X_509;
                    790:        CK_ATTRIBUTE tmpl[] = {
                    791:                {CKA_CLASS, &class, sizeof(class)},
                    792:                {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
                    793:                {CKA_ID, keyid.ptr, keyid.len},
                    794:        };
                    795:        CK_OBJECT_HANDLE object;
                    796:        CK_ATTRIBUTE attr[] = {
                    797:                {CKA_VALUE, NULL, 0},
                    798:        };
                    799:        enumerator_t *enumerator;
                    800:        chunk_t data = chunk_empty;
                    801:        public_key_t *key = NULL;
                    802:        certificate_t *cert;
                    803: 
                    804:        enumerator = this->lib->create_object_enumerator(this->lib, this->session,
                    805:                                                                        tmpl, countof(tmpl), attr, countof(attr));
                    806:        if (enumerator->enumerate(enumerator, &object))
                    807:        {
                    808:                data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen));
                    809:        }
                    810:        enumerator->destroy(enumerator);
                    811: 
                    812:        if (data.ptr)
                    813:        {
                    814:                cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
                    815:                                                                  BUILD_BLOB_ASN1_DER, data, BUILD_END);
                    816:                free(data.ptr);
                    817:                if (cert)
                    818:                {
                    819:                        key = cert->get_public_key(cert);
                    820:                        cert->destroy(cert);
                    821:                }
                    822:        }
                    823:        return key;
                    824: }
                    825: 
                    826: /**
                    827:  * See header.
                    828:  */
                    829: pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args)
                    830: {
                    831:        private_pkcs11_private_key_t *this;
                    832:        char *module = NULL;
                    833:        chunk_t keyid = chunk_empty, ckaid = chunk_empty;
                    834:        int slot = -1;
                    835:        CK_RV rv;
                    836: 
                    837:        while (TRUE)
                    838:        {
                    839:                switch (va_arg(args, builder_part_t))
                    840:                {
                    841:                        case BUILD_PKCS11_KEYID:
                    842:                                keyid = va_arg(args, chunk_t);
                    843:                                continue;
                    844:                        case BUILD_PKCS11_SLOT:
                    845:                                slot = va_arg(args, int);
                    846:                                continue;
                    847:                        case BUILD_PKCS11_MODULE:
                    848:                                module = va_arg(args, char*);
                    849:                                continue;
                    850:                        case BUILD_END:
                    851:                                break;
                    852:                        default:
                    853:                                return NULL;
                    854:                }
                    855:                break;
                    856:        }
                    857:        if (!keyid.len)
                    858:        {
                    859:                return NULL;
                    860:        }
                    861: 
                    862:        INIT(this,
                    863:                .public = {
                    864:                        .key = {
                    865:                                .get_type = _get_type,
                    866:                                .sign = _sign,
                    867:                                .decrypt = _decrypt,
                    868:                                .get_keysize = _get_keysize,
                    869:                                .get_public_key = _get_public_key,
                    870:                                .equals = private_key_equals,
                    871:                                .belongs_to = private_key_belongs_to,
                    872:                                .get_fingerprint = _get_fingerprint,
                    873:                                .has_fingerprint = private_key_has_fingerprint,
                    874:                                .get_encoding = _get_encoding,
                    875:                                .get_ref = _get_ref,
                    876:                                .destroy = _destroy,
                    877:                        },
                    878:                },
                    879:                .ref = 1,
                    880:        );
                    881: 
                    882:        if (module && slot != -1)
                    883:        {
                    884:                this->lib = find_lib(module);
                    885:                if (!this->lib)
                    886:                {
                    887:                        DBG1(DBG_CFG, "PKCS#11 module '%s' not found", module);
                    888:                        free(this);
                    889:                        return NULL;
                    890:                }
                    891:        }
                    892:        else
                    893:        {
                    894:                this->lib = find_lib_by_keyid(keyid, &slot, CKO_PUBLIC_KEY);
                    895:                if (!this->lib)
                    896:                {
                    897:                        this->lib = find_lib_by_keyid(keyid, &slot, CKO_CERTIFICATE);
                    898:                }
                    899:                if (!this->lib)
                    900:                {
                    901:                        this->lib = find_lib_and_keyid_by_skid(keyid, &ckaid, &slot);
                    902:                }
                    903:                if (!this->lib)
                    904:                {
                    905:                        DBG1(DBG_CFG, "no PKCS#11 module found having a keyid %#B", &keyid);
                    906:                        free(this);
                    907:                        return NULL;
                    908:                }
                    909:        }
                    910: 
                    911:        rv = this->lib->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
                    912:                                                                         NULL, NULL, &this->session);
                    913:        if (rv != CKR_OK)
                    914:        {
                    915:                DBG1(DBG_CFG, "opening private key session on '%s':%d failed: %N",
                    916:                         module, slot, ck_rv_names, rv);
                    917:                free(this);
                    918:                return NULL;
                    919:        }
                    920: 
                    921:        this->slot = slot;
                    922:        this->keyid = identification_create_from_encoding(ID_KEY_ID, keyid);
                    923: 
                    924:        if (!login(this, slot))
                    925:        {
                    926:                destroy(this);
                    927:                return NULL;
                    928:        }
                    929: 
                    930:        if (ckaid.ptr)
                    931:        {
                    932:                DBG1(DBG_CFG, "using CKA_ID '%#B' for key with keyid '%#B'",
                    933:                         &ckaid, &keyid);
                    934:                keyid = ckaid;
                    935:        }
                    936: 
                    937:        if (!find_key(this, keyid))
                    938:        {
                    939:                DBG1(DBG_CFG, "did not find the key with %s '%#B'",
                    940:                         ckaid.ptr ? "CKA_ID" : "keyid", &keyid);
                    941:                destroy(this);
                    942:                return NULL;
                    943:        }
                    944: 
                    945:        this->pubkey = pkcs11_public_key_connect(this->lib, slot, this->type, keyid);
                    946:        if (!this->pubkey)
                    947:        {
                    948:                this->pubkey = find_pubkey_in_certs(this, keyid);
                    949:                if (!this->pubkey)
                    950:                {
                    951:                        DBG1(DBG_CFG, "no public key or certificate found for private key "
                    952:                                 "(%s '%#B') on '%s':%d", ckaid.ptr ? "CKA_ID" : "keyid",
                    953:                                 &keyid, module, slot);
                    954:                        destroy(this);
                    955:                        return NULL;
                    956:                }
                    957:        }
                    958:        return &this->public;
                    959: }

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