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

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: 
1.1.1.2 ! misho     214:        mechanism = pkcs11_signature_scheme_to_mech(this->lib, this->slot, scheme,
        !           215:                                                                                                this->type, this->k, &hash_alg);
1.1       misho     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);
1.1.1.2 ! misho     280:                switch (scheme)
        !           281:                {
        !           282:                        case SIGN_RSA_EMSA_PKCS1_SHA1:
        !           283:                        case SIGN_RSA_EMSA_PKCS1_SHA2_256:
        !           284:                        case SIGN_RSA_EMSA_PKCS1_SHA2_384:
        !           285:                        case SIGN_RSA_EMSA_PKCS1_SHA2_512:
        !           286:                                /* encode PKCS#1 digestInfo if the token does not support it */
        !           287:                                hash = asn1_wrap(ASN1_SEQUENCE, "mm",
        !           288:                                                                 asn1_algorithmIdentifier(
        !           289:                                                                        hasher_algorithm_to_oid(hash_alg)),
        !           290:                                                                 asn1_wrap(ASN1_OCTET_STRING, "m", hash));
        !           291:                                break;
        !           292:                        default:
        !           293:                                break;
        !           294:                }
1.1       misho     295:                data = hash;
                    296:        }
                    297:        rv = this->lib->f->C_Verify(session, data.ptr, data.len, sig.ptr, sig.len);
                    298:        this->lib->f->C_CloseSession(session);
                    299:        chunk_free(&hash);
                    300:        if (rv != CKR_OK)
                    301:        {
                    302:                DBG1(DBG_LIB, "C_Verify() failed: %N", ck_rv_names, rv);
                    303:                return FALSE;
                    304:        }
                    305:        return TRUE;
                    306: }
                    307: 
                    308: METHOD(public_key_t, encrypt, bool,
                    309:        private_pkcs11_public_key_t *this, encryption_scheme_t scheme,
                    310:        chunk_t plain, chunk_t *crypt)
                    311: {
                    312:        CK_MECHANISM_PTR mechanism;
                    313:        CK_SESSION_HANDLE session;
                    314:        CK_BYTE_PTR buf;
                    315:        CK_ULONG len;
                    316:        CK_RV rv;
                    317: 
                    318:        mechanism = pkcs11_encryption_scheme_to_mech(scheme);
                    319:        if (!mechanism)
                    320:        {
                    321:                DBG1(DBG_LIB, "encryption scheme %N not supported",
                    322:                         encryption_scheme_names, scheme);
                    323:                return FALSE;
                    324:        }
                    325:        rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL,
                    326:                                                                         &session);
                    327:        if (rv != CKR_OK)
                    328:        {
                    329:                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
                    330:                return FALSE;
                    331:        }
                    332:        rv = this->lib->f->C_EncryptInit(session, mechanism, this->object);
                    333:        if (rv != CKR_OK)
                    334:        {
                    335:                this->lib->f->C_CloseSession(session);
                    336:                DBG1(DBG_LIB, "C_EncryptInit() failed: %N", ck_rv_names, rv);
                    337:                return FALSE;
                    338:        }
                    339:        len = (get_keysize(this) + 7) / 8;
                    340:        buf = malloc(len);
                    341:        rv = this->lib->f->C_Encrypt(session, plain.ptr, plain.len, buf, &len);
                    342:        this->lib->f->C_CloseSession(session);
                    343:        if (rv != CKR_OK)
                    344:        {
                    345:                DBG1(DBG_LIB, "C_Encrypt() failed: %N", ck_rv_names, rv);
                    346:                free(buf);
                    347:                return FALSE;
                    348:        }
                    349:        *crypt = chunk_create(buf, len);
                    350:        return TRUE;
                    351: }
                    352: 
                    353: /**
                    354:  * Encode ECDSA key using a given encoding type
                    355:  */
                    356: static bool encode_ecdsa(private_pkcs11_public_key_t *this,
                    357:                                                 cred_encoding_type_t type, chunk_t *encoding)
                    358: {
                    359:        enumerator_t *enumerator;
                    360:        bool success = FALSE;
                    361:        CK_ATTRIBUTE attr[] = {
                    362:                {CKA_EC_PARAMS, NULL, 0},
                    363:                {CKA_EC_POINT, NULL, 0},
                    364:        };
                    365: 
                    366:        if (type != PUBKEY_SPKI_ASN1_DER && type != PUBKEY_PEM)
                    367:        {
                    368:                return FALSE;
                    369:        }
                    370: 
                    371:        enumerator = this->lib->create_object_attr_enumerator(this->lib,
                    372:                                                        this->session, this->object, attr, countof(attr));
                    373:        if (enumerator && enumerator->enumerate(enumerator, NULL) &&
                    374:                attr[0].ulValueLen > 0 && attr[1].ulValueLen > 0)
                    375:        {
                    376:                chunk_t ecparams, ecpoint;
                    377:                ecparams = chunk_create(attr[0].pValue, attr[0].ulValueLen);
                    378:                ecpoint = chunk_create(attr[1].pValue, attr[1].ulValueLen);
                    379:                /* encode as subjectPublicKeyInfo */
                    380:                *encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
                    381:                                                asn1_wrap(ASN1_SEQUENCE, "mc",
                    382:                                                        asn1_build_known_oid(OID_EC_PUBLICKEY), ecparams),
                    383:                                                asn1_bitstring("c", ecpoint));
                    384:                success = TRUE;
                    385:                if (type == PUBKEY_PEM)
                    386:                {
                    387:                        chunk_t asn1 = *encoding;
                    388:                        success = lib->encoding->encode(lib->encoding, PUBKEY_PEM,
                    389:                                                        NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
                    390:                                                        asn1, CRED_PART_END);
                    391:                        chunk_clear(&asn1);
                    392:                }
                    393:        }
                    394:        DESTROY_IF(enumerator);
                    395:        return success;
                    396: }
                    397: 
                    398: /**
                    399:  * Compute fingerprint of an ECDSA key
                    400:  */
                    401: static bool fingerprint_ecdsa(private_pkcs11_public_key_t *this,
                    402:                                                          cred_encoding_type_t type, chunk_t *fp)
                    403: {
                    404:        hasher_t *hasher;
                    405:        chunk_t asn1;
                    406: 
                    407:        switch (type)
                    408:        {
                    409:                case KEYID_PUBKEY_SHA1:
                    410:                        if (!this->lib->get_ck_attribute(this->lib, this->session,
                    411:                                                this->object, CKA_EC_POINT, &asn1))
                    412:                        {
                    413:                                return FALSE;
                    414:                        }
                    415:                        break;
                    416:                case KEYID_PUBKEY_INFO_SHA1:
                    417:                        if (!encode_ecdsa(this, PUBKEY_SPKI_ASN1_DER, &asn1))
                    418:                        {
                    419:                                return FALSE;
                    420:                        }
                    421:                        break;
                    422:                default:
                    423:                        return FALSE;
                    424:        }
                    425:        hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
                    426:        if (!hasher || !hasher->allocate_hash(hasher, asn1, fp))
                    427:        {
                    428:                DESTROY_IF(hasher);
                    429:                chunk_clear(&asn1);
                    430:                return FALSE;
                    431:        }
                    432:        hasher->destroy(hasher);
                    433:        chunk_clear(&asn1);
                    434:        lib->encoding->cache(lib->encoding, type, this, *fp);
                    435:        return TRUE;
                    436: }
                    437: 
                    438: /**
                    439:  * Encode RSA key using a given encoding type
                    440:  */
                    441: static bool encode_rsa(private_pkcs11_public_key_t *this,
                    442:                                        cred_encoding_type_t type, void *cache, chunk_t *encoding)
                    443: {
                    444:        enumerator_t *enumerator;
                    445:        bool success = FALSE;
                    446:        CK_ATTRIBUTE attr[] = {
                    447:                {CKA_MODULUS, NULL, 0},
                    448:                {CKA_PUBLIC_EXPONENT, NULL, 0},
                    449:        };
                    450: 
                    451:        enumerator = this->lib->create_object_attr_enumerator(this->lib,
                    452:                                                        this->session, this->object, attr, countof(attr));
                    453:        if (enumerator && enumerator->enumerate(enumerator, NULL) &&
                    454:                attr[0].ulValueLen > 0 && attr[1].ulValueLen > 0)
                    455:        {
                    456:                chunk_t n, e;
                    457:                /* some tokens/libraries add unnecessary 0x00 prefixes */
                    458:                n = chunk_skip_zero(chunk_create(attr[0].pValue, attr[0].ulValueLen));
                    459:                if (n.ptr[0] & 0x80)
                    460:                {       /* add leading 0x00, encoders might expect it in two's complement */
                    461:                        n = chunk_cata("cc", chunk_from_chars(0x00), n);
                    462:                }
                    463:                e = chunk_skip_zero(chunk_create(attr[1].pValue, attr[1].ulValueLen));
                    464:                if (e.ptr[0] & 0x80)
                    465:                {
                    466:                        e = chunk_cata("cc", chunk_from_chars(0x00), e);
                    467:                }
                    468:                success = lib->encoding->encode(lib->encoding, type, cache, encoding,
                    469:                        CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
                    470:        }
                    471:        DESTROY_IF(enumerator);
                    472:        return success;
                    473: }
                    474: 
                    475: METHOD(public_key_t, get_encoding, bool,
                    476:        private_pkcs11_public_key_t *this, cred_encoding_type_t type,
                    477:        chunk_t *encoding)
                    478: {
                    479:        switch (this->type)
                    480:        {
                    481:                case KEY_RSA:
                    482:                        return encode_rsa(this, type, NULL, encoding);
                    483:                case KEY_ECDSA:
                    484:                        return encode_ecdsa(this, type, encoding);
                    485:                default:
                    486:                        return FALSE;
                    487:        }
                    488: }
                    489: 
                    490: METHOD(public_key_t, get_fingerprint, bool,
                    491:        private_pkcs11_public_key_t *this, cred_encoding_type_t type, chunk_t *fp)
                    492: {
                    493:        if (lib->encoding->get_cache(lib->encoding, type, this, fp))
                    494:        {
                    495:                return TRUE;
                    496:        }
                    497:        switch (this->type)
                    498:        {
                    499:                case KEY_RSA:
                    500:                        return encode_rsa(this, type, this, fp);
                    501:                case KEY_ECDSA:
                    502:                        return fingerprint_ecdsa(this, type, fp);
                    503:                default:
                    504:                        return FALSE;
                    505:        }
                    506: }
                    507: 
                    508: METHOD(public_key_t, get_ref, public_key_t*,
                    509:        private_pkcs11_public_key_t *this)
                    510: {
                    511:        ref_get(&this->ref);
                    512:        return &this->public.key;
                    513: }
                    514: 
                    515: METHOD(public_key_t, destroy, void,
                    516:        private_pkcs11_public_key_t *this)
                    517: {
                    518:        if (ref_put(&this->ref))
                    519:        {
                    520:                lib->encoding->clear_cache(lib->encoding, this);
                    521:                this->lib->f->C_CloseSession(this->session);
                    522:                free(this);
                    523:        }
                    524: }
                    525: 
                    526: /**
                    527:  * Create an empty PKCS#11 public key
                    528:  */
                    529: static private_pkcs11_public_key_t *create(key_type_t type, size_t k,
                    530:                                                        pkcs11_library_t *p11, CK_SLOT_ID slot,
                    531:                                                        CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
                    532: {
                    533:        private_pkcs11_public_key_t *this;
                    534: 
                    535:        INIT(this,
                    536:                .public = {
                    537:                        .key = {
                    538:                                .get_type = _get_type,
                    539:                                .verify = _verify,
                    540:                                .encrypt = _encrypt,
                    541:                                .equals = public_key_equals,
                    542:                                .get_keysize = _get_keysize,
                    543:                                .get_fingerprint = _get_fingerprint,
                    544:                                .has_fingerprint = public_key_has_fingerprint,
                    545:                                .get_encoding = _get_encoding,
                    546:                                .get_ref = _get_ref,
                    547:                                .destroy = _destroy,
                    548:                        },
                    549:                },
                    550:                .type = type,
                    551:                .k = k,
                    552:                .lib = p11,
                    553:                .slot = slot,
                    554:                .session = session,
                    555:                .object = object,
                    556:                .ref = 1,
                    557:        );
                    558: 
                    559:        return this;
                    560: }
                    561: 
                    562: /**
                    563:  * Find a key object, including PKCS11 library and slot
                    564:  */
                    565: static private_pkcs11_public_key_t* find_key(key_type_t type, size_t keylen,
                    566:                                                                                         CK_ATTRIBUTE_PTR tmpl, int count)
                    567: {
                    568:        private_pkcs11_public_key_t *this = NULL;
                    569:        pkcs11_manager_t *manager;
                    570:        enumerator_t *enumerator, *keys;
                    571:        pkcs11_library_t *p11;
                    572:        CK_SLOT_ID slot;
                    573: 
                    574:        manager = lib->get(lib, "pkcs11-manager");
                    575:        if (!manager)
                    576:        {
                    577:                return NULL;
                    578:        }
                    579: 
                    580:        enumerator = manager->create_token_enumerator(manager);
                    581:        while (enumerator->enumerate(enumerator, &p11, &slot))
                    582:        {
                    583:                CK_OBJECT_HANDLE object;
                    584:                CK_SESSION_HANDLE session;
                    585:                CK_RV rv;
                    586: 
                    587:                rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL,
                    588:                                                                   &session);
                    589:                if (rv != CKR_OK)
                    590:                {
                    591:                        DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
                    592:                        continue;
                    593:                }
                    594:                keys = p11->create_object_enumerator(p11, session, tmpl, count,
                    595:                                                                                         NULL, 0);
                    596:                if (keys->enumerate(keys, &object))
                    597:                {
                    598:                        this = create(type, keylen, p11, slot, session, object);
                    599:                        keys->destroy(keys);
                    600:                        break;
                    601:                }
                    602:                keys->destroy(keys);
                    603:                p11->f->C_CloseSession(session);
                    604:        }
                    605:        enumerator->destroy(enumerator);
                    606:        return this;
                    607: }
                    608: 
                    609: /**
                    610:  * Find an RSA key object
                    611:  */
                    612: static private_pkcs11_public_key_t* find_rsa_key(chunk_t n, chunk_t e,
                    613:                                                                                                 size_t keylen)
                    614: {
                    615:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    616:        CK_KEY_TYPE type = CKK_RSA;
                    617:        CK_ATTRIBUTE tmpl[] = {
                    618:                {CKA_CLASS, &class, sizeof(class)},
                    619:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    620:                {CKA_MODULUS, n.ptr, n.len},
                    621:                {CKA_PUBLIC_EXPONENT, e.ptr, e.len},
                    622:        };
                    623:        return find_key(KEY_RSA, keylen, tmpl, countof(tmpl));
                    624: }
                    625: 
                    626: /**
                    627:  * Find an ECDSA key object
                    628:  */
                    629: static private_pkcs11_public_key_t* find_ecdsa_key(chunk_t ecparams,
                    630:                                                                                                   chunk_t ecpoint,
                    631:                                                                                                   size_t keylen)
                    632: {
                    633:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    634:        CK_KEY_TYPE type = CKK_ECDSA;
                    635:        CK_ATTRIBUTE tmpl[] = {
                    636:                {CKA_CLASS, &class, sizeof(class)},
                    637:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    638:                {CKA_EC_PARAMS, ecparams.ptr, ecparams.len},
                    639:                {CKA_EC_POINT, ecpoint.ptr, ecpoint.len},
                    640:        };
                    641:        return find_key(KEY_ECDSA, keylen, tmpl, countof(tmpl));
                    642: }
                    643: 
                    644: /**
                    645:  * Create a key object in a suitable token session
                    646:  */
                    647: static private_pkcs11_public_key_t* create_key(key_type_t type, size_t keylen,
                    648:                                                                CK_MECHANISM_TYPE_PTR mechanisms, int mcount,
                    649:                                                                CK_ATTRIBUTE_PTR tmpl, int count)
                    650: {
                    651:        private_pkcs11_public_key_t *this = NULL;
                    652:        pkcs11_manager_t *manager;
                    653:        enumerator_t *enumerator, *mechs;
                    654:        pkcs11_library_t *p11;
                    655:        CK_SLOT_ID slot;
                    656: 
                    657:        manager = lib->get(lib, "pkcs11-manager");
                    658:        if (!manager)
                    659:        {
                    660:                return NULL;
                    661:        }
                    662: 
                    663:        enumerator = manager->create_token_enumerator(manager);
                    664:        while (enumerator->enumerate(enumerator, &p11, &slot))
                    665:        {
                    666:                CK_MECHANISM_TYPE mech;
                    667:                CK_MECHANISM_INFO info;
                    668:                CK_OBJECT_HANDLE object;
                    669:                CK_SESSION_HANDLE session;
                    670:                CK_RV rv;
                    671: 
                    672:                mechs = p11->create_mechanism_enumerator(p11, slot);
                    673:                while (mechs->enumerate(mechs, &mech, &info))
                    674:                {
                    675:                        bool found = FALSE;
                    676:                        int i;
                    677:                        if (!(info.flags & CKF_VERIFY))
                    678:                        {
                    679:                                continue;
                    680:                        }
                    681:                        for (i = 0; i < mcount; i++)
                    682:                        {
                    683:                                if (mechanisms[i] == mech)
                    684:                                {
                    685:                                        found = TRUE;
                    686:                                        break;
                    687:                                }
                    688:                        }
                    689:                        if (!found)
                    690:                        {
                    691:                                continue;
                    692:                        }
                    693:                        rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL,
                    694:                                                                           &session);
                    695:                        if (rv != CKR_OK)
                    696:                        {
                    697:                                DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
                    698:                                         ck_rv_names, rv);
                    699:                                continue;
                    700:                        }
                    701:                        rv = p11->f->C_CreateObject(session, tmpl, count, &object);
                    702:                        if (rv == CKR_OK)
                    703:                        {
                    704:                                this = create(type, keylen, p11, slot, session, object);
                    705:                                DBG2(DBG_CFG, "created %N public key on token '%s':%d ",
                    706:                                         key_type_names, type, p11->get_name(p11), slot);
                    707:                        }
                    708:                        else
                    709:                        {
                    710:                                DBG1(DBG_CFG, "creating %N public key on token '%s':%d "
                    711:                                         "failed: %N", key_type_names, type, p11->get_name(p11),
                    712:                                         slot, ck_rv_names, rv);
                    713:                                p11->f->C_CloseSession(session);
                    714:                        }
                    715:                        break;
                    716:                }
                    717:                mechs->destroy(mechs);
                    718:                if (this)
                    719:                {
                    720:                        break;
                    721:                }
                    722:        }
                    723:        enumerator->destroy(enumerator);
                    724:        return this;
                    725: }
                    726: 
                    727: /**
                    728:  * Create an RSA key object in a suitable token session
                    729:  */
                    730: static private_pkcs11_public_key_t* create_rsa_key(chunk_t n, chunk_t e,
                    731:                                                                                                   size_t keylen)
                    732: {
                    733:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    734:        CK_KEY_TYPE type = CKK_RSA;
                    735:        CK_ATTRIBUTE tmpl[] = {
                    736:                {CKA_CLASS, &class, sizeof(class)},
                    737:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    738:                {CKA_MODULUS, n.ptr, n.len},
                    739:                {CKA_PUBLIC_EXPONENT, e.ptr, e.len},
                    740:        };
                    741:        CK_MECHANISM_TYPE mechs[] = {
                    742:                CKM_RSA_PKCS,
                    743:                CKM_SHA1_RSA_PKCS,
                    744:                CKM_SHA256_RSA_PKCS,
                    745:                CKM_SHA384_RSA_PKCS,
                    746:                CKM_SHA512_RSA_PKCS,
                    747:                CKM_MD5_RSA_PKCS,
                    748:        };
                    749:        return create_key(KEY_RSA, keylen, mechs, countof(mechs), tmpl,
                    750:                                          countof(tmpl));
                    751: }
                    752: 
                    753: /**
                    754:  * Create an ECDSA key object in a suitable token session
                    755:  */
                    756: static private_pkcs11_public_key_t* create_ecdsa_key(chunk_t ecparams,
                    757:                                                                                                         chunk_t ecpoint,
                    758:                                                                                                         size_t keylen)
                    759: {
                    760:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    761:        CK_KEY_TYPE type = CKK_ECDSA;
                    762:        CK_ATTRIBUTE tmpl[] = {
                    763:                {CKA_CLASS, &class, sizeof(class)},
                    764:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    765:                {CKA_EC_PARAMS, ecparams.ptr, ecparams.len},
                    766:                {CKA_EC_POINT, ecpoint.ptr, ecpoint.len},
                    767:        };
                    768:        CK_MECHANISM_TYPE mechs[] = {
                    769:                CKM_ECDSA,
                    770:                CKM_ECDSA_SHA1,
                    771:        };
                    772:        return create_key(KEY_ECDSA, keylen, mechs,
                    773:                                          countof(mechs), tmpl, countof(tmpl));
                    774: }
                    775: 
                    776: /**
                    777:  * See header
                    778:  */
                    779: pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args)
                    780: {
                    781:        private_pkcs11_public_key_t *this;
                    782:        chunk_t n, e, blob;
                    783:        size_t keylen = 0;
                    784: 
                    785:        n = e = blob = chunk_empty;
                    786:        while (TRUE)
                    787:        {
                    788:                switch (va_arg(args, builder_part_t))
                    789:                {
                    790:                        case BUILD_BLOB_ASN1_DER:
                    791:                                blob = va_arg(args, chunk_t);
                    792:                                continue;
                    793:                        case BUILD_RSA_MODULUS:
                    794:                                n = va_arg(args, chunk_t);
                    795:                                continue;
                    796:                        case BUILD_RSA_PUB_EXP:
                    797:                                e = va_arg(args, chunk_t);
                    798:                                continue;
                    799:                        case BUILD_END:
                    800:                                break;
                    801:                        default:
                    802:                                return NULL;
                    803:                }
                    804:                break;
                    805:        }
                    806:        if (type == KEY_RSA && e.ptr && n.ptr)
                    807:        {
                    808:                if (n.len && n.ptr[0] == 0)
                    809:                {       /* trim leading zero byte in modulus */
                    810:                        n = chunk_skip(n, 1);
                    811:                }
                    812:                keylen = n.len * 8;
                    813:                this = find_rsa_key(n, e, keylen);
                    814:                if (this)
                    815:                {
                    816:                        return &this->public;
                    817:                }
                    818:                this = create_rsa_key(n, e, keylen);
                    819:                if (this)
                    820:                {
                    821:                        return &this->public;
                    822:                }
                    823:        }
                    824:        else if (type == KEY_ECDSA && blob.ptr)
                    825:        {
                    826:                chunk_t ecparams, ecpoint;
                    827:                ecparams = ecpoint = chunk_empty;
                    828:                if (parse_ecdsa_public_key(blob, &ecparams, &ecpoint, &keylen))
                    829:                {
                    830:                        this = find_ecdsa_key(ecparams, ecpoint, keylen);
                    831:                        if (!this)
                    832:                        {
                    833:                                this = create_ecdsa_key(ecparams, ecpoint, keylen);
                    834:                        }
                    835:                        chunk_free(&ecpoint);
                    836:                        if (this)
                    837:                        {
                    838:                                return &this->public;
                    839:                        }
                    840:                }
                    841:        }
                    842:        return NULL;
                    843: }
                    844: 
                    845: static private_pkcs11_public_key_t *find_key_by_keyid(pkcs11_library_t *p11,
                    846:                                                                                                int slot, key_type_t key_type,
                    847:                                                                                                chunk_t keyid)
                    848: {
                    849:        CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
                    850:        CK_KEY_TYPE type;
                    851:        CK_ATTRIBUTE tmpl[] = {
                    852:                {CKA_CLASS, &class, sizeof(class)},
                    853:                {CKA_ID, keyid.ptr, keyid.len},
                    854:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    855:        };
                    856:        CK_OBJECT_HANDLE object;
                    857:        CK_ATTRIBUTE attr[] = {
                    858:                {CKA_KEY_TYPE, &type, sizeof(type)},
                    859:        };
                    860:        CK_SESSION_HANDLE session;
                    861:        CK_RV rv;
                    862:        enumerator_t *enumerator;
                    863:        int count = countof(tmpl);
                    864:        bool found = FALSE;
                    865:        size_t keylen;
                    866: 
                    867:        switch (key_type)
                    868:        {
                    869:                case KEY_RSA:
                    870:                        type = CKK_RSA;
                    871:                        break;
                    872:                case KEY_ECDSA:
                    873:                        type = CKK_ECDSA;
                    874:                        break;
                    875:                default:
                    876:                        /* don't specify key type on KEY_ANY */
                    877:                        count--;
                    878:                        break;
                    879:        }
                    880: 
                    881:        rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &session);
                    882:        if (rv != CKR_OK)
                    883:        {
                    884:                DBG1(DBG_CFG, "opening public key session on '%s':%d failed: %N",
                    885:                         p11->get_name(p11), slot, ck_rv_names, rv);
                    886:                return NULL;
                    887:        }
                    888: 
                    889:        enumerator = p11->create_object_enumerator(p11, session, tmpl, count, attr,
                    890:                                                                                           countof(attr));
                    891:        if (enumerator->enumerate(enumerator, &object))
                    892:        {
                    893:                switch (type)
                    894:                {
                    895:                        case CKK_ECDSA:
                    896:                        {
                    897:                                chunk_t ecparams;
                    898:                                if (p11->get_ck_attribute(p11, session, object, CKA_EC_PARAMS,
                    899:                                                                                  &ecparams) &&
                    900:                                        keylen_from_ecparams(ecparams, &keylen))
                    901:                                {
                    902:                                        chunk_free(&ecparams);
                    903:                                        key_type = KEY_ECDSA;
                    904:                                        found = TRUE;
                    905:                                }
                    906:                                break;
                    907:                        }
                    908:                        case CKK_RSA:
                    909:                        {
                    910:                                chunk_t n;
                    911:                                if (p11->get_ck_attribute(p11, session, object, CKA_MODULUS,
                    912:                                                                                  &n) && n.len > 0)
                    913:                                {
                    914:                                        keylen = n.len * 8;
                    915:                                        chunk_free(&n);
                    916:                                        key_type = KEY_RSA;
                    917:                                        found = TRUE;
                    918:                                }
                    919:                                break;
                    920:                        }
                    921:                        default:
                    922:                                DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
                    923:                                break;
                    924:                }
                    925:        }
                    926:        enumerator->destroy(enumerator);
                    927: 
                    928:        if (found)
                    929:        {
                    930:                return create(key_type, keylen, p11, slot, session, object);
                    931:        }
                    932:        p11->f->C_CloseSession(session);
                    933:        return NULL;
                    934: }
                    935: 
                    936: /**
                    937:  * See header.
                    938:  */
                    939: public_key_t *pkcs11_public_key_connect(pkcs11_library_t *p11, int slot,
                    940:                                                                                key_type_t type, chunk_t keyid)
                    941: {
                    942:        private_pkcs11_public_key_t *this;
                    943: 
                    944:        this = find_key_by_keyid(p11, slot, type, keyid);
                    945:        if (!this)
                    946:        {
                    947:                return NULL;
                    948:        }
                    949:        return &this->public.key;
                    950: }

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