[BACK]Return to ssh-pkcs11.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/ssh-pkcs11.c, Revision 1.27

1.27    ! djm         1: /* $OpenBSD: ssh-pkcs11.c,v 1.26 2018/02/07 02:06:51 jsing Exp $ */
1.1       markus      2: /*
                      3:  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17:
                     18: #include <sys/types.h>
                     19: #include <sys/queue.h>
                     20: #include <stdarg.h>
                     21: #include <stdio.h>
                     22:
                     23: #include <string.h>
                     24: #include <dlfcn.h>
                     25:
1.9       markus     26: #include <openssl/x509.h>
                     27:
1.1       markus     28: #define CRYPTOKI_COMPAT
                     29: #include "pkcs11.h"
                     30:
                     31: #include "log.h"
                     32: #include "misc.h"
1.15      djm        33: #include "sshkey.h"
1.1       markus     34: #include "ssh-pkcs11.h"
                     35: #include "xmalloc.h"
                     36:
                     37: struct pkcs11_slotinfo {
                     38:        CK_TOKEN_INFO           token;
                     39:        CK_SESSION_HANDLE       session;
                     40:        int                     logged_in;
                     41: };
                     42:
                     43: struct pkcs11_provider {
                     44:        char                    *name;
                     45:        void                    *handle;
                     46:        CK_FUNCTION_LIST        *function_list;
                     47:        CK_INFO                 info;
                     48:        CK_ULONG                nslots;
                     49:        CK_SLOT_ID              *slotlist;
                     50:        struct pkcs11_slotinfo  *slotinfo;
                     51:        int                     valid;
                     52:        int                     refcount;
                     53:        TAILQ_ENTRY(pkcs11_provider) next;
                     54: };
                     55:
                     56: TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
                     57:
                     58: struct pkcs11_key {
                     59:        struct pkcs11_provider  *provider;
                     60:        CK_ULONG                slotidx;
                     61:        int                     (*orig_finish)(RSA *rsa);
1.27    ! djm        62:        RSA_METHOD              *rsa_method;
1.1       markus     63:        char                    *keyid;
                     64:        int                     keyid_len;
                     65: };
                     66:
                     67: int pkcs11_interactive = 0;
                     68:
                     69: int
                     70: pkcs11_init(int interactive)
                     71: {
                     72:        pkcs11_interactive = interactive;
                     73:        TAILQ_INIT(&pkcs11_providers);
                     74:        return (0);
                     75: }
                     76:
                     77: /*
                     78:  * finalize a provider shared libarary, it's no longer usable.
                     79:  * however, there might still be keys referencing this provider,
                     80:  * so the actuall freeing of memory is handled by pkcs11_provider_unref().
                     81:  * this is called when a provider gets unregistered.
                     82:  */
                     83: static void
                     84: pkcs11_provider_finalize(struct pkcs11_provider *p)
                     85: {
                     86:        CK_RV rv;
                     87:        CK_ULONG i;
                     88:
                     89:        debug("pkcs11_provider_finalize: %p refcount %d valid %d",
                     90:            p, p->refcount, p->valid);
                     91:        if (!p->valid)
                     92:                return;
                     93:        for (i = 0; i < p->nslots; i++) {
                     94:                if (p->slotinfo[i].session &&
                     95:                    (rv = p->function_list->C_CloseSession(
                     96:                    p->slotinfo[i].session)) != CKR_OK)
                     97:                        error("C_CloseSession failed: %lu", rv);
                     98:        }
                     99:        if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
                    100:                error("C_Finalize failed: %lu", rv);
                    101:        p->valid = 0;
                    102:        p->function_list = NULL;
1.3       deraadt   103: #ifdef HAVE_DLOPEN
1.1       markus    104:        dlclose(p->handle);
1.3       deraadt   105: #endif
1.1       markus    106: }
                    107:
                    108: /*
                    109:  * remove a reference to the provider.
                    110:  * called when a key gets destroyed or when the provider is unregistered.
                    111:  */
                    112: static void
                    113: pkcs11_provider_unref(struct pkcs11_provider *p)
                    114: {
                    115:        debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount);
                    116:        if (--p->refcount <= 0) {
                    117:                if (p->valid)
                    118:                        error("pkcs11_provider_unref: %p still valid", p);
1.7       djm       119:                free(p->slotlist);
                    120:                free(p->slotinfo);
                    121:                free(p);
1.1       markus    122:        }
                    123: }
                    124:
                    125: /* unregister all providers, keys might still point to the providers */
                    126: void
                    127: pkcs11_terminate(void)
                    128: {
                    129:        struct pkcs11_provider *p;
                    130:
                    131:        while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
                    132:                TAILQ_REMOVE(&pkcs11_providers, p, next);
                    133:                pkcs11_provider_finalize(p);
                    134:                pkcs11_provider_unref(p);
                    135:        }
                    136: }
                    137:
                    138: /* lookup provider by name */
                    139: static struct pkcs11_provider *
                    140: pkcs11_provider_lookup(char *provider_id)
                    141: {
                    142:        struct pkcs11_provider *p;
                    143:
                    144:        TAILQ_FOREACH(p, &pkcs11_providers, next) {
                    145:                debug("check %p %s", p, p->name);
                    146:                if (!strcmp(provider_id, p->name))
                    147:                        return (p);
                    148:        }
                    149:        return (NULL);
                    150: }
                    151:
                    152: /* unregister provider by name */
                    153: int
                    154: pkcs11_del_provider(char *provider_id)
                    155: {
                    156:        struct pkcs11_provider *p;
                    157:
                    158:        if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
                    159:                TAILQ_REMOVE(&pkcs11_providers, p, next);
                    160:                pkcs11_provider_finalize(p);
                    161:                pkcs11_provider_unref(p);
                    162:                return (0);
                    163:        }
                    164:        return (-1);
                    165: }
                    166:
                    167: /* openssl callback for freeing an RSA key */
                    168: static int
                    169: pkcs11_rsa_finish(RSA *rsa)
                    170: {
                    171:        struct pkcs11_key       *k11;
                    172:        int rv = -1;
                    173:
                    174:        if ((k11 = RSA_get_app_data(rsa)) != NULL) {
                    175:                if (k11->orig_finish)
                    176:                        rv = k11->orig_finish(rsa);
                    177:                if (k11->provider)
                    178:                        pkcs11_provider_unref(k11->provider);
1.27    ! djm       179:                RSA_meth_free(k11->rsa_method);
1.7       djm       180:                free(k11->keyid);
                    181:                free(k11);
1.1       markus    182:        }
                    183:        return (rv);
                    184: }
                    185:
1.5       markus    186: /* find a single 'obj' for given attributes */
                    187: static int
                    188: pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
                    189:     CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
                    190: {
                    191:        CK_FUNCTION_LIST        *f;
                    192:        CK_SESSION_HANDLE       session;
                    193:        CK_ULONG                nfound = 0;
                    194:        CK_RV                   rv;
                    195:        int                     ret = -1;
                    196:
                    197:        f = p->function_list;
                    198:        session = p->slotinfo[slotidx].session;
                    199:        if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
                    200:                error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
                    201:                return (-1);
                    202:        }
                    203:        if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
                    204:            nfound != 1) {
                    205:                debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
                    206:                    nfound, nattr, rv);
                    207:        } else
                    208:                ret = 0;
                    209:        if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
                    210:                error("C_FindObjectsFinal failed: %lu", rv);
                    211:        return (ret);
                    212: }
                    213:
1.1       markus    214: /* openssl callback doing the actual signing operation */
                    215: static int
                    216: pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
                    217:     int padding)
                    218: {
                    219:        struct pkcs11_key       *k11;
                    220:        struct pkcs11_slotinfo  *si;
                    221:        CK_FUNCTION_LIST        *f;
                    222:        CK_OBJECT_HANDLE        obj;
1.5       markus    223:        CK_ULONG                tlen = 0;
1.1       markus    224:        CK_RV                   rv;
                    225:        CK_OBJECT_CLASS         private_key_class = CKO_PRIVATE_KEY;
1.10      djm       226:        CK_BBOOL                true_val = CK_TRUE;
1.1       markus    227:        CK_MECHANISM            mech = {
                    228:                CKM_RSA_PKCS, NULL_PTR, 0
                    229:        };
                    230:        CK_ATTRIBUTE            key_filter[] = {
                    231:                {CKA_CLASS, &private_key_class, sizeof(private_key_class) },
                    232:                {CKA_ID, NULL, 0},
1.10      djm       233:                {CKA_SIGN, &true_val, sizeof(true_val) }
1.1       markus    234:        };
1.19      djm       235:        char                    *pin = NULL, prompt[1024];
1.1       markus    236:        int                     rval = -1;
                    237:
                    238:        if ((k11 = RSA_get_app_data(rsa)) == NULL) {
                    239:                error("RSA_get_app_data failed for rsa %p", rsa);
                    240:                return (-1);
                    241:        }
                    242:        if (!k11->provider || !k11->provider->valid) {
                    243:                error("no pkcs11 (valid) provider for rsa %p", rsa);
                    244:                return (-1);
                    245:        }
                    246:        f = k11->provider->function_list;
                    247:        si = &k11->provider->slotinfo[k11->slotidx];
                    248:        if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
                    249:                if (!pkcs11_interactive) {
1.19      djm       250:                        error("need pin entry%s", (si->token.flags &
                    251:                            CKF_PROTECTED_AUTHENTICATION_PATH) ?
                    252:                            " on reader keypad" : "");
1.1       markus    253:                        return (-1);
                    254:                }
1.19      djm       255:                if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
                    256:                        verbose("Deferring PIN entry to reader keypad.");
                    257:                else {
                    258:                        snprintf(prompt, sizeof(prompt),
                    259:                            "Enter PIN for '%s': ", si->token.label);
                    260:                        pin = read_passphrase(prompt, RP_ALLOW_EOF);
                    261:                        if (pin == NULL)
                    262:                                return (-1);    /* bail out */
                    263:                }
                    264:                rv = f->C_Login(si->session, CKU_USER, (u_char *)pin,
                    265:                    (pin != NULL) ? strlen(pin) : 0);
                    266:                if (pin != NULL) {
                    267:                        explicit_bzero(pin, strlen(pin));
                    268:                        free(pin);
                    269:                }
1.16      djm       270:                if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
1.1       markus    271:                        error("C_Login failed: %lu", rv);
                    272:                        return (-1);
                    273:                }
                    274:                si->logged_in = 1;
                    275:        }
                    276:        key_filter[1].pValue = k11->keyid;
                    277:        key_filter[1].ulValueLen = k11->keyid_len;
1.5       markus    278:        /* try to find object w/CKA_SIGN first, retry w/o */
                    279:        if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
                    280:            pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
                    281:                error("cannot find private key");
1.1       markus    282:        } else if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
                    283:                error("C_SignInit failed: %lu", rv);
                    284:        } else {
                    285:                /* XXX handle CKR_BUFFER_TOO_SMALL */
                    286:                tlen = RSA_size(rsa);
                    287:                rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
                    288:                if (rv == CKR_OK)
                    289:                        rval = tlen;
                    290:                else
                    291:                        error("C_Sign failed: %lu", rv);
                    292:        }
                    293:        return (rval);
                    294: }
                    295:
                    296: static int
                    297: pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
                    298:     int padding)
                    299: {
                    300:        return (-1);
                    301: }
                    302:
                    303: /* redirect private key operations for rsa key to pkcs11 token */
                    304: static int
                    305: pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
                    306:     CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
                    307: {
                    308:        struct pkcs11_key       *k11;
                    309:        const RSA_METHOD        *def = RSA_get_default_method();
                    310:
                    311:        k11 = xcalloc(1, sizeof(*k11));
                    312:        k11->provider = provider;
                    313:        provider->refcount++;   /* provider referenced by RSA key */
                    314:        k11->slotidx = slotidx;
                    315:        /* identify key object on smartcard */
                    316:        k11->keyid_len = keyid_attrib->ulValueLen;
1.22      djm       317:        if (k11->keyid_len > 0) {
                    318:                k11->keyid = xmalloc(k11->keyid_len);
                    319:                memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
                    320:        }
1.27    ! djm       321:        k11->rsa_method = RSA_meth_dup(def);
        !           322:        if (k11->rsa_method == NULL)
        !           323:                fatal("%s: RSA_meth_dup failed", __func__);
        !           324:        k11->orig_finish = RSA_meth_get_finish(def);
        !           325:        if (!RSA_meth_set1_name(k11->rsa_method, "pkcs11") ||
        !           326:            !RSA_meth_set_priv_enc(k11->rsa_method,
        !           327:            pkcs11_rsa_private_encrypt) ||
        !           328:            !RSA_meth_set_priv_dec(k11->rsa_method,
        !           329:            pkcs11_rsa_private_decrypt) ||
        !           330:            !RSA_meth_set_finish(k11->rsa_method, pkcs11_rsa_finish))
        !           331:                fatal("%s: setup pkcs11 method failed", __func__);
        !           332:        RSA_set_method(rsa, k11->rsa_method);
1.1       markus    333:        RSA_set_app_data(rsa, k11);
                    334:        return (0);
                    335: }
                    336:
                    337: /* remove trailing spaces */
                    338: static void
1.8       djm       339: rmspace(u_char *buf, size_t len)
1.1       markus    340: {
                    341:        size_t i;
                    342:
                    343:        if (!len)
                    344:                return;
                    345:        for (i = len - 1;  i > 0; i--)
                    346:                if (i == len - 1 || buf[i] == ' ')
                    347:                        buf[i] = '\0';
                    348:                else
                    349:                        break;
                    350: }
                    351:
                    352: /*
                    353:  * open a pkcs11 session and login if required.
                    354:  * if pin == NULL we delay login until key use
                    355:  */
                    356: static int
                    357: pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin)
                    358: {
                    359:        CK_RV                   rv;
                    360:        CK_FUNCTION_LIST        *f;
                    361:        CK_SESSION_HANDLE       session;
                    362:        int                     login_required;
                    363:
                    364:        f = p->function_list;
                    365:        login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED;
                    366:        if (pin && login_required && !strlen(pin)) {
                    367:                error("pin required");
                    368:                return (-1);
                    369:        }
                    370:        if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
                    371:            CKF_SERIAL_SESSION, NULL, NULL, &session))
                    372:            != CKR_OK) {
                    373:                error("C_OpenSession failed: %lu", rv);
                    374:                return (-1);
                    375:        }
                    376:        if (login_required && pin) {
1.16      djm       377:                rv = f->C_Login(session, CKU_USER,
1.17      deraadt   378:                    (u_char *)pin, strlen(pin));
1.16      djm       379:                if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
1.1       markus    380:                        error("C_Login failed: %lu", rv);
                    381:                        if ((rv = f->C_CloseSession(session)) != CKR_OK)
                    382:                                error("C_CloseSession failed: %lu", rv);
                    383:                        return (-1);
                    384:                }
                    385:                p->slotinfo[slotidx].logged_in = 1;
                    386:        }
                    387:        p->slotinfo[slotidx].session = session;
                    388:        return (0);
                    389: }
                    390:
                    391: /*
                    392:  * lookup public keys for token in slot identified by slotidx,
                    393:  * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
                    394:  * keysp points to an (possibly empty) array with *nkeys keys.
                    395:  */
1.9       markus    396: static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG,
1.15      djm       397:     CK_ATTRIBUTE [], CK_ATTRIBUTE [3], struct sshkey ***, int *)
1.13      djm       398:        __attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE))));
1.9       markus    399:
                    400: static int
                    401: pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
1.15      djm       402:     struct sshkey ***keysp, int *nkeys)
1.9       markus    403: {
                    404:        CK_OBJECT_CLASS         pubkey_class = CKO_PUBLIC_KEY;
                    405:        CK_OBJECT_CLASS         cert_class = CKO_CERTIFICATE;
                    406:        CK_ATTRIBUTE            pubkey_filter[] = {
                    407:                { CKA_CLASS, &pubkey_class, sizeof(pubkey_class) }
                    408:        };
                    409:        CK_ATTRIBUTE            cert_filter[] = {
                    410:                { CKA_CLASS, &cert_class, sizeof(cert_class) }
                    411:        };
                    412:        CK_ATTRIBUTE            pubkey_attribs[] = {
                    413:                { CKA_ID, NULL, 0 },
                    414:                { CKA_MODULUS, NULL, 0 },
                    415:                { CKA_PUBLIC_EXPONENT, NULL, 0 }
                    416:        };
                    417:        CK_ATTRIBUTE            cert_attribs[] = {
                    418:                { CKA_ID, NULL, 0 },
                    419:                { CKA_SUBJECT, NULL, 0 },
                    420:                { CKA_VALUE, NULL, 0 }
                    421:        };
                    422:
                    423:        if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, pubkey_attribs,
                    424:            keysp, nkeys) < 0 ||
                    425:            pkcs11_fetch_keys_filter(p, slotidx, cert_filter, cert_attribs,
                    426:            keysp, nkeys) < 0)
                    427:                return (-1);
                    428:        return (0);
                    429: }
                    430:
1.1       markus    431: static int
1.15      djm       432: pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
1.9       markus    433: {
                    434:        int i;
                    435:
                    436:        for (i = 0; i < *nkeys; i++)
1.15      djm       437:                if (sshkey_equal(key, (*keysp)[i]))
1.9       markus    438:                        return (1);
                    439:        return (0);
                    440: }
                    441:
                    442: static int
1.27    ! djm       443: have_rsa_key(const RSA *rsa)
        !           444: {
        !           445:        const BIGNUM *rsa_n, *rsa_e;
        !           446:
        !           447:        RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
        !           448:        return rsa_n != NULL && rsa_e != NULL;
        !           449: }
        !           450:
        !           451: static int
1.9       markus    452: pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
                    453:     CK_ATTRIBUTE filter[], CK_ATTRIBUTE attribs[3],
1.15      djm       454:     struct sshkey ***keysp, int *nkeys)
1.1       markus    455: {
1.15      djm       456:        struct sshkey           *key;
1.1       markus    457:        RSA                     *rsa;
1.9       markus    458:        X509                    *x509;
                    459:        EVP_PKEY                *evp;
1.1       markus    460:        int                     i;
1.9       markus    461:        const u_char            *cp;
1.1       markus    462:        CK_RV                   rv;
                    463:        CK_OBJECT_HANDLE        obj;
                    464:        CK_ULONG                nfound;
                    465:        CK_SESSION_HANDLE       session;
                    466:        CK_FUNCTION_LIST        *f;
                    467:
                    468:        f = p->function_list;
                    469:        session = p->slotinfo[slotidx].session;
                    470:        /* setup a filter the looks for public keys */
1.9       markus    471:        if ((rv = f->C_FindObjectsInit(session, filter, 1)) != CKR_OK) {
1.1       markus    472:                error("C_FindObjectsInit failed: %lu", rv);
                    473:                return (-1);
                    474:        }
                    475:        while (1) {
                    476:                /* XXX 3 attributes in attribs[] */
                    477:                for (i = 0; i < 3; i++) {
                    478:                        attribs[i].pValue = NULL;
                    479:                        attribs[i].ulValueLen = 0;
                    480:                }
                    481:                if ((rv = f->C_FindObjects(session, &obj, 1, &nfound)) != CKR_OK
                    482:                    || nfound == 0)
                    483:                        break;
                    484:                /* found a key, so figure out size of the attributes */
                    485:                if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
                    486:                    != CKR_OK) {
                    487:                        error("C_GetAttributeValue failed: %lu", rv);
                    488:                        continue;
                    489:                }
1.21      djm       490:                /*
                    491:                 * Allow CKA_ID (always first attribute) to be empty, but
                    492:                 * ensure that none of the others are zero length.
                    493:                 * XXX assumes CKA_ID is always first.
                    494:                 */
                    495:                if (attribs[1].ulValueLen == 0 ||
1.6       markus    496:                    attribs[2].ulValueLen == 0) {
                    497:                        continue;
                    498:                }
                    499:                /* allocate buffers for attributes */
1.21      djm       500:                for (i = 0; i < 3; i++) {
                    501:                        if (attribs[i].ulValueLen > 0) {
                    502:                                attribs[i].pValue = xmalloc(
                    503:                                    attribs[i].ulValueLen);
                    504:                        }
                    505:                }
                    506:
1.9       markus    507:                /*
                    508:                 * retrieve ID, modulus and public exponent of RSA key,
                    509:                 * or ID, subject and value for certificates.
                    510:                 */
                    511:                rsa = NULL;
1.1       markus    512:                if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
                    513:                    != CKR_OK) {
                    514:                        error("C_GetAttributeValue failed: %lu", rv);
1.9       markus    515:                } else if (attribs[1].type == CKA_MODULUS ) {
                    516:                        if ((rsa = RSA_new()) == NULL) {
                    517:                                error("RSA_new failed");
                    518:                        } else {
1.27    ! djm       519:                                BIGNUM *rsa_n, *rsa_e;
        !           520:
        !           521:                                rsa_n = BN_bin2bn(attribs[1].pValue,
1.9       markus    522:                                    attribs[1].ulValueLen, NULL);
1.27    ! djm       523:                                rsa_e = BN_bin2bn(attribs[2].pValue,
1.9       markus    524:                                    attribs[2].ulValueLen, NULL);
1.27    ! djm       525:                                if (rsa_n != NULL && rsa_e != NULL) {
        !           526:                                        if (!RSA_set0_key(rsa,
        !           527:                                            rsa_n, rsa_e, NULL))
        !           528:                                                fatal("%s: set key", __func__);
        !           529:                                        rsa_n = rsa_e = NULL; /* transferred */
        !           530:                                }
        !           531:                                BN_free(rsa_n);
        !           532:                                BN_free(rsa_e);
1.9       markus    533:                        }
1.1       markus    534:                } else {
1.9       markus    535:                        cp = attribs[2].pValue;
                    536:                        if ((x509 = X509_new()) == NULL) {
                    537:                                error("X509_new failed");
                    538:                        } else if (d2i_X509(&x509, &cp, attribs[2].ulValueLen)
                    539:                            == NULL) {
                    540:                                error("d2i_X509 failed");
                    541:                        } else if ((evp = X509_get_pubkey(x509)) == NULL ||
1.27    ! djm       542:                            EVP_PKEY_base_id(evp) != EVP_PKEY_RSA ||
        !           543:                            EVP_PKEY_get0_RSA(evp) == NULL) {
1.9       markus    544:                                debug("X509_get_pubkey failed or no rsa");
1.27    ! djm       545:                        } else if ((rsa = RSAPublicKey_dup(
        !           546:                            EVP_PKEY_get0_RSA(evp))) == NULL) {
1.9       markus    547:                                error("RSAPublicKey_dup");
                    548:                        }
1.26      jsing     549:                        X509_free(x509);
1.9       markus    550:                }
1.27    ! djm       551:                if (rsa && have_rsa_key(rsa) &&
1.9       markus    552:                    pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
1.24      markus    553:                        if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
                    554:                                fatal("sshkey_new failed");
1.9       markus    555:                        key->rsa = rsa;
                    556:                        key->type = KEY_RSA;
1.14      djm       557:                        key->flags |= SSHKEY_FLAG_EXT;
1.9       markus    558:                        if (pkcs11_key_included(keysp, nkeys, key)) {
1.15      djm       559:                                sshkey_free(key);
1.9       markus    560:                        } else {
1.1       markus    561:                                /* expand key array and add key */
1.25      deraadt   562:                                *keysp = xrecallocarray(*keysp, *nkeys,
                    563:                                    *nkeys + 1, sizeof(struct sshkey *));
1.1       markus    564:                                (*keysp)[*nkeys] = key;
                    565:                                *nkeys = *nkeys + 1;
                    566:                                debug("have %d keys", *nkeys);
                    567:                        }
1.9       markus    568:                } else if (rsa) {
                    569:                        RSA_free(rsa);
1.1       markus    570:                }
                    571:                for (i = 0; i < 3; i++)
1.7       djm       572:                        free(attribs[i].pValue);
1.1       markus    573:        }
                    574:        if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
                    575:                error("C_FindObjectsFinal failed: %lu", rv);
                    576:        return (0);
                    577: }
                    578:
1.2       markus    579: #ifdef HAVE_DLOPEN
1.1       markus    580: /* register a new provider, fails if provider already exists */
                    581: int
1.15      djm       582: pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1.1       markus    583: {
                    584:        int nkeys, need_finalize = 0;
                    585:        struct pkcs11_provider *p = NULL;
                    586:        void *handle = NULL;
                    587:        CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
                    588:        CK_RV rv;
                    589:        CK_FUNCTION_LIST *f = NULL;
                    590:        CK_TOKEN_INFO *token;
                    591:        CK_ULONG i;
                    592:
                    593:        *keyp = NULL;
                    594:        if (pkcs11_provider_lookup(provider_id) != NULL) {
1.23      djm       595:                debug("%s: provider already registered: %s",
                    596:                    __func__, provider_id);
1.1       markus    597:                goto fail;
                    598:        }
                    599:        /* open shared pkcs11-libarary */
                    600:        if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
                    601:                error("dlopen %s failed: %s", provider_id, dlerror());
                    602:                goto fail;
                    603:        }
                    604:        if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
                    605:                error("dlsym(C_GetFunctionList) failed: %s", dlerror());
                    606:                goto fail;
                    607:        }
                    608:        p = xcalloc(1, sizeof(*p));
                    609:        p->name = xstrdup(provider_id);
                    610:        p->handle = handle;
                    611:        /* setup the pkcs11 callbacks */
                    612:        if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
1.23      djm       613:                error("C_GetFunctionList for provider %s failed: %lu",
                    614:                    provider_id, rv);
1.1       markus    615:                goto fail;
                    616:        }
                    617:        p->function_list = f;
                    618:        if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
1.23      djm       619:                error("C_Initialize for provider %s failed: %lu",
                    620:                    provider_id, rv);
1.1       markus    621:                goto fail;
                    622:        }
                    623:        need_finalize = 1;
                    624:        if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
1.23      djm       625:                error("C_GetInfo for provider %s failed: %lu",
                    626:                    provider_id, rv);
1.1       markus    627:                goto fail;
                    628:        }
                    629:        rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
                    630:        rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
1.23      djm       631:        debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
1.1       markus    632:            " libraryDescription <%s> libraryVersion %d.%d",
1.23      djm       633:            provider_id,
1.1       markus    634:            p->info.manufacturerID,
                    635:            p->info.cryptokiVersion.major,
                    636:            p->info.cryptokiVersion.minor,
                    637:            p->info.libraryDescription,
                    638:            p->info.libraryVersion.major,
                    639:            p->info.libraryVersion.minor);
                    640:        if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
                    641:                error("C_GetSlotList failed: %lu", rv);
                    642:                goto fail;
                    643:        }
                    644:        if (p->nslots == 0) {
1.23      djm       645:                debug("%s: provider %s returned no slots", __func__,
                    646:                    provider_id);
1.1       markus    647:                goto fail;
                    648:        }
                    649:        p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
                    650:        if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
                    651:            != CKR_OK) {
1.23      djm       652:                error("C_GetSlotList for provider %s failed: %lu",
                    653:                    provider_id, rv);
1.1       markus    654:                goto fail;
                    655:        }
                    656:        p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
                    657:        p->valid = 1;
                    658:        nkeys = 0;
                    659:        for (i = 0; i < p->nslots; i++) {
                    660:                token = &p->slotinfo[i].token;
                    661:                if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
                    662:                    != CKR_OK) {
1.23      djm       663:                        error("C_GetTokenInfo for provider %s slot %lu "
                    664:                            "failed: %lu", provider_id, (unsigned long)i, rv);
1.20      djm       665:                        continue;
                    666:                }
                    667:                if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
1.23      djm       668:                        debug2("%s: ignoring uninitialised token in "
                    669:                            "provider %s slot %lu", __func__,
                    670:                            provider_id, (unsigned long)i);
1.1       markus    671:                        continue;
                    672:                }
                    673:                rmspace(token->label, sizeof(token->label));
                    674:                rmspace(token->manufacturerID, sizeof(token->manufacturerID));
                    675:                rmspace(token->model, sizeof(token->model));
                    676:                rmspace(token->serialNumber, sizeof(token->serialNumber));
1.23      djm       677:                debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
                    678:                    "model <%s> serial <%s> flags 0x%lx",
                    679:                    provider_id, (unsigned long)i,
1.1       markus    680:                    token->label, token->manufacturerID, token->model,
                    681:                    token->serialNumber, token->flags);
                    682:                /* open session, login with pin and retrieve public keys */
                    683:                if (pkcs11_open_session(p, i, pin) == 0)
                    684:                        pkcs11_fetch_keys(p, i, keyp, &nkeys);
                    685:        }
                    686:        if (nkeys > 0) {
                    687:                TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
                    688:                p->refcount++;  /* add to provider list */
                    689:                return (nkeys);
                    690:        }
1.23      djm       691:        debug("%s: provider %s returned no keys", __func__, provider_id);
1.1       markus    692:        /* don't add the provider, since it does not have any keys */
                    693: fail:
                    694:        if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
1.23      djm       695:                error("C_Finalize for provider %s failed: %lu",
                    696:                    provider_id, rv);
1.1       markus    697:        if (p) {
1.7       djm       698:                free(p->slotlist);
                    699:                free(p->slotinfo);
                    700:                free(p);
1.1       markus    701:        }
                    702:        if (handle)
                    703:                dlclose(handle);
                    704:        return (-1);
                    705: }
1.2       markus    706: #else
                    707: int
1.15      djm       708: pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
1.2       markus    709: {
                    710:        error("dlopen() not supported");
                    711:        return (-1);
                    712: }
                    713: #endif