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

1.1       misho       1: /*
                      2:  * Copyright (C) 2011-2015 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: #include "pkcs11_public_key.h"
                     20: 
                     21: #include "pkcs11.h"
                     22: #include "pkcs11_private_key.h"
                     23: #include "pkcs11_manager.h"
                     24: 
                     25: #include <asn1/oid.h>
                     26: #include <asn1/asn1.h>
                     27: #include <asn1/asn1_parser.h>
                     28: #include <utils/debug.h>
                     29: 
                     30: typedef struct private_pkcs11_public_key_t private_pkcs11_public_key_t;
                     31: 
                     32: /**
                     33:  * Private data of an pkcs11_public_key_t object.
                     34:  */
                     35: struct private_pkcs11_public_key_t {
                     36: 
                     37:        /**
                     38:         * Public pkcs11_public_key_t interface.
                     39:         */
                     40:        pkcs11_public_key_t public;
                     41: 
                     42:        /**
                     43:         * Type of the key
                     44:         */
                     45:        key_type_t type;
                     46: 
                     47:        /**
                     48:         * Key size in bits
                     49:         */
                     50:        size_t k;
                     51: 
                     52:        /**
                     53:         * PKCS#11 library this key uses
                     54:         */
                     55:        pkcs11_library_t *lib;
                     56: 
                     57:        /**
                     58:         * Slot the token is in
                     59:         */
                     60:        CK_SLOT_ID slot;
                     61: 
                     62:        /**
                     63:         * Session we use
                     64:         */
                     65:        CK_SESSION_HANDLE session;
                     66: 
                     67:        /**
                     68:         * Object handle to the key
                     69:         */
                     70:        CK_OBJECT_HANDLE object;
                     71: 
                     72:        /**
                     73:         * References to this key
                     74:         */
                     75:        refcount_t ref;
                     76: };
                     77: 
                     78: /**
                     79:  * Helper function that returns the base point order length in bits of the
                     80:  * given named curve.
                     81:  *
                     82:  * Currently only a subset of defined curves is supported (namely the 5 curves
                     83:  * over Fp recommended by NIST). IKEv2 only supports 3 out of these.
                     84:  *
                     85:  * 0 is returned if the given curve is not supported.
                     86:  */
                     87: static size_t basepoint_order_len(int oid)
                     88: {
                     89:        switch (oid)
                     90:        {
                     91:                case OID_PRIME192V1:
                     92:                        return 192;
                     93:                case OID_SECT224R1:
                     94:                        return 224;
                     95:                case OID_PRIME256V1:
                     96:                        return 256;
                     97:                case OID_SECT384R1:
                     98:                        return 384;
                     99:                case OID_SECT521R1:
                    100:                        return 521;
                    101:                default:
                    102:                        return 0;
                    103:        }
                    104: }
                    105: 
                    106: /**
                    107:  * Parses the given ecParameters (ASN.1) and returns the key length.
                    108:  */
                    109: static bool keylen_from_ecparams(chunk_t ecparams, size_t *keylen)
                    110: {
                    111:        if (!asn1_parse_simple_object(&ecparams, ASN1_OID, 0, "named curve"))
                    112:        {
                    113:                return FALSE;
                    114:        }
                    115:        *keylen = basepoint_order_len(asn1_known_oid(ecparams));
                    116:        return *keylen > 0;
                    117: }
                    118: 
                    119: /**
                    120:  * ASN.1 definition of a subjectPublicKeyInfo structure when used with ECDSA
                    121:  * we currently only support named curves.
                    122:  */
                    123: static const asn1Object_t pkinfoObjects[] = {
                    124:        { 0, "subjectPublicKeyInfo",    ASN1_SEQUENCE,          ASN1_NONE       }, /* 0 */
                    125:        { 1,   "algorithmIdentifier",   ASN1_SEQUENCE,          ASN1_NONE       }, /* 1 */
                    126:        { 2,     "algorithm",                   ASN1_OID,                       ASN1_BODY       }, /* 2 */
                    127:        { 2,     "namedCurve",                  ASN1_OID,                       ASN1_RAW        }, /* 3 */
                    128:        { 1,   "subjectPublicKey",              ASN1_BIT_STRING,        ASN1_BODY       }, /* 4 */
                    129:        { 0, "exit",                                    ASN1_EOC,                       ASN1_EXIT       }
                    130: };
                    131: #define PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM            2
                    132: #define PKINFO_SUBJECT_PUBLIC_KEY_NAMEDCURVE   3
                    133: #define PKINFO_SUBJECT_PUBLIC_KEY                              4
                    134: 
                    135: /**
                    136:  * Extract the DER encoded Parameters and ECPoint from the given DER encoded
                    137:  * subjectPublicKeyInfo.
                    138:  * Memory for ecpoint is allocated.
                    139:  */
                    140: static bool parse_ecdsa_public_key(chunk_t blob, chunk_t *ecparams,
                    141:                                                                   chunk_t *ecpoint, size_t *keylen)
                    142: {
                    143:        asn1_parser_t *parser;
                    144:        chunk_t object;
                    145:        int objectID;
                    146:        bool success = FALSE;
                    147: 
                    148:        parser = asn1_parser_create(pkinfoObjects, blob);
                    149: 
                    150:        while (parser->iterate(parser, &objectID, &object))
                    151:        {
                    152:                switch (objectID)
                    153:                {
                    154:                        case PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM:
                    155:                        {
                    156:                                if (asn1_known_oid(object) != OID_EC_PUBLICKEY)
                    157:                                {
                    158:                                        goto end;
                    159:                                }
                    160:                                break;
                    161:                        }
                    162:                        case PKINFO_SUBJECT_PUBLIC_KEY_NAMEDCURVE:
                    163:                        {
                    164:                                *ecparams = object;
                    165:                                if (!keylen_from_ecparams(object, keylen))
                    166:                                {
                    167:                                        goto end;
                    168:                                }
                    169:                                break;
                    170:                        }
                    171:                        case PKINFO_SUBJECT_PUBLIC_KEY:
                    172:                        {
                    173:                                if (object.len > 0 && *object.ptr == 0x00)
                    174:                                {       /* skip initial bit string octet defining 0 unused bits */
                    175:                                        object = chunk_skip(object, 1);
                    176:                                }
                    177:                                /* the correct way to encode an EC_POINT in PKCS#11 is as
                    178:                                 * ASN.1 octet string */
                    179:                                *ecpoint = asn1_wrap(ASN1_OCTET_STRING, "c", object);
                    180:                                break;
                    181:                        }
                    182:                }
                    183:        }
                    184:        success = parser->success(parser);
                    185: end:
                    186:        parser->destroy(parser);
                    187:        return success;
                    188: }
                    189: 
                    190: 
                    191: METHOD(public_key_t, get_type, key_type_t,
                    192:        private_pkcs11_public_key_t *this)
                    193: {
                    194:        return this->type;
                    195: }
                    196: 
                    197: METHOD(public_key_t, get_keysize, int,
                    198:        private_pkcs11_public_key_t *this)
                    199: {
                    200:        return this->k;
                    201: }
                    202: 
                    203: METHOD(public_key_t, verify, bool,
                    204:        private_pkcs11_public_key_t *this, signature_scheme_t scheme, void *params,
                    205:        chunk_t data, chunk_t sig)
                    206: {
                    207:        CK_MECHANISM_PTR mechanism;
                    208:        CK_SESSION_HANDLE session;
                    209:        CK_RV rv;
                    210:        hash_algorithm_t hash_alg;
                    211:        chunk_t hash = chunk_empty, parse, r, s;
                    212:        size_t len;
                    213: 
                    214:        mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, this->k,
                    215:                                                                                                &hash_alg);
                    216:        if (!mechanism)
                    217:        {
                    218:                DBG1(DBG_LIB, "signature scheme %N not supported",
                    219:                         signature_scheme_names, scheme);
                    220:                return FALSE;
                    221:        }
                    222:        switch (scheme)
                    223:        {
                    224:                case SIGN_ECDSA_WITH_SHA1_DER:
                    225:                case SIGN_ECDSA_WITH_SHA256_DER:
                    226:                case SIGN_ECDSA_WITH_SHA384_DER:
                    227:                case SIGN_ECDSA_WITH_SHA512_DER:
                    228:                        /* PKCS#11 expects the ECDSA signatures as simple concatenation of
                    229:                         * r and s, so unwrap the ASN.1 encoded sequence */
                    230:                        parse = sig;
                    231:                        if (asn1_unwrap(&parse, &parse) != ASN1_SEQUENCE ||
                    232:                                asn1_unwrap(&parse, &r) != ASN1_INTEGER ||
                    233:                                asn1_unwrap(&parse, &s) != ASN1_INTEGER)
                    234:                        {
                    235:                                return FALSE;
                    236:                        }
                    237:                        r = chunk_skip_zero(r);
                    238:                        s = chunk_skip_zero(s);
                    239:                        len = (get_keysize(this) + 7) / 8;
                    240:                        if (r.len > len || s.len > len)
                    241:                        {
                    242:                                return FALSE;
                    243:                        }
                    244:                        /* concatenate r and s (forced to the defined length) */
                    245:                        sig = chunk_alloca(2*len);
                    246:                        memset(sig.ptr, 0, sig.len);
                    247:                        memcpy(sig.ptr + (len - r.len), r.ptr, r.len);
                    248:                        memcpy(sig.ptr + len + (len - s.len), s.ptr, s.len);
                    249:                        break;
                    250:                default:
                    251:                        sig = chunk_skip_zero(sig);
                    252:                        break;
                    253:        }
                    254:        rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
                    255:                                                                         &session);
                    256:        if (rv != CKR_OK)
                    257:        {
                    258:                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
                    259:                return FALSE;
                    260:        }
                    261:        rv = this->lib->f->C_VerifyInit(session, mechanism, this->object);
                    262:        if (rv != CKR_OK)
                    263:        {
                    264:                this->lib->f->C_CloseSession(session);
                    265:                DBG1(DBG_LIB, "C_VerifyInit() failed: %N", ck_rv_names, rv);
                    266:                return FALSE;
                    267:        }
                    268:        if (hash_alg != HASH_UNKNOWN)
                    269:        {
                    270:                hasher_t *hasher;
                    271: 
                    272:                hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
                    273:                if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
                    274:                {
                    275:                        DESTROY_IF(hasher);
                    276:                        this->lib->f->C_CloseSession(session);
                    277:                        return FALSE;
                    278:                }
                    279:                hasher->destroy(hasher);
                    280:                data = hash;
                    281:        }
                    282:        rv = this->lib->f->C_Verify(session, data.ptr, data.len, sig.ptr, sig.len);
                    283:        this->lib->f->C_CloseSession(session);
                    284:        chunk_free(&hash);
                    285:        if (rv != CKR_OK)
                    286:        {
                    287:                DBG1(DBG_LIB, "C_Verify() failed: %N", ck_rv_names, rv);
                    288:                return FALSE;
                    289:        }
                    290:        return TRUE;
                    291: }
                    292: 
                    293: METHOD(public_key_t, encrypt, bool,
                    294:        private_pkcs11_public_key_t *this, encryption_scheme_t scheme,
                    295:        chunk_t plain, chunk_t *crypt)
                    296: {
                    297:        CK_MECHANISM_PTR mechanism;
                    298:        CK_SESSION_HANDLE session;
                    299:        CK_BYTE_PTR buf;
                    300:        CK_ULONG len;
                    301:        CK_RV rv;
                    302: 
                    303:        mechanism = pkcs11_encryption_scheme_to_mech(scheme);
                    304:        if (!mechanism)
                    305:        {
                    306:                DBG1(DBG_LIB, "encryption scheme %N not supported",
                    307:                         encryption_scheme_names, scheme);
                    308:                return FALSE;
                    309:        }
                    310:        rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
                    311:                                                                         &session);
                    312:        if (rv != CKR_OK)
                    313:        {
                    314:                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
                    315:                return FALSE;
                    316:        }
                    317:        rv = this->lib->f->C_EncryptInit(session, mechanism, this->object);
                    318:        if (rv != CKR_OK)
                    319:        {
                    320:                this->lib->f->C_CloseSession(session);
                    321:                DBG1(DBG_LIB, "C_EncryptInit() failed: %N", ck_rv_names, rv);
                    322:                return FALSE;
                    323:        }
                    324:        len = (get_keysize(this) + 7) / 8;
                    325:        buf = malloc(len);
                    326:        rv = this->lib->f->C_Encrypt(session, plain.ptr, plain.len, buf, &len);
                    327:        this->lib->f->C_CloseSession(session);
                    328:        if (rv != CKR_OK)
                    329:        {
                    330:                DBG1(DBG_LIB, "C_Encrypt() failed: %N", ck_rv_names, rv);
                    331:                free(buf);
                    332:                return FALSE;
                    333:        }
                    334:        *crypt = chunk_create(buf, len);
                    335:        return TRUE;
                    336: }
                    337: 
                    338: /**
                    339:  * Encode ECDSA key using a given encoding type
                    340:  */
                    341: static bool encode_ecdsa(private_pkcs11_public_key_t *this,
                    342:                                                 cred_encoding_type_t type, chunk_t *encoding)
                    343: {
                    344:        enumerator_t *enumerator;
                    345:        bool success = FALSE;
                    346:        CK_ATTRIBUTE attr[] = {
                    347:                {CKA_EC_PARAMS, NULL, 0},
                    348:                {CKA_EC_POINT, NULL, 0},
                    349:        };
                    350: 
                    351:        if (type != PUBKEY_SPKI_ASN1_DER && type != PUBKEY_PEM)
                    352:        {
                    353:                return FALSE;
                    354:        }
                    355: 
                    356:        enumerator = this->lib->create_object_attr_enumerator(this->lib,
                    357:                                                        this->session, this->object, attr, countof(attr));
                    358:        if (enumerator && enumerator->enumerate(enumerator, NULL) &&
                    359:                attr[0].ulValueLen > 0 && attr[1].ulValueLen > 0)
                    360:        {
                    361:                chunk_t ecparams, ecpoint;
                    362:                ecparams = chunk_create(attr[0].pValue, attr[0].ulValueLen);
                    363:                ecpoint = chunk_create(attr[1].pValue, attr[1].ulValueLen);
                    364:                /* encode as subjectPublicKeyInfo */
                    365:                *encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
                    366:                                                asn1_wrap(ASN1_SEQUENCE, "mc",
                    367:                                                        asn1_build_known_oid(OID_EC_PUBLICKEY), ecparams),
                    368:                                                asn1_bitstring("c", ecpoint));
                    369:                success = TRUE;
                    370:                if (type == PUBKEY_PEM)
                    371:                {
                    372:                        chunk_t asn1 = *encoding;
                    373:                        success = lib->encoding->encode(lib->encoding, PUBKEY_PEM,
                    374:                                                        NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
                    375:                                                        asn1, CRED_PART_END);
                    376:                        chunk_clear(&asn1);
                    377:                }
                    378:        }
                    379:        DESTROY_IF(enumerator);
                    380:        return success;
                    381: }
                    382: 
                    383: /**
                    384:  * Compute fingerprint of an ECDSA key
                    385:  */
                    386: static bool fingerprint_ecdsa(private_pkcs11_public_key_t *this,
                    387:                                                          cred_encoding_type_t type, chunk_t *fp)
                    388: {
                    389:        hasher_t *hasher;
                    390:        chunk_t asn1;
                    391: 
                    392:        switch (type)
                    393:        {
                    394:                case KEYID_PUBKEY_SHA1:
                    395:                        if (!this->lib->get_ck_attribute(this->lib, this->session,
                    396:                                                this->object, CKA_EC_POINT, &asn1))
                    397:                        {
                    398:                                return FALSE;
                    399:                        }
                    400:                        break;
                    401:                case KEYID_PUBKEY_INFO_SHA1:
                    402:                        if (!encode_ecdsa(this, PUBKEY_SPKI_ASN1_DER, &asn1))
                    403:                        {
                    404:                                return FALSE;
                    405:                        }
                    406:                        break;
                    407:                default:
                    408:                        return FALSE;
                    409:        }
                    410:        hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
                    411:        if (!hasher || !hasher->allocate_hash(hasher, asn1, fp))
                    412:        {
                    413:                DESTROY_IF(hasher);
                    414:                chunk_clear(&asn1);
                    415:                return FALSE;
                    416:        }
                    417:        hasher->destroy(hasher);
                    418:        chunk_clear(&asn1);
                    419:        lib->encoding->cache(lib->encoding, type, this, *fp);
                    420:        return TRUE;
                    421: }
                    422: 
                    423: /**
                    424:  * Encode RSA key using a given encoding type
                    425:  */
                    426: static bool encode_rsa(private_pkcs11_public_key_t *this,
                    427:                                        cred_encoding_type_t type, void *cache, chunk_t *encoding)
                    428: {
                    429:        enumerator_t *enumerator;
                    430:        bool success = FALSE;
                    431:        CK_ATTRIBUTE attr[] = {
                    432:                {CKA_MODULUS, NULL, 0},
                    433:                {CKA_PUBLIC_EXPONENT, NULL, 0},
                    434:        };
                    435: 
                    436:        enumerator = this->lib->create_object_attr_enumerator(this->lib,
                    437:                                                        this->session, this->object, attr, countof(attr));
                    438:        if (enumerator && enumerator->enumerate(enumerator, NULL) &&
                    439:                attr[0].ulValueLen > 0 && attr[1].ulValueLen > 0)
                    440:        {
                    441:                chunk_t n, e;
                    442:                /* some tokens/libraries add unnecessary 0x00 prefixes */
                    443:                n = chunk_skip_zero(chunk_create(attr[0].pValue, attr[0].ulValueLen));
                    444:                if (n.ptr[0] & 0x80)
                    445:                {       /* add leading 0x00, encoders might expect it in two's complement */
                    446:                        n = chunk_cata("cc", chunk_from_chars(0x00), n);
                    447:                }
                    448:                e = chunk_skip_zero(chunk_create(attr[1].pValue, attr[1].ulValueLen));
                    449:                if (e.ptr[0] & 0x80)
                    450:                {
                    451:                        e = chunk_cata("cc", chunk_from_chars(0x00), e);
                    452:                }
                    453:                success = lib->encoding->encode(lib->encoding, type, cache, encoding,
                    454:                        CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
                    455:        }
                    456:        DESTROY_IF(enumerator);
                    457:        return success;
                    458: }
                    459: 
                    460: METHOD(public_key_t, get_encoding, bool,
                    461:        private_pkcs11_public_key_t *this, cred_encoding_type_t type,
                    462:        chunk_t *encoding)
                    463: {
                    464:        switch (this->type)
                    465:        {
                    466:                case KEY_RSA:
                    467:                        return encode_rsa(this, type, NULL, encoding);
                    468:                case KEY_ECDSA:
                    469:                        return encode_ecdsa(this, type, encoding);
                    470:                default:
                    471:                        return FALSE;
                    472:        }
                    473: }
                    474: 
                    475: METHOD(public_key_t, get_fingerprint, bool,
                    476:        private_pkcs11_public_key_t *this, cred_encoding_type_t type, chunk_t *fp)
                    477: {
                    478:        if (lib->encoding->get_cache(lib->encoding, type, this, fp))
                    479:        {
                    480:                return TRUE;
                    481:        }
                    482:        switch (this->type)
                    483:        {
                    484:                case KEY_RSA:
                    485:                        return encode_rsa(this, type, this, fp);
                    486:                case KEY_ECDSA:
                    487:                        return fingerprint_ecdsa(this, type, fp);
                    488:                default:
                    489:                        return FALSE;
                    490:        }
                    491: }
                    492: 
                    493: METHOD(public_key_t, get_ref, public_key_t*,
                    494:        private_pkcs11_public_key_t *this)
                    495: {
                    496:        ref_get(&this->ref);
                    497:        return &this->public.key;
                    498: }
                    499: 
                    500: METHOD(public_key_t, destroy, void,
                    501:        private_pkcs11_public_key_t *this)
                    502: {
                    503:        if (ref_put(&this->ref))
                    504:        {
                    505:                lib->encoding->clear_cache(lib->encoding, this);
                    506:                this->lib->f->C_CloseSession(this->session);
                    507:                free(this);
                    508:        }
                    509: }
                    510: 
                    511: /**
                    512:  * Create an empty PKCS#11 public key
                    513:  */
                    514: static private_pkcs11_public_key_t *create(key_type_t type, size_t k,
                    515:                                                        pkcs11_library_t *p11, CK_SLOT_ID slot,
                    516:                                                        CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
                    517: {
                    518:        private_pkcs11_public_key_t *this;
                    519: 
                    520:        INIT(this,
                    521:                .public = {
                    522:                        .key = {
                    523:                                .get_type = _get_type,
                    524:                                .verify = _verify,
                    525:                                .encrypt = _encrypt,
                    526:                                .equals = public_key_equals,
                    527:                                .get_keysize = _get_keysize,
                    528:                                .get_fingerprint = _get_fingerprint,
                    529:                                .has_fingerprint = public_key_has_fingerprint,
                    530:                                .get_encoding = _get_encoding,
                    531:                                .get_ref = _get_ref,
                    532:                                .destroy = _destroy,
                    533:                        },
                    534:                },
                    535:                .type = type,
                    536:                .k = k,
                    537:                .lib = p11,
                    538:                .slot = slot,
                    539:                .session = session,
                    540:                .object = object,
                    541:                .ref = 1,
                    542:        );
                    543: 
                    544:        return this;
                    545: }
                    546: 
                    547: /**
                    548:  * Find a key object, including PKCS11 library and slot
                    549:  */
                    550: static private_pkcs11_public_key_t* find_key(key_type_t type, size_t keylen,
                    551:                                                                                         CK_ATTRIBUTE_PTR tmpl, int count)
                    552: {
                    553:        private_pkcs11_public_key_t *this = NULL;
                    554:        pkcs11_manager_t *manager;
                    555:        enumerator_t *enumerator, *keys;
                    556:        pkcs11_library_t *p11;
                    557:        CK_SLOT_ID slot;
                    558: 
                    559:        manager = lib->get(lib, "pkcs11-manager");
                    560:        if (!manager)
                    561:        {
                    562:                return NULL;
                    563:        }
                    564: 
                    565:        enumerator = manager->create_token_enumerator(manager);
                    566:        while (enumerator->enumerate(enumerator, &p11, &slot))
                    567:        {
                    568:                CK_OBJECT_HANDLE object;
                    569:                CK_SESSION_HANDLE session;
                    570:                CK_RV rv;
                    571: 
                    572:                rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL,
                    573:                                                                   &session);
                    574:                if (rv != CKR_OK)
                    575:                {
                    576:                        DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
                    577:                        continue;
                    578:                }
                    579:                keys = p11->create_object_enumerator(p11, session, tmpl, count,
                    580:                                                                                         NULL, 0);
                    581:                if (keys->enumerate(keys, &object))
                    582:                {
                    583:                        this = create(type, keylen, p11, slot, session, object);
                    584:                        keys->destroy(keys);
                    585:                        break;
                    586:                }
                    587:                keys->destroy(keys);
                    588:                p11->f->C_CloseSession(session);
                    589:        }
                    590:        enumerator->destroy(enumerator);
                    591:        return this;
                    592: }
                    593: 
                    594: /**
                    595:  * Find an RSA key object
                    596:  */
                    597: static private_pkcs11_public_key_t* find_rsa_key(chunk_t n, chunk_t e,
                    598:                                                                                                 size_t keylen)
                    599: {
                    600:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    601:        CK_KEY_TYPE type = CKK_RSA;
                    602:        CK_ATTRIBUTE tmpl[] = {
                    603:                {CKA_CLASS, &class, sizeof(class)},
                    604:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    605:                {CKA_MODULUS, n.ptr, n.len},
                    606:                {CKA_PUBLIC_EXPONENT, e.ptr, e.len},
                    607:        };
                    608:        return find_key(KEY_RSA, keylen, tmpl, countof(tmpl));
                    609: }
                    610: 
                    611: /**
                    612:  * Find an ECDSA key object
                    613:  */
                    614: static private_pkcs11_public_key_t* find_ecdsa_key(chunk_t ecparams,
                    615:                                                                                                   chunk_t ecpoint,
                    616:                                                                                                   size_t keylen)
                    617: {
                    618:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    619:        CK_KEY_TYPE type = CKK_ECDSA;
                    620:        CK_ATTRIBUTE tmpl[] = {
                    621:                {CKA_CLASS, &class, sizeof(class)},
                    622:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    623:                {CKA_EC_PARAMS, ecparams.ptr, ecparams.len},
                    624:                {CKA_EC_POINT, ecpoint.ptr, ecpoint.len},
                    625:        };
                    626:        return find_key(KEY_ECDSA, keylen, tmpl, countof(tmpl));
                    627: }
                    628: 
                    629: /**
                    630:  * Create a key object in a suitable token session
                    631:  */
                    632: static private_pkcs11_public_key_t* create_key(key_type_t type, size_t keylen,
                    633:                                                                CK_MECHANISM_TYPE_PTR mechanisms, int mcount,
                    634:                                                                CK_ATTRIBUTE_PTR tmpl, int count)
                    635: {
                    636:        private_pkcs11_public_key_t *this = NULL;
                    637:        pkcs11_manager_t *manager;
                    638:        enumerator_t *enumerator, *mechs;
                    639:        pkcs11_library_t *p11;
                    640:        CK_SLOT_ID slot;
                    641: 
                    642:        manager = lib->get(lib, "pkcs11-manager");
                    643:        if (!manager)
                    644:        {
                    645:                return NULL;
                    646:        }
                    647: 
                    648:        enumerator = manager->create_token_enumerator(manager);
                    649:        while (enumerator->enumerate(enumerator, &p11, &slot))
                    650:        {
                    651:                CK_MECHANISM_TYPE mech;
                    652:                CK_MECHANISM_INFO info;
                    653:                CK_OBJECT_HANDLE object;
                    654:                CK_SESSION_HANDLE session;
                    655:                CK_RV rv;
                    656: 
                    657:                mechs = p11->create_mechanism_enumerator(p11, slot);
                    658:                while (mechs->enumerate(mechs, &mech, &info))
                    659:                {
                    660:                        bool found = FALSE;
                    661:                        int i;
                    662:                        if (!(info.flags & CKF_VERIFY))
                    663:                        {
                    664:                                continue;
                    665:                        }
                    666:                        for (i = 0; i < mcount; i++)
                    667:                        {
                    668:                                if (mechanisms[i] == mech)
                    669:                                {
                    670:                                        found = TRUE;
                    671:                                        break;
                    672:                                }
                    673:                        }
                    674:                        if (!found)
                    675:                        {
                    676:                                continue;
                    677:                        }
                    678:                        rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL,
                    679:                                                                           &session);
                    680:                        if (rv != CKR_OK)
                    681:                        {
                    682:                                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
                    683:                                         ck_rv_names, rv);
                    684:                                continue;
                    685:                        }
                    686:                        rv = p11->f->C_CreateObject(session, tmpl, count, &object);
                    687:                        if (rv == CKR_OK)
                    688:                        {
                    689:                                this = create(type, keylen, p11, slot, session, object);
                    690:                                DBG2(DBG_CFG, "created %N public key on token '%s':%d ",
                    691:                                         key_type_names, type, p11->get_name(p11), slot);
                    692:                        }
                    693:                        else
                    694:                        {
                    695:                                DBG1(DBG_CFG, "creating %N public key on token '%s':%d "
                    696:                                         "failed: %N", key_type_names, type, p11->get_name(p11),
                    697:                                         slot, ck_rv_names, rv);
                    698:                                p11->f->C_CloseSession(session);
                    699:                        }
                    700:                        break;
                    701:                }
                    702:                mechs->destroy(mechs);
                    703:                if (this)
                    704:                {
                    705:                        break;
                    706:                }
                    707:        }
                    708:        enumerator->destroy(enumerator);
                    709:        return this;
                    710: }
                    711: 
                    712: /**
                    713:  * Create an RSA key object in a suitable token session
                    714:  */
                    715: static private_pkcs11_public_key_t* create_rsa_key(chunk_t n, chunk_t e,
                    716:                                                                                                   size_t keylen)
                    717: {
                    718:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    719:        CK_KEY_TYPE type = CKK_RSA;
                    720:        CK_ATTRIBUTE tmpl[] = {
                    721:                {CKA_CLASS, &class, sizeof(class)},
                    722:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    723:                {CKA_MODULUS, n.ptr, n.len},
                    724:                {CKA_PUBLIC_EXPONENT, e.ptr, e.len},
                    725:        };
                    726:        CK_MECHANISM_TYPE mechs[] = {
                    727:                CKM_RSA_PKCS,
                    728:                CKM_SHA1_RSA_PKCS,
                    729:                CKM_SHA256_RSA_PKCS,
                    730:                CKM_SHA384_RSA_PKCS,
                    731:                CKM_SHA512_RSA_PKCS,
                    732:                CKM_MD5_RSA_PKCS,
                    733:        };
                    734:        return create_key(KEY_RSA, keylen, mechs, countof(mechs), tmpl,
                    735:                                          countof(tmpl));
                    736: }
                    737: 
                    738: /**
                    739:  * Create an ECDSA key object in a suitable token session
                    740:  */
                    741: static private_pkcs11_public_key_t* create_ecdsa_key(chunk_t ecparams,
                    742:                                                                                                         chunk_t ecpoint,
                    743:                                                                                                         size_t keylen)
                    744: {
                    745:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    746:        CK_KEY_TYPE type = CKK_ECDSA;
                    747:        CK_ATTRIBUTE tmpl[] = {
                    748:                {CKA_CLASS, &class, sizeof(class)},
                    749:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    750:                {CKA_EC_PARAMS, ecparams.ptr, ecparams.len},
                    751:                {CKA_EC_POINT, ecpoint.ptr, ecpoint.len},
                    752:        };
                    753:        CK_MECHANISM_TYPE mechs[] = {
                    754:                CKM_ECDSA,
                    755:                CKM_ECDSA_SHA1,
                    756:        };
                    757:        return create_key(KEY_ECDSA, keylen, mechs,
                    758:                                          countof(mechs), tmpl, countof(tmpl));
                    759: }
                    760: 
                    761: /**
                    762:  * See header
                    763:  */
                    764: pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args)
                    765: {
                    766:        private_pkcs11_public_key_t *this;
                    767:        chunk_t n, e, blob;
                    768:        size_t keylen = 0;
                    769: 
                    770:        n = e = blob = chunk_empty;
                    771:        while (TRUE)
                    772:        {
                    773:                switch (va_arg(args, builder_part_t))
                    774:                {
                    775:                        case BUILD_BLOB_ASN1_DER:
                    776:                                blob = va_arg(args, chunk_t);
                    777:                                continue;
                    778:                        case BUILD_RSA_MODULUS:
                    779:                                n = va_arg(args, chunk_t);
                    780:                                continue;
                    781:                        case BUILD_RSA_PUB_EXP:
                    782:                                e = va_arg(args, chunk_t);
                    783:                                continue;
                    784:                        case BUILD_END:
                    785:                                break;
                    786:                        default:
                    787:                                return NULL;
                    788:                }
                    789:                break;
                    790:        }
                    791:        if (type == KEY_RSA && e.ptr && n.ptr)
                    792:        {
                    793:                if (n.len && n.ptr[0] == 0)
                    794:                {       /* trim leading zero byte in modulus */
                    795:                        n = chunk_skip(n, 1);
                    796:                }
                    797:                keylen = n.len * 8;
                    798:                this = find_rsa_key(n, e, keylen);
                    799:                if (this)
                    800:                {
                    801:                        return &this->public;
                    802:                }
                    803:                this = create_rsa_key(n, e, keylen);
                    804:                if (this)
                    805:                {
                    806:                        return &this->public;
                    807:                }
                    808:        }
                    809:        else if (type == KEY_ECDSA && blob.ptr)
                    810:        {
                    811:                chunk_t ecparams, ecpoint;
                    812:                ecparams = ecpoint = chunk_empty;
                    813:                if (parse_ecdsa_public_key(blob, &ecparams, &ecpoint, &keylen))
                    814:                {
                    815:                        this = find_ecdsa_key(ecparams, ecpoint, keylen);
                    816:                        if (!this)
                    817:                        {
                    818:                                this = create_ecdsa_key(ecparams, ecpoint, keylen);
                    819:                        }
                    820:                        chunk_free(&ecpoint);
                    821:                        if (this)
                    822:                        {
                    823:                                return &this->public;
                    824:                        }
                    825:                }
                    826:        }
                    827:        return NULL;
                    828: }
                    829: 
                    830: static private_pkcs11_public_key_t *find_key_by_keyid(pkcs11_library_t *p11,
                    831:                                                                                                int slot, key_type_t key_type,
                    832:                                                                                                chunk_t keyid)
                    833: {
                    834:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    835:        CK_KEY_TYPE type;
                    836:        CK_ATTRIBUTE tmpl[] = {
                    837:                {CKA_CLASS, &class, sizeof(class)},
                    838:                {CKA_ID, keyid.ptr, keyid.len},
                    839:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    840:        };
                    841:        CK_OBJECT_HANDLE object;
                    842:        CK_ATTRIBUTE attr[] = {
                    843:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    844:        };
                    845:        CK_SESSION_HANDLE session;
                    846:        CK_RV rv;
                    847:        enumerator_t *enumerator;
                    848:        int count = countof(tmpl);
                    849:        bool found = FALSE;
                    850:        size_t keylen;
                    851: 
                    852:        switch (key_type)
                    853:        {
                    854:                case KEY_RSA:
                    855:                        type = CKK_RSA;
                    856:                        break;
                    857:                case KEY_ECDSA:
                    858:                        type = CKK_ECDSA;
                    859:                        break;
                    860:                default:
                    861:                        /* don't specify key type on KEY_ANY */
                    862:                        count--;
                    863:                        break;
                    864:        }
                    865: 
                    866:        rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &session);
                    867:        if (rv != CKR_OK)
                    868:        {
                    869:                DBG1(DBG_CFG, "opening public key session on '%s':%d failed: %N",
                    870:                         p11->get_name(p11), slot, ck_rv_names, rv);
                    871:                return NULL;
                    872:        }
                    873: 
                    874:        enumerator = p11->create_object_enumerator(p11, session, tmpl, count, attr,
                    875:                                                                                           countof(attr));
                    876:        if (enumerator->enumerate(enumerator, &object))
                    877:        {
                    878:                switch (type)
                    879:                {
                    880:                        case CKK_ECDSA:
                    881:                        {
                    882:                                chunk_t ecparams;
                    883:                                if (p11->get_ck_attribute(p11, session, object, CKA_EC_PARAMS,
                    884:                                                                                  &ecparams) &&
                    885:                                        keylen_from_ecparams(ecparams, &keylen))
                    886:                                {
                    887:                                        chunk_free(&ecparams);
                    888:                                        key_type = KEY_ECDSA;
                    889:                                        found = TRUE;
                    890:                                }
                    891:                                break;
                    892:                        }
                    893:                        case CKK_RSA:
                    894:                        {
                    895:                                chunk_t n;
                    896:                                if (p11->get_ck_attribute(p11, session, object, CKA_MODULUS,
                    897:                                                                                  &n) && n.len > 0)
                    898:                                {
                    899:                                        keylen = n.len * 8;
                    900:                                        chunk_free(&n);
                    901:                                        key_type = KEY_RSA;
                    902:                                        found = TRUE;
                    903:                                }
                    904:                                break;
                    905:                        }
                    906:                        default:
                    907:                                DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
                    908:                                break;
                    909:                }
                    910:        }
                    911:        enumerator->destroy(enumerator);
                    912: 
                    913:        if (found)
                    914:        {
                    915:                return create(key_type, keylen, p11, slot, session, object);
                    916:        }
                    917:        p11->f->C_CloseSession(session);
                    918:        return NULL;
                    919: }
                    920: 
                    921: /**
                    922:  * See header.
                    923:  */
                    924: public_key_t *pkcs11_public_key_connect(pkcs11_library_t *p11, int slot,
                    925:                                                                                key_type_t type, chunk_t keyid)
                    926: {
                    927:        private_pkcs11_public_key_t *this;
                    928: 
                    929:        this = find_key_by_keyid(p11, slot, type, keyid);
                    930:        if (!this)
                    931:        {
                    932:                return NULL;
                    933:        }
                    934:        return &this->public.key;
                    935: }

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